From b440901843a930c6c87ec23c59f90f1349c25b50 Mon Sep 17 00:00:00 2001 From: IEatChili Date: Thu, 6 Jun 2024 15:23:12 -0400 Subject: feat: updated ui --- src/client/documents/DocumentTypes.ts | 1 + src/client/documents/Documents.ts | 4 + src/client/util/CurrentUserUtils.ts | 7 + src/client/views/Main.tsx | 2 + src/client/views/MainView.tsx | 1 + .../collectionFreeForm/ImageLabelBox.scss | 26 ++++ .../collectionFreeForm/ImageLabelBox.tsx | 150 +++++++++++++++++++++ .../collectionFreeForm/ImageLabelHandler.tsx | 2 +- .../collections/collectionFreeForm/MarqueeView.tsx | 56 +++++--- src/client/views/linking/LinkPopup.tsx | 1 - src/fields/Doc.ts | 1 + 11 files changed, 230 insertions(+), 21 deletions(-) create mode 100644 src/client/views/collections/collectionFreeForm/ImageLabelBox.scss create mode 100644 src/client/views/collections/collectionFreeForm/ImageLabelBox.tsx (limited to 'src') diff --git a/src/client/documents/DocumentTypes.ts b/src/client/documents/DocumentTypes.ts index 8f95068db..a9ea889b3 100644 --- a/src/client/documents/DocumentTypes.ts +++ b/src/client/documents/DocumentTypes.ts @@ -16,6 +16,7 @@ export enum DocumentType { SCREENSHOT = 'screenshot', FONTICON = 'fonticonbox', SEARCH = 'search', // search query + IMAGEGROUPER = 'imagegrouper', LABEL = 'label', // simple text label BUTTON = 'button', // onClick button WEBCAM = 'webcam', // webcam diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index a67e6b4f6..449347403 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -784,6 +784,10 @@ export namespace Docs { return InstanceFromProto(Prototypes.get(DocumentType.SEARCH), new List([]), options); } + export function ImageGrouperDocument(options: DocumentOptions = {}) { + return InstanceFromProto(Prototypes.get(DocumentType.IMAGEGROUPER), undefined, options); + } + export function LoadingDocument(file: File | string, options: DocumentOptions) { return InstanceFromProto(Prototypes.get(DocumentType.LOADING), undefined, { _height: 150, _width: 200, title: typeof file === 'string' ? file : file.name, ...options }, undefined, ''); } diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts index e095bc659..486b6815a 100644 --- a/src/client/util/CurrentUserUtils.ts +++ b/src/client/util/CurrentUserUtils.ts @@ -458,6 +458,7 @@ pie title Minerals in my tap water { title: "Shared", toolTip: "Shared Docs", target: Doc.MySharedDocs, ignoreClick: true, icon: "users", funcs: {badgeValue: badgeValue}}, { title: "Trails", toolTip: "Trails ⌘R", target: Doc.UserDoc(), ignoreClick: true, icon: "pres-trail", funcs: {target: getActiveDashTrails}}, { title: "User Doc", toolTip: "User Doc", target: this.setupUserDocView(doc, "myUserDocView"), ignoreClick: true, icon: "address-card",funcs: {hidden: "IsNoviceMode()"} }, + { title: "Image Grouper", toolTip: "Image Grouper", target: this.setupImageGrouper(doc, "myImageGrouper"), ignoreClick: true, icon: "folder-open", hidden: true } ].map(tuple => ({...tuple, scripts:{onClick: 'selectMainMenu(this)'}})); } @@ -493,6 +494,12 @@ pie title Minerals in my tap water _lockedPosition: true, _type_collection: CollectionViewType.Schema }); } + static setupImageGrouper(doc: Doc, field: string) { + return DocUtils.AssignDocField(doc, field, (opts) => Docs.Create.ImageGrouperDocument(opts), { + dontRegisterView: true, backgroundColor: "dimgray", ignoreClick: true, title: "Image Grouper", isSystem: true, childDragAction: dropActionType.embed, + _lockedPosition: true, _type_collection: CollectionViewType.Schema }); + } + /// Initializes the panel of draggable tools that is opened from the left sidebar. static setupToolsBtnPanel(doc: Doc, field:string) { const allTools = DocListCast(DocCast(doc[field])?.data); diff --git a/src/client/views/Main.tsx b/src/client/views/Main.tsx index 43b9a6b39..8242e7c27 100644 --- a/src/client/views/Main.tsx +++ b/src/client/views/Main.tsx @@ -60,6 +60,7 @@ import { SummaryView } from './nodes/formattedText/SummaryView'; import { ImportElementBox } from './nodes/importBox/ImportElementBox'; import { PresBox, PresElementBox } from './nodes/trails'; import { SearchBox } from './search/SearchBox'; +import { ImageLabelBox } from './collections/collectionFreeForm/ImageLabelBox'; dotenv.config(); @@ -131,6 +132,7 @@ FieldLoader.ServerLoadStatus = { requested: 0, retrieved: 0, message: 'cache' }; PresBox, PresElementBox, SearchBox, + ImageLabelBox, //Here! FunctionPlotBox, InkingStroke, LinkBox, diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index 31d88fb87..5b4c2b5ba 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -76,6 +76,7 @@ import { PresBox } from './nodes/trails'; import { AnchorMenu } from './pdf/AnchorMenu'; import { GPTPopup } from './pdf/GPTPopup/GPTPopup'; import { TopBar } from './topbar/TopBar'; +import { ImageLabelBox } from './collections/collectionFreeForm/ImageLabelBox'; const { LEFT_MENU_WIDTH, TOPBAR_HEIGHT } = require('./global/globalCssVariables.module.scss'); // prettier-ignore const _global = (window /* browser */ || global) /* node */ as any; diff --git a/src/client/views/collections/collectionFreeForm/ImageLabelBox.scss b/src/client/views/collections/collectionFreeForm/ImageLabelBox.scss new file mode 100644 index 000000000..d0c12814c --- /dev/null +++ b/src/client/views/collections/collectionFreeForm/ImageLabelBox.scss @@ -0,0 +1,26 @@ +.image-label-list { + display: flex; + flex-direction: column; + align-items: center; // Centers the content vertically in the flex container + width: 100%; + + > div { + display: flex; + justify-content: space-between; // Puts the content and delete button on opposite ends + align-items: center; + width: 100%; + margin-top: 8px; // Adds space between label rows + background-color: black; + + p { + text-align: center; // Centers the text of the paragraph + font-size: large; + vertical-align: middle; + } + + .IconButton { + // Styling for the delete button + margin-left: auto; // Pushes the button to the far right + } + } +} diff --git a/src/client/views/collections/collectionFreeForm/ImageLabelBox.tsx b/src/client/views/collections/collectionFreeForm/ImageLabelBox.tsx new file mode 100644 index 000000000..1c0035f0d --- /dev/null +++ b/src/client/views/collections/collectionFreeForm/ImageLabelBox.tsx @@ -0,0 +1,150 @@ +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { Colors, IconButton } from 'browndash-components'; +import { action, makeObservable, observable } from 'mobx'; +import { observer } from 'mobx-react'; +import React from 'react'; +import { Doc } from '../../../../fields/Doc'; +import { Docs } from '../../../documents/Documents'; +import { DocumentType } from '../../../documents/DocumentTypes'; +import { ViewBoxBaseComponent } from '../../DocComponent'; +import { FieldView, FieldViewProps } from '../../nodes/FieldView'; +import { MarqueeOptionsMenu } from './MarqueeOptionsMenu'; +import './ImageLabelBox.scss'; +import { MainView } from '../../MainView'; +import { MarqueeView } from './MarqueeView'; + +@observer +export class ImageLabelBox extends ViewBoxBaseComponent() { + public static LayoutString(fieldKey: string) { + return FieldView.LayoutString(ImageLabelBox, fieldKey); + } + + public static Instance: ImageLabelBox | null = null; + private _inputRef = React.createRef(); + @observable _loading: boolean = true; + @observable _currentLabel: string = ''; + @observable _labelGroups: string[] = []; + + constructor(props: any) { + super(props); + makeObservable(this); + ImageLabelBox.Instance = this; + + console.log('Image Box Has Been Initialized'); + } + + /** + * This method is called when the SearchBox component is first mounted. When the user opens + * the search panel, the search input box is automatically selected. This allows the user to + * type in the search input box immediately, without needing clicking on it first. + */ + componentDidMount() { + // if (this._inputRef.current) { + // this._inputRef.current.focus(); + // } + } + + @action + addLabel = (label: string) => { + label = label.toUpperCase().trim(); + if (label.length > 0) { + if (!this._labelGroups.includes(label)) { + this._labelGroups = [...this._labelGroups, label]; + } + } + }; + + @action + removeLabel = (label: string) => { + const labelUp = label.toUpperCase(); + this._labelGroups = this._labelGroups.filter(group => group !== labelUp); + }; + + @action + groupImages = () => { + MarqueeOptionsMenu.Instance.groupImages(); + this._labelGroups = []; + MainView.Instance.closeFlyout(); + }; + + @action + startLoading = () => { + this._loading = true; + }; + + @action + endLoading = () => { + this._loading = false; + }; + + render() { + if (this._loading) { + return
Loading...
; + } + + return ( +
+
+ { + // e.key === 'Enter' ? this.submitSearch() : null; + // e.stopPropagation(); + // }} + type="text" + placeholder="Input a group to put images into..." + aria-label="label-input" + id="new-label" + className="searchBox-input" + style={{ width: '100%', borderRadius: '5px' }} + ref={this._inputRef} + /> + { + const input = document.getElementById('new-label') as HTMLInputElement; + const newLabel = input.value; + this.addLabel(newLabel); + this._currentLabel = ''; + input.value = ''; + }} + icon={} + color={MarqueeOptionsMenu.Instance.userColor} + style={{ width: '19px' }} + /> + {this._labelGroups.length > 0 ? ( + } color={MarqueeOptionsMenu.Instance.userColor} style={{ width: '19px' }} /> + ) : ( +
+ )} +
+
+
+ {this._labelGroups.map(group => { + return ( +
+

{group}

+ { + this.removeLabel(group); + }} + icon={'x'} + color={MarqueeOptionsMenu.Instance.userColor} + style={{ width: '8px' }} + /> +
+ ); + })} +
+
+
+ ); + } +} + +Docs.Prototypes.TemplateMap.set(DocumentType.IMAGEGROUPER, { + layout: { view: ImageLabelBox, dataField: 'data' }, + options: { acl: '', _width: 400 }, +}); diff --git a/src/client/views/collections/collectionFreeForm/ImageLabelHandler.tsx b/src/client/views/collections/collectionFreeForm/ImageLabelHandler.tsx index 7f27c6b5c..73befb205 100644 --- a/src/client/views/collections/collectionFreeForm/ImageLabelHandler.tsx +++ b/src/client/views/collections/collectionFreeForm/ImageLabelHandler.tsx @@ -77,7 +77,7 @@ export class ImageLabelHandler extends ObservableReactComponent<{}> { }}>
} color={MarqueeOptionsMenu.Instance.userColor} style={{ width: '19px' }} /> - + { diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx index dc15c83c5..bb5a2a66e 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx @@ -5,7 +5,7 @@ import { observer } from 'mobx-react'; import * as React from 'react'; import { ClientUtils, lightOrDark, returnFalse } from '../../../../ClientUtils'; import { intersectRect, numberRange } from '../../../../Utils'; -import { Doc, NumListCast, Opt } from '../../../../fields/Doc'; +import { Doc, DocListCast, NumListCast, Opt } from '../../../../fields/Doc'; import { AclAdmin, AclAugment, AclEdit, DocData } from '../../../../fields/DocSymbols'; import { Id } from '../../../../fields/FieldSymbols'; import { InkData, InkField, InkTool } from '../../../../fields/InkField'; @@ -36,6 +36,9 @@ import { CollectionFreeFormView } from './CollectionFreeFormView'; import { ImageLabelHandler } from './ImageLabelHandler'; import { MarqueeOptionsMenu } from './MarqueeOptionsMenu'; import './MarqueeView.scss'; +import { MainView } from '../../MainView'; +import { ImageLabelBox } from './ImageLabelBox'; +import { SearchBox } from '../../search/SearchBox'; interface MarqueeViewProps { getContainerTransform: () => Transform; @@ -53,6 +56,9 @@ interface MarqueeViewProps { slowLoadDocuments: (files: File[] | string, options: DocumentOptions, generatedDocuments: Doc[], text: string, completed: ((doc: Doc[]) => void) | undefined, addDocument: (doc: Doc | Doc[]) => boolean) => Promise; } +/** + * A component that deals with the marquee select in the freeform canvas. + */ @observer export class MarqueeView extends ObservableReactComponent { public static CurViewBounds(pinDoc: Doc, panelWidth: number, panelHeight: number) { @@ -60,9 +66,12 @@ export class MarqueeView extends ObservableReactComponent { - this._selectedDocs = this.marqueeSelect(false, DocumentType.IMG); + if (e) { + const groupButton = DocListCast(Doc.MyLeftSidebarMenu.data).find(d => d.target === Doc.MyImageGrouper); + if (groupButton) { + MainView.Instance.expandFlyout(groupButton); + while (!ImageLabelBox.Instance) { + await new Promise(resolve => setTimeout(resolve, 1000)).then(() => { + console.log('Waiting for Image Label Box'); + }); + } + ImageLabelBox.Instance.startLoading(); + } + } + + this._selectedDocs = this.marqueeSelect(false, DocumentType.IMG); // Get the selected documents from the marquee select. const imageInfos = this._selectedDocs.map(async doc => { - const [name, type] = ImageCast(doc[Doc.LayoutFieldKey(doc)]).url.href.split('.'); - return CollectionCardView.imageUrlToBase64(`${name}_o.${type}`).then(hrefBase64 => + if (!doc[DocData].data_labels) { + const [name, type] = ImageCast(doc[Doc.LayoutFieldKey(doc)]).url.href.split('.'); + return CollectionCardView.imageUrlToBase64(`${name}_o.${type}`).then(hrefBase64 => !hrefBase64 ? undefined : gptImageLabel(hrefBase64).then(labels => Promise.all(labels.split('\n').map(label => gptGetEmbedding(label))).then(embeddings => ({ doc, embeddings, labels }))) ); // prettier-ignore - }); + } + }); // Converts the images into a Base64 format, afterwhich the information is sent to GPT to label them. (await Promise.all(imageInfos)).forEach(imageInfo => { - if (imageInfo && Array.isArray(imageInfo.embeddings)) { + if (imageInfo && imageInfo.embeddings && Array.isArray(imageInfo.embeddings)) { imageInfo.doc[DocData].data_labels = imageInfo.labels; numberRange(3).forEach(n => { imageInfo.doc[`data_labels_embedding_${n + 1}`] = new List(imageInfo.embeddings[n]); }); } - }); + }); // Add the labels as fields to each image. - if (e) { - ImageLabelHandler.Instance.displayLabelHandler(e.pageX, e.pageY); - } + ImageLabelBox.Instance!.endLoading(); + console.log('Complete!'); }); /** @@ -464,7 +486,7 @@ export class MarqueeView extends ObservableReactComponent { - const labelGroups = ImageLabelHandler.Instance._labelGroups; + const labelGroups = ImageLabelBox.Instance!._labelGroups; const labelToEmbedding = new Map(); // Create embeddings for the labels. await Promise.all(labelGroups.map(async label => gptGetEmbedding(label).then(labelEmbedding => labelToEmbedding.set(label, labelEmbedding)))); @@ -478,14 +500,10 @@ export class MarqueeView extends ObservableReactComponent ({ label, similarityScore: bestEmbedScore(labelToEmbedding.get(label)) })) .reduce((prev, cur) => cur.similarityScore < 0.3 || cur.similarityScore <= prev.similarityScore ? prev: cur, { label: '', similarityScore: 0, }); // prettier-ignore - - numberRange(3).forEach(n => { - doc[`data_labels_embedding_${n + 1}`] = undefined; - }); - doc[DocData].data_label = mostSimilarLabelCollect; + doc[DocData].data_label = mostSimilarLabelCollect; // The label most similar to the image's contents. }); - this._props.Document._type_collection = CollectionViewType.Time; - this._props.Document.pivotField = 'data_label'; + this._props.Document._type_collection = CollectionViewType.Time; // Change the collection view to a Time view. + this._props.Document.pivotField = 'data_label'; // Sets the pivot to be the 'data_label'. }); @undoBatch diff --git a/src/client/views/linking/LinkPopup.tsx b/src/client/views/linking/LinkPopup.tsx index 76a8396ff..2405e375d 100644 --- a/src/client/views/linking/LinkPopup.tsx +++ b/src/client/views/linking/LinkPopup.tsx @@ -45,7 +45,6 @@ export class LinkPopup extends React.Component { {/* */} - Date: Mon, 10 Jun 2024 11:06:02 -0400 Subject: feat: ui changes --- package-lock.json | 6 +++ package.json | 1 + .../collectionFreeForm/ImageLabelBox.scss | 23 +++++++++ .../collectionFreeForm/ImageLabelBox.tsx | 60 ++++++++++++++++++---- .../collectionFreeForm/MarqueeOptionsMenu.tsx | 2 +- .../collections/collectionFreeForm/MarqueeView.tsx | 9 ++-- 6 files changed, 86 insertions(+), 15 deletions(-) (limited to 'src') diff --git a/package-lock.json b/package-lock.json index 9b3904ff7..6cd2ab605 100644 --- a/package-lock.json +++ b/package-lock.json @@ -136,6 +136,7 @@ "js-datepicker": "^5.18.2", "jsonschema": "^1.4.1", "jszip": "^3.10.1", + "ldrs": "^1.0.2", "lodash": "^4.17.21", "mapbox-gl": "^3.0.1", "markdown-it": "^14.1.0", @@ -23613,6 +23614,11 @@ "safe-buffer": "~5.1.0" } }, + "node_modules/ldrs": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/ldrs/-/ldrs-1.0.2.tgz", + "integrity": "sha512-sYJmivdkIiHrUEqTrEWccBoLdaENpzbzkABI5rk8rRxTXrg9i2xVuDvUUuhOhJY3RmQyaoxs046pM1DCRdcIpg==" + }, "node_modules/leac": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/leac/-/leac-0.6.0.tgz", diff --git a/package.json b/package.json index ed05c4f45..bbd2a4c46 100644 --- a/package.json +++ b/package.json @@ -221,6 +221,7 @@ "js-datepicker": "^5.18.2", "jsonschema": "^1.4.1", "jszip": "^3.10.1", + "ldrs": "^1.0.2", "lodash": "^4.17.21", "mapbox-gl": "^3.0.1", "markdown-it": "^14.1.0", diff --git a/src/client/views/collections/collectionFreeForm/ImageLabelBox.scss b/src/client/views/collections/collectionFreeForm/ImageLabelBox.scss index d0c12814c..5f2ce4e14 100644 --- a/src/client/views/collections/collectionFreeForm/ImageLabelBox.scss +++ b/src/client/views/collections/collectionFreeForm/ImageLabelBox.scss @@ -1,3 +1,18 @@ +.image-box-container { + display: flex; + align-items: center; + justify-content: center; + width: 100%; + height: 100%; + font-size: 10px; + line-height: 1; + background: none; + z-index: 1000; + padding: 0px; + overflow: auto; + cursor: default; +} + .image-label-list { display: flex; flex-direction: column; @@ -16,6 +31,7 @@ text-align: center; // Centers the text of the paragraph font-size: large; vertical-align: middle; + margin-left: 10px; } .IconButton { @@ -24,3 +40,10 @@ } } } + +.image-information { + display: flex; + flex-direction: column; + //align-items: center; + width: 100%; +} diff --git a/src/client/views/collections/collectionFreeForm/ImageLabelBox.tsx b/src/client/views/collections/collectionFreeForm/ImageLabelBox.tsx index 1c0035f0d..83ae69cfb 100644 --- a/src/client/views/collections/collectionFreeForm/ImageLabelBox.tsx +++ b/src/client/views/collections/collectionFreeForm/ImageLabelBox.tsx @@ -12,6 +12,11 @@ import { MarqueeOptionsMenu } from './MarqueeOptionsMenu'; import './ImageLabelBox.scss'; import { MainView } from '../../MainView'; import { MarqueeView } from './MarqueeView'; +import 'ldrs/ring'; +import { ring } from 'ldrs'; +import { SnappingManager } from '../../../util/SnappingManager'; +import { ImageCast } from '../../../../fields/Types'; +import { DocData } from '../../../../fields/DocSymbols'; @observer export class ImageLabelBox extends ViewBoxBaseComponent() { @@ -24,12 +29,14 @@ export class ImageLabelBox extends ViewBoxBaseComponent() { @observable _loading: boolean = true; @observable _currentLabel: string = ''; @observable _labelGroups: string[] = []; + @observable _selectedImages: Doc[] = []; + @observable _displayImageInformation: boolean = false; constructor(props: any) { super(props); makeObservable(this); ImageLabelBox.Instance = this; - + ring.register(); console.log('Image Box Has Been Initialized'); } @@ -77,14 +84,32 @@ export class ImageLabelBox extends ViewBoxBaseComponent() { this._loading = false; }; + @action + setSelectedImages = (selected: Doc[]) => { + this._selectedImages = selected; + }; + render() { if (this._loading) { - return
Loading...
; + return ( +
+ +
+ ); } return ( -
-
+
+
+ { + this._displayImageInformation = !this._displayImageInformation; + }} + icon={this._displayImageInformation ? : } + color={MarqueeOptionsMenu.Instance.userColor} + style={{ width: '19px' }} + /> () { // e.stopPropagation(); // }} type="text" - placeholder="Input a group to put images into..." + placeholder="Input labels for image groupings..." aria-label="label-input" id="new-label" className="searchBox-input" @@ -101,7 +126,7 @@ export class ImageLabelBox extends ViewBoxBaseComponent() { ref={this._inputRef} /> { const input = document.getElementById('new-label') as HTMLInputElement; const newLabel = input.value; @@ -113,11 +138,7 @@ export class ImageLabelBox extends ViewBoxBaseComponent() { color={MarqueeOptionsMenu.Instance.userColor} style={{ width: '19px' }} /> - {this._labelGroups.length > 0 ? ( - } color={MarqueeOptionsMenu.Instance.userColor} style={{ width: '19px' }} /> - ) : ( -
- )} + {this._labelGroups.length > 0 ? } color={Colors.MEDIUM_BLUE} style={{ width: '19px' }} /> :
}
@@ -139,6 +160,23 @@ export class ImageLabelBox extends ViewBoxBaseComponent() { })}
+ {this._displayImageInformation ? ( +
+ {this._selectedImages.map(doc => { + const [name, type] = ImageCast(doc[Doc.LayoutFieldKey(doc)]).url.href.split('.'); + return ( +
+ + {(doc[DocData].data_labels as string).split('\n').map(label => { + return
{label}
; + })} +
+ ); + })} +
+ ) : ( +
+ )}
); } diff --git a/src/client/views/collections/collectionFreeForm/MarqueeOptionsMenu.tsx b/src/client/views/collections/collectionFreeForm/MarqueeOptionsMenu.tsx index f02cd9d45..b94a22d04 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeOptionsMenu.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeOptionsMenu.tsx @@ -39,7 +39,7 @@ export class MarqueeOptionsMenu extends AntimodeMenu { } color={this.userColor} /> } color={this.userColor} /> } color={this.userColor} /> - } color={this.userColor} /> + } color={this.userColor} /> ); return this.getElement(buttons); diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx index bb5a2a66e..f98883bff 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx @@ -456,6 +456,7 @@ export class MarqueeView extends ObservableReactComponent { if (!doc[DocData].data_labels) { @@ -478,7 +479,7 @@ export class MarqueeView extends ObservableReactComponent Date: Wed, 12 Jun 2024 12:32:19 -0400 Subject: feat: updated and fixed ui --- src/client/util/CurrentUserUtils.ts | 2 +- src/client/views/MainView.tsx | 2 +- .../collectionFreeForm/ImageLabelBox.scss | 40 +++++- .../collectionFreeForm/ImageLabelBox.tsx | 159 +++++++++++++++------ .../collections/collectionFreeForm/MarqueeView.tsx | 46 +----- 5 files changed, 164 insertions(+), 85 deletions(-) (limited to 'src') diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts index 486b6815a..cb3d9df62 100644 --- a/src/client/util/CurrentUserUtils.ts +++ b/src/client/util/CurrentUserUtils.ts @@ -458,7 +458,7 @@ pie title Minerals in my tap water { title: "Shared", toolTip: "Shared Docs", target: Doc.MySharedDocs, ignoreClick: true, icon: "users", funcs: {badgeValue: badgeValue}}, { title: "Trails", toolTip: "Trails ⌘R", target: Doc.UserDoc(), ignoreClick: true, icon: "pres-trail", funcs: {target: getActiveDashTrails}}, { title: "User Doc", toolTip: "User Doc", target: this.setupUserDocView(doc, "myUserDocView"), ignoreClick: true, icon: "address-card",funcs: {hidden: "IsNoviceMode()"} }, - { title: "Image Grouper", toolTip: "Image Grouper", target: this.setupImageGrouper(doc, "myImageGrouper"), ignoreClick: true, icon: "folder-open", hidden: true } + { title: "Image Grouper", toolTip: "Image Grouper", target: this.setupImageGrouper(doc, "myImageGrouper"), ignoreClick: true, icon: "folder-open", hidden: false } ].map(tuple => ({...tuple, scripts:{onClick: 'selectMainMenu(this)'}})); } diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index 5b4c2b5ba..716edc22d 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -76,7 +76,7 @@ import { PresBox } from './nodes/trails'; import { AnchorMenu } from './pdf/AnchorMenu'; import { GPTPopup } from './pdf/GPTPopup/GPTPopup'; import { TopBar } from './topbar/TopBar'; -import { ImageLabelBox } from './collections/collectionFreeForm/ImageLabelBox'; +import { ImageLabelBox, ImageLabelBoxData } from './collections/collectionFreeForm/ImageLabelBox'; const { LEFT_MENU_WIDTH, TOPBAR_HEIGHT } = require('./global/globalCssVariables.module.scss'); // prettier-ignore const _global = (window /* browser */ || global) /* node */ as any; diff --git a/src/client/views/collections/collectionFreeForm/ImageLabelBox.scss b/src/client/views/collections/collectionFreeForm/ImageLabelBox.scss index 5f2ce4e14..819c72760 100644 --- a/src/client/views/collections/collectionFreeForm/ImageLabelBox.scss +++ b/src/client/views/collections/collectionFreeForm/ImageLabelBox.scss @@ -41,9 +41,45 @@ } } -.image-information { +.image-information-list { display: flex; flex-direction: column; - //align-items: center; + align-items: center; + width: 100%; + margin-top: 10px; +} + +.image-information { + border: 1px solid; width: 100%; + display: inline-flex; + flex-direction: column; + justify-content: center; + align-items: center; + overflow: hidden; + padding: 2px; + overflow-x: auto; + overflow-y: auto; + + img { + max-width: 200px; + max-height: 200px; + width: auto; + height: auto; + } +} + +.image-information-labels { + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + + .image-label { + margin-top: 5px; + margin-bottom: 5px; + padding: 3px; + border-radius: 2px; + border: solid 1px; + } } diff --git a/src/client/views/collections/collectionFreeForm/ImageLabelBox.tsx b/src/client/views/collections/collectionFreeForm/ImageLabelBox.tsx index 83ae69cfb..f5530ccc4 100644 --- a/src/client/views/collections/collectionFreeForm/ImageLabelBox.tsx +++ b/src/client/views/collections/collectionFreeForm/ImageLabelBox.tsx @@ -1,6 +1,6 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { Colors, IconButton } from 'browndash-components'; -import { action, makeObservable, observable } from 'mobx'; +import { action, computed, makeObservable, observable, reaction } from 'mobx'; import { observer } from 'mobx-react'; import React from 'react'; import { Doc } from '../../../../fields/Doc'; @@ -11,12 +11,51 @@ import { FieldView, FieldViewProps } from '../../nodes/FieldView'; import { MarqueeOptionsMenu } from './MarqueeOptionsMenu'; import './ImageLabelBox.scss'; import { MainView } from '../../MainView'; -import { MarqueeView } from './MarqueeView'; import 'ldrs/ring'; import { ring } from 'ldrs'; import { SnappingManager } from '../../../util/SnappingManager'; import { ImageCast } from '../../../../fields/Types'; import { DocData } from '../../../../fields/DocSymbols'; +import { SettingsManager } from '../../../util/SettingsManager'; +import { CollectionCardView } from '../CollectionCardDeckView'; +import { gptGetEmbedding, gptImageLabel } from '../../../apis/gpt/GPT'; +import { numberRange, Utils } from '../../../../Utils'; +import { List } from '../../../../fields/List'; + +export class ImageLabelBoxData { + static _instance: ImageLabelBoxData; + @observable _docs: Doc[] = []; + @observable _labelGroups: string[] = []; + + constructor() { + makeObservable(this); + ImageLabelBoxData._instance = this; + } + public static get Instance() { + return ImageLabelBoxData._instance ?? new ImageLabelBoxData(); + } + + @action + public setData = (docs: Doc[]) => { + this._docs = docs; + }; + + @action + addLabel = (label: string) => { + label = label.toUpperCase().trim(); + if (label.length > 0) { + if (!this._labelGroups.includes(label)) { + this._labelGroups = [...this._labelGroups, label]; + } + } + }; + + @action + removeLabel = (label: string) => { + const labelUp = label.toUpperCase(); + this._labelGroups = this._labelGroups.filter(group => group !== labelUp); + }; +} @observer export class ImageLabelBox extends ViewBoxBaseComponent() { @@ -24,59 +63,53 @@ export class ImageLabelBox extends ViewBoxBaseComponent() { return FieldView.LayoutString(ImageLabelBox, fieldKey); } - public static Instance: ImageLabelBox | null = null; + public static Instance: ImageLabelBox; private _inputRef = React.createRef(); - @observable _loading: boolean = true; - @observable _currentLabel: string = ''; - @observable _labelGroups: string[] = []; - @observable _selectedImages: Doc[] = []; + @observable _loading: boolean = false; + private _currentLabel: string = ''; + + @computed get _labelGroups() { + return ImageLabelBoxData.Instance._labelGroups; + } + + @computed get _selectedImages() { + // return DocListCast(this.dataDoc.data); + return ImageLabelBoxData.Instance._docs; + } @observable _displayImageInformation: boolean = false; constructor(props: any) { super(props); makeObservable(this); - ImageLabelBox.Instance = this; ring.register(); + ImageLabelBox.Instance = this; console.log('Image Box Has Been Initialized'); } + // ImageLabelBox.Instance.setData() /** * This method is called when the SearchBox component is first mounted. When the user opens * the search panel, the search input box is automatically selected. This allows the user to * type in the search input box immediately, without needing clicking on it first. */ componentDidMount() { - // if (this._inputRef.current) { - // this._inputRef.current.focus(); - // } + this.classifyImagesInBox(); + reaction( + () => this._selectedImages, + () => this.classifyImagesInBox() + ); } - @action - addLabel = (label: string) => { - label = label.toUpperCase().trim(); - if (label.length > 0) { - if (!this._labelGroups.includes(label)) { - this._labelGroups = [...this._labelGroups, label]; - } - } - }; - - @action - removeLabel = (label: string) => { - const labelUp = label.toUpperCase(); - this._labelGroups = this._labelGroups.filter(group => group !== labelUp); - }; - @action groupImages = () => { MarqueeOptionsMenu.Instance.groupImages(); - this._labelGroups = []; MainView.Instance.closeFlyout(); }; @action startLoading = () => { this._loading = true; + console.log('Start loading has been called!'); }; @action @@ -85,8 +118,38 @@ export class ImageLabelBox extends ViewBoxBaseComponent() { }; @action - setSelectedImages = (selected: Doc[]) => { - this._selectedImages = selected; + toggleDisplayInformation = () => { + this._displayImageInformation = !this._displayImageInformation; + }; + + onInputChange = action((e: React.ChangeEvent) => { + this._currentLabel = e.target.value; + }); + + classifyImagesInBox = async () => { + this.startLoading(); + + const imageInfos = this._selectedImages.map(async doc => { + if (!doc[DocData].data_labels) { + const [name, type] = ImageCast(doc[Doc.LayoutFieldKey(doc)]).url.href.split('.'); + return CollectionCardView.imageUrlToBase64(`${name}_o.${type}`).then(hrefBase64 => + !hrefBase64 ? undefined : + gptImageLabel(hrefBase64).then(labels => + Promise.all(labels.split('\n').map(label => gptGetEmbedding(label))).then(embeddings => + ({ doc, embeddings, labels }))) ); // prettier-ignore + } + }); // Converts the images into a Base64 format, afterwhich the information is sent to GPT to label them. + + (await Promise.all(imageInfos)).forEach(imageInfo => { + if (imageInfo && imageInfo.embeddings && Array.isArray(imageInfo.embeddings)) { + imageInfo.doc[DocData].data_labels = imageInfo.labels; + numberRange(3).forEach(n => { + imageInfo.doc[`data_labels_embedding_${n + 1}`] = new List(imageInfo.embeddings[n]); + }); + } + }); // Add the labels as fields to each image. + + this.endLoading(); }; render() { @@ -98,14 +161,20 @@ export class ImageLabelBox extends ViewBoxBaseComponent() { ); } + if (this._selectedImages.length === 0) { + return ( +
+

In order to classify and sort images, marquee select the desired images and press the 'Classify and Sort Images' button. Then, add the desired groups for the images to be put in.

+
+ ); + } + return (
{ - this._displayImageInformation = !this._displayImageInformation; - }} + onPointerDown={this.toggleDisplayInformation} icon={this._displayImageInformation ? : } color={MarqueeOptionsMenu.Instance.userColor} style={{ width: '19px' }} @@ -113,6 +182,7 @@ export class ImageLabelBox extends ViewBoxBaseComponent() { { // e.key === 'Enter' ? this.submitSearch() : null; // e.stopPropagation(); @@ -129,8 +199,7 @@ export class ImageLabelBox extends ViewBoxBaseComponent() { tooltip={'Add a label'} onPointerDown={() => { const input = document.getElementById('new-label') as HTMLInputElement; - const newLabel = input.value; - this.addLabel(newLabel); + ImageLabelBoxData.Instance.addLabel(this._currentLabel); this._currentLabel = ''; input.value = ''; }} @@ -144,12 +213,12 @@ export class ImageLabelBox extends ViewBoxBaseComponent() {
{this._labelGroups.map(group => { return ( -
+

{group}

{ - this.removeLabel(group); + ImageLabelBoxData.Instance.removeLabel(group); }} icon={'x'} color={MarqueeOptionsMenu.Instance.userColor} @@ -161,15 +230,21 @@ export class ImageLabelBox extends ViewBoxBaseComponent() {
{this._displayImageInformation ? ( -
+
{this._selectedImages.map(doc => { const [name, type] = ImageCast(doc[Doc.LayoutFieldKey(doc)]).url.href.split('.'); return ( -
+
- {(doc[DocData].data_labels as string).split('\n').map(label => { - return
{label}
; - })} +
+ {(doc[DocData].data_labels as string).split('\n').map(label => { + return ( +
+ {label} +
+ ); + })} +
); })} diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx index f98883bff..81f2a94c1 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx @@ -37,7 +37,7 @@ import { ImageLabelHandler } from './ImageLabelHandler'; import { MarqueeOptionsMenu } from './MarqueeOptionsMenu'; import './MarqueeView.scss'; import { MainView } from '../../MainView'; -import { ImageLabelBox } from './ImageLabelBox'; +import { ImageLabelBox, ImageLabelBoxData } from './ImageLabelBox'; import { SearchBox } from '../../search/SearchBox'; interface MarqueeViewProps { @@ -442,44 +442,12 @@ export class MarqueeView extends ObservableReactComponent { - if (e) { - const groupButton = DocListCast(Doc.MyLeftSidebarMenu.data).find(d => d.target === Doc.MyImageGrouper); - if (groupButton) { - MainView.Instance.expandFlyout(groupButton); - while (!ImageLabelBox.Instance) { - await new Promise(resolve => setTimeout(resolve, 1000)).then(() => { - console.log('Waiting for Image Label Box'); - }); - } - ImageLabelBox.Instance.startLoading(); - } + const groupButton = DocListCast(Doc.MyLeftSidebarMenu.data).find(d => d.target === Doc.MyImageGrouper); + if (groupButton) { + this._selectedDocs = this.marqueeSelect(false, DocumentType.IMG); + ImageLabelBoxData.Instance.setData(this._selectedDocs); + MainView.Instance.expandFlyout(groupButton); } - - this._selectedDocs = this.marqueeSelect(false, DocumentType.IMG); // Get the selected documents from the marquee select. - ImageLabelBox.Instance!.setSelectedImages(this._selectedDocs); - - const imageInfos = this._selectedDocs.map(async doc => { - if (!doc[DocData].data_labels) { - const [name, type] = ImageCast(doc[Doc.LayoutFieldKey(doc)]).url.href.split('.'); - return CollectionCardView.imageUrlToBase64(`${name}_o.${type}`).then(hrefBase64 => - !hrefBase64 ? undefined : - gptImageLabel(hrefBase64).then(labels => - Promise.all(labels.split('\n').map(label => gptGetEmbedding(label))).then(embeddings => - ({ doc, embeddings, labels }))) ); // prettier-ignore - } - }); // Converts the images into a Base64 format, afterwhich the information is sent to GPT to label them. - - (await Promise.all(imageInfos)).forEach(imageInfo => { - if (imageInfo && imageInfo.embeddings && Array.isArray(imageInfo.embeddings)) { - imageInfo.doc[DocData].data_labels = imageInfo.labels; - numberRange(3).forEach(n => { - imageInfo.doc[`data_labels_embedding_${n + 1}`] = new List(imageInfo.embeddings[n]); - }); - } - }); // Add the labels as fields to each image. - - ImageLabelBox.Instance!.endLoading(); - console.log(this._selectedDocs); }); /** @@ -496,7 +464,7 @@ export class MarqueeView extends ObservableReactComponent { const embedLists = numberRange(3).map(n => Array.from(NumListCast(doc[`data_labels_embedding_${n + 1}`]))); - const bestEmbedScore = (embedding: Opt) => Math.max(...embedLists.map(l => (embedding && similarity(Array.from(embedding), l)) || 0)); + const bestEmbedScore = (embedding: Opt) => Math.max(...embedLists.map((l, index) => (embedding && (1 - index * 0.1) * similarity(Array.from(embedding), l)!) || 0)); const {label: mostSimilarLabelCollect} = labelGroups.map(label => ({ label, similarityScore: bestEmbedScore(labelToEmbedding.get(label)) })) .reduce((prev, cur) => cur.similarityScore < 0.3 || cur.similarityScore <= prev.similarityScore ? prev: cur, -- cgit v1.2.3-70-g09d2 From 8aee62b8623e23f6478960291857ee47f50f9aaf Mon Sep 17 00:00:00 2001 From: IEatChili Date: Thu, 13 Jun 2024 16:28:24 -0400 Subject: feat: more ui updates --- .../collectionFreeForm/ImageLabelBox.tsx | 81 +++++++++++++++++++--- .../collections/collectionFreeForm/MarqueeView.tsx | 22 +----- src/client/views/nodes/ImageBox.tsx | 4 ++ 3 files changed, 76 insertions(+), 31 deletions(-) (limited to 'src') diff --git a/src/client/views/collections/collectionFreeForm/ImageLabelBox.tsx b/src/client/views/collections/collectionFreeForm/ImageLabelBox.tsx index f5530ccc4..571a4504f 100644 --- a/src/client/views/collections/collectionFreeForm/ImageLabelBox.tsx +++ b/src/client/views/collections/collectionFreeForm/ImageLabelBox.tsx @@ -3,9 +3,9 @@ import { Colors, IconButton } from 'browndash-components'; import { action, computed, makeObservable, observable, reaction } from 'mobx'; import { observer } from 'mobx-react'; import React from 'react'; -import { Doc } from '../../../../fields/Doc'; +import { Doc, NumListCast, Opt } from '../../../../fields/Doc'; import { Docs } from '../../../documents/Documents'; -import { DocumentType } from '../../../documents/DocumentTypes'; +import { CollectionViewType, DocumentType } from '../../../documents/DocumentTypes'; import { ViewBoxBaseComponent } from '../../DocComponent'; import { FieldView, FieldViewProps } from '../../nodes/FieldView'; import { MarqueeOptionsMenu } from './MarqueeOptionsMenu'; @@ -21,6 +21,9 @@ import { CollectionCardView } from '../CollectionCardDeckView'; import { gptGetEmbedding, gptImageLabel } from '../../../apis/gpt/GPT'; import { numberRange, Utils } from '../../../../Utils'; import { List } from '../../../../fields/List'; +import { DragManager } from '../../../util/DragManager'; +import { OpenWhere } from '../../nodes/OpenWhere'; +import similarity from 'compute-cosine-similarity'; export class ImageLabelBoxData { static _instance: ImageLabelBoxData; @@ -63,11 +66,26 @@ export class ImageLabelBox extends ViewBoxBaseComponent() { return FieldView.LayoutString(ImageLabelBox, fieldKey); } + private _dropDisposer?: DragManager.DragDropDisposer; public static Instance: ImageLabelBox; private _inputRef = React.createRef(); @observable _loading: boolean = false; private _currentLabel: string = ''; + protected createDropTarget = (ele: HTMLDivElement) => { + this._dropDisposer?.(); + ele && (this._dropDisposer = DragManager.MakeDropTarget(ele, this.onInternalDrop.bind(this), this.layoutDoc)); + }; + + protected onInternalDrop(e: Event, de: DragManager.DropEvent): boolean { + const { docDragData } = de.complete; + if (docDragData) { + ImageLabelBoxData.Instance.setData(ImageLabelBoxData.Instance._docs.concat(docDragData.droppedDocuments)); + return false; + } + return false; + } + @computed get _labelGroups() { return ImageLabelBoxData.Instance._labelGroups; } @@ -102,7 +120,7 @@ export class ImageLabelBox extends ViewBoxBaseComponent() { @action groupImages = () => { - MarqueeOptionsMenu.Instance.groupImages(); + this.groupImagesInBox(); MainView.Instance.closeFlyout(); }; @@ -122,6 +140,14 @@ export class ImageLabelBox extends ViewBoxBaseComponent() { this._displayImageInformation = !this._displayImageInformation; }; + @action + submitLabel = () => { + const input = document.getElementById('new-label') as HTMLInputElement; + ImageLabelBoxData.Instance.addLabel(this._currentLabel); + this._currentLabel = ''; + input.value = ''; + }; + onInputChange = action((e: React.ChangeEvent) => { this._currentLabel = e.target.value; }); @@ -143,6 +169,13 @@ export class ImageLabelBox extends ViewBoxBaseComponent() { (await Promise.all(imageInfos)).forEach(imageInfo => { if (imageInfo && imageInfo.embeddings && Array.isArray(imageInfo.embeddings)) { imageInfo.doc[DocData].data_labels = imageInfo.labels; + + const labels = imageInfo.labels.split('\n'); + labels.forEach(label => { + label = label.replace(/^\d+\.\s*/, '').trim(); + imageInfo.doc[DocData][`${label}`] = true; + }); + numberRange(3).forEach(n => { imageInfo.doc[`data_labels_embedding_${n + 1}`] = new List(imageInfo.embeddings[n]); }); @@ -152,6 +185,32 @@ export class ImageLabelBox extends ViewBoxBaseComponent() { this.endLoading(); }; + /** + * Groups images to most similar labels. + */ + groupImagesInBox = action(async () => { + console.log('Calling!'); + const labelToEmbedding = new Map(); + // Create embeddings for the labels. + await Promise.all(this._labelGroups.map(async label => gptGetEmbedding(label).then(labelEmbedding => labelToEmbedding.set(label, labelEmbedding)))); + + // For each image, loop through the labels, and calculate similarity. Associate it with the + // most similar one. + this._selectedImages.forEach(doc => { + const embedLists = numberRange(3).map(n => Array.from(NumListCast(doc[`data_labels_embedding_${n + 1}`]))); + const bestEmbedScore = (embedding: Opt) => Math.max(...embedLists.map((l, index) => (embedding && (1 - index * 0.1) * similarity(Array.from(embedding), l)!) || 0)); + const {label: mostSimilarLabelCollect} = + this._labelGroups.map(label => ({ label, similarityScore: bestEmbedScore(labelToEmbedding.get(label)) })) + .reduce((prev, cur) => cur.similarityScore < 0.3 || cur.similarityScore <= prev.similarityScore ? prev: cur, + { label: '', similarityScore: 0, }); // prettier-ignore + doc[DocData].data_label = mostSimilarLabelCollect; // The label most similar to the image's contents. + }); + + if (this._selectedImages) { + MarqueeOptionsMenu.Instance.groupImages(); + } + }); + render() { if (this._loading) { return ( @@ -163,14 +222,14 @@ export class ImageLabelBox extends ViewBoxBaseComponent() { if (this._selectedImages.length === 0) { return ( -
+
this.createDropTarget(ele)}>

In order to classify and sort images, marquee select the desired images and press the 'Classify and Sort Images' button. Then, add the desired groups for the images to be put in.

); } return ( -
+
this.createDropTarget(ele)}>
() { defaultValue="" autoComplete="off" onChange={this.onInputChange} - // onKeyDown={e => { - // e.key === 'Enter' ? this.submitSearch() : null; - // e.stopPropagation(); - // }} + onKeyDown={e => { + e.key === 'Enter' ? this.submitLabel() : null; + e.stopPropagation(); + }} type="text" - placeholder="Input labels for image groupings..." + placeholder="Input groups for images to be put into..." aria-label="label-input" id="new-label" className="searchBox-input" @@ -234,7 +293,7 @@ export class ImageLabelBox extends ViewBoxBaseComponent() { {this._selectedImages.map(doc => { const [name, type] = ImageCast(doc[Doc.LayoutFieldKey(doc)]).url.href.split('.'); return ( -
+
this._props.addDocTab(doc, OpenWhere.addRightKeyvalue)}>
{(doc[DocData].data_labels as string).split('\n').map(label => { diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx index 81f2a94c1..f03a9d62d 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx @@ -455,26 +455,8 @@ export class MarqueeView extends ObservableReactComponent { - const labelGroups = ImageLabelBox.Instance!._labelGroups; - const labelToEmbedding = new Map(); - // Create embeddings for the labels. - await Promise.all(labelGroups.map(async label => gptGetEmbedding(label).then(labelEmbedding => labelToEmbedding.set(label, labelEmbedding)))); - - // For each image, loop through the labels, and calculate similarity. Associate it with the - // most similar one. - this._selectedDocs.forEach(doc => { - const embedLists = numberRange(3).map(n => Array.from(NumListCast(doc[`data_labels_embedding_${n + 1}`]))); - const bestEmbedScore = (embedding: Opt) => Math.max(...embedLists.map((l, index) => (embedding && (1 - index * 0.1) * similarity(Array.from(embedding), l)!) || 0)); - const {label: mostSimilarLabelCollect} = - labelGroups.map(label => ({ label, similarityScore: bestEmbedScore(labelToEmbedding.get(label)) })) - .reduce((prev, cur) => cur.similarityScore < 0.3 || cur.similarityScore <= prev.similarityScore ? prev: cur, - { label: '', similarityScore: 0, }); // prettier-ignore - doc[DocData].data_label = mostSimilarLabelCollect; // The label most similar to the image's contents. - }); - if (this._selectedDocs) { - this._props.Document._type_collection = CollectionViewType.Time; // Change the collection view to a Time view. - this._props.Document.pivotField = 'data_label'; // Sets the pivot to be the 'data_label'. - } + this._props.Document._type_collection = CollectionViewType.Time; // Change the collection view to a Time view. + this._props.Document.pivotField = 'data_label'; // Sets the pivot to be the 'data_label'. }); @undoBatch diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx index e4b3a1b9b..3da878a4f 100644 --- a/src/client/views/nodes/ImageBox.tsx +++ b/src/client/views/nodes/ImageBox.tsx @@ -173,6 +173,10 @@ export class ImageBox extends ViewBoxAnnotatableComponent() { Doc.SetNativeHeight(this.dataDoc, Doc.NativeHeight(targetDoc), this.fieldKey); } } + const layoutDoc = de.complete.docDragData?.draggedDocuments[0]; + const targetField = Doc.LayoutFieldKey(layoutDoc); + const targetDoc = layoutDoc[DocData]; + console.log(targetDoc[targetField]); added === false && e.preventDefault(); added !== undefined && e.stopPropagation(); return added; -- cgit v1.2.3-70-g09d2 From 376ff1626b24cbac12b27ad072690424549f05c7 Mon Sep 17 00:00:00 2001 From: IEatChili Date: Tue, 18 Jun 2024 14:33:47 -0400 Subject: feat: added view of labels on docs in freeform --- src/client/views/KeywordBox.tsx | 69 +++++++++++++++++++ src/client/views/StyleProvider.scss | 13 ++++ src/client/views/StyleProvider.tsx | 9 +++ .../collectionFreeForm/ImageLabelBox.tsx | 79 ++++++++++++++++------ src/client/views/nodes/DocumentView.tsx | 2 +- src/client/views/nodes/ImageBox.tsx | 9 +++ 6 files changed, 161 insertions(+), 20 deletions(-) create mode 100644 src/client/views/KeywordBox.tsx (limited to 'src') diff --git a/src/client/views/KeywordBox.tsx b/src/client/views/KeywordBox.tsx new file mode 100644 index 000000000..3faddeb64 --- /dev/null +++ b/src/client/views/KeywordBox.tsx @@ -0,0 +1,69 @@ +import { action, makeObservable } from 'mobx'; +import { observer } from 'mobx-react'; +import React from 'react'; +import { Doc } from '../../fields/Doc'; +import { DocData } from '../../fields/DocSymbols'; +import { List } from '../../fields/List'; +import { ObservableReactComponent } from './ObservableReactComponent'; + +interface KeywordBoxProps { + _doc: Doc; + _isEditing: boolean; +} + +@observer +export class KeywordBox extends ObservableReactComponent { + constructor(props: any) { + super(props); + makeObservable(this); + } + + @action + setToEditing = () => { + this._props._isEditing = true; + }; + + @action + setToView = () => { + this._props._isEditing = false; + }; + + submitLabel = () => {}; + + onInputChange = () => {}; + + render() { + const keywordsList = this._props._doc![DocData].data_labels; + return ( +
+ {(keywordsList as List).map(label => { + return ( +
+ {label} +
+ ); + })} + {this._props._isEditing ? ( +
+ { + e.key === 'Enter' ? this.submitLabel() : null; + e.stopPropagation(); + }} + type="text" + placeholder="Input keywords for document..." + aria-label="keyword-input" + className="keyword-input" + style={{ width: '100%', borderRadius: '5px' }} + /> +
+ ) : ( +
+ )} +
+ ); + } +} diff --git a/src/client/views/StyleProvider.scss b/src/client/views/StyleProvider.scss index ce00f6101..1e2af9a3a 100644 --- a/src/client/views/StyleProvider.scss +++ b/src/client/views/StyleProvider.scss @@ -53,3 +53,16 @@ .styleProvider-treeView-icon { opacity: 0; } + +.keywords-container { + display: flex; + flex-wrap: wrap; +} + +.keyword { + padding: 5px 10px; + background-color: lightblue; + border: 1px solid black; + border-radius: 5px; + white-space: nowrap; +} diff --git a/src/client/views/StyleProvider.tsx b/src/client/views/StyleProvider.tsx index b7f8a3170..fb509516a 100644 --- a/src/client/views/StyleProvider.tsx +++ b/src/client/views/StyleProvider.tsx @@ -12,7 +12,9 @@ import { BsArrowDown, BsArrowDownUp, BsArrowUp } from 'react-icons/bs'; import { FaFilter } from 'react-icons/fa'; import { ClientUtils, DashColor, lightOrDark } from '../../ClientUtils'; import { Doc, Opt, StrListCast } from '../../fields/Doc'; +import { DocData } from '../../fields/DocSymbols'; import { Id } from '../../fields/FieldSymbols'; +import { List } from '../../fields/List'; import { ScriptField } from '../../fields/ScriptField'; import { BoolCast, Cast, DocCast, ImageCast, NumCast, ScriptCast, StrCast } from '../../fields/Types'; import { AudioAnnoState } from '../../server/SharedMediaTypes'; @@ -23,6 +25,7 @@ import { SnappingManager } from '../util/SnappingManager'; import { undoBatch, UndoManager } from '../util/UndoManager'; import { TreeSort } from './collections/TreeSort'; import { Colors } from './global/globalEnums'; +import { KeywordBox } from './KeywordBox'; import { DocumentView, DocumentViewProps } from './nodes/DocumentView'; import { FieldViewProps } from './nodes/FieldView'; import { StyleProp } from './StyleProp'; @@ -367,12 +370,18 @@ export function DefaultStyleProvider(doc: Opt, props: Opt ); }; + const keywords = () => { + if (doc && doc![DocData].data_labels && doc![DocData].showLabels) { + return () + } + } return ( <> {paint()} {lock()} {filter()} {audio()} + {keywords()} ); } diff --git a/src/client/views/collections/collectionFreeForm/ImageLabelBox.tsx b/src/client/views/collections/collectionFreeForm/ImageLabelBox.tsx index 571a4504f..cfb81e1a0 100644 --- a/src/client/views/collections/collectionFreeForm/ImageLabelBox.tsx +++ b/src/client/views/collections/collectionFreeForm/ImageLabelBox.tsx @@ -5,7 +5,7 @@ import { observer } from 'mobx-react'; import React from 'react'; import { Doc, NumListCast, Opt } from '../../../../fields/Doc'; import { Docs } from '../../../documents/Documents'; -import { CollectionViewType, DocumentType } from '../../../documents/DocumentTypes'; +import { DocumentType } from '../../../documents/DocumentTypes'; import { ViewBoxBaseComponent } from '../../DocComponent'; import { FieldView, FieldViewProps } from '../../nodes/FieldView'; import { MarqueeOptionsMenu } from './MarqueeOptionsMenu'; @@ -24,6 +24,9 @@ import { List } from '../../../../fields/List'; import { DragManager } from '../../../util/DragManager'; import { OpenWhere } from '../../nodes/OpenWhere'; import similarity from 'compute-cosine-similarity'; +import { DocumentView } from '../../nodes/DocumentView'; + +export class ImageInformationItem {} export class ImageLabelBoxData { static _instance: ImageLabelBoxData; @@ -101,7 +104,6 @@ export class ImageLabelBox extends ViewBoxBaseComponent() { makeObservable(this); ring.register(); ImageLabelBox.Instance = this; - console.log('Image Box Has Been Initialized'); } // ImageLabelBox.Instance.setData() @@ -127,7 +129,6 @@ export class ImageLabelBox extends ViewBoxBaseComponent() { @action startLoading = () => { this._loading = true; - console.log('Start loading has been called!'); }; @action @@ -138,6 +139,11 @@ export class ImageLabelBox extends ViewBoxBaseComponent() { @action toggleDisplayInformation = () => { this._displayImageInformation = !this._displayImageInformation; + if (this._displayImageInformation) { + this._selectedImages.forEach(doc => (doc[DocData].showLabels = true)); + } else { + this._selectedImages.forEach(doc => (doc[DocData].showLabels = false)); + } }; @action @@ -155,33 +161,58 @@ export class ImageLabelBox extends ViewBoxBaseComponent() { classifyImagesInBox = async () => { this.startLoading(); + // const imageInfos = this._selectedImages.map(async doc => { + // if (!doc[DocData].data_labels) { + // const [name, type] = ImageCast(doc[Doc.LayoutFieldKey(doc)]).url.href.split('.'); + // return CollectionCardView.imageUrlToBase64(`${name}_o.${type}`).then(hrefBase64 => + // !hrefBase64 ? undefined : + // gptImageLabel(hrefBase64).then(labels => + // Promise.all(labels.split('\n').map(label => gptGetEmbedding(label))).then(embeddings => + // ({ doc, embeddings, labels }))) ); // prettier-ignore + // } + // }); // Converts the images into a Base64 format, afterwhich the information is sent to GPT to label them. + const imageInfos = this._selectedImages.map(async doc => { if (!doc[DocData].data_labels) { const [name, type] = ImageCast(doc[Doc.LayoutFieldKey(doc)]).url.href.split('.'); return CollectionCardView.imageUrlToBase64(`${name}_o.${type}`).then(hrefBase64 => !hrefBase64 ? undefined : gptImageLabel(hrefBase64).then(labels => - Promise.all(labels.split('\n').map(label => gptGetEmbedding(label))).then(embeddings => - ({ doc, embeddings, labels }))) ); // prettier-ignore + + ({ doc, labels }))) ; // prettier-ignore } - }); // Converts the images into a Base64 format, afterwhich the information is sent to GPT to label them. + }); (await Promise.all(imageInfos)).forEach(imageInfo => { - if (imageInfo && imageInfo.embeddings && Array.isArray(imageInfo.embeddings)) { - imageInfo.doc[DocData].data_labels = imageInfo.labels; + if (imageInfo) { + imageInfo.doc[DocData].data_labels = new List(); const labels = imageInfo.labels.split('\n'); labels.forEach(label => { - label = label.replace(/^\d+\.\s*/, '').trim(); + label = label.replace(/^\d+\.\s*|-|\*/, '').trim(); imageInfo.doc[DocData][`${label}`] = true; - }); - - numberRange(3).forEach(n => { - imageInfo.doc[`data_labels_embedding_${n + 1}`] = new List(imageInfo.embeddings[n]); + (imageInfo.doc[DocData].data_labels as List).push(label); }); } }); // Add the labels as fields to each image. + // (await Promise.all(imageInfos)).forEach(imageInfo => { + // if (imageInfo && imageInfo.embeddings && Array.isArray(imageInfo.embeddings)) { + // imageInfo.doc[DocData].data_labels = new List(); + + // const labels = imageInfo.labels.split('\n'); + // labels.forEach(label => { + // label = label.replace(/^\d+\.\s*|-|\*/, '').trim(); + // imageInfo.doc[DocData][`${label}`] = true; + // (imageInfo.doc[DocData].data_labels as List).push(label); + // }); + + // numberRange(5).forEach(n => { + // imageInfo.doc[`data_labels_embedding_${n + 1}`] = new List(imageInfo.embeddings[n]); + // }); + // } + // }); // Add the labels as fields to each image. + this.endLoading(); }; @@ -189,7 +220,13 @@ export class ImageLabelBox extends ViewBoxBaseComponent() { * Groups images to most similar labels. */ groupImagesInBox = action(async () => { - console.log('Calling!'); + this._selectedImages.forEach(doc => { + (doc[DocData].data_labels as List).forEach(async (label, index) => { + const embedding = await gptGetEmbedding(label); + doc[`data_labels_embedding_${index + 1}`] = new List(embedding); + }); + }); + const labelToEmbedding = new Map(); // Create embeddings for the labels. await Promise.all(this._labelGroups.map(async label => gptGetEmbedding(label).then(labelEmbedding => labelToEmbedding.set(label, labelEmbedding)))); @@ -197,7 +234,7 @@ export class ImageLabelBox extends ViewBoxBaseComponent() { // For each image, loop through the labels, and calculate similarity. Associate it with the // most similar one. this._selectedImages.forEach(doc => { - const embedLists = numberRange(3).map(n => Array.from(NumListCast(doc[`data_labels_embedding_${n + 1}`]))); + const embedLists = numberRange(5).map(n => Array.from(NumListCast(doc[`data_labels_embedding_${n + 1}`]))); const bestEmbedScore = (embedding: Opt) => Math.max(...embedLists.map((l, index) => (embedding && (1 - index * 0.1) * similarity(Array.from(embedding), l)!) || 0)); const {label: mostSimilarLabelCollect} = this._labelGroups.map(label => ({ label, similarityScore: bestEmbedScore(labelToEmbedding.get(label)) })) @@ -293,10 +330,14 @@ export class ImageLabelBox extends ViewBoxBaseComponent() { {this._selectedImages.map(doc => { const [name, type] = ImageCast(doc[Doc.LayoutFieldKey(doc)]).url.href.split('.'); return ( -
this._props.addDocTab(doc, OpenWhere.addRightKeyvalue)}> - -
- {(doc[DocData].data_labels as string).split('\n').map(label => { +
+ { + await DocumentView.showDocument(doc, { willZoomCentered: true }); + }}> +
this._props.addDocTab(doc, OpenWhere.addRightKeyvalue)}> + {(doc[DocData].data_labels as List).map(label => { return (
{label} diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 7a1f94948..9ff96c692 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -573,7 +573,7 @@ export class DocumentViewInternal extends DocComponent DocumentView.SetLightboxDoc(this.Document), icon: 'external-link-alt' }); } - appearanceItems.push({ description: 'Pin', event: () => this._props.pinToPres(this.Document, {}), icon: 'eye' }); + appearanceItems.push({ description: 'Pin', event: () => this._props.pinToPres(this.Document, {}), icon: 'map-pin' }); if (this.Document._layout_isFlashcard) { appearanceItems.push({ description: 'Create ChatCard', event: () => this.askGPT(), icon: 'id-card' }); } diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx index 3da878a4f..fb90f907f 100644 --- a/src/client/views/nodes/ImageBox.tsx +++ b/src/client/views/nodes/ImageBox.tsx @@ -1,5 +1,6 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { Tooltip } from '@mui/material'; +import zIndex from '@mui/material/styles/zIndex'; import { Colors } from 'browndash-components'; import { action, computed, IReactionDisposer, makeObservable, observable, ObservableMap, reaction } from 'mobx'; import { observer } from 'mobx-react'; @@ -10,6 +11,7 @@ import { Doc, DocListCast, Opt } from '../../../fields/Doc'; import { DocData } from '../../../fields/DocSymbols'; import { Id } from '../../../fields/FieldSymbols'; import { InkTool } from '../../../fields/InkField'; +import { List } from '../../../fields/List'; import { ObjectField } from '../../../fields/ObjectField'; import { Cast, ImageCast, NumCast, StrCast } from '../../../fields/Types'; import { ImageField } from '../../../fields/URLField'; @@ -281,6 +283,13 @@ export class ImageBox extends ViewBoxAnnotatableComponent() { }), icon: 'pencil-alt', }); + funcs.push({ + description: 'Toggle Keywords', + event: () => { + this.Document[DocData].showLabels = !this.Document[DocData].showLabels; + }, + icon: 'eye', + }); ContextMenu.Instance?.addItem({ description: 'Options...', subitems: funcs, icon: 'asterisk' }); } }; -- cgit v1.2.3-70-g09d2 From 3190f1eb07a47a5e1ccdd20e346b47094118292d Mon Sep 17 00:00:00 2001 From: IEatChili Date: Wed, 26 Jun 2024 13:58:20 -0400 Subject: feat: worked more on keyword input for docs --- src/client/views/DocumentButtonBar.tsx | 19 +++ src/client/views/DocumentDecorations.tsx | 1 + src/client/views/KeywordBox.tsx | 168 +++++++++++++++++---- src/client/views/StyleProvider.scss | 31 +++- src/client/views/StyleProvider.tsx | 6 +- .../collectionFreeForm/ImageLabelBox.tsx | 53 ++----- .../collections/collectionFreeForm/MarqueeView.tsx | 28 +++- src/client/views/nodes/ImageBox.tsx | 7 - 8 files changed, 233 insertions(+), 80 deletions(-) (limited to 'src') diff --git a/src/client/views/DocumentButtonBar.tsx b/src/client/views/DocumentButtonBar.tsx index 487868169..a75c7098c 100644 --- a/src/client/views/DocumentButtonBar.tsx +++ b/src/client/views/DocumentButtonBar.tsx @@ -31,6 +31,7 @@ import { DocumentLinksButton } from './nodes/DocumentLinksButton'; import { DocumentView } from './nodes/DocumentView'; import { OpenWhere } from './nodes/OpenWhere'; import { DashFieldView } from './nodes/formattedText/DashFieldView'; +import { DocData } from '../../fields/DocSymbols'; @observer export class DocumentButtonBar extends ObservableReactComponent<{ views: () => (DocumentView | undefined)[]; stack?: any }> { @@ -282,6 +283,23 @@ export class DocumentButtonBar extends ObservableReactComponent<{ views: () => ( ); } + @computed + get keywordButton() { + const targetDoc = this.view0?.Document; + return !targetDoc ? null : ( + Open keyword menu
}> +
{ + targetDoc[DocData].showLabels = !targetDoc[DocData].showLabels; + }}> + +
+ + ); + } + @observable _isRecording = false; _stopFunc: () => void = emptyFunction; @computed @@ -452,6 +470,7 @@ export class DocumentButtonBar extends ObservableReactComponent<{ views: () => (
{this.pinButton}
{this.recordButton}
{this.calendarButton}
+
{this.keywordButton}
{!Doc.UserDoc().documentLinksButton_fullMenu ? null :
{this.shareButton}
}
{this.menuButton}
diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index 93c3e3338..20bf8fd9f 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -88,6 +88,7 @@ export class DocumentDecorations extends ObservableReactComponent center.x+x || this.Bounds.r < center.x+x || this.Bounds.y > center.y+y || this.Bounds.b < center.y+y ))); + })); // prettier-ignore } diff --git a/src/client/views/KeywordBox.tsx b/src/client/views/KeywordBox.tsx index 3faddeb64..8c69f446d 100644 --- a/src/client/views/KeywordBox.tsx +++ b/src/client/views/KeywordBox.tsx @@ -1,64 +1,170 @@ -import { action, makeObservable } from 'mobx'; +import { Colors, IconButton } from 'browndash-components'; +import { action, computed, makeObservable, observable, reaction } from 'mobx'; import { observer } from 'mobx-react'; import React from 'react'; import { Doc } from '../../fields/Doc'; import { DocData } from '../../fields/DocSymbols'; import { List } from '../../fields/List'; +import { DragManager, SetupDrag } from '../util/DragManager'; +import { SnappingManager } from '../util/SnappingManager'; +import { DocumentView } from './nodes/DocumentView'; import { ObservableReactComponent } from './ObservableReactComponent'; +interface KeywordItemProps { + doc: Doc; + label: string; + setToEditing: () => void; + isEditing: boolean; +} + +@observer +export class KeywordItem extends ObservableReactComponent { + constructor(props: any) { + super(props); + makeObservable(this); + this.ref = React.createRef(); + } + + private _dropDisposer?: DragManager.DragDropDisposer; + private ref: React.RefObject; + + protected createDropTarget = (ele: HTMLDivElement) => { + this._dropDisposer?.(); + SetupDrag(this.ref, () => undefined); + //ele && (this._dropDisposer = DragManager. (ele, this.onInternalDrop.bind(this), this.layoutDoc)); + //ele && (this._dropDisposer = DragManager.MakeDropTarget(ele, this.onInternalDrop.bind(this), this.layoutDoc)); + }; + + @action + removeLabel = () => { + if (this._props.doc[DocData].data_labels) { + this._props.doc[DocData].data_labels = (this._props.doc[DocData].data_labels as List).filter(label => label !== this._props.label) as List; + } + }; + + render() { + return ( +
{}} ref={this.ref}> + {this._props.label} + {this.props.isEditing && } +
+ ); + } +} + interface KeywordBoxProps { - _doc: Doc; - _isEditing: boolean; + doc: Doc; + isEditing: boolean; } @observer export class KeywordBox extends ObservableReactComponent { + @observable _currentInput: string = ''; + //private disposer: () => void; + constructor(props: any) { super(props); makeObservable(this); } + // componentDidMount(): void { + // reaction( + // () => ({ + // isDragging: SnappingManager.IsDragging, + // selectedDoc: DocumentView.SelectedDocs().lastElement(), + // isEditing: this._props.isEditing, + // }), + // ({ isDragging, selectedDoc, isEditing }) => { + // if (isDragging || selectedDoc !== this._props.doc || !isEditing) { + // this.setToView(); + // } + // } + // ); + // } + + // componentWillUnmount() { + // this.disposer(); + // } + @action setToEditing = () => { - this._props._isEditing = true; + this._props.isEditing = true; }; @action setToView = () => { - this._props._isEditing = false; + this._props.isEditing = false; }; - submitLabel = () => {}; + submitLabel = () => { + if (this._currentInput.trim()) { + if (!this._props.doc[DocData].data_labels) { + this._props.doc[DocData].data_labels = new List(); + } - onInputChange = () => {}; + (this._props.doc![DocData].data_labels! as List).push(this._currentInput.trim()); + this._currentInput = ''; // Clear the input box + } + }; + + @action + onInputChange = (e: React.ChangeEvent) => { + this._currentInput = e.target.value; + }; render() { - const keywordsList = this._props._doc![DocData].data_labels; + const keywordsList = this._props.doc[DocData].data_labels ? this._props.doc[DocData].data_labels : new List(); + const seldoc = DocumentView.SelectedDocs().lastElement(); + if (SnappingManager.IsDragging || !(seldoc === this._props.doc) || !this._props.isEditing) { + setTimeout( + action(() => { + if ((keywordsList as List).length === 0) { + this._props.doc[DocData].showLabels = false; + } + this.setToView(); + }) + ); + } + return ( -
- {(keywordsList as List).map(label => { - return ( -
- {label} +
+
+ {(keywordsList as List).map(label => { + return ; + })} +
+ {this._props.isEditing ? ( +
+
+ { + e.key === 'Enter' ? this.submitLabel() : null; + e.stopPropagation(); + }} + type="text" + placeholder="Input keywords for document..." + aria-label="keyword-input" + className="keyword-input" + style={{ width: '100%', borderRadius: '5px' }} + /> +
+
+ { + if ((keywordsList as List).length === 0) { + this._props.doc[DocData].showLabels = false; + } else { + this.setToView(); + } + }} + icon={'x'} + style={{ width: '4px' }} + />
- ); - })} - {this._props._isEditing ? ( -
- { - e.key === 'Enter' ? this.submitLabel() : null; - e.stopPropagation(); - }} - type="text" - placeholder="Input keywords for document..." - aria-label="keyword-input" - className="keyword-input" - style={{ width: '100%', borderRadius: '5px' }} - />
) : (
diff --git a/src/client/views/StyleProvider.scss b/src/client/views/StyleProvider.scss index 1e2af9a3a..7cc06f922 100644 --- a/src/client/views/StyleProvider.scss +++ b/src/client/views/StyleProvider.scss @@ -57,12 +57,41 @@ .keywords-container { display: flex; flex-wrap: wrap; + flex-direction: column; + padding-bottom: 4px; + border: 1px solid; + border-radius: 4px; +} + +.keywords-list { + display: flex; + flex-wrap: wrap; } .keyword { - padding: 5px 10px; + padding: 5px 5px; background-color: lightblue; border: 1px solid black; border-radius: 5px; white-space: nowrap; + display: flex; + align-items: center; +} + +.keyword-editing-box { + margin-top: 8px; +} + +.keyword-input-box { + // display: flex; + // align-items: center; + // align-content: center; + margin: auto; + align-self: center; + width: 90%; +} + +.keyword-buttons { + margin-left: auto; + width: 10%; } diff --git a/src/client/views/StyleProvider.tsx b/src/client/views/StyleProvider.tsx index fb509516a..f4d73cd1d 100644 --- a/src/client/views/StyleProvider.tsx +++ b/src/client/views/StyleProvider.tsx @@ -371,8 +371,10 @@ export function DefaultStyleProvider(doc: Opt, props: Opt { - if (doc && doc![DocData].data_labels && doc![DocData].showLabels) { - return () + if (doc && doc![DocData].showLabels && (!doc[DocData].data_labels || (doc[DocData].data_labels as List).length === 0)){ + return () + } else if (doc && doc![DocData].data_labels && doc![DocData].showLabels) { + return () } } return ( diff --git a/src/client/views/collections/collectionFreeForm/ImageLabelBox.tsx b/src/client/views/collections/collectionFreeForm/ImageLabelBox.tsx index cfb81e1a0..fec4d3e12 100644 --- a/src/client/views/collections/collectionFreeForm/ImageLabelBox.tsx +++ b/src/client/views/collections/collectionFreeForm/ImageLabelBox.tsx @@ -123,7 +123,6 @@ export class ImageLabelBox extends ViewBoxBaseComponent() { @action groupImages = () => { this.groupImagesInBox(); - MainView.Instance.closeFlyout(); }; @action @@ -161,16 +160,7 @@ export class ImageLabelBox extends ViewBoxBaseComponent() { classifyImagesInBox = async () => { this.startLoading(); - // const imageInfos = this._selectedImages.map(async doc => { - // if (!doc[DocData].data_labels) { - // const [name, type] = ImageCast(doc[Doc.LayoutFieldKey(doc)]).url.href.split('.'); - // return CollectionCardView.imageUrlToBase64(`${name}_o.${type}`).then(hrefBase64 => - // !hrefBase64 ? undefined : - // gptImageLabel(hrefBase64).then(labels => - // Promise.all(labels.split('\n').map(label => gptGetEmbedding(label))).then(embeddings => - // ({ doc, embeddings, labels }))) ); // prettier-ignore - // } - // }); // Converts the images into a Base64 format, afterwhich the information is sent to GPT to label them. + // Converts the images into a Base64 format, afterwhich the information is sent to GPT to label them. const imageInfos = this._selectedImages.map(async doc => { if (!doc[DocData].data_labels) { @@ -178,8 +168,7 @@ export class ImageLabelBox extends ViewBoxBaseComponent() { return CollectionCardView.imageUrlToBase64(`${name}_o.${type}`).then(hrefBase64 => !hrefBase64 ? undefined : gptImageLabel(hrefBase64).then(labels => - - ({ doc, labels }))) ; // prettier-ignore + ({ doc, labels }))) ; // prettier-ignore } }); @@ -194,24 +183,7 @@ export class ImageLabelBox extends ViewBoxBaseComponent() { (imageInfo.doc[DocData].data_labels as List).push(label); }); } - }); // Add the labels as fields to each image. - - // (await Promise.all(imageInfos)).forEach(imageInfo => { - // if (imageInfo && imageInfo.embeddings && Array.isArray(imageInfo.embeddings)) { - // imageInfo.doc[DocData].data_labels = new List(); - - // const labels = imageInfo.labels.split('\n'); - // labels.forEach(label => { - // label = label.replace(/^\d+\.\s*|-|\*/, '').trim(); - // imageInfo.doc[DocData][`${label}`] = true; - // (imageInfo.doc[DocData].data_labels as List).push(label); - // }); - - // numberRange(5).forEach(n => { - // imageInfo.doc[`data_labels_embedding_${n + 1}`] = new List(imageInfo.embeddings[n]); - // }); - // } - // }); // Add the labels as fields to each image. + }); this.endLoading(); }; @@ -220,12 +192,15 @@ export class ImageLabelBox extends ViewBoxBaseComponent() { * Groups images to most similar labels. */ groupImagesInBox = action(async () => { - this._selectedImages.forEach(doc => { - (doc[DocData].data_labels as List).forEach(async (label, index) => { + this.startLoading(); + + for (const doc of this._selectedImages) { + for (let index = 0; index < (doc[DocData].data_labels as List).length; index++) { + const label = (doc[DocData].data_labels as List)[index]; const embedding = await gptGetEmbedding(label); doc[`data_labels_embedding_${index + 1}`] = new List(embedding); - }); - }); + } + } const labelToEmbedding = new Map(); // Create embeddings for the labels. @@ -234,8 +209,8 @@ export class ImageLabelBox extends ViewBoxBaseComponent() { // For each image, loop through the labels, and calculate similarity. Associate it with the // most similar one. this._selectedImages.forEach(doc => { - const embedLists = numberRange(5).map(n => Array.from(NumListCast(doc[`data_labels_embedding_${n + 1}`]))); - const bestEmbedScore = (embedding: Opt) => Math.max(...embedLists.map((l, index) => (embedding && (1 - index * 0.1) * similarity(Array.from(embedding), l)!) || 0)); + const embedLists = numberRange((doc[DocData].data_labels as List).length).map(n => Array.from(NumListCast(doc[`data_labels_embedding_${n + 1}`]))); + const bestEmbedScore = (embedding: Opt) => Math.max(...embedLists.map((l, index) => (embedding && similarity(Array.from(embedding), l)!) || 0)); const {label: mostSimilarLabelCollect} = this._labelGroups.map(label => ({ label, similarityScore: bestEmbedScore(labelToEmbedding.get(label)) })) .reduce((prev, cur) => cur.similarityScore < 0.3 || cur.similarityScore <= prev.similarityScore ? prev: cur, @@ -243,9 +218,13 @@ export class ImageLabelBox extends ViewBoxBaseComponent() { doc[DocData].data_label = mostSimilarLabelCollect; // The label most similar to the image's contents. }); + this.endLoading(); + if (this._selectedImages) { MarqueeOptionsMenu.Instance.groupImages(); } + + MainView.Instance.closeFlyout(); }); render() { diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx index f03a9d62d..197681f62 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx @@ -455,8 +455,32 @@ export class MarqueeView extends ObservableReactComponent { - this._props.Document._type_collection = CollectionViewType.Time; // Change the collection view to a Time view. - this._props.Document.pivotField = 'data_label'; // Sets the pivot to be the 'data_label'. + const labelGroups: string[] = ImageLabelBoxData.Instance._labelGroups; + const labelToCollection: Map = new Map(); + const selectedImages = ImageLabelBoxData.Instance._docs; + + // Create new collections associated with each label and get the embeddings for the labels. + let x_offset = 0; + for (const label of labelGroups) { + const newCollection = this.getCollection([], undefined, false); + newCollection._freeform_panX = this.Bounds.left + this.Bounds.width / 2; + newCollection._freeform_panY = this.Bounds.top + this.Bounds.height / 2; + console.log(newCollection._x); + labelToCollection.set(label, newCollection); + this._props.addDocument?.(newCollection); + //newCollection._x = (newCollection._x as number) + x_offset; + //x_offset += newCollection._width as number; + } + + for (const doc of selectedImages) { + if (doc[DocData].data_label) { + Doc.AddDocToList(labelToCollection.get(doc[DocData].data_label as string)!, undefined, doc); + this._props.removeDocument?.(doc); + } + } + + //this._props.Document._type_collection = CollectionViewType.Time; // Change the collection view to a Time view. + //this._props.Document.pivotField = 'data_label'; // Sets the pivot to be the 'data_label'. }); @undoBatch diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx index fb90f907f..1c90fae9e 100644 --- a/src/client/views/nodes/ImageBox.tsx +++ b/src/client/views/nodes/ImageBox.tsx @@ -283,13 +283,6 @@ export class ImageBox extends ViewBoxAnnotatableComponent() { }), icon: 'pencil-alt', }); - funcs.push({ - description: 'Toggle Keywords', - event: () => { - this.Document[DocData].showLabels = !this.Document[DocData].showLabels; - }, - icon: 'eye', - }); ContextMenu.Instance?.addItem({ description: 'Options...', subitems: funcs, icon: 'asterisk' }); } }; -- cgit v1.2.3-70-g09d2 From 7e13e1df797f1d3358f553802527bf42c5574e81 Mon Sep 17 00:00:00 2001 From: IEatChili Date: Thu, 27 Jun 2024 13:55:55 -0400 Subject: feat: added grid of collections when sorting --- src/client/views/KeywordBox.tsx | 2 ++ .../collections/collectionFreeForm/MarqueeView.tsx | 21 ++++++++++++++++++--- 2 files changed, 20 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/client/views/KeywordBox.tsx b/src/client/views/KeywordBox.tsx index 8c69f446d..d94f011f4 100644 --- a/src/client/views/KeywordBox.tsx +++ b/src/client/views/KeywordBox.tsx @@ -39,6 +39,7 @@ export class KeywordItem extends ObservableReactComponent { removeLabel = () => { if (this._props.doc[DocData].data_labels) { this._props.doc[DocData].data_labels = (this._props.doc[DocData].data_labels as List).filter(label => label !== this._props.label) as List; + this._props.doc![DocData][`${this._props.label}`] = false; } }; @@ -103,6 +104,7 @@ export class KeywordBox extends ObservableReactComponent { } (this._props.doc![DocData].data_labels! as List).push(this._currentInput.trim()); + this._props.doc![DocData][`${this._currentInput}`] = true; this._currentInput = ''; // Clear the input box } }; diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx index 197681f62..07e3acb1d 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx @@ -461,17 +461,32 @@ export class MarqueeView extends ObservableReactComponent Date: Wed, 17 Jul 2024 15:13:11 -0400 Subject: feat: created smart collections --- src/client/documents/Documents.ts | 9 +- src/client/views/DocumentDecorations.scss | 2 +- src/client/views/DocumentDecorations.tsx | 2 + src/client/views/KeywordBox.tsx | 197 +++++++++++++++++---- src/client/views/StyleProvider.scss | 1 - src/client/views/collections/CollectionSubView.tsx | 4 +- src/client/views/collections/CollectionView.tsx | 1 + .../collectionFreeForm/ImageLabelBox.tsx | 4 +- .../collections/collectionFreeForm/MarqueeView.tsx | 3 - 9 files changed, 174 insertions(+), 49 deletions(-) (limited to 'src') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 449347403..3737aa0b5 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -37,12 +37,13 @@ export enum FInfoFieldType { date = 'date', list = 'list', rtf = 'rich text', + map = 'map', } export class FInfo { description: string = ''; readOnly: boolean = false; fieldType?: FInfoFieldType; - values?: FieldType[]; + values?: FieldType[] | Map; filterable?: boolean = true; // can be used as a Filter in FilterPanel // format?: string; // format to display values (e.g, decimal places, $, etc) @@ -143,6 +144,10 @@ class ListInfo extends FInfo { fieldType? = FInfoFieldType.list; values?: List[] = []; } +class MapInfo extends FInfo { + fieldType? = FInfoFieldType.map; + values?: Map = new Map(); +} type BOOLt = BoolInfo | boolean; type NUMt = NumInfo | number; type STRt = StrInfo | string; @@ -155,6 +160,7 @@ type COLLt = CTypeInfo | CollectionViewType; type DROPt = DAInfo | dropActionType; type DATEt = DateInfo | number; type DTYPEt = DTypeInfo | string; +type MAPt = MapInfo | Map; export class DocumentOptions { // coordinate and dimensions depending on view x?: NUMt = new NumInfo('horizontal coordinate in freeform view', false); @@ -481,6 +487,7 @@ export class DocumentOptions { cardSort?: STRt = new StrInfo('way cards are sorted in deck view'); cardSort_customField?: STRt = new StrInfo('field key used for sorting cards'); cardSort_visibleSortGroups?: List; // which sorting values are being filtered (shown) + keywords?: MAPt = new MapInfo('keywords', true); } export const DocOptions = new DocumentOptions(); diff --git a/src/client/views/DocumentDecorations.scss b/src/client/views/DocumentDecorations.scss index 239c0a977..67e1054c3 100644 --- a/src/client/views/DocumentDecorations.scss +++ b/src/client/views/DocumentDecorations.scss @@ -512,7 +512,7 @@ $resizeHandler: 8px; justify-content: center; align-items: center; gap: 5px; - top: 4px; + //top: 4px; background: $light-gray; opacity: 0.2; pointer-events: all; diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index 20bf8fd9f..dc40562e8 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -640,6 +640,7 @@ export class DocumentDecorations extends ObservableReactComponent { @@ -831,6 +832,7 @@ export class DocumentDecorations extends ObservableReactComponent DocumentView.Selected()} /> diff --git a/src/client/views/KeywordBox.tsx b/src/client/views/KeywordBox.tsx index d94f011f4..321362299 100644 --- a/src/client/views/KeywordBox.tsx +++ b/src/client/views/KeywordBox.tsx @@ -2,17 +2,26 @@ import { Colors, IconButton } from 'browndash-components'; import { action, computed, makeObservable, observable, reaction } from 'mobx'; import { observer } from 'mobx-react'; import React from 'react'; -import { Doc } from '../../fields/Doc'; +import { returnFalse, setupMoveUpEvents } from '../../ClientUtils'; +import { Doc, DocListCast } from '../../fields/Doc'; import { DocData } from '../../fields/DocSymbols'; import { List } from '../../fields/List'; +import { DocCast, NumCast } from '../../fields/Types'; +import { emptyFunction } from '../../Utils'; +import { Docs } from '../documents/Documents'; +import { DocUtils } from '../documents/DocUtils'; import { DragManager, SetupDrag } from '../util/DragManager'; import { SnappingManager } from '../util/SnappingManager'; +import { CollectionFreeFormView } from './collections/collectionFreeForm'; +import { MainView } from './MainView'; import { DocumentView } from './nodes/DocumentView'; import { ObservableReactComponent } from './ObservableReactComponent'; interface KeywordItemProps { doc: Doc; - label: string; + keyword: string; + keywordDoc: Doc; + keywordCollection: Doc[]; setToEditing: () => void; isEditing: boolean; } @@ -25,28 +34,77 @@ export class KeywordItem extends ObservableReactComponent { this.ref = React.createRef(); } - private _dropDisposer?: DragManager.DragDropDisposer; private ref: React.RefObject; - protected createDropTarget = (ele: HTMLDivElement) => { - this._dropDisposer?.(); - SetupDrag(this.ref, () => undefined); - //ele && (this._dropDisposer = DragManager. (ele, this.onInternalDrop.bind(this), this.layoutDoc)); - //ele && (this._dropDisposer = DragManager.MakeDropTarget(ele, this.onInternalDrop.bind(this), this.layoutDoc)); + getKeywordCollectionDocs = () => { + for (const doc of DocListCast(Doc.UserDoc().myKeywordCollections)) { + if (doc.title === this._props.keyword) { + return doc[DocData].docs; + } + } + return null; + }; + + createCollection = () => { + const selected = DocListCast(this.getKeywordCollectionDocs()!); + const newEmbeddings = selected.map(doc => Doc.MakeEmbedding(doc)); + const newCollection = ((doc: Doc) => { + const docData = doc[DocData]; + docData.data = new List(newEmbeddings); + docData.title = this._props.keyword; + doc._freeform_panX = doc._freeform_panY = 0; + return doc; + })(Doc.MakeCopy(Doc.UserDoc().emptyCollection as Doc, true)); + newEmbeddings.forEach(embed => (embed.embedContainer = newCollection)); + newCollection._width = 900; + newCollection._height = 900; + newCollection.layout_fitWidth = true; + //newCollection[DocData].smartCollection = this._props.keywordDoc; + + this._props.keywordDoc.collections = new List([...DocListCast(this._props.keywordDoc.collections), newCollection]); + return newCollection; + }; + + @action + handleDragStart = (e: React.PointerEvent) => { + if (this._props.isEditing) { + const clone = this.ref.current?.cloneNode(true) as HTMLElement; + if (!clone) return; + + setupMoveUpEvents( + this, + e, + () => { + const dragData = new DragManager.DocumentDragData([this.createCollection()]); + DragManager.StartDocumentDrag([this.ref.current!], dragData, e.clientX, e.clientY, {}); + return true; + }, + returnFalse, + emptyFunction + ); + e.preventDefault(); + } }; @action removeLabel = () => { if (this._props.doc[DocData].data_labels) { - this._props.doc[DocData].data_labels = (this._props.doc[DocData].data_labels as List).filter(label => label !== this._props.label) as List; - this._props.doc![DocData][`${this._props.label}`] = false; + const filtered_docs = new List(DocListCast(this.getKeywordCollectionDocs()!).filter(doc => doc !== this._props.doc)); + this._props.keywordDoc[DocData].docs = filtered_docs; + + this._props.doc[DocData].data_labels = (this._props.doc[DocData].data_labels as List).filter(label => label !== this._props.keyword) as List; + this._props.doc![DocData][`${this._props.keyword}`] = false; + + for (const collection of DocListCast(this._props.keywordDoc.collections)) { + collection[DocData].data = new List(DocListCast(collection[DocData].data).filter(doc => !Doc.AreProtosEqual(this._props.doc, doc))); + } } }; render() { return ( -
{}} ref={this.ref}> - {this._props.label} +
+ {this._props.keyword} {this.props.isEditing && }
); @@ -61,31 +119,39 @@ interface KeywordBoxProps { @observer export class KeywordBox extends ObservableReactComponent { @observable _currentInput: string = ''; - //private disposer: () => void; + private height: number = 0; + private ref: React.RefObject; + + @computed + get currentScale() { + return NumCast((this._props.doc.embedContainer as Doc)?._freeform_scale, 1); + } constructor(props: any) { super(props); makeObservable(this); + this.ref = React.createRef(); } - // componentDidMount(): void { - // reaction( - // () => ({ - // isDragging: SnappingManager.IsDragging, - // selectedDoc: DocumentView.SelectedDocs().lastElement(), - // isEditing: this._props.isEditing, - // }), - // ({ isDragging, selectedDoc, isEditing }) => { - // if (isDragging || selectedDoc !== this._props.doc || !isEditing) { - // this.setToView(); - // } - // } - // ); - // } - - // componentWillUnmount() { - // this.disposer(); - // } + componentDidMount(): void { + this.height = this.ref.current?.getBoundingClientRect().height ? this.ref.current?.getBoundingClientRect().height : 0; + this._props.doc._keywordHeight = this.height; + + reaction( + () => this.currentScale, + () => { + if (this.currentScale < 1) { + this.height = this.ref.current?.getBoundingClientRect().height ? this.ref.current?.getBoundingClientRect().height : 0; + this._props.doc._keywordHeight = this.height; + } + } + ); + } + + componentDidUpdate(prevProps: Readonly): void { + this.height = this.ref.current?.getBoundingClientRect().height ? this.ref.current?.getBoundingClientRect().height : 0; + this._props.doc._keywordHeight = this.height; + } @action setToEditing = () => { @@ -97,14 +163,51 @@ export class KeywordBox extends ObservableReactComponent { this._props.isEditing = false; }; + getKeywordCollection = (keyword: string) => { + for (const doc of DocListCast(Doc.UserDoc().myKeywordCollections)) { + if (doc.title === keyword) { + return doc; + } + } + + const keywordCollection = new Doc(); + keywordCollection.title = keyword; + keywordCollection[DocData].docs = new List(); + keywordCollection.collections = new List(); + Doc.UserDoc().myKeywordCollections = new List([...DocListCast(Doc.UserDoc().myKeywordCollections), keywordCollection]); + + return keywordCollection; + }; + submitLabel = () => { - if (this._currentInput.trim()) { + if (!Doc.UserDoc().myKeywordCollections) { + Doc.UserDoc().myKeywordCollections = new List(); + } + + const submittedLabel = this._currentInput.trim(); + if (submittedLabel) { + // If the keyword collection is not in the user doc, add it as a new doc, with the keyword as its title. + const keywordCollection = this.getKeywordCollection(submittedLabel); + + // If the document has no keywords field, create the field. if (!this._props.doc[DocData].data_labels) { this._props.doc[DocData].data_labels = new List(); } - (this._props.doc![DocData].data_labels! as List).push(this._currentInput.trim()); + // Add this document to the keyword's collection of associated documents. + keywordCollection[DocData].docs = new List([...DocListCast(keywordCollection[DocData].docs), this._props.doc]); + + // Push the keyword to the document's keyword list field. + (this._props.doc![DocData].data_labels! as List).push(submittedLabel); this._props.doc![DocData][`${this._currentInput}`] = true; + + // Iterate through the keyword document's collections and add a copy of the document to each collection + for (const collection of DocListCast(keywordCollection.collections)) { + const newEmbedding = Doc.MakeEmbedding(this._props.doc); + collection[DocData].data = new List([...DocListCast(collection.data), newEmbedding]); + newEmbedding.embedContainer = collection; + } + this._currentInput = ''; // Clear the input box } }; @@ -120,19 +223,35 @@ export class KeywordBox extends ObservableReactComponent { if (SnappingManager.IsDragging || !(seldoc === this._props.doc) || !this._props.isEditing) { setTimeout( action(() => { - if ((keywordsList as List).length === 0) { - this._props.doc[DocData].showLabels = false; - } + // if ((keywordsList as List).length === 0) { + // this._props.doc[DocData].showLabels = false; + // } this.setToView(); }) ); } return ( -
+
- {(keywordsList as List).map(label => { - return ; + {(keywordsList as List).map(keyword => { + return ( + + ); })}
{this._props.isEditing ? ( diff --git a/src/client/views/StyleProvider.scss b/src/client/views/StyleProvider.scss index 7cc06f922..4267762aa 100644 --- a/src/client/views/StyleProvider.scss +++ b/src/client/views/StyleProvider.scss @@ -58,7 +58,6 @@ display: flex; flex-wrap: wrap; flex-direction: column; - padding-bottom: 4px; border: 1px solid; border-radius: 4px; } diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx index e250d7a90..26528b2b3 100644 --- a/src/client/views/collections/CollectionSubView.tsx +++ b/src/client/views/collections/CollectionSubView.tsx @@ -1,4 +1,4 @@ -import { action, computed, makeObservable, observable } from 'mobx'; +import { action, computed, IReactionDisposer, makeObservable, observable, reaction } from 'mobx'; import * as React from 'react'; import * as rp from 'request-promise'; import { ClientUtils, returnFalse } from '../../../ClientUtils'; @@ -9,7 +9,7 @@ import { Id } from '../../../fields/FieldSymbols'; import { List } from '../../../fields/List'; import { listSpec } from '../../../fields/Schema'; import { ScriptField } from '../../../fields/ScriptField'; -import { BoolCast, Cast, ScriptCast, StrCast } from '../../../fields/Types'; +import { BoolCast, Cast, DocCast, ScriptCast, StrCast } from '../../../fields/Types'; import { WebField } from '../../../fields/URLField'; import { GetEffectiveAcl, TraceMobx } from '../../../fields/util'; import { GestureUtils } from '../../../pen-gestures/GestureUtils'; diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index 5c304b4a9..a750b731a 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -34,6 +34,7 @@ import { CollectionMulticolumnView } from './collectionMulticolumn/CollectionMul import { CollectionMultirowView } from './collectionMulticolumn/CollectionMultirowView'; import { CollectionSchemaView } from './collectionSchema/CollectionSchemaView'; import { CollectionCardView } from './CollectionCardDeckView'; +import { DocData } from '../../../fields/DocSymbols'; @observer export class CollectionView extends ViewBoxAnnotatableComponent() { diff --git a/src/client/views/collections/collectionFreeForm/ImageLabelBox.tsx b/src/client/views/collections/collectionFreeForm/ImageLabelBox.tsx index fec4d3e12..af01d6cbc 100644 --- a/src/client/views/collections/collectionFreeForm/ImageLabelBox.tsx +++ b/src/client/views/collections/collectionFreeForm/ImageLabelBox.tsx @@ -238,14 +238,14 @@ export class ImageLabelBox extends ViewBoxBaseComponent() { if (this._selectedImages.length === 0) { return ( -
this.createDropTarget(ele)}> +
this.createDropTarget(ele!)}>

In order to classify and sort images, marquee select the desired images and press the 'Classify and Sort Images' button. Then, add the desired groups for the images to be put in.

); } return ( -
this.createDropTarget(ele)}> +
this.createDropTarget(ele!)}>
Date: Thu, 18 Jul 2024 15:31:13 -0400 Subject: starting to remove anys --- src/ClientUtils.ts | 14 +++++++++---- src/client/util/DocumentManager.ts | 1 - .../collectionFreeForm/CollectionFreeFormView.tsx | 4 ++-- .../views/nodes/CollectionFreeFormDocumentView.tsx | 6 +++--- src/client/views/nodes/DocumentView.tsx | 24 +++++++++++----------- src/client/views/nodes/FieldView.tsx | 6 +++--- .../views/nodes/formattedText/FormattedTextBox.tsx | 4 ++-- 7 files changed, 32 insertions(+), 27 deletions(-) (limited to 'src') diff --git a/src/ClientUtils.ts b/src/ClientUtils.ts index 630d7edbc..b890e7bfc 100644 --- a/src/ClientUtils.ts +++ b/src/ClientUtils.ts @@ -479,10 +479,16 @@ export function clearStyleSheetRules(sheet: CSSStyleSheet|null) { return false; } +export class simPointerEvent extends PointerEvent { + dash?: boolean; +} +export class simMouseEvent extends MouseEvent { + dash?: boolean; +} export function simulateMouseClick(element: Element | null | undefined, x: number, y: number, sx: number, sy: number, rightClick = true) { if (!element) return; ['pointerdown', 'pointerup'].forEach(event => { - const me = new PointerEvent(event, { + const me = new simPointerEvent(event, { view: window, bubbles: true, cancelable: true, @@ -493,12 +499,12 @@ export function simulateMouseClick(element: Element | null | undefined, x: numbe screenX: sx, screenY: sy, }); - (me as any).dash = true; + me.dash = true; element.dispatchEvent(me); }); if (rightClick) { - const me = new MouseEvent('contextmenu', { + const me = new simMouseEvent('contextmenu', { view: window, bubbles: true, cancelable: true, @@ -510,7 +516,7 @@ export function simulateMouseClick(element: Element | null | undefined, x: numbe screenX: sx, screenY: sy, }); - (me as any).dash = true; + me.dash = true; element.dispatchEvent(me); } } diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts index 96b8b5657..e41546d09 100644 --- a/src/client/util/DocumentManager.ts +++ b/src/client/util/DocumentManager.ts @@ -356,7 +356,6 @@ export class DocumentManager { if (options.playMedia) docView.ComponentView?.playFrom?.(NumCast(docView.Document._layout_currentTimecode)); if (options.playAudio) DocumentManager.playAudioAnno(docView.Document); if (options.toggleTarget && (!options.didMove || docView.Document.hidden)) docView.Document.hidden = !docView.Document.hidden; - Doc.AddUnHighlightWatcher(() => docView.Document[Animation] = undefined); } } } diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 5b7f09be3..812aa5fa3 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -83,7 +83,7 @@ export class CollectionFreeFormView extends CollectionSubView(); public static from(dv?: DocumentView): CollectionFreeFormView | undefined { - const parent = CollectionFreeFormDocumentView.from(dv)?._props.parent; + const parent = CollectionFreeFormDocumentView.from(dv)?._props.reactParent; return parent instanceof CollectionFreeFormView ? parent : undefined; } @@ -1488,7 +1488,7 @@ export class CollectionFreeFormView extends CollectionSubView boolean; isAnyChildContentActive: () => boolean; - parent: any; + reactParent: React.Component; } @observer export class CollectionFreeFormDocumentView extends DocComponent() { @@ -71,7 +71,7 @@ export class CollectionFreeFormDocumentView extends DocComponent (Doc.LayoutFieldKey(doc) ? [Doc.LayoutFieldKey(doc)] : []); // fields that are configured to be animatable using animation frames public static from(dv?: DocumentView): CollectionFreeFormDocumentView | undefined { - return dv?._props.parent instanceof CollectionFreeFormDocumentView ? dv._props.parent : undefined; + return dv?._props.reactParent instanceof CollectionFreeFormDocumentView ? dv._props.reactParent : undefined; } constructor(props: CollectionFreeFormDocumentViewProps & freeFormProps) { @@ -304,7 +304,7 @@ export class CollectionFreeFormDocumentView extends DocComponent val.lower)).omit} // prettier-ignore - parent={this} + reactParent={this} DataTransition={this.DataTransition} LocalRotation={this.localRotation} CollectionFreeFormDocumentView={this.returnThis} diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index ce7cfa5f4..5bb12d890 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -7,7 +7,7 @@ import { IReactionDisposer, action, computed, makeObservable, observable, reacti import { observer } from 'mobx-react'; import * as React from 'react'; import { Fade, JackInTheBox } from 'react-awesome-reveal'; -import { ClientUtils, DivWidth, isTargetChildOf as isParentOf, lightOrDark, returnFalse, returnVal, simulateMouseClick } from '../../../ClientUtils'; +import { ClientUtils, DivWidth, isTargetChildOf as isParentOf, lightOrDark, returnFalse, returnVal, simMouseEvent, simulateMouseClick } from '../../../ClientUtils'; import { Utils, emptyFunction } from '../../../Utils'; import { Doc, DocListCast, Field, FieldType, Opt, StrListCast } from '../../../fields/Doc'; import { AclAdmin, AclEdit, AclPrivate, Animation, AudioPlay, DocData, DocViews } from '../../../fields/DocSymbols'; @@ -89,7 +89,7 @@ export interface DocumentViewProps extends FieldViewSharedProps { dragStarting?: () => void; dragEnding?: () => void; - parent?: any; // parent React component view (see CollectionFreeFormDocumentView) + reactParent?: React.Component; // parent React component view (see CollectionFreeFormDocumentView) } @observer export class DocumentViewInternal extends DocComponent() { @@ -105,7 +105,7 @@ export class DocumentViewInternal extends DocComponent any); + private _singleClickFunc: undefined | (() => void); private _longPressSelector: NodeJS.Timeout | undefined; private _downX: number = 0; private _downY: number = 0; @@ -224,7 +224,7 @@ export class DocumentViewInternal extends DocComponent this.style(this.Document, StyleProp.PointerEvents), + () => this.style(this.Document, StyleProp.PointerEvents) as ("all" | "none" | "visiblePainted" | undefined), pointerevents => { this._pointerEvents = pointerevents; }, @@ -450,7 +450,7 @@ export class DocumentViewInternal extends DocComponent { if (this.Document.type !== DocumentType.MAP) DocumentViewInternal.SelectAfterContextMenu && this._props.select(false); // on a mac, the context menu is triggered on mouse down, but a YouTube video becaomes interactive when selected which means that the context menu won't show up. by delaying the selection until hopefully after the pointer up, the context menu will appear. setTimeout(() => simulateMouseClick(document.elementFromPoint(e.clientX, e.clientY), e.clientX, e.clientY, e.screenX, e.screenY)); @@ -710,7 +710,7 @@ export class DocumentViewInternal extends DocComponent this._rootSelected; - panelHeight = () => this._props.PanelHeight() - this.headerMargin; + panelHeight = () => this._props.PanelHeight() - Number(this.headerMargin); screenToLocalContent = () => this._props.ScreenToLocalTransform().translate(0, -this.headerMargin); onClickFunc = this.disableClickScriptFunc ? undefined : () => this.onClickHdlr; setHeight = (height: number) => { !this._props.suppressSetHeight && (this.layoutDoc._height = Math.min(NumCast(this.layoutDoc._maxHeight, Number.MAX_SAFE_INTEGER), height)); } // prettier-ignore @@ -722,7 +722,7 @@ export class DocumentViewInternal extends DocComponent this._props.PanelWidth() || 1; anchorPanelHeight = () => this._props.PanelHeight() || 1; - anchorStyleProvider = (doc: Opt, props: Opt, property: string): any => { + anchorStyleProvider = (doc: Opt, props: Opt, property: string) => { // prettier-ignore switch (property.split(':')[0]) { case StyleProp.ShowTitle: return ''; @@ -770,7 +770,7 @@ export class DocumentViewInternal extends DocComponent, props: Opt, property: string) => this._props?.styleProvider?.(doc, props, property + ':caption'); fieldsDropdown = (placeholder: string) => (
{ r && (this._titleDropDownInnerWidth = DivWidth(r));} )} // prettier-ignore + ref=r => { r && runInAction(() => (this._titleDropDownInnerWidth = DivWidth(r);}) )} // prettier-ignore onPointerDown={action(() => { this._changingTitleField = true; })} // prettier-ignore style={{ width: 'max-content', background: SnappingManager.userBackgroundColor, color: SnappingManager.userColor, transformOrigin: 'left', transform: `scale(${this.titleHeight / 30 /* height of Dropdown */})` }}> () {
{DocumentViewInternal.AnimationEffect(
- console.log('PARSE error', e)} renderInWrapper={false} jsx={StrCast(this._htmlOverlayText)} /> + console.log('PARSE error', e)} renderInWrapper={false} jsx={StrCast(this._htmlOverlayText)} />
, { ...(this._htmlOverlayEffect ?? {}), presentation_effect: effect ?? PresEffect.Expand } as any as Doc, this.Document @@ -1461,7 +1461,7 @@ export class DocumentView extends DocComponent() { }}> Opt; // eslint-disable-next-line no-use-before-define -export type StyleProviderFuncType = (doc: Opt, props: Opt, property: string) => any; +export type StyleProviderFuncType = (doc: Opt, props: Opt, property: string) => Opt |{ clipPath: string; jsx: Element; } | JSX.Element | null; // // these properties get assigned through the render() method of the DocumentView when it creates this node. // However, that only happens because the properties are "defined" in the markup for the field view. @@ -45,7 +45,7 @@ export interface FieldViewSharedProps { containerViewPath?: () => DocumentView[]; fitContentsToBox?: () => boolean; // used by freeformview to fit its contents to its panel. corresponds to _freeform_fitContentsToBox property on a Document isGroupActive?: () => string | undefined; // is this document part of a group that is active - setContentViewBox?: (view: ViewBoxInterface) => any; // called by rendered field's viewBox so that DocumentView can make direct calls to the viewBox + setContentViewBox?: (view: ViewBoxInterface) => any; // called by rendered field's viewBox so that DocumentView can make direct calls to the viewBox PanelWidth: () => number; PanelHeight: () => number; isDocumentActive?: () => boolean | undefined; // whether a document should handle pointer events diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx index 5b435e44a..b0c6120d4 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx +++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx @@ -14,7 +14,7 @@ import { EditorState, NodeSelection, Plugin, Selection, TextSelection, Transacti import { EditorView, NodeViewConstructor } from 'prosemirror-view'; import * as React from 'react'; import { BsMarkdownFill } from 'react-icons/bs'; -import { addStyleSheet, addStyleSheetRule, clearStyleSheetRules, ClientUtils, DivWidth, returnFalse, returnZero, setupMoveUpEvents, smoothScroll, StopEvent } from '../../../../ClientUtils'; +import { addStyleSheet, addStyleSheetRule, clearStyleSheetRules, ClientUtils, DivWidth, returnFalse, returnZero, setupMoveUpEvents, simMouseEvent, smoothScroll, StopEvent } from '../../../../ClientUtils'; import { DateField } from '../../../../fields/DateField'; import { CreateLinkToActiveAudio, Doc, DocListCast, Field, FieldType, Opt, StrListCast } from '../../../../fields/Doc'; import { AclAdmin, AclAugment, AclEdit, AclSelfEdit, DocCss, DocData, ForceServerWrite, UpdatingFromServer } from '../../../../fields/DocSymbols'; @@ -821,7 +821,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent node that wraps the hyerlink while (target && !target.dataset?.targethrefs) target = target.parentElement; const editor = this._editorView; - if (editor && target && !(e.nativeEvent as any).dash) { + if (editor && target && !(e.nativeEvent instanceof simMouseEvent ? e.nativeEvent.dash : false)) { const hrefs = (target.dataset?.targethrefs as string) ?.trim() .split(' ') -- cgit v1.2.3-70-g09d2 From ef83179eacbd9cd7296683e9e07b426da18c0647 Mon Sep 17 00:00:00 2001 From: geireann Date: Thu, 18 Jul 2024 15:32:23 -0400 Subject: from last --- src/client/views/StyleProvider.tsx | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/client/views/StyleProvider.tsx b/src/client/views/StyleProvider.tsx index 8c100f238..618f69221 100644 --- a/src/client/views/StyleProvider.tsx +++ b/src/client/views/StyleProvider.tsx @@ -72,7 +72,7 @@ export function SetFilterOpener(func: () => void) { // a preliminary implementation of a dash style sheet for setting rendering properties of documents nested within a Tab // -export function DefaultStyleProvider(doc: Opt, props: Opt, property: string): any { +export function DefaultStyleProvider(doc: Opt, props: Opt, property: string) { const remoteDocHeader = 'author;author_date;noMargin'; const isCaption = property.includes(':caption'); const isAnchor = property.includes(':anchor'); @@ -110,9 +110,9 @@ export function DefaultStyleProvider(doc: Opt, props: Opt doc && BoolCast(doc._lockedPosition); const titleHeight = () => styleProvider?.(doc, props, StyleProp.TitleHeight); const backgroundCol = () => styleProvider?.(doc, props, StyleProp.BackgroundColor + ':nonTransparent' + (isNonTransparentLevel + 1)); - const color = () => styleProvider?.(doc, props, StyleProp.Color); + const color = () => styleProvider?.(doc, props, StyleProp.Color) as string; const opacity = () => styleProvider?.(doc, props, StyleProp.Opacity); - const layoutShowTitle = () => styleProvider?.(doc, props, StyleProp.ShowTitle); + const layoutShowTitle = () => styleProvider?.(doc, props, StyleProp.ShowTitle) as string; // prettier-ignore switch (property.split(':')[0]) { case StyleProp.TreeViewIcon: { @@ -152,7 +152,7 @@ export function DefaultStyleProvider(doc: Opt, props: Opt, props: Opt, props: Opt Date: Thu, 18 Jul 2024 15:32:40 -0400 Subject: from last --- src/client/views/nodes/DocumentView.tsx | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 5bb12d890..24cb4ccf6 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -134,15 +134,15 @@ export class DocumentViewInternal extends DocComponent this._animateScaleTime ?? 100; style = (doc: Doc, sprop: StyleProp | string) => this._props.styleProvider?.(doc, this._props, sprop); - @computed get opacity() { return this.style(this.layoutDoc, StyleProp.Opacity); } // prettier-ignore + @computed get opacity() { return this.style(this.layoutDoc, StyleProp.Opacity) as number; } // prettier-ignore @computed get boxShadow() { return this.style(this.layoutDoc, StyleProp.BoxShadow); } // prettier-ignore @computed get borderRounding() { return this.style(this.layoutDoc, StyleProp.BorderRounding); } // prettier-ignore - @computed get widgetDecorations() { return this.style(this.layoutDoc, StyleProp.Decorations); } // prettier-ignore - @computed get backgroundBoxColor(){ return this.style(this.layoutDoc, StyleProp.BackgroundColor + ':docView'); } // prettier-ignore + @computed get widgetDecorations() { return this.style(this.layoutDoc, StyleProp.Decorations) as JSX.Element; } // prettier-ignore + @computed get backgroundBoxColor(){ return this.style(this.layoutDoc, StyleProp.BackgroundColor + ':docView') as string; } // prettier-ignore @computed get showTitle() { return this.style(this.layoutDoc, StyleProp.ShowTitle) as Opt; } // prettier-ignore - @computed get showCaption() { return this.style(this.layoutDoc, StyleProp.ShowCaption) ?? 0; } // prettier-ignore - @computed get headerMargin() { return this.style(this.layoutDoc, StyleProp.HeaderMargin) ?? 0; } // prettier-ignore - @computed get titleHeight() { return this.style(this.layoutDoc, StyleProp.TitleHeight) ?? 0; } // prettier-ignore + @computed get showCaption() { return this.style(this.layoutDoc, StyleProp.ShowCaption) as string ?? ""; } // prettier-ignore + @computed get headerMargin() { return this.style(this.layoutDoc, StyleProp.HeaderMargin) as number ?? 0; } // prettier-ignore + @computed get titleHeight() { return this.style(this.layoutDoc, StyleProp.TitleHeight) as number ?? 0; } // prettier-ignore @computed get docContents() { return this.style(this.Document, StyleProp.DocContents); } // prettier-ignore @computed get highlighting() { return this.style(this.Document, StyleProp.Highlighting); } // prettier-ignore @computed get borderPath() { return this.style(this.Document, StyleProp.BorderPath); } // prettier-ignore @@ -710,7 +710,7 @@ export class DocumentViewInternal extends DocComponent this._rootSelected; - panelHeight = () => this._props.PanelHeight() - Number(this.headerMargin); + panelHeight = () => this._props.PanelHeight() - this.headerMargin; screenToLocalContent = () => this._props.ScreenToLocalTransform().translate(0, -this.headerMargin); onClickFunc = this.disableClickScriptFunc ? undefined : () => this.onClickHdlr; setHeight = (height: number) => { !this._props.suppressSetHeight && (this.layoutDoc._height = Math.min(NumCast(this.layoutDoc._maxHeight, Number.MAX_SAFE_INTEGER), height)); } // prettier-ignore @@ -770,7 +770,7 @@ export class DocumentViewInternal extends DocComponent, props: Opt, property: string) => this._props?.styleProvider?.(doc, props, property + ':caption'); fieldsDropdown = (placeholder: string) => (
{ r && runInAction(() => (this._titleDropDownInnerWidth = DivWidth(r);}) )} // prettier-ignore + ref={r => { r && runInAction(() => (this._titleDropDownInnerWidth = DivWidth(r)));}} // prettier-ignore onPointerDown={action(() => { this._changingTitleField = true; })} // prettier-ignore style={{ width: 'max-content', background: SnappingManager.userBackgroundColor, color: SnappingManager.userColor, transformOrigin: 'left', transform: `scale(${this.titleHeight / 30 /* height of Dropdown */})` }}> Date: Mon, 22 Jul 2024 15:26:27 -0400 Subject: adding type fixes to avoid 'any's --- .env.swo | Bin 0 -> 12288 bytes .eslintrc.json | 2 +- package-lock.json | 1544 ++++++++++---------- package.json | 2 +- src/ClientUtils.ts | 10 +- src/client/views/InkingStroke.tsx | 17 +- src/client/views/StyleProvider.tsx | 3 +- .../views/collections/CollectionCarousel3DView.tsx | 10 +- .../views/collections/CollectionDockingView.tsx | 7 +- src/client/views/collections/CollectionSubView.tsx | 2 +- src/client/views/collections/TabDocView.tsx | 13 +- src/client/views/collections/TreeView.tsx | 8 +- .../CollectionFreeFormLayoutEngines.tsx | 20 +- .../collectionFreeForm/CollectionFreeFormView.tsx | 77 +- src/client/views/nodes/DocumentView.tsx | 85 +- src/client/views/nodes/FieldView.tsx | 26 +- .../views/nodes/RecordingBox/RecordingView.tsx | 14 +- src/client/views/nodes/ScreenshotBox.tsx | 1 - 18 files changed, 938 insertions(+), 903 deletions(-) create mode 100644 .env.swo (limited to 'src') diff --git a/.env.swo b/.env.swo new file mode 100644 index 000000000..1a66a7865 Binary files /dev/null and b/.env.swo differ diff --git a/.eslintrc.json b/.eslintrc.json index 2e4da56b8..e0298fd5f 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -47,7 +47,7 @@ "no-underscore-dangle": "off", "no-nested-ternary": "off", "lines-between-class-members": "off", - "no-explicit-any": "off", + "no-explicit-any": "on", // Note: you must disable the base rule as it can report incorrect errors "no-shadow": "off", "@typescript-eslint/no-shadow": "warn", diff --git a/package-lock.json b/package-lock.json index f11d8a462..0187d7952 100644 --- a/package-lock.json +++ b/package-lock.json @@ -101,7 +101,7 @@ "express-session": "^1.17.3", "express-validator": "^7.0.1", "extract-colors": "^4.0.2", - "ffmpeg": "0.0.4", + "ffmpeg": "^0.0.4", "file-loader": "^6.2.0", "file-saver": "^2.0.5", "find-in-files": "^0.5.0", @@ -541,9 +541,9 @@ } }, "node_modules/@azure/core-rest-pipeline": { - "version": "1.16.1", - "resolved": "https://registry.npmjs.org/@azure/core-rest-pipeline/-/core-rest-pipeline-1.16.1.tgz", - "integrity": "sha512-ExPSbgjwCoht6kB7B4MeZoBAxcQSIl29r/bPeazZJx50ej4JJCByimLOrZoIsurISNyJQQHf30b3JfqC3Hb88A==", + "version": "1.16.2", + "resolved": "https://registry.npmjs.org/@azure/core-rest-pipeline/-/core-rest-pipeline-1.16.2.tgz", + "integrity": "sha512-Hnhm/PG9/SQ07JJyLDv3l9Qr8V3xgAe1hFoBYzt6LaalMxfL/ZqFaZf/bz5VN3pMcleCPwl8ivlS2Fjxq/iC8Q==", "dependencies": { "@azure/abort-controller": "^2.0.0", "@azure/core-auth": "^1.4.0", @@ -581,9 +581,9 @@ } }, "node_modules/@azure/core-util": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@azure/core-util/-/core-util-1.9.0.tgz", - "integrity": "sha512-AfalUQ1ZppaKuxPPMsFEUdX6GZPB3d9paR9d/TTL7Ow2De8cJaC7ibi7kWVlFAVPCYo31OcnGymc0R89DX8Oaw==", + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/@azure/core-util/-/core-util-1.9.1.tgz", + "integrity": "sha512-OLsq0etbHO1MA7j6FouXFghuHrAFGk+5C1imcpQ2e+0oZhYF07WLA+NW2Vqs70R7d+zOAWiWM3tbE1sXcDN66g==", "dependencies": { "@azure/abort-controller": "^2.0.0", "tslib": "^2.6.2" @@ -616,9 +616,9 @@ } }, "node_modules/@azure/logger": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@azure/logger/-/logger-1.1.2.tgz", - "integrity": "sha512-l170uE7bsKpIU6B/giRc9i4NI0Mj+tANMMMxf7Zi/5cKzEqPayP7+X1WPrG7e+91JgY8N+7K7nF2WOi7iVhXvg==", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@azure/logger/-/logger-1.1.3.tgz", + "integrity": "sha512-J8/cIKNQB1Fc9fuYqBVnrppiUtW+5WWJPCj/tAokC5LdSTwkWWttN+jsRgw9BLYD7JDBx7PceiqOBxJJ1tQz3Q==", "dependencies": { "tslib": "^2.6.2" }, @@ -662,29 +662,29 @@ } }, "node_modules/@babel/compat-data": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.24.7.tgz", - "integrity": "sha512-qJzAIcv03PyaWqxRgO4mSU3lihncDT296vnyuE2O8uA4w3UHWI4S3hgeZd1L8W1Bft40w9JxJ2b412iDUFFRhw==", + "version": "7.24.9", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.24.9.tgz", + "integrity": "sha512-e701mcfApCJqMMueQI0Fb68Amflj83+dvAvHawoBpAz+GDjCIyGHzNwnefjsWJ3xiYAqqiQFoWbspGYBdb2/ng==", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/core": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.24.7.tgz", - "integrity": "sha512-nykK+LEK86ahTkX/3TgauT0ikKoNCfKHEaZYTUVupJdTLzGNvrblu4u6fa7DhZONAltdf8e662t/abY8idrd/g==", + "version": "7.24.9", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.24.9.tgz", + "integrity": "sha512-5e3FI4Q3M3Pbr21+5xJwCv6ZT6KmGkI0vw3Tozy5ODAQFTIWe37iT8Cr7Ice2Ntb+M3iSKCEWMB1MBgKrW3whg==", "peer": true, "dependencies": { "@ampproject/remapping": "^2.2.0", "@babel/code-frame": "^7.24.7", - "@babel/generator": "^7.24.7", - "@babel/helper-compilation-targets": "^7.24.7", - "@babel/helper-module-transforms": "^7.24.7", - "@babel/helpers": "^7.24.7", - "@babel/parser": "^7.24.7", + "@babel/generator": "^7.24.9", + "@babel/helper-compilation-targets": "^7.24.8", + "@babel/helper-module-transforms": "^7.24.9", + "@babel/helpers": "^7.24.8", + "@babel/parser": "^7.24.8", "@babel/template": "^7.24.7", - "@babel/traverse": "^7.24.7", - "@babel/types": "^7.24.7", + "@babel/traverse": "^7.24.8", + "@babel/types": "^7.24.9", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", @@ -700,11 +700,11 @@ } }, "node_modules/@babel/generator": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.24.7.tgz", - "integrity": "sha512-oipXieGC3i45Y1A41t4tAqpnEZWgB/lC6Ehh6+rOviR5XWpTtMmLN+fGjz9vOiNRt0p6RtO6DtD0pdU3vpqdSA==", + "version": "7.24.10", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.24.10.tgz", + "integrity": "sha512-o9HBZL1G2129luEUlG1hB4N/nlYNWHnpwlND9eOMclRqqu1YDy2sSYVCFUZwl8I1Gxh+QSRrP2vD7EpUmFVXxg==", "dependencies": { - "@babel/types": "^7.24.7", + "@babel/types": "^7.24.9", "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.25", "jsesc": "^2.5.1" @@ -737,13 +737,13 @@ } }, "node_modules/@babel/helper-compilation-targets": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.24.7.tgz", - "integrity": "sha512-ctSdRHBi20qWOfy27RUb4Fhp07KSJ3sXcuSvTrXrc4aG8NSYDo1ici3Vhg9bg69y5bj0Mr1lh0aeEgTvc12rMg==", + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.24.8.tgz", + "integrity": "sha512-oU+UoqCHdp+nWVDkpldqIQL/i/bvAv53tRqLG/s+cOXxe66zOYLU7ar/Xs3LdmBihrUMEUhwu6dMZwbNOYDwvw==", "dependencies": { - "@babel/compat-data": "^7.24.7", - "@babel/helper-validator-option": "^7.24.7", - "browserslist": "^4.22.2", + "@babel/compat-data": "^7.24.8", + "@babel/helper-validator-option": "^7.24.8", + "browserslist": "^4.23.1", "lru-cache": "^5.1.1", "semver": "^6.3.1" }, @@ -752,14 +752,14 @@ } }, "node_modules/@babel/helper-create-class-features-plugin": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.24.7.tgz", - "integrity": "sha512-kTkaDl7c9vO80zeX1rJxnuRpEsD5tA81yh11X1gQo+PhSti3JS+7qeZo9U4RHobKRiFPKaGK3svUAeb8D0Q7eg==", + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.24.8.tgz", + "integrity": "sha512-4f6Oqnmyp2PP3olgUMmOwC3akxSm5aBYraQ6YDdKy7NcAMkDECHWG0DEnV6M2UAkERgIBhYt8S27rURPg7SxWA==", "dependencies": { "@babel/helper-annotate-as-pure": "^7.24.7", "@babel/helper-environment-visitor": "^7.24.7", "@babel/helper-function-name": "^7.24.7", - "@babel/helper-member-expression-to-functions": "^7.24.7", + "@babel/helper-member-expression-to-functions": "^7.24.8", "@babel/helper-optimise-call-expression": "^7.24.7", "@babel/helper-replace-supers": "^7.24.7", "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7", @@ -839,12 +839,12 @@ } }, "node_modules/@babel/helper-member-expression-to-functions": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.24.7.tgz", - "integrity": "sha512-LGeMaf5JN4hAT471eJdBs/GK1DoYIJ5GCtZN/EsL6KUiiDZOvO/eKE11AMZJa2zP4zk4qe9V2O/hxAmkRc8p6w==", + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.24.8.tgz", + "integrity": "sha512-LABppdt+Lp/RlBxqrh4qgf1oEH/WxdzQNDJIu5gC/W1GyvPVrOBiItmmM8wan2fm4oYqFuFfkXmlGpLQhPY8CA==", "dependencies": { - "@babel/traverse": "^7.24.7", - "@babel/types": "^7.24.7" + "@babel/traverse": "^7.24.8", + "@babel/types": "^7.24.8" }, "engines": { "node": ">=6.9.0" @@ -863,9 +863,9 @@ } }, "node_modules/@babel/helper-module-transforms": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.24.7.tgz", - "integrity": "sha512-1fuJEwIrp+97rM4RWdO+qrRsZlAeL1lQJoPqtCYWv0NL115XM93hIH4CSRln2w52SqvmY5hqdtauB6QFCDiZNQ==", + "version": "7.24.9", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.24.9.tgz", + "integrity": "sha512-oYbh+rtFKj/HwBQkFlUzvcybzklmVdVV3UU+mN7n2t/q3yGHbuVdNxyFvSBO1tfvjyArpHNcWMAzsSPdyI46hw==", "dependencies": { "@babel/helper-environment-visitor": "^7.24.7", "@babel/helper-module-imports": "^7.24.7", @@ -892,9 +892,9 @@ } }, "node_modules/@babel/helper-plugin-utils": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.7.tgz", - "integrity": "sha512-Rq76wjt7yz9AAc1KnlRKNAi/dMSVWgDRx43FHoJEbcYU6xOWaE2dVPwcdTukJrjxS65GITyfbvEYHvkirZ6uEg==", + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.8.tgz", + "integrity": "sha512-FFWx5142D8h2Mgr/iPVGH5G7w6jDn4jUSpZTyDnQO0Yn7Ks2Kuz6Pci8H6MPCoUJegd/UZQ3tAvfLCxQSnWWwg==", "engines": { "node": ">=6.9.0" } @@ -967,9 +967,9 @@ } }, "node_modules/@babel/helper-string-parser": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.7.tgz", - "integrity": "sha512-7MbVt6xrwFQbunH2DNQsAP5sTGxfqQtErvBIvIMi6EQnbgUOuVYanvREcmFrOPhoXBrTtjhhP+lW+o5UfK+tDg==", + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.8.tgz", + "integrity": "sha512-pO9KhhRcuUyGnJWwyEgnRJTSIZHiT+vMD0kPeD+so0l7mxkMT19g3pjY9GTnHySck/hDzq+dtW/4VgnMkippsQ==", "engines": { "node": ">=6.9.0" } @@ -983,9 +983,9 @@ } }, "node_modules/@babel/helper-validator-option": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.24.7.tgz", - "integrity": "sha512-yy1/KvjhV/ZCL+SM7hBrvnZJ3ZuT9OuZgIJAGpPEToANvc3iM6iDvBnRjtElWibHU6n8/LPR/EjX9EtIEYO3pw==", + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.24.8.tgz", + "integrity": "sha512-xb8t9tD1MHLungh/AIoWYN+gVHaB9kwlu8gffXGSt3FFEIT7RjS+xWbc2vUD1UTZdIpKj/ab3rdqJ7ufngyi2Q==", "engines": { "node": ">=6.9.0" } @@ -1005,13 +1005,13 @@ } }, "node_modules/@babel/helpers": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.24.7.tgz", - "integrity": "sha512-NlmJJtvcw72yRJRcnCmGvSi+3jDEg8qFu3z0AFoymmzLx5ERVWyzd9kVXr7Th9/8yIJi2Zc6av4Tqz3wFs8QWg==", + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.24.8.tgz", + "integrity": "sha512-gV2265Nkcz7weJJfvDoAEVzC1e2OTDpkGbEsebse8koXUJUXPsCMi7sRo/+SPMuMZ9MtUPnGwITTnQnU5YjyaQ==", "peer": true, "dependencies": { "@babel/template": "^7.24.7", - "@babel/types": "^7.24.7" + "@babel/types": "^7.24.8" }, "engines": { "node": ">=6.9.0" @@ -1032,9 +1032,9 @@ } }, "node_modules/@babel/parser": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.7.tgz", - "integrity": "sha512-9uUYRm6OqQrCqQdG1iCBwBPZgN8ciDBro2nIOFaiRz1/BCxaI7CNvQbDHvsArAC7Tw9Hda/B3U+6ui9u4HWXPw==", + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.8.tgz", + "integrity": "sha512-WzfbgXOkGzZiXXCqk43kKwZjzwx4oulxZi3nq2TYL9mOjQv6kYwul9mz6ID36njuL7Xkp6nJEfok848Zj10j/w==", "bin": { "parser": "bin/babel-parser.js" }, @@ -1451,15 +1451,15 @@ } }, "node_modules/@babel/plugin-transform-classes": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.24.7.tgz", - "integrity": "sha512-CFbbBigp8ln4FU6Bpy6g7sE8B/WmCmzvivzUC6xDAdWVsjYTXijpuuGJmYkAaoWAzcItGKT3IOAbxRItZ5HTjw==", + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.24.8.tgz", + "integrity": "sha512-VXy91c47uujj758ud9wx+OMgheXm4qJfyhj1P18YvlrQkNOSrwsteHk+EFS3OMGfhMhpZa0A+81eE7G4QC+3CA==", "dependencies": { "@babel/helper-annotate-as-pure": "^7.24.7", - "@babel/helper-compilation-targets": "^7.24.7", + "@babel/helper-compilation-targets": "^7.24.8", "@babel/helper-environment-visitor": "^7.24.7", "@babel/helper-function-name": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.8", "@babel/helper-replace-supers": "^7.24.7", "@babel/helper-split-export-declaration": "^7.24.7", "globals": "^11.1.0" @@ -1495,11 +1495,11 @@ } }, "node_modules/@babel/plugin-transform-destructuring": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.24.7.tgz", - "integrity": "sha512-19eJO/8kdCQ9zISOf+SEUJM/bAUIsvY3YDnXZTupUCQ8LgrWnsG/gFB9dvXqdXnRXMAM8fvt7b0CBKQHNGy1mw==", + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.24.8.tgz", + "integrity": "sha512-36e87mfY8TnRxc7yc6M9g9gOB7rKgSahqkIKwLpz4Ppk2+zC2Cy1is0uwtuSG6AE4zlTOUa+7JGz9jCJGLqQFQ==", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.24.8" }, "engines": { "node": ">=6.9.0" @@ -1687,12 +1687,12 @@ } }, "node_modules/@babel/plugin-transform-modules-commonjs": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.24.7.tgz", - "integrity": "sha512-iFI8GDxtevHJ/Z22J5xQpVqFLlMNstcLXh994xifFwxxGslr2ZXXLWgtBeLctOD63UFDArdvN6Tg8RFw+aEmjQ==", + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.24.8.tgz", + "integrity": "sha512-WHsk9H8XxRs3JXKWFiqtQebdh9b/pTk4EgueygFzYlTKAg0Ud985mSevdNjdXdFBATSKVJGQXP1tv6aGbssLKA==", "dependencies": { - "@babel/helper-module-transforms": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7", + "@babel/helper-module-transforms": "^7.24.8", + "@babel/helper-plugin-utils": "^7.24.8", "@babel/helper-simple-access": "^7.24.7" }, "engines": { @@ -1841,11 +1841,11 @@ } }, "node_modules/@babel/plugin-transform-optional-chaining": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.24.7.tgz", - "integrity": "sha512-tK+0N9yd4j+x/4hxF3F0e0fu/VdcxU18y5SevtyM/PCFlQvXbR0Zmlo2eBrKtVipGNFzpq56o8WsIIKcJFUCRQ==", + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.24.8.tgz", + "integrity": "sha512-5cTOLSMs9eypEy8JUVvIKOu6NgvbJMnpG62VpIHrTmROdQ+L5mDAaI40g25k5vXti55JWNX5jCkq3HZxXBQANw==", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.8", "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7", "@babel/plugin-syntax-optional-chaining": "^7.8.3" }, @@ -2064,11 +2064,11 @@ } }, "node_modules/@babel/plugin-transform-typeof-symbol": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.24.7.tgz", - "integrity": "sha512-VtR8hDy7YLB7+Pet9IarXjg/zgCMSF+1mNS/EQEiEaUPoFXCVsHG64SIxcaaI2zJgRiv+YmgaQESUfWAdbjzgg==", + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.24.8.tgz", + "integrity": "sha512-adNTUpDCVnmAE58VEqKlAA6ZBlNkMnWD0ZcW76lyNFN3MJniyGFZfNwERVk8Ap56MCnXztmDr19T4mPTztcuaw==", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.24.8" }, "engines": { "node": ">=6.9.0" @@ -2137,14 +2137,14 @@ } }, "node_modules/@babel/preset-env": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.24.7.tgz", - "integrity": "sha512-1YZNsc+y6cTvWlDHidMBsQZrZfEFjRIo/BZCT906PMdzOyXtSLTgqGdrpcuTDCXyd11Am5uQULtDIcCfnTc8fQ==", - "dependencies": { - "@babel/compat-data": "^7.24.7", - "@babel/helper-compilation-targets": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/helper-validator-option": "^7.24.7", + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.24.8.tgz", + "integrity": "sha512-vObvMZB6hNWuDxhSaEPTKCwcqkAIuDtE+bQGn4XMXne1DSLzFVY8Vmj1bm+mUQXYNN8NmaQEO+r8MMbzPr1jBQ==", + "dependencies": { + "@babel/compat-data": "^7.24.8", + "@babel/helper-compilation-targets": "^7.24.8", + "@babel/helper-plugin-utils": "^7.24.8", + "@babel/helper-validator-option": "^7.24.8", "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "^7.24.7", "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.24.7", "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.24.7", @@ -2175,9 +2175,9 @@ "@babel/plugin-transform-block-scoping": "^7.24.7", "@babel/plugin-transform-class-properties": "^7.24.7", "@babel/plugin-transform-class-static-block": "^7.24.7", - "@babel/plugin-transform-classes": "^7.24.7", + "@babel/plugin-transform-classes": "^7.24.8", "@babel/plugin-transform-computed-properties": "^7.24.7", - "@babel/plugin-transform-destructuring": "^7.24.7", + "@babel/plugin-transform-destructuring": "^7.24.8", "@babel/plugin-transform-dotall-regex": "^7.24.7", "@babel/plugin-transform-duplicate-keys": "^7.24.7", "@babel/plugin-transform-dynamic-import": "^7.24.7", @@ -2190,7 +2190,7 @@ "@babel/plugin-transform-logical-assignment-operators": "^7.24.7", "@babel/plugin-transform-member-expression-literals": "^7.24.7", "@babel/plugin-transform-modules-amd": "^7.24.7", - "@babel/plugin-transform-modules-commonjs": "^7.24.7", + "@babel/plugin-transform-modules-commonjs": "^7.24.8", "@babel/plugin-transform-modules-systemjs": "^7.24.7", "@babel/plugin-transform-modules-umd": "^7.24.7", "@babel/plugin-transform-named-capturing-groups-regex": "^7.24.7", @@ -2200,7 +2200,7 @@ "@babel/plugin-transform-object-rest-spread": "^7.24.7", "@babel/plugin-transform-object-super": "^7.24.7", "@babel/plugin-transform-optional-catch-binding": "^7.24.7", - "@babel/plugin-transform-optional-chaining": "^7.24.7", + "@babel/plugin-transform-optional-chaining": "^7.24.8", "@babel/plugin-transform-parameters": "^7.24.7", "@babel/plugin-transform-private-methods": "^7.24.7", "@babel/plugin-transform-private-property-in-object": "^7.24.7", @@ -2211,7 +2211,7 @@ "@babel/plugin-transform-spread": "^7.24.7", "@babel/plugin-transform-sticky-regex": "^7.24.7", "@babel/plugin-transform-template-literals": "^7.24.7", - "@babel/plugin-transform-typeof-symbol": "^7.24.7", + "@babel/plugin-transform-typeof-symbol": "^7.24.8", "@babel/plugin-transform-unicode-escapes": "^7.24.7", "@babel/plugin-transform-unicode-property-regex": "^7.24.7", "@babel/plugin-transform-unicode-regex": "^7.24.7", @@ -2220,7 +2220,7 @@ "babel-plugin-polyfill-corejs2": "^0.4.10", "babel-plugin-polyfill-corejs3": "^0.10.4", "babel-plugin-polyfill-regenerator": "^0.6.1", - "core-js-compat": "^3.31.0", + "core-js-compat": "^3.37.1", "semver": "^6.3.1" }, "engines": { @@ -2268,9 +2268,9 @@ "integrity": "sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA==" }, "node_modules/@babel/runtime": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.7.tgz", - "integrity": "sha512-UwgBRMjJP+xv857DCngvqXI3Iq6J4v0wXmwc6sapg+zyhbwmQX67LUEFrkK5tbyJ30jGuG3ZvWpBiB9LCy1kWw==", + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.8.tgz", + "integrity": "sha512-5F7SDGs1T72ZczbRwbGO9lQi0NLjQxzl6i4lJxLxfW9U5UluCSyEJeniWvnhl3/euNiqQVbo8zruhsDfid0esA==", "dependencies": { "regenerator-runtime": "^0.14.0" }, @@ -2279,9 +2279,9 @@ } }, "node_modules/@babel/runtime-corejs3": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.24.7.tgz", - "integrity": "sha512-eytSX6JLBY6PVAeQa2bFlDx/7Mmln/gaEpsit5a3WEvjGfiIytEsgAwuIXCPM0xvw0v0cJn3ilq0/TvXrW0kgA==", + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.24.8.tgz", + "integrity": "sha512-DXG/BhegtMHhnN7YPIvxWd303/9aXvYFD1TjNL3CD6tUrhI2LVsg3Lck0aql5TRH29n4sj3emcROypkZVUfSuA==", "dependencies": { "core-js-pure": "^3.30.2", "regenerator-runtime": "^0.14.0" @@ -2304,18 +2304,18 @@ } }, "node_modules/@babel/traverse": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.24.7.tgz", - "integrity": "sha512-yb65Ed5S/QAcewNPh0nZczy9JdYXkkAbIsEo+P7BE7yO3txAY30Y/oPa3QkQ5It3xVG2kpKMg9MsdxZaO31uKA==", + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.24.8.tgz", + "integrity": "sha512-t0P1xxAPzEDcEPmjprAQq19NWum4K0EQPjMwZQZbHt+GiZqvjCHjj755Weq1YRPVzBI+3zSfvScfpnuIecVFJQ==", "dependencies": { "@babel/code-frame": "^7.24.7", - "@babel/generator": "^7.24.7", + "@babel/generator": "^7.24.8", "@babel/helper-environment-visitor": "^7.24.7", "@babel/helper-function-name": "^7.24.7", "@babel/helper-hoist-variables": "^7.24.7", "@babel/helper-split-export-declaration": "^7.24.7", - "@babel/parser": "^7.24.7", - "@babel/types": "^7.24.7", + "@babel/parser": "^7.24.8", + "@babel/types": "^7.24.8", "debug": "^4.3.1", "globals": "^11.1.0" }, @@ -2332,11 +2332,11 @@ } }, "node_modules/@babel/types": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.24.7.tgz", - "integrity": "sha512-XEFXSlxiG5td2EJRe8vOmRbaXVgfcBlszKujvVmWIK/UpywWljQCfzAv3RQCGujWQ1RD4YYWEAqDXfuJiy8f5Q==", + "version": "7.24.9", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.24.9.tgz", + "integrity": "sha512-xm8XrMKz0IlUdocVbYJe0Z9xEgidU7msskG8BbhnTPK/HZ2z/7FP7ykqPgrUH+C+r414mNfNWam1f2vqOjqjYQ==", "dependencies": { - "@babel/helper-string-parser": "^7.24.7", + "@babel/helper-string-parser": "^7.24.8", "@babel/helper-validator-identifier": "^7.24.7", "to-fast-properties": "^2.0.0" }, @@ -2385,15 +2385,15 @@ } }, "node_modules/@emotion/babel-plugin": { - "version": "11.11.0", - "resolved": "https://registry.npmjs.org/@emotion/babel-plugin/-/babel-plugin-11.11.0.tgz", - "integrity": "sha512-m4HEDZleaaCH+XgDDsPF15Ht6wTLsgDTeR3WYj9Q/k76JtWhrJjcP4+/XlG8LGT/Rol9qUfOIztXeA84ATpqPQ==", + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/@emotion/babel-plugin/-/babel-plugin-11.12.0.tgz", + "integrity": "sha512-y2WQb+oP8Jqvvclh8Q55gLUyb7UFvgv7eJfsj7td5TToBrIUtPay2kMrZi4xjq9qw2vD0ZR5fSho0yqoFgX7Rw==", "dependencies": { "@babel/helper-module-imports": "^7.16.7", "@babel/runtime": "^7.18.3", - "@emotion/hash": "^0.9.1", - "@emotion/memoize": "^0.8.1", - "@emotion/serialize": "^1.1.2", + "@emotion/hash": "^0.9.2", + "@emotion/memoize": "^0.9.0", + "@emotion/serialize": "^1.2.0", "babel-plugin-macros": "^3.1.0", "convert-source-map": "^1.5.0", "escape-string-regexp": "^4.0.0", @@ -2408,47 +2408,47 @@ "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==" }, "node_modules/@emotion/cache": { - "version": "11.11.0", - "resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-11.11.0.tgz", - "integrity": "sha512-P34z9ssTCBi3e9EI1ZsWpNHcfY1r09ZO0rZbRO2ob3ZQMnFI35jB536qoXbkdesr5EUhYi22anuEJuyxifaqAQ==", - "dependencies": { - "@emotion/memoize": "^0.8.1", - "@emotion/sheet": "^1.2.2", - "@emotion/utils": "^1.2.1", - "@emotion/weak-memoize": "^0.3.1", + "version": "11.13.0", + "resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-11.13.0.tgz", + "integrity": "sha512-hPV345J/tH0Cwk2wnU/3PBzORQ9HeX+kQSbwI+jslzpRCHE6fSGTohswksA/Ensr8znPzwfzKZCmAM9Lmlhp7g==", + "dependencies": { + "@emotion/memoize": "^0.9.0", + "@emotion/sheet": "^1.4.0", + "@emotion/utils": "^1.4.0", + "@emotion/weak-memoize": "^0.4.0", "stylis": "4.2.0" } }, "node_modules/@emotion/hash": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.9.1.tgz", - "integrity": "sha512-gJB6HLm5rYwSLI6PQa+X1t5CFGrv1J1TWG+sOyMCeKz2ojaj6Fnl/rZEspogG+cvqbt4AE/2eIyD2QfLKTBNlQ==" + "version": "0.9.2", + "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.9.2.tgz", + "integrity": "sha512-MyqliTZGuOm3+5ZRSaaBGP3USLw6+EGykkwZns2EPC5g8jJ4z9OrdZY9apkl3+UP9+sdz76YYkwCKP5gh8iY3g==" }, "node_modules/@emotion/is-prop-valid": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-1.2.2.tgz", - "integrity": "sha512-uNsoYd37AFmaCdXlg6EYD1KaPOaRWRByMCYzbKUX4+hhMfrxdVSelShywL4JVaAeM/eHUOSprYBQls+/neX3pw==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-1.3.0.tgz", + "integrity": "sha512-SHetuSLvJDzuNbOdtPVbq6yMMMlLoW5Q94uDqJZqy50gcmAjxFkVqmzqSGEFq9gT2iMuIeKV1PXVWmvUhuZLlQ==", "dependencies": { - "@emotion/memoize": "^0.8.1" + "@emotion/memoize": "^0.9.0" } }, "node_modules/@emotion/memoize": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.8.1.tgz", - "integrity": "sha512-W2P2c/VRW1/1tLox0mVUalvnWXxavmv/Oum2aPsRcoDJuob75FC3Y8FbpfLwUegRcxINtGUMPq0tFCvYNTBXNA==" + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.9.0.tgz", + "integrity": "sha512-30FAj7/EoJ5mwVPOWhAyCX+FPfMDrVecJAM+Iw9NRoSl4BBAQeqj4cApHHUXOVvIPgLVDsCFoz/hGD+5QQD1GQ==" }, "node_modules/@emotion/react": { - "version": "11.11.4", - "resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.11.4.tgz", - "integrity": "sha512-t8AjMlF0gHpvvxk5mAtCqR4vmxiGHCeJBaQO6gncUSdklELOgtwjerNY2yuJNfwnc6vi16U/+uMF+afIawJ9iw==", + "version": "11.13.0", + "resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.13.0.tgz", + "integrity": "sha512-WkL+bw1REC2VNV1goQyfxjx1GYJkcc23CRQkXX+vZNLINyfI7o+uUn/rTGPt/xJ3bJHd5GcljgnxHf4wRw5VWQ==", "dependencies": { "@babel/runtime": "^7.18.3", - "@emotion/babel-plugin": "^11.11.0", - "@emotion/cache": "^11.11.0", - "@emotion/serialize": "^1.1.3", - "@emotion/use-insertion-effect-with-fallbacks": "^1.0.1", - "@emotion/utils": "^1.2.1", - "@emotion/weak-memoize": "^0.3.1", + "@emotion/babel-plugin": "^11.12.0", + "@emotion/cache": "^11.13.0", + "@emotion/serialize": "^1.3.0", + "@emotion/use-insertion-effect-with-fallbacks": "^1.1.0", + "@emotion/utils": "^1.4.0", + "@emotion/weak-memoize": "^0.4.0", "hoist-non-react-statics": "^3.3.1" }, "peerDependencies": { @@ -2461,33 +2461,33 @@ } }, "node_modules/@emotion/serialize": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-1.1.4.tgz", - "integrity": "sha512-RIN04MBT8g+FnDwgvIUi8czvr1LU1alUMI05LekWB5DGyTm8cCBMCRpq3GqaiyEDRptEXOyXnvZ58GZYu4kBxQ==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-1.3.0.tgz", + "integrity": "sha512-jACuBa9SlYajnpIVXB+XOXnfJHyckDfe6fOpORIM6yhBDlqGuExvDdZYHDQGoDf3bZXGv7tNr+LpLjJqiEQ6EA==", "dependencies": { - "@emotion/hash": "^0.9.1", - "@emotion/memoize": "^0.8.1", - "@emotion/unitless": "^0.8.1", - "@emotion/utils": "^1.2.1", + "@emotion/hash": "^0.9.2", + "@emotion/memoize": "^0.9.0", + "@emotion/unitless": "^0.9.0", + "@emotion/utils": "^1.4.0", "csstype": "^3.0.2" } }, "node_modules/@emotion/sheet": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/@emotion/sheet/-/sheet-1.2.2.tgz", - "integrity": "sha512-0QBtGvaqtWi+nx6doRwDdBIzhNdZrXUppvTM4dtZZWEGTXL/XE/yJxLMGlDT1Gt+UHH5IX1n+jkXyytE/av7OA==" + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@emotion/sheet/-/sheet-1.4.0.tgz", + "integrity": "sha512-fTBW9/8r2w3dXWYM4HCB1Rdp8NLibOw2+XELH5m5+AkWiL/KqYX6dc0kKYlaYyKjrQ6ds33MCdMPEwgs2z1rqg==" }, "node_modules/@emotion/styled": { - "version": "11.11.5", - "resolved": "https://registry.npmjs.org/@emotion/styled/-/styled-11.11.5.tgz", - "integrity": "sha512-/ZjjnaNKvuMPxcIiUkf/9SHoG4Q196DRl1w82hQ3WCsjo1IUR8uaGWrC6a87CrYAW0Kb/pK7hk8BnLgLRi9KoQ==", + "version": "11.13.0", + "resolved": "https://registry.npmjs.org/@emotion/styled/-/styled-11.13.0.tgz", + "integrity": "sha512-tkzkY7nQhW/zC4hztlwucpT8QEZ6eUzpXDRhww/Eej4tFfO0FxQYWRyg/c5CCXa4d/f174kqeXYjuQRnhzf6dA==", "dependencies": { "@babel/runtime": "^7.18.3", - "@emotion/babel-plugin": "^11.11.0", - "@emotion/is-prop-valid": "^1.2.2", - "@emotion/serialize": "^1.1.4", - "@emotion/use-insertion-effect-with-fallbacks": "^1.0.1", - "@emotion/utils": "^1.2.1" + "@emotion/babel-plugin": "^11.12.0", + "@emotion/is-prop-valid": "^1.3.0", + "@emotion/serialize": "^1.3.0", + "@emotion/use-insertion-effect-with-fallbacks": "^1.1.0", + "@emotion/utils": "^1.4.0" }, "peerDependencies": { "@emotion/react": "^11.0.0-rc.0", @@ -2506,27 +2506,27 @@ "peer": true }, "node_modules/@emotion/unitless": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.8.1.tgz", - "integrity": "sha512-KOEGMu6dmJZtpadb476IsZBclKvILjopjUii3V+7MnXIQCYh8W3NgNcgwo21n9LXZX6EDIKvqfjYxXebDwxKmQ==" + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.9.0.tgz", + "integrity": "sha512-TP6GgNZtmtFaFcsOgExdnfxLLpRDla4Q66tnenA9CktvVSdNKDvMVuUah4QvWPIpNjrWsGg3qeGo9a43QooGZQ==" }, "node_modules/@emotion/use-insertion-effect-with-fallbacks": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@emotion/use-insertion-effect-with-fallbacks/-/use-insertion-effect-with-fallbacks-1.0.1.tgz", - "integrity": "sha512-jT/qyKZ9rzLErtrjGgdkMBn2OP8wl0G3sQlBb3YPryvKHsjvINUhVaPFfP+fpBcOkmrVOVEEHQFJ7nbj2TH2gw==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@emotion/use-insertion-effect-with-fallbacks/-/use-insertion-effect-with-fallbacks-1.1.0.tgz", + "integrity": "sha512-+wBOcIV5snwGgI2ya3u99D7/FJquOIniQT1IKyDsBmEgwvpxMNeS65Oib7OnE2d2aY+3BU4OiH+0Wchf8yk3Hw==", "peerDependencies": { "react": ">=16.8.0" } }, "node_modules/@emotion/utils": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-1.2.1.tgz", - "integrity": "sha512-Y2tGf3I+XVnajdItskUCn6LX+VUDmP6lTL4fcqsXAv43dnlbZiuW4MWQW38rW/BVWSE7Q/7+XQocmpnRYILUmg==" + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-1.4.0.tgz", + "integrity": "sha512-spEnrA1b6hDR/C68lC2M7m6ALPUHZC0lIY7jAS/B/9DuuO1ZP04eov8SMv/6fwRd8pzmsn2AuJEznRREWlQrlQ==" }, "node_modules/@emotion/weak-memoize": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.3.1.tgz", - "integrity": "sha512-EsBwpc7hBUJWAsNPBmJy4hxWx12v6bshQsldrVmjxJoc3isbxhOrF2IcCpaXxfvq03NwkI7sbsOLXbYuqF/8Ww==" + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.4.0.tgz", + "integrity": "sha512-snKqtPW01tN0ui7yu9rGv69aJXr/a/Ywvl11sUjNtEcRc+ng/mQriFL0wLXMef74iHa/EkftbDzU9F8iFbH+zg==" }, "node_modules/@eslint-community/eslint-utils": { "version": "4.4.0", @@ -2634,9 +2634,9 @@ } }, "node_modules/@eslint/js": { - "version": "9.6.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.6.0.tgz", - "integrity": "sha512-D9B0/3vNg44ZeWbYMpBoXqNP4j6eQD5vNwIlGAuFRRzK/WtT/jvDQW3Bi9kkf3PMDMlM7Yi+73VLUsn5bJcl8A==", + "version": "9.7.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.7.0.tgz", + "integrity": "sha512-ChuWDQenef8OSFnvuxv0TCVxEwmu3+hPNKvM9B34qpM0rDRbjL8t5QkQeHHeAfsKQjuH9wS82WeCi1J/owatng==", "dev": true, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -2670,29 +2670,29 @@ } }, "node_modules/@floating-ui/core": { - "version": "1.6.4", - "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.6.4.tgz", - "integrity": "sha512-a4IowK4QkXl4SCWTGUR0INAfEOX3wtsYw3rKK5InQEHMGObkR8Xk44qYQD9P4r6HHw0iIfK6GUKECmY8sTkqRA==", + "version": "1.6.5", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.6.5.tgz", + "integrity": "sha512-8GrTWmoFhm5BsMZOTHeGD2/0FLKLQQHvO/ZmQga4tKempYRLz8aqJGqXVuQgisnMObq2YZ2SgkwctN1LOOxcqA==", "dependencies": { - "@floating-ui/utils": "^0.2.4" + "@floating-ui/utils": "^0.2.5" } }, "node_modules/@floating-ui/dom": { - "version": "1.6.7", - "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.6.7.tgz", - "integrity": "sha512-wmVfPG5o2xnKDU4jx/m4w5qva9FWHcnZ8BvzEe90D/RpwsJaTAVYPEPdQ8sbr/N8zZTAHlZUTQdqg8ZUbzHmng==", + "version": "1.6.8", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.6.8.tgz", + "integrity": "sha512-kx62rP19VZ767Q653wsP1XZCGIirkE09E0QUGNYTM/ttbbQHqcGPdSfWFxUyyNLc/W6aoJRBajOSXhP6GXjC0Q==", "dependencies": { "@floating-ui/core": "^1.6.0", - "@floating-ui/utils": "^0.2.4" + "@floating-ui/utils": "^0.2.5" } }, "node_modules/@floating-ui/react": { - "version": "0.26.19", - "resolved": "https://registry.npmjs.org/@floating-ui/react/-/react-0.26.19.tgz", - "integrity": "sha512-Jk6zITdjjIvjO/VdQFvpRaD3qPwOHH6AoDHxjhpy+oK4KFgaSP871HYWUAPdnLmx1gQ+w/pB312co3tVml+BXA==", + "version": "0.26.20", + "resolved": "https://registry.npmjs.org/@floating-ui/react/-/react-0.26.20.tgz", + "integrity": "sha512-RixKJJG92fcIsVoqrFr4Onpzh7hlOx4U7NV4aLhMLmtvjZ5oTB/WzXaANYUZATKqXvvW7t9sCxtzejip26N5Ag==", "dependencies": { "@floating-ui/react-dom": "^2.1.1", - "@floating-ui/utils": "^0.2.4", + "@floating-ui/utils": "^0.2.5", "tabbable": "^6.0.0" }, "peerDependencies": { @@ -2713,9 +2713,9 @@ } }, "node_modules/@floating-ui/utils": { - "version": "0.2.4", - "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.4.tgz", - "integrity": "sha512-dWO2pw8hhi+WrXq1YJy2yCuWoL20PddgGaqTgVe4cOS9Q6qklXCiA1tJEqX6BEwRNSCP84/afac9hd4MS+zEUA==" + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.5.tgz", + "integrity": "sha512-sTcG+QZ6fdEUObICavU+aB3Mp8HY4n14wYHdxK4fXjPmv3PXZZeY5RaguJmGyeH/CJQhX3fqKUtS4qc1LoHwhQ==" }, "node_modules/@formatjs/ecma402-abstract": { "version": "2.0.0", @@ -2762,57 +2762,52 @@ } }, "node_modules/@fortawesome/fontawesome-common-types": { - "version": "6.5.2", - "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-6.5.2.tgz", - "integrity": "sha512-gBxPg3aVO6J0kpfHNILc+NMhXnqHumFxOmjYCFfOiLZfwhnnfhtsdA2hfJlDnj+8PjAs6kKQPenOTKj3Rf7zHw==", - "hasInstallScript": true, + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-6.6.0.tgz", + "integrity": "sha512-xyX0X9mc0kyz9plIyryrRbl7ngsA9jz77mCZJsUkLl+ZKs0KWObgaEBoSgQiYWAsSmjz/yjl0F++Got0Mdp4Rw==", "engines": { "node": ">=6" } }, "node_modules/@fortawesome/fontawesome-svg-core": { - "version": "6.5.2", - "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-6.5.2.tgz", - "integrity": "sha512-5CdaCBGl8Rh9ohNdxeeTMxIj8oc3KNBgIeLMvJosBMdslK/UnEB8rzyDRrbKdL1kDweqBPo4GT9wvnakHWucZw==", - "hasInstallScript": true, + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-6.6.0.tgz", + "integrity": "sha512-KHwPkCk6oRT4HADE7smhfsKudt9N/9lm6EJ5BVg0tD1yPA5hht837fB87F8pn15D8JfTqQOjhKTktwmLMiD7Kg==", "dependencies": { - "@fortawesome/fontawesome-common-types": "6.5.2" + "@fortawesome/fontawesome-common-types": "6.6.0" }, "engines": { "node": ">=6" } }, "node_modules/@fortawesome/free-brands-svg-icons": { - "version": "6.5.2", - "resolved": "https://registry.npmjs.org/@fortawesome/free-brands-svg-icons/-/free-brands-svg-icons-6.5.2.tgz", - "integrity": "sha512-zi5FNYdmKLnEc0jc0uuHH17kz/hfYTg4Uei0wMGzcoCL/4d3WM3u1VMc0iGGa31HuhV5i7ZK8ZlTCQrHqRHSGQ==", - "hasInstallScript": true, + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/@fortawesome/free-brands-svg-icons/-/free-brands-svg-icons-6.6.0.tgz", + "integrity": "sha512-1MPD8lMNW/earme4OQi1IFHtmHUwAKgghXlNwWi9GO7QkTfD+IIaYpIai4m2YJEzqfEji3jFHX1DZI5pbY/biQ==", "dependencies": { - "@fortawesome/fontawesome-common-types": "6.5.2" + "@fortawesome/fontawesome-common-types": "6.6.0" }, "engines": { "node": ">=6" } }, "node_modules/@fortawesome/free-regular-svg-icons": { - "version": "6.5.2", - "resolved": "https://registry.npmjs.org/@fortawesome/free-regular-svg-icons/-/free-regular-svg-icons-6.5.2.tgz", - "integrity": "sha512-iabw/f5f8Uy2nTRtJ13XZTS1O5+t+anvlamJ3zJGLEVE2pKsAWhPv2lq01uQlfgCX7VaveT3EVs515cCN9jRbw==", - "hasInstallScript": true, + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/@fortawesome/free-regular-svg-icons/-/free-regular-svg-icons-6.6.0.tgz", + "integrity": "sha512-Yv9hDzL4aI73BEwSEh20clrY8q/uLxawaQ98lekBx6t9dQKDHcDzzV1p2YtBGTtolYtNqcWdniOnhzB+JPnQEQ==", "dependencies": { - "@fortawesome/fontawesome-common-types": "6.5.2" + "@fortawesome/fontawesome-common-types": "6.6.0" }, "engines": { "node": ">=6" } }, "node_modules/@fortawesome/free-solid-svg-icons": { - "version": "6.5.2", - "resolved": "https://registry.npmjs.org/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-6.5.2.tgz", - "integrity": "sha512-QWFZYXFE7O1Gr1dTIp+D6UcFUF0qElOnZptpi7PBUMylJh+vFmIedVe1Ir6RM1t2tEQLLSV1k7bR4o92M+uqlw==", - "hasInstallScript": true, + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-6.6.0.tgz", + "integrity": "sha512-IYv/2skhEDFc2WGUcqvFJkeK39Q+HyPf5GHUrT/l2pKbtgEIv1al1TKd6qStR5OIwQdN1GZP54ci3y4mroJWjA==", "dependencies": { - "@fortawesome/fontawesome-common-types": "6.5.2" + "@fortawesome/fontawesome-common-types": "6.6.0" }, "engines": { "node": ">=6" @@ -2831,30 +2826,30 @@ } }, "node_modules/@fullcalendar/core": { - "version": "6.1.14", - "resolved": "https://registry.npmjs.org/@fullcalendar/core/-/core-6.1.14.tgz", - "integrity": "sha512-hIPRBevm0aMc2aHy1hRIJgXmI1QTvQM1neQa9oxtuqUmF1+ApYC3oAdwcQMTuI7lHHw3pKJDyJFkKLPPnL6HXA==", + "version": "6.1.15", + "resolved": "https://registry.npmjs.org/@fullcalendar/core/-/core-6.1.15.tgz", + "integrity": "sha512-BuX7o6ALpLb84cMw1FCB9/cSgF4JbVO894cjJZ6kP74jzbUZNjtwffwRdA+Id8rrLjT30d/7TrkW90k4zbXB5Q==", "dependencies": { "preact": "~10.12.1" } }, "node_modules/@fullcalendar/daygrid": { - "version": "6.1.14", - "resolved": "https://registry.npmjs.org/@fullcalendar/daygrid/-/daygrid-6.1.14.tgz", - "integrity": "sha512-DSyjiA1dEM8k3bOCrZpZOmAOZu71KGtH02ze+4QKuhxkmn/zQghmmLRdfzpOrcyJg6xGKkoB4pBcO+2lXar8XQ==", + "version": "6.1.15", + "resolved": "https://registry.npmjs.org/@fullcalendar/daygrid/-/daygrid-6.1.15.tgz", + "integrity": "sha512-j8tL0HhfiVsdtOCLfzK2J0RtSkiad3BYYemwQKq512cx6btz6ZZ2RNc/hVnIxluuWFyvx5sXZwoeTJsFSFTEFA==", "peerDependencies": { - "@fullcalendar/core": "~6.1.14" + "@fullcalendar/core": "~6.1.15" } }, "node_modules/@fullcalendar/multimonth": { - "version": "6.1.14", - "resolved": "https://registry.npmjs.org/@fullcalendar/multimonth/-/multimonth-6.1.14.tgz", - "integrity": "sha512-el2vbZZgTkdufgOvRxqx61czjRMfEK50449g4SkqbagtS3ITNMAv84KHFcsbXVbd9Nh3UhbXDuYZuzJZpvY7mQ==", + "version": "6.1.15", + "resolved": "https://registry.npmjs.org/@fullcalendar/multimonth/-/multimonth-6.1.15.tgz", + "integrity": "sha512-sEZY6jbOYkeF9TwhUldG+UUVv+hiPlGkS8zZEgPR7ypcjhipyA03c5rPjx7N6huOHqh6lCMH59zlohLooQRlaw==", "dependencies": { - "@fullcalendar/daygrid": "~6.1.14" + "@fullcalendar/daygrid": "~6.1.15" }, "peerDependencies": { - "@fullcalendar/core": "~6.1.14" + "@fullcalendar/core": "~6.1.15" } }, "node_modules/@googlemaps/js-api-loader": { @@ -3717,9 +3712,9 @@ } }, "node_modules/@mapbox/node-pre-gyp/node_modules/semver": { - "version": "7.6.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", - "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", "bin": { "semver": "bin/semver.js" }, @@ -3777,57 +3772,26 @@ } }, "node_modules/@mongodb-js/saslprep": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/@mongodb-js/saslprep/-/saslprep-1.1.7.tgz", - "integrity": "sha512-dCHW/oEX0KJ4NjDULBo3JiOaK5+6axtpBbS+ao2ZInoAL9/YRQLhXzSNAFz7hP4nzLkIqsfYAK/PDE3+XHny0Q==", + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/@mongodb-js/saslprep/-/saslprep-1.1.8.tgz", + "integrity": "sha512-qKwC/M/nNNaKUBMQ0nuzm47b7ZYWQHN3pcXq4IIcoSBc2hOIrflAxJduIvvqmhoz3gR2TacTAs8vlsCVPkiEdQ==", "dependencies": { "sparse-bitfield": "^3.0.3" } }, - "node_modules/@mui/base": { - "version": "5.0.0-beta.40", - "resolved": "https://registry.npmjs.org/@mui/base/-/base-5.0.0-beta.40.tgz", - "integrity": "sha512-I/lGHztkCzvwlXpjD2+SNmvNQvB4227xBXhISPjEaJUXGImOQ9f3D2Yj/T3KasSI/h0MLWy74X0J6clhPmsRbQ==", - "dependencies": { - "@babel/runtime": "^7.23.9", - "@floating-ui/react-dom": "^2.0.8", - "@mui/types": "^7.2.14", - "@mui/utils": "^5.15.14", - "@popperjs/core": "^2.11.8", - "clsx": "^2.1.0", - "prop-types": "^15.8.1" - }, - "engines": { - "node": ">=12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/mui-org" - }, - "peerDependencies": { - "@types/react": "^17.0.0 || ^18.0.0", - "react": "^17.0.0 || ^18.0.0", - "react-dom": "^17.0.0 || ^18.0.0" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, "node_modules/@mui/core-downloads-tracker": { - "version": "5.16.0", - "resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-5.16.0.tgz", - "integrity": "sha512-8SLffXYPRVpcZx5QzxNE8fytTqzp+IuU3deZbQWg/vSaTlDpR5YVrQ4qQtXTi5cRdhOufV5INylmwlKK+//nPw==", + "version": "5.16.4", + "resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-5.16.4.tgz", + "integrity": "sha512-rNdHXhclwjEZnK+//3SR43YRx0VtjdHnUFhMSGYmAMJve+KiwEja/41EYh8V3pZKqF2geKyfcFUenTfDTYUR4w==", "funding": { "type": "opencollective", "url": "https://opencollective.com/mui-org" } }, "node_modules/@mui/icons-material": { - "version": "5.16.0", - "resolved": "https://registry.npmjs.org/@mui/icons-material/-/icons-material-5.16.0.tgz", - "integrity": "sha512-6ISoOhkp9w5gD0PEW9JklrcbyARDkFWNTBdwXZ1Oy5IGlyu9B0zG0hnUIe4H17IaF1Vgj6C8VI+v4tkSdK0veg==", + "version": "5.16.4", + "resolved": "https://registry.npmjs.org/@mui/icons-material/-/icons-material-5.16.4.tgz", + "integrity": "sha512-j9/CWctv6TH6Dou2uR2EH7UOgu79CW/YcozxCYVLJ7l03pCsiOlJ5sBArnWJxJ+nGkFwyL/1d1k8JEPMDR125A==", "dependencies": { "@babel/runtime": "^7.23.9" }, @@ -3850,21 +3814,21 @@ } }, "node_modules/@mui/material": { - "version": "5.16.0", - "resolved": "https://registry.npmjs.org/@mui/material/-/material-5.16.0.tgz", - "integrity": "sha512-DbR1NckTLpjt9Zut9EGQ70th86HfN0BYQgyYro6aXQrNfjzSwe3BJS1AyBQ5mJ7TdL6YVRqohfukxj9JlqZZUg==", + "version": "5.16.4", + "resolved": "https://registry.npmjs.org/@mui/material/-/material-5.16.4.tgz", + "integrity": "sha512-dBnh3/zRYgEVIS3OE4oTbujse3gifA0qLMmuUk13ywsDCbngJsdgwW5LuYeiT5pfA8PGPGSqM7mxNytYXgiMCw==", "dependencies": { "@babel/runtime": "^7.23.9", - "@mui/base": "5.0.0-beta.40", - "@mui/core-downloads-tracker": "^5.16.0", - "@mui/system": "^5.16.0", - "@mui/types": "^7.2.14", - "@mui/utils": "^5.16.0", + "@mui/core-downloads-tracker": "^5.16.4", + "@mui/system": "^5.16.4", + "@mui/types": "^7.2.15", + "@mui/utils": "^5.16.4", + "@popperjs/core": "^2.11.8", "@types/react-transition-group": "^4.4.10", "clsx": "^2.1.0", "csstype": "^3.1.3", "prop-types": "^15.8.1", - "react-is": "^18.2.0", + "react-is": "^18.3.1", "react-transition-group": "^4.4.5" }, "engines": { @@ -3894,12 +3858,12 @@ } }, "node_modules/@mui/private-theming": { - "version": "5.16.0", - "resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-5.16.0.tgz", - "integrity": "sha512-sYpubkO1MZOnxNyVOClrPNOTs0MfuRVVnAvCeMaOaXt6GimgQbnUcshYv2pSr6PFj+Mqzdff/FYOBceK8u5QgA==", + "version": "5.16.4", + "resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-5.16.4.tgz", + "integrity": "sha512-ZsAm8cq31SJ37SVWLRlu02v9SRthxnfQofaiv14L5Bht51B0dz6yQEoVU/V8UduZDCCIrWkBHuReVfKhE/UuXA==", "dependencies": { "@babel/runtime": "^7.23.9", - "@mui/utils": "^5.16.0", + "@mui/utils": "^5.16.4", "prop-types": "^15.8.1" }, "engines": { @@ -3920,9 +3884,9 @@ } }, "node_modules/@mui/styled-engine": { - "version": "5.15.14", - "resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-5.15.14.tgz", - "integrity": "sha512-RILkuVD8gY6PvjZjqnWhz8fu68dVkqhM5+jYWfB5yhlSQKg+2rHkmEwm75XIeAqI3qwOndK6zELK5H6Zxn4NHw==", + "version": "5.16.4", + "resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-5.16.4.tgz", + "integrity": "sha512-0+mnkf+UiAmTVB8PZFqOhqf729Yh0Cxq29/5cA3VAyDVTRIUUQ8FXQhiAhUIbijFmM72rY80ahFPXIm4WDbzcA==", "dependencies": { "@babel/runtime": "^7.23.9", "@emotion/cache": "^11.11.0", @@ -3951,15 +3915,15 @@ } }, "node_modules/@mui/system": { - "version": "5.16.0", - "resolved": "https://registry.npmjs.org/@mui/system/-/system-5.16.0.tgz", - "integrity": "sha512-9YbkC2m3+pNumAvubYv+ijLtog6puJ0fJ6rYfzfLCM47pWrw3m+30nXNM8zMgDaKL6vpfWJcCXm+LPaWBpy7sw==", + "version": "5.16.4", + "resolved": "https://registry.npmjs.org/@mui/system/-/system-5.16.4.tgz", + "integrity": "sha512-ET1Ujl2/8hbsD611/mqUuNArMCGv/fIWO/f8B3ZqF5iyPHM2aS74vhTNyjytncc4i6dYwGxNk+tLa7GwjNS0/w==", "dependencies": { "@babel/runtime": "^7.23.9", - "@mui/private-theming": "^5.16.0", - "@mui/styled-engine": "^5.15.14", - "@mui/types": "^7.2.14", - "@mui/utils": "^5.16.0", + "@mui/private-theming": "^5.16.4", + "@mui/styled-engine": "^5.16.4", + "@mui/types": "^7.2.15", + "@mui/utils": "^5.16.4", "clsx": "^2.1.0", "csstype": "^3.1.3", "prop-types": "^15.8.1" @@ -3990,9 +3954,9 @@ } }, "node_modules/@mui/types": { - "version": "7.2.14", - "resolved": "https://registry.npmjs.org/@mui/types/-/types-7.2.14.tgz", - "integrity": "sha512-MZsBZ4q4HfzBsywtXgM1Ksj6HDThtiwmOKUXH1pKYISI9gAVXCNHNpo7TlGoGrBaYWZTdNoirIN7JsQcQUjmQQ==", + "version": "7.2.15", + "resolved": "https://registry.npmjs.org/@mui/types/-/types-7.2.15.tgz", + "integrity": "sha512-nbo7yPhtKJkdf9kcVOF8JZHPZTmqXjJ/tI0bdWgHg5tp9AnIN4Y7f7wm9T+0SyGYJk76+GYZ8Q5XaTYAsUHN0Q==", "peerDependencies": { "@types/react": "^17.0.0 || ^18.0.0" }, @@ -4003,14 +3967,15 @@ } }, "node_modules/@mui/utils": { - "version": "5.16.0", - "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-5.16.0.tgz", - "integrity": "sha512-kLLi5J1xY+mwtUlMb8Ubdxf4qFAA1+U7WPBvjM/qQ4CIwLCohNb0sHo1oYPufjSIH/Z9+dhVxD7dJlfGjd1AVA==", + "version": "5.16.4", + "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-5.16.4.tgz", + "integrity": "sha512-nlppYwq10TBIFqp7qxY0SvbACOXeOjeVL3pOcDsK0FT8XjrEXh9/+lkg8AEIzD16z7YfiJDQjaJG2OLkE7BxNg==", "dependencies": { "@babel/runtime": "^7.23.9", - "@types/prop-types": "^15.7.11", + "@types/prop-types": "^15.7.12", + "clsx": "^2.1.1", "prop-types": "^15.8.1", - "react-is": "^18.2.0" + "react-is": "^18.3.1" }, "engines": { "node": ">=12.0.0" @@ -4117,9 +4082,9 @@ "integrity": "sha512-QBhVjcUa9W7Wwhm6DBFu6ZZ+1/t/oYxqc2tp81Pi41YNuJinbFRx8B133qVOrAaBbF7D/m0Et6f9/pZt9Rc+tg==" }, "node_modules/@octokit/request": { - "version": "9.1.1", - "resolved": "https://registry.npmjs.org/@octokit/request/-/request-9.1.1.tgz", - "integrity": "sha512-pyAguc0p+f+GbQho0uNetNQMmLG1e80WjkIaqqgUkihqUp0boRU6nKItXO4VWnr+nbZiLGEyy4TeKRwqaLvYgw==", + "version": "9.1.3", + "resolved": "https://registry.npmjs.org/@octokit/request/-/request-9.1.3.tgz", + "integrity": "sha512-V+TFhu5fdF3K58rs1pGUJIDH5RZLbZm5BI+MNF+6o/ssFNT4vWlCh/tVpF3NxGtP15HUxTTMUbsG5llAuU2CZA==", "dependencies": { "@octokit/endpoint": "^10.0.0", "@octokit/request-error": "^6.0.1", @@ -4131,9 +4096,9 @@ } }, "node_modules/@octokit/request-error": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-6.1.1.tgz", - "integrity": "sha512-1mw1gqT3fR/WFvnoVpY/zUM2o/XkMs/2AszUUG9I69xn0JFLv6PGkPhNk5lbfvROs79wiS0bqiJNxfCZcRJJdg==", + "version": "6.1.4", + "resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-6.1.4.tgz", + "integrity": "sha512-VpAhIUxwhWZQImo/dWAN/NpPqqojR6PSLgLYAituLM6U+ddx9hCioFGwBr5Mi+oi5CLeJkcAs3gJ0PYYzU6wUg==", "dependencies": { "@octokit/types": "^13.0.0" }, @@ -6150,25 +6115,25 @@ } }, "node_modules/@react-spring/animated": { - "version": "9.7.3", - "resolved": "https://registry.npmjs.org/@react-spring/animated/-/animated-9.7.3.tgz", - "integrity": "sha512-5CWeNJt9pNgyvuSzQH+uy2pvTg8Y4/OisoscZIR8/ZNLIOI+CatFBhGZpDGTF/OzdNFsAoGk3wiUYTwoJ0YIvw==", + "version": "9.7.4", + "resolved": "https://registry.npmjs.org/@react-spring/animated/-/animated-9.7.4.tgz", + "integrity": "sha512-7As+8Pty2QlemJ9O5ecsuPKjmO0NKvmVkRR1n6mEotFgWar8FKuQt2xgxz3RTgxcccghpx1YdS1FCdElQNexmQ==", "dependencies": { - "@react-spring/shared": "~9.7.3", - "@react-spring/types": "~9.7.3" + "@react-spring/shared": "~9.7.4", + "@react-spring/types": "~9.7.4" }, "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0" } }, "node_modules/@react-spring/core": { - "version": "9.7.3", - "resolved": "https://registry.npmjs.org/@react-spring/core/-/core-9.7.3.tgz", - "integrity": "sha512-IqFdPVf3ZOC1Cx7+M0cXf4odNLxDC+n7IN3MDcVCTIOSBfqEcBebSv+vlY5AhM0zw05PDbjKrNmBpzv/AqpjnQ==", + "version": "9.7.4", + "resolved": "https://registry.npmjs.org/@react-spring/core/-/core-9.7.4.tgz", + "integrity": "sha512-GzjA44niEJBFUe9jN3zubRDDDP2E4tBlhNlSIkTChiNf9p4ZQlgXBg50qbXfSXHQPHak/ExYxwhipKVsQ/sUTw==", "dependencies": { - "@react-spring/animated": "~9.7.3", - "@react-spring/shared": "~9.7.3", - "@react-spring/types": "~9.7.3" + "@react-spring/animated": "~9.7.4", + "@react-spring/shared": "~9.7.4", + "@react-spring/types": "~9.7.4" }, "funding": { "type": "opencollective", @@ -6178,31 +6143,37 @@ "react": "^16.8.0 || ^17.0.0 || ^18.0.0" } }, + "node_modules/@react-spring/rafz": { + "version": "9.7.4", + "resolved": "https://registry.npmjs.org/@react-spring/rafz/-/rafz-9.7.4.tgz", + "integrity": "sha512-mqDI6rW0Ca8IdryOMiXRhMtVGiEGLIO89vIOyFQXRIwwIMX30HLya24g9z4olDvFyeDW3+kibiKwtZnA4xhldA==" + }, "node_modules/@react-spring/shared": { - "version": "9.7.3", - "resolved": "https://registry.npmjs.org/@react-spring/shared/-/shared-9.7.3.tgz", - "integrity": "sha512-NEopD+9S5xYyQ0pGtioacLhL2luflh6HACSSDUZOwLHoxA5eku1UPuqcJqjwSD6luKjjLfiLOspxo43FUHKKSA==", + "version": "9.7.4", + "resolved": "https://registry.npmjs.org/@react-spring/shared/-/shared-9.7.4.tgz", + "integrity": "sha512-bEPI7cQp94dOtCFSEYpxvLxj0+xQfB5r9Ru1h8OMycsIq7zFZon1G0sHrBLaLQIWeMCllc4tVDYRTLIRv70C8w==", "dependencies": { - "@react-spring/types": "~9.7.3" + "@react-spring/rafz": "~9.7.4", + "@react-spring/types": "~9.7.4" }, "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0" } }, "node_modules/@react-spring/types": { - "version": "9.7.3", - "resolved": "https://registry.npmjs.org/@react-spring/types/-/types-9.7.3.tgz", - "integrity": "sha512-Kpx/fQ/ZFX31OtlqVEFfgaD1ACzul4NksrvIgYfIFq9JpDHFwQkMVZ10tbo0FU/grje4rcL4EIrjekl3kYwgWw==" + "version": "9.7.4", + "resolved": "https://registry.npmjs.org/@react-spring/types/-/types-9.7.4.tgz", + "integrity": "sha512-iQVztO09ZVfsletMiY+DpT/JRiBntdsdJ4uqk3UJFhrhS8mIC9ZOZbmfGSRs/kdbNPQkVyzucceDicQ/3Mlj9g==" }, "node_modules/@react-spring/web": { - "version": "9.7.3", - "resolved": "https://registry.npmjs.org/@react-spring/web/-/web-9.7.3.tgz", - "integrity": "sha512-BXt6BpS9aJL/QdVqEIX9YoUy8CE6TJrU0mNCqSoxdXlIeNcEBWOfIyE6B14ENNsyQKS3wOWkiJfco0tCr/9tUg==", + "version": "9.7.4", + "resolved": "https://registry.npmjs.org/@react-spring/web/-/web-9.7.4.tgz", + "integrity": "sha512-UMvCZp7I5HCVIleSa4BwbNxynqvj+mJjG2m20VO2yPoi2pnCYANy58flvz9v/YcXTAvsmL655FV3pm5fbr6akA==", "dependencies": { - "@react-spring/animated": "~9.7.3", - "@react-spring/core": "~9.7.3", - "@react-spring/shared": "~9.7.3", - "@react-spring/types": "~9.7.3" + "@react-spring/animated": "~9.7.4", + "@react-spring/core": "~9.7.4", + "@react-spring/shared": "~9.7.4", + "@react-spring/types": "~9.7.4" }, "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0", @@ -7169,9 +7140,9 @@ } }, "node_modules/@swc/helpers": { - "version": "0.5.11", - "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.11.tgz", - "integrity": "sha512-YNlnKRWF2sVojTpIyzwou9XoTNbzbzONwRhOoniEioF1AtaitTvVZblaQRrAzChWQ1bLYyYSWzM18y4WwgzJ+A==", + "version": "0.5.12", + "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.12.tgz", + "integrity": "sha512-KMZNXiGibsW9kvZAO1Pam2JPTDBm+KSHMMHWdsyI/1DbIZjT2A6Gy3hblVXUMEDvUAKq+e0vL0X0o54owWji7g==", "dependencies": { "tslib": "^2.4.0" } @@ -8025,25 +7996,6 @@ "url": "https://opencollective.com/turf" } }, - "node_modules/@turf/line-overlap/node_modules/deep-equal": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.1.2.tgz", - "integrity": "sha512-5tdhKF6DbU7iIzrIOa1AOUt39ZRm13cmL1cGEh//aqR8x9+tNfbywRf0n5FD/18OKMdo7DNEtrX2t22ZAkI+eg==", - "dependencies": { - "is-arguments": "^1.1.1", - "is-date-object": "^1.0.5", - "is-regex": "^1.1.4", - "object-is": "^1.1.5", - "object-keys": "^1.1.1", - "regexp.prototype.flags": "^1.5.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/@turf/line-segment": { "version": "6.5.0", "resolved": "https://registry.npmjs.org/@turf/line-segment/-/line-segment-6.5.0.tgz", @@ -9448,11 +9400,26 @@ } }, "node_modules/@types/lodash": { - "version": "4.17.6", - "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.6.tgz", - "integrity": "sha512-OpXEVoCKSS3lQqjx9GGGOapBeuW5eUboYHRlHP9urXPX25IKZ6AnP5ZRxtVf63iieUbsHxLn8NQ5Nlftc6yzAA==", + "version": "4.17.7", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.7.tgz", + "integrity": "sha512-8wTvZawATi/lsmNu10/j2hk1KEP0IvjubqPE3cu1Xz7xfXXt5oCq3SNUz4fMIP4XGF9Ky+Ue2tBA3hcS7LSBlA==", "dev": true }, + "node_modules/@types/mapbox__point-geometry": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/@types/mapbox__point-geometry/-/mapbox__point-geometry-0.1.4.tgz", + "integrity": "sha512-mUWlSxAmYLfwnRBmgYV86tgYmMIICX4kza8YnE/eIlywGe2XoOxlpVnXWwir92xRLjwyarqwpu2EJKD2pk0IUA==" + }, + "node_modules/@types/mapbox__vector-tile": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/@types/mapbox__vector-tile/-/mapbox__vector-tile-1.3.4.tgz", + "integrity": "sha512-bpd8dRn9pr6xKvuEBQup8pwQfD4VUyqO/2deGjfpe6AwC8YRlyEipvefyRJUSiCJTZuCb8Pl1ciVV5ekqJ96Bg==", + "dependencies": { + "@types/geojson": "*", + "@types/mapbox__point-geometry": "*", + "@types/pbf": "*" + } + }, "node_modules/@types/mapbox-gl": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/@types/mapbox-gl/-/mapbox-gl-3.1.0.tgz", @@ -9493,9 +9460,9 @@ "integrity": "sha512-nG96G3Wp6acyAgJqGasjODb+acrI7KltPiRxzHPXnP3NgI28bpQDRv53olbqGXbfcgF5aiiHmO3xpwEpS5Ld9g==" }, "node_modules/@types/node": { - "version": "20.14.10", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.14.10.tgz", - "integrity": "sha512-MdiXf+nDuMvY0gJKxyfZ7/6UFsETO7mGKF54MVD/ekJS6HdFtpZFBgrh6Pseu64XTb2MLyFPlbW6hj8HYRQNOQ==", + "version": "20.14.11", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.14.11.tgz", + "integrity": "sha512-kprQpL8MMeszbz6ojB5/tU8PLN4kesnN8Gjzw349rDlNgsSzg90lAVj3llK99Dh7JON+t9AuscPPFW6mPbTnSA==", "dependencies": { "undici-types": "~5.26.4" } @@ -9593,6 +9560,11 @@ "@types/passport": "*" } }, + "node_modules/@types/pbf": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@types/pbf/-/pbf-3.0.5.tgz", + "integrity": "sha512-j3pOPiEcWZ34R6a6mN07mUkM4o4Lwf6hPNt8eilOeZhTFbxFXmKhvXl9Y28jotFPaI1bpPDJsbCprUoNke6OrA==" + }, "node_modules/@types/pdf-parse": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/@types/pdf-parse/-/pdf-parse-1.1.4.tgz", @@ -9915,9 +9887,9 @@ } }, "node_modules/@types/ws": { - "version": "8.5.10", - "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.10.tgz", - "integrity": "sha512-vmQSUcfalpIq0R9q7uTo2lXs6eGIpt9wtnLdMv9LVpIjCA/+ufZRozlVoVelIYixx1ugCBKDhn89vnsEGOCx9A==", + "version": "8.5.11", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.11.tgz", + "integrity": "sha512-4+q7P5h3SpJxaBft0Dzpbr6lmMaqh0Jr2tbhJZ/luAwvD7ohSCniYkwz/pLxuT2h0EOa6QADgJj1Ko+TzRfZ+w==", "dev": true, "dependencies": { "@types/node": "*" @@ -9943,16 +9915,16 @@ "dev": true }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.16.0.tgz", - "integrity": "sha512-py1miT6iQpJcs1BiJjm54AMzeuMPBSPuKPlnT8HlfudbcS5rYeX5jajpLf3mrdRh9dA/Ec2FVUY0ifeVNDIhZw==", + "version": "7.16.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.16.1.tgz", + "integrity": "sha512-SxdPak/5bO0EnGktV05+Hq8oatjAYVY3Zh2bye9pGZy6+jwyR3LG3YKkV4YatlsgqXP28BTeVm9pqwJM96vf2A==", "dev": true, "dependencies": { "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "7.16.0", - "@typescript-eslint/type-utils": "7.16.0", - "@typescript-eslint/utils": "7.16.0", - "@typescript-eslint/visitor-keys": "7.16.0", + "@typescript-eslint/scope-manager": "7.16.1", + "@typescript-eslint/type-utils": "7.16.1", + "@typescript-eslint/utils": "7.16.1", + "@typescript-eslint/visitor-keys": "7.16.1", "graphemer": "^1.4.0", "ignore": "^5.3.1", "natural-compare": "^1.4.0", @@ -9976,14 +9948,14 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.16.0.tgz", - "integrity": "sha512-ar9E+k7CU8rWi2e5ErzQiC93KKEFAXA2Kky0scAlPcxYblLt8+XZuHUZwlyfXILyQa95P6lQg+eZgh/dDs3+Vw==", - "dependencies": { - "@typescript-eslint/scope-manager": "7.16.0", - "@typescript-eslint/types": "7.16.0", - "@typescript-eslint/typescript-estree": "7.16.0", - "@typescript-eslint/visitor-keys": "7.16.0", + "version": "7.16.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.16.1.tgz", + "integrity": "sha512-u+1Qx86jfGQ5i4JjK33/FnawZRpsLxRnKzGE6EABZ40KxVT/vWsiZFEBBHjFOljmmV3MBYOHEKi0Jm9hbAOClA==", + "dependencies": { + "@typescript-eslint/scope-manager": "7.16.1", + "@typescript-eslint/types": "7.16.1", + "@typescript-eslint/typescript-estree": "7.16.1", + "@typescript-eslint/visitor-keys": "7.16.1", "debug": "^4.3.4" }, "engines": { @@ -10003,12 +9975,12 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.16.0.tgz", - "integrity": "sha512-8gVv3kW6n01Q6TrI1cmTZ9YMFi3ucDT7i7aI5lEikk2ebk1AEjrwX8MDTdaX5D7fPXMBLvnsaa0IFTAu+jcfOw==", + "version": "7.16.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.16.1.tgz", + "integrity": "sha512-nYpyv6ALte18gbMz323RM+vpFpTjfNdyakbf3nsLvF43uF9KeNC289SUEW3QLZ1xPtyINJ1dIsZOuWuSRIWygw==", "dependencies": { - "@typescript-eslint/types": "7.16.0", - "@typescript-eslint/visitor-keys": "7.16.0" + "@typescript-eslint/types": "7.16.1", + "@typescript-eslint/visitor-keys": "7.16.1" }, "engines": { "node": "^18.18.0 || >=20.0.0" @@ -10019,13 +9991,13 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.16.0.tgz", - "integrity": "sha512-j0fuUswUjDHfqV/UdW6mLtOQQseORqfdmoBNDFOqs9rvNVR2e+cmu6zJu/Ku4SDuqiJko6YnhwcL8x45r8Oqxg==", + "version": "7.16.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.16.1.tgz", + "integrity": "sha512-rbu/H2MWXN4SkjIIyWcmYBjlp55VT+1G3duFOIukTNFxr9PI35pLc2ydwAfejCEitCv4uztA07q0QWanOHC7dA==", "dev": true, "dependencies": { - "@typescript-eslint/typescript-estree": "7.16.0", - "@typescript-eslint/utils": "7.16.0", + "@typescript-eslint/typescript-estree": "7.16.1", + "@typescript-eslint/utils": "7.16.1", "debug": "^4.3.4", "ts-api-utils": "^1.3.0" }, @@ -10046,9 +10018,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.16.0.tgz", - "integrity": "sha512-fecuH15Y+TzlUutvUl9Cc2XJxqdLr7+93SQIbcZfd4XRGGKoxyljK27b+kxKamjRkU7FYC6RrbSCg0ALcZn/xw==", + "version": "7.16.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.16.1.tgz", + "integrity": "sha512-AQn9XqCzUXd4bAVEsAXM/Izk11Wx2u4H3BAfQVhSfzfDOm/wAON9nP7J5rpkCxts7E5TELmN845xTUCQrD1xIQ==", "engines": { "node": "^18.18.0 || >=20.0.0" }, @@ -10058,12 +10030,12 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.16.0.tgz", - "integrity": "sha512-a5NTvk51ZndFuOLCh5OaJBELYc2O3Zqxfl3Js78VFE1zE46J2AaVuW+rEbVkQznjkmlzWsUI15BG5tQMixzZLw==", + "version": "7.16.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.16.1.tgz", + "integrity": "sha512-0vFPk8tMjj6apaAZ1HlwM8w7jbghC8jc1aRNJG5vN8Ym5miyhTQGMqU++kuBFDNKe9NcPeZ6x0zfSzV8xC1UlQ==", "dependencies": { - "@typescript-eslint/types": "7.16.0", - "@typescript-eslint/visitor-keys": "7.16.0", + "@typescript-eslint/types": "7.16.1", + "@typescript-eslint/visitor-keys": "7.16.1", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -10085,9 +10057,9 @@ } }, "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": { - "version": "7.6.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", - "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", "bin": { "semver": "bin/semver.js" }, @@ -10096,15 +10068,15 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.16.0.tgz", - "integrity": "sha512-PqP4kP3hb4r7Jav+NiRCntlVzhxBNWq6ZQ+zQwII1y/G/1gdIPeYDCKr2+dH6049yJQsWZiHU6RlwvIFBXXGNA==", + "version": "7.16.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.16.1.tgz", + "integrity": "sha512-WrFM8nzCowV0he0RlkotGDujx78xudsxnGMBHI88l5J8wEhED6yBwaSLP99ygfrzAjsQvcYQ94quDwI0d7E1fA==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", - "@typescript-eslint/scope-manager": "7.16.0", - "@typescript-eslint/types": "7.16.0", - "@typescript-eslint/typescript-estree": "7.16.0" + "@typescript-eslint/scope-manager": "7.16.1", + "@typescript-eslint/types": "7.16.1", + "@typescript-eslint/typescript-estree": "7.16.1" }, "engines": { "node": "^18.18.0 || >=20.0.0" @@ -10118,11 +10090,11 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.16.0.tgz", - "integrity": "sha512-rMo01uPy9C7XxG7AFsxa8zLnWXTF8N3PYclekWSrurvhwiw1eW88mrKiAYe6s53AUY57nTRz8dJsuuXdkAhzCg==", + "version": "7.16.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.16.1.tgz", + "integrity": "sha512-Qlzzx4sE4u3FsHTPQAAQFJFNOuqtuY0LFrZHwQ8IHK705XxBiWOFkfKRWu6niB7hwfgnwIpO4jTC75ozW1PHWg==", "dependencies": { - "@typescript-eslint/types": "7.16.0", + "@typescript-eslint/types": "7.16.1", "eslint-visitor-keys": "^3.4.3" }, "engines": { @@ -10139,55 +10111,55 @@ "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==" }, "node_modules/@vue/compiler-core": { - "version": "3.4.31", - "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.4.31.tgz", - "integrity": "sha512-skOiodXWTV3DxfDhB4rOf3OGalpITLlgCeOwb+Y9GJpfQ8ErigdBUHomBzvG78JoVE8MJoQsb+qhZiHfKeNeEg==", + "version": "3.4.33", + "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.4.33.tgz", + "integrity": "sha512-MoIREbkdPQlnGfSKDMgzTqzqx5nmEjIc0ydLVYlTACGBsfvOJ4tHSbZXKVF536n6fB+0eZaGEOqsGThPpdvF5A==", "dependencies": { "@babel/parser": "^7.24.7", - "@vue/shared": "3.4.31", + "@vue/shared": "3.4.33", "entities": "^4.5.0", "estree-walker": "^2.0.2", "source-map-js": "^1.2.0" } }, "node_modules/@vue/compiler-dom": { - "version": "3.4.31", - "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.4.31.tgz", - "integrity": "sha512-wK424WMXsG1IGMyDGyLqB+TbmEBFM78hIsOJ9QwUVLGrcSk0ak6zYty7Pj8ftm7nEtdU/DGQxAXp0/lM/2cEpQ==", + "version": "3.4.33", + "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.4.33.tgz", + "integrity": "sha512-GzB8fxEHKw0gGet5BKlpfXEqoBnzSVWwMnT+dc25wE7pFEfrU/QsvjZMP9rD4iVXHBBoemTct8mN0GJEI6ZX5A==", "dependencies": { - "@vue/compiler-core": "3.4.31", - "@vue/shared": "3.4.31" + "@vue/compiler-core": "3.4.33", + "@vue/shared": "3.4.33" } }, "node_modules/@vue/compiler-sfc": { - "version": "3.4.31", - "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.4.31.tgz", - "integrity": "sha512-einJxqEw8IIJxzmnxmJBuK2usI+lJonl53foq+9etB2HAzlPjAS/wa7r0uUpXw5ByX3/0uswVSrjNb17vJm1kQ==", + "version": "3.4.33", + "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.4.33.tgz", + "integrity": "sha512-7rk7Vbkn21xMwIUpHQR4hCVejwE6nvhBOiDgoBcR03qvGqRKA7dCBSsHZhwhYUsmjlbJ7OtD5UFIyhP6BY+c8A==", "dependencies": { "@babel/parser": "^7.24.7", - "@vue/compiler-core": "3.4.31", - "@vue/compiler-dom": "3.4.31", - "@vue/compiler-ssr": "3.4.31", - "@vue/shared": "3.4.31", + "@vue/compiler-core": "3.4.33", + "@vue/compiler-dom": "3.4.33", + "@vue/compiler-ssr": "3.4.33", + "@vue/shared": "3.4.33", "estree-walker": "^2.0.2", "magic-string": "^0.30.10", - "postcss": "^8.4.38", + "postcss": "^8.4.39", "source-map-js": "^1.2.0" } }, "node_modules/@vue/compiler-ssr": { - "version": "3.4.31", - "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.4.31.tgz", - "integrity": "sha512-RtefmITAje3fJ8FSg1gwgDhdKhZVntIVbwupdyZDSifZTRMiWxWehAOTCc8/KZDnBOcYQ4/9VWxsTbd3wT0hAA==", + "version": "3.4.33", + "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.4.33.tgz", + "integrity": "sha512-0WveC9Ai+eT/1b6LCV5IfsufBZ0HP7pSSTdDjcuW302tTEgoBw8rHVHKPbGUtzGReUFCRXbv6zQDDgucnV2WzQ==", "dependencies": { - "@vue/compiler-dom": "3.4.31", - "@vue/shared": "3.4.31" + "@vue/compiler-dom": "3.4.33", + "@vue/shared": "3.4.33" } }, "node_modules/@vue/shared": { - "version": "3.4.31", - "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.4.31.tgz", - "integrity": "sha512-Yp3wtJk//8cO4NItOPpi3QkLExAr/aLBGZMmTtW9WpdwBCJpRM6zj9WgWktXAl8IDIozwNMByT45JP3tO3ACWA==" + "version": "3.4.33", + "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.4.33.tgz", + "integrity": "sha512-aoRY0jQk3A/cuvdkodTrM4NMfxco8n55eG4H7ML/CRy7OryHfiqvug4xrCBBMbbN+dvXAetDDwZW9DXWWjBntA==" }, "node_modules/@webassemblyjs/ast": { "version": "1.12.1", @@ -10519,14 +10491,14 @@ } }, "node_modules/ajv-formats/node_modules/ajv": { - "version": "8.16.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.16.0.tgz", - "integrity": "sha512-F0twR8U1ZU67JIEtekUcLkXkoO5mMMmgGD8sK/xUFzJ805jxHQl92hImFAqqXMyMYjSPOyUPAwHYhB72g5sTXw==", + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", "dependencies": { "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.4.1" + "require-from-string": "^2.0.2" }, "funding": { "type": "github", @@ -10736,6 +10708,38 @@ "deep-equal": "^2.0.5" } }, + "node_modules/aria-query/node_modules/deep-equal": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-2.2.3.tgz", + "integrity": "sha512-ZIwpnevOurS8bpT4192sqAowWM76JDKSHYzMLty3BZGSswgq6pBaH3DhCSW5xVAZICZyKdOBPjwww5wfgT/6PA==", + "dev": true, + "dependencies": { + "array-buffer-byte-length": "^1.0.0", + "call-bind": "^1.0.5", + "es-get-iterator": "^1.1.3", + "get-intrinsic": "^1.2.2", + "is-arguments": "^1.1.1", + "is-array-buffer": "^3.0.2", + "is-date-object": "^1.0.5", + "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.2", + "isarray": "^2.0.5", + "object-is": "^1.1.5", + "object-keys": "^1.1.1", + "object.assign": "^4.1.4", + "regexp.prototype.flags": "^1.5.1", + "side-channel": "^1.0.4", + "which-boxed-primitive": "^1.0.2", + "which-collection": "^1.0.1", + "which-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/arr-union": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", @@ -10888,18 +10892,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/array.prototype.toreversed": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/array.prototype.toreversed/-/array.prototype.toreversed-1.1.2.tgz", - "integrity": "sha512-wwDCoT4Ck4Cz7sLtgUmzR5UV3YF5mFHUlbChCzZBQZ+0m2cl/DH3tKgvphv1nKgFsJ48oCSg6p91q2Vm0I/ZMA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "es-shim-unscopables": "^1.0.0" - } - }, "node_modules/array.prototype.tosorted": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/array.prototype.tosorted/-/array.prototype.tosorted-1.1.4.tgz", @@ -11080,6 +11072,38 @@ "deep-equal": "^2.0.5" } }, + "node_modules/axobject-query/node_modules/deep-equal": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-2.2.3.tgz", + "integrity": "sha512-ZIwpnevOurS8bpT4192sqAowWM76JDKSHYzMLty3BZGSswgq6pBaH3DhCSW5xVAZICZyKdOBPjwww5wfgT/6PA==", + "dev": true, + "dependencies": { + "array-buffer-byte-length": "^1.0.0", + "call-bind": "^1.0.5", + "es-get-iterator": "^1.1.3", + "get-intrinsic": "^1.2.2", + "is-arguments": "^1.1.1", + "is-array-buffer": "^3.0.2", + "is-date-object": "^1.0.5", + "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.2", + "isarray": "^2.0.5", + "object-is": "^1.1.5", + "object-keys": "^1.1.1", + "object.assign": "^4.1.4", + "regexp.prototype.flags": "^1.5.1", + "side-channel": "^1.0.4", + "which-boxed-primitive": "^1.0.2", + "which-collection": "^1.0.1", + "which-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/b4a": { "version": "1.6.6", "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.6.6.tgz", @@ -11620,6 +11644,13 @@ "which", "write-file-atomic" ], + "workspaces": [ + "docs", + "smoke-tests", + "mock-globals", + "mock-registry", + "workspaces/*" + ], "dependencies": { "@isaacs/string-locale-compare": "^1.1.0", "@npmcli/arborist": "^6.5.0", @@ -13529,19 +13560,6 @@ "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, - "node_modules/browndash-components/node_modules/npm/node_modules/node-gyp/node_modules/readable-stream": { - "version": "3.6.2", - "inBundle": true, - "license": "MIT", - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, "node_modules/browndash-components/node_modules/npm/node_modules/node-gyp/node_modules/signal-exit": { "version": "3.0.7", "inBundle": true, @@ -13987,6 +14005,19 @@ "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, + "node_modules/browndash-components/node_modules/npm/node_modules/readable-stream": { + "version": "3.6.2", + "inBundle": true, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/browndash-components/node_modules/npm/node_modules/retry": { "version": "0.12.0", "inBundle": true, @@ -14872,9 +14903,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001641", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001641.tgz", - "integrity": "sha512-Phv5thgl67bHYo1TtMY/MurjkHhV4EDaCosezRXgZ8jzA/Ub+wjxAvbGvjoFENStinwi5kCyOYV3mi5tOGykwA==", + "version": "1.0.30001643", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001643.tgz", + "integrity": "sha512-ERgWGNleEilSrHM6iUz/zJNSQTP8Mr21wDWpdgvRwcTXGAq6jMtOUPP4dqFPTdKqZ2wKTdtB+uucZ3MRpAUSmg==", "funding": [ { "type": "opencollective", @@ -15559,6 +15590,11 @@ "tinyqueue": "^2.0.3" } }, + "node_modules/concaveman/node_modules/quickselect": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/quickselect/-/quickselect-2.0.0.tgz", + "integrity": "sha512-RKJ22hX8mHe3Y6wH/N3wCM6BWtjaxIyyUIkpHOvfFnxdI4yD4tBXEBKSbriGujF6jnSVkJrffuo6vxACiSSxIw==" + }, "node_modules/concaveman/node_modules/rbush": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/rbush/-/rbush-3.0.1.tgz", @@ -15887,9 +15923,9 @@ } }, "node_modules/css-loader/node_modules/semver": { - "version": "7.6.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", - "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", "bin": { "semver": "bin/semver.js" }, @@ -16061,9 +16097,9 @@ "integrity": "sha512-GAj5FOq0Hd+RsCGVJxZuKaIDXDf3h6GQoNEjFgbLLI/trgtavwUbSnZ5pVfg27DVCaWjIohryS0JFwIJyT2cMg==" }, "node_modules/cytoscape": { - "version": "3.30.0", - "resolved": "https://registry.npmjs.org/cytoscape/-/cytoscape-3.30.0.tgz", - "integrity": "sha512-l590mjTHT6/Cbxp13dGPC2Y7VXdgc+rUeF8AnF/JPzhjNevbDJfObnJgaSjlldOgBQZbue+X6IUZ7r5GAgvauQ==", + "version": "3.30.1", + "resolved": "https://registry.npmjs.org/cytoscape/-/cytoscape-3.30.1.tgz", + "integrity": "sha512-TRJc3HbBPkHd50u9YfJh2FxD1lDLZ+JXnJoyBn5LkncoeuT7fapO/Hq/Ed8TdFclaKshzInge2i30bg7VKeoPQ==", "engines": { "node": ">=0.10" } @@ -16627,9 +16663,9 @@ } }, "node_modules/dayjs": { - "version": "1.11.11", - "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.11.tgz", - "integrity": "sha512-okzr3f11N6WuqYtZSvm+F776mB41wRZMhKP+hc34YdW+KmtYYK9iqvHSwo2k9FEH3fhGXvOPV6yz2IcSrfRUDg==" + "version": "1.11.12", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.12.tgz", + "integrity": "sha512-Rt2g+nTbLlDWZTwwrIXjy9MeiZmSDI375FvZs72ngxx8PDC6YXOeR3q5LAuPzjZQxhiWdRKac7RKV+YyQYfYIg==" }, "node_modules/debug": { "version": "4.3.5", @@ -16725,29 +16761,16 @@ } }, "node_modules/deep-equal": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-2.2.3.tgz", - "integrity": "sha512-ZIwpnevOurS8bpT4192sqAowWM76JDKSHYzMLty3BZGSswgq6pBaH3DhCSW5xVAZICZyKdOBPjwww5wfgT/6PA==", - "dev": true, + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.1.2.tgz", + "integrity": "sha512-5tdhKF6DbU7iIzrIOa1AOUt39ZRm13cmL1cGEh//aqR8x9+tNfbywRf0n5FD/18OKMdo7DNEtrX2t22ZAkI+eg==", "dependencies": { - "array-buffer-byte-length": "^1.0.0", - "call-bind": "^1.0.5", - "es-get-iterator": "^1.1.3", - "get-intrinsic": "^1.2.2", "is-arguments": "^1.1.1", - "is-array-buffer": "^3.0.2", "is-date-object": "^1.0.5", "is-regex": "^1.1.4", - "is-shared-array-buffer": "^1.0.2", - "isarray": "^2.0.5", "object-is": "^1.1.5", "object-keys": "^1.1.1", - "object.assign": "^4.1.4", - "regexp.prototype.flags": "^1.5.1", - "side-channel": "^1.0.4", - "which-boxed-primitive": "^1.0.2", - "which-collection": "^1.0.1", - "which-typed-array": "^1.1.13" + "regexp.prototype.flags": "^1.5.1" }, "engines": { "node": ">= 0.4" @@ -16951,9 +16974,9 @@ } }, "node_modules/depcheck/node_modules/semver": { - "version": "7.6.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", - "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", "bin": { "semver": "bin/semver.js" }, @@ -17226,9 +17249,9 @@ "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" }, "node_modules/electron-to-chromium": { - "version": "1.4.823", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.823.tgz", - "integrity": "sha512-4h+oPeAiGQOHFyUJOqpoEcPj/xxlicxBzOErVeYVMMmAiXUXsGpsFd0QXBMaUUbnD8hhSfLf9uw+MlsoIA7j5w==" + "version": "1.4.832", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.832.tgz", + "integrity": "sha512-cTen3SB0H2SGU7x467NRe1eVcQgcuS6jckKfWJHia2eo0cHIGOqHoAxevIYZD4eRHcWjkvFzo93bi3vJ9W+1lA==" }, "node_modules/elkjs": { "version": "0.9.3", @@ -17309,9 +17332,9 @@ } }, "node_modules/engine.io-parser": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.2.2.tgz", - "integrity": "sha512-RcyUFKA93/CXH20l4SoVvzZfrSDMOTUS3bWVpTt2FuFP+XYrL8i8oonHP7WInRyVHXh0n/ORtoeiE1os+8qkSw==", + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.2.3.tgz", + "integrity": "sha512-HqD3yTBfnBxIrbnM1DoD6Pcq8NECnh8d4As1Qgh0z5Gg3jRRIqijury0CL3ghu/edArpUYiYqQiDUQBIs4np3Q==", "engines": { "node": ">=10.0.0" } @@ -18828,13 +18851,13 @@ } }, "node_modules/eslint-plugin-prettier": { - "version": "5.1.3", - "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.1.3.tgz", - "integrity": "sha512-C9GCVAs4Eq7ZC/XFQHITLiHJxQngdtraXaM+LoUFoFp/lHNl2Zn8f3WQbe9HvTBBQ9YnKFB0/2Ajdqwo5D1EAw==", + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.2.1.tgz", + "integrity": "sha512-gH3iR3g4JfF+yYPaJYkN7jEl9QbweL/YfkoRlNnuIEHEz1vHVlCmWOS+eGGiRuzHQXdJFCOTxRgvju9b8VUmrw==", "dev": true, "dependencies": { "prettier-linter-helpers": "^1.0.0", - "synckit": "^0.8.6" + "synckit": "^0.9.1" }, "engines": { "node": "^14.18.0 || >=16.0.0" @@ -18858,35 +18881,35 @@ } }, "node_modules/eslint-plugin-react": { - "version": "7.34.3", - "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.34.3.tgz", - "integrity": "sha512-aoW4MV891jkUulwDApQbPYTVZmeuSyFrudpbTAQuj5Fv8VL+o6df2xIGpw8B0hPjAaih1/Fb0om9grCdyFYemA==", + "version": "7.35.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.35.0.tgz", + "integrity": "sha512-v501SSMOWv8gerHkk+IIQBkcGRGrO2nfybfj5pLxuJNFTPxxA3PSryhXTK+9pNbtkggheDdsC0E9Q8CuPk6JKA==", "dev": true, "dependencies": { "array-includes": "^3.1.8", "array.prototype.findlast": "^1.2.5", "array.prototype.flatmap": "^1.3.2", - "array.prototype.toreversed": "^1.1.2", "array.prototype.tosorted": "^1.1.4", "doctrine": "^2.1.0", "es-iterator-helpers": "^1.0.19", "estraverse": "^5.3.0", + "hasown": "^2.0.2", "jsx-ast-utils": "^2.4.1 || ^3.0.0", "minimatch": "^3.1.2", "object.entries": "^1.1.8", "object.fromentries": "^2.0.8", - "object.hasown": "^1.1.4", "object.values": "^1.2.0", "prop-types": "^15.8.1", "resolve": "^2.0.0-next.5", "semver": "^6.3.1", - "string.prototype.matchall": "^4.0.11" + "string.prototype.matchall": "^4.0.11", + "string.prototype.repeat": "^1.0.0" }, "engines": { "node": ">=4" }, "peerDependencies": { - "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8" + "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7" } }, "node_modules/eslint-plugin-react-hooks": { @@ -19596,6 +19619,11 @@ "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==" }, + "node_modules/fast-uri": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.0.1.tgz", + "integrity": "sha512-MWipKbbYiYI0UC7cl8m/i/IWTqfC8YXsqjzybjddLsFjStroQzsHXkc73JutMvBiXmOvapk+axIl79ig5t55Bw==" + }, "node_modules/fast-xml-parser": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.4.0.tgz", @@ -20226,9 +20254,9 @@ } }, "node_modules/fork-ts-checker-webpack-plugin/node_modules/semver": { - "version": "7.6.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", - "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", "bin": { "semver": "bin/semver.js" }, @@ -20570,25 +20598,6 @@ "deep-equal": "^1.0.0" } }, - "node_modules/geojson-equality/node_modules/deep-equal": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.1.2.tgz", - "integrity": "sha512-5tdhKF6DbU7iIzrIOa1AOUt39ZRm13cmL1cGEh//aqR8x9+tNfbywRf0n5FD/18OKMdo7DNEtrX2t22ZAkI+eg==", - "dependencies": { - "is-arguments": "^1.1.1", - "is-date-object": "^1.0.5", - "is-regex": "^1.1.4", - "object-is": "^1.1.5", - "object-keys": "^1.1.1", - "regexp.prototype.flags": "^1.5.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/geojson-rbush": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/geojson-rbush/-/geojson-rbush-3.2.0.tgz", @@ -20606,6 +20615,11 @@ "resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.8.tgz", "integrity": "sha512-1rkryxURpr6aWP7R786/UQOkJ3PcpQiWkAXBmdWc7ryFWqN6a4xfK7BtjXvFBKO9LjQ+MWQSWxYeZX1OApnArA==" }, + "node_modules/geojson-rbush/node_modules/quickselect": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/quickselect/-/quickselect-2.0.0.tgz", + "integrity": "sha512-RKJ22hX8mHe3Y6wH/N3wCM6BWtjaxIyyUIkpHOvfFnxdI4yD4tBXEBKSbriGujF6jnSVkJrffuo6vxACiSSxIw==" + }, "node_modules/geojson-rbush/node_modules/rbush": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/rbush/-/rbush-3.0.1.tgz", @@ -20704,9 +20718,9 @@ } }, "node_modules/get-tsconfig": { - "version": "4.7.5", - "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.7.5.tgz", - "integrity": "sha512-ZCuZCnlqNzjb4QprAzXKdpp/gh6KTxSJuw3IBsPnV/7fV4NxC9ckB+vPTt8w7fJA0TaSD7c55BR47JD6MEDyDw==", + "version": "4.7.6", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.7.6.tgz", + "integrity": "sha512-ZAqrLlu18NbDdRaHq+AKXzAmqIUPswPWKUchfytdAjiRFnCe5ojG2bstg6mRiZabkKfCoL/e98pbBELIV/YCeA==", "dev": true, "dependencies": { "resolve-pkg-maps": "^1.0.0" @@ -21959,8 +21973,7 @@ "node_modules/image-size-stream/node_modules/image-size": { "version": "0.3.5", "resolved": "git+ssh://git@github.com/netroy/image-size.git#da2c863807a3e9602617bdd357b0de3ab4a064c1", - "integrity": "sha512-nF4/PT7i5t72LJKRBAXfM8PCzUDQurOUzPsNUjQDpUhFpLNuCpSY0+XIHNcc/LtoU3GqSCK3wQDU+CCty3Bfcw==", - "license": "MIT", + "integrity": "sha512-bOV/01RFEAMM7OJU4alHoipipEYAdVk1W9rto2aN1ZnEZsZ1A1OCVJJ2iMaaJIKidVXGZNbP9knmW/3wWTZ4/Q==", "bin": { "image-size": "bin/image-size" }, @@ -21995,9 +22008,9 @@ "integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==" }, "node_modules/immutable": { - "version": "4.3.6", - "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.6.tgz", - "integrity": "sha512-Ju0+lEMyzMVZarkTn/gqRpdqd5dOPaz1mCZ0SH3JV6iFw81PldE/PEB1hWVEA288HPt4WXW8O7AWxB10M+03QQ==" + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.7.tgz", + "integrity": "sha512-1hqclzwYwjRDFLjcFxOM5AYkkG0rpFPpr1RLPMEuGczoS7YA8gLhy8SWXYRAA/XwfEHpfo3cw5JGioS32fnMRw==" }, "node_modules/import-fresh": { "version": "3.3.0", @@ -22023,9 +22036,9 @@ } }, "node_modules/import-local": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", - "integrity": "sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.2.0.tgz", + "integrity": "sha512-2SPlun1JUPWoM6t3F0dw0FkCF/jWY8kttcY4f599GLTSjh2OCuuhdTkJQsEcZzBqbXZGKMK2OqW1oZsjtf/gQA==", "dependencies": { "pkg-dir": "^4.2.0", "resolve-cwd": "^3.0.0" @@ -22591,9 +22604,9 @@ } }, "node_modules/is-core-module": { - "version": "2.14.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.14.0.tgz", - "integrity": "sha512-a5dFJih5ZLYlRtDc0dZWP7RiKr6xIKzmn/oAYCDvdLThadVgyJwlaoQPmRtMSpz+rk0OGAgIu+TcM9HUF0fk1A==", + "version": "2.15.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.15.0.tgz", + "integrity": "sha512-Dd+Lb2/zvk9SKy1TGCt1wFJFo/MWBPMX5x7KcvLajWTGuomczdQX61PvY5yK6SVACwpoexWo81IfFyoKY2QnTA==", "dependencies": { "hasown": "^2.0.2" }, @@ -23108,15 +23121,12 @@ } }, "node_modules/jackspeak": { - "version": "3.4.2", - "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.2.tgz", - "integrity": "sha512-qH3nOSj8q/8+Eg8LUPOq3C+6HWkpUioIjDsq1+D4zY91oZvpPttw8GwtF1nReRYKXl+1AORyFqtm2f5Q1SB6/Q==", + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", + "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", "dependencies": { "@isaacs/cliui": "^8.0.2" }, - "engines": { - "node": "14 >=14.21 || 16 >=16.20 || >=18" - }, "funding": { "url": "https://github.com/sponsors/isaacs" }, @@ -23356,9 +23366,9 @@ "integrity": "sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==" }, "node_modules/jsdom": { - "version": "24.1.0", - "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-24.1.0.tgz", - "integrity": "sha512-6gpM7pRXCwIOKxX47cgOyvyQDN/Eh0f1MeKySBV2xGdKtqJBLj8P25eY3EVCWo2mglDDzozR2r2MW4T+JiNUZA==", + "version": "24.1.1", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-24.1.1.tgz", + "integrity": "sha512-5O1wWV99Jhq4DV7rCLIoZ/UIhyQeDR7wHVyZAHAshbrvZsLs+Xzz7gtwnlJTJDjleiTKh54F4dXrX70vJQTyJQ==", "dev": true, "dependencies": { "cssstyle": "^4.0.1", @@ -23367,11 +23377,11 @@ "form-data": "^4.0.0", "html-encoding-sniffer": "^4.0.0", "http-proxy-agent": "^7.0.2", - "https-proxy-agent": "^7.0.4", + "https-proxy-agent": "^7.0.5", "is-potential-custom-element-name": "^1.0.1", - "nwsapi": "^2.2.10", + "nwsapi": "^2.2.12", "parse5": "^7.1.2", - "rrweb-cssom": "^0.7.0", + "rrweb-cssom": "^0.7.1", "saxes": "^6.0.0", "symbol-tree": "^3.2.4", "tough-cookie": "^4.1.4", @@ -23380,7 +23390,7 @@ "whatwg-encoding": "^3.1.1", "whatwg-mimetype": "^4.0.0", "whatwg-url": "^14.0.0", - "ws": "^8.17.0", + "ws": "^8.18.0", "xml-name-validator": "^5.0.0" }, "engines": { @@ -24175,9 +24185,13 @@ "dev": true }, "node_modules/mapbox-gl": { - "version": "3.5.1", - "resolved": "https://registry.npmjs.org/mapbox-gl/-/mapbox-gl-3.5.1.tgz", - "integrity": "sha512-sf4N18vl5FHS8lPRWZjTZShgIziDqSxan3MazHClvYYXezsAPn6hApRvAS2HEMTq7MXzRcvvt4sYgQWLubwnBw==", + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/mapbox-gl/-/mapbox-gl-3.5.2.tgz", + "integrity": "sha512-KUrmDmLFKPp3MSsWGNTH5uvtYwJknV+eFJ+vxiN6hqKpzbme37z+JfYs5Mehs3CgFaIV/pUdnEV9UPUZJPuS+Q==", + "workspaces": [ + "src/style-spec", + "test/build/typings" + ], "dependencies": { "@mapbox/jsonlint-lines-primitives": "^2.0.2", "@mapbox/mapbox-gl-supported": "^3.0.0", @@ -24186,6 +24200,8 @@ "@mapbox/unitbezier": "^0.0.1", "@mapbox/vector-tile": "^1.3.1", "@mapbox/whoots-js": "^3.1.0", + "@types/geojson": "^7946.0.14", + "@types/mapbox__vector-tile": "^1.3.4", "cheap-ruler": "^4.0.0", "csscolorparser": "~1.0.3", "earcut": "^3.0.0", @@ -24198,12 +24214,12 @@ "murmurhash-js": "^1.0.0", "pbf": "^3.2.1", "potpack": "^2.0.0", - "quickselect": "^2.0.0", + "quickselect": "^3.0.0", "rw": "^1.3.3", "serialize-to-js": "^3.1.2", "supercluster": "^8.0.1", - "tiny-lru": "^11.2.6", - "tinyqueue": "^2.0.3", + "tiny-lru": "^11.2.11", + "tinyqueue": "^3.0.0", "tweakpane": "^4.0.4", "vt-pbf": "^3.1.3" } @@ -24213,6 +24229,11 @@ "resolved": "https://registry.npmjs.org/earcut/-/earcut-3.0.0.tgz", "integrity": "sha512-41Fs7Q/PLq1SDbqjsgcY7GA42T0jvaCNGXgGtsNdvg+Yv8eIu06bxv4/PoREkZ9nMDNwnUSG9OFB9+yv8eKhDg==" }, + "node_modules/mapbox-gl/node_modules/tinyqueue": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/tinyqueue/-/tinyqueue-3.0.0.tgz", + "integrity": "sha512-gRa9gwYU3ECmQYv3lslts5hxuIa90veaEcxDYuu3QGOIAEM2mOZkVHp48ANJuu1CURtRdHKUBY5Lm1tHV+sD4g==" + }, "node_modules/markdown-it": { "version": "14.1.0", "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-14.1.0.tgz", @@ -30807,9 +30828,9 @@ "integrity": "sha512-yc0LhH6tItlvfLBugVUEtgawwFU2sIe+cSdmRJJCTMZ5GEJyLxNyC/NIOAOGk67Fa8GNpOttO3Xz/1bHpXFD/g==" }, "node_modules/mobx": { - "version": "6.13.0", - "resolved": "https://registry.npmjs.org/mobx/-/mobx-6.13.0.tgz", - "integrity": "sha512-1laWODrBWmB7mDJ8EClCjUQTyLwJ0ydJgE4FtK7t9r3JnjXgc9OhmYs2P4RtHrY1co5+4T6cKP2UswX2SU29mA==", + "version": "6.13.1", + "resolved": "https://registry.npmjs.org/mobx/-/mobx-6.13.1.tgz", + "integrity": "sha512-ekLRxgjWJr8hVxj9ZKuClPwM/iHckx3euIJ3Np7zLVNtqJvfbbq7l370W/98C8EabdQ1pB5Jd3BbDWxJPNnaOg==", "funding": { "type": "opencollective", "url": "https://opencollective.com/mobx" @@ -30872,9 +30893,9 @@ } }, "node_modules/mocha": { - "version": "10.6.0", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.6.0.tgz", - "integrity": "sha512-hxjt4+EEB0SA0ZDygSS015t65lJw/I2yRCS3Ae+SJ5FrbzrXgfYwJr96f0OvIXdj7h4lv/vLCrH3rkiuizFSvw==", + "version": "10.7.0", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.7.0.tgz", + "integrity": "sha512-v8/rBWr2VO5YkspYINnvu81inSz2y3ODJrhO175/Exzor1RcEZZkizgE2A+w/CAXXoESS8Kys5E62dOHGHzULA==", "dev": true, "dependencies": { "ansi-colors": "^4.1.3", @@ -31064,9 +31085,9 @@ } }, "node_modules/mongoose": { - "version": "8.5.0", - "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-8.5.0.tgz", - "integrity": "sha512-iGgZvgO+fIgX1AQMehkG+Wj8qrWc9it8vUZrSKWjrebgfwHTqUcIdTgWK8mT1us1xd83NOQxiuGbg9ZJtLxs2Q==", + "version": "8.5.1", + "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-8.5.1.tgz", + "integrity": "sha512-OhVcwVl91A1G6+XpjDcpkGP7l7ikZkxa0DylX7NT/lcEqAjggzSdqDxb48A+xsDxqNAr0ntSJ1yiE3+KJTOd5Q==", "dependencies": { "bson": "^6.7.0", "kareem": "2.6.3", @@ -31401,9 +31422,9 @@ } }, "node_modules/node-releases": { - "version": "2.0.14", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz", - "integrity": "sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==" + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.18.tgz", + "integrity": "sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==" }, "node_modules/node-stream-zip": { "version": "1.15.0", @@ -31473,9 +31494,9 @@ } }, "node_modules/nodemon/node_modules/semver": { - "version": "7.6.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", - "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", "bin": { "semver": "bin/semver.js" }, @@ -31522,9 +31543,9 @@ } }, "node_modules/npm": { - "version": "10.8.1", - "resolved": "https://registry.npmjs.org/npm/-/npm-10.8.1.tgz", - "integrity": "sha512-Dp1C6SvSMYQI7YHq/y2l94uvI+59Eqbu1EpuKQHQ8p16txXRuRit5gH3Lnaagk2aXDIjg/Iru9pd05bnneKgdw==", + "version": "10.8.2", + "resolved": "https://registry.npmjs.org/npm/-/npm-10.8.2.tgz", + "integrity": "sha512-x/AIjFIKRllrhcb48dqUNAAZl0ig9+qMuN91RpZo3Cb2+zuibfh+KISl6+kVVyktDz230JKc208UkQwwMqyB+w==", "bundleDependencies": [ "@isaacs/string-locale-compare", "@npmcli/arborist", @@ -31595,15 +31616,22 @@ "which", "write-file-atomic" ], + "workspaces": [ + "docs", + "smoke-tests", + "mock-globals", + "mock-registry", + "workspaces/*" + ], "dependencies": { "@isaacs/string-locale-compare": "^1.1.0", - "@npmcli/arborist": "^7.5.3", - "@npmcli/config": "^8.3.3", + "@npmcli/arborist": "^7.5.4", + "@npmcli/config": "^8.3.4", "@npmcli/fs": "^3.1.1", "@npmcli/map-workspaces": "^3.0.6", - "@npmcli/package-json": "^5.1.1", + "@npmcli/package-json": "^5.2.0", "@npmcli/promise-spawn": "^7.0.2", - "@npmcli/redact": "^2.0.0", + "@npmcli/redact": "^2.0.1", "@npmcli/run-script": "^8.1.0", "@sigstore/tuf": "^2.3.4", "abbrev": "^2.0.0", @@ -31614,7 +31642,7 @@ "cli-columns": "^4.0.0", "fastest-levenshtein": "^1.0.16", "fs-minipass": "^3.0.3", - "glob": "^10.4.1", + "glob": "^10.4.2", "graceful-fs": "^4.2.11", "hosted-git-info": "^7.0.2", "ini": "^4.1.3", @@ -31622,30 +31650,30 @@ "is-cidr": "^5.1.0", "json-parse-even-better-errors": "^3.0.2", "libnpmaccess": "^8.0.6", - "libnpmdiff": "^6.1.3", - "libnpmexec": "^8.1.2", - "libnpmfund": "^5.0.11", + "libnpmdiff": "^6.1.4", + "libnpmexec": "^8.1.3", + "libnpmfund": "^5.0.12", "libnpmhook": "^10.0.5", "libnpmorg": "^6.0.6", - "libnpmpack": "^7.0.3", + "libnpmpack": "^7.0.4", "libnpmpublish": "^9.0.9", "libnpmsearch": "^7.0.6", "libnpmteam": "^6.0.5", "libnpmversion": "^6.0.3", "make-fetch-happen": "^13.0.1", - "minimatch": "^9.0.4", + "minimatch": "^9.0.5", "minipass": "^7.1.1", "minipass-pipeline": "^1.2.4", "ms": "^2.1.2", "node-gyp": "^10.1.0", "nopt": "^7.2.1", - "normalize-package-data": "^6.0.1", + "normalize-package-data": "^6.0.2", "npm-audit-report": "^5.0.0", "npm-install-checks": "^6.3.0", "npm-package-arg": "^11.0.2", - "npm-pick-manifest": "^9.0.1", + "npm-pick-manifest": "^9.1.0", "npm-profile": "^10.0.0", - "npm-registry-fetch": "^17.0.1", + "npm-registry-fetch": "^17.1.0", "npm-user-validate": "^2.0.1", "p-map": "^4.0.0", "pacote": "^18.0.6", @@ -31768,7 +31796,7 @@ } }, "node_modules/npm/node_modules/@npmcli/arborist": { - "version": "7.5.3", + "version": "7.5.4", "inBundle": true, "license": "ISC", "dependencies": { @@ -31816,16 +31844,16 @@ } }, "node_modules/npm/node_modules/@npmcli/config": { - "version": "8.3.3", + "version": "8.3.4", "inBundle": true, "license": "ISC", "dependencies": { "@npmcli/map-workspaces": "^3.0.2", + "@npmcli/package-json": "^5.1.1", "ci-info": "^4.0.0", "ini": "^4.1.2", "nopt": "^7.2.1", "proc-log": "^4.2.0", - "read-package-json-fast": "^3.0.2", "semver": "^7.3.5", "walk-up-path": "^3.0.1" }, @@ -31845,11 +31873,12 @@ } }, "node_modules/npm/node_modules/@npmcli/git": { - "version": "5.0.7", + "version": "5.0.8", "inBundle": true, "license": "ISC", "dependencies": { "@npmcli/promise-spawn": "^7.0.0", + "ini": "^4.1.3", "lru-cache": "^10.0.1", "npm-pick-manifest": "^9.0.0", "proc-log": "^4.0.0", @@ -31923,7 +31952,7 @@ } }, "node_modules/npm/node_modules/@npmcli/package-json": { - "version": "5.1.1", + "version": "5.2.0", "inBundle": true, "license": "ISC", "dependencies": { @@ -31962,7 +31991,7 @@ } }, "node_modules/npm/node_modules/@npmcli/redact": { - "version": "2.0.0", + "version": "2.0.1", "inBundle": true, "license": "ISC", "engines": { @@ -32334,7 +32363,7 @@ } }, "node_modules/npm/node_modules/debug": { - "version": "4.3.4", + "version": "4.3.5", "inBundle": true, "license": "MIT", "dependencies": { @@ -32408,7 +32437,7 @@ } }, "node_modules/npm/node_modules/foreground-child": { - "version": "3.1.1", + "version": "3.2.1", "inBundle": true, "license": "ISC", "dependencies": { @@ -32433,16 +32462,8 @@ "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, - "node_modules/npm/node_modules/function-bind": { - "version": "1.1.2", - "inBundle": true, - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/npm/node_modules/glob": { - "version": "10.4.1", + "version": "10.4.2", "inBundle": true, "license": "ISC", "dependencies": { @@ -32450,6 +32471,7 @@ "jackspeak": "^3.1.2", "minimatch": "^9.0.4", "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", "path-scurry": "^1.11.1" }, "bin": { @@ -32467,17 +32489,6 @@ "inBundle": true, "license": "ISC" }, - "node_modules/npm/node_modules/hasown": { - "version": "2.0.2", - "inBundle": true, - "license": "MIT", - "dependencies": { - "function-bind": "^1.1.2" - }, - "engines": { - "node": ">= 0.4" - } - }, "node_modules/npm/node_modules/hosted-git-info": { "version": "7.0.2", "inBundle": true, @@ -32507,7 +32518,7 @@ } }, "node_modules/npm/node_modules/https-proxy-agent": { - "version": "7.0.4", + "version": "7.0.5", "inBundle": true, "license": "MIT", "dependencies": { @@ -32616,17 +32627,6 @@ "node": ">=14" } }, - "node_modules/npm/node_modules/is-core-module": { - "version": "2.13.1", - "inBundle": true, - "license": "MIT", - "dependencies": { - "hasown": "^2.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/npm/node_modules/is-fullwidth-code-point": { "version": "3.0.0", "inBundle": true, @@ -32646,7 +32646,7 @@ "license": "ISC" }, "node_modules/npm/node_modules/jackspeak": { - "version": "3.1.2", + "version": "3.4.0", "inBundle": true, "license": "BlueOak-1.0.0", "dependencies": { @@ -32714,11 +32714,11 @@ } }, "node_modules/npm/node_modules/libnpmdiff": { - "version": "6.1.3", + "version": "6.1.4", "inBundle": true, "license": "ISC", "dependencies": { - "@npmcli/arborist": "^7.5.3", + "@npmcli/arborist": "^7.5.4", "@npmcli/installed-package-contents": "^2.1.0", "binary-extensions": "^2.3.0", "diff": "^5.1.0", @@ -32732,11 +32732,11 @@ } }, "node_modules/npm/node_modules/libnpmexec": { - "version": "8.1.2", + "version": "8.1.3", "inBundle": true, "license": "ISC", "dependencies": { - "@npmcli/arborist": "^7.5.3", + "@npmcli/arborist": "^7.5.4", "@npmcli/run-script": "^8.1.0", "ci-info": "^4.0.0", "npm-package-arg": "^11.0.2", @@ -32752,11 +32752,11 @@ } }, "node_modules/npm/node_modules/libnpmfund": { - "version": "5.0.11", + "version": "5.0.12", "inBundle": true, "license": "ISC", "dependencies": { - "@npmcli/arborist": "^7.5.3" + "@npmcli/arborist": "^7.5.4" }, "engines": { "node": "^16.14.0 || >=18.0.0" @@ -32787,11 +32787,11 @@ } }, "node_modules/npm/node_modules/libnpmpack": { - "version": "7.0.3", + "version": "7.0.4", "inBundle": true, "license": "ISC", "dependencies": { - "@npmcli/arborist": "^7.5.3", + "@npmcli/arborist": "^7.5.4", "@npmcli/run-script": "^8.1.0", "npm-package-arg": "^11.0.2", "pacote": "^18.0.6" @@ -32887,7 +32887,7 @@ } }, "node_modules/npm/node_modules/minimatch": { - "version": "9.0.4", + "version": "9.0.5", "inBundle": true, "license": "ISC", "dependencies": { @@ -32957,26 +32957,6 @@ "node": ">=8" } }, - "node_modules/npm/node_modules/minipass-json-stream": { - "version": "1.0.1", - "inBundle": true, - "license": "MIT", - "dependencies": { - "jsonparse": "^1.3.1", - "minipass": "^3.0.0" - } - }, - "node_modules/npm/node_modules/minipass-json-stream/node_modules/minipass": { - "version": "3.3.6", - "inBundle": true, - "license": "ISC", - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/npm/node_modules/minipass-pipeline": { "version": "1.2.4", "inBundle": true, @@ -33122,12 +33102,11 @@ } }, "node_modules/npm/node_modules/normalize-package-data": { - "version": "6.0.1", + "version": "6.0.2", "inBundle": true, "license": "BSD-2-Clause", "dependencies": { "hosted-git-info": "^7.0.0", - "is-core-module": "^2.8.1", "semver": "^7.3.5", "validate-npm-package-license": "^3.0.4" }, @@ -33199,7 +33178,7 @@ } }, "node_modules/npm/node_modules/npm-pick-manifest": { - "version": "9.0.1", + "version": "9.1.0", "inBundle": true, "license": "ISC", "dependencies": { @@ -33225,15 +33204,15 @@ } }, "node_modules/npm/node_modules/npm-registry-fetch": { - "version": "17.0.1", + "version": "17.1.0", "inBundle": true, "license": "ISC", "dependencies": { "@npmcli/redact": "^2.0.0", + "jsonparse": "^1.3.1", "make-fetch-happen": "^13.0.0", "minipass": "^7.0.2", "minipass-fetch": "^3.0.0", - "minipass-json-stream": "^1.0.1", "minizlib": "^2.1.2", "npm-package-arg": "^11.0.0", "proc-log": "^4.0.0" @@ -33264,6 +33243,11 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/npm/node_modules/package-json-from-dist": { + "version": "1.0.0", + "inBundle": true, + "license": "BlueOak-1.0.0" + }, "node_modules/npm/node_modules/pacote": { "version": "18.0.6", "inBundle": true, @@ -33534,13 +33518,13 @@ } }, "node_modules/npm/node_modules/socks-proxy-agent": { - "version": "8.0.3", + "version": "8.0.4", "inBundle": true, "license": "MIT", "dependencies": { "agent-base": "^7.1.1", "debug": "^4.3.4", - "socks": "^2.7.1" + "socks": "^2.8.3" }, "engines": { "node": ">= 14" @@ -33951,9 +33935,9 @@ } }, "node_modules/nwsapi": { - "version": "2.2.10", - "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.10.tgz", - "integrity": "sha512-QK0sRs7MKv0tKe1+5uZIQk/C8XGza4DAnztJG8iD+TpJIORARrCxczA738awHrZoHeTjSSoHqao2teO0dC/gFQ==", + "version": "2.2.12", + "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.12.tgz", + "integrity": "sha512-qXDmcVlZV4XRtKFzddidpfVP4oMSGhga+xdMc25mv8kaLUHtgzCDhUxkrN8exkGdTlLNaXj7CV3GtON7zuGZ+w==", "dev": true }, "node_modules/oauth": { @@ -34134,23 +34118,6 @@ "node": ">= 0.4" } }, - "node_modules/object.hasown": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/object.hasown/-/object.hasown-1.1.4.tgz", - "integrity": "sha512-FZ9LZt9/RHzGySlBARE3VF+gE26TxR38SdmqOqliuTnl9wrKulaQs+4dee1V+Io8VfxqzAfHu6YuRgUy8OHoTg==", - "dev": true, - "dependencies": { - "define-properties": "^1.2.1", - "es-abstract": "^1.23.2", - "es-object-atoms": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/object.values": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.2.0.tgz", @@ -34240,9 +34207,9 @@ } }, "node_modules/openai": { - "version": "4.52.5", - "resolved": "https://registry.npmjs.org/openai/-/openai-4.52.5.tgz", - "integrity": "sha512-qqH8GsyPE3z06took/2uWOGqRcrZNlRoPAsihpg4jsl0+2Dfelnw6HDDMep0EI2Cfzw75nn3vHRZehep/IZzxg==", + "version": "4.52.7", + "resolved": "https://registry.npmjs.org/openai/-/openai-4.52.7.tgz", + "integrity": "sha512-dgxA6UZHary6NXUHEDj5TWt8ogv0+ibH+b4pT5RrWMjiRZVylNwLcw/2ubDrX5n0oUmHX/ZgudMJeemxzOvz7A==", "dependencies": { "@types/node": "^18.11.18", "@types/node-fetch": "^2.6.4", @@ -34258,9 +34225,9 @@ } }, "node_modules/openai/node_modules/@types/node": { - "version": "18.19.39", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.39.tgz", - "integrity": "sha512-nPwTRDKUctxw3di5b4TfT3I0sWDiWoPQCZjXhvdkINntwr8lcoVCKsTgnXeRubKIlfnV+eN/HYk6Jb40tbcEAQ==", + "version": "18.19.41", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.41.tgz", + "integrity": "sha512-LX84pRJ+evD2e2nrgYCHObGWkiQJ1mL+meAgbvnwk/US6vmMY7S2ygBTGV2Jw91s9vUsLSXeDEkUHZIJGLrhsg==", "dependencies": { "undici-types": "~5.26.4" } @@ -35067,9 +35034,9 @@ } }, "node_modules/postcss-selector-parser": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.0.tgz", - "integrity": "sha512-UMz42UD0UY0EApS0ZL9o1XnLhSTtvvvLe5Dc2H2O56fvRZi+KulDyf5ctDhhtYJBGKStV2FL1fy6253cmLgqVQ==", + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.1.tgz", + "integrity": "sha512-b4dlw/9V8A71rLIDsSwVmak9z2DuBUB7CA1/wSdelNEzqsjoSPeADTWNO09lpH49Diy3/JIZ2bSPB1dI3LJCHg==", "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" @@ -35106,9 +35073,9 @@ } }, "node_modules/prettier": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.3.2.tgz", - "integrity": "sha512-rAVeHYMcv8ATV5d508CFdn+8/pHPpXeIid1DdrPwXnaAdH7cqjVbpJaT5eq4yRAFU/lsbwYwSF/n5iNrdJHPQA==", + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.3.3.tgz", + "integrity": "sha512-i2tDNA0O5IrMO757lfrdQZCc2jPNDVntV0m/+4whiDfWaTKfMNgR7Qz0NAeGz/nRqF4m5/6CLzbP4/liHt12Ew==", "dev": true, "bin": { "prettier": "bin/prettier.cjs" @@ -35260,17 +35227,17 @@ } }, "node_modules/prosemirror-model": { - "version": "1.21.3", - "resolved": "https://registry.npmjs.org/prosemirror-model/-/prosemirror-model-1.21.3.tgz", - "integrity": "sha512-nt2Xs/RNGepD9hrrkzXvtCm1mpGJoQfFSPktGa0BF/aav6XsnmVGZ9sTXNWRLupAz5SCLa3EyKlFeK7zJWROKg==", + "version": "1.22.2", + "resolved": "https://registry.npmjs.org/prosemirror-model/-/prosemirror-model-1.22.2.tgz", + "integrity": "sha512-I4lS7HHIW47D0Xv/gWmi4iUWcQIDYaJKd8Hk4+lcSps+553FlQrhmxtItpEvTr75iAruhzVShVp6WUwsT6Boww==", "dependencies": { "orderedmap": "^2.0.0" } }, "node_modules/prosemirror-schema-list": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/prosemirror-schema-list/-/prosemirror-schema-list-1.4.0.tgz", - "integrity": "sha512-nZOIq/AkBSzCENxUyLm5ltWE53e2PLk65ghMN8qLQptOmDVixZlPqtMeQdiNw0odL9vNpalEjl3upgRkuJ/Jyw==", + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/prosemirror-schema-list/-/prosemirror-schema-list-1.4.1.tgz", + "integrity": "sha512-jbDyaP/6AFfDfu70VzySsD75Om2t3sXTOdl5+31Wlxlg62td1haUpty/ybajSfJ1pkGadlOfwQq9kgW5IMo1Rg==", "dependencies": { "prosemirror-model": "^1.0.0", "prosemirror-state": "^1.0.0", @@ -35296,9 +35263,9 @@ } }, "node_modules/prosemirror-view": { - "version": "1.33.8", - "resolved": "https://registry.npmjs.org/prosemirror-view/-/prosemirror-view-1.33.8.tgz", - "integrity": "sha512-4PhMr/ufz2cdvFgpUAnZfs+0xij3RsFysreeG9V/utpwX7AJtYCDVyuRxzWoMJIEf4C7wVihuBNMPpFLPCiLQw==", + "version": "1.33.9", + "resolved": "https://registry.npmjs.org/prosemirror-view/-/prosemirror-view-1.33.9.tgz", + "integrity": "sha512-xV1A0Vz9cIcEnwmMhKKFAOkfIp8XmJRnaZoPqNXrPS7EK5n11Ov8V76KhR0RsfQd/SIzmWY+bg+M44A2Lx/Nnw==", "dependencies": { "prosemirror-model": "^1.20.0", "prosemirror-state": "^1.0.0", @@ -35563,9 +35530,9 @@ } }, "node_modules/quickselect": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/quickselect/-/quickselect-2.0.0.tgz", - "integrity": "sha512-RKJ22hX8mHe3Y6wH/N3wCM6BWtjaxIyyUIkpHOvfFnxdI4yD4tBXEBKSbriGujF6jnSVkJrffuo6vxACiSSxIw==" + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/quickselect/-/quickselect-3.0.0.tgz", + "integrity": "sha512-XdjUArbK4Bm5fLLvlm5KpTFOiOThgfWWI4axAZDWg4E/0mKdZyI9tNEfds27qCi1ze/vwTR16kvmmGhRra3c2g==" }, "node_modules/random-bytes": { "version": "1.0.0", @@ -35930,9 +35897,9 @@ } }, "node_modules/react-intersection-observer": { - "version": "9.10.3", - "resolved": "https://registry.npmjs.org/react-intersection-observer/-/react-intersection-observer-9.10.3.tgz", - "integrity": "sha512-9NYfKwPZRovB6QJee7fDg0zz/SyYrqXtn5xTZU0vwLtLVBtfu9aZt1pVmr825REE49VPDZ7Lm5SNHjJBOTZHpA==", + "version": "9.13.0", + "resolved": "https://registry.npmjs.org/react-intersection-observer/-/react-intersection-observer-9.13.0.tgz", + "integrity": "sha512-y0UvBfjDiXqC8h0EWccyaj4dVBWMxgEx0t5RGNzQsvkfvZwugnKwxpu70StY4ivzYuMajavwUDjH4LJyIki9Lw==", "peerDependencies": { "react": "^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react-dom": "^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" @@ -37492,11 +37459,12 @@ } }, "node_modules/rimraf": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-6.0.0.tgz", - "integrity": "sha512-u+yqhM92LW+89cxUQK0SRyvXYQmyuKHx0jkx4W7KfwLGLqJnQM5031Uv1trE4gB9XEXBM/s6MxKlfW95IidqaA==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-6.0.1.tgz", + "integrity": "sha512-9dkvaxAsk/xNXSJzMgFqqMCuFgt2+KsOFek3TMLfo8NCPfWpBmqwyNn5Y+NX56QUYfCtsyhF3ayiboEoUmJk/A==", "dependencies": { - "glob": "^11.0.0" + "glob": "^11.0.0", + "package-json-from-dist": "^1.0.0" }, "bin": { "rimraf": "dist/esm/bin.mjs" @@ -37737,9 +37705,9 @@ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, "node_modules/sass": { - "version": "1.77.7", - "resolved": "https://registry.npmjs.org/sass/-/sass-1.77.7.tgz", - "integrity": "sha512-9ywH75cO+rLjbrZ6en3Gp8qAMwPGBapFtlsMJoDTkcMU/bSe5a6cjKVUn5Jr4Gzg5GbP3HE8cm+02pLCgcoMow==", + "version": "1.77.8", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.77.8.tgz", + "integrity": "sha512-4UHg6prsrycW20fqLGPShtEvo/WyHRVRHwOP4DzkUrObWoWI05QBSfzU71TVB7PFaL104TwNaHpjlWXAZbQiNQ==", "dependencies": { "chokidar": ">=3.0.0 <4.0.0", "immutable": "^4.0.0", @@ -37835,14 +37803,14 @@ } }, "node_modules/schema-utils/node_modules/ajv": { - "version": "8.16.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.16.0.tgz", - "integrity": "sha512-F0twR8U1ZU67JIEtekUcLkXkoO5mMMmgGD8sK/xUFzJ805jxHQl92hImFAqqXMyMYjSPOyUPAwHYhB72g5sTXw==", + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", "dependencies": { "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.4.1" + "require-from-string": "^2.0.2" }, "funding": { "type": "github", @@ -38346,9 +38314,9 @@ } }, "node_modules/simple-update-notifier/node_modules/semver": { - "version": "7.6.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", - "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", "bin": { "semver": "bin/semver.js" }, @@ -38926,6 +38894,16 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/string.prototype.repeat": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/string.prototype.repeat/-/string.prototype.repeat-1.0.0.tgz", + "integrity": "sha512-0u/TldDbKD8bFCQ/4f5+mNRrXwZ8hg2w7ZR8wa16e8z9XpePWl3eGEcUD0OXpEH/VJH/2G3gjUtR3ZOiBe2S/w==", + "dev": true, + "dependencies": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.5" + } + }, "node_modules/string.prototype.trim": { "version": "1.2.9", "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.9.tgz", @@ -39130,9 +39108,9 @@ } }, "node_modules/styled-components": { - "version": "6.1.11", - "resolved": "https://registry.npmjs.org/styled-components/-/styled-components-6.1.11.tgz", - "integrity": "sha512-Ui0jXPzbp1phYij90h12ksljKGqF8ncGx+pjrNPsSPhbUUjWT2tD1FwGo2LF6USCnbrsIhNngDfodhxbegfEOA==", + "version": "6.1.12", + "resolved": "https://registry.npmjs.org/styled-components/-/styled-components-6.1.12.tgz", + "integrity": "sha512-n/O4PzRPhbYI0k1vKKayfti3C/IGcPf+DqcrOB7O/ab9x4u/zjqraneT5N45+sIe87cxrCApXM8Bna7NYxwoTA==", "dependencies": { "@emotion/is-prop-valid": "1.2.2", "@emotion/unitless": "0.8.1", @@ -39156,6 +39134,24 @@ "react-dom": ">= 16.8.0" } }, + "node_modules/styled-components/node_modules/@emotion/is-prop-valid": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-1.2.2.tgz", + "integrity": "sha512-uNsoYd37AFmaCdXlg6EYD1KaPOaRWRByMCYzbKUX4+hhMfrxdVSelShywL4JVaAeM/eHUOSprYBQls+/neX3pw==", + "dependencies": { + "@emotion/memoize": "^0.8.1" + } + }, + "node_modules/styled-components/node_modules/@emotion/memoize": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.8.1.tgz", + "integrity": "sha512-W2P2c/VRW1/1tLox0mVUalvnWXxavmv/Oum2aPsRcoDJuob75FC3Y8FbpfLwUegRcxINtGUMPq0tFCvYNTBXNA==" + }, + "node_modules/styled-components/node_modules/@emotion/unitless": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.8.1.tgz", + "integrity": "sha512-KOEGMu6dmJZtpadb476IsZBclKvILjopjUii3V+7MnXIQCYh8W3NgNcgwo21n9LXZX6EDIKvqfjYxXebDwxKmQ==" + }, "node_modules/styled-components/node_modules/postcss": { "version": "8.4.38", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.38.tgz", @@ -39235,9 +39231,9 @@ "dev": true }, "node_modules/synckit": { - "version": "0.8.8", - "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.8.8.tgz", - "integrity": "sha512-HwOKAP7Wc5aRGYdKH+dw0PRRpbO841v2DENBtjnR5HFWoiNByAl7vrx3p0G/rCyYXQsrxqtX48TImFtPcIHSpQ==", + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.9.1.tgz", + "integrity": "sha512-7gr8p9TQP6RAHusBOSLs46F4564ZrjV8xFmw5zCmgmhGUcw2hxsShhJ6CEiHQMgPDwAQ1fWHPM0ypc4RMAig4A==", "dev": true, "dependencies": { "@pkgr/core": "^0.1.0", @@ -39383,9 +39379,9 @@ "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" }, "node_modules/terser": { - "version": "5.31.2", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.31.2.tgz", - "integrity": "sha512-LGyRZVFm/QElZHy/CPr/O4eNZOZIzsrQ92y4v9UJe/pFJjypje2yI3C2FmPtvUEnhadlSbmG2nXtdcjHOjCfxw==", + "version": "5.31.3", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.31.3.tgz", + "integrity": "sha512-pAfYn3NIZLyZpa83ZKigvj6Rn9c/vd5KfYGX7cN1mnzqgDcxWvrU5ZtAfIKhEXz9nRecw4z3LXkjaq96/qZqAA==", "dependencies": { "@jridgewell/source-map": "^0.3.3", "acorn": "^8.8.2", @@ -39849,9 +39845,9 @@ } }, "node_modules/ts-loader/node_modules/semver": { - "version": "7.6.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", - "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", "dev": true, "bin": { "semver": "bin/semver.js" @@ -40373,9 +40369,9 @@ } }, "node_modules/type-fest": { - "version": "4.21.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.21.0.tgz", - "integrity": "sha512-ADn2w7hVPcK6w1I0uWnM//y1rLXZhzB9mr0a3OirzclKF1Wp6VzevUmzz/NRAWunOT6E8HrnpGY7xOfc6K57fA==", + "version": "4.23.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.23.0.tgz", + "integrity": "sha512-ZiBujro2ohr5+Z/hZWHESLz3g08BBdrdLMieYFULJO+tWc437sn8kQsWLJoZErY8alNhxre9K4p3GURAG11n+w==", "engines": { "node": ">=16" }, @@ -40486,14 +40482,14 @@ "integrity": "sha512-7sI4e/bZijOzyURng88oOFZCISQPTHozfE2sUu5AviFYk5QV7fYGb6YiDl+vKjF/pICA354JImBImL9XJWUvdQ==" }, "node_modules/typescript-eslint": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-7.16.0.tgz", - "integrity": "sha512-kaVRivQjOzuoCXU6+hLnjo3/baxyzWVO5GrnExkFzETRYJKVHYkrJglOu2OCm8Hi9RPDWX1PTNNTpU5KRV0+RA==", + "version": "7.16.1", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-7.16.1.tgz", + "integrity": "sha512-889oE5qELj65q/tGeOSvlreNKhimitFwZqQ0o7PcWC7/lgRkAMknznsCsV8J8mZGTP/Z+cIbX8accf2DE33hrA==", "dev": true, "dependencies": { - "@typescript-eslint/eslint-plugin": "7.16.0", - "@typescript-eslint/parser": "7.16.0", - "@typescript-eslint/utils": "7.16.0" + "@typescript-eslint/eslint-plugin": "7.16.1", + "@typescript-eslint/parser": "7.16.1", + "@typescript-eslint/utils": "7.16.1" }, "engines": { "node": "^18.18.0 || >=20.0.0" @@ -41122,9 +41118,9 @@ } }, "node_modules/vfile": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/vfile/-/vfile-6.0.1.tgz", - "integrity": "sha512-1bYqc7pt6NIADBJ98UiG0Bn/CHIVOoZ/IyEkqIruLg0mE1BKzkOXY2D6CSqQIcKqgadppE5lrxgWXJmXd7zZJw==", + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/vfile/-/vfile-6.0.2.tgz", + "integrity": "sha512-zND7NlS8rJYb/sPqkb13ZvbbUoExdbi4w3SfRrMq6R3FvnLQmmfpajJNITuuYm6AZ5uao9vy4BAos3EXBPf2rg==", "dependencies": { "@types/unist": "^3.0.0", "unist-util-stringify-position": "^4.0.0", @@ -41136,9 +41132,9 @@ } }, "node_modules/vfile-location": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/vfile-location/-/vfile-location-5.0.2.tgz", - "integrity": "sha512-NXPYyxyBSH7zB5U6+3uDdd6Nybz6o6/od9rk8bp9H8GR3L+cm/fC0uUTbqBmUTnMCUDslAGBOIKNfvvb+gGlDg==", + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/vfile-location/-/vfile-location-5.0.3.tgz", + "integrity": "sha512-5yXvWDEgqeiYiBe1lbxYF7UMAIm/IcopxMHrMQDq3nvKcjPKIhZklUKL+AE7J7uApI4kwe2snsK+eI6UTj9EHg==", "dependencies": { "@types/unist": "^3.0.0", "vfile": "^6.0.0" @@ -41324,9 +41320,9 @@ } }, "node_modules/webpack": { - "version": "5.92.1", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.92.1.tgz", - "integrity": "sha512-JECQ7IwJb+7fgUFBlrJzbyu3GEuNBcdqr1LD7IbSzwkSmIevTm8PF+wej3Oxuz/JFBUZ6O1o43zsPkwm1C4TmA==", + "version": "5.93.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.93.0.tgz", + "integrity": "sha512-Y0m5oEY1LRuwly578VqluorkXbvXKh7U3rLoQCEO04M97ScRr44afGVkI0FQFsXzysk5OgFAxjZAb9rsGQVihA==", "dependencies": { "@types/eslint-scope": "^3.7.3", "@types/estree": "^1.0.5", @@ -41441,9 +41437,9 @@ } }, "node_modules/webpack-dev-middleware": { - "version": "7.2.1", - "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-7.2.1.tgz", - "integrity": "sha512-hRLz+jPQXo999Nx9fXVdKlg/aehsw1ajA9skAneGmT03xwmyuhvF93p6HUKKbWhXdcERtGTzUCtIQr+2IQegrA==", + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-7.3.0.tgz", + "integrity": "sha512-xD2qnNew+F6KwOGZR7kWdbIou/ud7cVqLEXeK1q0nHcNsX/u7ul/fSdlOTX4ntSL5FNFy7ZJJXbf0piF591JYw==", "dependencies": { "colorette": "^2.0.10", "memfs": "^4.6.0", diff --git a/package.json b/package.json index a614d108e..56800edfc 100644 --- a/package.json +++ b/package.json @@ -186,7 +186,7 @@ "express-session": "^1.17.3", "express-validator": "^7.0.1", "extract-colors": "^4.0.2", - "ffmpeg": "0.0.4", + "ffmpeg": "^0.0.4", "file-loader": "^6.2.0", "file-saver": "^2.0.5", "find-in-files": "^0.5.0", diff --git a/src/ClientUtils.ts b/src/ClientUtils.ts index b890e7bfc..fc415d589 100644 --- a/src/ClientUtils.ts +++ b/src/ClientUtils.ts @@ -7,11 +7,11 @@ import { CollectionViewType, DocumentType } from './client/documents/DocumentTyp import { Colors } from './client/views/global/globalEnums'; import { CreateImage } from './client/views/nodes/WebBoxRenderer'; -export function DashColor(color: string) { +export function DashColor(color: string | undefined) { try { return color ? Color(color.toLowerCase()) : Color('transparent'); } catch (e) { - if (color.includes('gradient')) console.log("using color 'white' in place of :" + color); + if (color?.includes('gradient')) console.log("using color 'white' in place of :" + color); else console.log('COLOR error:', e); return Color('white'); } @@ -455,7 +455,7 @@ export function addStyleSheet() { const sheets = document.head.appendChild(style); return sheets.sheet; } -export function addStyleSheetRule(sheet: CSSStyleSheet | null, selector: string, css: string | {[key:string]: string}, selectorPrefix = '.') { +export function addStyleSheetRule(sheet: CSSStyleSheet | null, selector: string, css: string | { [key: string]: string }, selectorPrefix = '.') { const propText = typeof css === 'string' ? css @@ -464,14 +464,14 @@ export function addStyleSheetRule(sheet: CSSStyleSheet | null, selector: string, .join(';'); return sheet?.insertRule(selectorPrefix + selector + '{' + propText + '}', sheet.cssRules.length); } -export function removeStyleSheetRule(sheet: CSSStyleSheet|null, rule: number) { +export function removeStyleSheetRule(sheet: CSSStyleSheet | null, rule: number) { if (sheet?.rules.length) { sheet.removeRule(rule); return true; } return false; } -export function clearStyleSheetRules(sheet: CSSStyleSheet|null) { +export function clearStyleSheetRules(sheet: CSSStyleSheet | null) { if (sheet?.rules.length) { numberRange(sheet.rules.length).map(() => sheet.removeRule(0)); return true; diff --git a/src/client/views/InkingStroke.tsx b/src/client/views/InkingStroke.tsx index 55f28f415..784d252a3 100644 --- a/src/client/views/InkingStroke.tsx +++ b/src/client/views/InkingStroke.tsx @@ -47,6 +47,7 @@ import { FormattedTextBox, FormattedTextBoxProps } from './nodes/formattedText/F import { PinDocView, PinProps } from './PinFuncs'; import { StyleProp } from './StyleProp'; +// eslint-disable-next-line @typescript-eslint/no-var-requires const { INK_MASK_SIZE } = require('./global/globalCssVariables.module.scss'); // prettier-ignore @observer @@ -292,7 +293,7 @@ export class InkingStroke extends ViewBoxAnnotatableComponent() * @param boundsTop the screen space top coordinate of the ink stroke * @returns the JSX controls for displaying an editing UI for the stroke (control point & tangent handles) */ - componentUI = (boundsLeft: number, boundsTop: number) => { + componentUI = (boundsLeft: number, boundsTop: number): null | JSX.Element => { const inkDoc = this.Document; const { inkData, inkStrokeWidth } = this.inkScaledData(); const screenSpaceCenterlineStrokeWidth = Math.min(3, inkStrokeWidth * this.ScreenToLocalBoxXf().inverse().Scale); // the width of the blue line widget that shows the centerline of the ink stroke @@ -344,12 +345,12 @@ export class InkingStroke extends ViewBoxAnnotatableComponent() }; @computed get fillColor(): string { const isInkMask = BoolCast(this.layoutDoc.stroke_isInkMask); - return isInkMask ? DashColor(StrCast(this.layoutDoc.fillColor, 'transparent')).blacken(0).rgb().toString() : this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.FillColor) ?? 'transparent'; + return isInkMask ? DashColor(StrCast(this.layoutDoc.fillColor, 'transparent')).blacken(0).rgb().toString() : ((this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.FillColor) as 'string') ?? 'transparent'); } @computed get strokeColor() { const { inkData } = this.inkScaledData(); const { fillColor } = this; - return !InkingStroke.IsClosed(inkData) && fillColor && fillColor !== 'transparent' ? fillColor : this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.Color) ?? StrCast(this.layoutDoc.color); + return !InkingStroke.IsClosed(inkData) && fillColor && fillColor !== 'transparent' ? fillColor : ((this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.Color) as 'string') ?? StrCast(this.layoutDoc.color)); } render() { TraceMobx(); @@ -370,8 +371,8 @@ export class InkingStroke extends ViewBoxAnnotatableComponent() }); } const highlight = !this.controlUndo && this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.Highlighting); - const highlightIndex = highlight?.highlightIndex; - const highlightColor = !this._props.isSelected() && !isInkMask && highlight?.highlightIndex ? highlight?.highlightColor : undefined; + const { highlightIndex, highlightColor: hColor } = (highlight as { highlightIndex?: number; highlightColor?: string }) ?? { highlightIndex: undefined, highlightColor: undefined }; + const highlightColor = !this._props.isSelected() && !isInkMask && highlightIndex ? hColor : undefined; const color = StrCast(this.layoutDoc.stroke_outlineColor, !closed && fillColor && fillColor !== 'transparent' ? StrCast(this.layoutDoc.color, 'transparent') : 'transparent'); // Visually renders the polygonal line made by the user. @@ -401,12 +402,12 @@ export class InkingStroke extends ViewBoxAnnotatableComponent() ); const higlightMargin = Math.min(12, Math.max(2, 0.3 * inkStrokeWidth)); // Invisible polygonal line that enables the ink to be selected by the user. - const clickableLine = (downHdlr?: (e: React.PointerEvent) => void, mask: boolean = false): any => + const clickableLine = (downHdlr?: (e: React.PointerEvent) => void, mask: boolean = false) => InteractionUtils.CreatePolyline( inkData, inkLeft, inkTop, - mask && color === 'transparent' ? this.strokeColor : highlightColor ?? color, + mask && color === 'transparent' ? this.strokeColor : (highlightColor ?? color), inkStrokeWidth, inkStrokeWidth + NumCast(this.layoutDoc.stroke_borderWidth) + (fillColor ? (closed ? higlightMargin : (highlightIndex ?? 0) + higlightMargin) : higlightMargin), StrCast(this.layoutDoc.stroke_lineJoin), @@ -420,7 +421,7 @@ export class InkingStroke extends ViewBoxAnnotatableComponent() inkScaleX, inkScaleY, '', - this._props.pointerEvents?.() ?? 'visiblepainted', + this._props.pointerEvents?.() ?? 'visiblePainted', 0.0, false, downHdlr, diff --git a/src/client/views/StyleProvider.tsx b/src/client/views/StyleProvider.tsx index 618f69221..9cb52aacf 100644 --- a/src/client/views/StyleProvider.tsx +++ b/src/client/views/StyleProvider.tsx @@ -144,7 +144,7 @@ export function DefaultStyleProvider(doc: Opt, props: Opt, props: Opt void) { diff --git a/src/client/views/collections/CollectionCarousel3DView.tsx b/src/client/views/collections/CollectionCarousel3DView.tsx index 38f681e87..c799eb3c8 100644 --- a/src/client/views/collections/CollectionCarousel3DView.tsx +++ b/src/client/views/collections/CollectionCarousel3DView.tsx @@ -1,5 +1,3 @@ -/* eslint-disable jsx-a11y/no-static-element-interactions */ -/* eslint-disable jsx-a11y/click-events-have-key-events */ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { computed, makeObservable } from 'mobx'; import { observer } from 'mobx-react'; @@ -15,7 +13,7 @@ import { StyleProp } from '../StyleProp'; import { DocumentView } from '../nodes/DocumentView'; import { FocusViewOptions } from '../nodes/FocusViewOptions'; import './CollectionCarousel3DView.scss'; -import { CollectionSubView } from './CollectionSubView'; +import { CollectionSubView, SubCollectionViewProps } from './CollectionSubView'; // eslint-disable-next-line @typescript-eslint/no-var-requires const { CAROUSEL3D_CENTER_SCALE, CAROUSEL3D_SIDE_SCALE, CAROUSEL3D_TOP } = require('../global/globalCssVariables.module.scss'); @@ -25,7 +23,7 @@ export class CollectionCarousel3DView extends CollectionSubView() { @computed get scrollSpeed() { return this.layoutDoc._autoScrollSpeed ? NumCast(this.layoutDoc._autoScrollSpeed) : 1000; // default scroll speed } - constructor(props: any) { + constructor(props: SubCollectionViewProps) { super(props); makeObservable(this); } @@ -181,8 +179,8 @@ export class CollectionCarousel3DView extends CollectionSubView() { className="collectionCarousel3DView-outer" ref={this.createDashEventsTarget} style={{ - background: this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.BackgroundColor), - color: this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.Color), + background: this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.BackgroundColor) as string, + color: this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.Color) as string, }}>
{this.content} diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx index 2a36e96bf..5a142cc6e 100644 --- a/src/client/views/collections/CollectionDockingView.tsx +++ b/src/client/views/collections/CollectionDockingView.tsx @@ -1,3 +1,4 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ import { action, IReactionDisposer, makeObservable, observable, reaction } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; @@ -28,7 +29,7 @@ import { OverlayView } from '../OverlayView'; import { ScriptingRepl } from '../ScriptingRepl'; import { UndoStack } from '../UndoStack'; import './CollectionDockingView.scss'; -import { CollectionSubView } from './CollectionSubView'; +import { CollectionSubView, SubCollectionViewProps } from './CollectionSubView'; const _global = (window /* browser */ || global) /* node */ as any; @@ -40,7 +41,7 @@ export class CollectionDockingView extends CollectionSubView() { * configuring golden layout to render its documents using the specified React component * @param ele - typically would be set to TabDocView */ - public static Init(ele: any) { + public static Init(ele: JSX.Element | null) { this.tabClass = ele; DocumentView.addSplit = CollectionDockingView.AddSplit; } @@ -60,7 +61,7 @@ export class CollectionDockingView extends CollectionSubView() { private _goldenLayout: any = null; static _highlightStyleSheet = addStyleSheet(); - constructor(props: any) { + constructor(props: SubCollectionViewProps) { super(props); makeObservable(this); if (this._props.renderDepth < 0) CollectionDockingView.Instance = this; diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx index e250d7a90..b7169ece0 100644 --- a/src/client/views/collections/CollectionSubView.tsx +++ b/src/client/views/collections/CollectionSubView.tsx @@ -67,7 +67,7 @@ export function CollectionSubView() { private gestureDisposer?: GestureUtils.GestureEventDisposer; protected _mainCont?: HTMLDivElement; - constructor(props: any) { + constructor(props: X & SubCollectionViewProps) { super(props); makeObservable(this); } diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx index 46f61290e..f50f7394b 100644 --- a/src/client/views/collections/TabDocView.tsx +++ b/src/client/views/collections/TabDocView.tsx @@ -14,7 +14,7 @@ import { Id } from '../../../fields/FieldSymbols'; import { List } from '../../../fields/List'; import { FieldId } from '../../../fields/RefField'; import { ComputedField } from '../../../fields/ScriptField'; -import { Cast, DocCast, NumCast, StrCast, toList } from '../../../fields/Types'; +import { Cast, NumCast, StrCast, toList } from '../../../fields/Types'; import { DocServer } from '../../DocServer'; import { CollectionViewType, DocumentType } from '../../documents/DocumentTypes'; import { Docs } from '../../documents/Documents'; @@ -67,7 +67,7 @@ class TabMiniThumb extends React.Component { } @observer export class TabMinimapView extends ObservableReactComponent { - static miniStyleProvider = (doc: Opt, props: Opt, property: string): any => { + static miniStyleProvider = (doc: Opt, props: Opt, property: string) => { if (doc) { switch (property.split(':')[0]) { case StyleProp.PointerEvents: return 'none'; @@ -274,7 +274,7 @@ export class TabDocView extends ObservableReactComponent { } static Activate = (tabDoc: Doc) => { - const tab = Array.from(CollectionDockingView.Instance?.tabMap!).find(findTab => findTab.DashDoc === tabDoc && !findTab.contentItem.config.props.keyValue); + const tab = Array.from(CollectionDockingView.Instance?.tabMap ?? []).find(findTab => findTab.DashDoc === tabDoc && !findTab.contentItem.config.props.keyValue); tab?.header.parent.setActiveContentItem(tab.contentItem); // glr: Panning does not work when this is set - (this line is for trying to make a tab that is not topmost become topmost) return tab !== undefined; }; @@ -286,7 +286,7 @@ export class TabDocView extends ObservableReactComponent { // } // return undefined; // } - constructor(props: any) { + constructor(props: TabDocViewProps) { super(props); makeObservable(this); DocumentView.activateTabView = TabDocView.Activate; @@ -399,9 +399,10 @@ export class TabDocView extends ObservableReactComponent { tab._disposers.color = reaction( () => ({ variant: SnappingManager.userVariantColor, degree: Doc.GetBrushStatus(doc), highlight: DefaultStyleProvider(this._document, undefined, StyleProp.Highlighting) }), ({ variant, degree, highlight }) => { - const color = highlight?.highlightIndex === Doc.DocBrushStatus.highlighted ? highlight.highlightColor : degree ? ['transparent', variant, variant, 'orange'][degree] : variant; + const { highlightIndex, highlightColor } = (highlight as { highlightIndex: number; highlightColor: string }) ?? { highlightIndex: undefined, highlightColor: undefined }; + const color = highlightIndex === Doc.DocBrushStatus.highlighted ? highlightColor : degree ? ['transparent', variant, variant, 'orange'][degree] : variant; - const textColor = color === variant ? SnappingManager.userColor ?? '' : lightOrDark(color); + const textColor = color === variant ? (SnappingManager.userColor ?? '') : lightOrDark(color); titleEle.style.color = textColor; iconWrap.style.color = textColor; closeWrap.style.color = textColor; diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx index f69aea2a7..161d93788 100644 --- a/src/client/views/collections/TreeView.tsx +++ b/src/client/views/collections/TreeView.tsx @@ -472,7 +472,7 @@ export class TreeView extends ObservableReactComponent { refTransform = (ref: HTMLElement | undefined | null) => { if (!ref) return this.ScreenToLocalTransform(); const { translateX, translateY, scale } = ClientUtils.GetScreenTransform(ref); - return new Transform(-translateX, -translateY, 1).scale(1/scale); + return new Transform(-translateX, -translateY, 1).scale(1 / scale); }; docTransform = () => this.refTransform(this._dref?.ContentDiv); getTransform = () => this.refTransform(this._tref.current); @@ -777,7 +777,7 @@ export class TreeView extends ObservableReactComponent { @computed get renderBullet() { TraceMobx(); - const iconType = this.treeView._props.styleProvider?.(this.Document, this.treeView._props, StyleProp.TreeViewIcon + (this.treeViewOpen ? ':treeOpen' : !this.childDocs.length ? ':empty' : '')) || 'question'; + const iconType = (this.treeView._props.styleProvider?.(this.Document, this.treeView._props, StyleProp.TreeViewIcon + (this.treeViewOpen ? ':treeOpen' : !this.childDocs.length ? ':empty' : '')) as string) || 'question'; const color = SettingsManager.userColor; const checked = this.onCheckedClick ? this.Document.treeView_Checked ?? 'unchecked' : undefined; return ( @@ -923,7 +923,7 @@ export class TreeView extends ObservableReactComponent { style={{ // just render a title for a tree view label (identified by treeViewDoc being set in 'props') maxWidth: props?.PanelWidth() || undefined, - background: props?.styleProvider?.(doc, props, StyleProp.BackgroundColor), + background: props?.styleProvider?.(doc, props, StyleProp.BackgroundColor) as string, outline: SnappingManager.IsDragging ? undefined: `solid ${highlightColor} ${highlightIndex}px`, paddingLeft: NumCast(treeView.Document.childXPadding, NumCast(treeView._props.childXPadding, Doc.IsComicStyle(doc)?20:0)), paddingRight: NumCast(treeView.Document.childXPadding, NumCast(treeView._props.childXPadding, Doc.IsComicStyle(doc)?20:0)), @@ -1179,7 +1179,7 @@ export class TreeView extends ObservableReactComponent { @computed get renderBorder() { const sorting = StrCast(this.Document.treeView_SortCriterion, TreeSort.WhenAdded); - const sortings = (this._props.styleProvider?.(this.Document, this.treeView._props, StyleProp.TreeViewSortings) ?? {}) as { [key: string]: { color: string; label: string } }; + const sortings = (this._props.styleProvider?.(this.Document, this.treeView._props, StyleProp.TreeViewSortings) ?? {}) as { [key: string]: { color: string; icon: JSX.Element } }; return (
{!this.treeViewOpen ? null : this.renderContent} diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx index de51cc73c..79aad0ef2 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx @@ -9,7 +9,7 @@ import { aggregateBounds } from '../../../../Utils'; export interface ViewDefBounds { type: string; - payload: any; + payload: unknown; x: number; y: number; z?: number; @@ -72,11 +72,15 @@ function toLabel(target: FieldResult) { */ function getTextWidth(text: string, font: string): number { // re-use canvas object for better performance - const canvas = (getTextWidth as any).canvas || ((getTextWidth as any).canvas = document.createElement('canvas')); + const selfStoreHack = getTextWidth as unknown as { canvas: Element }; + const canvas = (selfStoreHack.canvas = (selfStoreHack.canvas as unknown as HTMLCanvasElement) ?? document.createElement('canvas')); const context = canvas.getContext('2d'); - context.font = font; - const metrics = context.measureText(text); - return metrics.width; + if (context) { + context.font = font; + const metrics = context.measureText(text); + return metrics.width; + } + return 0; } interface PivotColumn { @@ -131,13 +135,13 @@ export function computeStarburstLayout(poolData: Map, pivotDoc return normalizeResults(burstDiam, 12, docMap, poolData, viewDefsToJSX, [], 0, [divider]); } -export function computePivotLayout(poolData: Map, pivotDoc: Doc, childPairs: { layout: Doc; data?: Doc }[], panelDim: number[], viewDefsToJSX: (views: ViewDefBounds[]) => ViewDefResult[], engineProps: any) { +export function computePivotLayout(poolData: Map, pivotDoc: Doc, childPairs: { layout: Doc; data?: Doc }[], panelDim: number[], viewDefsToJSX: (views: ViewDefBounds[]) => ViewDefResult[], engineProps: unknown) { const docMap = new Map(); const fieldKey = 'data'; const pivotColumnGroups = new Map, PivotColumn>(); let nonNumbers = 0; - const pivotFieldKey = toLabel(engineProps?.pivotField ?? pivotDoc._pivotField) || 'author'; + const pivotFieldKey = toLabel((engineProps as { pivotField?: string })?.pivotField ?? pivotDoc._pivotField) || 'author'; childPairs.forEach(pair => { const listValue = Cast(pair.layout[pivotFieldKey], listSpec('string'), null); @@ -265,7 +269,7 @@ export function computePivotLayout(poolData: Map, pivotDoc: Do y: -maxColHeight + pivotAxisWidth, width: pivotAxisWidth * numCols * expander, height: maxColHeight, - payload: pivotColumnGroups.get(key)!.filters, + payload: pivotColumnGroups.get(key)?.filters, })); groupNames.push(...dividers); // eslint-disable-next-line no-use-before-define diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 812aa5fa3..39c3da7a5 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -1,6 +1,4 @@ /* eslint-disable react/jsx-props-no-spreading */ -/* eslint-disable jsx-a11y/click-events-have-key-events */ -/* eslint-disable jsx-a11y/no-static-element-interactions */ import { Bezier } from 'bezier-js'; import { Colors } from 'browndash-components'; import { action, computed, IReactionDisposer, makeObservable, observable, reaction, runInAction } from 'mobx'; @@ -9,7 +7,7 @@ import { computedFn } from 'mobx-utils'; import * as React from 'react'; import { ClientUtils, DashColor, lightOrDark, OmitKeys, returnFalse, returnZero, setupMoveUpEvents, UpdateIcon } from '../../../../ClientUtils'; import { DateField } from '../../../../fields/DateField'; -import { Doc, DocListCast, Field, FieldType, Opt } from '../../../../fields/Doc'; +import { Doc, DocListCast, Field, FieldType, Opt, StrListCast } from '../../../../fields/Doc'; import { ActiveArrowEnd, ActiveArrowStart, ActiveDash, ActiveEraserWidth, ActiveInkBezierApprox, ActiveInkColor, ActiveInkWidth, ActiveIsInkMask, SetActiveInkColor, SetActiveInkWidth } from '../../nodes/DocumentView'; import { DocData, Height, Width } from '../../../../fields/DocSymbols'; import { Id } from '../../../../fields/FieldSymbols'; @@ -46,7 +44,7 @@ import { FormattedTextBox } from '../../nodes/formattedText/FormattedTextBox'; import { OpenWhere, OpenWhereMod } from '../../nodes/OpenWhere'; import { PinDocView, PinProps } from '../../PinFuncs'; import { StyleProp } from '../../StyleProp'; -import { CollectionSubView } from '../CollectionSubView'; +import { CollectionSubView, SubCollectionViewProps } from '../CollectionSubView'; import { TreeViewType } from '../CollectionTreeViewType'; import { CollectionFreeFormBackgroundGrid } from './CollectionFreeFormBackgroundGrid'; import { CollectionFreeFormClusters } from './CollectionFreeFormClusters'; @@ -71,7 +69,7 @@ export interface collectionFreeformViewProps { childPointerEvents?: () => string | undefined; viewField?: string; noOverlay?: boolean; // used to suppress docs in the overlay (z) layer (ie, for minimap since overlay doesn't scale) - engineProps?: any; + engineProps?: unknown; getScrollHeight?: () => number | undefined; } @@ -123,14 +121,14 @@ export class CollectionFreeFormView extends CollectionSubView(); @observable _brushedView: { width: number; height: number; panX: number; panY: number } | undefined = undefined; // highlighted region of freeform canvas used by presentations to indicate a region @observable GroupChildDrag: boolean = false; // child document view being dragged. needed to update drop areas of groups when a group item is dragged. - @observable _childPointerEvents: 'none' | 'all' | 'visiblepainted' | undefined = undefined; + @observable _childPointerEvents: 'none' | 'all' | 'visiblePainted' | undefined = undefined; @observable _lightboxDoc: Opt = undefined; @observable _paintedId = 'id' + Utils.GenerateGuid().replace(/-/g, ''); @observable _keyframeEditing = false; @observable _eraserX: number = 0; @observable _eraserY: number = 0; @observable _showEraserCircle: boolean = false; // to determine whether the radius eraser should show - constructor(props: collectionFreeformViewProps) { + constructor(props: SubCollectionViewProps) { super(props); makeObservable(this); } @@ -140,12 +138,12 @@ export class CollectionFreeFormView extends CollectionSubView ele.bounds && !ele.bounds.z && ele.inkMask !== -1 && ele.inkMask !== undefined).map(ele => ele.ele); @@ -185,7 +183,7 @@ export class CollectionFreeFormView extends CollectionSubView { + focus = (anchor: Doc, options: FocusViewOptions) => { if (anchor.isGroup && !options.docTransform && options.contextPath?.length) { // don't focus on group if there's a context path because we're about to focus on a group item // which will override any group focus. (If we allowed the group to focus, it would mark didMove even if there were no net movement) @@ -374,14 +372,14 @@ export class CollectionFreeFormView extends CollectionSubView { + // eslint-disable-next-line @typescript-eslint/no-explicit-any if ((curve as any)._linear) { // bezier.js doesn't intersect properly if the curve is actually a line -- so get intersect other curve against this line, then figure out the t coordinates of the intersection on this line const intersections = otherCurve.lineIntersects({ p1: curve.points[0], p2: curve.points[3] }); @@ -1187,6 +1186,7 @@ export class CollectionFreeFormView extends CollectionSubView this._childPointerEvents; - childContentsActive = () => (this._props.childContentsActive ?? this.isContentActive() === false ? returnFalse : emptyFunction)(); + childContentsActive = () => ((this._props.childContentsActive ?? this.isContentActive() === false) ? returnFalse : emptyFunction)(); getChildDocView(entry: PoolData) { const childLayout = entry.pair.layout; const childData = entry.pair.data; @@ -1603,7 +1603,7 @@ export class CollectionFreeFormView extends CollectionSubView { + onViewDefDivClick = (e: React.MouseEvent, payload: unknown) => { (this._props.viewDefDivClick || ScriptCast(this.Document.onViewDefDivClick))?.script.run({ this: this.Document, payload }); e.stopPropagation(); }; @@ -1637,7 +1637,7 @@ export class CollectionFreeFormView extends CollectionSubView this.onViewDefDivClick(e, viewDef)} style={{ width, height, backgroundColor: color, transform }} @@ -1658,7 +1658,7 @@ export class CollectionFreeFormView extends CollectionSubView, - engine: (poolData: Map, pivotDoc: Doc, childPairs: { layout: Doc; data?: Doc }[], panelDim: number[], viewDefsToJSX: (views: ViewDefBounds[]) => ViewDefResult[], engineProps: any) => ViewDefResult[] + engine: (poolData: Map, pivotDoc: Doc, childPairs: { layout: Doc; data?: Doc }[], panelDim: number[], viewDefsToJSX: (views: ViewDefBounds[]) => ViewDefResult[], engineProps: unknown) => ViewDefResult[] ) { return engine(poolData, this.Document, this.childLayoutPairs, [this._props.PanelWidth(), this._props.PanelHeight()], this.viewDefsToJSX, this._props.engineProps); } @@ -1688,7 +1688,7 @@ export class CollectionFreeFormView extends CollectionSubView elements.push({ ele: this.getChildDocView(entry[1]), - bounds: (entry[1].opacity === 0 ? { payload:undefined, type:"", ...entry[1], width: 0, height: 0 } : { payload:undefined, type:"",...entry[1] }), + bounds: entry[1].opacity === 0 ? { payload: undefined, type: '', ...entry[1], width: 0, height: 0 } : { payload: undefined, type: '', ...entry[1] }, inkMask: BoolCast(entry[1].pair.layout.stroke_isInkMask) ? NumCast(entry[1].pair.layout.opacity, 1) : -1, }) ); @@ -1771,7 +1771,7 @@ export class CollectionFreeFormView extends CollectionSubView this.childPointerEvents, pointerevents => { - this._childPointerEvents = pointerevents as any; + this._childPointerEvents = pointerevents as 'none' | 'all' | 'visiblePainted' | undefined; }, { fireImmediately: true } ); @@ -1812,24 +1812,25 @@ export class CollectionFreeFormView extends CollectionSubView { const contentDiv = this.DocumentView?.().ContentDiv; - contentDiv && UpdateIcon( - this.layoutDoc[Id] + '-icon' + new Date().getTime(), - contentDiv, - NumCast(this.layoutDoc._width), - NumCast(this.layoutDoc._height), - this._props.PanelWidth(), - this._props.PanelHeight(), - 0, - 1, - false, - '', - (iconFile, nativeWidth, nativeHeight) => { - this.dataDoc.icon = new ImageField(iconFile); - this.dataDoc.icon_nativeWidth = nativeWidth; - this.dataDoc.icon_nativeHeight = nativeHeight; - } - ); - } + contentDiv && + UpdateIcon( + this.layoutDoc[Id] + '-icon' + new Date().getTime(), + contentDiv, + NumCast(this.layoutDoc._width), + NumCast(this.layoutDoc._height), + this._props.PanelWidth(), + this._props.PanelHeight(), + 0, + 1, + false, + '', + (iconFile, nativeWidth, nativeHeight) => { + this.dataDoc.icon = new ImageField(iconFile); + this.dataDoc.icon_nativeWidth = nativeWidth; + this.dataDoc.icon_nativeHeight = nativeHeight; + } + ); + }; @action onCursorMove = (e: React.PointerEvent) => { @@ -2134,7 +2135,7 @@ export class CollectionFreeFormView extends CollectionSubView e.preventDefault()} onContextMenu={this.onContextMenu} style={{ - pointerEvents: this._props.isContentActive() && SnappingManager.IsDragging ? 'all' : (this._props.pointerEvents?.() as any), + pointerEvents: this._props.isContentActive() && SnappingManager.IsDragging ? 'all' : this._props.pointerEvents?.(), textAlign: this.isAnnotationOverlay ? 'initial' : undefined, transform: `scale(${this.nativeDimScaling})`, width: `${100 / this.nativeDimScaling}%`, diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 24cb4ccf6..0f2905d5b 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -1,6 +1,5 @@ /* eslint-disable no-use-before-define */ /* eslint-disable react/jsx-props-no-spreading */ -/* eslint-disable jsx-a11y/no-static-element-interactions */ import { IconProp } from '@fortawesome/fontawesome-svg-core'; import { Howl } from 'howler'; import { IReactionDisposer, action, computed, makeObservable, observable, reaction, runInAction } from 'mobx'; @@ -55,13 +54,6 @@ import { PresEffect, PresEffectDirection } from './trails/PresEnums'; import SpringAnimation from './trails/SlideEffect'; import { SpringType, springMappings } from './trails/SpringUtils'; -interface Window { - MediaRecorder: MediaRecorder; -} -declare class MediaRecorder { - constructor(e: any); // whatever MediaRecorder has -} - export interface DocumentViewProps extends FieldViewSharedProps { hideDecorations?: boolean; // whether to suppress all DocumentDecorations when doc is selected hideResizeHandles?: boolean; // whether to suppress resized handles on doc decorations when this document is selected @@ -135,15 +127,15 @@ export class DocumentViewInternal extends DocComponent this._animateScaleTime ?? 100; style = (doc: Doc, sprop: StyleProp | string) => this._props.styleProvider?.(doc, this._props, sprop); @computed get opacity() { return this.style(this.layoutDoc, StyleProp.Opacity) as number; } // prettier-ignore - @computed get boxShadow() { return this.style(this.layoutDoc, StyleProp.BoxShadow); } // prettier-ignore - @computed get borderRounding() { return this.style(this.layoutDoc, StyleProp.BorderRounding); } // prettier-ignore + @computed get boxShadow() { return this.style(this.layoutDoc, StyleProp.BoxShadow) as string; } // prettier-ignore + @computed get borderRounding() { return this.style(this.layoutDoc, StyleProp.BorderRounding) as string; } // prettier-ignore @computed get widgetDecorations() { return this.style(this.layoutDoc, StyleProp.Decorations) as JSX.Element; } // prettier-ignore @computed get backgroundBoxColor(){ return this.style(this.layoutDoc, StyleProp.BackgroundColor + ':docView') as string; } // prettier-ignore @computed get showTitle() { return this.style(this.layoutDoc, StyleProp.ShowTitle) as Opt; } // prettier-ignore @computed get showCaption() { return this.style(this.layoutDoc, StyleProp.ShowCaption) as string ?? ""; } // prettier-ignore @computed get headerMargin() { return this.style(this.layoutDoc, StyleProp.HeaderMargin) as number ?? 0; } // prettier-ignore @computed get titleHeight() { return this.style(this.layoutDoc, StyleProp.TitleHeight) as number ?? 0; } // prettier-ignore - @computed get docContents() { return this.style(this.Document, StyleProp.DocContents); } // prettier-ignore + @computed get docContents() { return this.style(this.Document, StyleProp.DocContents) as JSX.Element; } // prettier-ignore @computed get highlighting() { return this.style(this.Document, StyleProp.Highlighting); } // prettier-ignore @computed get borderPath() { return this.style(this.Document, StyleProp.BorderPath); } // prettier-ignore @@ -164,13 +156,13 @@ export class DocumentViewInternal extends DocComponent this.style(this.Document, StyleProp.PointerEvents) as ("all" | "none" | "visiblePainted" | undefined), + () => this.style(this.Document, StyleProp.PointerEvents) as 'all' | 'none' | 'visiblePainted' | undefined, pointerevents => { this._pointerEvents = pointerevents; }, @@ -450,7 +442,11 @@ export class DocumentViewInternal extends DocComponent - ); + )); }; render() { TraceMobx(); const { highlighting, borderPath } = this; + const { highlightIndex, highlightStyle, highlightColor, highlightStroke } = (highlighting as { highlightIndex: number; highlightStyle: string; highlightColor: string; highlightStroke: boolean }) ?? { + highlightIndex: undefined, + highlightStyle: undefined, + highlightColor: undefined, + highlightStroke: undefined, + }; + const { clipPath, jsx } = (borderPath as { clipPath: string; jsx: JSX.Element }) ?? { clipPath: undefined, jsx: undefined }; const boxShadow = !highlighting ? this.boxShadow - : highlighting && this.borderRounding && highlighting.highlightStyle !== 'dashed' - ? `0 0 0 ${highlighting.highlightIndex}px ${highlighting.highlightColor}` + : highlighting && this.borderRounding && highlightStyle !== 'dashed' + ? `0 0 0 ${highlightIndex}px ${highlightColor}` : this.boxShadow || (this.Document.isTemplateForField ? 'black 0.2vw 0.2vw 0.8vw' : undefined); const renderDoc = this.renderDoc({ borderRadius: this.borderRounding, - outline: highlighting && !this.borderRounding && !highlighting.highlightStroke ? `${highlighting.highlightColor} ${highlighting.highlightStyle} ${highlighting.highlightIndex}px` : 'solid 0px', - border: highlighting && this.borderRounding && highlighting.highlightStyle === 'dashed' ? `${highlighting.highlightStyle} ${highlighting.highlightColor} ${highlighting.highlightIndex}px` : undefined, + outline: highlighting && !this.borderRounding && !highlightStroke ? `${highlightColor} ${highlightStyle} ${highlightIndex}px` : 'solid 0px', + border: highlighting && this.borderRounding && highlightStyle === 'dashed' ? `${highlightStyle} ${highlightColor} ${highlightIndex}px` : undefined, boxShadow, - clipPath: borderPath?.clipPath, + clipPath, }); return ( - // eslint-disable-next-line jsx-a11y/click-events-have-key-events
- {this._componentView?.isUnstyledView?.() || this.Document.type === DocumentType.CONFIG ? renderDoc : DocumentViewInternal.AnimationEffect(renderDoc, this.Document[Animation], this.Document)} - {borderPath?.jsx} + {this._componentView?.isUnstyledView?.() || this.Document.type === DocumentType.CONFIG || !renderDoc ? renderDoc : DocumentViewInternal.AnimationEffect(renderDoc, this.Document[Animation], this.Document)} + {jsx}
); } @@ -968,7 +970,22 @@ export class DocumentViewInternal extends DocComponent, root: Doc) { + public static AnimationEffect( + renderDoc: JSX.Element, + presEffectDoc: Opt< + | Doc + | { + presentation_effectDirection?: string; + followLinkAnimDirection?: string; + presentation_transition?: number; + followLinkTransitionTime?: number; + presentation_effectTiming?: number; + presentation_effect?: string; + followLinkAnimEffect?: string; + } + >, + root: Doc + ) { const dir = ((presEffectDoc?.presentation_effectDirection ?? presEffectDoc?.followLinkAnimDirection) || PresEffectDirection.Center) as PresEffectDirection; const duration = Cast(presEffectDoc?.presentation_transition, 'number', Cast(presEffectDoc?.followLinkTransitionTime, 'number', null)); const effectProps = { @@ -982,7 +999,7 @@ export class DocumentViewInternal extends DocComponent() { public static allViews: () => DocumentView[]; public static addView: (dv: DocumentView) => void | undefined; public static removeView: (dv: DocumentView) => void | undefined; - public static addViewRenderedCb: (doc: Opt, func: (dv: DocumentView) => any) => boolean; + public static addViewRenderedCb: (doc: Opt, func: (dv: DocumentView) => void) => boolean; public static getViews = (doc?: Doc) => Array.from(doc?.[DocViews] ?? []) as DocumentView[]; public static getFirstDocumentView: (toFind: Doc) => DocumentView | undefined; public static getDocumentView: (target: Doc | undefined, preferredCollection?: DocumentView) => Opt; @@ -1107,7 +1124,7 @@ export class DocumentView extends DocComponent() { @observable private _htmlOverlayText: Opt = undefined; @observable private _isHovering = false; @observable private _selected = false; - @observable public static CurrentlyPlaying: DocumentView[] = []; // audio or video media views that are currently playing + @observable public static CurrentlyPlaying: DocumentView[] = []; // audio or video media views that are currently playing @computed private get shouldNotScale() { return (this.layout_fitWidth && !this.nativeWidth) || this.ComponentView?.isUnstyledView?.(); @@ -1254,7 +1271,6 @@ export class DocumentView extends DocComponent() { } public playAnnotation = () => { - const self = this; const audioAnnoState = this.dataDoc.audioAnnoState ?? AudioAnnoState.stopped; const audioAnnos = Cast(this.dataDoc[this.LayoutFieldKey + '_audioAnnotations'], listSpec(AudioField), null); const anno = audioAnnos?.lastElement(); @@ -1267,7 +1283,7 @@ export class DocumentView extends DocComponent() { autoplay: true, loop: false, volume: 0.5, - onend: action(() => { self.dataDoc.audioAnnoState = AudioAnnoState.stopped; }), // prettier-ignore + onend: action(() => { this.dataDoc.audioAnnoState = AudioAnnoState.stopped; }), // prettier-ignore }); this.dataDoc.audioAnnoState = AudioAnnoState.playing; break; @@ -1426,9 +1442,10 @@ export class DocumentView extends DocComponent() {
{DocumentViewInternal.AnimationEffect(
- console.log('PARSE error', e)} renderInWrapper={false} jsx={StrCast(this._htmlOverlayText)} /> + {/* eslint-disable-next-line @typescript-eslint/no-explicit-any */} + console.log('PARSE error', e)} renderInWrapper={false} jsx={StrCast(this._htmlOverlayText)} />
, - { ...(this._htmlOverlayEffect ?? {}), presentation_effect: effect ?? PresEffect.Expand } as any as Doc, + { ...(this._htmlOverlayEffect ?? {}), presentation_effect: effect ?? PresEffect.Expand }, this.Document )}
@@ -1457,7 +1474,7 @@ export class DocumentView extends DocComponent() { style={{ transform: `translate(${this.centeringX}px, ${this.centeringY}px)`, width: xshift ?? `${this._props.PanelWidth() - this.Xshift * 2}px`, - height: this._props.forceAutoHeight ? undefined : yshift ?? (this.layout_fitWidth ? `${this.panelHeight}px` : `${(this.effectiveNativeHeight / this.effectiveNativeWidth) * this._props.PanelWidth()}px`), + height: this._props.forceAutoHeight ? undefined : (yshift ?? (this.layout_fitWidth ? `${this.panelHeight}px` : `${(this.effectiveNativeHeight / this.effectiveNativeWidth) * this._props.PanelWidth()}px`)), }}> Opt; // eslint-disable-next-line no-use-before-define -export type StyleProviderFuncType = (doc: Opt, props: Opt, property: string) => Opt |{ clipPath: string; jsx: Element; } | JSX.Element | null; +export type StyleProviderFuncType = ( + doc: Opt, + props: Opt, + property: string +) => + | Opt + | { clipPath: string; jsx: JSX.Element } + | JSX.Element + | null + | { + [key: string]: + | { + color: string; + icon: JSX.Element | string; + } + | undefined; + } + | { highlightStyle: string; highlightColor: string; highlightIndex: number; highlightStroke: boolean } + | undefined; // // these properties get assigned through the render() method of the DocumentView when it creates this node. // However, that only happens because the properties are "defined" in the markup for the field view. @@ -30,7 +48,7 @@ export interface FieldViewSharedProps { LayoutTemplateString?: string; LayoutTemplate?: () => Opt; renderDepth: number; - scriptContext?: any; // can be assigned anything and will be passed as 'scriptContext' to any OnClick script that executes on this document + scriptContext?: unknown; // can be assigned anything and will be passed as 'scriptContext' to any OnClick script that executes on this document xPadding?: number; yPadding?: number; dontRegisterView?: boolean; @@ -45,7 +63,7 @@ export interface FieldViewSharedProps { containerViewPath?: () => DocumentView[]; fitContentsToBox?: () => boolean; // used by freeformview to fit its contents to its panel. corresponds to _freeform_fitContentsToBox property on a Document isGroupActive?: () => string | undefined; // is this document part of a group that is active - setContentViewBox?: (view: ViewBoxInterface) => any; // called by rendered field's viewBox so that DocumentView can make direct calls to the viewBox + setContentViewBox?: (view: ViewBoxInterface) => void; // called by rendered field's viewBox so that DocumentView can make direct calls to the viewBox PanelWidth: () => number; PanelHeight: () => number; isDocumentActive?: () => boolean | undefined; // whether a document should handle pointer events @@ -76,7 +94,7 @@ export interface FieldViewSharedProps { bringToFront?: (doc: Doc, sendToBack?: boolean) => void; waitForDoubleClickToClick?: () => 'never' | 'always' | undefined; defaultDoubleClick?: () => 'default' | 'ignore' | undefined; - pointerEvents?: () => Opt; + pointerEvents?: () => Opt<'none' | 'all' | 'visiblePainted'>; suppressSetHeight?: boolean; } diff --git a/src/client/views/nodes/RecordingBox/RecordingView.tsx b/src/client/views/nodes/RecordingBox/RecordingView.tsx index b8451fe60..37ffca2d6 100644 --- a/src/client/views/nodes/RecordingBox/RecordingView.tsx +++ b/src/client/views/nodes/RecordingBox/RecordingView.tsx @@ -1,6 +1,4 @@ -/* eslint-disable jsx-a11y/label-has-associated-control */ /* eslint-disable react/button-has-type */ -/* eslint-disable jsx-a11y/control-has-associated-label */ import * as React from 'react'; import { useEffect, useRef, useState } from 'react'; import { IconContext } from 'react-icons'; @@ -14,7 +12,7 @@ import { ProgressBar } from './ProgressBar'; import './RecordingView.scss'; export interface MediaSegment { - videoChunks: any[]; + videoChunks: Blob[]; endTime: number; startTime: number; presentation?: Presentation; @@ -91,15 +89,15 @@ export function RecordingView(props: IRecordingViewProps) { }, []); useEffect(() => { - let interval: any = null; + let interval: null | NodeJS.Timeout = null; if (recording) { interval = setInterval(() => { setRecordingTimer(unit => unit + 1); }, 10); } else if (!recording && recordingTimer !== 0) { - clearInterval(interval); + interval && clearInterval(interval); } - return () => clearInterval(interval); + return interval ? () => clearInterval(interval!) : undefined; }, [recording]); const setVideoProgressHelper = (curProgrss: number) => { @@ -127,9 +125,9 @@ export function RecordingView(props: IRecordingViewProps) { if (!videoRecorder.current) videoRecorder.current = new MediaRecorder(await startShowingStream()); // temporary chunks of video - let videoChunks: any = []; + let videoChunks: Blob[] = []; - videoRecorder.current.ondataavailable = (event: any) => { + videoRecorder.current.ondataavailable = (event: BlobEvent) => { if (event.data.size > 0) videoChunks.push(event.data); }; diff --git a/src/client/views/nodes/ScreenshotBox.tsx b/src/client/views/nodes/ScreenshotBox.tsx index 3be50f5e6..9ef1071f7 100644 --- a/src/client/views/nodes/ScreenshotBox.tsx +++ b/src/client/views/nodes/ScreenshotBox.tsx @@ -1,4 +1,3 @@ -/* eslint-disable jsx-a11y/media-has-caption */ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import * as React from 'react'; // import { Canvas } from '@react-three/fiber'; -- cgit v1.2.3-70-g09d2 From ff1840832e1da2e0b0510045574354970a88decc Mon Sep 17 00:00:00 2001 From: geireann Date: Wed, 24 Jul 2024 17:03:16 -0400 Subject: more update of anys --- package-lock.json | 42 +++++++++++++++++++++++++----------- package.json | 2 ++ src/client/views/StyleProvider.tsx | 29 +++++++++++-------------- src/client/views/nodes/FieldView.tsx | 1 + 4 files changed, 44 insertions(+), 30 deletions(-) (limited to 'src') diff --git a/package-lock.json b/package-lock.json index 0187d7952..ae5f01daa 100644 --- a/package-lock.json +++ b/package-lock.json @@ -220,6 +220,7 @@ "styled-components": "^6.1.1", "supercluster": "^8.0.1", "textarea-caret": "^3.1.0", + "textfit": "^2.4.0", "tough-cookie": "^4.1.3", "tslint": "^6.1.3", "tslint-loader": "^3.5.4", @@ -283,6 +284,7 @@ "@types/request": "^2.48.12", "@types/request-promise": "^4.1.51", "@types/shelljs": "^0.8.15", + "@types/textfit": "^2.4.4", "@types/uuid": "^10.0.0", "@types/valid-url": "^1.0.7", "@types/webpack": "^5.28.5", @@ -9824,6 +9826,15 @@ "@types/geojson": "*" } }, + "node_modules/@types/textfit": { + "version": "2.4.4", + "resolved": "https://registry.npmjs.org/@types/textfit/-/textfit-2.4.4.tgz", + "integrity": "sha512-AYlNcJ5j/WspQfbHIhoF0Wo63F5+REnX/VPFSH5unUUuwRcr6IoXxZki3vYhG4DRVUQe51AsFYyRxml5u+qaAg==", + "dev": true, + "dependencies": { + "@types/jquery": "*" + } + }, "node_modules/@types/tough-cookie": { "version": "4.0.5", "resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-4.0.5.tgz", @@ -13560,6 +13571,19 @@ "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, + "node_modules/browndash-components/node_modules/npm/node_modules/node-gyp/node_modules/readable-stream": { + "version": "3.6.2", + "inBundle": true, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/browndash-components/node_modules/npm/node_modules/node-gyp/node_modules/signal-exit": { "version": "3.0.7", "inBundle": true, @@ -14005,19 +14029,6 @@ "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, - "node_modules/browndash-components/node_modules/npm/node_modules/readable-stream": { - "version": "3.6.2", - "inBundle": true, - "license": "MIT", - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, "node_modules/browndash-components/node_modules/npm/node_modules/retry": { "version": "0.12.0", "inBundle": true, @@ -39503,6 +39514,11 @@ "resolved": "https://registry.npmjs.org/textarea-caret/-/textarea-caret-3.1.0.tgz", "integrity": "sha512-cXAvzO9pP5CGa6NKx0WYHl+8CHKZs8byMkt3PCJBCmq2a34YA9pO1NrQET5pzeqnBjBdToF5No4rrmkDUgQC2Q==" }, + "node_modules/textfit": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/textfit/-/textfit-2.4.0.tgz", + "integrity": "sha512-/x4aoY5+/tJmu+iwpBH1yw75TFp86M6X15SvaaY/Eep7YySQYtqdOifEtfvVyMwzl7SZ+G4RQw00FD9g5R6i1Q==" + }, "node_modules/thingies": { "version": "1.21.0", "resolved": "https://registry.npmjs.org/thingies/-/thingies-1.21.0.tgz", diff --git a/package.json b/package.json index 56800edfc..d58bf3e9f 100644 --- a/package.json +++ b/package.json @@ -63,6 +63,7 @@ "@types/request": "^2.48.12", "@types/request-promise": "^4.1.51", "@types/shelljs": "^0.8.15", + "@types/textfit": "^2.4.4", "@types/uuid": "^10.0.0", "@types/valid-url": "^1.0.7", "@types/webpack": "^5.28.5", @@ -305,6 +306,7 @@ "styled-components": "^6.1.1", "supercluster": "^8.0.1", "textarea-caret": "^3.1.0", + "textfit": "^2.4.0", "tough-cookie": "^4.1.3", "tslint": "^6.1.3", "tslint-loader": "^3.5.4", diff --git a/src/client/views/StyleProvider.tsx b/src/client/views/StyleProvider.tsx index 9cb52aacf..8a07a6bd7 100644 --- a/src/client/views/StyleProvider.tsx +++ b/src/client/views/StyleProvider.tsx @@ -1,6 +1,3 @@ -/* eslint-disable jsx-a11y/alt-text */ -/* eslint-disable jsx-a11y/no-static-element-interactions */ -/* eslint-disable jsx-a11y/click-events-have-key-events */ import { IconProp } from '@fortawesome/fontawesome-svg-core'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { Tooltip } from '@mui/material'; @@ -24,7 +21,7 @@ import { undoBatch, UndoManager } from '../util/UndoManager'; import { TreeSort } from './collections/TreeSort'; import { Colors } from './global/globalEnums'; import { DocumentView, DocumentViewProps } from './nodes/DocumentView'; -import { FieldViewProps } from './nodes/FieldView'; +import { FieldViewProps, StyleProviderFuncType } from './nodes/FieldView'; import { StyleProp } from './StyleProp'; import './StyleProvider.scss'; @@ -43,9 +40,9 @@ function togglePaintView(e: React.MouseEvent, doc: Opt, props: Opt + const replacer = (match: string, expr: string) => // bcz: this executes a script to convert a property expression string: { script } into a value ScriptField.MakeFunction(expr, { this: Doc.name, scale: 'number' })?.script.run({ this: doc, scale }).result?.toString() ?? ''; divKeys.forEach((prop: string) => { @@ -72,7 +69,7 @@ export function SetFilterOpener(func: () => void) { // a preliminary implementation of a dash style sheet for setting rendering properties of documents nested within a Tab // -export function DefaultStyleProvider(doc: Opt, props: Opt, property: string) { +export function DefaultStyleProvider(doc: Opt, props: Opt, property: string) : StyleProviderFuncType { const remoteDocHeader = 'author;author_date;noMargin'; const isCaption = property.includes(':caption'); const isAnchor = property.includes(':anchor'); @@ -297,8 +294,7 @@ export function DefaultStyleProvider(doc: Opt, props: Opt, props: Opt
} closeOnSelect - setSelectedVal={((dv: DocumentView) => { + setSelectedVal={((dvValue: unknown) => { + const dv = dvValue as DocumentView; dv.select(false); SnappingManager.SetPropertiesWidth(250); _filterOpener?.(); - }) as any // Dropdown assumes values are strings or numbers.. + }) // Dropdown assumes values are strings or numbers.. } size={Size.XSMALL} width={15} @@ -345,11 +342,9 @@ export function DefaultStyleProvider(doc: Opt, props: Opt StrListCast(dv?.Document.childFilters).length || StrListCast(dv?.Document.childRangeFilters).length) - .map(dv => ({ - text: StrCast(dv?.Document.title), - val: dv as any, - style: {color:SnappingManager.userColor, background:SnappingManager.userBackgroundColor}, - } as IListItemProps)) } + .map(dv => ({ text: StrCast(dv?.Document.title), + val: dv as unknown, + style: {color:SnappingManager.userColor, background:SnappingManager.userBackgroundColor} } as IListItemProps)) } />
); @@ -387,7 +382,7 @@ export function DashboardToggleButton(doc: Doc, field: string, onIcon: IconProp, } + icon={} onClick={undoBatch( action((e: React.MouseEvent) => { e.stopPropagation(); diff --git a/src/client/views/nodes/FieldView.tsx b/src/client/views/nodes/FieldView.tsx index c77f5a136..fc59e9e26 100644 --- a/src/client/views/nodes/FieldView.tsx +++ b/src/client/views/nodes/FieldView.tsx @@ -26,6 +26,7 @@ export type StyleProviderFuncType = ( | Opt | { clipPath: string; jsx: JSX.Element } | JSX.Element + | JSX.IntrinsicElements | null | { [key: string]: -- cgit v1.2.3-70-g09d2 From e1db06d59d580aa640212a0d3a6aeecb9122bdf0 Mon Sep 17 00:00:00 2001 From: geireann Date: Thu, 25 Jul 2024 15:06:01 -0400 Subject: lots more 'any' cleanup and more. --- src/client/views/MarqueeAnnotator.tsx | 21 +- src/client/views/nodes/DataVizBox/DataVizBox.tsx | 6 +- src/client/views/nodes/ImageBox.tsx | 6 +- src/client/views/nodes/VideoBox.tsx | 16 +- src/client/views/nodes/WebBox.tsx | 48 ++-- .../views/nodes/formattedText/FormattedTextBox.tsx | 260 ++++++++------------- .../formattedText/FormattedTextBoxComment.tsx | 10 +- .../views/nodes/formattedText/RichTextMenu.tsx | 91 ++++---- src/client/views/pdf/AnchorMenu.tsx | 4 +- src/client/views/pdf/PDFViewer.tsx | 34 ++- 10 files changed, 213 insertions(+), 283 deletions(-) (limited to 'src') diff --git a/src/client/views/MarqueeAnnotator.tsx b/src/client/views/MarqueeAnnotator.tsx index c18ac6738..8aed34d24 100644 --- a/src/client/views/MarqueeAnnotator.tsx +++ b/src/client/views/MarqueeAnnotator.tsx @@ -27,7 +27,7 @@ export interface MarqueeAnnotatorProps { containerOffset?: () => number[]; marqueeContainer: HTMLDivElement; docView: () => DocumentView; - savedAnnotations: () => ObservableMap; + savedAnnotations: () => ObservableMap; selectionText: () => string; annotationLayer: HTMLDivElement; addDocument: (doc: Doc) => boolean; @@ -41,7 +41,7 @@ export interface MarqueeAnnotatorProps { export class MarqueeAnnotator extends ObservableReactComponent { private _start: { x: number; y: number } = { x: 0, y: 0 }; - constructor(props: any) { + constructor(props: MarqueeAnnotatorProps) { super(props); makeObservable(this); } @@ -60,13 +60,13 @@ export class MarqueeAnnotator extends ObservableReactComponent): Opt => { + makeAnnotationDocument = (color: string, isLinkButton?: boolean, savedAnnotations?: ObservableMap): Opt => { const savedAnnoMap = savedAnnotations?.values() && Array.from(savedAnnotations?.values()).length ? savedAnnotations : this.props.savedAnnotations(); if (savedAnnoMap.size === 0) return undefined; const savedAnnos = Array.from(savedAnnoMap.values())[0]; const doc = this.props.Document; const scale = (this.props.annotationLayerScaling?.() || 1) * NumCast(doc._freeform_scale, 1); - if (savedAnnos.length && (savedAnnos[0] as any).marqueeing) { + if (savedAnnos.length && savedAnnos[0].marqueeing) { const anno = savedAnnos[0]; const containerOffset = this.props.containerOffset?.() || [0, 0]; const marqueeAnno = Docs.Create.FreeformDocument([], { @@ -86,8 +86,9 @@ export class MarqueeAnnotator extends ObservableReactComponent, annotationLayer: HTMLDivElement, div: HTMLDivElement, page: number) => { + public static previewNewAnnotation = action((savedAnnotations: ObservableMap, annotationLayer: HTMLDivElement & { marqueeing?: boolean}, div: HTMLDivElement, page: number) => { div.style.backgroundColor = '#ACCEF7'; div.style.opacity = '0.5'; annotationLayer.append(div); @@ -264,17 +265,17 @@ export class MarqueeAnnotator extends ObservableReactComponent { - copy.style[prop as any] = marqueeStyle[prop as any]; + copy.style[prop as unknown as number] = marqueeStyle[prop as unknown as number]; // bcz: hack to get around TS type checking for array index with strings }); copy.className = 'marqueeAnnotator-annotationBox'; copy.style.top = parseInt(marqueeStyle.top.toString().replace('px', '')) / scale + this.props.scrollTop + 'px'; copy.style.left = parseInt(marqueeStyle.left.toString().replace('px', '')) / scale + 'px'; copy.style.width = parseInt(marqueeStyle.width.toString().replace('px', '')) / scale + 'px'; copy.style.height = parseInt(marqueeStyle.height.toString().replace('px', '')) / scale + 'px'; - (copy as any).marqueeing = true; + copy.marqueeing = true; MarqueeAnnotator.previewNewAnnotation(this.props.savedAnnotations(), this.props.annotationLayer, copy, this.props.getPageFromScroll?.(this.top) || 0); AnchorMenu.Instance.jumpTo(x, y); } diff --git a/src/client/views/nodes/DataVizBox/DataVizBox.tsx b/src/client/views/nodes/DataVizBox/DataVizBox.tsx index 4d5f15a3e..baf8693ca 100644 --- a/src/client/views/nodes/DataVizBox/DataVizBox.tsx +++ b/src/client/views/nodes/DataVizBox/DataVizBox.tsx @@ -50,7 +50,7 @@ export class DataVizBox extends ViewBoxAnnotatableComponent() { sidebarAddDoc: ((doc: Doc | Doc[], sidebarKey?: string | undefined) => boolean) | undefined; crop: ((region: Doc | undefined, addCrop?: boolean) => Doc | undefined) | undefined; @observable _marqueeing: number[] | undefined = undefined; - @observable _savedAnnotations = new ObservableMap(); + @observable _savedAnnotations = new ObservableMap(); constructor(props: FieldViewProps) { super(props); @@ -376,8 +376,8 @@ export class DataVizBox extends ViewBoxAnnotatableComponent() { this._props.select(false); MarqueeAnnotator.clearAnnotations(this._savedAnnotations); this._marqueeing = [e.clientX, e.clientY]; - const target = e.target as any; - if (e.target && (target.className.includes('endOfContent') || (target.parentElement.className !== 'textLayer' && target.parentElement.parentElement?.className !== 'textLayer'))) { + const target = e.target as HTMLElement; + if (e.target && (target.className.includes('endOfContent') || (target.parentElement?.className !== 'textLayer' && target.parentElement?.parentElement?.className !== 'textLayer'))) { /* empty */ } else { // if textLayer is hit, then we select text instead of using a marquee so clear out the marquee. diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx index 68c313480..ce7552047 100644 --- a/src/client/views/nodes/ImageBox.tsx +++ b/src/client/views/nodes/ImageBox.tsx @@ -73,7 +73,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent() { private _marqueeref = React.createRef(); private _mainCont: React.RefObject = React.createRef(); private _annotationLayer: React.RefObject = React.createRef(); - @observable _savedAnnotations = new ObservableMap(); + @observable _savedAnnotations = new ObservableMap(); @observable _curSuffix = ''; @observable _error = ''; @observable _isHovering = false; // flag to switch between primary and alternate images on hover @@ -356,7 +356,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent() { @computed get content() { TraceMobx(); - const backColor = DashColor(this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.BackgroundColor) ?? Colors.WHITE); + const backColor = DashColor(this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.BackgroundColor) as string ?? Colors.WHITE); const backAlpha = backColor.red() === 0 && backColor.green() === 0 && backColor.blue() === 0 ? backColor.alpha() : 1; const srcpath = this.layoutDoc.hideImage ? '' : this.paths[0]; const fadepath = this.layoutDoc.hideImage ? '' : this.paths.lastElement(); @@ -456,7 +456,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent() { savedAnnotations = () => this._savedAnnotations; render() { TraceMobx(); - const borderRad = this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.BorderRounding); + const borderRad = this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.BorderRounding) as string; const borderRadius = borderRad?.includes('px') ? `${Number(borderRad.split('px')[0]) / (this._props.NativeDimScaling?.() || 1)}px` : borderRad; return (
() { private _marqueeref = React.createRef(); private _mainCont: React.RefObject = React.createRef(); // outermost div private _annotationLayer: React.RefObject = React.createRef(); - private _playRegionTimer: any = null; // timeout for playback - private _controlsFadeTimer: any = null; // timeout for controls fade + private _playRegionTimer: NodeJS.Timeout | undefined; // timeout for playback + private _controlsFadeTimer: NodeJS.Timeout | undefined; // timeout for controls fade private _ffref = React.createRef(); constructor(props: FieldViewProps) { @@ -142,7 +141,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent() { switch (e.key) { case 'ArrowLeft': case 'ArrowRight': - clearTimeout(this._controlsFadeTimer); + this._controlsFadeTimer && clearTimeout(this._controlsFadeTimer); this._scrubbing = true; this._controlsFadeTimer = setTimeout( action(() => { @@ -217,7 +216,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent() { this._playTimer = undefined; this.updateTimecode(); if (!this._finished) { - clearTimeout(this._playRegionTimer); // if paused in the middle of playback, prevents restart on next play + this._playRegionTimer && clearTimeout(this._playRegionTimer); // if paused in the middle of playback, prevents restart on next play } this._playRegionTimer = undefined; }; @@ -420,7 +419,6 @@ export class VideoBox extends ViewBoxAnnotatableComponent() { this._videoRef = vref; if (vref) { this._videoRef!.ontimeupdate = this.updateTimecode; - // @ts-ignore // vref.onfullscreenchange = action((e) => this._fullScreen = vref.webkitDisplayingFullscreen); this._disposers.reactionDisposer?.(); this._disposers.reactionDisposer = reaction( @@ -469,7 +467,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent() { runInAction(() => { this._screenCapture = !this._screenCapture; }); - this._videoRef!.srcObject = !this._screenCapture ? undefined : await (navigator.mediaDevices as any).getDisplayMedia({ video: true }); + this._videoRef!.srcObject = !this._screenCapture ? null : await (navigator.mediaDevices).getDisplayMedia({ video: true }); }, icon: 'expand-arrows-alt', }); @@ -877,7 +875,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent() { return (
{ + ref={action((r: CollectionStackedTimeline) => { this._stackedTimeline = r; })} // eslint-disable-next-line react/jsx-props-no-spreading @@ -968,7 +966,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent() { focus = (anchor: Doc, options: FocusViewOptions) => (anchor.type === DocumentType.CONFIG ? undefined : this._ffref.current?.focus(anchor, options)); savedAnnotations = () => this._savedAnnotations; render() { - const borderRad = this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.BorderRounding); + const borderRad = this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.BorderRounding) as string; const borderRadius = borderRad?.includes('px') ? `${Number(borderRad.split('px')[0]) / this.scaling()}px` : borderRad; return (
() { private _sidebarRef = React.createRef(); private _searchRef = React.createRef(); private _searchString = ''; - private _scrollTimer: any; + private _scrollTimer: NodeJS.Timeout | undefined; private _getAnchor: (savedAnnotations: Opt>, addAsAnnotation: boolean) => Opt = () => undefined; @observable private _webUrl = ''; // url of the src parameter of the embedded iframe but not necessarily the rendered page - eg, when following a link, the rendered page changes but we don't want the src parameter to also change as that would cause an unnecessary re-render. @@ -85,7 +83,7 @@ export class WebBox extends ViewBoxAnnotatableComponent() { this._marqueeing = val; } @observable private _iframe: HTMLIFrameElement | null = null; - @observable private _savedAnnotations = new ObservableMap(); + @observable private _savedAnnotations = new ObservableMap(); @observable private _scrollHeight = NumCast(this.layoutDoc.scrollHeight); @computed get _url() { return this.webField?.toString() || ''; @@ -361,8 +359,8 @@ export class WebBox extends ViewBoxAnnotatableComponent() { return anchor; }; - _textAnnotationCreator: (() => ObservableMap) | undefined; - savedAnnotationsCreator: () => ObservableMap = () => this._textAnnotationCreator?.() || this._savedAnnotations; + _textAnnotationCreator: (() => ObservableMap) | undefined; + savedAnnotationsCreator: () => ObservableMap = () => this._textAnnotationCreator?.() || this._savedAnnotations; @action iframeMove = (e: PointerEvent) => { @@ -399,7 +397,7 @@ export class WebBox extends ViewBoxAnnotatableComponent() { .transformPoint(e.clientX, e.clientY - NumCast(this.layoutDoc.layout_scrollTop)); if (!this._marqueeref.current?.isEmpty) this._marqueeref.current?.onEnd(theclick[0], theclick[1]); else { - if (!(e.target as any)?.tagName?.includes('INPUT')) this.finishMarquee(theclick[0], theclick[1]); + if (!(e.target as HTMLElement)?.tagName?.includes('INPUT')) this.finishMarquee(theclick[0], theclick[1]); this._getAnchor = AnchorMenu.Instance?.GetAnchor; this.marqueeing = undefined; } @@ -430,7 +428,8 @@ export class WebBox extends ViewBoxAnnotatableComponent() { this._setPreviewCursor?.(e.clientX, e.clientY, false, true, this.Document); MarqueeAnnotator.clearAnnotations(this._savedAnnotations); - if (!word && !(e.target as any)?.className?.includes('rangeslider') && !(e.target as any)?.onclick && !(e.target as any)?.parentNode?.onclick) { + const target = e.target as HTMLElement; + if (!word && !target?.className?.includes('rangeslider') && !target?.onclick && !target?.parentElement?.onclick) { if (e.button !== 2) this.marqueeing = [e.clientX, e.clientY]; e.preventDefault(); } @@ -470,7 +469,8 @@ export class WebBox extends ViewBoxAnnotatableComponent() { .transformPoint(e.clientX, e.clientY - NumCast(this.layoutDoc.layout_scrollTop)); MarqueeAnnotator.clearAnnotations(this._savedAnnotations); const word = getWordAtPoint(e.target, e.clientX, e.clientY); - if (!word && !(e.target as any)?.className?.includes('rangeslider') && !(e.target as any)?.onclick && !(e.target as any)?.parentNode?.onclick) { + const target = e.target as HTMLElement; + if (!word && !target?.className?.includes('rangeslider') && !target?.onclick && !target?.parentElement?.onclick) { this.marqueeing = theclick; this._marqueeref.current?.onInitiateSelection(this.marqueeing); this._iframe?.contentDocument?.addEventListener('pointermove', this.iframeMove); @@ -479,16 +479,16 @@ export class WebBox extends ViewBoxAnnotatableComponent() { }; isFirefox = () => 'InstallTrigger' in window; // navigator.userAgent.indexOf("Chrome") !== -1; - addWebStyleSheet(document: any, styleType: string = 'text/css') { + addWebStyleSheet(document: Document | null | undefined, styleType: string = 'text/css') { if (document) { const style = document.createElement('style'); style.type = styleType; const sheets = document.head.appendChild(style); - return (sheets as any).sheet; + return sheets.sheet; } return undefined; } - addWebStyleSheetRule(sheet: any, selector: any, css: any, selectorPrefix = '.') { + addWebStyleSheetRule(sheet: CSSStyleSheet | null | undefined, selector: string, css: {[key:string]: string}, selectorPrefix = '.') { const propText = typeof css === 'string' ? css @@ -498,7 +498,7 @@ export class WebBox extends ViewBoxAnnotatableComponent() { return sheet?.insertRule(selectorPrefix + selector + '{' + propText + '}', sheet.cssRules.length); } - _iframetimeout: any = undefined; + _iframetimeout: NodeJS.Timeout|undefined = undefined; @observable _warning = 0; @action iframeLoaded = () => { @@ -520,7 +520,7 @@ export class WebBox extends ViewBoxAnnotatableComponent() { if (requrlraw !== this._url.toString()) { if (requrlraw.match(/q=.*&/)?.length && this._url.toString().match(/q=.*&/)?.length) { const matches = requrlraw.match(/[^a-zA-z]q=[^&]*/g); - const newsearch = matches?.lastElement()!; + const newsearch = matches?.lastElement() || ""; if (matches) { requrlraw = requrlraw.substring(0, requrlraw.indexOf(newsearch)); for (let i = 1; i < Array.from(matches)?.length; i++) { @@ -570,8 +570,10 @@ export class WebBox extends ViewBoxAnnotatableComponent() { undoBatch( action((e: MouseEvent) => { let eleHref = ''; - for (let ele = e.target as any; ele; ele = ele.parentElement) { - eleHref = (typeof ele.href === 'string' ? ele.href : ele.href?.baseVal) || ele.parentElement?.href || eleHref; + for (let ele = e.target as HTMLElement | Element | null; ele; ele = ele.parentElement) { + if (ele instanceof HTMLAnchorElement) { + eleHref = (typeof ele.href === 'string' ? ele.href : eleHref) || (ele.parentElement && ("href" in ele.parentElement) ? ele.parentElement.href as string: eleHref); + } } const origin = this.webField?.origin; if (eleHref && origin) { @@ -850,10 +852,10 @@ export class WebBox extends ViewBoxAnnotatableComponent() { return ( { + ref={action((r: HTMLSpanElement) => { if (r) { this._scrollHeight = DivHeight(r); - this.lighttext = Array.from(r.children).some((c: any) => c instanceof HTMLElement && lightOrDark(getComputedStyle(c).color) !== Colors.WHITE); + this.lighttext = Array.from(r.children).some((c: Element) => c instanceof HTMLElement && lightOrDark(getComputedStyle(c).color) !== Colors.WHITE); } })} contentEditable @@ -1001,7 +1003,7 @@ export class WebBox extends ViewBoxAnnotatableComponent() { }; _innerCollectionView: CollectionFreeFormView | undefined; zoomScaling = () => this._innerCollectionView?.zoomScaling() ?? 1; - setInnerContent = (component: ViewBoxInterface) => { + setInnerContent = (component: ViewBoxInterface) => { this._innerCollectionView = component as CollectionFreeFormView; }; @@ -1083,7 +1085,7 @@ export class WebBox extends ViewBoxAnnotatableComponent() { @computed get webpage() { TraceMobx(); const previewScale = this._previewNativeWidth ? 1 - this.sidebarWidth() / this._previewNativeWidth : 1; - const pointerEvents = this.layoutDoc._lockedPosition ? 'none' : (this._props.pointerEvents?.() as any); + const pointerEvents = this.layoutDoc._lockedPosition ? 'none' : (this._props.pointerEvents?.() as "none" | "all" | "visiblePainted" | undefined) const scale = previewScale * (this._props.NativeDimScaling?.() || 1); return (
() { anchorMenuClick = () => this._sidebarRef.current?.anchorMenuClick; transparentFilter = () => [...this._props.childFilters(), ClientUtils.TransparentBackgroundFilter]; opaqueFilter = () => [...this._props.childFilters(), ClientUtils.noDragDocsFilter, ...(SnappingManager.CanEmbed ? [] : [ClientUtils.OpaqueBackgroundFilter])]; - childStyleProvider = (doc: Doc | undefined, props: Opt, property: string): any => { + childStyleProvider = (doc: Doc | undefined, props: Opt, property: string) => { if (doc instanceof Doc && property === StyleProp.PointerEvents) { if (this.inlineTextAnnotations.includes(doc)) return 'none'; } @@ -1168,7 +1170,7 @@ export class WebBox extends ViewBoxAnnotatableComponent() { render() { TraceMobx(); const previewScale = this._previewNativeWidth ? 1 - this.sidebarWidth() / this._previewNativeWidth : 1; - const pointerEvents = this.layoutDoc._lockedPosition ? 'none' : (this._props.pointerEvents?.() as any); + const pointerEvents = this.layoutDoc._lockedPosition ? 'none' : (this._props.pointerEvents?.() as 'none' | 'all' | 'visiblePainted' | undefined); const scale = previewScale * (this._props.NativeDimScaling?.() || 1); return (
() { pointerEvents: this.pointerEvents(), // position: SnappingManager.IsDragging ? 'absolute' : undefined, }}> -
+
(); private _sidebarTagRef = React.createRef(); private _ref: React.RefObject = React.createRef(); private _scrollRef: HTMLDivElement | null = null; - private _editorView: Opt; + private _editorView: Opt; public _applyingChange: string = ''; private _inDrop = false; private _finishingLink = false; @@ -108,79 +108,40 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent; - private _keymap: any = undefined; + private _keymap: KeyMap | undefined = undefined; private _rules: RichTextRules | undefined; private _forceUncollapse = true; // if the cursor doesn't move between clicks, then the selection will disappear for some reason. This flags the 2nd click as happening on a selection which allows bullet points to toggle private _break = true; public ProseRef?: HTMLDivElement; - public get EditorView() { - return this._editorView; - } - public get SidebarKey() { - return this.fieldKey + '_sidebar'; - } - @computed get allSidebarDocs() { - return DocListCast(this.dataDoc[this.SidebarKey]); - } - - @computed get noSidebar() { - return this.DocumentView?.()._props.hideDecorationTitle || this._props.noSidebar || this.Document._layout_noSidebar; - } - @computed get layout_sidebarWidthPercent() { - return this._showSidebar ? '20%' : StrCast(this.layoutDoc._layout_sidebarWidthPercent, '0%'); - } - @computed get sidebarColor() { - return StrCast(this.layoutDoc.sidebar_color, StrCast(this.layoutDoc[this.fieldKey + '_backgroundColor'], '#e4e4e4')); - } - @computed get layout_autoHeight() { - return (this._props.forceAutoHeight || this.layoutDoc._layout_autoHeight) && !this._props.ignoreAutoHeight; - } - @computed get textHeight() { - return NumCast(this.dataDoc[this.fieldKey + '_height']); - } - @computed get scrollHeight() { - return NumCast(this.dataDoc[this.fieldKey + '_scrollHeight']); - } - @computed get sidebarHeight() { - return !this.sidebarWidth() ? 0 : NumCast(this.dataDoc[this.SidebarKey + '_height']); - } - @computed get titleHeight() { - return this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.HeaderMargin) || 0; - } - @computed get layout_autoHeightMargins() { - return this.titleHeight + NumCast(this.layoutDoc._layout_autoHeightMargins); - } - @computed get _recordingDictation() { - return this.dataDoc?.mediaState === mediaState.Recording; - } - set _recordingDictation(value) { - !this.dataDoc[`${this.fieldKey}_recordingSource`] && (this.dataDoc.mediaState = value ? mediaState.Recording : undefined); - } + set _recordingDictation(value) { !this.dataDoc[`${this.fieldKey}_recordingSource`] && (this.dataDoc.mediaState = value ? mediaState.Recording : undefined); } + @computed get _recordingDictation() { return this.dataDoc?.mediaState === mediaState.Recording; } // prettier-ignore + @computed get allSidebarDocs() { return DocListCast(this.dataDoc[this.SidebarKey]); } // prettier-ignore + @computed get noSidebar() { return this.DocumentView?.()._props.hideDecorationTitle || this._props.noSidebar || this.Document._layout_noSidebar; } // prettier-ignore + @computed get layout_sidebarWidthPercent() { return this._showSidebar ? '20%' : StrCast(this.layoutDoc._layout_sidebarWidthPercent, '0%'); } // prettier-ignore + @computed get sidebarColor() { return StrCast(this.layoutDoc.sidebar_color, StrCast(this.layoutDoc[this.fieldKey + '_backgroundColor'], '#e4e4e4')); } // prettier-ignore + @computed get layout_autoHeight() { return (this._props.forceAutoHeight || this.layoutDoc._layout_autoHeight) && !this._props.ignoreAutoHeight; } // prettier-ignore + @computed get textHeight() { return NumCast(this.dataDoc[this.fieldKey + '_height']); } // prettier-ignore + @computed get scrollHeight() { return NumCast(this.dataDoc[this.fieldKey + '_scrollHeight']); } // prettier-ignore + @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() { this._keymap = buildKeymap(schema, this._props); this._rules = new RichTextRules(this.Document, this); - return { - schema, - plugins: [ - inputRules(this._rules.inpRules), - this.richTextMenuPlugin(), - history(), - keymap(this._keymap), - keymap(baseKeymap), - new Plugin({ props: { attributes: { class: 'ProseMirror-example-setup-style' } } }), - new Plugin({ - view(/* editorView */) { - return new FormattedTextBoxComment(); - }, - }), - ], - }; + return { schema, + plugins: [ + inputRules(this._rules.inpRules), + this.richTextMenuPlugin(), + history(), + keymap(this._keymap), + keymap(baseKeymap), + new Plugin({ props: { attributes: { class: 'ProseMirror-example-setup-style' } } }), + new Plugin({ view: () => new FormattedTextBoxComment() }), + ] }; } - // State for GPT - @observable - private gptRes: string = ''; - + public get EditorView() { return this._editorView; } + public get SidebarKey() { return this.fieldKey + '_sidebar'; } public makeAIFlashcards: () => void = unimplementedFunction; public addToCollection: ((doc: Doc | Doc[], annotationKey?: string | undefined) => boolean) | undefined; @@ -205,9 +166,9 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent { - const foundLinkAnchors = findLinkMark(node.marks)?.attrs.allAnchors.filter((a: any) => a.anchorId === a1[Id] || a.anchorId === a2[Id]) || []; + let allFoundLinkAnchors: { href: string; title: string; anchorId: string }[] = []; + state.doc.nodesBetween(0, state.doc.nodeSize - 2, (node: Node /* , pos: number, parent: any */) => { + const foundLinkAnchors = findLinkMark(node.marks)?.attrs.allAnchors.filter((a: { href: string; title: string; anchorId: string }) => a.anchorId === a1[Id] || a.anchorId === a2[Id]) || []; allFoundLinkAnchors = foundLinkAnchors.length ? foundLinkAnchors : allFoundLinkAnchors; return true; }); @@ -255,7 +216,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent void = emptyFunction; const targetData = target[DocData]; targetData.mediaState = mediaState.Recording; DictationManager.recordAudioAnnotation(targetData, Doc.LayoutFieldKey(target), stop => { stopFunc = stop }); // prettier-ignore @@ -273,10 +234,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent { - this._editorView?.state && RichTextMenu.Instance?.setFontField(color, 'fontHighlight'); - return undefined; - }, 'highlght text'); + AnchorMenu.Instance.Highlight = undoable((color: string) => this._editorView?.state && RichTextMenu.Instance?.setFontField(color, 'fontHighlight'), 'highlght text'); AnchorMenu.Instance.onMakeAnchor = () => this.getAnchor(true); AnchorMenu.Instance.StartCropDrag = unimplementedFunction; /** @@ -292,7 +250,8 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent this.getAnchor(true), targetCreator), e.pageX, e.pageY); + const docView = this.DocumentView?.(); + docView && DragManager.StartAnchorAnnoDrag([ele], new DragManager.AnchorAnnoDragData(docView, () => this.getAnchor(true), targetCreator), e.pageX, e.pageY); }); AnchorMenu.Instance.setSelectedText(window.getSelection()?.toString() ?? ''); @@ -345,7 +304,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent { + state.tr.doc.nodesBetween(0, state.doc.content.size, (node: Node /* , pos: number, parent: any */) => { if (node.type === schema.nodes.dashField && node.attrs.fieldKey.startsWith('#')) { accumTags.push(node.attrs.fieldKey); } @@ -410,8 +369,8 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent) => { + hyperlinkTerm = (trIn: Transaction, target: Doc, newAutoLinks: Set) => { let tr = trIn; const editorView = this._editorView; if (editorView && !Doc.AreProtosEqual(target, this.Document)) { @@ -493,7 +452,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent { + tr.doc.nodesBetween(sel.from, sel.to, (node: Node, pos: number /* , parent: any */) => { if (node.firstChild === null && !node.marks.find((m: Mark) => m.type.name === schema.marks.noAutoLinkAnchor.name) && node.marks.find((m: Mark) => m.type.name === schema.marks.splitter.name)) { alink = alink ?? @@ -646,15 +605,15 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent { const cm = ContextMenu.Instance; - let target = e.target as any; // hrefs are stored on the database of the node that wraps the hyerlink - while (target && !target.dataset?.targethrefs) target = target.parentElement; + let target:Element|HTMLElement|null = e.target as HTMLElement; // hrefs are stored on the database of the node that wraps the hyerlink + while (target && (!(target instanceof HTMLElement) || !target.dataset?.targethrefs)) target = target.parentElement; const editor = this._editorView; if (editor && target && !(e.nativeEvent instanceof simMouseEvent ? e.nativeEvent.dash : false)) { const hrefs = (target.dataset?.targethrefs as string) @@ -1107,7 +1066,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent { + tr.doc.nodesBetween(selection.from, selection.to, (node: Node, pos: number /* , parent: any */) => { if (node.firstChild === null && node.marks.find((m: Mark) => m.type.name === schema.marks.splitter.name)) { const allAnchors = [{ href, title, anchorId: anchor[Id] }]; allAnchors.push(...(node.marks.find((m: Mark) => m.type.name === schema.marks.linkAnchor.name)?.attrs.allAnchors ?? [])); @@ -1184,17 +1143,17 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent= 0) { + const firstChild = ret.frag.childCount ? ret.frag.child(0) : undefined; + if (ret.start >= 0 && (ret.frag.size || (firstChild && [state.schema.nodes.dashDoc, state.schema.nodes.audioTag].includes(firstChild.type)))) { !options.instant && (this._focusSpeed = focusSpeed); - let selection = TextSelection.near(editor.state.doc.resolve(ret.start)); // default to near the start + let selection = TextSelection.near(state.doc.resolve(ret.start)); // default to near the start if (ret.frag.firstChild) { - selection = TextSelection.between(editor.state.doc.resolve(ret.start), editor.state.doc.resolve(ret.start + ret.frag.firstChild.nodeSize)); // bcz: looks better to not have the target selected + selection = TextSelection.between(state.doc.resolve(ret.start), state.doc.resolve(ret.start + ret.frag.firstChild.nodeSize)); // bcz: looks better to not have the target selected } - editor.dispatch(editor.state.tr.setSelection(new TextSelection(selection.$from, selection.$from)).scrollIntoView()); + this._editorView.dispatch(state.tr.setSelection(new TextSelection(selection.$from, selection.$from)).scrollIntoView()); const escAnchorId = textAnchorId[0] >= '0' && textAnchorId[0] <= '9' ? `\\3${textAnchorId[0]} ${textAnchorId.substr(1)}` : textAnchorId; addStyleSheetRule(FormattedTextBox._highlightStyleSheet, `${escAnchorId}`, { background: 'yellow', transform: 'scale(3)', 'transform-origin': 'left bottom' }); setTimeout(() => { @@ -1405,41 +1364,36 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent { - self._props.rootSelected?.() && RichTextMenu.Instance && (RichTextMenu.Instance.view = newView); - }); + return new Plugin({view : action((newView: EditorView) => { + this._props.rootSelected?.() && RichTextMenu.Instance && (RichTextMenu.Instance.view = newView); return new RichTextMenuPlugin({ editorProps: this._props }); - }, - }); - } + })}); + }; _didScroll = false; _scrollStopper: undefined | (() => void); + // eslint-disable-next-line @typescript-eslint/no-explicit-any setupEditor(config: any, fieldKey: string) { const curText = Cast(this.dataDoc[this.fieldKey], RichTextField, null) || StrCast(this.dataDoc[this.fieldKey]); const rtfField = Cast((!curText && this.layoutDoc[this.fieldKey]) || this.dataDoc[fieldKey], RichTextField); if (this.ProseRef) { - const self = this; this._editorView?.destroy(); this._editorView = new EditorView(this.ProseRef, { state: rtfField?.Data ? EditorState.fromJSON(config, JSON.parse(rtfField.Data)) : EditorState.create(config), handleScrollToSelection: editorView => { const docPos = editorView.coordsAtPos(editorView.state.selection.to); - const viewRect = self._ref.current!.getBoundingClientRect(); - const scrollRef = self._scrollRef; + const viewRect = this._ref.current!.getBoundingClientRect(); + const scrollRef = this._scrollRef; const topOff = docPos.top < viewRect.top ? docPos.top - viewRect.top : undefined; const botOff = docPos.bottom > viewRect.bottom ? docPos.bottom - viewRect.bottom : undefined; if (((topOff && Math.abs(Math.trunc(topOff)) > 0) || (botOff && Math.abs(Math.trunc(botOff)) > 0)) && scrollRef) { const shift = Math.min(topOff ?? Number.MAX_VALUE, botOff ?? Number.MAX_VALUE); - const scrollPos = scrollRef.scrollTop + shift * self.ScreenToLocalBoxXf().Scale; + const scrollPos = scrollRef.scrollTop + shift * this.ScreenToLocalBoxXf().Scale; if (this._focusSpeed !== undefined) { setTimeout(() => { scrollPos && (this._scrollStopper = smoothScroll(this._focusSpeed || 0, scrollRef, scrollPos, 'ease', this._scrollStopper)); @@ -1470,7 +1424,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent { - if ((e.nativeEvent as any).handledByInnerReactInstance) { - return; // e.stopPropagation(); - } - (e.nativeEvent as any).handledByInnerReactInstance = true; - if (this.Document.forceActive) e.stopPropagation(); this.tryUpdateScrollHeight(); // if a doc a fitWidth doc is being viewed in different embedContainer (eg freeform & lightbox), then it will have conflicting heights. so when the doc is clicked on, we want to make sure it has the appropriate height for the selected view. - if ((e.target as any).tagName === 'AUDIOTAG') { + const target = e.target as HTMLElement; + if (target.tagName === 'AUDIOTAG') { e.preventDefault(); e.stopPropagation(); - const timecode = Number((e.target as any)?.dataset?.timecode); - DocServer.GetRefField((e.target as any)?.dataset?.audioid || 0).then(anchor => { + const timecode = Number(target.dataset?.timecode); + DocServer.GetRefField(target.dataset?.audioid || "").then(anchor => { if (anchor instanceof Doc) { // const timecode = NumCast(anchor.timecodeToShow, 0); const audiodoc = anchor.annotationOn as Doc; @@ -1583,7 +1533,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent node that wraps the hyerlink - for (let { target } = e as any; target && !target.dataset?.targethrefs; target = target.parentElement); - while (clickTarget && !clickTarget.dataset?.targethrefs) clickTarget = clickTarget.parentElement; - FormattedTextBoxComment.update(this, this.EditorView!, undefined, clickTarget?.dataset?.targethrefs, clickTarget?.dataset.linkdoc, clickTarget?.dataset.nopreview === 'true'); + let clickTarget:HTMLElement|Element|null = e.target as HTMLElement; // hrefs are stored on the dataset of the node that wraps the hyerlink + for (let target:HTMLElement|Element|null = clickTarget as HTMLElement; target instanceof HTMLElement && !target.dataset?.targethrefs; target = target.parentElement); + while (clickTarget instanceof HTMLElement && !clickTarget.dataset?.targethrefs) clickTarget = clickTarget.parentElement; + const dataset = clickTarget instanceof HTMLElement ? clickTarget?.dataset : undefined; + FormattedTextBoxComment.update(this, this.EditorView!, undefined, dataset?.targethrefs, dataset?.linkdoc, dataset?.nopreview === 'true'); } }; @action @@ -1626,27 +1577,24 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent { const pos = ipos ?? (this._editorView?.state.selection.$from.pos || 1); setTimeout(() => this._editorView?.dispatch(this._editorView.state.tr.setSelection(TextSelection.near(this._editorView.state.doc.resolve(pos)))), 100); - setTimeout(() => (this.ProseRef?.children?.[0] as any).focus(), 200); + setTimeout(() => (this.ProseRef?.children?.[0] as HTMLElement).focus(), 200); }; @action onFocused = (e: React.FocusEvent): void => { // applyDevTools.applyDevTools(this._editorView); - this.ProseRef?.children[0] === e.nativeEvent.target && this._editorView && RichTextMenu.Instance?.updateMenu(this._editorView, undefined, this._props, this.layoutDoc); e.stopPropagation(); }; onClick = (e: React.MouseEvent): void => { if (!this._props.isContentActive()) return; - if ((e.nativeEvent as any).handledByInnerReactInstance) { - e.stopPropagation(); - return; - } - if (!this._forceUncollapse || (this._editorView!.root as any).getSelection().isCollapsed) { + const editorView = this._editorView; + const editorRoot = editorView?.root instanceof Document ?editorView.root : undefined; + if (editorView && (!this._forceUncollapse || editorRoot?.getSelection()?.isCollapsed)) { // this is a hack to allow the cursor to be placed at the end of a document when the document ends in an inline dash comment. Apparently Chrome on Windows has a bug/feature which breaks this when clicking after the end of the text. - const pcords = this._editorView!.posAtCoords({ left: e.clientX, top: e.clientY }); - const node = pcords && this._editorView!.state.doc.nodeAt(pcords.pos); // get what prosemirror thinks the clicked node is (if it's null, then we didn't click on any text) - if (pcords && node?.type === this._editorView!.state.schema.nodes.dashComment) { - this._editorView!.dispatch(this._editorView!.state.tr.setSelection(TextSelection.create(this._editorView!.state.doc, pcords.pos + 2))); + const pcords = editorView.posAtCoords({ left: e.clientX, top: e.clientY }); + const node = pcords && editorView.state.doc.nodeAt(pcords.pos); // get what prosemirror thinks the clicked node is (if it's null, then we didn't click on any text) + if (pcords && node?.type === editorView.state.schema.nodes.dashComment) { + this._editorView!.dispatch(editorView.state.tr.setSelection(TextSelection.create(editorView.state.doc, pcords.pos + 2))); e.preventDefault(); } if (!node && this.ProseRef) { @@ -1654,19 +1602,19 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent boundsRect.left && e.clientX < boundsRect.right && e.clientY > boundsRect.bottom) { // if we clicked below the last prosemirror div, then set the selection to be the end of the document - this._editorView?.focus(); - this._editorView!.dispatch(this._editorView!.state.tr.setSelection(TextSelection.create(this._editorView!.state.doc, this._editorView!.state.doc.content.size))); + editorView.focus(); + editorView.dispatch(editorView.state.tr.setSelection(TextSelection.create(editorView.state.doc, editorView.state.doc.content.size))); } - } else if (node && [this._editorView!.state.schema.nodes.ordered_list, this._editorView!.state.schema.nodes.listItem].includes(node.type) && node !== (this._editorView!.state.selection as NodeSelection)?.node && pcords) { - this._editorView!.dispatch(this._editorView!.state.tr.setSelection(NodeSelection.create(this._editorView!.state.doc, pcords.pos))); + } else if (node && [editorView.state.schema.nodes.ordered_list, editorView.state.schema.nodes.listItem].includes(node.type) && node !== (editorView.state.selection as NodeSelection)?.node && pcords) { + editorView.dispatch(editorView.state.tr.setSelection(NodeSelection.create(editorView.state.doc, pcords.pos))); } } - if (this._props.rootSelected?.()) { + if (editorView && this._props.rootSelected?.()) { // if text box is selected, then it consumes all click events - (e.nativeEvent as any).handledByInnerReactInstance = true; - this.hitBulletTargets(e.clientX, e.clientY, !this._editorView?.state.selection.empty || this._forceUncollapse, false, e.shiftKey); + e.stopPropagation(); + this.hitBulletTargets(e.clientX, e.clientY, !editorView.state.selection.empty || this._forceUncollapse, false, e.shiftKey); } - this._forceUncollapse = !(this._editorView!.root as any).getSelection().isCollapsed; + this._forceUncollapse = !editorRoot?.getSelection()?.isCollapsed; }; // this hackiness handles clicking on the list item bullets to do expand/collapse. the bullets are ::before pseudo elements so there's no real way to hit test against them. hitBulletTargets(x: number, y: number, collapse: boolean, highlightOnly: boolean, selectOrderedList: boolean = false) { @@ -1682,9 +1630,9 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent 3) { + if ($olistPos && $olistPos.depth) { olistNode = $olistPos.parent; - $olistPos = this._editorView?.state.doc.resolve(($olistPos as any).path[($olistPos as any).path.length - 4]); + $olistPos = this._editorView?.state.doc.resolve($olistPos.start($olistPos.depth - 1)); } } const maxSize = this._editorView?.state.doc.content.size ?? 0; @@ -1715,7 +1663,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent { + onBlur = (e: React.FocusEvent) => { if (this.ProseRef?.children[0] !== e.nativeEvent.target) return; if (!(this.EditorView?.state.selection instanceof NodeSelection) || this.EditorView.state.selection.node.type !== this.EditorView.state.schema.nodes.footnote) { const stordMarks = this._editorView?.state.storedMarks?.slice(); @@ -1780,7 +1728,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent d?.author).length; const color = !annotated ? Colors.WHITE : Colors.BLACK; - const backgroundColor = !annotated ? (this.sidebarWidth() ? Colors.MEDIUM_BLUE : Colors.BLACK) : this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.WidgetColor + (annotated ? ':annotated' : '')); + const backgroundColor = !annotated ? (this.sidebarWidth() ? Colors.MEDIUM_BLUE : Colors.BLACK) : this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.WidgetColor + (annotated ? ':annotated' : '')) as string; return !annotated && (!this._props.isContentActive() || SnappingManager.IsDragging || Doc.ActiveTool !== InkTool.None) ? null : (
{ + // eslint-disable-next-line @typescript-eslint/no-explicit-any const ComponentTag: any = tag === CollectionViewType.Tree ? CollectionTreeView : tag === 'translation' ? FormattedTextBox : CollectionStackingView; return ComponentTag === CollectionStackingView ? ( { + let child: Node | undefined; + state.doc.nodesBetween(state.selection.from, state.selection.to, (node: Node /* , pos: number, parent: any */) => { !child && node.marks.length && (child = node); }); const mark = child && findOtherUserMark(child.marks); diff --git a/src/client/views/nodes/formattedText/RichTextMenu.tsx b/src/client/views/nodes/formattedText/RichTextMenu.tsx index a612f3c65..247b7c097 100644 --- a/src/client/views/nodes/formattedText/RichTextMenu.tsx +++ b/src/client/views/nodes/formattedText/RichTextMenu.tsx @@ -5,7 +5,7 @@ import { observer } from 'mobx-react'; import { lift, wrapIn } from 'prosemirror-commands'; import { Mark, MarkType } from 'prosemirror-model'; import { wrapInList } from 'prosemirror-schema-list'; -import { EditorState, NodeSelection, TextSelection } from 'prosemirror-state'; +import { EditorState, NodeSelection, TextSelection, Transaction } from 'prosemirror-state'; import { EditorView } from 'prosemirror-view'; import * as React from 'react'; import { Doc } from '../../../../fields/Doc'; @@ -17,7 +17,7 @@ import { ObservableReactComponent } from '../../ObservableReactComponent'; import { DocumentView } from '../DocumentView'; import { EquationBox } from '../EquationBox'; import { FieldViewProps } from '../FieldView'; -import { FormattedTextBox } from './FormattedTextBox'; +import { FormattedTextBox, FormattedTextBoxProps } from './FormattedTextBox'; import { updateBullets } from './ProsemirrorExampleTransfer'; import './RichTextMenu.scss'; import { schema } from './schema_rts'; @@ -35,8 +35,8 @@ export class RichTextMenu extends AntimodeMenu { private _linkToRef = React.createRef(); layoutDoc: Doc | undefined; - @observable public view?: EditorView = undefined; - public editorProps: FieldViewProps | undefined; + @observable public view?: EditorView & { TextView ?: FormattedTextBox } = undefined; + public editorProps: FieldViewProps | AntimodeMenuProps |undefined; public _brushMap: Map> = new Map(); @@ -114,17 +114,17 @@ export class RichTextMenu extends AntimodeMenu { } _disposer: IReactionDisposer | undefined; componentDidMount() { - this._disposer = reaction( - () => DocumentView.Selected().slice(), - () => this.updateMenu(undefined, undefined, undefined, undefined) - ); + // this._disposer = reaction( + // () => DocumentView.Selected().slice(), + // () => this.updateMenu(undefined, undefined, undefined, undefined) + // ); } componentWillUnmount() { this._disposer?.(); } @action - public updateMenu(view: EditorView | undefined, lastState: EditorState | undefined, props: any, layoutDoc: Doc | undefined) { + public updateMenu(view: EditorView | undefined, lastState: EditorState | undefined, props: FormattedTextBoxProps|AntimodeMenuProps|undefined, layoutDoc: Doc | undefined) { if (this._linkToRef.current?.getBoundingClientRect().width) { return; } @@ -158,7 +158,7 @@ export class RichTextMenu extends AntimodeMenu { this.getTextLinkTargetTitle().then(targetTitle => this.setCurrentLink(targetTitle)); } - setMark = (mark: Mark, state: EditorState, dispatch: any, dontToggle: boolean = false) => { + setMark = (mark: Mark, state: EditorState, dispatch: (tr:Transaction) => void, dontToggle: boolean = false) => { if (mark) { const newPos = state.selection.$anchor.node()?.type === schema.nodes.ordered_list ? state.selection.from : state.selection.from; const node = (state.selection as NodeSelection).node ?? (newPos >= 0 ? state.doc.nodeAt(newPos) : undefined); @@ -177,17 +177,18 @@ export class RichTextMenu extends AntimodeMenu { toggleMark(mark.type, mark.attrs)(state, dispatch); } } - this.updateMenu(this.view, undefined, undefined, this.layoutDoc); + // this.updateMenu(this.view, undefined, undefined, this.layoutDoc); } }; // finds font sizes and families in selection - getActiveAlignment() { + getActiveAlignment = () => { if (this.view && this.TextView?._props.rootSelected?.()) { - const { path } = this.view.state.selection.$from as any; - for (let i = path.length - 3; i < path.length && i >= 0; i -= 3) { - if (path[i]?.type === this.view.state.schema.nodes.paragraph || path[i]?.type === this.view.state.schema.nodes.heading) { - return path[i].attrs.align || 'left'; + const from = this.view.state.selection.$from; + for (let i = from.depth; i >= 0; i--) { + const node = from.node(i); + if (node.type === this.view.state.schema.nodes.paragraph || node.type === this.view.state.schema.nodes.heading) { + return node.attrs.align || 'left'; } } } @@ -195,7 +196,7 @@ export class RichTextMenu extends AntimodeMenu { } // finds font sizes and families in selection - getActiveListStyle() { + getActiveListStyle = () => { const state = this.view?.state; if (state) { const pos = state.selection.$anchor; @@ -321,7 +322,7 @@ export class RichTextMenu extends AntimodeMenu { if (this.view) { const mark = this.view.state.schema.mark(this.view.state.schema.marks.noAutoLinkAnchor); this.setMark(mark, this.view.state, this.view.dispatch, false); - this.TextView.autoLink(); + this.TextView?.autoLink(); this.view.focus(); } }; @@ -350,7 +351,7 @@ export class RichTextMenu extends AntimodeMenu { }; setFontField = (value: string, fontField: 'fontSize' | 'fontFamily' | 'fontColor' | 'fontHighlight') => { - if (this.view) { + if (this.TextView && this.view) { const { text, paragraph } = this.view.state.schema.nodes; const selNode = this.view.state.selection.$anchor.node(); if (this.view.state.selection.from === 1 && this.view.state.selection.empty && [undefined, text, paragraph].includes(selNode?.type)) { @@ -360,11 +361,11 @@ export class RichTextMenu extends AntimodeMenu { const attrs: { [key: string]: string } = {}; attrs[fontField] = value; const fmark = this.view?.state.schema.marks['pF' + fontField.substring(1)].create(attrs); - this.setMark(fmark, this.view.state, (tx: any) => this.view!.dispatch(tx.addStoredMark(fmark)), true); + this.setMark(fmark, this.view.state, (tx: Transaction) => this.view!.dispatch(tx.addStoredMark(fmark)), true); this.view.focus(); } else { Doc.UserDoc()[fontField] = value; - this.updateMenu(this.view, undefined, this.props, this.layoutDoc); + // this.updateMenu(this.view, undefined, this.props, this.layoutDoc); } }; @@ -383,17 +384,17 @@ export class RichTextMenu extends AntimodeMenu { marks && tx2.setStoredMarks([...marks]); this.view.dispatch(tx2); } else - !wrapInList(schema.nodes.ordered_list)(this.view.state, (tx2: any) => { + !wrapInList(schema.nodes.ordered_list)(this.view.state, (tx2: Transaction) => { const tx3 = updateBullets(tx2, schema, newMapStyle, this.view!.state.selection.from - 1, this.view!.state.selection.to + 1); marks && tx3.ensureMarks([...marks]); marks && tx3.setStoredMarks([...marks]); this.view!.dispatch(tx3); }); this.view.focus(); - this.updateMenu(this.view, undefined, this.props, this.layoutDoc); + // this.updateMenu(this.view, undefined, this.props, this.layoutDoc); }; - insertSummarizer(state: EditorState, dispatch: any) { + insertSummarizer(state: EditorState, dispatch: (tr:Transaction) => void) { if (state.selection.empty) return false; const mark = state.schema.marks.summarize.create(); const { tr } = state; @@ -407,7 +408,7 @@ export class RichTextMenu extends AntimodeMenu { vcenterToggle = () => { this.layoutDoc && (this.layoutDoc._layout_centered = !this.layoutDoc._layout_centered); }; - align = (view: EditorView, dispatch: any, alignment: 'left' | 'right' | 'center') => { + align = (view: EditorView, dispatch: (tr:Transaction) => void, alignment: 'left' | 'right' | 'center') => { if (this.TextView?._props.rootSelected?.()) { let { tr } = view.state; view.state.doc.nodesBetween(view.state.selection.from, view.state.selection.to, (node, pos) => { @@ -423,7 +424,7 @@ export class RichTextMenu extends AntimodeMenu { } }; - paragraphSetup(state: EditorState, dispatch: any, field: 'inset' | 'indent', value?: 0 | 10 | -10) { + paragraphSetup(state: EditorState, dispatch: (tr:Transaction) => void, field: 'inset' | 'indent', value?: 0 | 10 | -10) { let { tr } = state; state.doc.nodesBetween(state.selection.from, state.selection.to, (node, pos) => { if (node.type === schema.nodes.paragraph || node.type === schema.nodes.heading) { @@ -439,9 +440,9 @@ export class RichTextMenu extends AntimodeMenu { return true; } - insertBlockquote(state: EditorState, dispatch: any) { - const { path } = state.selection.$from as any; - if (path.length > 6 && path[path.length - 6].type === schema.nodes.blockquote) { + insertBlockquote(state: EditorState, dispatch: (tr:Transaction) => void) { + const node = state.selection.$from.depth ? state.selection.$from.node(state.selection.$from.depth-1): undefined; + if (node?.type === schema.nodes.blockquote) { lift(state, dispatch); } else { wrapIn(schema.nodes.blockquote)(state, dispatch); @@ -449,7 +450,7 @@ export class RichTextMenu extends AntimodeMenu { return true; } - insertHorizontalRule(state: EditorState, dispatch: any) { + insertHorizontalRule(state: EditorState, dispatch: (tr:Transaction) => void) { dispatch(state.tr.replaceSelectionWith(state.schema.nodes.horizontal_rule.create()).scrollIntoView()); return true; } @@ -497,7 +498,7 @@ export class RichTextMenu extends AntimodeMenu { } get TextView() { - return (this.view as any)?.TextView as FormattedTextBox; + return this.view?.TextView; } get TextViewFieldKey() { return this.TextView?._props.fieldKey; @@ -512,11 +513,9 @@ export class RichTextMenu extends AntimodeMenu { } createLinkButton() { - const self = this; - - function onLinkChange(e: React.ChangeEvent) { - self.TextView?.endUndoTypingBatch(); - UndoManager.RunInBatch(() => self.setCurrentLink(e.target.value), 'link change'); + const onLinkChange = (e: React.ChangeEvent) => { + this.TextView?.endUndoTypingBatch(); + UndoManager.RunInBatch(() => this.setCurrentLink(e.target.value), 'link change'); } const link = this.currentLink ? this.currentLink : ''; @@ -524,7 +523,6 @@ export class RichTextMenu extends AntimodeMenu { const button = ( set hyperlink
} placement="bottom"> { - // eslint-disable-next-line jsx-a11y/control-has-associated-label @@ -589,7 +587,7 @@ export class RichTextMenu extends AntimodeMenu { // TODO: should check for valid URL @undoBatch makeLinkToURL = (target: string) => { - ((this.view as any)?.TextView as FormattedTextBox).makeLinkAnchor(undefined, 'onRadd:rightight', target, target); + this.TextView?.makeLinkAnchor(undefined, 'onRadd:rightight', target, target); }; @undoBatch @@ -597,12 +595,12 @@ export class RichTextMenu extends AntimodeMenu { if (this.view) { const linkAnchor = this.view.state.selection.$from.nodeAfter?.marks.find(m => m.type === this.view!.state.schema.marks.linkAnchor); if (linkAnchor) { - const allAnchors = linkAnchor.attrs.allAnchors.slice(); - this.TextView.RemoveAnchorFromSelection(allAnchors); + const allAnchors = (linkAnchor.attrs.allAnchors as { href: string; title: string; linkId: string; targetId: string; }[]).slice(); + this.TextView?.RemoveAnchorFromSelection(allAnchors); // bcz: Argh ... this will remove the link from the document even it's anchored somewhere else in the text which happens if only part of the anchor text was selected. allAnchors - .filter((aref: any) => aref?.href.indexOf(Doc.localServerPath()) === 0) - .forEach((aref: any) => { + .filter(aref => aref?.href.indexOf(Doc.localServerPath()) === 0) + .forEach(aref => { const anchorId = aref.href.replace(Doc.localServerPath(), '').split('?')[0]; anchorId && DocServer.GetRefField(anchorId).then(linkDoc => Doc.DeleteLink?.(linkDoc as Doc)); }); @@ -629,7 +627,7 @@ export class ButtonDropdown extends ObservableReactComponent {this._props.button} { - // eslint-disable-next-line jsx-a11y/control-has-associated-label @@ -697,12 +694,12 @@ export class ButtonDropdown extends ObservableReactComponent { // eslint-disable-next-line react/no-unused-class-component-methods - update(view: EditorView, lastState: EditorState | undefined) { - RichTextMenu.Instance?.updateMenu(view, lastState, this.props.editorProps, (view as any).TextView?.layoutDoc); + update(view: EditorView & {TextView ?: FormattedTextBox}, lastState: EditorState | undefined) { + RichTextMenu.Instance?.updateMenu(view, lastState, this.props.editorProps, view.TextView?.layoutDoc); } render() { return null; diff --git a/src/client/views/pdf/AnchorMenu.tsx b/src/client/views/pdf/AnchorMenu.tsx index 2f6824466..03585a8b7 100644 --- a/src/client/views/pdf/AnchorMenu.tsx +++ b/src/client/views/pdf/AnchorMenu.tsx @@ -25,7 +25,7 @@ export class AnchorMenu extends AntimodeMenu { private _commentRef = React.createRef(); private _cropRef = React.createRef(); - constructor(props: any) { + constructor(props: AntimodeMenuProps) { super(props); makeObservable(this); AnchorMenu.Instance = this; @@ -50,7 +50,7 @@ export class AnchorMenu extends AntimodeMenu { public OnAudio: (e: PointerEvent) => void = unimplementedFunction; public StartDrag: (e: PointerEvent, ele: HTMLElement) => void = unimplementedFunction; public StartCropDrag: (e: PointerEvent, ele: HTMLElement) => void = unimplementedFunction; - public Highlight: (color: string) => Opt = (/* color: string */) => undefined; + public Highlight: (color: string) => void = emptyFunction; public GetAnchor: (savedAnnotations: Opt>, addAsAnnotation: boolean) => Opt = emptyFunction; public Delete: () => void = unimplementedFunction; public PinToPres: () => void = unimplementedFunction; diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx index fa5e5cedb..1279563ef 100644 --- a/src/client/views/pdf/PDFViewer.tsx +++ b/src/client/views/pdf/PDFViewer.tsx @@ -1,5 +1,3 @@ -/* eslint-disable jsx-a11y/no-static-element-interactions */ -/* eslint-disable jsx-a11y/click-events-have-key-events */ import { action, computed, IReactionDisposer, makeObservable, observable, ObservableMap, reaction, runInAction } from 'mobx'; import { observer } from 'mobx-react'; import * as Pdfjs from 'pdfjs-dist'; @@ -64,13 +62,13 @@ export class PDFViewer extends ObservableReactComponent { } @observable _pageSizes: { width: number; height: number }[] = []; - @observable _savedAnnotations = new ObservableMap(); + @observable _savedAnnotations = new ObservableMap(); @observable _textSelecting = true; @observable _showWaiting = true; @observable Index: number = -1; - private _pdfViewer: any; - private _styleRule: any; // stylesheet rule for making hyperlinks clickable + private _pdfViewer!: PDFJSViewer.PDFViewer; + private _styleRule: number | undefined; // stylesheet rule for making hyperlinks clickable private _retries = 0; // number of times tried to create the PDF viewer private _setPreviewCursor: undefined | ((x: number, y: number, drag: boolean, hide: boolean, doc: Opt) => void); private _marqueeref = React.createRef(); @@ -107,7 +105,7 @@ export class PDFViewer extends ObservableReactComponent { }); this.setupPdfJsViewer(); this._mainCont.current?.addEventListener('scroll', e => { - (e.target as any).scrollLeft = 0; + (e.target as HTMLElement).scrollLeft = 0; }); this._disposers.layout_autoHeight = reaction( @@ -211,18 +209,12 @@ export class PDFViewer extends ObservableReactComponent { }; pagesinit = () => { - if (this._pdfViewer._setDocumentViewerElement?.offsetParent) { - runInAction(() => { - this._pdfViewer.currentScaleValue = this._props.layoutDoc._freeform_scale = 1; - }); - this.gotoPage(NumCast(this._props.Document._layout_curPage, 1)); - } document.removeEventListener('pagesinit', this.pagesinit); let quickScroll: { loc?: string; easeFunc?: 'ease' | 'linear' } | undefined = { loc: this._initialScroll ? this._initialScroll.loc?.toString() : '', easeFunc: this._initialScroll ? this._initialScroll.easeFunc : undefined }; this._disposers.scale = reaction( () => NumCast(this._props.layoutDoc._freeform_scale, 1), scale => { - this._pdfViewer.currentScaleValue = scale; + this._pdfViewer.currentScaleValue = scale+""; }, { fireImmediately: true } ); @@ -321,7 +313,7 @@ export class PDFViewer extends ObservableReactComponent { } }; - @observable private _scrollTimer: any = undefined; + @observable private _scrollTimer: NodeJS.Timeout | undefined = undefined; onScroll = () => { if (this._mainCont.current && !this._forcedScroll) { @@ -330,7 +322,7 @@ export class PDFViewer extends ObservableReactComponent { this._props.layoutDoc._layout_scrollTop = this._mainCont.current.scrollTop; } this._ignoreScroll = false; - if (this._scrollTimer) clearTimeout(this._scrollTimer); // wait until a scrolling pause, then create an anchor to audio + this._scrollTimer && clearTimeout(this._scrollTimer); // wait until a scrolling pause, then create an anchor to audio this._scrollTimer = setTimeout(() => { CreateLinkToActiveAudio(() => this._props.pdfBox.getAnchor(true)!, false); this._scrollTimer = undefined; @@ -390,8 +382,8 @@ export class PDFViewer extends ObservableReactComponent { this._props.select(false); MarqueeAnnotator.clearAnnotations(this._savedAnnotations); this.isAnnotating = true; - const target = e.target as any; - if (e.target && (target.className.includes('endOfContent') || (target.parentElement.className !== 'textLayer' && target.parentElement.parentElement?.className !== 'textLayer'))) { + const target = e.target as HTMLElement; + if (e.target && (target.className.includes('endOfContent') || (target.parentElement?.className !== 'textLayer' && target.parentElement?.parentElement?.className !== 'textLayer'))) { this._textSelecting = false; } else { // if textLayer is hit, then we select text instead of using a marquee so clear out the marquee. @@ -491,7 +483,7 @@ export class PDFViewer extends ObservableReactComponent { e.stopPropagation(); if (e.ctrlKey) { const curScale = Number(this._pdfViewer.currentScaleValue); - this._pdfViewer.currentScaleValue = Math.max(1, Math.min(10, curScale - (curScale * e.deltaY) / 1000)); + this._pdfViewer.currentScaleValue = Math.max(1, Math.min(10, curScale - (curScale * e.deltaY) / 1000)) + ""; this._props.layoutDoc._freeform_scale = Number(this._pdfViewer.currentScaleValue); } } @@ -520,7 +512,7 @@ export class PDFViewer extends ObservableReactComponent { panelHeight = () => this._props.PanelHeight() / (this._props.NativeDimScaling?.() || 1); transparentFilter = () => [...this._props.childFilters(), ClientUtils.TransparentBackgroundFilter]; opaqueFilter = () => [...this._props.childFilters(), ClientUtils.noDragDocsFilter, ...(SnappingManager.CanEmbed && this._props.isContentActive() ? [] : [ClientUtils.OpaqueBackgroundFilter])]; - childStyleProvider = (doc: Doc | undefined, props: Opt, property: string): any => { + childStyleProvider = (doc: Doc | undefined, props: Opt, property: string) => { if (doc instanceof Doc && property === StyleProp.PointerEvents) { if (this.inlineTextAnnotations.includes(doc) || this._props.isContentActive() === false) return 'none'; const isInk = doc.layout_isSvg && !props?.LayoutTemplateString; @@ -531,11 +523,11 @@ export class PDFViewer extends ObservableReactComponent { }; childPointerEvents = () => (this._props.isContentActive() !== false ? 'all' : 'none'); - renderAnnotations = (childFilters: () => string[], mixBlendMode?: any, display?: string) => ( + renderAnnotations = (childFilters: () => string[], mixBlendMode?: 'hard-light' | 'multiply', display?: string) => (
-- cgit v1.2.3-70-g09d2 From 6cf715a76dfb3f6a80fbf7c33e643681ea1a584c Mon Sep 17 00:00:00 2001 From: IEatChili Date: Tue, 30 Jul 2024 14:30:08 -0400 Subject: feat: adjusted ui: --- src/client/views/DocumentDecorations.tsx | 2 +- src/client/views/KeywordBox.tsx | 263 +++++++++++++++++++------------ src/client/views/StyleProvider.scss | 26 ++- 3 files changed, 189 insertions(+), 102 deletions(-) (limited to 'src') diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index dc40562e8..bd6952620 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -832,7 +832,7 @@ export class DocumentDecorations extends ObservableReactComponent DocumentView.Selected()} /> diff --git a/src/client/views/KeywordBox.tsx b/src/client/views/KeywordBox.tsx index 321362299..68584a7fa 100644 --- a/src/client/views/KeywordBox.tsx +++ b/src/client/views/KeywordBox.tsx @@ -1,4 +1,4 @@ -import { Colors, IconButton } from 'browndash-components'; +import { Button, Colors, IconButton } from 'browndash-components'; import { action, computed, makeObservable, observable, reaction } from 'mobx'; import { observer } from 'mobx-react'; import React from 'react'; @@ -6,14 +6,11 @@ import { returnFalse, setupMoveUpEvents } from '../../ClientUtils'; import { Doc, DocListCast } from '../../fields/Doc'; import { DocData } from '../../fields/DocSymbols'; import { List } from '../../fields/List'; -import { DocCast, NumCast } from '../../fields/Types'; +import { NumCast, StrCast } from '../../fields/Types'; import { emptyFunction } from '../../Utils'; -import { Docs } from '../documents/Documents'; -import { DocUtils } from '../documents/DocUtils'; -import { DragManager, SetupDrag } from '../util/DragManager'; +import { DocumentType } from '../documents/DocumentTypes'; +import { DragManager } from '../util/DragManager'; import { SnappingManager } from '../util/SnappingManager'; -import { CollectionFreeFormView } from './collections/collectionFreeForm'; -import { MainView } from './MainView'; import { DocumentView } from './nodes/DocumentView'; import { ObservableReactComponent } from './ObservableReactComponent'; @@ -21,11 +18,13 @@ interface KeywordItemProps { doc: Doc; keyword: string; keywordDoc: Doc; - keywordCollection: Doc[]; setToEditing: () => void; isEditing: boolean; } +/** + * A component that handles individual keywords. + */ @observer export class KeywordItem extends ObservableReactComponent { constructor(props: any) { @@ -36,8 +35,12 @@ export class KeywordItem extends ObservableReactComponent { private ref: React.RefObject; + /** + * Gets the documents that a keyword is associated with. + * @returns An array of documents that contain the keyword. + */ getKeywordCollectionDocs = () => { - for (const doc of DocListCast(Doc.UserDoc().myKeywordCollections)) { + for (const doc of DocListCast(Doc.ActiveDashboard?.myKeywordCollections)) { if (doc.title === this._props.keyword) { return doc[DocData].docs; } @@ -45,9 +48,16 @@ export class KeywordItem extends ObservableReactComponent { return null; }; + /** + * Creates a smart collection. + * @returns + */ createCollection = () => { + // Get the documents that contain the keyword. const selected = DocListCast(this.getKeywordCollectionDocs()!); const newEmbeddings = selected.map(doc => Doc.MakeEmbedding(doc)); + + // Create a new collection and set up configurations. const newCollection = ((doc: Doc) => { const docData = doc[DocData]; docData.data = new List(newEmbeddings); @@ -59,9 +69,12 @@ export class KeywordItem extends ObservableReactComponent { newCollection._width = 900; newCollection._height = 900; newCollection.layout_fitWidth = true; - //newCollection[DocData].smartCollection = this._props.keywordDoc; + // Add the collection to the keyword document's list of associated smart collections. this._props.keywordDoc.collections = new List([...DocListCast(this._props.keywordDoc.collections), newCollection]); + newCollection[DocData].data_labels = new List([this._props.keyword]); + newCollection[DocData][`${this._props.keyword}`] = true; + newCollection[DocData].showLabels = true; return newCollection; }; @@ -89,16 +102,24 @@ export class KeywordItem extends ObservableReactComponent { @action removeLabel = () => { if (this._props.doc[DocData].data_labels) { - const filtered_docs = new List(DocListCast(this.getKeywordCollectionDocs()!).filter(doc => doc !== this._props.doc)); - this._props.keywordDoc[DocData].docs = filtered_docs; + if (this._props.doc.type === DocumentType.COL) { + const filtered_collections = new List(DocListCast(this._props.keywordDoc.collections).filter(doc => doc !== this._props.doc)); + this._props.keywordDoc.collections = filtered_collections; - this._props.doc[DocData].data_labels = (this._props.doc[DocData].data_labels as List).filter(label => label !== this._props.keyword) as List; - this._props.doc![DocData][`${this._props.keyword}`] = false; + for (const cur_doc of DocListCast(this.getKeywordCollectionDocs()!, [])) { + this._props.doc[DocData].data = new List(DocListCast(this._props.doc[DocData].data).filter(doc => !Doc.AreProtosEqual(cur_doc, doc))); + } + } else { + const filtered_docs = new List(DocListCast(this.getKeywordCollectionDocs()!).filter(doc => doc !== this._props.doc)); + this._props.keywordDoc[DocData].docs = filtered_docs; - for (const collection of DocListCast(this._props.keywordDoc.collections)) { - collection[DocData].data = new List(DocListCast(collection[DocData].data).filter(doc => !Doc.AreProtosEqual(this._props.doc, doc))); + for (const collection of DocListCast(this._props.keywordDoc.collections)) { + collection[DocData].data = new List(DocListCast(collection[DocData].data).filter(doc => !Doc.AreProtosEqual(this._props.doc, doc))); + } } } + this._props.doc[DocData].data_labels = (this._props.doc[DocData].data_labels as List).filter(label => label !== this._props.keyword) as List; + this._props.doc![DocData][`${this._props.keyword}`] = false; }; render() { @@ -116,6 +137,9 @@ interface KeywordBoxProps { isEditing: boolean; } +/** + * A component that handles the keyword display for documents. + */ @observer export class KeywordBox extends ObservableReactComponent { @observable _currentInput: string = ''; @@ -127,30 +151,32 @@ export class KeywordBox extends ObservableReactComponent { return NumCast((this._props.doc.embedContainer as Doc)?._freeform_scale, 1); } + @computed + get cur_height() { + return this.ref.current?.offsetHeight ? this.ref.current?.offsetHeight : 0; + } + constructor(props: any) { super(props); makeObservable(this); this.ref = React.createRef(); - } - - componentDidMount(): void { - this.height = this.ref.current?.getBoundingClientRect().height ? this.ref.current?.getBoundingClientRect().height : 0; - this._props.doc._keywordHeight = this.height; reaction( - () => this.currentScale, + () => this.cur_height, () => { - if (this.currentScale < 1) { - this.height = this.ref.current?.getBoundingClientRect().height ? this.ref.current?.getBoundingClientRect().height : 0; - this._props.doc._keywordHeight = this.height; - } + this._props.doc[DocData].keywordHeight = this.height; } ); } + componentDidMount(): void { + this.height = this.ref.current?.offsetHeight ? this.ref.current?.offsetHeight : 0; + this._props.doc[DocData].keywordHeight = this.height; + } + componentDidUpdate(prevProps: Readonly): void { - this.height = this.ref.current?.getBoundingClientRect().height ? this.ref.current?.getBoundingClientRect().height : 0; - this._props.doc._keywordHeight = this.height; + this.height = this.ref.current?.offsetHeight ? this.ref.current?.offsetHeight : 0; + this._props.doc[DocData].keywordHeight = this.height; } @action @@ -163,30 +189,44 @@ export class KeywordBox extends ObservableReactComponent { this._props.isEditing = false; }; + /** + * Gets the document associated with a keyword. + * @param keyword The keyword being searched for + * @returns A Doc containing keyword information + */ getKeywordCollection = (keyword: string) => { - for (const doc of DocListCast(Doc.UserDoc().myKeywordCollections)) { + // Look for the keyword document. + for (const doc of DocListCast(Doc.ActiveDashboard!.myKeywordCollections)) { if (doc.title === keyword) { return doc; } } + // If not contained, create a new document and add it to the active Dashboard's keyword list. const keywordCollection = new Doc(); keywordCollection.title = keyword; keywordCollection[DocData].docs = new List(); keywordCollection.collections = new List(); - Doc.UserDoc().myKeywordCollections = new List([...DocListCast(Doc.UserDoc().myKeywordCollections), keywordCollection]); + if (Doc.ActiveDashboard) { + Doc.ActiveDashboard.myKeywordCollections = new List([...DocListCast(Doc.ActiveDashboard.myKeywordCollections), keywordCollection]); + } return keywordCollection; }; - submitLabel = () => { - if (!Doc.UserDoc().myKeywordCollections) { - Doc.UserDoc().myKeywordCollections = new List(); + /** + * Adds the keyword to the document. + * @param keyword + */ + submitLabel = (keyword: string) => { + // If the active Dashboard does not have a keyword collection, create it. + if (Doc.ActiveDashboard && !Doc.ActiveDashboard.myKeywordCollections) { + Doc.ActiveDashboard.myKeywordCollections = new List(); } - const submittedLabel = this._currentInput.trim(); - if (submittedLabel) { - // If the keyword collection is not in the user doc, add it as a new doc, with the keyword as its title. + const submittedLabel = keyword.trim(); + if (submittedLabel && !this._props.doc![DocData][`${submittedLabel}`]) { + // If the keyword collection is not in active Dashboard, add it as a new doc, with the keyword as its title. const keywordCollection = this.getKeywordCollection(submittedLabel); // If the document has no keywords field, create the field. @@ -194,20 +234,31 @@ export class KeywordBox extends ObservableReactComponent { this._props.doc[DocData].data_labels = new List(); } - // Add this document to the keyword's collection of associated documents. - keywordCollection[DocData].docs = new List([...DocListCast(keywordCollection[DocData].docs), this._props.doc]); - - // Push the keyword to the document's keyword list field. - (this._props.doc![DocData].data_labels! as List).push(submittedLabel); - this._props.doc![DocData][`${this._currentInput}`] = true; + // If the document is of type COLLECTION, make it a smart collection, otherwise, add the keyword to the document. + if (this._props.doc.type === DocumentType.COL) { + keywordCollection.collections = new List([...DocListCast(keywordCollection.collections), this._props.doc]); - // Iterate through the keyword document's collections and add a copy of the document to each collection - for (const collection of DocListCast(keywordCollection.collections)) { - const newEmbedding = Doc.MakeEmbedding(this._props.doc); - collection[DocData].data = new List([...DocListCast(collection.data), newEmbedding]); - newEmbedding.embedContainer = collection; + // Iterate through the keyword document's collections and add a copy of the document to each collection + for (const doc of DocListCast(keywordCollection[DocData].docs)) { + const newEmbedding = Doc.MakeEmbedding(doc); + this._props.doc[DocData].data = new List([...DocListCast(this._props.doc[DocData].data), newEmbedding]); + newEmbedding.embedContainer = this._props.doc; + } + } else { + // Add this document to the keyword's collection of associated documents. + keywordCollection[DocData].docs = new List([...DocListCast(keywordCollection[DocData].docs), this._props.doc]); + + // Iterate through the keyword document's collections and add a copy of the document to each collection + for (const collection of DocListCast(keywordCollection.collections)) { + const newEmbedding = Doc.MakeEmbedding(this._props.doc); + collection[DocData].data = new List([...DocListCast(collection.data), newEmbedding]); + newEmbedding.embedContainer = collection; + } } + // Push the keyword to the document's keyword list field. + (this._props.doc![DocData].data_labels! as List).push(submittedLabel); + this._props.doc![DocData][`${submittedLabel}`] = true; this._currentInput = ''; // Clear the input box } }; @@ -223,9 +274,9 @@ export class KeywordBox extends ObservableReactComponent { if (SnappingManager.IsDragging || !(seldoc === this._props.doc) || !this._props.isEditing) { setTimeout( action(() => { - // if ((keywordsList as List).length === 0) { - // this._props.doc[DocData].showLabels = false; - // } + if ((keywordsList as List).length === 0) { + this._props.doc[DocData].showLabels = false; + } this.setToView(); }) ); @@ -237,59 +288,75 @@ export class KeywordBox extends ObservableReactComponent { ref={this.ref} style={{ transformOrigin: 'top left', + overflow: 'hidden', transform: `scale(${1 / this.currentScale})`, backgroundColor: this._props.isEditing ? Colors.LIGHT_GRAY : Colors.TRANSPARENT, borderColor: this._props.isEditing ? Colors.BLACK : Colors.TRANSPARENT, + maxWidth: `400px`, }}> -
- {(keywordsList as List).map(keyword => { - return ( - - ); - })} -
- {this._props.isEditing ? ( -
-
- { - e.key === 'Enter' ? this.submitLabel() : null; - e.stopPropagation(); - }} - type="text" - placeholder="Input keywords for document..." - aria-label="keyword-input" - className="keyword-input" - style={{ width: '100%', borderRadius: '5px' }} - /> -
-
- { - if ((keywordsList as List).length === 0) { - this._props.doc[DocData].showLabels = false; - } else { - this.setToView(); - } - }} - icon={'x'} - style={{ width: '4px' }} - /> -
+
+
+ {(keywordsList as List).map(keyword => { + return ; + })}
- ) : ( -
- )} + {this._props.isEditing ? ( +
+
+ { + e.key === 'Enter' ? this.submitLabel(this._currentInput) : null; + e.stopPropagation(); + }} + type="text" + placeholder="Input keywords for document..." + aria-label="keyword-input" + className="keyword-input" + style={{ width: '100%', borderRadius: '5px' }} + /> +
+ {Doc.ActiveDashboard?.myKeywordCollections ? ( +
+ {DocListCast(Doc.ActiveDashboard?.myKeywordCollections).map(doc => { + const keyword = StrCast(doc.title); + return ( +
+ ) : ( +
+ )} +
+ { + if ((keywordsList as List).length === 0) { + this._props.doc[DocData].showLabels = false; + } else { + this.setToView(); + } + }} + icon={'x'} + style={{ width: '4px' }} + /> +
+
+ ) : ( +
+ )} +
); } diff --git a/src/client/views/StyleProvider.scss b/src/client/views/StyleProvider.scss index 4267762aa..1d41697f5 100644 --- a/src/client/views/StyleProvider.scss +++ b/src/client/views/StyleProvider.scss @@ -77,14 +77,34 @@ align-items: center; } +.keyword-suggestions-box { + display: flex; + flex-wrap: wrap; + margin: auto; + align-self: center; + width: 90%; + border: 1px solid black; + border-radius: 2px; + margin-top: 8px; +} + +.keyword-suggestion { + cursor: pointer; + padding: 1px 1px; + margin: 2px 2px; + background-color: lightblue; + border: 1px solid black; + border-radius: 5px; + white-space: nowrap; + display: flex; + align-items: center; +} + .keyword-editing-box { margin-top: 8px; } .keyword-input-box { - // display: flex; - // align-items: center; - // align-content: center; margin: auto; align-self: center; width: 90%; -- cgit v1.2.3-70-g09d2 From 426411ca07db203857617f385b14697c4db2f163 Mon Sep 17 00:00:00 2001 From: IEatChili Date: Thu, 1 Aug 2024 14:29:21 -0400 Subject: feat: added groundwork for face recognition --- package-lock.json | 64 ++++++++++ package.json | 1 + src/client/views/Main.tsx | 2 + src/client/views/search/FaceRecognitionHandler.tsx | 86 +++++++++++++ src/server/public/models/age_gender_model-shard1 | Bin 0 -> 429708 bytes .../models/age_gender_model-weights_manifest.json | 1 + .../public/models/face_expression_model-shard1 | Bin 0 -> 329468 bytes .../face_expression_model-weights_manifest.json | 1 + .../public/models/face_landmark_68_model-shard1 | Bin 0 -> 356840 bytes .../face_landmark_68_model-weights_manifest.json | 1 + .../models/face_landmark_68_tiny_model-shard1 | Bin 0 -> 77224 bytes ...ce_landmark_68_tiny_model-weights_manifest.json | 1 + .../public/models/face_recognition_model-shard1 | Bin 0 -> 4194304 bytes .../public/models/face_recognition_model-shard2 | 6 + .../face_recognition_model-weights_manifest.json | 1 + src/server/public/models/mtcnn_model-shard1 | Bin 0 -> 1983400 bytes .../models/mtcnn_model-weights_manifest.json | 1 + .../public/models/ssd_mobilenetv1_model-shard1 | Bin 0 -> 4194304 bytes .../public/models/ssd_mobilenetv1_model-shard2 | 137 +++++++++++++++++++++ .../ssd_mobilenetv1_model-weights_manifest.json | 1 + .../public/models/tiny_face_detector_model-shard1 | Bin 0 -> 193321 bytes .../tiny_face_detector_model-weights_manifest.json | 1 + 22 files changed, 304 insertions(+) create mode 100644 src/client/views/search/FaceRecognitionHandler.tsx create mode 100644 src/server/public/models/age_gender_model-shard1 create mode 100644 src/server/public/models/age_gender_model-weights_manifest.json create mode 100644 src/server/public/models/face_expression_model-shard1 create mode 100644 src/server/public/models/face_expression_model-weights_manifest.json create mode 100644 src/server/public/models/face_landmark_68_model-shard1 create mode 100644 src/server/public/models/face_landmark_68_model-weights_manifest.json create mode 100644 src/server/public/models/face_landmark_68_tiny_model-shard1 create mode 100644 src/server/public/models/face_landmark_68_tiny_model-weights_manifest.json create mode 100644 src/server/public/models/face_recognition_model-shard1 create mode 100644 src/server/public/models/face_recognition_model-shard2 create mode 100644 src/server/public/models/face_recognition_model-weights_manifest.json create mode 100644 src/server/public/models/mtcnn_model-shard1 create mode 100644 src/server/public/models/mtcnn_model-weights_manifest.json create mode 100644 src/server/public/models/ssd_mobilenetv1_model-shard1 create mode 100644 src/server/public/models/ssd_mobilenetv1_model-shard2 create mode 100644 src/server/public/models/ssd_mobilenetv1_model-weights_manifest.json create mode 100644 src/server/public/models/tiny_face_detector_model-shard1 create mode 100644 src/server/public/models/tiny_face_detector_model-weights_manifest.json (limited to 'src') diff --git a/package-lock.json b/package-lock.json index 6cd2ab605..35b4b6238 100644 --- a/package-lock.json +++ b/package-lock.json @@ -101,6 +101,7 @@ "express-session": "^1.17.3", "express-validator": "^7.0.1", "extract-colors": "^4.0.2", + "face-api.js": "^0.22.2", "ffmpeg": "0.0.4", "file-loader": "^6.2.0", "file-saver": "^2.0.5", @@ -7084,6 +7085,30 @@ "node": ">=14.16" } }, + "node_modules/@tensorflow/tfjs-core": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@tensorflow/tfjs-core/-/tfjs-core-1.7.0.tgz", + "integrity": "sha512-uwQdiklNjqBnHPeseOdG0sGxrI3+d6lybaKu2+ou3ajVeKdPEwpWbgqA6iHjq1iylnOGkgkbbnQ6r2lwkiIIHw==", + "dependencies": { + "@types/offscreencanvas": "~2019.3.0", + "@types/seedrandom": "2.4.27", + "@types/webgl-ext": "0.0.30", + "@types/webgl2": "0.0.4", + "node-fetch": "~2.1.2", + "seedrandom": "2.4.3" + }, + "engines": { + "yarn": ">= 1.3.2" + } + }, + "node_modules/@tensorflow/tfjs-core/node_modules/node-fetch": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.1.2.tgz", + "integrity": "sha512-IHLHYskTc2arMYsHZH82PVX8CSKT5lzb7AXeyO06QnjGDKtkv+pv3mEki6S7reB/x1QPo+YPxQRNEVgR5V/w3Q==", + "engines": { + "node": "4.x || >=6.0.0" + } + }, "node_modules/@tokenizer/token": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/@tokenizer/token/-/token-0.3.0.tgz", @@ -9424,6 +9449,11 @@ "@types/node": "*" } }, + "node_modules/@types/offscreencanvas": { + "version": "2019.3.0", + "resolved": "https://registry.npmjs.org/@types/offscreencanvas/-/offscreencanvas-2019.3.0.tgz", + "integrity": "sha512-esIJx9bQg+QYF0ra8GnvfianIY8qWB0GBx54PK5Eps6m+xTj86KLavHv6qDhzKcu5UUOgNfJ2pWaIIV7TRUd9Q==" + }, "node_modules/@types/parse-json": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.2.tgz", @@ -9671,6 +9701,11 @@ "integrity": "sha512-WZLiwShhwLRmeV6zH+GkbOFT6Z6VklCItrDioxUnv+u4Ll+8vKeFySoFyK/0ctcRpOmwAicELfmys1sDc/Rw+A==", "optional": true }, + "node_modules/@types/seedrandom": { + "version": "2.4.27", + "resolved": "https://registry.npmjs.org/@types/seedrandom/-/seedrandom-2.4.27.tgz", + "integrity": "sha512-YvMLqFak/7rt//lPBtEHv3M4sRNA+HGxrhFZ+DQs9K2IkYJbNwVIb8avtJfhDiuaUBX/AW0jnjv48FV8h3u9bQ==" + }, "node_modules/@types/send": { "version": "0.17.4", "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.4.tgz", @@ -9786,6 +9821,16 @@ "resolved": "https://registry.npmjs.org/@types/web/-/web-0.0.147.tgz", "integrity": "sha512-HubXF+XiMsQBdwhMC9w1aZuSOZ6CvcBR01MA4UdQCbWABkcrSBbMGQ0VnqTJlEU1b78WCx8quv8pznnDXSiUtQ==" }, + "node_modules/@types/webgl-ext": { + "version": "0.0.30", + "resolved": "https://registry.npmjs.org/@types/webgl-ext/-/webgl-ext-0.0.30.tgz", + "integrity": "sha512-LKVgNmBxN0BbljJrVUwkxwRYqzsAEPcZOe6S2T6ZaBDIrFp0qu4FNlpc5sM1tGbXUYFgdVQIoeLk1Y1UoblyEg==" + }, + "node_modules/@types/webgl2": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/@types/webgl2/-/webgl2-0.0.4.tgz", + "integrity": "sha512-PACt1xdErJbMUOUweSrbVM7gSIYm1vTncW2hF6Os/EeWi6TXYAYMPp+8v6rzHmypE5gHrxaxZNXgMkJVIdZpHw==" + }, "node_modules/@types/webidl-conversions": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/@types/webidl-conversions/-/webidl-conversions-7.0.3.tgz", @@ -19377,6 +19422,20 @@ "node >=0.6.0" ] }, + "node_modules/face-api.js": { + "version": "0.22.2", + "resolved": "https://registry.npmjs.org/face-api.js/-/face-api.js-0.22.2.tgz", + "integrity": "sha512-9Bbv/yaBRTKCXjiDqzryeKhYxmgSjJ7ukvOvEBy6krA0Ah/vNBlsf7iBNfJljWiPA8Tys1/MnB3lyP2Hfmsuyw==", + "dependencies": { + "@tensorflow/tfjs-core": "1.7.0", + "tslib": "^1.11.1" + } + }, + "node_modules/face-api.js/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" + }, "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", @@ -37613,6 +37672,11 @@ "resolved": "https://registry.npmjs.org/section-iterator/-/section-iterator-2.0.0.tgz", "integrity": "sha512-xvTNwcbeDayXotnV32zLb3duQsP+4XosHpb/F+tu6VzEZFmIjzPdNk6/O+QOOx5XTh08KL2ufdXeCO33p380pQ==" }, + "node_modules/seedrandom": { + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/seedrandom/-/seedrandom-2.4.3.tgz", + "integrity": "sha512-2CkZ9Wn2dS4mMUWQaXLsOAfGD+irMlLEeSP3cMxpGbgyOOzJGFa+MWCOMTOCMyZinHRPxyOj/S/C57li/1to6Q==" + }, "node_modules/selderee": { "version": "0.11.0", "resolved": "https://registry.npmjs.org/selderee/-/selderee-0.11.0.tgz", diff --git a/package.json b/package.json index bbd2a4c46..019a1e308 100644 --- a/package.json +++ b/package.json @@ -186,6 +186,7 @@ "express-session": "^1.17.3", "express-validator": "^7.0.1", "extract-colors": "^4.0.2", + "face-api.js": "^0.22.2", "ffmpeg": "0.0.4", "file-loader": "^6.2.0", "file-saver": "^2.0.5", diff --git a/src/client/views/Main.tsx b/src/client/views/Main.tsx index 8242e7c27..ada934aea 100644 --- a/src/client/views/Main.tsx +++ b/src/client/views/Main.tsx @@ -61,6 +61,7 @@ import { ImportElementBox } from './nodes/importBox/ImportElementBox'; import { PresBox, PresElementBox } from './nodes/trails'; import { SearchBox } from './search/SearchBox'; import { ImageLabelBox } from './collections/collectionFreeForm/ImageLabelBox'; +import { FaceRecognitionHandler } from './search/FaceRecognitionHandler'; dotenv.config(); @@ -96,6 +97,7 @@ FieldLoader.ServerLoadStatus = { requested: 0, retrieved: 0, message: 'cache' }; new BranchingTrailManager({}); new PingManager(); new KeyManager(); + new FaceRecognitionHandler(); // initialize plugins and classes that require plugins CollectionDockingView.Init(TabDocView); diff --git a/src/client/views/search/FaceRecognitionHandler.tsx b/src/client/views/search/FaceRecognitionHandler.tsx new file mode 100644 index 000000000..86619b2d1 --- /dev/null +++ b/src/client/views/search/FaceRecognitionHandler.tsx @@ -0,0 +1,86 @@ +import * as faceapi from 'face-api.js'; +import { FaceMatcher, TinyFaceDetectorOptions } from 'face-api.js'; +import { Doc, DocListCast, NumListCast } from '../../../fields/Doc'; +import { DocData } from '../../../fields/DocSymbols'; +import { List } from '../../../fields/List'; +import { ObjectField } from '../../../fields/ObjectField'; +import { StrCast } from '../../../fields/Types'; + +export class FaceRecognitionHandler { + static _instance: FaceRecognitionHandler; + + constructor() { + FaceRecognitionHandler._instance = this; + this.loadModels(); + if (!Doc.ActiveDashboard![DocData].faceDocuments) { + Doc.ActiveDashboard![DocData].faceDocuments = new List(); + } + } + + async loadModels() { + const MODEL_URL = `/models`; + await faceapi.loadTinyFaceDetectorModel(MODEL_URL); + await faceapi.loadFaceLandmarkTinyModel(MODEL_URL); + await faceapi.loadFaceRecognitionModel(MODEL_URL); + } + + public static get Instance() { + return FaceRecognitionHandler._instance ?? new FaceRecognitionHandler(); + } + + public async findMatches(doc: Doc, imageURL: string) { + const img = await this.loadImage(imageURL); + + const fullFaceDescriptions = await faceapi.detectAllFaces(img, new TinyFaceDetectorOptions()).withFaceLandmarks(true).withFaceDescriptors(); + + fullFaceDescriptions.forEach(fd => { + const match = this.findMatch(fd.descriptor); + if (match) { + match[DocData].associatedDocs = new List([...DocListCast(match[DocData].associatedDocs), doc]); + match[DocData].faceDescriptors = new List>([...(match[DocData].faceDescriptors as List>), Array.from(fd.descriptor) as List]); + } else { + const newFaceDocument = new Doc(); + const converted_array = Array.from(fd.descriptor); + newFaceDocument[DocData].faceDescriptors = new List>(); + (newFaceDocument[DocData].faceDescriptors as List>).push(converted_array as List); + newFaceDocument[DocData].label = `Person ${DocListCast(Doc.ActiveDashboard![DocData].faceDocuments).length + 1}`; + newFaceDocument[DocData].associatedDocs = new List([doc]); + + Doc.ActiveDashboard![DocData].faceDocuments = new List([...DocListCast(Doc.ActiveDashboard![DocData].faceDocuments), newFaceDocument]); + } + }); + } + + private findMatch(cur_descriptor: Float32Array) { + if (DocListCast(Doc.ActiveDashboard![DocData].faceDocuments).length < 1) { + return null; + } + + const faceDescriptors: faceapi.LabeledFaceDescriptors[] = DocListCast(Doc.ActiveDashboard![DocData].faceDocuments).map(faceDocument => { + const float32Array = (faceDocument[DocData].faceDescriptors as List>).map(faceDescriptor => new Float32Array(Array.from(faceDescriptor))); + return new faceapi.LabeledFaceDescriptors(StrCast(faceDocument[DocData].label), float32Array); + }); + const faceMatcher = new FaceMatcher(faceDescriptors, 0.6); + const match = faceMatcher.findBestMatch(cur_descriptor); + + if (match.label == 'unknown') { + return null; + } else { + for (const doc of DocListCast(Doc.ActiveDashboard![DocData].faceDocuments)) { + if (doc[DocData].label === match.label) { + return doc; + } + } + } + } + + private loadImage = (src: string): Promise => { + return new Promise((resolve, reject) => { + const img = new Image(); + img.crossOrigin = 'anonymous'; + img.onload = () => resolve(img); + img.onerror = err => reject(err); + img.src = src; + }); + }; +} diff --git a/src/server/public/models/age_gender_model-shard1 b/src/server/public/models/age_gender_model-shard1 new file mode 100644 index 000000000..d942d6ad1 Binary files /dev/null and b/src/server/public/models/age_gender_model-shard1 differ diff --git a/src/server/public/models/age_gender_model-weights_manifest.json b/src/server/public/models/age_gender_model-weights_manifest.json new file mode 100644 index 000000000..ebc009ab8 --- /dev/null +++ b/src/server/public/models/age_gender_model-weights_manifest.json @@ -0,0 +1 @@ +[{"weights":[{"name":"entry_flow/conv_in/filters","shape":[3,3,3,32],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.005431825039433498,"min":-0.7441600304023892}},{"name":"entry_flow/conv_in/bias","shape":[32],"dtype":"float32"},{"name":"entry_flow/reduction_block_0/separable_conv0/depthwise_filter","shape":[3,3,32,1],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.005691980614381678,"min":-0.6090419257388395}},{"name":"entry_flow/reduction_block_0/separable_conv0/pointwise_filter","shape":[1,1,32,64],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.009089225881239947,"min":-1.1179747833925135}},{"name":"entry_flow/reduction_block_0/separable_conv0/bias","shape":[64],"dtype":"float32"},{"name":"entry_flow/reduction_block_0/separable_conv1/depthwise_filter","shape":[3,3,64,1],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.00683894624897078,"min":-0.8138346036275228}},{"name":"entry_flow/reduction_block_0/separable_conv1/pointwise_filter","shape":[1,1,64,64],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.011632566358528886,"min":-1.3028474321552352}},{"name":"entry_flow/reduction_block_0/separable_conv1/bias","shape":[64],"dtype":"float32"},{"name":"entry_flow/reduction_block_0/expansion_conv/filters","shape":[1,1,32,64],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.010254812240600587,"min":-0.9229331016540528}},{"name":"entry_flow/reduction_block_0/expansion_conv/bias","shape":[64],"dtype":"float32"},{"name":"entry_flow/reduction_block_1/separable_conv0/depthwise_filter","shape":[3,3,64,1],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.0052509616403018725,"min":-0.6406173201168285}},{"name":"entry_flow/reduction_block_1/separable_conv0/pointwise_filter","shape":[1,1,64,128],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.010788509424994973,"min":-1.4564487723743214}},{"name":"entry_flow/reduction_block_1/separable_conv0/bias","shape":[128],"dtype":"float32"},{"name":"entry_flow/reduction_block_1/separable_conv1/depthwise_filter","shape":[3,3,128,1],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.00553213918910307,"min":-0.7025816770160899}},{"name":"entry_flow/reduction_block_1/separable_conv1/pointwise_filter","shape":[1,1,128,128],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.013602388606351965,"min":-1.6186842441558837}},{"name":"entry_flow/reduction_block_1/separable_conv1/bias","shape":[128],"dtype":"float32"},{"name":"entry_flow/reduction_block_1/expansion_conv/filters","shape":[1,1,64,128],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.007571851038465313,"min":-1.158493208885193}},{"name":"entry_flow/reduction_block_1/expansion_conv/bias","shape":[128],"dtype":"float32"},{"name":"middle_flow/main_block_0/separable_conv0/depthwise_filter","shape":[3,3,128,1],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.005766328409606335,"min":-0.6688940955143349}},{"name":"middle_flow/main_block_0/separable_conv0/pointwise_filter","shape":[1,1,128,128],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.012136116214826995,"min":-1.5776951079275094}},{"name":"middle_flow/main_block_0/separable_conv0/bias","shape":[128],"dtype":"float32"},{"name":"middle_flow/main_block_0/separable_conv1/depthwise_filter","shape":[3,3,128,1],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.004314773222979377,"min":-0.5652352922102984}},{"name":"middle_flow/main_block_0/separable_conv1/pointwise_filter","shape":[1,1,128,128],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.01107162026798024,"min":-1.2400214700137868}},{"name":"middle_flow/main_block_0/separable_conv1/bias","shape":[128],"dtype":"float32"},{"name":"middle_flow/main_block_0/separable_conv2/depthwise_filter","shape":[3,3,128,1],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.0036451735917259667,"min":-0.4848080876995536}},{"name":"middle_flow/main_block_0/separable_conv2/pointwise_filter","shape":[1,1,128,128],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.008791744942758598,"min":-1.134135097615859}},{"name":"middle_flow/main_block_0/separable_conv2/bias","shape":[128],"dtype":"float32"},{"name":"middle_flow/main_block_1/separable_conv0/depthwise_filter","shape":[3,3,128,1],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.004915751896652521,"min":-0.6095532351849126}},{"name":"middle_flow/main_block_1/separable_conv0/pointwise_filter","shape":[1,1,128,128],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.010868691463096469,"min":-1.3368490499608656}},{"name":"middle_flow/main_block_1/separable_conv0/bias","shape":[128],"dtype":"float32"},{"name":"middle_flow/main_block_1/separable_conv1/depthwise_filter","shape":[3,3,128,1],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.005010117269029804,"min":-0.6012140722835765}},{"name":"middle_flow/main_block_1/separable_conv1/pointwise_filter","shape":[1,1,128,128],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.010311148213405235,"min":-1.3816938605963016}},{"name":"middle_flow/main_block_1/separable_conv1/bias","shape":[128],"dtype":"float32"},{"name":"middle_flow/main_block_1/separable_conv2/depthwise_filter","shape":[3,3,128,1],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.004911523706772748,"min":-0.7367285560159123}},{"name":"middle_flow/main_block_1/separable_conv2/pointwise_filter","shape":[1,1,128,128],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.008976466047997568,"min":-1.2207993825276693}},{"name":"middle_flow/main_block_1/separable_conv2/bias","shape":[128],"dtype":"float32"},{"name":"exit_flow/reduction_block/separable_conv0/depthwise_filter","shape":[3,3,128,1],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.005074804436926748,"min":-0.7104726211697447}},{"name":"exit_flow/reduction_block/separable_conv0/pointwise_filter","shape":[1,1,128,256],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.011453078307357489,"min":-1.4545409450344011}},{"name":"exit_flow/reduction_block/separable_conv0/bias","shape":[256],"dtype":"float32"},{"name":"exit_flow/reduction_block/separable_conv1/depthwise_filter","shape":[3,3,256,1],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.007741751390344957,"min":-1.1380374543807086}},{"name":"exit_flow/reduction_block/separable_conv1/pointwise_filter","shape":[1,1,256,256],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.011347713189966538,"min":-1.497898141075583}},{"name":"exit_flow/reduction_block/separable_conv1/bias","shape":[256],"dtype":"float32"},{"name":"exit_flow/reduction_block/expansion_conv/filters","shape":[1,1,128,256],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.006717281014311547,"min":-0.8329428457746318}},{"name":"exit_flow/reduction_block/expansion_conv/bias","shape":[256],"dtype":"float32"},{"name":"exit_flow/separable_conv/depthwise_filter","shape":[3,3,256,1],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.0027201742518181892,"min":-0.3237007359663645}},{"name":"exit_flow/separable_conv/pointwise_filter","shape":[1,1,256,512],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.010076364348916447,"min":-1.330080094056971}},{"name":"exit_flow/separable_conv/bias","shape":[512],"dtype":"float32"},{"name":"fc/age/weights","shape":[512,1],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.008674054987290326,"min":-1.2664120281443876}},{"name":"fc/age/bias","shape":[1],"dtype":"float32"},{"name":"fc/gender/weights","shape":[512,2],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.0029948226377075793,"min":-0.34140978069866407}},{"name":"fc/gender/bias","shape":[2],"dtype":"float32"}],"paths":["age_gender_model-shard1"]}] \ No newline at end of file diff --git a/src/server/public/models/face_expression_model-shard1 b/src/server/public/models/face_expression_model-shard1 new file mode 100644 index 000000000..619cdf6d4 Binary files /dev/null and b/src/server/public/models/face_expression_model-shard1 differ diff --git a/src/server/public/models/face_expression_model-weights_manifest.json b/src/server/public/models/face_expression_model-weights_manifest.json new file mode 100644 index 000000000..7b74b5ab4 --- /dev/null +++ b/src/server/public/models/face_expression_model-weights_manifest.json @@ -0,0 +1 @@ +[{"weights":[{"name":"dense0/conv0/filters","shape":[3,3,3,32],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.0057930146946626555,"min":-0.7125408074435067}},{"name":"dense0/conv0/bias","shape":[32],"dtype":"float32"},{"name":"dense0/conv1/depthwise_filter","shape":[3,3,32,1],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.006473719839956246,"min":-0.6408982641556684}},{"name":"dense0/conv1/pointwise_filter","shape":[1,1,32,32],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.010509579321917366,"min":-1.408283629136927}},{"name":"dense0/conv1/bias","shape":[32],"dtype":"float32"},{"name":"dense0/conv2/depthwise_filter","shape":[3,3,32,1],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.005666389652326995,"min":-0.7252978754978554}},{"name":"dense0/conv2/pointwise_filter","shape":[1,1,32,32],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.010316079270605948,"min":-1.1760330368490781}},{"name":"dense0/conv2/bias","shape":[32],"dtype":"float32"},{"name":"dense0/conv3/depthwise_filter","shape":[3,3,32,1],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.0063220320963392074,"min":-0.853474333005793}},{"name":"dense0/conv3/pointwise_filter","shape":[1,1,32,32],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.010322785377502442,"min":-1.4658355236053466}},{"name":"dense0/conv3/bias","shape":[32],"dtype":"float32"},{"name":"dense1/conv0/depthwise_filter","shape":[3,3,32,1],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.0042531527724920535,"min":-0.5741756242864272}},{"name":"dense1/conv0/pointwise_filter","shape":[1,1,32,64],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.010653339647779278,"min":-1.1825207009035}},{"name":"dense1/conv0/bias","shape":[64],"dtype":"float32"},{"name":"dense1/conv1/depthwise_filter","shape":[3,3,64,1],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.005166931012097527,"min":-0.6355325144879957}},{"name":"dense1/conv1/pointwise_filter","shape":[1,1,64,64],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.011478300188101974,"min":-1.3888743227603388}},{"name":"dense1/conv1/bias","shape":[64],"dtype":"float32"},{"name":"dense1/conv2/depthwise_filter","shape":[3,3,64,1],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.006144821410085641,"min":-0.8479853545918185}},{"name":"dense1/conv2/pointwise_filter","shape":[1,1,64,64],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.010541967317169788,"min":-1.3809977185492421}},{"name":"dense1/conv2/bias","shape":[64],"dtype":"float32"},{"name":"dense1/conv3/depthwise_filter","shape":[3,3,64,1],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.005769844849904378,"min":-0.686611537138621}},{"name":"dense1/conv3/pointwise_filter","shape":[1,1,64,64],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.010939095534530341,"min":-1.2689350820055196}},{"name":"dense1/conv3/bias","shape":[64],"dtype":"float32"},{"name":"dense2/conv0/depthwise_filter","shape":[3,3,64,1],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.0037769308277204924,"min":-0.40790852939381317}},{"name":"dense2/conv0/pointwise_filter","shape":[1,1,64,128],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.01188667194516051,"min":-1.4382873053644218}},{"name":"dense2/conv0/bias","shape":[128],"dtype":"float32"},{"name":"dense2/conv1/depthwise_filter","shape":[3,3,128,1],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.006497045825509464,"min":-0.8381189114907208}},{"name":"dense2/conv1/pointwise_filter","shape":[1,1,128,128],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.011632198913424622,"min":-1.3377028750438316}},{"name":"dense2/conv1/bias","shape":[128],"dtype":"float32"},{"name":"dense2/conv2/depthwise_filter","shape":[3,3,128,1],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.005947182225246056,"min":-0.7969224181829715}},{"name":"dense2/conv2/pointwise_filter","shape":[1,1,128,128],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.011436844339557722,"min":-1.4524792311238306}},{"name":"dense2/conv2/bias","shape":[128],"dtype":"float32"},{"name":"dense2/conv3/depthwise_filter","shape":[3,3,128,1],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.006665432686899222,"min":-0.8998334127313949}},{"name":"dense2/conv3/pointwise_filter","shape":[1,1,128,128],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.01283421422920975,"min":-1.642779421338848}},{"name":"dense2/conv3/bias","shape":[128],"dtype":"float32"},{"name":"dense3/conv0/depthwise_filter","shape":[3,3,128,1],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.004711699953266218,"min":-0.6737730933170692}},{"name":"dense3/conv0/pointwise_filter","shape":[1,1,128,256],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.010955964817720302,"min":-1.3914075318504784}},{"name":"dense3/conv0/bias","shape":[256],"dtype":"float32"},{"name":"dense3/conv1/depthwise_filter","shape":[3,3,256,1],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.00554193468654857,"min":-0.7149095745647656}},{"name":"dense3/conv1/pointwise_filter","shape":[1,1,256,256],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.016790372250126858,"min":-2.484975093018775}},{"name":"dense3/conv1/bias","shape":[256],"dtype":"float32"},{"name":"dense3/conv2/depthwise_filter","shape":[3,3,256,1],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.006361540626077091,"min":-0.8142772001378676}},{"name":"dense3/conv2/pointwise_filter","shape":[1,1,256,256],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.01777329678628959,"min":-1.7062364914838006}},{"name":"dense3/conv2/bias","shape":[256],"dtype":"float32"},{"name":"dense3/conv3/depthwise_filter","shape":[3,3,256,1],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.006900275922289082,"min":-0.8625344902861353}},{"name":"dense3/conv3/pointwise_filter","shape":[1,1,256,256],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.015449936717164282,"min":-1.9003422162112067}},{"name":"dense3/conv3/bias","shape":[256],"dtype":"float32"},{"name":"fc/weights","shape":[256,7],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.004834276554631252,"min":-0.7203072066400565}},{"name":"fc/bias","shape":[7],"dtype":"float32"}],"paths":["face_expression_model-shard1"]}] \ No newline at end of file diff --git a/src/server/public/models/face_landmark_68_model-shard1 b/src/server/public/models/face_landmark_68_model-shard1 new file mode 100644 index 000000000..fcaca474f Binary files /dev/null and b/src/server/public/models/face_landmark_68_model-shard1 differ diff --git a/src/server/public/models/face_landmark_68_model-weights_manifest.json b/src/server/public/models/face_landmark_68_model-weights_manifest.json new file mode 100644 index 000000000..0fe27075f --- /dev/null +++ b/src/server/public/models/face_landmark_68_model-weights_manifest.json @@ -0,0 +1 @@ +[{"weights":[{"name":"dense0/conv0/filters","shape":[3,3,3,32],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.004853619781194949,"min":-0.5872879935245888}},{"name":"dense0/conv0/bias","shape":[32],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.004396426443960153,"min":-0.7298067896973853}},{"name":"dense0/conv1/depthwise_filter","shape":[3,3,32,1],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.00635151559231328,"min":-0.5589333721235686}},{"name":"dense0/conv1/pointwise_filter","shape":[1,1,32,32],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.009354315552057004,"min":-1.2628325995276957}},{"name":"dense0/conv1/bias","shape":[32],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.0029380727048013726,"min":-0.5846764682554731}},{"name":"dense0/conv2/depthwise_filter","shape":[3,3,32,1],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.0049374802439820535,"min":-0.6171850304977566}},{"name":"dense0/conv2/pointwise_filter","shape":[1,1,32,32],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.009941946758943446,"min":-1.3421628124573652}},{"name":"dense0/conv2/bias","shape":[32],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.0030300481062309416,"min":-0.5272283704841838}},{"name":"dense0/conv3/depthwise_filter","shape":[3,3,32,1],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.005672684837790097,"min":-0.7431217137505026}},{"name":"dense0/conv3/pointwise_filter","shape":[1,1,32,32],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.010712201455060173,"min":-1.5639814124387852}},{"name":"dense0/conv3/bias","shape":[32],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.0030966934035806097,"min":-0.3839899820439956}},{"name":"dense1/conv0/depthwise_filter","shape":[3,3,32,1],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.0039155554537679636,"min":-0.48161332081345953}},{"name":"dense1/conv0/pointwise_filter","shape":[1,1,32,64],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.01023082966898002,"min":-1.094698774580862}},{"name":"dense1/conv0/bias","shape":[64],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.0027264176630506327,"min":-0.3871513081531898}},{"name":"dense1/conv1/depthwise_filter","shape":[3,3,64,1],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.004583378632863362,"min":-0.5454220573107401}},{"name":"dense1/conv1/pointwise_filter","shape":[1,1,64,64],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.00915846403907327,"min":-1.117332612766939}},{"name":"dense1/conv1/bias","shape":[64],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.003091680419211294,"min":-0.5966943209077797}},{"name":"dense1/conv2/depthwise_filter","shape":[3,3,64,1],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.005407439727409214,"min":-0.708374604290607}},{"name":"dense1/conv2/pointwise_filter","shape":[1,1,64,64],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.00946493943532308,"min":-1.2399070660273235}},{"name":"dense1/conv2/bias","shape":[64],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.004409168514550901,"min":-0.9788354102303}},{"name":"dense1/conv3/depthwise_filter","shape":[3,3,64,1],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.004478132958505668,"min":-0.6493292789833219}},{"name":"dense1/conv3/pointwise_filter","shape":[1,1,64,64],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.011063695888893277,"min":-1.2501976354449402}},{"name":"dense1/conv3/bias","shape":[64],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.003909627596537272,"min":-0.6646366914113363}},{"name":"dense2/conv0/depthwise_filter","shape":[3,3,64,1],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.003213915404151468,"min":-0.3374611174359041}},{"name":"dense2/conv0/pointwise_filter","shape":[1,1,64,128],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.010917326048308728,"min":-1.4520043644250609}},{"name":"dense2/conv0/bias","shape":[128],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.002800439152063108,"min":-0.38085972468058266}},{"name":"dense2/conv1/depthwise_filter","shape":[3,3,128,1],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.0050568851770139206,"min":-0.6927932692509071}},{"name":"dense2/conv1/pointwise_filter","shape":[1,1,128,128],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.01074961213504567,"min":-1.3222022926106174}},{"name":"dense2/conv1/bias","shape":[128],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.0030654204242369708,"min":-0.5487102559384177}},{"name":"dense2/conv2/depthwise_filter","shape":[3,3,128,1],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.00591809165244009,"min":-0.917304206128214}},{"name":"dense2/conv2/pointwise_filter","shape":[1,1,128,128],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.01092823346455892,"min":-1.366029183069865}},{"name":"dense2/conv2/bias","shape":[128],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.002681120470458386,"min":-0.36463238398234055}},{"name":"dense2/conv3/depthwise_filter","shape":[3,3,128,1],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.0048311497650894465,"min":-0.5797379718107336}},{"name":"dense2/conv3/pointwise_filter","shape":[1,1,128,128],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.011227761062921263,"min":-1.4483811771168429}},{"name":"dense2/conv3/bias","shape":[128],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.0034643323982463162,"min":-0.3360402426298927}},{"name":"dense3/conv0/depthwise_filter","shape":[3,3,128,1],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.003394978887894574,"min":-0.49227193874471326}},{"name":"dense3/conv0/pointwise_filter","shape":[1,1,128,256],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.010051267287310432,"min":-1.2765109454884247}},{"name":"dense3/conv0/bias","shape":[256],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.003142924752889895,"min":-0.4588670139219247}},{"name":"dense3/conv1/depthwise_filter","shape":[3,3,256,1],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.00448304671867221,"min":-0.5872791201460595}},{"name":"dense3/conv1/pointwise_filter","shape":[1,1,256,256],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.016063522357566685,"min":-2.3613377865623026}},{"name":"dense3/conv1/bias","shape":[256],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.00287135781026354,"min":-0.47664539650374765}},{"name":"dense3/conv2/depthwise_filter","shape":[3,3,256,1],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.006002906724518421,"min":-0.7923836876364315}},{"name":"dense3/conv2/pointwise_filter","shape":[1,1,256,256],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.017087187019048954,"min":-1.6061955797906016}},{"name":"dense3/conv2/bias","shape":[256],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.003124481205846749,"min":-0.46242321846531886}},{"name":"dense3/conv3/depthwise_filter","shape":[3,3,256,1],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.006576311588287353,"min":-1.0193282961845398}},{"name":"dense3/conv3/pointwise_filter","shape":[1,1,256,256],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.015590153955945782,"min":-1.99553970636106}},{"name":"dense3/conv3/bias","shape":[256],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.004453541601405424,"min":-0.6546706154065973}},{"name":"fc/weights","shape":[256,136],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.010417488509533453,"min":-1.500118345372817}},{"name":"fc/bias","shape":[136],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.0025084222648658005,"min":0.07683877646923065}}],"paths":["face_landmark_68_model-shard1"]}] \ No newline at end of file diff --git a/src/server/public/models/face_landmark_68_tiny_model-shard1 b/src/server/public/models/face_landmark_68_tiny_model-shard1 new file mode 100644 index 000000000..f04a9d5ec Binary files /dev/null and b/src/server/public/models/face_landmark_68_tiny_model-shard1 differ diff --git a/src/server/public/models/face_landmark_68_tiny_model-weights_manifest.json b/src/server/public/models/face_landmark_68_tiny_model-weights_manifest.json new file mode 100644 index 000000000..5dc790e48 --- /dev/null +++ b/src/server/public/models/face_landmark_68_tiny_model-weights_manifest.json @@ -0,0 +1 @@ +[{"weights":[{"name":"dense0/conv0/filters","shape":[3,3,3,32],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.008194216092427571,"min":-0.9423348506291708}},{"name":"dense0/conv0/bias","shape":[32],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.006839508168837603,"min":-0.8412595047670252}},{"name":"dense0/conv1/depthwise_filter","shape":[3,3,32,1],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.009194007106855804,"min":-1.2779669878529567}},{"name":"dense0/conv1/pointwise_filter","shape":[1,1,32,32],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.0036026100317637128,"min":-0.3170296827952067}},{"name":"dense0/conv1/bias","shape":[32],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.000740380117706224,"min":-0.06367269012273527}},{"name":"dense0/conv2/depthwise_filter","shape":[3,3,32,1],"dtype":"float32","quantization":{"dtype":"uint8","scale":1,"min":0}},{"name":"dense0/conv2/pointwise_filter","shape":[1,1,32,32],"dtype":"float32","quantization":{"dtype":"uint8","scale":1,"min":0}},{"name":"dense0/conv2/bias","shape":[32],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.0037702228508743585,"min":-0.6220867703942692}},{"name":"dense1/conv0/depthwise_filter","shape":[3,3,32,1],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.0033707996209462483,"min":-0.421349952618281}},{"name":"dense1/conv0/pointwise_filter","shape":[1,1,32,64],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.014611541991140328,"min":-1.8556658328748217}},{"name":"dense1/conv0/bias","shape":[64],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.002832523046755323,"min":-0.30307996600281956}},{"name":"dense1/conv1/depthwise_filter","shape":[3,3,64,1],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.006593170586754294,"min":-0.6329443763284123}},{"name":"dense1/conv1/pointwise_filter","shape":[1,1,64,64],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.012215249211180444,"min":-1.6001976466646382}},{"name":"dense1/conv1/bias","shape":[64],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.002384825547536214,"min":-0.3028728445370992}},{"name":"dense1/conv2/depthwise_filter","shape":[3,3,64,1],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.005859645441466687,"min":-0.7617539073906693}},{"name":"dense1/conv2/pointwise_filter","shape":[1,1,64,64],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.013121426806730382,"min":-1.7845140457153321}},{"name":"dense1/conv2/bias","shape":[64],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.0032247188044529336,"min":-0.46435950784122243}},{"name":"dense2/conv0/depthwise_filter","shape":[3,3,64,1],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.002659512618008782,"min":-0.32977956463308894}},{"name":"dense2/conv0/pointwise_filter","shape":[1,1,64,128],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.015499923743453681,"min":-1.9839902391620712}},{"name":"dense2/conv0/bias","shape":[128],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.0032450980999890497,"min":-0.522460794098237}},{"name":"dense2/conv1/depthwise_filter","shape":[3,3,128,1],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.005911862382701799,"min":-0.792189559282041}},{"name":"dense2/conv1/pointwise_filter","shape":[1,1,128,128],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.021025861478319356,"min":-2.2077154552235325}},{"name":"dense2/conv1/bias","shape":[128],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.00349616945958605,"min":-0.46149436866535865}},{"name":"dense2/conv2/depthwise_filter","shape":[3,3,128,1],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.008104994250278847,"min":-1.013124281284856}},{"name":"dense2/conv2/pointwise_filter","shape":[1,1,128,128],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.029337059282789044,"min":-3.5791212325002633}},{"name":"dense2/conv2/bias","shape":[128],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.0038808938334969913,"min":-0.4230174278511721}},{"name":"fc/weights","shape":[128,136],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.014016061670639936,"min":-1.8921683255363912}},{"name":"fc/bias","shape":[136],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.0029505149698724935,"min":0.088760145008564}}],"paths":["face_landmark_68_tiny_model-shard1"]}] \ No newline at end of file diff --git a/src/server/public/models/face_recognition_model-shard1 b/src/server/public/models/face_recognition_model-shard1 new file mode 100644 index 000000000..3d4b3017a Binary files /dev/null and b/src/server/public/models/face_recognition_model-shard1 differ diff --git a/src/server/public/models/face_recognition_model-shard2 b/src/server/public/models/face_recognition_model-shard2 new file mode 100644 index 000000000..8a4b5fbe2 --- /dev/null +++ b/src/server/public/models/face_recognition_model-shard2 @@ -0,0 +1,6 @@ +r^~~}pz|~v}yy||{r_{}~~|pxr؛uy|y~~}z|}v{jŖx{v~uq{sM|~Sh~oh~su~}g}~}sqxwz|w|yymzn}~~~z}~~lu~w|u~zdx~~}~uo}vr}|~{r~}}{}xy{{s~}~}znwy}}y}|v}y’p~}~ux}v~~qpzTut~۔~iq}v}vz|t{|}|ix~||}~}~v}|}wx|z~|y}y|{x|}}|{vx}w{zœ}uy|{z|zy{~z{||u~q~|u~~|{~||y~~|}}w}}}{sz~|hxד֛v|z{~~~~zqyxffecx|wsv|s}}yf{}qwvtox|}~{}z}{~rza|u{~w~}wwt{Ȍ~b~oyzywyz{{tfjuy~z~yUs~z|ݎxr~u|{r}wr~w|su{{h{x{~~ue}yz~v~{kzqt{{v}s~xz拗|ys}p|s{Pxvԉolowzc~{y~|ytz|~~}~{}vz|rv{|~jt[u{~ϧy}v~qu~{|~~|qy|w}|y}|mwxpzvtx|lxl|~~{ŏyxt{ov}|}}}}uov~szz~s~y~}~ɡz|z~}y}܍{}~v{vwytx|}rw~vy}~~zzu{|~~y|y}}}u}Γ‰~wj~rmya{||~r}}v~m~guqznz~v||w}v}}Ďpyc^|w}uxw}|ٜ{xx}coƖ2}t~_x|yxy~|v|wxryv~w{~|y~ʞx~trf}w}}v}|{y|wuzuy|{~wrzxi|zv}|zuuw|zr}z||}~{|z~|ut]|ck}}{w}wy}xz}~y{wxp}z~{x{}}u~~q~|~~}x~z}~|zwz~}}z}nwsj~~yt{}uv~}Yz{~{q{}~~~~|zz~~r~yzzzgsz}}~x~tkgp}{~}v|vt|{z{{{{u}}zu~~}e|vnwCC~];u~wtu}a~r|~{y|Ǔzy}ďw{z}~~{|z{ruzt|{{}}wruy}y{~u|zz}|}z|~~v{w~}u~{||‘}quy}||ydp}}}w}v{l~|d~{||z~t|~}Í}yu~xy~t|t{|~}yr{w}v{wxyȤy|vw}s|}{~sĕ}×|||Ó}^yuz}{s|c{r}ixzd~|zzizpv{}tz}Ȗ|{|}su~~u~~euu}yj|~}vwywy~|~}}}vt{zv}z}}wu}jbvkJusg:}z`ZnGcXFYb1x{y% +Ss@X6kzTpYuqDlUq2s]crv/N>bvb\#D9)BSZaOf@WiaUZ8[_`qwsyrkp|mvFZum^a=FpJdF$H_7Z]Bgy2bUf_c_ixs:VjBTJ9!"+O`f5)36Xfnp2h(  97ML>9V%R +lfE5')<7WSq:ci};NVQ*siMrHB;5W%]1Sd; VNGi4l+#c:`*jZAw0asD6a4^j!7c aq0=A#)[NZDX:N''HVM!=PF$3^:?0/T]\\ 1$%#z=6OM0N=8I9bQ",#OlnLV@CJ3A%: "|AQc&VjA1"%Qq8HM.<$AcA=[:%S~JftOj~*te?M(FK3|*@.@Q7w8+ *[>[4g~q_v`z/B2'~^9284lz*4P=?@nj {c}{~{{}||wzwtwx|}c~z{y~xu}|{~s~ysdxx}q{|s|rsqxzryx~vzx{~w|~ymty}z~zoyyr}z|~~osxuyhxu}~~m~njx|{~{nul}r~wzo~`niniowk|x}twstz|jtyap|q~z`ws]yy|sjv}z~y{|{zx{~txyxy|x~yv}|y}~zn|ry}~s~y|my~~}}xtuu|z}qnzy}}~wqx|u}~z||~xy|v~z~|~~vy{z{zvt{}q||y}~vw{x~pw{mn{xrouyu{vuj~v~yst||z}r}u{}|wm}h~{{}|{ukz|v{zzty}u~|~j~vs~r{s|zt}x~zywux{wv}{~zvyy~|zw}~uz{{~tx{}{lg~}~{{}trzoz~~uy{x{u||z~{}v{}~~gsxwt}|t|m}xyzwq~t}qszc|o|}vwvy~x}{~{zuozd}zno~cu~x~fk~|g|k{}zhwxsz{r|yymw|yw}j~ztp|{yt}~sy~~ux~m{o}||{|}oxz~uxop|~|~x|}xtx|w~sx{vxq}oz|}}}z{y}w|zzwx~mz~~{v|}tr~g|m~{vys}{z|}xpuwv~s}{}z~}x~rr|~|x~}|~}~uz~}~tx~~}}mq{hqrvvyokzhr}t{v{k|~~otU~}Yj}m{|ozosln}t{|sUdz{ayPqs_z|x}|xxlq{q~}~prs}}~|{wwvyx|}no}{v{pvt~~{qm|}y||{ltvvx}wy{y}~~t{x|z}w}v|v|}z|~xz~zyy{~|zmzqyxrxyppx~}z~wj~mux~{ry}yuwx|xho}t{||tyzwv||wy|{np}|v|~}}|{{ov}xn~}u||toy~v~z|r|tur}~w}un~{|szxx{y}mt}tvtu~s~|x~~{~vy|vu~{~}|lqy~}}|~|}}xs~}|ux~y{{s||}oqu~}}}|}v{rxv|~o}q~z{vw~|z~~~~ox|zt}ux{{qo{f}}w{|zn|}{hry{|}|tqqly|~txzryzyun~tuv~[szsx}{w}Zpzv~tr{|w}xyo~xxm{r~uw{xx~zw~{xyzzwwy|tuw~s|t{w~ztyz}w}|}y{{t}|~~|u~x}s~~}|~~|}{}vt{x}~w|~{w|zvt~sxm|zyxpw~yrxzv{|{z~x~|||s{}~}w}|zrwt}~zwysxtp}zz}|x}{w{{to~izvtorkmu~klTz}}|~]uqps}~x^|w~|~~syy|ux{}uvy~}}yioxs~{{|yvxnyu{tx}~to{z~x}|~{y~{zxst|y{~y~w}zzqz}pw|}tx}vywy~|}xy}~sqwy~y}~|wz{}xy}~{zrp~s}~w}}m}~|{us~|z~hku{y|w{z~zx~ti}{wz{wn{ym{p{~}y}zxx|}}z}w{yut}w~}xwx~{klvztuz{~y}|pxzw}|ru{||z}|s}swx||n~y~z{}|}pwus{|nk|~z}qt~wl}s~wzuss}je{~sj\zkfht~gnsteoysz{|zwm}\q}s~}zwx~zzu}||q{|t}v|~xwts~vx{s}{||t}||{}|{jzuxzzr}u~r}suv~l~q~|}}z}~noxyxwiw~~w~}ty}{}{vswx}}~rp~ysvx|{|ux|~{y}~ws~~}v|zyswl{~w~{v}wxw~r|}}xxpq~~}}y|x{s}ss|z~vxsozus~}tvylx{ou{r~}z|xww|pi}y|{y{wwvts|~|jy|ywvv}v{x~|}{}vzs~}w}w~u{{~wz~zy~}swx{}{y~tz{~~wt{{zwx~qq{vy}zw|~v}~vzy~vx}{~mozvyvt}j}zyuuv}z}gky}~~u{}}}tzq{zy~uw||iqxm|s|n|{}wvsf|o{{yt~v~~xzy|ym}~v~uy~xu~z|z~s|~vz~~~zs~||v~m}xgYzuh~dyzl|vg}rPo|ebkwxpz}~y{}|}}|uvys|sx}xz_iz{~zvwww|~wvxv{{||zr~sqzrx{nsru}xqj~{{}tw|x~qvslv~~sxu}||~x|~{|}kvnk}}}{}~uwvv|oyo|}}}vnvo|~xt}~{~mq{}~}}px~z}vy~}~|sx}n~}yx}~}zuvz~}~~vzx~}v{kp|wwq|{wtzzswyr}Yp|{}wpo~|w~qe|vzwyzr}toymt~{{uz{|xxwo}yhou}{r{xpw{}xwxxz}~}{|z|y~mxyvx}u}zy{uyyxz}uyvrz}~{{r{zuv{~tw}}~}pp~zxw{|x{}z{yu|t}}}xyn~x}|}y}v|g|q|zvys}~y{y~xyzp|w{y}~zzp}~xmv}n|xwmjjyt~{{~z|rn~{vnsw~xdg]vzbiryurylrZ~w{zq}oe|qu|y{yhkp~^{tut~vsvize[z}o|}|vlvfe~qtuwiwv}}~je~|k}wy~}qgx|u|p}r{|v}}u|y~rw~zxk~vv{|s}||{{}|~{|vxur|||x}~zywmwww}ty|oyqyz{uw}~|pumrg|}}zuvw|oyz}~}}~{zl|z}r{w}~~wz~zu~u}}p~}v{u{kzy~~umw{|~}|~}z}}}{~z~|oz{{~{{qypw{|}sy}|yr|w}xl}lozqj~v}{}}}|z~v~wyz~~~~}yw}|v|wy}yz{x|vwzUx~~|}}~wzv~zwuzuy~rq}|}zz~~nrtx|vu~{}~}q}|zpzzv~y}v|m{r{}{yyqvt|y{~~xUs}uxzyt|y|ut~~}y}o~vuxz~~}y}z{}z{p}x}~|~w~~w}|}~z~xy}}m{w|x~}h~}z|{|{{}{{zvvrv||x|||g}}o}y|}sz}ql~zx~qt}~usz}z|zp{y~xs}}}xz}vy}{y|~o|znr}||z{}yr|x~w}{sy~~us}}|p~i~~vt{|{|qwzyy~}}wru~y|t}zlhu|r~}ziw~}~~ywzvz}zuwxvpot~|~y|z~}nyvytzyv||v~{~|pi|z{vzss~l}{}u}u|{s~z~~y{q~~~~vukj{|{|wzs{vY}syyxys|}o|~qp|turyyu~|~|y~w}|w~wsq}}wy{vvrp{x{s|}zts|x{}o}|}~qz|w{}zu}zy{~~wy~{zt}p~p~~u{}i{u~|v}qz|}~n|o|n{yzxzx}z|z{r|ty}{||{pt~|v~{vyy~ulxy|}~y~xyrvtrkx~y}s{rtvjtcxixzut~yx{e||zpZo~{hor~Ʉn{izxx|nr|qzlhLj~zz}qpdu~~z~i{{}~uuxux}}~po~~}}~}z~~wv}y|~tw|ylpz|{yyu~{yx}w{yz|}w{w}}jw}w}{|wy~~xxvlyqz{{zosuu}q~{vx}sw|x{|x||~yr~{|wlzvz}{vzz{~f~||x{x~zhw~{z{{}kwk{}sw{yx~pzwt|}~~u}yyrvwx|}{vx|wz~qt}}{}q}w}tysx}~x||ux{rux~~qo}x}wvy}jy|ltp|{}|~xr|mw{gz{s{y|rgvqqw~mmuuR|z{y\y|oncrltreulmys{vwi|ss}pu\r{}x|}p}}yw}rxxyx{wuw}nx~{yr}{ytw~}||v}zt}}z}ui||{}{zx~~uww|qvzwv}vr}{{u}mpt}z}vv|}}x~}t|y~{z}yz}{z}}xz~yu~wtp}a|j}rtwusyz|b{sy{bć]tmy}z|v}x[}svxjs}Nvzpy}v~zjHWzuz`w`~rzvt|oxwyt|}X~rmvsr}tvowpɟ~y~rz~~s}i~}}}~huj}|k}|}{uv~~|nv}{s||{{vw|x~yroy{xr~~~}~y{~{vtwvy}|r~o||}~|w{x_v|~}zx{{ztzz~}~l|~{xky{}tx{r|}r|wyy}uwyttxy{~mpz{~y|uz}u|{w}t|cvv{xx}~~||yyozzxu||}{~xv}xwsp|~s~|y~y~vxr}~t|wzm}~}~~~ni~|~w}}~n~{rypz}pwoy~~{wzvx~{qxxtuw{~}vp~vzy~|}mnyy{~{|}{{x{quy{}rw}}js{w~x~~u{u{xz}u~ru{|tv|{|}|y{{|p~uzzz~qxvwxnp}|v}{mw}v~t}l~|||pwuw{jz|}~zzr|z~qw}u|tx{|p|p~|}~sz}{wxvq}pzww~}~rw|~yztwxxv|{}|mo}w~yvz}}v~~~}|}z|v}yu}yv|{t~~z|zp|w|{}v|ssr~~zvw{|zmzvw~|}z~r}ts~wrz~}~|rxv|xzl}~tyxw~i|{~w~{~ypuxt{}y{~x}zyvxx{~wx|}}}}|~zq~~p{~~shz}}w}}g{yxu}tq}~wn{izur}}{|g~v|v{y||}rtyrqi\vxt~wzix~qn{~{ypzv~rvv{}x}{~p{i|~}u{{|~}{pw}}~}q|qu}~xpvuq~~|{~rx~{zw}x}qypxuw|tz{r}{xp}rmto|j}{r|zx|wwt{s{{y}{nxzz|w}|z|qm}}|i~q{uvszz}yxyt}z|w{`}v|x}~x{~x|mv~vxxxvpo}y~lsZz~~~|qzy|y|j}zs}~wzv}{rys}n{c{vym{}~}np}|{nwz|ydd{xy|w{~x}rytx~op}|~}~{}|lez]}WVov}j}x{z~wsxsymy]bzqv|vr}~y|_\zkr}`cuitt}j||spsr}}}yz|~tx}}|}pvx}x}l|yyr|mw{|zvwo~}}|}{}~vx|}xz|wo|~ol~lx|}wz|}wysx~}}{}{|xwz|zrx|w}ntow|botxqy~s{zs`}~zuxs}|rkvlyz}twxcmugm~{u|uuw{{yz|||u|wssnz|~y}ywzxzy~}kt~}~x}qxm{np{ezmxx{s{xw}}zvuzunyv~wu{~oz|xrs~}ys|zz{y|u|vw|{wx{{}}~|mzos~g}~|x|wwtpj~~tq}z}{jnmzr|}qyf~||txqz|mxz~qiywwx}y~}vuzs{}{qwrx{v}}sur{vzy}|syu{ty~|zylw{{tzx{|}~w~{}xv}uv~x}~uzo|||sxy|~mz~|yy|~}vzu~~zuu~}}|z~yvzvz~ux{~}wx|pm|||q|zxwz|~ux{~}~p~~o}p}{z}pw~zwxz|sp}}u}yv|z}o~v{}v{vs|qloym{iuls}yzvltgzos_s|p`m|ym~yu{{q}y{{dt~vygy}v~yw|~~}}~}~{~~~|~~~s}}}|}|~uww}lyzxqyyv{~}x~|~z|yz}yu|v}~zwr|{{xyz}}x|t~{{r~{w}y{y{}x~}y}o||z{|xx{~}|~}|{~|~lv~z{~}z|}yx|w}o|~s{yy~uu{st{~}}xyvw|wz~vw}u{{|}m~{{w{kt~{yv~|~w{u{w~{{}m}s{{w|zz~}q~m{|w|wqw~{{|tu|~}{~~v|x{}zzx}xw{y~w~|u}y~p|s}|{zz{}}{|p{}{r}uw||zw~{~u}t|{~v{~~}~|x}~y~{ov~}~~~c~~u|vq~|wzw{~`yr|yhf}qmxz~t{}yy{tutrk~}uzq{wkxrwotjnmztaw~rvkaolqzLvr~ww}uo|k}yw|^fqqzrw~~{r~lrwv|{ezqz{vy||rw|{{vx{~{xyxy~|y|xz|}qw|{yxx~qp{~~zx~xxyxvy}|{qqy}|xx~~sz~zxtyz}~|pqw}u||}z|uw{|x}~ty}~}}}tp~{lwx}}wzm}u|{uztv|w{}v}zsuzvvpkdw|o[u|r{~{bruv|{v}zyjyxdy}~}|wvy|~yy|r|}zuy|w{wvz}ytye|r~~|}{v~uv~|~~x}}|xsz}lvs{|}{y{uywy||uyz}w{z}z}}{~y|v~~xzx}~vww{q~~|}Njwzv}{qxt}w|yxz{z}~vi|y~{|}zsw{yx{~x~x{~ty|yv}~yvz|~~}~}{}w~r~}~|x}|{zr|iutvtkzyujosvwmt~y~~|}|{mV|gvupjymv}p|yxupky|xyozmts~rpft}}v|{}w{y}y{zz{|upyvt{w~ycw}{zuzv~~v|wvz}z}p||ox~~t~zyx}t{z~v|v|~wxtrz}}yz}uzsxw|ux|}y}y||}~wyzxxx~~u}z~yze|w{y~z{rv|{tzw~{||z|{yvww~u{||||x~}pz~yz|}}~|nt}x{}w~}~{|x~{u{|rv}t~|n~}zyjttw}{w{~wk~zv}}}z}}~rm~ui~p|~}y{z|vz{~yu{y}~p}{{}y{z}~ohr}u~y{~wpz{||s}t|vt|~}ovuzxyrw~}|~u{~z~~|~v|w|r}}}~|~yx{}zn{{}~zuw}w{wi{xx|}u}zzzzzzw|}im|~~|||t}qvq|~|tw{z~~~yv~w|wxm}rzi|w|hnygzgtrywxtvsyyunzjpzcyg}t~Eyv6zyxvpnxss{qt}n{z{u}{vu~wu{t~|~|zw~}zyxt~z}x~lt~{~y~i{}~{|~}}z}~{|w|yw}y~z{xzvxztw}}zzp||}x}}||qo|~}z}~~}}~~ty|{{{~~{v|yux~~zuky{k|}{}vtx{w{z|z|~z~}{~~~uwt~}~|tv{sss|w|}r}}q}}~~zyyz{{vzw{yvqn{~z}zxy|}y{x~yw{~z}~z{v}~{|}}zpqwx~~}{{v~}w~yy|~}x~~zzy~|{y~vr}h{{z|gtslpsqeDbt@YqolUaxwl‰trD~nyyuvytW|{|qxrwyLsvuG~mgfqhgljdugayy|~sd}yn}}vxyev{x~~~~~}|{w}}{utwzu}z~{{vz|{|}{{wqvyrz{}|{{y|{nzvyc}}~}~u{{r|}~}}v}~|xpv|z}zq}~~~tz~~~|s~~~r~~z{v}~~|y~rz{|oxzt|x|mxxzxwr}~}|u~yytz~|qz~|wv|tr{x{u~jq{~}~w{|}uu|x~y}z}|}||x~ww~x{~wsulz{u}}kus|}wv||~wx~{|vv~|}x~zxtuwnxzwz~~|}}{v|~x{~}~}wzz|vs}p{~vzz|yi~tyu{~|iq||z}z}~|ntk~t~by}|~y|{v|{}w~wz|o~{{|zm~jy}rt~x|y{s~yw~xwzztyvvw{}}z}}nsy|q}|z}wv~{tz}}{|vwu~y||u}yy~z~{~u~u}pxp}z{}}x||o|w|{|~{{~{~y{x~{z|~}{{~ty~}~|}{r~p}w}z~u~}~~{v~y{uty~{vwssTze|vN~q|q}mvbkp}dgnoya~pvbx}wqnlzwu{|{w}|}x~}yu|q|x{v{|~}y~{yrv}~}xuo||xzvw{tux|q{sxptqvzz~www}yv~z|z}~znt}w~z}w||{{t{}upy~~}|y}~yyx{s{zop||w}yx}vy~|w{s}w}s|z|}~x}}}|x{{{ww}y{d|n|mxvx~}w~twd}u}x}{v|~~|{xv~~ve|xy}w|wunvxqv|}{i}kҋ~r{}sy~}o|~{t{xpxy|x|}i|}w|y|qw||y|~}x~|w|~xw~tz}}}~p{yozyz|~|~~~x{}x|~~xv|{~|~|zz}{{~ztwp{~}xzzz~x{yx{z{|}vytt}{sxzs|{|}|hq~~}}|ug{wy{wr|s}u~}~{y}vuq{|~~yx|y|}xuxv~|||~}r~~~pswrz|zyzz}t~}tu|~~}zzx}|}tqtzywu~m{w{~}~xs|y~y}~~~qpw~x~x||tz~~}x}r}wrwwz~{~yz~|~|s~{~yt{u~{~}~~~~vt~|v~j~~~y~xy|yy}vux}|z~}z}wv~{~}|~~|r~qz}}|y~twu{y{}v|}vy}u}}vn}wwuz}|x~zx~y}y}tv|{~~|uuz{}}u|uy|{w~vuz~|~{~}{w~Lv~}dr~txqytkprw~~mop~~y{~|qryuj_vukmz{xyrxv}y~w~ux~}{y~}y{}}~{yi{rxpwz}x|o}z}yzty|{y|{|vt{r|xwu~}{z}w|y|nz||y{|{z~o{}{~~|~~x|}|}w}u|z~zyt|v|{~{}uzuts~}zq|z|q{}a~^q~p~ozzqs|}wpui{vyq~}ms~|]~yt{xp|hynj|~~q`|~u~}z{~w{ju}v|x{}~}x~~~{q}~z~x~x~ny|~~u}}zywu|p}{yzxz~z{~v|||~u{zvx~|{v{}p|v{}|{sx}wv{|{x|y{y{~|}z~~{w~}wz}|}u~zx}}}~|}~~|{z~zvy}}ws}{suv}ty~x|}~yr~{zyvrpu}}|~~~{yy{~{}~{|q{}|zz}vsz~wwyrpv~v~}{~o|~}{||x~fuuj}~{~{~s~xw}lqzrwgu}fz{s~wv}y}wsx}ryux{u~|nzwzy}{w|wty}~vz~p|u{~zsvs}~w}{x~{}|~~||}|wt{~zr~~~y}x~|wz}{~}rqx{{|w{~v|z~z~z~}{~x}|~xsqw|}y|w{uu~yos~xv}||ylymuy|~{s~g~e~o}g{r^r}yenny|}~|r|t}qurn{zw}|ws}y~~u{~}xzu{xy{}x~m{{|~rz~x}xzz[{~{b|~q}{zw]yHwroz|qat~|]{~|wrwx~~qw~smtzyz~}|}|xx{yt~p|uzx}vupus}y{s~q|zqp~uyxpvq|xzvy|z~wu{{x}}{~{Sx}m}s~{y{quzvvzbyfszx|}yzruls|~~|~{{~}z{~vw~v|l~x~|xx`~{zxn|lu~|v{w~eys|~t{zuvn|pu}u}~w}~w{~xn~|{~~~w}~{t{|xt|uw}||s{{~{{|r{ty~}p{}glx_wy|u`ns}|}{vy}uq|}~vyv~~~w{}uys}}wxzsx}{qolypz{yi{~kyz{wvs|~m{|rzmuzu|zw~{x{r}~xqwzr|u}w{~xyuw}|uyv~rz}~~{x|xxzx~t~{~|{~u{z}}{~xwxxzs~{{{sw~~w~y{}x}{u~|~qx}~uzzr{vvzzyz~~~||{roxr}xw~{{tq~zsw}|~t}u~}xw|y{x{~|y|wt|y{}gq~}y}}~~zw}w|~|}z{}zy|||q{~z~tupjw~uxjynnY_~x~rbXhtzkqhqsbzdcyn}|i{qb{l}}{z{ij{sjurhi]kys}gxgvtnp}k~vh~usr~[x|}~{~~}~zyz~}~vuwzz{u}~ux}}vx{t~|~q~|o|~z~wxxt|q}r|z|wov{w{|qx{yoz|~wxpu{mzzz~~~|wq~}~~m}x}}osxxy}}|x{z{~wz||uzxqxx~t~~ywy~rt|~~y~~z|}~|zxy}t{k{x~{y|~z~x}}|{zy{~z~zw~v{z~~yv~y~u{ww~uwvsvx~|c}z{|io|z{yy||v}|}z{v~x{|~~wyt~x}~}~|}lwy}~~o}w~t~qzzpu|wp{~h~ywz{{wx{~z{~|}|ktuyp|{|yq|}wwotxwr~}zw}wy||{k{{w}qh|r|{vk|xzvpqzv}~y~v{svxz{{wqpfzxw{y}|}qyswv~~w~vy}{|w}~vw~{vrv{ym~|~~n~xz~r{x{~|}}~}~vwvysu~~~u}svyw~{v}}{tuq}mxst|ux}t~s~{sso}|wzuy~|sz{}xpyz}v~}zny}~tt|||{z~{yuqxz{~tmzw{yq||yzzsjo{onxxx}x~p~~~zx|}}w~}|y{g{kv|trn|y}zzy~s}|vewwosv}||}wt}}zbz|yx}}}z~{yq{vs~w|s{lx~xUnqvddq~k{|ʕ|_}upulw~vwsyksp}{{{uv~|||}w|vxvtt|~wlx|x|~|sl|Ynw{v~{u|~so|}p}yr}nztu{{wszyq|xg}wi{u|rk~{vesq~s~v|q~~}u~zxyw}yxwz}~}{{quy}usz~w~}vz}x||zzd~ty}|y{~w~w{~{~|}~~y{p~yzu}~susyv}~xv|xt{w}nq|~|vxx~|w~~juz||w}~{}vxqqy~ji{x{Wyx~x~~zlnt}Qwutiszt|~}xs|{x{zw|~xr{o{trmy|Z|xi}uzwtrsnussTxr}~}{s~[jh~~vvosv\syӋ}~ttzxmnw~lwuxq|qz~xw}yzs|}y}|||wwy~{~}{vw}~zylv{yrou~q||~}q||~wy~o}}~zzzxzxs|~v|||y{v}m}ou}s~x~v|xr~w|v~~zvx{yxy}{{}pmv~hyuy{}xzzx}|zy{w{z{}yzw}~|{otxx}}n~||~~}V{{hzwzpq}~{}tx|~t{}|}y|}{}{|s{zzs}srpwrzs|t{|p}|wyzxx{uyvwyujxxxx~gwz}vx~~~}br}qgwk{r{z|tp}|vytv}iyrx{~zv}y}z|}m{fzw~}y}~s}rs|zx}~||~mwz|~wxvstn|urxywvv~t~ls}usyy}|zr}xv{|w}u}xhy}zx{~{~|ntq|nw~}~}|z}~}y}~}vrwuql~uos}~psq{zno}u|qxi}ywusxsw{|~vqcxx[vdyz||Tzz|~qzy{~t~~wy}}}g~}~}}~ss}t}x|}{}tv~}z|uuvx~yy}u|w}z|{~||~{ty||rzyt||zr}owrz~z}}wss|~~~wvys{}{}q||}z~m~xy{|y}wtrz}{}|vry\|ky|{j~z~~{zu||ywy~ofxw{pw~||hx}yxw}x}}lxod~mx}{vjes~qx~}zk~~u~|rNJmwy~sqi~|Nqwmwsv>~uo~aytygzfpqa{yk\lpvul]~wl}f|z|fpk}}fgw~z~{|s}xy}zp~|r~q|y|}}}}~xoz|~u}sx|ox|euzy|xw{~xr|{~zyu}s~}py|w~sttv|uz~wv~{}x~}y~s|y}{}z}}~u{t}|}|~y}qtxz}u}zsr{||~~||~qw||z|{~w}||tu{w~}~ztxw}|}||zx~{{w}{w}y{~yrx||y}~{~zz{zx~xqypynxw|~t}|v{~zwrsv{~|v}~yz}y~}~~{wy|z~|p~}~{{~snt{xzr~wzx{wu~s|zuw~{sy~u{x|jzw~vlr}~}v}zrv~Z}|}tl|tywrvzs{}~v|y}{|uzry|z|}zztxw|vowup|z{vuxywzw|tl}l|~ty|zyxxt}o~||vx~sx}z|~x|r||z|v~~t|tmw{qz~vx~x}{r}}z{{vz|y||}ptqz~}}z}|z{x~xuqwszvUz|y}~|~yny}yv}z}~x{x~{m}wy}u{{|z{~w}{tvy~~x{~~}}rz}}z|~ztq{tw~~t~z||zxx~}vtwxx{z|z~wsz}x~}xv|}z}|vy|wlug{|qwx~v~v|}yy{{}~x~|w~~~slw|~}}zxw|~zx|~}{}~{}z~r}r~qyxxsx}~|u}~r~wv~pw~|q~u{t}ttjry|}vv~xv}}|u|{pz|}z{r|yzx~rvtznv~wx|y~~}v}}{}}o{u}~~w{}|p~}{}{w~y~~}~~zz}{~|}}~|~kx|{~jxz}tpw{rv|~|{w}|z|x~}r~wj}ywzx}wyy}{}{zx}|txz{zs}}~w{|~x~~y~}w~xt|prrvzrqvwo|}xnx}xuzvu~ntyw}y{ushvru|}xeb|vz~wn}z~}ez}uwwivy~~~k{v~}{}yr|ss~zyr{||||{j~x|}}z~{zv{~szy|~oyty~n||~y}}xt~zt~yvn{wx}y|}~~v|{|~{||}w}uyuwyny|gyw~so~}y~w}x|rluyt|t}u}tz~x|vuttwyr~yz~vyrp}zm{m~yoro{vt}q|~|~z}ymq|mqh|}vvr}rzx~r~z{{~}{xzZ{zv{{~wwtyy~s~~}xu}~}|utztwvvwot~v~wt|~qsxy~{zv{~zt~u}~vs|wztv~tw~znto}wnz|~z|w}uo{p{yt}qsu~yvjt|q{|{utyr|u||x~~|x}|}z|y~}vroxzny{zwzit{||wvuuyz}|p|}qpyx}{}~zu~xx}y|}{n|{|}yv|yz}~~zx~|{~z|{ryvy}r|~{}p}{i|~lw{zpuw|ozwz{ru|z~zwzz{xz~r}nzxzw}yposx{upv~|z}v~~~}}~{||~s~~xk{~~r}{v}u|{yy}|~o}rau{~wvl~pyh}y~uzx~xslv}}vs~~}yyvyyxy|Vl}|qnkb{f~yptv{ou|hw~v~zy{zx}nt|nr{{~vvuyz|w}yx~|vzv{}}|wwu~~{zu}}p{~yxvu~womww|}w{sxxvootvy~|suxuqh{z}|~|dzxzw{}{v}ryyzzyy|wyw~w}|zy{}x|v{~|yx}vvmvvzq|kuxvuxxt~zztwjyzwzt~v{ozuzvy~tv{x|}v{y~}rmt{zuy}w{}~wr~z}}yz{|xyv~|iz}z|}}{w|~xz|v~ov~|vu}z|}}{~y~z}w~yknzmyw{w}}s|vtvx}xx~wspy}}rx|s}mttw|x|xszuxw{|}}}yn{y|{rzz}~|xjjyxo|}}v}||~{{{~}}~vw|zt{{~{y~{w~}}{~~}}~zpw~}wz{vozv|y~wwwxyw~|ty|t~{wyu{y}{q~x|z~pmvz{{~}{||}|{suzss~~~tsq|}}}}|{~www~~|nrozzwy|}zvfzq}wquzmvvy||kpju~kzyus}y|{xqx{~yp}z{sq|}z}~pyyz|vtz}}{txvy|x}ya{ut{y~xyvyx~~|}~s~|}zrrynz~~~u|~}}ss{{~}zztwzzwzwt|sz}zv{}wryyxz~zzz{{vt|nv}x~||||q{vzpx{{x{~uo{nyz~~oyyx~zt~z~w}lzz~}}~}{mt{woywv~ly|~ttz}~}~{|vyt||}}py{{~vs{~~|~{{{|t}{z~yv}y|{xzr|qw{y~}{|xzuzyx|z{w}~}z{z~|||{trn{{}|x{~|mswvxz}~yu{z{~pxrt}~zz{p{{|v~s~}wuzx}}z|v}}q~x{|q]|{wjo{stlxy}y}|v~~v~{wx{}vz}zryzks|zu{~{z{{w|lyatwz}vzvizy|z~||z|y~~|{s{~|}}}||vty~|~zxu~|z{ou||||}zz}}~~yv~}{|w~|v~s{|y{~|y||zyw~pvy||y|{z~zz}~|{zzov~}}w~c~~~u|uq}|wzw{~^yr}zhf}q~mwz~t~}{|ug~~}W~xoz{|{rz{nxxjqc||sysyzwil{s~xuy||ptxmzW]l~y|n}}q|nz~r}wSnzr}{tlhyudVz|z|dw~xv|vz{xqvu|xy|w}wyyy|z~wyyy{}xyt~yyy~}zvmpu}y~|yxx|xy{wy~~|qqwx~sw~}~wwy}~~wyz|~upyrxstsxv{~~~~{}vwz~{}x~~uqwu}w{{rruu|rht{w}zh{yryluuy~vny~r}v|nzxml~y|~||~~tz~y}u{~rwz}t{x~r~~u~wqsutyy}wzx|vpw~y~}~flwzr|~p||ys|}xzu}~{jszz}||x{~y}q||ox}{~q{y|}~~wz|~vyx}|y}~k{vv~y}~k~ztz}}y~}zux|}}y~q}wy~uyyr~{{x{q}}||w{}zt}}}|xypw}~rvz}xw~~|p{zy~|y|txt|vpuv{o~~t}r}}||zx{py}tyx|{}ovy~}~}}v}~}}yz~~~p}}{{y~{||szГ|zk|z~}zuk{z_tjxu~}~x}z~zb}gpwv\qx{p~~`z~oyw~{_myjj||}z|}~}}w|xw|sv~}s~{~|{yt~~nx|}z~vw~w~uz|z}|v}xyfv|oyu|}~~zx|~z~~ww}~{|}}~}{z{v}t|}}yzxyxy{vzt{rv}{w|z{z~x~|txu|~y}|yzx}|wm}|}jwz}{~vynszguzt{vwx{qry}xy{r{|s}uyys~vxxx~wy~{}y~|~ypq~su|z|{w{y}|}zvyspzt~s|p}}{}~~yzzr|}~zv|y{wq{ztnz|}{xr~|rz{z}j~p|ty{}~q~}vsy{lyruy}x{suv~x}{~{v|uv||to|~zw~}~y{}tq{~y~}wv~~|xuzmz}sx}u|}{}y~nt{vo{m{}q~}w}wsu}{{}yz~}s|{y}}xsw|}y}|{~}|}z~w}x}wzu{opxy{~||~{~y~w~y}}~|vu~~}|syx}uvu~v~}x}zy~|{}s}y~}~~||~~~~zz}x~}|xw{n}w}xy|{}zz}}py{zwyy~}~rw}ltxzqxs|~x{|t}u||o~~upuz|}{w~vy}~z|~y~{v~{x~{yz}xz}|}u{}uxyu{r~ywmz}~xys|~{tuzy~{{}}y~{~}|}}~}|x}||w}~w~~~~~{~~|}yz}}}~~zw}{}~zz{v{|~y}~zv~}r~~}փ~}~}x|~z}r~z~lu|{k}vw{w}~yxq~v|}w}s}s~vws}~}x{|m{vuv~|}yzpzvruz~t}}n}ps|x{u~sg~~~}x}yzz~|t|}|l~{z{u~uz|qwuyyzq{{z|t|{{y}~|y|~}w|}v~|xz}yvx|}}w}~w}uyz~zz}~z|}zy}w~{vlwuypYs|yv~rq{y{xy{}{{{{}n}yv}kwr[{yy~~xyz~~}nyxz}it{tu|kw~tzxo{fpfsrux|}|~y{qxvtyT{|~lnwxzlrymw{~}|y{yyz{y|~~{|}}w}pq}|{~}q}z~|x~f}xwwq}}ux}t|ww{yy|z|yz}~wzwxvyxxxl|y|}y~|~~}u~uw{~yy~{o~urx|tuxtw|wz}~~p}xz~}z~~|yp~stt|w~~z{x~z}}z|}}~~zw}zz}yw}~~wrx~}{|x{~y|~{||}z{|uy}|wyzrr{}v~z||z{~~wrz~|{|}{{{~}x{uyzw}}}~}}~jv~|uzsqvo}|~zzws|twil}z}myuq}w{t~}s}yx}~}u|~|p|zx}z{~yyvs}s}|tux|y{_z{}yucj~zv}f}v|~x||zo{}zu~mq}|tc|~|bp{qyz~x~mror{z{z|yq}w}y}xu~}~~y~~w{~~}wx{|xrr~}}szwzxz||ywx{}zyx{}|}|wx~||v{xs}}~y|{ykw}{j|}wq{~krz{wk}v|uw~|dy}ix|x|u^j~vy|zzttz|w|v|}otz||}}z{}|ymy|yzm{v}|y}q|~xvwxyz|nr~|y}wx{y|x{||x{uv}}|w~w~}}~|~}|u~{uz{~{{|q}~y|}w~{~zw{~}x}}~}|{z{{tzrtrkr~{ro|}t}˅|~}irqvw|yl{tt~~{oysp||Yl~svluu{qvv|suwrui}}~~}whuvt{z~~}w}~||{}{s{w~z{|wwz{~~|zgx}|}t[xz}zz}vq~{~}w|{u||y|r}}}}t|{t~~rzuu{}{|y~vq~}v}}z~x~yp{~yz||n}m{{xurz}{x}|w|wqzw{xy{||}|vzs|o|{|ytyvz}~~y~}r|{s~x}}~x|}z~~v}}|v}~t{y~|{o~tw]S~~|tw}|Ys|{|u}~}oqVvzxt~x{}r_}n}t{~wy~}v]{V~nt}i}x:w|wz|t|ws}~yu|y}~w}ov}|h|wu}{~~|zvjlvqw~{z}|{z|{|wtw~t}{w~|sx~pxr|{q{}x||zz}|x|~z~|{}w|z}|~yz~|~~||v|t~{~|zz{~r~|~yzyz|||{tooxv~l~wczvtyv}|||lew|z~|~ywy~yynny~yxttz{xyut}{{x}|z~t|xtwjywx{x{spvs|~{w~~}}s}{zw}}zywu}~|}zr{~xyz~y{|~szuxxy}zxzt~~}|y{z}}z~||uyz}}~z{x~{{}zx~|wywz{}p}}rsy{u~d|}}zvz{zyzt{r}y}zkx{~x|p}z|sy}|y}z}wu~{}~|~~tyquw}|{y}wxvu~~}w|wxzz{yh{p~ou~}ywzx}~v|{u}{zw}u|{|~p}y~|xy}y{yu{~y|}||||z{~|}|z}xt~{z}t{~~}}w}huiuTxvvvf{zx~ujqtu{kovp\oskr}yjx}`vytlqvzi{eyxwY^~t~e_uuuyz}zsvwrx{~zz~u~~x|z~{y}e~mqv}w~p~{}S{~s{|vm{~z|}~stl}ps}sy}g}s{~|~y{}|}~z{}zx}}u}^{}}|su}~wzznws|z|t~~w}}~|wy{x|wwwup~|y|{}~~{i}~xwt}xo}x|mytrr|vxyy~m{wx}{|u|{{}}z{{|yr^w~u{}}y|t{{w}|zo}|m}~x}}}r~zyx{}xtwz|}mu|c|v{r|~v}o~y|y{u|~ot}uwt}|ut}{u{~y|prs~}x||~{|x~tx}}vs}l|u~|wwuxz|}{xwy~}~u}w~{~v||y~|}~}~{ystz|yp}zt~}{{|n|}~k|v}i}{y|vr}|~|vz~lx}psw{~uz|xmx{~}~~~~|}{|}z{zs}||~yw~s}}|{~{}uz~}t~{~zxqswxz}y}mz}{~|nyz}{|z}t{~~y~|||}~~z~tv|~~}z}||}~|sxw~v~{w~~}}|~s|vpXr}w~u{}w}j~|syzQ~{~z}}}~z}yrpwz{~|}vw|yy}}q~zmz||tw{|x{yz||x}r|x|yssyyvs}u}||yzr|}}zxv}zz~~y{xx}~x}}{xv~|xyyz}v}z}zy}~xwzu}x}v}}uz~wus}y}z}s~}{~~wvvy}{yu~x|}wuvxv|~x~vywvlk{mwyv{}}ryse|oz{|t~~izzeuic}x~tjsu|n|pr}a{}~nzytm}ty{yx~w~~xu|p}z|y{x}v|x~xxo{t{v~}uyt~zx}y}{z{oy||y|xzx~}~xx~u}{~x{sywx}}rn|xw|q}dp{ws}{~n|xou~}wv~~xzzvzxityo|z~jyuq{l}_}y~z|~{vw{tt{j~dz~|xtr~~qwxl|}}zvmk{zyw|w{|{n|yxxsu{vzqyzz}y~x{w{wvxdnrno|{jmasx|s{}r{oxzyo||xy}|szyz|}|y{z}huvqzo~{~z~{y|qz~v}{q~}xtw{}w~zkyyo~|~t|}|x{u}~sj}u{{y{vl|s}~{{zx}}x~x}xyw|}rlws{|}u~|y~y|}~~xs|~xs~{v}x~|vz}{}zt{z~wy~}z~nrxwyuxs{|~|qu}zv}t{op~tqnxnzs~z}xzs}{ll}rszvl~y|~y~x|Zz{uysz{{y|{}xt|t|wqvn|}}}{q~yxxw~yj}u^{qywz{y~zgw}kx|x{||z{|}{z~p}x|x}|~{w}vxv|}tzyw}~u|~x~}~|t~{}zrz~x~|}{}}z}z~}~xt~}|}z~x}}sxsy}~~q|~t}|s||{{yw|}xz|xt|z{}}~wxk{{~~z}w}~jw}zx{vzwtw{j~r}|~xyt~t|{u}~}u~z|{v~|{q~y~|}wz{~}|}}|~~|zpz~z~}uuwxzztuzww|ytvy|~n}yu~}ztv{wn~t|ztxfmvu{yvuzyywxqv|}v~dkynvy~}~}x~v|{~|~}|}}yz{v||z}{|~}~y~yx~~|}}w~yh}x{t{{||xn}zvz~xl{z{uoxyzz~|t|}|qrw|u|}{hz~zqq|zux~z~pvzu{~~pstvwzxp}x~s{{|sw||{}y{~{s~~pq{xxzx{wsz{ns|xq|~p~|}~xsw}}yzp|~m~{{vnk~||~y}|~~{z}~wzwxvxzywxorz}}}~x{zy{|~y{y|z}zzuxuxsxtu|w{~ssy}vzzt~ooy|jt}uru~y}|clour|u|mo||y}}wq}~ixox{}{z{xy|~zry}z{~i|ne}~~~v{ywr~txsq{}ww`|lyi|}~t{r|rsy|~|~xvk|t}~w}uxwwt}}pozxq|vz{w~}|tv{g~zlux{n}{w}~{unrz~|ty{{xs|rz{jym}{~~{yng_}wyxw~|xtv|sruzn~p|~nzz{vs{uuvw}tx}f~xuzm}xy{}zklzsu{r~yytskv~~syx|v}xqxpwq~|yt|}v|x~h{~vz||tzq|ryx|}qw|~x}y{{{rnwzs{||~yi~{p|~q~|~kv~ztxiwxxszuw}qz{mu~xysg}~}m~uzyywysrz{{y|{~~pzzi}rz~yryy|~~pxwjr}r~ztr}s~|{|xx}zs}|s{z~~vv|x|l{z|uy{pt{}y}srv~mo~}xxy~||{~y~t{zsfqw~xv|}}t~y{w{x{wv|y{|~zwq{{r~{o~s~|bpo}pHjmxc~}dsh{`uwq{~=v}yxl{xe{rl|}y{{}zzu}|yxt~|r}}~}{|~t{~{`zwxvv~|mamnvt~r{rwln^Kwczx|w~zz~|qypywt}oyszxwypkqzvj}gt~{y|wgx}{l}~~|f}x||r~ks}~~~xk~t}{zyswn}mzvyzr||}~~zw~{vxv~|wz{|w{zux~ur}|{}uectun{}}xq|}}tp|pz~uw{}{}yw~|~}{r}~||}~s{s}~{y|xx|vz}~|}{|~{{w|zy}}~zvxr{}yyruv~~}~z||vy~}~xwh}}|rw}v||yyx}xyzngq|zwzj|opz|ant{gkyZ{szou|}ru}q~wxqt}t|H{Thwh}vxqgsv}u|1u[su}{~|}sydv~o~kv}~ryrjyxZxzgy}|w~t{{~y|mzxq}y{{|zvv}w{u|z|}}~{x~ux{v|xz|w}~}~}y{~yvr~z}~}wz~z|njz{jmz~x~vys~lw~zylmx|ux|vh~{tvzw{~v{zwnzm~zn}}{jx}y}pwvzr~xx~|ww|x}~}|~u{}{}{}|s}ny{u{~myu~}z}nqrzp~u~skpsyonszklws|yrl{rw|}~tzxsvwsyxs}{~x}wuz{m}{{{zpt~{y{|~rz~tm~Z|uzgwsyvs}yzvlp}{}o~}||xwu|y~z{w}{|}}~wyv}|}xxr}|}}~{wz{ry}}}}tz~tql~||zs|i~pxz{z}tnrdx~ipyu~tpyo}ltm|uxrpmny~yl{|}wdzy}}i{||kxq}uq}wqpz|uzprqxvxssy|ry|rtny~w~q}v}}|x}t~}~r}|}}z}uto{t~~y~~u}o}|z|~pxvvs|rxtlr}|~qsvrxzwlno|qxyq|~~zowx}vz}{|y{~~~|r}w~|{|n~w}{t{}}}yz}}~y{zy~y{v|}}zwsxo~~w~|w{z~y~|{|~{||~xn~sssnzuqsu|z}yj}pwmswx~y}|ty{c|~to{z~u|y}|v\g|n~{hm~uvx|qs~ntbsxzw~~q~}{|sx~{}{}}ypux}v}xzrv}zxym~o}|u}u}}{z~|xz~r~|{zzzz|{y||nv}~}|z}p~~kz|wy{l{~~qy{x{spy{x|wl}}}}|~{{g~~{xz~w{s}{|}|{}s{~|}~{{|zsq}uwxlz|~~~qnzo|xrsz}h~{xy}jy|}ruv|w}~z~wcjcokygx}|nqu{z}}fvzvti}|{|z}wy{}|x|qw{s}zuz|{}~|u|}vtj}}~{{~|vzx{{v}~yyzw{zy~{}~}}{~}xx{}z}|}l{ts}ur{||||x|}{zztxzssqt{|hwtutzxy{zs~xwvy|}x}}t~{}nh}|}v~t}}}{}y{srzt{y~syyvux~n{n~|wx|w}wv{|rzw|{}{{o{}pu{{{|{x~z~x~{q}{~|v||}y||{}}~z}z|~}|~||qzuzty}|v}wwu{wxm}rtu~}w||vx|||yz}~}~}xyxzy~vur{{x~{|{|~~uy~{x~wus}wwyvzxyzz{wywqrw{w~zwmy~|}|z{~~vz~yx{~|xq~|vw~x~|{|uxy|r|w{||~s{w|{y~rxtqy{k||zrz}ttvry|vv{xvxx~st|~{~i}z|}yfquox|yzc~sry~x}y~|qqc~yxtoy}ktw}l{|ry{yuz|yx|wl~|zvxu{|}|~|m{~}xx|q{}|y~svostv{{voj}{{zw}}|o~u~|w{z{vv{|}~qu~yn}uzz}yo}uy|}z~yxziot~|zszs~xw~{||~~~rzsmsx}v}r}uyzv}i}v}~z~|x|~}z}~}u|ztz|~}{}|}|}~s}~~xxoxxnxjml~~~uv~uqr}vxy|txuYwwp|y|}s~nt~|{w~~r}z|v}x~~|xx~r|yyzzwy|{xv~{v}~~}|z{w~~u|~z{{||~{}|}us~|~x~x{u~{ys|yv{~x}yy~xj{}wp|}{}zz~{xzxt~xqy~{zy{vwz}zw{}u}~||y~}ytyyyxzx}z|vzzzx{xwox|~f~||s|~y~}w{uy}vz|}{~}|w~u{s|~u~z~}_}zzv{wrix{}~~xz|}{~z~rtwssnn~~yxz}zk}~wv}}v|{}y{|}}{x|~~tyu{{z|u{|~vr}}u||x|y~}~v}|||}}yzyp}~~g}|wx}z~~~|wt|}}y|ty~}}ju|vqwvyvxyr~}}}n|o|}s{vt~~|w|{|texhx|~|xwu~wymxzxx|}x|~}{~}}}xyzy{|{v~v~|{z|zw}zw~yt}|r~_zmuywuyyd{yitvlpozvb{r^y~q|}w}y{~yst{y{}z}{znvy~z~syvy~{{n}lnp~x~t~emr}xovprrid|jsq~|sxz|mw{}|{wv|zo~n~~~~s|uw~x}uv|||z}|~{w}y}}k}u{y~|{x}{x{~}|{su}rvz~z~zzw{~~|~~x~z~yyz||twy}{{sy|{|{z~~y}{tx{u~vz~}m}wxrt~}~~w|~{t}xyps~uvsyuz}xy|zz}|{}~q~~{||twzx~~}unwp~v~x|lwxwzuyyc{w|z}|x}qouzvwx}{|~~~r{}~w{|q~vy~~z{{~}|}oz\z{xxy|~w}}|s}r}zz|yzzyy~}}~}|{uux~yz~ztz~}ax}q}q}}r}|yxv}||w|xw{r{x~{v}v}y|xrlqzk~sYsx~zv]y~||wu{Wwtfz~vxuxvrr{y{|du|juvr}}|vqv}mxv{ywrwwyqsy{plylw}y}|yu}~v~}{}~z{|zuywwry\z|~g~eb}lvjmxxxzk|{z{}xz}yyWx}}yunxsxttz}vz|}u}~~zlzeusu|ywx|{x{e|vuu}{|xv~{xw}}s{lq{}syzp}|y{{~xozx{t{|r~~{~|z}|ur|w~~wyzwz{y}x{o~z~{}~{{{~xzultw{s}}~v{y}z|~wxu}z{t~}yzx{v|z~z|y{zqy{~uw}}}~{z{|~{}{qt}~v~u{}{}}w}~o~uwot}|p|Tym\}p{v{z{ppx}xrziwg}mtzosp{}hquu|~y|n~zxht{u|wqv{uyn{hyspo|swz|p{~uxxu}|x|z{x}}]yruz|||~xr{}y~wl~~zz||{~}vu||u~}wuy{{rzwxj}oun~{}{y}|oyxmos}{i|q{xzzys|m~|x}{~}t{|x|~{|uyxv}~qozyxzy{y~{~vwwy~~|{{~}zx|~x|z{z|u|o}}wv|txf{w{om}s}y~~|{|s~~p}p{yyV|w~|f~|~}m}kykz}}~xz~ovruf{oi}~u}{x|{zu|ekx{}}xx|}lxzs}{~|Txvwm{vt|zq}twuxur|ov~||x|xux{}wux~x}q|x}|uvvt~wx~xy}|p~|xwm|~putd|xu|w}yqsyquyvk~lz|zyqo}|wo~yyv~{|t~|ywzp}y{zsww|r{{}|{y}x}|tx~zt|wwzyrqxz{y||x}}ty}~xwytqxuz}}}l|zv{}}~ytyz|~{uz}s|~{y~~~~xw{||~y|zz~}}~r{~nzkwzz}sx||||{~y}~}{}{z~~|zyz{~wzyz|y}v~y~y~vzv|~}}}{yytzw}{{zwt}~{x{~{~{|~}}se{}}t~utuq~rpvc|}vum{||r~|mpt}{~ijqiyyvhy}w~}z}nno{moysy|knu~~~|qw|zt}|~{u{~}}~{z~|{}~yz|q}uu~|{~s|}|x}~~}tw}|pzo}z|w{x{yqv|~ytx}~z|tu}t~~tyu|||s|w~|}n}~u|tzu}z|z}xz~~y{vru|~xxyrvyyt|}~z{zuzzywzzx~o|~qwqt~~~rxu{uz|||xwtv|s|vrz|}}wwvsy~x}zxt}xxz^r~gtsyyy|xzb~xrw_~qutyzsqxy{t{~v~|~wrz}|zztz{yxxsup~zz}x||}~yt{uzzz}~|{|v{}xyxt~|{|~ps|r~us}uzx{}vw~~~}{xy~y~}y{zw{~wv}sx|}{}}xwy|v}z~t}t{z}}z|}zwt~u}vt}yj{}{uvqwrw{qur}}vy}~~||y~s}p~uusjw}wxuzz||ww}|rx|}wswtt|}y}xskv~zg|t|vy{wyyqtvuz{ww}|}v|u~x{yz{u~qxhixxk}vyvsnzj}~pz}y~}hyzq~x}}j~~|rzyu{~~u~wx~~|{y{|||~x|xy{||txyo~z{|v|xxvsvy~yy{~{|{{{jypr}~z}~o~~}v{wx}~yt|}}t|xx|~}x|~yu~xor|t}}rxzyw}{}|}|}z~x}|xq{~||xww}zzz|{~|y{xxznv}~}~{c~}}u|v}q}{wzw|}^xq|ygf}q}mxz~t]zs{Q|rvt|irpy~y~s|W}xos|~}|q{}vvv{|hzwox~|yz{o{{vwmvz|nxrs}rz~|~zyvw~ky~xopow|xys~~|xt}~}t}{y{lxyc~||ytz|~su|{y}tx}w~~x{vu{yx}w}wwtyz||ztv}|z~w~wz~w}w}}y}}wxz~zu{yx~x}{|w~{~r}{}~zxw~y}x}t}zw}~~w}w~φw{zw~x{~}~wrf~{w|q~~yx||~|~~uc{xzu|xw}yz{|ytrr~n|{qzh}o|~{wx|slzwz|xj|}|z|x}ywnvus{|~ytvzo~cj{vwo~uuw||ry|}{w~wlyxs|zy~wz~zzzxz~x}yx~|yw{vzu~}|hyswuv}p|frtn}wg|nz~{~xykm}ts}rzsz~xr~~v~}|}n}yzzz~~~zz~n}xy|~xl~xD}twr}}m}~}~{~~~}i{rq{usx~vkw~myyvhvu~yxrxznx}{lwvu~wxyzyxx{z~}nvybjxxjr|v~}y{|{p{pvrt{}|y||zxxtxx}wyuvzvmiqzru~ytw~w{|~}ts}uf{wwW~~}{~}xzw~p{z|tta^{zy~oy_p|v~|uvkbzq|ynzt{qgzly|lzt}~|w~|~y~~|yzxrqxtvzyx{tvw|{{y|yy}zx|{}{ywyui~||~{wuv~w~kxuvosus}x~~}~yxt||}|xs||w}|{}z~}zzr{w{{yy}vzx}|xvs}uyawx~mou~uz|{x~py}{wyz}py|~~|twq}~y|s|rl{~}w~vyp~}|~zx||~q~xuv~xnt{~~y{tyvlo{osyv}|szw}yyrwnv{v~tu~||{sw}zy~w~zuxws~wr||~{v|xy{|~uyz|w|i}wwx}txv{~}{~mwzxwytw~|m~{|{yp|u}wt~~vzn|~~}{{mw{c|qgryu~}~v{|r|y|{|zy}w}~|~}}wp}}xvu}~zx}~{y}w~~{~{~{xyw~{|sxzsw{|~~~ts{}tmqy|wyqyv~}zvn}}}zzrwv~u{w{}v{otyq~{rzz|fmQaz|~v{|}~w}xwz}uxlymz}tu}sz}|qsp{|s}{xhlr~~v}opxtqwzvpmz}roxz{~ywu|zrzy}~z~zzvssp|yyqwqzszy~rztux|~}}xw}vzs|{zzvy~}y~~~~}~~xyy~{vwz{vonntu~s|~|{xs~~pzu~~x|~|~|}{{{|zy}|}xsxzqu~n~q|nw}ry}p{y{tuvzxu~{wu~}w~u~{~}ts~x~s}||}}~~{}~~|~|||yjqyu~{{tzyp|z|smozu~}~xq~pzm|v}mp~|w}}~}~~}}~}yx~|}vzzy}|~w|ss}vul|~wumsu~}ww|yzwxuxyo}z|x|z~w~qdqwzywl|sxxkgc}~nqywrqyZnvwx~~{kusviwuquwk~zek}uszuw{c}{z}y{}xmxzzzuw~n|{}}z}z~o}s|z|oznursz~ywzx~|{w}~xl|{|}u{s~|~~}}}|znzzpsq|rsuyw|}wsztuuyvu}tyyqxvxs~{}x|z~u}}{}z{~}|}~}}~|~zzx|w~xy{z|}~{y}y}t|y~w|v|z~{~~yz~~y}~}x~o~ur|zwxvo|zq|s}ruy}|qw~t}zvy|wp}z|~{~zx{~zprzyxt{nqrwvu}|~vp}yy~||zu}{p~~yur}|~u|y~}vp~s|u{{y}zxtz~}x}~|{|z{~yqxx||syy}~zwq~~}s||~~}|~}xz~{tux~}s{l|rouso|x~vuw~txxtyw}{zwlny~owv|~}}{{}tss{zz~l|}~~xl}u~{~|xuyq}~{{}{w{w~|vtq{}{s}yxrwuvxv|vzu}}{|{~|~w}xuvy}u{i~z|u{}x}twurttz{mqvz}~~zzpx|t||z~zvyrzw{~}{|}ruy{wrp~vxnt~vy|w~y~~v|t}|qr~{}{{v}}xt|{stpmotsyn}y{xvu{ytp~zzztyzrjbqwsw_c}yhp}~z|y|ltv}xlz{ww~|my{s}h{~wyzkwvulv}xkt}s}sooz}{}iy\{vyt{{x~}z~}~vyxw}}}|~{vyw~ryw~u|}}}xrtxuw}~utzx~qwyhu|}zmvu}{t{{q}wzz|z}o}{t~zz{}pry|}{o~v~~~}ozy}ux{xry~}z~yu~y}~~xr~}v}q~}t{}w||}~{q|juv{v{{s}~~}}w~yu}}|~yzl{um{~}g||}xtkx|}~{{y~|~}z|x~|}ztjprur|lvyx}wy~zvwtq~tow~{}qvuT|}~ouzom~|~zu~|v||y{}{{~|{||z{ryrrpununzq~v{~~r}tx}rvwx}wrz|x}}{wzxtr~totq}sqwr~~wv}t{}w|w~}tzxwoz{yyx{y||x}|xz|}yxwx}|~|u~{}}~wr}~~u|{~~||yzy{vrt~sxyxqz~{otv~yy||yy~{}|~u}xyt{zx}u}w~wr|r|yvptv|uqyuy|}|}|r||utro~}lx}x{|zpz|u|}||{{}}}xn}}v|zrum}~wzo|{ke{t}t}~{xzz}yx~uxz~|yyv{z~t{zt|sw{|xs~u~|x}{w}~}wy~{xr||ys~uz{w~xtvww|v}ts}|}}rxt|v~zsvqx~X}||~~~nw{|q||}}|zz}|yx|{w||{z{z}~yq}{x{z}s{z|~{}zHO~wx~txwyveez}|}{suwx}{m~xrwxtv|le{t}mfkgylgf}zolqsfuu}}w~w|xpz[qrxyt}x}~||~~|zzzw}s}~|u~x{{qzw}vr~s~}xzpvxwyw~~z~{}owzvvu|zw~~ozt~zy}yt}wt~~|{v}pz~}|~kzw}ox|}}}v~sqw~~zvzz}z~}{}|~xszu}wqmppt|}q~y|||~t}zt|pox{zvw{w{v~yzw}x|u{||{}y}qwx|~{w}}}{{y||~xxy{}~uxxs|tqquv~zw{z}}~~zpwy}{||rp}xt~{|~}|~}{y}xry{yztu}qurwzt}~tvy~{r~|q~{gsw|y~{rtt{t}x}o}|{pnxytx{}yt{~y{tnvf~yqxz}|twk{}z~u}||~{}~s{~|xw||~}}~{{x}v|}o~||y~}yt~xvzt~~yosv|w{|~xvwx}~twssvw{y|~vp~{ou||xyzt{~os}rxz~s~}ptys}{zwz}m~xws{{yu~~}zy}}v|~vujwt}z`w|xdizsw}vhk~rwqsmutptiztuwtxn{uyp~wzkowcqvy|zsv~h}t|x{vvyopr~}t|zj~}yz{yzktyvwwzyzu~||zxx}x|}wo~{{}x~y~|~~zt{~y|}ewqmmoztk~}lwszp|r~~|yuvk`ttj{lx}{o~vwqzcoeq}{pszzlysrz{htf_}o{\{|hwmockvy|~~~qztox|zz{o{qz}m|i|~~|{sy~zu{f}~|mńm~~n~~ztvpo{r}zw}|vr|x~v{}qlx{y}{{}~~w}xur{vnyxzk~}~wnyu}{~zrt}qq{v{{y~uyz|u~y~xz|~|kz{|~y~u~~~{{~w~v|~{~~zxx{z|{u~yrysrpvvrystzz~{}wyz{zp~~}}m~xq}|{u~~zw}|~|w{~~}|xzwuz~~|x}}xzkpu~jv{on|yn}yjxkr5l|~~{y{uwznx|{n}ixwot~tsu|{y}srx~y~}}{}}y|~~~{wwztttxx}~}z}~qywwto~u}ro}~uy}ozvwz|}~yz|{}|y~~y|}~~yzwt|zrqtwz|r|xz|{u~|}{~m~wwgxy|zzuvqvvzp~{{zlwu~{wz|wwx~|}s~}|rqz}|r|rzv|vtvu}{|xt{q{r~|vz}}vy~~{{r~{~}~||~ssymrvxrvz|uxg{~etwytv~{{uy}xlnwpxwyrz|{rzz{}~|~sw~|{{xt~~v~q~~|~~{u}}z}sqx}`~n|i}}u}gU}\fry~|tqr{}~qlplu}~}r|oodOrx}wgensy{zp҇~z{zw|v{w\ux|q_cb~n}nuzkh}zspmiz`}u^}yz~gezq~}qn{ttk{zru}~||~xy}|z{k~|v}tyw|{u|glnv}pq{vxyqtx}zwtwmv|z}r{yyv|vu{wxt{k~{}{~|qyzvr}sy}{nwx{|w{vlw|{r~~}~x]w{{xxz{u~|}wr{yx~~tzzosnrqguz{~rqyrz|gx{shqv~mk|wtsv||{{yskvo}ytx}xz~ydyyyuy~{z~~txvm{|{x|qx|t~rsuy~u|wt}vu~}v~|}sm{snztvg||kx}|zqn{~|w{}tyqg}}}qtqv}||x}~{zz~y|q~p~~x{}y~z{}~z{}y~qy}vzzyu~{{ty}}x|}r{tlmr|}nyu}Mw|~twz}}x}l|orzxw|{|t~wx}zuov~~~{x~ys||{esysr{y|u}~}otuwwu}sxt|rx{kt}zrrq{~~sv}s~usty{}~{|{y{|{v}}~{}x{zzx{qztfw{x~~y~}t|{sxy|~suy|uzz~z~~zv||w}xx{~~c~y|z{z{{y|x~u|zw|xrot~s~}vx~~v~yt}w}~{~{{{zypxy{}ujxsuiks}vz}~{y~z}{z{qx}y{}t|zx|f{vq~|~h}{zsv~y|yty~u}w~{u~|zy~|o}~txxxt|~vzs}tx{xr}q{{wt}sozy|ru~{{zt{}yvyzzss~lzrm}~t|{yu~}xy~~t{{|~q~~wt}wx}~~zz|z}~{}ywqyv|t~z}}~z~||~{y|}yszu{zp{oss|w~s|xzs{y{z}z}~w{|py}|}z{}pw}xz|jvxo~wr>yvpr~s{}Uxpzxy~rn}vt{~yyys{xzttnxuiwf~|qvX~mv~nutRyvz~zx~rx~{}qsmo}~~z{zs}v{tWxty}vyt{zs}uv{t{vuvrx{~|v}xz~~||~~~x~vq}~|u{}}{}~yrx{wy~x}|~y|}xyxyszrxx}yssxptvnrvy||{yosrvr|}~}q~szz}x}w}zxyst}wr~~{}{{v|{~|}~uqt~~}w|}|~|vww~uvr~v~~}rww}~vntuwx{xysk}x{{|{r}zu~w{~}uxqzxz}}{we~jyxrx~v}zqjy~|n{{z|yzowm}}~zttn{}q{zpl||tvpun}rriwsozzru}vvu{~}kzzj{}ux|ith|j{|y}tzxk~|pXj|zhpr~Ņ~n{ujy~zwko{pwlTLk}{zz}xkewuz~}u}{~~}}s~yu|qv}y~muour~}uz~p{szywz}y}l{t||~~r}w}|}~w{z|}xv{vq~vv}uo~lutz{zux|{~xvz}x|{{|{x{s}p}~}tp|r}~v}}}v}~~||}wr|}|v}|{~~wrz|}v}~xy}~|||ss}z||{w}}}~z}x~qwy{||{~zxwv~~}kx{o|{z~uxzx|}{~u{y~|z|v}{~wq|z}w~u|~~|}{~~utz{n}vyu}~|s}}x}}wxt}~y~{{{}y|u}{r{u|~xy~|~y~~{|wtp{x{t{u~|xovwrx|wt}twtzg|}~xz{z}~n~lrn}vkxy{r|qx~zsyz}v}zzv{{~|yn~vrz{|st{}tt}x{~}z|zzz~}uxur|yxln}qxrwqx}sy||{}q}}p|vyzryuus~w~{x|yy|~{|v|wjsl~uuv}w{}nvwo{ntjaguyw{~wryd_ofy}kssx~zzrzv~x}{vlxzr|}{u{|z~}~~~i~v~yv|}yz}|vx~~y}w|~vy~zu~xw{z}~~}x~}}yy}}{}~{|ys|k~{t~yz}zy}||{|||q}y~|ux~qr}{x~qm||k|~z}|~xx}}x~{~}}xy~w||y{v}}v~w}{|}|yt{|~{|x}zy{wz|x}z~yiv{gu{aSpsn{{yqE{zaxws|wzjw^~wszt{tzvukq]tumpUfhufkoowzujyxzylpwyuxe{tfzx|gq\}~rqb{qfr}{ymVaoikywxu|vw}owzv|w{teu{zrr|t|~swmzxv}x||tp|pyryz}ryy{xv|v~x~supmyxy~~~k~}~}~{~{|qrw}}zu{}y~xrp|m~|}v|{{}ywy{}ts~~~r~{|~~x}w}u{z{sss~}}|yrwruqvz~~~~u~}{~wvwt|~vp{}s~r{xx~ur|{|oxzl{xpx{{uitzs|~vyn|{n|x|{qsw{~wy}~~ruwp~xk}x}~|z}v~||x}||~qsqsrt}{{o}q|y~y}~}~sw{z}yzvz||vz}zq|}|~x~sr{}yr~~wq}{u|}yz}z|yyv~e~zw~~}~o~zq|y~}v|}}yuqw{~|||}y~~xqzuxuob~|y}uz~zy}wyv~{y~}|x|~|sw|r~||yuzzx|yyvys{rr{{{x~vu{uwu}qzxzui~{|~o}}zv~wv{~s}uqt{|nwzy}wu{uy}z}~xpz}}xxx~ouy{wzu}t|kz}{wo}wz~|y|}~~|}w{~~~xzq~y|~zmzqzuxzyv}{u|{uz~~{|~z}i}}}u~~sow|zuy~~||~x{}p{tz}t|z{xr{}y|~}yozxxqskz~n{svn}~w~sy|}}xwy~~x{w~vz~wvw~vzusryptv~~}s{||{rz}oyqvttwxu~vzz~k~}xo~tzwpojy~[~x|{tyys{{{xxz}yt}xsw{zz~p}}|mxu{yt}u~xzuz~~}~z}~xsyzzn~{{sy~q|qxu~~xtvpovt|xx|z}}p~{}s}}{xy}yyo}us|ozlzvq~r}v||}z|r~p~{x}~wzuvtxq{y|{vq|uz}v{w~z}{x}ujzz|||vxy~|z|ux|zp{|~~v}}ymz}ru}r}|~w~|uyp|j{ww~~vy}{xz{~xezw~s}{qy|yt{{zwtz}{{}}v|v}r|v{wwwvt~s}x{|wm}~yywuu|}ovvx{~oqstywrr~qysttx}nz}~v}ru~}{}|yxpwz~|z{~{vsu~|ps|nxu{y|y~x~x}u|xoyxt~o}yp|}~yuxxz{tt|{|}}{v{sw|ws}{~vvf~ywkv~j~w|~|xwusizts{p{wx{{|xd~ouszz|}~xrhovo|txnww|{~{~x}{ypxpx~|~p}}y||z|}}~}~w|ywrsq}}y{qyz|lr}~{s~}x~{yw}x|t|xzzq~uosu|xt{{}}z}~}|q|yunz{jrj}pxpxysy}yqlu~zz}{||yxx}m|~voxw~q~|trpn|ww|wopwmv}z~u|srzxpuq{xvos{tsvp|}x||ra}wp~m}{s{}}|z~x}}{}~~|}{vq{}v|}}}~|}}}v}}{{z~}svys|~vtmqrs|r|xvwzw|}o}}}sv}y~|x~||wr}{~|u}~~|}{~~zq~{zv{{|k}m|}~vz}}~t{v|v~{}{|{h}z{t~r|yt{xuz}rurz}}y~~{y~vyuy{ur~xnxuwzt{|ztv{xyu|y}||x}y{qc}`xYXopzm}|yu~{ws|zqx^bupxyzz|{g]~fr~cf~~|zl}p{rwrnnq~t~wr~~~v}|{}~|zvwxxwrt{ksxxvq|t~}cxp|w~}|~z{~z~xv{t~|||r}|s|{{zx}xxt}vwt{tw}xi{{}wrv}~~|u|~x}z~yx|r}|u{}{~|}}nzz{|{~z}|z}vtyu{sy{}~}y||~y~`fxxsfy{l}~zu}vlp{l|U}{}yvn~ssxx{zrxs~w|vqvzf{wg~rrks}ls}twx}}tlltwtyrx~sxwpjyzft~yq}xspsy{{ptktr{q}hu~w{wqs~ky|xn~uozufyww~{wzk~jn~vrx|s}wqnt|||ymv~}z}ozsx|z~zy~p{wzy|yzsvqus}z{vz|~qur~mzu{{{v{{}xkz}~hw~y|}vsll~}sr|zy~g}lzq}eyhw|xx|ryzsy{z}rszw~y{~~zwqq|w{~}y{z~x~}~}~wqzlv|~pw}~~r}{}ww}r~y~~y}yx{~vw~zz~tt}rs~{yq|y|~{}|oz{|x~|~{o|tmwxznvzrxzrvszsz~~|y}yuq{y{oyt{}|q~yt|~}~|wttw||v}{}|}yz}||y{|x}{y~qw|}{l{y~rqux~s~{vx|xux}v~u}z|wz~s~vks}orswrz|u{w~}}~~s||~}rwzy|~}{ut}w}w|runrss{ux~ux}}t}s}wr~~}~v|y~rtq|~~|}zr~s{b}lphuy{v`y}r}ikw{porzscnUvk~zpg{vz~ik~q^luxxt|~}~z||s~kzx}yz~u|~r{r{|}xs~~x{ym}y~~k}r{zx|{x~xkp}|y|{|}~}|w}u{w{v~|xzm{xu||wvppszvkz|v|z}}~~{z}~{w|z}}~|}~{{~~}}}zyw}x|~|~{x|x~vxvs{z}v|y~|xy}m}zq|{~}~}u}~t}{}|vz~v|~}~}w{~{xz|yk}uz~{wz}vr~}}~|z}iuuvr~|szcuzz|w|v~~k{zvw~`}yy{r~kxqvu{mnwt{n{~}xywzutqsw{uu~r}}wxm~w|u~xvzy~g~k{yxqwxw~{mh|~t{y{|~mt}{{p}}yx~}y}tz}y~||}}y|z|{}qr{szv~~rwx~~syz}w{x~gw|s~t~uu~~|}x~|{p}z}z|z~}w~x|z~|}y|~wzr|}~xv|}z~|}~t}yuvwvp|t}uz}~|zy}~}~p~~x{w~myugsfzv}qey}}xhx|vu}|msvkzcvtsl|yv}wtont|j}qzwW]rn}ouy}lt~]o{p~hq{anv{a|vuv|j~Yrvmsr~nyx|x~{vxw}{q{|x~{r~|zz|{}~vr}}}|u||~}|v}|pwxurw}|{tv|ptt}xvx{r}|xsz{|w|}}w{|xvr~~|rvpuv~|}{m~}yuxnszsu{~~|yvrxwursvyys|z{k{tvvs}qovu~}|~uy}w{wqyzr{{xmuu~yw|{{syxyt{vntwmywy~xzypwu~ouuuqozywz}|jlrvz_|{ds|~{uz|~||{ptunt~uxrvsz~~wutwv~~}p{ts{tmzz~~|}}|{{u~uv~|~x~}{xtz|kus{|}zy{xywz~~~mx}w~v~{z|~m}{|}wyq~|q}v~|vzwx|~{wzzkxz~~z{xzv}v~wy~|zw}w~us~{xxtv{rtvt{zr~yo~|~z~{v~v|{}v~xtxx~y{p|y{wx|}{}j{|}}}i|}zrpxwww}t~yvx~~~ppynju{uuv{ypoz}eymvnjwvy|w|rtr}l}szr~y}}wv}uzm~ytv}~vpzouuyupv|zitt{||ktz}w{zwu}|y}}x{~xq{wirxyvsv~}~wyxvjPcz؅rswwoxwu]wocr}qdqIyh{v~Y|jzduunw~a~x{]iy|tqvayzwuv{{znnxizq{zpx}v{{~|}y~~qp~qqx}}us|{ssl~}lw{{u~osszo{lxovtws~~}x}v}}~~zq}oo{~x}vz{y|muyw|~}j~~|vs|y}}tuqz}z{z{y}~||~~{{}}|~~}z||{s}x{zuqm~{}yo{~p~~{}~x~v}}pvz{y~x}y|{zy~~w~}|tsxxuy}uwxz|{uz~vw}{yx{}y}}w|~{z|qzpyoq}yyx|yewlx}yt|qxrtyuq}rvq{rvt|r~u{ywj{uy}|}{wzzyzjtzu{|{rzqvqw}ztzqo{y~sVu|iy}~~{l{b{}}~wrs}n~~|stx~k{xrz|s}|iq~v~pp}}o|}q{vmmu}xw{ta~pokyq~~xsiwp}iyzk{zzw}xu~{{~wy}wvz|z}xqxy}{z~x|~yo}~~y~xy{y}~z~v|z}t}vwuzsr|}wyysmp}vxasp|{y~orslk|zwzxtwyn{st{uryxpsu}zyzyuzi~zroqt{z{r}tku{~woutly|~uxx}tupb{~ykvzo}t||}m{zq{qm{s}|ujzx~pkq||}o}uwq|{{us{|{pvup}uiyyx}zxt~}}{}vxmov~z|p|yp|l||syw}~{k~rqs~~wx}|{yo|q|}{yu}v~x}xzz{v}mzoptupy|{xnzv|x|sv~}}}{wo}~yo~}~||s{~xsz~{~}~|zxyw}xw}z|yz|~r~ea|y{o|}~ifzeYfqqqyhbsw}rk}z|~|^xbxxr}}xzwvu~fwk{yvjq|v{zwvvot}us}vq|uvznu}um~zvznyv}rzz~|~}~v|y}vl}{{{yx}yy}|z~vtz~|w}xxp|qlx}u}|hz{uyv}~mvuum~wv}n}}}nw|xx}wyu~zjwp}{wy~~z|z{z{wz}}wzwtvk}{~}}~|}x|zy~wr}w{|zputyv~{~xzux~u~}uv}{~ww~~v~~s}xx|z}{{{}ytzzxw~{u~{zyz|zxo}~vz~q}a~|n}|{yu~~|r|{|tpzwqz{}z|~{xo}sk~|t~q|||o|wy|g}`{t~oyzputqyuru}mt~xv{txy~hz|l{ynuzky~wnyztvzrgzvrzt~n{t{~zqxytxqql}ylxux~m~~u|orpx}|}zsiu|t~tuwlw~}xp~v~euzrsps}{}|pu~~zgkzu}vv~x|||yym{v}nt}||tyt|u{~}xyywzo}~txw~z{}z~}~||{o}kwv~ujx{xv~|~{y~mbk~cyungls}wxnl}~|k^sokLqzZeqvilU~luqeul~s~~hiunqjnptbjzuvqwu||ifvnzyq|o|sw|kliwe|ow~yuzw}|uozvq{{z~z}~wsutv~}~ny}{u|x~x~{t{}}yy~{~xx}z|yx}|{}}|~w}||zyvqmtvz}zgy}wuzmo|hnurz~|{s~s}x|y~u}os|sw{zx~}{x|{~{{~z}}kq}z|my}vzxi|x|}~{~rp|{y~s|}{||{z|vu|uiu~q~zvm{|zu~y{v~~{}|~~wr{sv}zp|v|}yt~jw}wyr~~y~rv~w|x|x}}v|yux{|~{v|}}|p||}}zmw~~k|r~yu~|r{{oyxoxztlxyi|~yqy}tuts|||p}{{uy||y}yy}y{z}y~~uz{zzw~}zny~xmvyn~|x{}zsx~x}||{m~uy{s{~|yv{p{~}|w|rs|~}~nw|y{z{~y|~p~~x~{w~ym}~{|q{~m}|~||wv}wwuy}swt{zwot|szsx}z{~w~s~~{zwu}xw}zwwz~~~~|y{~}}us~~}m}~ww{y|~~}nt{w}~}y}rw}{z|mozs}{w~|h}xtziuxup{{z{pru{~z{~zwi}ywxrvu}}vmqxp|}ts}}}lsyx~~xxit}s}~tvx||w{qzurxvzx||tztwsxvzrwu~n{~vvp{y~~~frt}u|m{ltq|qo~~y}uy~~fl|{tj{s|s|p~v|~zrrwnh}yjr{{wyzm|xqwvyqrp~x~q|n|}y{~qz{nwqyuse|{u{fu}zz~lx{|vrtt|q~uu|jz}yyu}q|}{}r~ytzoqzw|}{ut}|{}{|x~|tx|}nwk}~|}~wx~yt~uv|wu~wzupxzvu|x{tz}xt|uwtxv}j~}|mx{|~x|x~r}}yu{s}sx~q{{}v|}ys{{|yzwo|}n}m{txzz|}}}ozt|{y{{vwt~tz{~z{vz}{tusxzzuxw}~ww{~}}}{{|w{tn{xnvxwztr}inopvvH~x~h~togqfzvxy~y`p}jpym{nhq}ox}z{y}|vrvc~qzw}xn}|tvvwyyz{{q|~w}v}}|yv{s{|}zsdvsx||swy}{msrvwwzz|~kwy~|uuv~ry}z}{{wsv|{~tr{tvp~|~~|xzyu}e{{~uyq~}vuzwus~yqwy|{nyvtxr}}v~p}r{{m}o{|tlrypuww~zwqzz{|y}nw|o}~wjw~q{yzzqvo{po||~vurq~}zzvmv|wy~v~{z}|~{s|}{ft{vt~ousxu{zsvuyh~zn}ux|o~~s}yxzz}y{vxxtxu|~wv{vzz~xpxux{vt}{{xu|~y|~y{yqx}|pnu{~{zxuzp~}w~n{xvm~t{qs|ot|vwt~|x~}yqxoy~uwr|~qyxlwz~s~|z~w}~z}zvm|p{z{}w~}|xtzx{zt{stx|z|jnty{nt|uyux}lmxg~}w{s`nazo^z~|˒||[{x}}l{zw|}v}w|y~~|rxxu{wx||xv{~}~}xostz|v{|{|~w|q~|sow~ww{}l~{}}n|uz{l|~{ou}t}s|~zx}w~}wvxx~x|y|x}}|{zw|~~w}o{v|}|y{ot~~n{twxw}{v{vpt{s~j{q}}u}us{|wx~|m{~~}~v||}~~z{~~{ytywvm{|qu~|~|}lz{okrxzvvz}}~~~yv{}szyl~p}~yy{~}q|}un|~|ywx~pux}{}~jy}x}~n~x~yrwz{{|yu~|}~|~y~{{|yyxr}~v}s}z{}xnxyt~}{~xu}vq|zxpu~lzzsv~w~s|yvtyxo}w}qxw~x~}}~|}~}{z{~xu{{mo{pvol~zt~t{~u~wmx}v{vxvtt|qqzrm|mu{|ym~x}n}~z{p}zuyy}ys|mrru|xozwz{|{z{|nwl}~{twk}vx}{tssw|{v|zywqqp}l{rvyu~}kwoy{ipfpy}{v{x|uyotxwztwnu|~vsz}y}yqtpwr}rps~zmwr{}w}tmrtzzwxu}~|y{p|~ss}}ox~iu|~{{m]{v}r~vr~xw}yzx~yx{xxn}ww{tyz~w|}wr|~fnyy}|{|y|}zzp~}uk}xlwt|vu}|xg~y~xlipy|y{|yy|ryyzzh}sv|~z~xv{u~rzs~|~w~ox~~zmqX{t}x~{~|{o}~u}}x}}}fss}zwz}y|o{zyy~{{rx|w~yyyq~|~{zwzprwy~wzvr~}zz|zuwluMq|srx{d}swzxzvgrf|vz}ytzx}~|yqpsw|smzyuz~||uy|~t{tx}}yyyz|mzwy}{x{}yxxyz|v|}wyy~|m}x}zy{swqy}u~r{|xu{}o~{xrzv|zv|~}|}zq~|y}u}~~}}w~~~tx{wvyw{w{|~z}w~}ypyzvzvqyp|xrzwyxxueztlz{ms|}|x~yvwlvwz}|~}uz~|}{{}|}{tz}}qpx|x{r|{y|}zs}yxrw{zy{}}z~|y}~||m}x{zrvzv~}|ztovy}z}z~w{t|r~ts{|wn}}{y}y|}~{}~~~x{puu{n{{|z{w|z{}~pnx|w}|~{x}|{v~x}{|z~{~|x{z|v{wtnz~y{}uu~xv{}z}xrq}zx}}xp|p{xyxxz~|y~t}~v{|w~|x~z~r{}}xqvsv~tyqo{ux|x{o{n}tuz~vk|}xuk}~|m{{w~t}s|uyywj{nx}xz~zx~{~}~yxz~xzvxl|ul}rxzw|}~zy}~vzyy~~x|t~wu{~~|n~v~|zsztyuzx~v}w}uxyv}}tx~y{|u~vyy{q~nk}ǧkvwqtqyrl{y|m}}}tzyqu|wsosw~usp{qyz}y{u~|s}|~|||t|xwzyzw~yu|}}wx|{{}tu~|pnv{y~vz{swxxxxv~zvp~yv|x}~z~tvszx}vx{sx}|zvv}svvt{wz{||}l}|s{u{|{yp~}~vv~u~uwzy}wxj|y~r{~v}q|u~|~wzr~mt}xrzq~}~~w|yy{~r}mxz|w}r~vyz~|utrs~i|zsxtqz|ryst}y||xvyyyxz{xv{u~vu|~{zxwuq{p~pzzm|{yp~{}~z{vuom{ny~r|lc~}ovrzmwvzwsjtzZ}zzuzznozljowhr`lwjl|qvss{nvur}mw{}`p}huX{zm{vioisqp^qr|iz|{{umxnqo{q~v}jzz~uk~~}_sw}zx~|uvt}}~}zx{}{wig|~ri{|yzx{zw}{s~vwy}vopxz{u}~sv|ry~}|{szt}w}zu}uyyputy|ytu|{|u{|v|}v~s{|wiswtw|x~~z}~wu}}}vv~w{u}wqz}~o|}vw}|x|{}zv|{z}~}|uhk|s|lsupxo}xzxynnnstx}ki~dwrzq~w|kryyzxwxx|{tώmiblkUwn{u_~{yiohyscizn\|xrtqmt|dl|yjuSqYd}{|eeyqlit|_fp|jv~ytu~vv{~~yovo~ztwuxyr|}xmv}hn}zsuu}~u}yntz~~|~zzx}z|}zqwuyz|{}vzuyq{sxuosquugz|w{xqkwzuy{vpzyt}q}r~xzw}z|dy{xyzp{~w~{z{o~w{vyu|~vowwUl|vrzjsszksz~|oizme{~qtp{sxxzxu{y~|rcttw}wszzq{|{yzw~}{qlz{|nzqup}r~~v{q{~y~}xqpy}mm~~zvyy~z{lz{~~~nwzzpt}s~|y|jhm{~ttx{w~fs~t{y{}yz||vzyxmzwl~}|z{mzzx|xxvyzzy|jt}tu~~uwvzm~r|}twshw{wv}z}z~xxcr~|t}{~w~iqfq}ts}}s}~}}uluy~uvy}v|~{wz}~wu|~|vys~|v{}x}~y|}z|xzz~jzwyvz~z{ytt}~}x}}|yz|o}p|}ytpxj}yy~v}{p||~s|~~zvz}x~z{zroz}~s~z|wz~y~|~wryzuwy{y{zx|~vy~}~{uz~pt{}r~g{vz|z~{vu~s~{q|wq{sxxqm|}xozwy}y}~~u}{t}y~}q~pw~yu~vurv}v{i|~smy~xws~}w}|x{txg~}~|z|}~x|yp|ywzq}zm~kpyv|su{ss|xwyw|yn|{w|mw{yo{p~y{i}~|{hryxn|u{ytzz}s|~{n~wws|{~s|tsyx~utv~~u|y}yz}}{[|{~~}potsquw~}yvrwu|{~ws}g|xtxz~wyo~u~{xyv~z{yvym}}y||{{ly{~~xty{|xz~yurnp}}r|uuw~}{|y~o~ty}|}}v~z{r~pMz{zw[{a~h}J}tipd|zpthvvym|l]rcpUpUje_z|urՆwyzyxv~{yzivwrzm{|{ul]wx}lv|}wovyyzyvw~zkr||}mz{xw}|~h~~w{||q{ytxpxu|k|s~yvptr}uk}zrxy{{~r~{isp~x|v}yp{zt~~x|vu}o}rt}yptypxx}sw|}r{~y|x}}|oz~vz{tr|zxv~~w}txvz~wxu{ym}vz}nytx}zul~wx}zt{tyq}}{y{{tzh{uqxtjxzvyqz~mfx}i{ozz}{xwwgvi|{l}}iyt}zny~f}uy|yz~ny}prw{wy}zx{{nst}ysuguv}xz`~ygwyyts|x{vtumo}uu}}v~{mpwuzrs|xo|vgzw[ussqx}zy|pxynzmzxuwxirxyz|p}uxuqvp~ro}{sxk~vz|~w{y}v~~zwy}~qyiy{ymwv{v|nx}ky{|y}uqed}t|sx~~z~}qv|}~wyvy{~pp|uvur{ziyszxn~w}wuvpwv}yz}u~~~~{tnr{|{tz|~}zluewv~zuz}qt}kxz~v|yxq}zh|ooyoyum}~v~rv|||}}xx|vv{~zxxruzx}}w}x{|wxuoqh|x~xm|h|rtw~ygvv~~~w~n}|{~vzs~|y|jx||ovnxpv}t{{x||v~}}}kp~{u{ytyttp{|rwxo}xwwo}~~}~x|vs}~vby~swzg|z~yxy{yz|hty{~|hi{rzmky}~wjr~e}w~Wo]m{~k{zzxlrpvk{xsr{{jnuw}yswpqzoj}tlwrmjrzXw~{{{nsur|~nqnu|qgjown|spuzts~|thOtxtryz~{}{}oz|~usp~q|yv~}vx}|zs|vv~it}wy~k||t||wyu~mp|}v\}}tx|vx{v}wzz{{oqyx{g~t{msz{u~utzx{osrpv}wkp{n}nuvovu{u}}yszttrys}lfzuo{{pt}~}y~vzqzyypz{q{vv{vsuz|ynouuuu~ov~vyzv~{~zry{{xw~}}s|{}ww}|{u}~|~x~|r|vu{rv}}wg{zm{xzvyqy||zy~ux|xtxx~}jlrvr|w~|{|sww}{xx}|xwvu{xz~|rtl~p}~uS~~rsw~}wynw~iy}vr}cttz}r{ysqvqxl|}xuu~|z}}|wf}}ry{|}t~qx{y~vyqzw}{vxpv~`y}{r~}|u~y|~~||x~z|uw{wz~}{t~qyyz|yx}~swn~~zov|rsy}~~u~wyzzt{~ur~z{|~}~u|}|yzvysz}m|~fns}sj~mkrb{pw}~xosdzqtvN{gerzuhrp}|}zu~}zvvfui|ku~_~tq|nnz~ytzu~x{{vw|}uyn}o{~|w}~w{}~y~~znwzy~|{{|~{{hzqsystyv|~{|ytr{|u~|~y~{v~||zn|xy~zt~w|||yp|nnwt{|~z|y||}pvvr{yu|yy}unqxlrzjw}z{rqdu~yxwt|}rx|d~{|x~rzyzu{yy|{~}rrzt}~|zn~~{x|o}t~|{~{~~{mxv{~}{v|~{o}{o{|tmx}q}vsn|l}~|~|~rx|uow~r|vwoxwpyz}|w|w}v}yv}|{w{xx{}~~u}yo|zkxvVv\skrtz}|}`{jv~~ywlpvxn{yvshzm}vz}pwyswsvqzohpgm|dvov{mxpyKtZpm]{y~o{xx[cl{Ėfzuyw|}rv}tulw|w}q~nw~prvyy{r~|nnym}r~rzz}|z~x|r|~|~|}zs}uzwz|w~mxt~rx|xz|~{~uyw}yn~}zzms{|k|wz}}}v~{~~|n}yzl}l|x|rw{{wny{w}|}xv~pq|q~}qvpsvx}q~wxzyvtsw~su}}~sn{wtynws}mtnw~vty{xyynx}py|~~x{w{zw}|yz}y~{~x~xr|o~ul}x~}|}}n|v~v{~y|t|}xzv}{}vyov~{||~zy}}|zv}zn}x|t}zxw{w{mu{~x{z~||~z}|pvv}q}~{~{}}~wo~~}ux~yz~wy~~z}}vw|rn{mvr{xy{v{vz~}y{z{|}t}zmxvryw|w|y}yy~w~}t~myr||u~py{}~|xlyyyss{{}v|{|t{v|y~}}v~~~v|jxy{~wuy|{|~yryt}~q}{}xn{w{wq}z{~nv~}w~n{z|u}yyzx~wuy|~v~x~it~zw~zssvzlyxrzspt|ty}}u~^fy}vrtlmz~}{lqyz}|}|utvy~{ws~xuxxw|s{y|~~y~uv~}{yzigp}|zynvzu|yq|v{xzwzwuy|uv||xwwgvyzo~y}w}{~tvrv|{vz~x}~}~|~v|~u|wzzzy{}z~{vflztyp{y|v|sxlh~kvuwv}~x|~ynyy}~rpwuq{vlw}}|zts}|o|kh~x{zzz{|}|tjwu||{tx|lxu}}x{q~q{unvnt}opuwyruuurzrs{tztq{~q~y}~ksuy~nzwss{ktt|{sxxuyrx{wtyz~y|t|uu~y{}}~nwp|u{xs{{s}}~vv|r|}zw}{{}v}q}m}wx~ywojx}mj|||s}{tozyyyivxpt|uq|~qp~op|{y}o}}ru~ynz|w~r_}v~|}{|{~|ws{~k|{ytwz}}}tt|tkzs|}|zxww~w|l||{p}r}}zs|z~{tzysx}vxy|qytzu{~svn{{xv{~{}wyy~t|unqttw|zv|yzswzvly~w|rw~}{yr~zytuy{|{r{}|zqv}o}xwwl~}yvq~wzxyxvsuxtuy~}{yt}~owwm~t~}r}n}~}}rz{vquxwrxr~}w}zuzxppoy|swwz~fz|}qxosyi~zuwmxxvs}{ix|{y~y~zz|zyovv{|ruuly}lzwxjp{wx|wxx~xxvz{~m|zx|s~|x}}p~w{rquzlz|{{txtw}q~~{ro}}vrxxxp~m~lotn}svvk|x}}v|~|Uyx]^^`sn{upvvY|hvcp|ygyy’s|zxno~vvtxpuf{d{lstq|nosyz{nwynpyri~bdvtxvzpz}zk|pyq~^v}xlvozx}q{py~ivzylr~|~}|ut~{{|}nsz{z~zkyquh~y{n~tstq|~|{w}s}y~{x|zzzzxj~~xmut{zu|tlw{pq}dtw}r{~}uwvzst{wzxtyt}|yopo}{uz{szyxrzznywxy|r{y}tw|{u~v{{to}tz}p|x{v~xn~wvzyq}||}{}xv~x}y{ow}{n}}z~zy}~|xyuw|nvnus~~xy}}~yqzr}q|xx||~v~vuo~yty}}t}|x}zvz|}vu~r}{v|~z~rxmz{tuuw{}~|s|mu~o~|irv~pp~o|z~xwq}pzx{rzp{pz}|ws}nyu~{z~~|zw|ty~{~}~~{~zwz~}ty~uqx{ptq}~|vy}s~z~~|~u}suu|}m||}{|~z|z~y~~}}|}z~y~wzx}xzk{otrtpxyh}xut|~~~r{z|ws}{w~x~s~tv}}||~yt}{}~yy}~z{|wy~yn||nz~}{{o~o|~q~~|~y~}u}{|znyzr~zsm|vx|qw|szu~|uu~{}vsr|wppttwiuzpqu}~x|stt~{uv~}|xvy{uyy}vl~tsw}tmkxqmuvw~{mx}q|pvwzlcnuo}~~u~w{}p|zzx|||}~}~zs{nq}}t|vxuz|~vzto~~gux{wz}~~v}i}{~}nz~w|kxry}qw{x{fo}~pupw|||~~ys}{u{zsxvg}vy|{z{}xtw|}t|o|zyytn}s[{x~xzzsw|trt}~rzyywxx|t~wvytxzw|tz}y~otd}zt~{~s}}u|{{w{uty|tnst|uvoyxy{wousvcntzyr{pxt~szp}}zhsx}wwtvtyqxux}wpo}|}vsrw|kpt~wyq~~zvo|zzgpvos~tuo{~b~wxeby{s{|zr{wz|n{{rz}yv|{y|~|xn|}{srxpyq{~|}opvq}|~}o}x{www{~y{wxyy~v~~~}vwy~~x||z|y|ko{{~xw|t|ot|{y~}~~}z}||yvuvsn}p{s~|v}w}pk|{s{~z{z~~}|}x|~uxxyozmznvykx}yz}|{i~ny{u{|uusyz}rvsswl~|nuz}~{yzr~xvtvr{|yzp|z{{vxxxzv{ylo~|zxzxzpyyw~|~}ysv|rr~zwykq{~p{xy~~rv~u~xy|p}~~mzy|v}vy|{zwvz|v~yw|k~krsvgp~~}uv{{lwz{{wj}~{tvv{|yum|u}nf{puml{{yu}|ywzz~~myk~k}yyk~{t{|}rs|t}usm~y}vxu{ly{kw}~~x|v}u~xwm~~z}l~{z~~zw{s|xxwx}yv~s}l{qk~rouzpo}{|xxv~o}}rz{w{p}v~|k|~nvwwt~z}}|y}wxv}t~kzy}|ovxn{vzuzp}zy}|jt{~v|u{wo~xx~t~t{~~}x|x}~txzzypy}y}v{~u|xvxyvxyitz{~|ozv{vzz~w~xzz~z}y{{ws}u{}uy}q}y|zq}xqvw}~kq}|~|tzwy{ywcv~||~vqzxyyrwn~|w|z|yx}{wr{wh{{x}}my~w~w|mywixtqury~y{tzoz|~y~v}ztvxwuzz{~w|~xvqxnz{tx~}xvvzus}|~xt}}wnx}~z{zrzjo|xzszxz}s||lvr|zp{v}~qy~x~zxv}y{{}}u{zn~tx{z}jswpg{|s|wy~zy{~zv|x{~q}}tz~sz}sv}n~lrszwt}{{vs|s~|yuww~r{|zvxprx{~~}x}zy|syzr{w{~r~v~|~z{~~vz}y}w}u}s}rq~}yw{h{}}x|~mwy|~xs{wz}vtzvk}zx~v~x|{zuyz{wxx}tm|um~z|wstpz|}|yv}mr^~~r{s|t}uy{qz~sz~t{|o~fztxz}uwwwuwvyy}~wxl{plytsygv}pwu{x|{lvn~vq~w}wmzusnl~~~vszp}~~xr{~z~~ousoyqxz|}w|x~smsy~}vltzn||}{~t}s|v{|w~z{zvzpsnzys~|w}|r}{~ytvv|gy{|z~s||sosv~yvzl|}pu}|~w~t{}|vzwsw{u}z}~s{~y~{{|{{|wyxrzt{vjzojqwysn{wwtz}|{}}ox}|{ztpf{myduyin|gon{vfpk}oxzw~yvbvs}~zp{yvmX~xw`yzruopnuzq|yxrztrx~n~nw|s|pwxu}u}~|swy~xt~yw}z}wztplz{~x~~zxzpv||h~{m}tu{{muwz}o}z{|yq}x{~z|}~~ys}u{~{{n}v{{{o{~zxwuyu{tz{yx}o~yvwm~txo~~rrw~|usr~sjyy}ww}}|xx}}}}z|z{zz~v{n|w|}~v}w}||}wx}}z|zw}}}y{}}mz{{s~y{~~yg|y{z~zt|uq{}|yˆ|~|u}|~twqq{yi}x|{x}uz{u}}|}z}zzm~~{p|}v|s||r~ps{zt~un}|su}kwly|}~w|t~x}xo~p~}|z|}|y||z}xxv}~wysxvkc{pzo~|~ututp{{qjw~q}~wztu~frg|vj~w|w~s~lzx||||smx~yyn|r~}k~{y~rv~lw~}x|}}t~v{{xnyz||t~~z~rt}ttzw~vzx|w{z{{q{v}}~uj}|ow}r}yz{}uyq~~{sy~||{|v~v{x|xt|kq}~}{}~{q~j}{~ty~xzy}~yx}wlzoo|{m|zx{{z{~u|~z~xv~|}xyy{vz}}~}{nsww}~}~|v}|u}z{|~}x{nx{w}|r~|||~{ryxz{y|vwv|{}~~y{yszu~}wt}{}xz~yw~|xo{zqtuw{~y}v}o|}r|~~z|zoywqy{s}|w}{|vz~~ty|v~~yu|}wv{y|}{zws|sz~~z}zu}q{hlruo}u{}|zS|shp|x|v~vyqm}dvv}tydnb{z|mjvs~zn|zolv~nde|ze~dpxzlmysossipzmwvogY~ehylsoodw\pzetjy{qxifywnfnpxy|uppwv|}|hw}[yz~s~qd}y|yivvz||tvzeyj}zv{|tq{v~~w~}xxwq{zqxxpmzvz}wtmwwxx{y`}vy|v|gw}ttzvrr}dwy{stuwx{mwtrgwyrsoxn~mute{syxuqh|{vwz}qx~tj}}~y~xywyq|{}{zywn|vjwjxvopw|~uthv|yyvvyymqq|v|~uz{zx{}ov|cz~pwup|v{}qz{|sx}t~xy|wwzvnuyruty|mxxp|x{zuxz}{x|tyj|}uuzxy~x|ty{x|}~}||}k{|ouzpv}{{{~Qw{v~qyy{zsv}|ox{m~g{xxuyuzv}ztwhok{{xz}xt~{v}y{qr{pkf~zwvvwr{{z|~{}}~w~|yn~ny}s|~~vzp~w}v{~x~l|}~q}r~~}|zxswzu|{uy}}x{~zzw}xxtxw}ernyt{wu||{}wuu|l~|whuv{||zywv}y}pslzs{z{z~rv|~yvmuwt~n}s{wrm~n{|tllq~po~{zq|~usviq}qsnyv|u|l|zvx}xx|r~{sx|rzuxx~ngvi|uxsvuwr~~}v{stx~}~ovozyxvx{u{usw}|y}y~u}r~v~|qt|~t{wy~{~}~u|wow}{j}}{x{xum~umztw{u~wn{{zu|rijys{{zxyl}w}xz~x|q{}ztvz|~{}}y|{vx~~}z||styw}}y{n~|~~n}{v}s{tu{~s~uxd~i{zm{{zztu{wh}|l|zm{s~|vt|o|y}|~w~w|u}{|o|~uwx~z~|}q~xv|{mxu{u~w~||vy}w|v|~p|~{}}}yz~xs{{|vl~w~x}~{}}|qwt||~yq|x|syzzyty|tz|}|}}w~v~{}{||}zw|~}~qzm~yynw{w{wz|ipx}~~rerp|tzo||~zku}gr}|v|v|q~}~n~~}vxphw{p{s~r}|}yz^~|v|y{w{wv{r{}}ym|~~v{~}|sz|}}x|}wq}}w{stxp}~{y~z|~{{~xx~~pv{}t}y{}}|}{z~y}~{uryxqu~}ww}z}y|yn}|zy|zzws{{}{{w}w{w|r}zqy|iu|v}|x}~{|yt|z{{~sv}v}tty}ypzuzwxt~wn~}ts}Zu}y|{{~w}up~yoxx{jx|}my}yz}}|ttwu}zpz}szzw~|||}}y{}~x|w{zuvv{n||~us|vz|m|rwywzu{~{{~{|z}|ys|~v{yz~u}mtyxqvs}n~pz~s{mztzvz~x~u}ymtt|rz}pwvpyw{ox}}xsz~{}||}}u~t~rwy}rg|x}~~z|s{~y~zw}lyz{x~~oguzxxlqwytvtqy|}x|xs~{h}w|xuwo}}r|zw~~x}ypsvyro~~u~}r|zsuzzv|tzo}~~~ry|tqu~~~v~{{yp|~ywp|}rt{vu~|{sv{~w|yroy}qv~y}}y~vx}q~ypoty{lo{|re{sqwytp~twzmwr}n|z~|wyx~|ryr|wxqsz}{}h|ww{||wzsyvyw|utyrrfxkz}||wxj{}|zkw~yt|r{_z{yr}y}v|zx~v}y{~}s{yx{||~zr~zk~tr}z{~}{~unyz\~x}{~vz{nyzqxzzmyzr}w|tvszuz{~y~{zsxs|q~z~|~~u|~|xtrlz~ynyqkz|luz{qxvyvzsx~{}w}zwz}l{h}}zryly|{}j}~zv{|~}{qo{z{tvtw}szx}yus}}yx}j~{{zq{y}tsz{}yxuv}u|~v}l|o~z|rwwyyv~||~|vwy}xrvy}pt~yy{|}y}w}y|{}|}vn{uy|yw|y}}{toa~uus}nyvyr|}z}sy{|}{s~zzz}o{~t~}i{uqsu~jqjvtx|nrksheol[~cqytp}{u}|vxd|qpspxqwr_qno[gyskqwrN{{{ubr}vz~lszyvo|v{otzv{f`n{rpj{qs}wwomtuhxtus}m{q}ruybwiuwzjs{zjmymqyavqswyjf}xny\tqo|z|swvz{sqyv|us}|}}ywyxrw~|~||{nvz~~q|}{zv~~{q|}uus{mw}zvzl}wxwt{sx|{y~v|q|l|}~{y{}xy~~~yv}~~}~{~x~zv}|mxvo{}up~{wqw~g||~~mt|xrt|~v|r|lxx}wy|~~|~}}~|q{n}u{ypv}~tnw~~wjvf~|}}l{||vqw~~~rx|q~mzzu~o|~~x{|x|}{zmy{zxozprs{z~}yvs|ygyyv{ru}~z~q~wu}yq|~lvu|s~yzvy}|y|}yrl}xm_utqxwv}xrsw|c_zn~h{uw{sw~waj~{z|mwu{x~|{mw|ltx}wm}uw|~ys|zr||w{{|~}yot~}vq||~{wyzq{}rxemzmyrxt||wpx}w}wxxpj{l|t}r{|uwrrwvxqryvy{y{~~k~ystx{wv}y}x|}t}}ru~{ou|sy~||~{y{yv~y}~wsx}n{wvuviszwxu}o{}~u}vo~}{lxv}v{t~sy|~{{{~|{oy~vw~{z}sxop{x{u}zvz~kw|ssv}ux~||t{|w{xz|zpsp|xp~y}wruzxp|{~|}|~zrw{}}|x~yt{ty~{v||zzu|tyu~{{y{||w~|}wtyxro|||rkqt}~g{~r|xl~y}|{yuzz{zz|uty|`y}}|gxmqs{y~y||}spvwslzuzyv{qvvwjz|||zyzyy}zrx|s{z}z}z}}|rw|u}y|zytyy{v~}~|y_z|~f}~eh}~xyv|yqdpxsrrh\y~dt}kyvr{{z~vj}fyw~{u~vr{vszu}uw}yb~xyyx{~t|~mxwv{~|~vyiy||}|x}t}xrtz|k~k~lqz~dyr{wqyu|qnk~n~kx|yrs~zj{|xu~}~}y||m{ui}tyy~p}yswtm~s~uxvvr~y|sz|iz~y|||xyur{|j{~vyrt}|~}}r}}o{}wtimx|wk|xmvxuq{yxzyyx~~w{vyyzxot}x}t~}y~s}{w|qyzvw~xo{zyxty}vuky}zz{yvzr{}}ss{zrz~xp}~{|}w~r|w|zx{|u{}y{}zw~u}wus~nz~owq|{wy{~vtw}||{v~|yyurz}w}u|yyxiz}~zwv~~|~{z~}zzy~wx}u}yv~jy~r~}|t}ylpptwuyrqspmwrsv~t}y|{skqowotuy~wz{l~}vj}|t^vmpxg|}wsny~r}~|zy~zyply{zu{mmtp}xx{}px{|j}p~wvzr}xy}~vs}qw{~z~wfoy}j{|t{l{vj~lz}uowvxykxss~uur~}v~{~w|~}tws~|mt~~pvurvnzzz|}zz~}t~yv|k|slw}vmux}xpv||}{tpy~xvvs||mvfyyxo|y|rw~q|~lzxyyu}{}~zyxuzvhxrn|zty}rsz|xu|x{w{z|sk}orxz{{xzw}tu{u}x{ztux}uyw~~y~~}y}o|zy|r|vt{u{~xym|y{||r}wicpx|mk~x{{v||yxx{{wvzvwy}{yqqtzx|{|{zx{lu|uxszu||u|z{|vzzw}{}{zzv~~|}w{{w~u}~v{~x|zz}{pz}|u~|yn|{}wzz}x}zrtyy|{}nx|}zzy}sv}}uz|uwz~kw|{~}|~yv~|wy|y|w}}{}syzzj{~z|zvvt~~vqwk{|wwyuwxqxkyjz{wr|{{rz|h}~q~|w|~ww}y~}~lyyvxy|yt~{}{yw{|~}|{}zr}rx{v~z~z}zxzzy~{~v|olxs|tyvq{~}w~{y|q}zzvlm{w}p~|o}}}y}}~y|z~}~}}yoz}z~y}zy}vzv{zy{vx|jm{|}x}a}mxi|ymvz|zuytq{wz}}ixvpoz{}~tzy|skutzrzl}|{yv~z~|}^yy}~otp~}xu|~p}tkwj}uxm~||wn|u{r{w~}x~{yw{|u{yur~v~x{wwzvzu~{~xw{~}rwy{sz~sy}svxx}|}{{~|z{{w{yu~a}}|oonq~|||zvt~o}{wtso~iy}uk|zlzwsyy}v{wtus{rs~zv|rr{zx{|~t|}~ztwqx~wuy|ym}u{|{~{xxyq~{z|xwz}ywzv|zs|m|}yyqup|vu}y~|tz{p}~ytj|jwtm|zl}{xxyz{}}x}~||yyz~y|u|}}{tu|~zz}r}}wwx|w~q|~~Tvx~}wvwqvpÒ~zw~}n~yyy}~|||u}||{pvw~r||uz{}}{xq}~{jzw|t{}ys~}pmrvxpzrwq{n|~s}sxw~qtwuzvr{zztvqunz~~}{~{vz|~~z{yxz~wyu~up{zwqv}~|yty}zvwwx~z}|szzsw{}{vuy}~y}x{~}~vywn{||rpq~{y|w~zzr~p{r{tjzj|m}ymxnxyvzwp{r{sw{}zos~{uy|t}~v}s~xxxqvzz|{~}wyzl}}|w~}}||~|}~v|xzmz}ur|yntz}zƏr{~~czxxtpwzyukwzz~kqv~rvl|ywz|w}ky}|wl}{wXu~udwxxmwxxuuw~|tp|ryz||y~{}|~|zm{wqqq~{uu{}~zwxxov{tk~j{l}|lz{u}uz~}}w~x{yvu{uv}qt{z{~{{}x}}wswpy{wx}w}|t|u{|urt{}}|oyvyx|z|wuxtsuqxzjyp~zzm{|}xxoxu}uzm}w|zyxo~suxpuvtvsryw|w}|~yuyzsv|}{nymxvyt{tsx~||}z~}vp|{|{{~zz|{~o~~}}wty~v{voz|z{ww}mwpxjzx|kvtl}~u|~}{u{wy||z}yuw{iszoxv}|{{|~guppsx~xwyqyzw{ulkz}znzoq|oz{x}y~q}urz{pv}}~}}z~~}yvzruv}}x}wt{{w{}|`vv{xo|sqy}}~{szvo}vthizp}l}n~nuqv{w}x{yz~|q|u}ltot}qz}w|zz~{tuzx~w~r|xy{~wttstyq{{z~|z}{}t|tty~}~~~{}||z|uyu{m}{~y||vt~~|{t~t{|tyx~|x{~}z~}}{vt~~sxmx{}~z}~~{y~~~{}xg||qrry~}}~xxy}p}}quk~zj~|mmzow{rvzx|x{~{r|sy{rtxz|yw}w~~yxw{{|v}v~|{o|~~zoqvts}royw~vnqmzxxzjuxywr~{lbuw|zjk}zrzgv~tzs{xnsy|qz|vxhk|ys}y}}}z}q{m~hjzsynxqvts~x~p~yv}|pwpuwvorxt}}i}}twy~jw{}|z}kqyzw|upzuzyyvxuvxzsyyxwz{pv{k~}v}{y~wu{npz|zss}||xvyxt|x{~t{vxwuwmc~n~|~[yppsw~ym{tsrtzjn}qo}wb|pyz~pwx}tsz}r~wds}ypww{wz~||v|w{~fx~nnryzm|zz~k~zu}{n|~ysjyk~yvht{jz}wiq~~g}v}sy{yz~wiz~o{tnt}zix}tg}hv|sz~q~~|b{vzrk~~}|t{{|xyxpz|}u}o{oq{wv|y~~|yvwo{vri}jv|zx~l{u~lls}zx{q}wt~ryr{v}smr|o{|u{q|yws~~vt{wpq~}lr}nsxrvwyrj{oxg}u|rpnyv}x{mvv}y{njs~wtwrt}o|s}}~xm~zv}y~qqv~ty~kz~yq|w}~kszo}|yu{ym}|{k|~|x~u|y}{k~s|w|wzw|k{{}rspt~xuvo{~tu}skylvz|kxxmuzur~w}}s|}zwuw{x{you~s|}{{n~~~{{zus}}|{~uo~}y~~|vtyn}~zwqto}}v{{p~vtm~jol|{ow|vuz||x~}x|}||tv~xwqt}}xzyz~o|~~{w{uw}~tyzo}uqÏsr|~~wxzysssstryyRmvv{|m|syt}zqxtsjzzx}p|uqz~lzwzwxruwtttzis{x~~u~|v|w}||}vl{ux|ptxz|mwto~{w~{wvp|o}}wv{~zqv|uw{r|px~[sx|vz|xNzy~~px}srqt}{y|v{|zxzy{~y~l|x}zzzo}hj~z}y{~wtyw|~}{yz}ryz{hy}t||rwvm|szwt~xw|wuq~zxwpoxuyw|x}rxtwr{|wzwz{~||~}}y{t~{tx|ru~|zxw}}ytw~z~||~xx}u{~{wz~yz}txsxg~x|w{|~~yz|yur~{tzz{z|yvwwxql}yzx|vn|~y~{n~|zt}w~xxxx{v~{z}t~mw~v}|yw}vsuvurw{x|s|xs}vzv~yxwvv}y{}v~{uy}w~yr|}w{w|{|}yxry~ryyx{~|yzxx|y{}{~w~|||xz~}}~v}w~Xor|{zuzjx}y~|y~}v~\zyv~lwuu|xi}rSxq}~tsl|zxep|x{{y~vrvuyz{oywy~n}}uuyww|p}w|~xzxuxtw}s}uxz~|xxv|yryu{x||~xv}x~|zzct{vp|sr|{szzw{o~}uh~jz{xm}z{mrx{}w}y~z{{{s}wwtq|w{z}z}|o{v~}{unzx~rz{yw}~~}zwyl}xptoxyz}zv{{ozuotm~jz}zl{l{xzx{x~|zz~}|r|uu~syq~uz~|}zz~t{{y}q}t~yy}pvz~yo{v{yrdp|z}ly|tnw}xvzn~x{z~~xrzwzq||z~|tn|vuwywz~~wyxxwp~}|~uoyzqzm}uy}u~}|{x{t}{txxqpq}ztzkynwevyzw|~qv~{wuxq~wyv}ytzwtz~}~zzzq}wtrowrou}zszltv}z{t}{}v{}|z}w{~}usp{}qtw~{w|wwtyy{~stws~~~x~{}}xv|vh|~}vprqn{~qpsutl}j|{l~zoyu{|z|u~|x{}q{sv~|~n|tv|~z}}|}{~t~o}{|~{x}~n~qvuy{~}}}v{zoyv~uylpq~tox~m}|x{v|m~}rs~p}~yjyztsv{rx{{vs}wxqr~qxn{wr~twz}z~~|x|x|z|s~~~y~o~p}}y{}sv|~~{|}vp|o{w|v|~t}uuuxpxxv{{s~y{}{v}rvyr~tyw|vzqwr~u|}v{t}zsz{xkwpyss|zsy~|zwo{z~{y}swuu~|~x}s~xvuz~y|vx{}~qzw||vuv|}x}}z{zws~}tyl|~x{z{{y}v||utsm}xy}my|i~}~|{mcpz~p{vtx{u|z~yyntut~}i|iz}f{dw}pu~mzz}}{ktw~x}p{u~vyh~}txxrzw|ynxvtno{|lxvt}~}{vqw}|uw}|}zqtpuqr{os{~z}uyzw~x{w{zuur}y{x|wx}~vxy}z{}{}}vh|}|v|ux~tqy}q}lt{|hquttx|zsq{qx}|zv}u}{}t{{|{~p{{ypzu{{x|zt~l}qzrz|zyy~w}u{||vw~r}|ms{~kpvmd~}b~zyt9akoxexzjxpwqisz~{{k}xqtqu{y}v{~yq|kuyvoyxzzvytt}}tlus|wy{p}{|spyp~~}|}{|}v}~|~~n}u~x}|~~tw{S{esXswzl{v|yy}~vowvuy|pwrw}|z}yyz{p|p}s~yu}~twt|{}}k|zyyyw{quyzz}y{xwzzz~}qvn}s|~zkz~{yuj~~}}{~uw|uy||vzf}v}q~|yޏqu{|z|v|r}zxuv|gk|z{{~}ztysx~|||~|}}|{~zx~}roxpz}j~rzyz{~{zuy~}}|v}xyw}y~{}~v~{rw}r{}u|vzxkw~t{}mxyx~r|{yz}}z||~s{}syypzy|~z|q~prorv|{z~p~|wto~j}ql{zox}tyy}x~{}v|su~~uto{zvy|}m}~y|wwlzx~xw}vm|~w~y{yspqzvz|nwu~zpwvz{zvsmzvq{{x}zq}{r{xx~|}n}w}~vty|ww|~tvnxszuz|tqzy|ytuqw{}~mvq}qms}sku|}o|t}zqzzssw{|~stu{|~nz~~w~yp{~{x}oww{|~qqpzywt}q{szxz}|zv~xx}roz||v}{u||`}zoqqm|{{vv}p~}ytm~jzxyk}{}opszt|}v~{xzxs|qv|t~qs{x~yyv}|z~}~tztzyy}}vvulx}t~w{xzuz~z}|}{z~{}xzgzvrto}zuw}o}wtk~j~v|n|ylzy|z{yw{z|}{w|w~||pyrv}zy}y|~vw}~w}ys{x}ym{~grln}~nxtzvx~pt~{||~{p{~w}yu}wsw}zy}~~q~y|y~q{zu{w~||u{szszx}zsy|k~zpr{y{|dw{}}||}xx{vvx~}jt~r|xuy~}vx{n}w~}sl~~uw|{w||~~w{~t}w||uz}{w|{}{uz~|}ny~||{~zuyw}|w{z|xs}|x|||{~{u{}y}~|}{y}{~wy~h~yq}np~v|o}|yzp~sk}j~{l}zk||yryp||}x|yyvs|qu~}{y~nt{xy|zu}yvu|zv}t|yky}vz||}||z}~{gu|qpq{|mx}zrzo}}}jztj|jx|zvx{l{|im~vwy|w~x~yxxt|~rztzvvxr~pt}z}yv}ztuz}~{|tyvmvvy|yt}sw}~{{rsqzr{oj~tr~lv|qzqw|zvju}pvt|vszt|~uxuycw~uqyn~}~{xxlyo}f|{qx}|suixwv|Jrua}u~|y}kuwq}vru||pxm}ms{tuw}wyo}t|zy}z{}~yv~xn{zzq|zuyzwrp{~~h{xt|v}w~zzvz}wxuvxzxw|~wur|}zx{o|wrzzr}y~|zxuwzz}x~y|}pu|y~{ozwyv|~y||rt}v{}|~|}z}x{}x~~z|v|{|u~z{{}|wy}z}xlg}}Y{mt||zmo~}tyvv~|pt{p}vr{bzsr}{~|xxs\n|xZxuzer{y~w{rsxw{}ry~}m~t{~|}o{ry{eoyv}{~{z}i~Xhtuyuwg}gz{ttvz~}rqsptz{yv~}vtjzvspk}~|dz{kpjhpsy~pjzgzr~}z}{x~tkw{~qjn~}ssows}xriu|zrmw}rtxt{myox~yywqvttufsy}~}_~qu{urqt{mkxxzzswu}}~rzumw|||w{qx{|is{otwoY~wuzmtztz}|k~n~}t}sn}vuzm}iry|}z{}|~~wzwxvy|~}}~}}}{~vx|q}rxxzx{m{zz|xy~~ppwt}{_~}wu{~zy|gtgiqiz}{qnq}ymz|tu{tvwq}wuyskvx|xur~w}wzs~r|y{z|{|p~xw~{rpxz}ut~}}nyvwt~{z|y{yxy{sy~y~s{~}i~}mmo{p{{{p|}~{y{sxoyytmjsql{|~j~~r~~dzvsoj|wpyuzqps}{rt|}u}uwx|z|z|yszxru}my|uzn~zqz}|ttx}~{~y~}v}zz|~ws}y|{zx|~unXw~{{lvwz|vq~x}z{x~w}~|ou}{u{~u{y}wtim{|}~{w~{wuspz{{~~~t^}}zz}}z{bppp}uoyy{{xwp}uquxvzy{|qwx{|}q|}||}u}}z}{{sz|z{x~rzzz~qkz~}v~}}vy}srywy~{zuyx|u|~xt}xivt{}x~{szwz~{}||~|~sz{}|v~}~w|z}~x~~||z~{{{}zry}p}n{|lrr{|{{p~~vuyo~rtzt{|x~lw{psmzol{|z}~{tzd|~u}xz{ox{~~i}|puqrvzl}{~ww|{~yuz|f~}~pqpvl|yyzyxp}}tk}i{mz~zlyyotsx{t}{zwx~tzrz~}~qryrx|{~v|tz|{v~tpzvuxbsl||~||{|i}}ug}vp{ztxt}t|}w~vlu|}r|z}~}qzfwotpo}tuzz~m~u{svzwzp{xnptzmyou|t|~st}s||xwuy|~~sx{ys~vwlsuux}w}~t{xtvyvn}~{|~~~{|_k}xtt{suz}|x~|r~~xxkp|tuwy{vtv}z~}}}z~t~ty{~~x~}~xxywzuvu}s_l}d~}}xrws{}~{ycywvxtvm|ypnux|zz}{u|~}{x}|}|{zt}|y{{bz{q~yt{u}wrxzt|yuv|xszz}vz{t||}{~}|y~{{z|z|v~z{xw{~~xyv}{~{w{|}zhw~~}}wwvnm~br}}veqwqRoz{tvwfrq}dy{{xyy}horl~gwy}w~ctmm}v{unn~trzt}qi}ysltuhykss~{qxut}t}vq{ugy|]q|}k~z{|phzy{sy~r}{iw~st_gzp~|w}p}zixw}zr{~x|wykw|vzxc|u||]v~q|dtwsnvu}tvy{rwzvouu|}|xx|sxoy{|z{{ztzryy}zwvyr|zwx~}x{v~z|ur{{yv~~yvpx|{|~~zt|xyw{|w}}}}{|~{w~z~}{w}st}|ay~v}pzvqwv{wuwy}u}r}x|ut}zt{{yqyyr|zw{yy~}}|t||}yq~~}~w{~zzy{~wv~~|y}{{wz~~xyz}Uh|}z|~xwjtpt|szzg~|{{p~vx~yz~rs|tzyr}}p{wzv{{y|}lu{|{btnx~~zaam{~z}y{p|suz}}|zyqx|xu{xyr}n|x}vywwnp|cb|y}|xxx|tsv{wyzs|}sp}dx|tmnwlxwxsmztyzozzrz{oyysoxp}uty{q{ki}~}nu{ht~x}}wxv}st~zqspt|x{yzy~utyxr||s{}whu~~~wz||vtox|~nv~{{~yxPyo|r~u~vuk|}wv~op}xkp~a|oj|{|z|u~r||||~{v}y~{z|~uttyyzw~|u~}u}vp{ysyzkyxpvtv}u{zxx|z|w~{zmvvron{zvyzg|yy{xu}zzrxzvs{w{wnz{p~y{~wy{~~zznz}r~nzxx{zx}}{|yyuw}pt|zwvyr|{{|~twu~}q~zzxyv|~{omxyzs{zz}{yv{}uw}|w{}~}xy}~|{yur}|}sz{~xz~msz}quy|y~ut~{w}||z}||t{~r{{po~vn~um|{{uqwkwzzz~}~~|r}npw|yu{wvzk|~wz~x~||~sm}z}|~~ryz}{quZz{s{k~yqo{|}|rzol}wxzyl|gw~yyl}|{yxrxtr~{{wzv{yyxx}||}~wmxtn~u}q~tv}~|v}}}||vv{|{~v}~o}wtzxxxuvqtzxizy}lzktz~~{tyv{zv}~sQvx{~~~qpwz{n}}v~qb||q|wpqxusts|mymyvz{qw|oyyswouom}lyd|vv{vt|yswy~r|xskhuqnypy~vwvu~yy|wnv}wu}||}tm|{z~tqjxyl}tup{}}{}l~wvu{u|}kxyw~}rr{}{y}w}}}{{upw~}xzwuyzs{}|~z|}}w|vxiyprro{|~voz~oytljyvl~o~yolw~yx|y{{{|sx|~ruv}~|xy|~}~||y}zw~sv{~|muvjt~{mp}vtux^p{y|_tw|]rx}iw}ko|{lyu|w|}z~tv{w}x|n~n{wqxr~{spl}s|a|wx|w|wwxprku}w|~w}i}u}~z~y~{[yswvwt||gz}{}}y||o}m~myy~|}roy{tzsx{|}~y~}}osww{xs|u~~dystv}r~|vywb}wzrm|}uj||o~ozzw{}~st}}zw~~t}txyx}{y{z~l~xs~q~vy|{||{~}uux{|v}vxv}xpx}wxw~|k|rm|y~|}~ppxy|ouvv}stnr~vyyspsw}{qyvwz}t|u~qy{q|z|qjvryr|}{ou~}uwww{|{}p}}k{|u~w}juz~~t~sxu~}x|y{~~z|txty~||~{{}~~t|~{}w~gy|~|}w~m{on}t|~|~yuv~n|vorhlx|xh{vp}twvw|m~zvl{u|pn|yorx{zzxyt|~~swzxzyx}vnzvsv}z}|}|Sj}}z~skn{|mihw|mz}}yu}rkx~yz||n~yvumuf}}{{n{|y|w~Xr]|u{|v4vh{~v{|z{txuoms(iuFmw{k|{|wpzvT_~{wetzonyyntm~{uk}}z}v{{m}wpax~jn|pz}zupg}t}}y{{j{{quwxr~zz~~cw~~pppz|}u~wtpztnmj}x}m||k|{mz~x~y|yw~t|tuvz}qu{wzo{~~|zw~sx}woz{rv}{xwqvz~ktu}wwzp~v|yz|z~v|vw~xyw|}}rtu^|~x]pk}ku~w}mz|zkwr{zgws~}v~fwzs|~~}wz{q|wzzz}w{x^}xosp|s}~xtuowyshi||m~nymkvrzs~ty{wy{r{rs~y{}ps{v|x|y~|~~~ptx|}~u~|p}zx{{}|u~~u}uz|u}~|}}{}|p~}|p{u{u}||{|~~}vxz|ttys~x{{yxtu}~Vrwt_~|nz}yt}ygyw|sx}zupz|nq}}wv}{~wytty~~xx|}}}}|zw~u}w}pvlyvhvyy}~vqzwlz}z~|y~{u|w~|t~k~zn{vvyy|}u~zr}}ru|symzqzxv}z{uyl{||{wv|xvytus}k}szpxwu}zxz}|{xvwp}|}z{|}v}}zz~|}~x~u{z}u|vwyz|~}~sn|r{|}xys{s}zzws{zy~stxs{|z}}xau~vvlsxrrb|wws|ssx}|ueyxuslumy`hswzl~r\|{sp~o}{vxvg~{znxxowspkv{ytvz~|}lw|osx{}or}rmku`vpkzsk|sxxtynyyfh}y{uqt{jyzyy{vjzyx_x}f{tokvxwo~qkprrwwvs~~xruvw~}sxvk}{y}sv~vwutv~x{x~mjqhos{ox|rsxxz~||yyuq}|u|wy{yst}}{}zv{uyqp}}~~~zv~qrt~x|zp~ls~xuzvwql{h~}zs~|}n}vus~v{}}z}|}{usu{pvu~~~vwx}}{xyz~}yv}uyx~jw}|c~yuwy|pzdzp~{z~uys~vvjvwwvqtec|uywpt{v{h||rtzm|xyty|qysw}||vaj|vvsz|{xysrryuxqqzro~ykx}v|vx|w~vv|v|zst{xsvozv~|u~{~wq{r|}|xy{xpvztt{uszw}vy~~v|txw||p{xwwz}zzqy|}xvu}}~{tsutuu~~svvjv{zv|y{{~{z|}{x~z}}}zoxu~rrm||{~sx}}oz~tm|j|m|}l|~y{}y|zt{|{|wyy|}|suz}szzy{}yw}u~}r}}z~y~xgp{zy~}tvw~wryzpws}}tw|vz|y~||ou{~wy{|z}}~p|oozx{ur{zvcxuyx{xzxvv~{}}w{x}}zvux|ywtxy~}~{|rz~t~|}sx}yy||~xszzzt|yx|{{|y~szrqzrnwzr|x~n}{yso{}|q~v{yw|zvzw{vxzunsr|vv}~~u}urjzy{}v~xy{q{vsx~{|}n}zxv}|z~~wz~sw{vt}r{|}z~~{~y{~w|~{wxw}}r~|}y~{}yxxz{u}{}{y|{|}~|wysx}zwvw}}w{|tvztp{tr|tzvx~qsyr~}p~t|x~w{wyqr{usk|xt~sylzts{u}yy|zyo}}x{{|k}}{vw~{z{~tu||xw{yz|{|x}{xu~{zw~y~}}|}|~|z{t{xy~x}~yyzxr}xy~{y_~su}lz|~w{|vv~}xtq}x{mv~u}zzzzlnu}x{~w|}}}|q|z|~~w~|j|~z|}nrz}l{t{u~v{v~}jqyx}ypnvu~|{|vvr|~j~~{v~|uv{z}zm~}}|}sw}t}}|{}z}oz{pvrno}l}{oz}}v{wqrls~|ki{|zzxvqy{~u}nunl~wyy}x}x||yyzy|z|wtxsz{}}|w}u~o{{|qx||}~{wzqtz|vupusvxtxtw}sx|{|ry{|fr}|}y~uzxr~mzs~ws~}z{rywxuywyx}u~yyz}wvdys|stujov~~}oysm{uu~zmzww|pu}rvx{xuz~ur{{pv{z|~s}}|~v}|p{{szuzdzx~y{y|{tzsuzu~yx}||}{~{zwwzuty~~{}}~y~~}svu~}|^tyzp}sq{tz~}{xxpumfkzsyn|}i}n|{v|{z~||{w}wy|xqw~y}{{i{|~vpy}z}}w}p|p{|}ul~v~~xwuzo}~twtt}{{{r|v~wopy}xr~|}t~~s{||~|{}}|wxvz{|x{vyxxu{{}z{|n{|vh||{uyr{~~v~}z{~~iu}xx|vxxw}v{{v{|l{~}~}{rxss{}|ys}|qxwxukkqwnv|nm}~rz|{{yy~y{}|y}|vxxxznvwo{z~zzqxr|yx|}rw|wz{~t|~txyt}||}~z}~{xztty|~{}{c~}|t~}rpw~ts{sylqx|v~lv{yxv|vsvu{z~|t{y~}|zoy~uwzvnwworyusq}w{v{syvxz~t|yn|s}uustz{{~~t}}}zrvnu{x~yzyr~|~zw}w}yv|y||x|{}~xxy}yrwqxyxzqx~{y|ozllu||ymsy{ux}{v}{tsoj|j|dr~gzaxr{qu{}oxxu{r~v}q}~ywozyzzxnxsl}ugyrt}}{}yvxv{zq{}tqrowyu~lvyuzxzuzxwjtu|Uuw{rzwn}vw|}~yuz~y||}s}~nvpt~y~xul~snrv}ztz{{}|myw|iz}rysbuztr~t}vo{u{uxszyyx{wq|w|p|tx|rwrypq||~szz{w|r~{{wz~rw~r{~yywp{~~zw}vw~~xu|xz~zs|~xt|{|~~v{}~wyxpjyqttv}s|pzlw{~u{wv}su~{zluz{pm~wsvn{{yz|yexw{~s{tw|xouq}ttp~{w~x}prxw|u~}v~w}{wwv|}u|t|}}|~vy{}{uzx}|~|}rz}|{zvtz{xz}|~wgu}~}~muoj~~ot{xvquwpx~~y~x|utgyzxo|zzw~xvqpvs{{}~}xyyy}llu|yzp|qoz}q}zv|xv}{~{}tz~xnm|w~lh{s|zox|ysvo|z|wzz~z~|{r{||r}x{}~xt{}v{~q|nzvx|{|v|y|xvxh~yp|oo~o|z{yyowtki~{wl{xkzp~ryy|wx{x}~t{r|}}qs~zx{|~~~wzu|y}xwlvwxx|p{sy|yuu|}~nz}tw}vz{~smln~x|xr|~y|yv~}rs}~m|nm|}tjr{ix|i~wx|lo|z~t}n~p{vyl|oxw|tz||nxn{wn|~|xtvt}n|~~|vs}ox~}nrusp~~rsu}yp}wzw{y~vv{}Zyopp~{q||vrvo}sj}i~x|m}u|lrxmzv|}t~yzwt|t{rt~z{zrs{zyy{{}z~{{u}zw}v|~~|~s|ww}~y{yy{~x{nzpopux}zzwwortrk|i|tjzzl|z|t}tt}{{yp||{zrsw}{rt~|x~{~n}{zwuzoxrymwtwzs{mw|{~~}m~pp~s~|zu~{oy}{{sj|i~zzl~y~n{xm{~u|}w}~z{|yt}uq~{}|mv}~~z{~xw~vl}vz}}q{z~||ppt{{u|zyuzy|}|}|z}~~}~wt~lv}=xquc~z~|~}}htz|t~ys{s~yn}q|z~}s}~t}|{y~|yy~{}~|zzyyt}~{~t~~zbx|~sywxn{svf{}xpz|}x~tu|vrx~~{uvssh|}xy}x~|zr~zrw|tyu{~|wwrwz|w{v~~{zz}y}~{}y~vyvs~r}~gxxzvyzrm|wx~a~{zv~txz|zw|}x{ttwytr}|{s~u}{}ucnr|s}|}|~outxzv}p|}rvx{qyt{}~{|}vz~~}~y{|~~qz|w~ytx~{uv~tzxp{{pzs~q~~z}~{|}q}}}v{{~x{|~~vy|w~|~t{z`||tpop{~{|uywu{p{y~tkjyl}xy{n}}lxyx{tzuzwszv|qz{uxprvkx}||y~}l}q~z|{}w|zwwqwuuZv{o|Y`|xrs|}vx`dqroVkot}xxr~ifu}td{rwty|zk~yt}cyy~opvzyzk{{y|}ohkt{}rsxhw|uz}u|gup|{utrpxp}p}utzwyo{~|j{{mq}wvx|swzto~zx{huu{uzsrux|~syw{t|uqu|n}~gtnxusv{rvs~owtzfxv|ztxmw}u|{rvy{y{ixxnz||~|u|tu~rvk~zw}u}|~tzz~wz||y{xxqmu}~y{z|}{vy{wx~}nz~xkizquz}l}{o|z}}x{}{vxwz|{syt{yyz}ztz|~{w}|tz|~~~yuy||zz{swv~wyvz}{~}uxwg|wqqpw{z|~vxtspqxtlzirl~yzowxs{vy}~~uy~wy}u|rq~os~xx|}x~}}}y|sy}}|w{||nyq||zlpi~|yur~y{zxomu|zkuts~r|{x|p|h~~{nt|{y}vo}v~vz~y}iyx~{~}s|u{u||}vwsp{\x|p}w|t{vs{~x{|yz~}zx}v}~iy~zn~{|{{}|uu{y~t}ruz{x~{zy||ww~|}y{vuv}vy~{y~y}y~~zt}}{~zzt|}tyw{|~{|wz~}nyz~n~roluy{~~o~{tn}jztk||n~|uz{}x~~z}v|tvwrut}w{w|{|u}twy}vz~nwz||~oz{}rwqu~{x{~x~|}|~z~~}zzww{tsx}|z|zTqivz~tz}|zzR|t|v||xn|npQrsu{}x~dzxtt|uqv}s~ttz}y~juowvy{qrywz}nzvqrmk~vlov|vkwiy~lwxt~{qxo}vyo~{itw~v~^oxt}~|opv~qvt{w{x|pzuh||~v{|{u{x|`|opn}~~v|}xuwo|rxskyhzy{l|~{l}s}qyu~yuzw{}|q|ruwrvpry~|x|x~||x|~~y|s|vy~wuo~tz|rv{~}{uF\}xxj}|lx{{u|wsl\n|w}}pz{zqwuux}qcr{~{x{uxsgZ}xizuuexjnzpn~}~wy~}qYt{o}|oju~y}{||x|{rs|{{}yq{s~|yy|p}{w}{||z{|~ttxv~~~~|z}}wxvzovz|xuzs~|j{z}|}y}{ttj{uyy~p}|mxn~t|d{qmv~t}zm}s~|uuw{n||q{s~wy}}w{tx~|y~}t|nz~yyzv{p{put|}wz{vu{x~~xzwz|zq|}yr~{qmtpx|{zrz||||}}vtpvs~|p|ox|gi~uxkx}}}~~p~u}~u}o~|x{xy}}z{yxzz}}yxqxxs}y{}r|wu}z||~|vx{{~z}}|{yvmx}xqs~s}y~~ztz||z|~tz~tyz}}}~~|~s{}{z~||{ttxx}{~z~y{vy{rztwyy~~s~z|~pu{pqo{v}x|uwxps~{{z}}z{|}~wu||tqx{t|qymvmssx{p}}tsyrwvz~x|v{ys}wxv~z{ykw{r{xpzwnu}|}{||ysptz{y{rzmw~}~zz}{|x}r|zz}~ysb{dnvpmws{wyr}qpx~rwjqsm{pzxp|v]{w{{rxzwpzs}t{|xz~mlswvw{}u||{xv~r}sxlv~uzzz}~v}xxt|vzt{}|xuz}sxwwvt|zqwr}x}oxzs|vwyxtwxw{xt]ywzq{xzwwv|mu|wxsj}zwz}uxz{~|}ssx}tu|qpwyuy}y{{v~z~yr~{}y~}xy~t}s{z~~ss|zz|tv}y{{v}|zutvpm}xx|}x~gzx{|]|u}t{f|ksqwvf|uvtf~|t[|vpsx|rx|oxu~lz{|{|uz{{uy~|vyz~}twtz}}x~||w}ux}us}ztw|~}y~{x~}}|xy~fxy~~|yo|qo|v~~yq}oz|tkl~uyn{z|pq~svoz|}xwr}vu}||x}luzt||zxz~wz{r|yw}usyy~n~b{ruz{xzc}őrq~mytzu~z~~~{{v|y}o{~|~v}|~v~rn~mazi|wsy~ywquywu~rpp|xqww~wieky{nvxwu~{y{|xurg{}~zvszfs}yz{xmwnt~}{x~~t~ouy|y~{~|zl}yyppbynv~vlm{zv{~}|~|}{{{wx{|r}o{sy~xxwxyvx{lzrzq~x{yxt}vxfzx|wsuub~ezywol~y|e{ytqzn{y}xpy}r|vry~x|ig}tt~nw}{~~yzubtuuvnppo~zesuvxtvxtytwxt}zsryyttrxs|{g|{}z~uo{s{{|xxvuqvywo|xupzwxux~uzuvwwupyws{z{zydvz{|vvt|{|z{osspst~}ttu}osy{uzzxz}vu~|||xzzyxxwzuuqrqxr~y|{outlzk~|m}{|~l{}|{x{~wxu~zu|z{wsv~~suywz}yu{~~t~~{vy}x|qyzvrxtwpwy|y{o{|xwx~ruypq~}z~y{|xhz}~~v}v{{{zrzvwvx~oxtuirwpux~zywysuwwu}v|w}zx|x|y|y}}}up~~nyqxz{~{~v{s{zx||{{vtuy{}ty~zv~qpzz{}|y|~{w~wqz|}}t||q~|~~wwul}~pxtyy}zwokswym|so~}uix~v}w{v|{zoztv|wysr{z}zv|yu{}x}{us|yw{~~w|t|j}}o}x~y~vu{l|~n}pvp}~v~zuzoy{{unkuk}|m|ysx~|{|}|x{}wvyy~zou~y~x}~s}sy{xr~m|~x~|{x|jyz~qtr~{}wx|p~}v|ul~yk~~xm|{m{~y~}zxzyw~~t{ty~}|~qt|}}zw~s}w|u{}~~~w~zp}z~y~suxk~{{v}i~`}bky?wouot~wcdvxyx||kv~o}}}}}sz}wdtv}|}~wvhoxoxuoq{|z_{x{kssyuu~~|z~||~z~}{vty~~~uzp{z|~~y{{~ti}v}u~xt~|xv{u{}}{nx{|vu|ryww{sn}m|xx}|}v~}twmzutvyy~{{~~wy{zwe}{}rxlssszyv}{w~xwzrtztvy{xu}}u~{vz}~oyvnxy~xx|~xr}~||~{|~~}|s}w~m{w|zxz|wy|~vwzxyx~~~wz}xtvs}{wx{yu}}wyqyq}o{|x|zqz}}l|y}y|wxliv}|~{{euvx~xx~}o|}ẇokvx|{hg|vtx}xw~s~}~p{ihkvjvzx}plw~{~gytxu|~|vqzw|x{zy{~xp|||}w|u|qy~~u~us{ryku{p{t}v}t|yv{{~s|||xqiz{|z{|}o~|~o}iwr}}|xw{n~wjxyysy}|{pyx~|}xz|~o}zyfxoy}u~w|ir}vy}uu}r~}w{nex}|{}{wxxp{v}~w}ty{v{uywvx|w|}vxn~p{y}vyx~}o|{{yxw|}r}|~~{yt|zz}|{yty~~o{x|{{~sv}~n~uwxzzrnvxu}rv{xysg}ttt{}wzyz|w}uzu{ztz}{vwnq|x||~~zprmxlpk}ym{wr~y|{vv|wt|z{}pzv{t}{~uwzk}wws{t|}wuo}||z{{r}w}vyvxxyovntw|}{|x{tzt~vr{z{yvwz|z|vthtzy{|wn{w|~|r{woz{oBv}nu|ry|{|xm^i{{zv~|zy{}qvjxsrsso|vouvw~|urx}~vxnfwxxpv|x~yzcwsy^wws~txsim{m{|{lz}{x|}zr{iffm~{t{wuspoz~qo|x{~}ut}~o|zwtqsy~{yxz~v{wxqxwxwtv|~}~{m~u}s{{nnu}zr~|{iirtp~e}r~zl|wvnww~ktwm{~{v{s|~tzix{zyux{rzziv~w}}{tpt{zz}wzs}w||z}iwz|t{wp{~py}{zt~r{tv{v~svvxqt||yu{wsqzzyysty|oy{|w|}~ty|tzu|}zxyiq}yy~t}y|w~ttryttxsr}zvzwu|w|{|zx|}x|}xvw~{~y{|vr{~}ux{t|}{ury|v|wxy|zyx~{uzu}{t}~z~w|~x}xyvr}|s|y~z~w{~z~}wy|xwt}~txz~{}~z|z|~}{L~xw]~szlyt{}mjzzylt{{|y{~~}}}{|||b~zzqzpritot}oyu|x|w}vpk^Zyrpiqqwpwwwxlqcmorwumq~lxlv||}}wxrzotx}umqytpk}tkzzqynnr|}~nzxs|qxlty~s|}tvyzz}pt{~}sovvwk~myp~z}oyw~v{{}z}|r~s{xp|}}|}yw{x|y{y}qrz~||w|t|w~z|z{}styz{zw~~u|{tyj~|u~puon|z}|yw}p|vvtm}jnv|l||wnxx~z~~x{{y}{u{u{~trt{x~y~~{~~zs~t~uxwqvy{v|~wvyg~~|up}nq~}~yy}{|s~o~y|skzjzj~yn|vzz{s}|xwt}s{sl{vqp{}|~v|u~pz{z~x|ox{~x}~~}{vvwqz}|~pno{xzwzz|vw{oxwysixh~t}zj{x}ow}v|x}{~~yz}}r~us|pu|~o}z~o}|}{vyrvtz|qp{|szzz}{{}~~ty|}g{zq|nq}t{~qyw~uo}sk{iwk|zm~}{v~utssvwu|q}ql}|zxqx~x}{}x{~~|zyuxw{zrw~|p|zx~~}c}f~n|z{z|}}zmjLypyt{z}u{{~~yx|v{nwqwnt~v|~lz|kyrvj}}~ynymno~}}|}uq}w{izzsj|}{cxul~y|cuy~vnq}q{xsryx|~t|z{ots{w~~vs}zl~um{wmysp}~{uusuusq{u|~vsz}wpr{zns{~jquwqzt~v}u}{|~ut~||s|{ks|~|}xuoz}nzvt~|ovw~|||zu{rswx|wr}}jv{tyuy{~onz~}smw{{}~w~}~zslroz~~y~y{yxy}stxytxv~|vye]n~gzyl{{~xn{~qwhrj|z}ttr{s|gny}z{x~up{ozmz}}|msziru|~v|}w|qnz}~}}}{~u|{{v{{|x~z}|z~||y||}u|}{{{|~}z}wz}ys}zy~{z|l}yus|u}mz~zysx~y{v{{w}}~~xt|~j~q|zc}~}}}y~q~{bwvrws|wwvr}t}{unvv~}{{x~{|y}|wr|s}}zzx|y}}q~{wy{zz}w|~rt{{|wvz}cx}~`wow~m}}{j}~rzv{ymzi{~rzzw}~jpubtxn{y~|ux}vw{vu^}y{zwoxk}~|os~{mt}{v}{}}u}~y{~}sq{vzvt~oo|wvt~z{syyyu{ztp}mvm}xx}y~{x{o{pudu}|tss|~kxz|s~||~y~~tv~{yz{}{z~z|}||~v~r{}}yv~~|~{}||{~|||{mtzxir~v|z}w|~x}|y~vs}py}r}wy~p~{~xx}zy|x~o}uq}uoxr~tq}|y}tvz{}r~~y{y{~f|}|v{~~}~}uvqro{~qutpmzu}{yp{{}vyt}vvw|r~~|~}}~y|u~yxv}{mozyy}{{tvtyz{qy|}yw~y}|}~zrwzxvzl~puw{h|qu|~}v|}~v|yxwv|y}~qyozy{w}}rxvxvw}{u|~z|~v}wzvv}vuv|}}s{yv|}zivtz}p~{yrz|~s{zr||}|yt||xyq}||~|y{yvy|~{|yzrr{yxk{}mxtxvwzxmxz}}~{}{z|y~}zx~~~}~|z|zt~~~|y|}~}|v{lw{y}xr|}wy}y|}~szuo|yuys~k~~|v~ww{{}|yv~z}|puvy{~zzy{}~z|zxyyz|\zym}nu}{{tz|{{t}|}{r{}~~txz{}swy{||t~z}|r}xr|~|~zvw~nmw}{wvyoy}o~~~x~ynsk{z}}{zzz~{zz}|~~z||~r~|z~~ywyy|}w~v|{{zqy|~~zn}uy~zzxw~v{~|~v}t||usrm~zy}|~x{y~}{z|x~z|{{}|~z|~z~}~~~{}}y~v{~~{}|{x}}{~w|{|}vz|y}mxw~l{{}wy~~x|zy~rvx}z~z~zy{{p|{y}~}}s||~|}||zv{v{}xt{~zqxyysvxz|w~}}z~}}~~y~w{yux}}zw}q{wyy}t~xz~{}{y||xrry}ez~~{~xyd~yv|ys~{~|ytr||{~{wzzxw|x~y}{}~zd{u{}{x|y~|u~vz{~zzts||{uxwzn~vs{qm~wx~~z||}{|{x{w~}{}}|~{{|}~zy~~|{~}r}~wszxy}qwy~wz{|x|{~w}u}xvf|x{}sy|w|}wf~zgyY{z}vlwwx~|xjrmo}z~~o}wvzs|~pk}~{|~hlw}ycz{uymn}sznxwuzw{sr}f|}{o}w}m}x}~~zsyno~thy|yosylx~}yv{w|wvyz{x~}}~|~{rx}|~w|}{{}~wy}|~ppswr{}|myu}wk}}y|wz}}syq|u~~{ztyq~{~~|}}~y~y~v~|y~y{t}}~}{l|r~zyujqt{~~}v|}z~}|~pmyt~|~w{}}tz~|vw|~~m}t~{m|}r|r{z~y{~}{~z~x}y}}yzyo|{u}|}yx~{zwo}z|l{{~~~{vyw|yz{|ux~vxy{}|~~r}{~|}~}ww|sz}{tpo~{ky|zv}~v}vvzzx}}~u}|{{}yx}{zpy{zvt{}}z}|ws|y|l}qvhq{u|t|~z~{}~qny~}|lrvgq{t|t|~|}w{qny}w}}}ous|wjs{~w}~z{~}x}|zz{{tqz~z|~{lrzxhqyu|~t|~{~~zy|qn{z}y}~~ltyyhqzu{y}~vz{{~}x}}}q{nyzxstylyz{{x~~y~}{}{}xzyv}~|w{|~{}}{~}zqtvw|}iz{{l{}z~|yvw}wi|{oq{y}r|n|v~qy~|{~~|y||~tp|umz~t|{t~w|y~wtsnwpy}vpz}z|u|||~~uy~}ul~gox}yv}vo|pnx}}{|}~zx}w}|tx~{}}w}}{~~~}~|y}~r{urrrmz{}~w{v}y~}}~}||~z|~z|}xz~yu~~{sqw~xmz|~wz~}||w~|w{~|}}~|x~~xv}~z|xqy|u~}z|z~}|ytbd~{{~}~z{y{||tw}}~{zv~l{}u~}|t~~~~~vy{}}|x}y~yzu}v~~}}|pu~|mu~w}w~|~wx|}s{try{uv}}zythow}|ytyr~}urz{rktzsupw|kx}|~sy}oyshtu|x}|}~ru|ytz}~~{|}z}z{y}mqt}~ny~{|z~v}{cuzyxswr~vxwvqyz}z}~|}~||}{~{oz~}{{sy~xw~{tny{~wz}{v|}wx{}{}lwuwfyhqu|yv{~{}uyz|~q|~nywy~y|y{ozzzzy~u~z|}yvx~}~v~|~z~~yi}|r{u~u~}qz~yu}tg{|{}}x}yt}|~}{||~y}|qywxzzsxyrz}~|{v~y}z|~{xzy}t{z|x|~|rx}~yymux~~zy~}~~tv~us~z~{lqzkz~z{wx~|~yzwy~zz}{}yu~z|xzv{|}~}||{{v}zx~~w|||}zxtzv~myn||~{vyz{}yxu~x{|}}|~xp{v|v~}ys}~{|}y}t~wx|qqw|}~u|{o{zu~z}~}}x~w||v}|~~~lt{wiqu{w{}}z|qnx}y}}~m}vuztn~x}}|}y}w{}xxv~~}t}~y{~}}}rtz~|}{{|{ztqsn~wwt|v}w~y}vt}~u|v~~}}zy~wz}ur{owyyp|~}~~zy{uzwz|~}~|~}zy}~z~rz~nxw~~usyd|z}{z|zwr{vr|~uz~zzyszwxp|z}|~|y}ws|z|jvx~w~rkz{x~|z{zyl|z}w|{{z{tumu~oy}ir~v|~}v|}u~{}{y{rs|qz}~y~lrucuhqu{vv||~}~qny~}q}ypw~poy{~}{q~skyy|v~x}~l~w~|~|{t~~~u{v}x|~znwoz}~~r|~||xs}|z~z}~psvz~u{t~{z|{vxj~wy}}v~z}o~||nsw{k{sv|}{zt}~}xq~~~rpz}z|~y{}vv~s~{~vzw}{yz{|p|vvs}t|}zpxxs{w~xuwxxq}fwx||}~~}znxxvwozu~vwz{|my~{|xvvv{|y~u}vp}s~w~}w}xltwgq|t{~zu|~zvx}qny}|zqs~m{~yz{}~y~{}y}}{o{~|}uy~{y}s|w}~~ssp|}t}vm}xr}}~|z|~t{~u{}}{s~}z|yy}py|xy|}}zy}|vztxlptx{s|xv|w~u}w~q{||vstl~y}v}{y~}yw}}}x|{x}}~}~|w}}}}ouw{qyjr}}w}yv}~lx}tuttry{rmv~l{v{yq{y}vpx{~|~w~{qrxt~|~v|~{|{}~}s}{|~~~}qukpz{w|vbxkuw~{~t~z~vz{}tzvr{|~|ts|s~x|}{~|{{q~~xu}~~{}|||yz~{||~{|}k{uzv|w{||z{wy{v~u~~}|{|w}{yjt}zpwu}~rnv~}~|w{|yz~y{~{zuy{{|z~~x||}{}nny~jxzttn~~}yyw{}}y}|~||}|pw}xw~}r~|z|x{v|~}~}}}|v~{l{r|{j~qt~{uv{||}}~}~pmz|k|wuox}v}}pz|{mz_tyyyf{qwr{w~vps~~|tzm{|x~}||zm~s~`{qvt{psdr{r~p{pzvw{u}zyy{z}~z{q}|s}uvus{cyr}{~|hyy{z|~{y{z~p}|{yw}|{w|yz|zzu|~s~{{{w||iu|}~uwv}{}{zz~r~rx~~xz}z}~~}~~|wslfun~ws~qqttlzx{w{tr}|qeyygyanx}~~z~zv~wwnmxe|z|m}q{vxxnx|X^~y}zpmn~|g\h}s}xvym|yk~r~Wurgvzv|pytzg^qhcto{~{u}~tewq{}xqzyz}uyzy}|~m~ywuv}}{|yx}|wz|~|~z~vyw}|}o{x{{zy}q|{|w|~x}~~|yy}|y|~~~|h|pry{tkuzvvwuyyq|srnus|zq~}nz{|~~}|{||nrs}}{xot}m~t}v|vwz~{~x}~ws{}}{{~s}q|~}vwzqr}ql}x}}xzw~{~t{v||}|}uou|yww}}r|wx|~}~{lr~vhqu{vv||{~|}~}q~nzyz|}srpey`jyukw{~zsg|ropl{{{{tr~swjitt~~zynonzvw{y~zpuvzv~|xyto]~upwo}ty|qyqy}~|yy~}}{}}y{~~~{{{y|uzmz~{{{u}}z{}|~}{rz}|}zzwx}{|j}z~{yvw|u}~~|~y}x}~rx~{}yy~}}w}wx|wz|~x~rtnoxwy~}xo~yw}zwsuru{o~{z~~~tv~u}wqmby{yrutql~w~|}y{}x}{{~}{v|yy}}~y}}{~{}|~}yyqnyxyzu{r|w}y{us|}}~|~}|~sx~|z~xy|izzw|zuww|~u{yzz||xz|~~mvxc~}}}{zwv{xg~|wx|su|yts|sxy|z{yz|y{~z{{ynw}tw{{}w{xzuv|qr~z{t{sxp{{yyu|}lq}xgpu|wu||qzu~qnw}Qdyx{}rzv~nvxy|k}yqpvq|~iz~}{oxn]vxk~mw}vyyÉiuyuwzxv~lwryhy{~~}|vqkn~o|ozy~x~lx}}vn{ynwx{}~k~s~}ov{|~yy|}}|}wwr|~z}syps}utz{~v|||~ym]xkqvsu{atxp}{}o~q|x{{x{|s{wq~xu}z}t{uy}{z~t|v}t||v{xv{tqx}twvy}{{{zr}yw~{~|wuzzrtz~l|q|zsw|~~xtxt~{~{rv}}xv{||oi}|y~n~}s}z~wmy{}v~||}uq{~||{ygvm}puryxy{}}|~oodwv|kvqv{k~vjzlx}rztpx}vsp}z{y~|v~}|ypv~}xq{l{yr{~{wtylwzyxvhz}y}xy~m}}sshr}u|w}w{{q{r||z}w|}|n{~~{uxxy{v|t~ww~|~~||xumz|sqww{}w{}}z{xdz|z||ztqzsukf}xw~zxu{y||ryw{y|}z~tx|y|v}xu{yyyzyrwzvzxx|}t~y}yv|}{v~~pmx}t{v|wNwuv~x}wyx{x}}}k|prywnz}{t~{xwqztow~|}|~mytvq||vtuz|vx~{x}uxwzyxn}{ft}~p|}}{~~kz~wd}}qzzr{u~|r}xzuu}}~mqwuw|xws}}~lqw}{sz|}yozl~~xu{{~~}yvwwy|~}vv}zz~y}{xvyko~}|~xz~~|wx||~x}yqu{z~~x|~}~zn~uz}t|~{~~mz{}{}{{{v|}us}{}~~xwy}}}}~|x|mp~z}{x~{{~{|~w~~{uz~ms|~\vfqw}v|}~t~}pz|p|q~{~ry~~{vyt{po}y}oyv|~|wsyy{zyr}~|~w}~}t}|}v{|o}z{y}zkozyqyy~|yo}zz}{r}~yzr~|{~}zz~}zvz~}~mp}twmwz|vxp|w|z~zuwtxv~}w|yw~z}utiy{vzv|}~}pqjv}}zw~w|}}r}{x~zu{|w|zzz||y|xwwpx~|koxvV~{|}|yxtu_|~~vtx~t~|k}ykz}}{w|~vyqtmssyo|~zzuvwtvv~_{~u{}z~r~||}pxtmo|y}}{zys|v|saurw{vws~yv~sv~|r}t}|~plzr}|iqu~|{v||}|~}|qoz~wy{lqzgq~{u{~~u|}{y|~}~qnyyz{zn}t{|k{s|v|}||v|~~y}}|rp{{|~wo~oozws{~}vzxuvvt}s|sqmqz{zwzkygmqv|v~xmz|~}~lvx|yyiqu{{{v~{~}{wy~|qny||lsyhqu||{t|~t|zv~~zqny}wtrpm~ww{{w{z{uu|}~w|~{~|wz|}w}|~|}}~}ry}zs~~|}u~{yo{vt}~}{|~|~zyy{yp~~wy}xtq~zy~{ztw}v|}|}ujzx|}wwsn~r|sxz|xxu|xahx~~|kxz}tyxo}u}yujsustva~~|twjpw}z{v~mwky~}~z}ty~{}|w{{{{|y|}qqw}w}~|}}w~uy}||pv}|}}}u}u}rvzk}w||}yz}|y~~w{u{z~y}}w~vzw{~y~|~~~~}|w|~z~mqzgq{yu|||}s|~w{p|~{v}~tsuroy}{zms}wiru||xu|~u|~|~~}z~r~ny|~lv~soxhqu|v||y{}q}ny}}~~xtl}ty~~~yhqu|}uv|}yv{y}{~r~oy|y~~}|{m~w|}t~}|}}}{}ox~|{|ywzu{pxzm~|uy}~~rx~|W~~}z~yzzl}{v~||y}~|}luymwhq~t{v{}}}y{{qnxzr{|~zrx{zxv~v{vuuy|ix~x{}xx~~o~~xyx{vy{}}{puyw~xy}}}~q|}|~xpwwl|z|}}{p{~{w}}su{}{{w}}~{{y~|~{~p}|~~~}x~~z|{}xnz|xuvv~z}y~|rqhl~|{y}~zl{}z|s~~|v~s}z|zsz|u~tzz~uwx~r~z{zzu}{|z{zxt~{~}||tlw~~n}zw}~wx~x|wt{{{x~~ys~}wp{z{}zx~y|~xp}|{}v{{}{|}s{|v}uwnu~{}~z~zywjszhr{{{t}~xv~u}n|vx}z~~|~rw}~z|qx~~uz~~ls|~wiq~t{~u{}x}y~}pmzyz|}p}z|x|~y}s~~~x{w|xyz{q|x~w}{|}k~vs{wy{}u}w{|~xt~z|}v{|~}ys|z{y||quqv}z~p{y~v}}|~p~}z{yjy|x~{}o}x}h~w}k}xz||k{rsw|y|t|y}}}w}y{xzzt}vf{g]w}~}z~mutizuz~ywsvzx{z{{pttqsxqwp|hV|uqz{sy~n~w}}xxqvpgyzz}w~h~{rxp}q~wyvvxn|}x~vzl~yx}w||~~umy|wsx}|}sxxvmyz}o~~~m{w}ryz|~q{|z~w~yyz}|}~yxy{~}z}~~}}ppky{pqsz}zw~|~wzr|~t{|lu{~uw{y|yyv|{usm{|{zcw~}~~{~z~|{|~lr~vzltfp}u|t|~}x{{~~qnx{|{}~w}|lskvfpxu||}v}t|~v|}}}yur~nw{t|xy{~mt{hqu~|~u{}sy{~~yr|ox~~{lz~~l|~}tyx~|u{z{~|z|w~t}z~{t~q{rz~~y{||}{~}y{~||}z}o}|pz}}{yv{}~rkqz{t~}yv}y|y|{|}w}z~|q{t{w~{oyup}~z|yzz|z||uz{t`xx~t~|vqnuozl|utywx{|yzr}{yw~y~{wxzy{uz|zwr}yw|~|z}~yy{mrx}~kzz}yyyy{}}~wx~tyt{p|{~|w|~}~xz~s}}tuy}{w{{yx}~lsxxhqyt{yzu{~}{z|~pn~zt~z}ltwhqu|~v{~}z{~~}qnxxzyzwv|o~v}o{px|{y|zz~z|zpy~tnz~y~xv{~|zydo}o}y|nx~trx~uxy~~zz}{||wy{pzz~~uwxw}~{{{{h{}~|ut}|uqt|~onvzz|yz|{xp|y|}}}tx~q~~x}k~woxw}{r{x~rpy|v~zv{v~}y|~|zy~}x|rv}~~}{|~~y~p~~wsjy}uwsxz~}pstzz{ux}|wv}u|x|z~}u~{}|xoy{|xt{n~vmz{o}|||x{|qy{vn{|v}}~~{}xt}yty~{zz~}z}r{|{~|vz{|~}~~z}u~}{ntz}iru|~v|z~p{~y}rpyt~v}~}ls}t{zry}w}y~uq}w|z}|mrws}|t~z{z{j|x|xsxx~u|x}~v}}}}{x{|~}}z}u~xv{}~|~~svrslwz~y}w{y|}{~{zvz~}|}~{~|r||rxroxzxzovtzyv}r~x|zv~}{~}zz~}w}xqz}~}puvk{xw}z}~~z}{yv~|}~t}y{w|{}yx|yxx|qszmyz}|xy|{}yx{xny{~~{|y|zs~}|}nz~|~mz}xz|vz}~yxmw~xqwz~w|}|{zxxqy~wdsp|~~vv~~{~~}zzy~mn|xgqyu|ys|~~|yp{xroy|}}{}~~}{}z~w~y~}w|}vx~}m{~znx{w|r~}r~}~w{u{|xxxpv~u}s}}}|u^~zcu~utvumzt|||}~}wvxxwy|}xv}xw|tz}z~}wv{v|rxyy}|xmwzzzp~~{{{~rj|~{}~r|~t}{||{wy|}~}z}z~}mzv~w{y}{zp{vhzur{{s~zuz~uuvvu}vvz~}qo}~{~yyzy|uy{w|zxqu|ru|u}~wwqxmlx|{{|}x}{v{}{s}{{}{|~}wyxzx~~~~}zzx}}|wszpjzpznt~|t|vyx}xrvq~x}s}~z}|z|y{{{||yzrt{~pgzv{m}ts}vwnn{}o~t~~r|vs|{x}xq|t{~x{zzsx|}xx}~}~vu|xsw}{{vxutzm|yws|ywz}~~y}|{xt{{}}v~|x|wuz{twwl|wz{zu{|}x|yw}~}{}{{t}}w}{~}~u||yy{}~zz~{z|~v|{~z{wz||qvs~z{wuxnxxv|xzi{~qxz}vuvxwz|x{~s{|~|z~pxy}y~ty}|y{yz|{i{vu}~{~lsswgqzt|~t|~v~z~qnx}{~}w}~uz}}{~|}}q{~z~~{{ltzwgqzu|vu{~oywy~zq~nxuzps~m{~r{{|vz|y{xzy{~}ywxzzx~|~{xzx|}|~|wy}uz}|{}~y|~~y|u|~lt~ziqu~{|~v{z|zz}wqnzy}{wl}}|z}~pnry~z|zup~m|~{}v}{z~}zxy{x|}xwrt~qlx~x~~|}xyw{|~{|{~zww~||{z}|}{~~}~x|vzvue~xb}X\o~z}o{}wzy~v}mZgt~xsyw~|i_}js^o}|wkvzmspiq{u~{{luvyiq|u|w{}|}z}qnw}x|yxus{}}p|y|~z{uvx}zz}~|s{z~~{u~~v|}}z|t~}utyxnu{y{|r}}o}v{w{}s{~ww{y~}~zv|lq~yhqu|uzu|}{{}||vx~r~oy~t{}|}luwyiq~u{|~v{}|}zwqn|y}}~{|~pz~r}|}~v||sv}yx}vzwzlzzvty}||u~~u{x|~w}s{{{y}~z|t~~qjtw{vqszwozx}~u~f{|p}v}wwxpxmor}a{o{}{u{{pgqv{~ve}wyu{}cg|||yyr{{vxso|{yposwy}t|z}y`y~uyxzw{~rmxvwzqxx~t~z}|~~h{z|zy|wary||Zx}~~~w|}~}w{`yov{{zxrz~nnsr|vuqx|}ty{}y|z{}b~wuyo{{vz}ww}wyy{y~~{mw||ywyy{~oqvjy|zyw}{{wxx|s{|yy~|~~xz}yxzjv{|x~|t~}~zuzxux~_~~}~{x{}ol|}try}zx}|k~o~zq|}~izyz}oz~z~|~}v~~~v}tyx~zpmv|hq~u|~v|}z|y}|roz~{r{}pru{y{|puy}~}q}x~xx|zz}zt{vq{w{}{y~zv~wwuywh~s}~zz|~uv|}|x}onvvmzz~{|zs{~~yzwxtwzv}|}tyy}}~~y{~uz|}zwy}s|to~}}}y~}}|pwp|~w~|x|||z~u~x|}x{~z}~r|zyr~x~}zkxxy~}}{|}|twuzmn{wwv~}zz~~|wzxvn~~}~|}u{|nv~m{}}z~wv~zxwnx|zy~}~xy}y~|}uwn|~}{}z|||r|yqu|}}zupulz}yq{y~|wz{z~{~ty|{|~~~{{}|}~}y~~~{|~ls|z{wiqu{{~w{|~z}z~pmw{orp|{}|z}z{~s}pya|n}ku}d}u{wz]o~q}~fgxyoioxs}jWs~j~pf{{vx||hipZh{txuyx{r|{ysuor{~v}yy}iyywz}}}v|~wyvz}zz{|||w}o}x}|}~tv~|v~|lt|{Vthq~t|s}u|}}}~q}~nx}y|}z{vn}w~|zvz~yyysz|~i}~~wx{zywmy~z}ttztw{{u{|yty~_y{tywyyz{~}xz}~yx}}z|~w}wmyr{sq~y{vy~}z{}{}~{z}v~x~{xt~w{v}}}wz~ot{y|{z~~{r}n{{~}vx{wm}y|}|}{}v|yl|~}|uzzny~}tw~p}y~{w|y{{~~urwy}|}zx|~z{|q|y}{{}~}wzuys~{r}pr~sz~}~~upjx~yzxxlzx~{|z{~|nq~|xywy|}}|{s{{su}{|t}w|{}uw~|zzo{z~{v~v~~||ox}|w~ly~|}tz|}~|wzyyp}|}v~qn||{xt{z~|wlzzx~{t~~ts}|opiyr~ly{}x{~vy}}zpzyv~{~~wr~}zw~z{~tz|x{y}}}||~o}x{{}}|~s~|z}~}~~|x~||~w||~xv~{x~zzz}~lryziqu||~u||zys|xqnyztvt{w}xuv}r{|cnsxx}pu|w|vvz|ywx{}}y{}y||f{~}{}rx~{{w{wquvj~}|o~}l~~||zi{z~wvytylyww~pjv{}~m}|wvyzjpiosn{x|wywuwm{{xwsq}|{yz|z|}w{p|yy}~||}~r~|n{zz}z~wxwy~s}y{ts|kv{ryz}zyz}|~lszxhq~t{}xu{}}y}}~~~qnyvpwrum{|}}w{z~|{r|zx{y}~~|qwxzu|~}|}x}{{~|~}{twp|mnw}~}~ty{z|yr}}xzz}}{}}|}{r|rqrny{qy|x~{t|yw{x~u|~~~~v}vo{|wxt}stzpmx|{y~|xxvwq{z~}}s}x|}}{}ut|v~}~~uov}zjruv}}{}u~~z~x~y||}}|tzzs~{y~xt{no~zvzpq}z|}xu{tzy{n}{yw||vp~|y|{}~~|}|u~uv~|~~~y~}wtzkrs{}z~|~ywz|xnqyhmxp}w}{|}z~u~sn|~}wyzz{z}~r}||{tz}ww{{{z|v}w~|y~}z~}}{r}}|{r}||{v~~~y{qywy{y|}vyj~|y|}v~z{xxz|~wyuxyx|u}ztdvwxvizpcvpw{zk{yxzyzoz|wr{qr|qyxwpxy{~c{sszm|g}vyss~pyrpv{uzg{unmtzt}xvivx|twjqny{rsx|~uzts}t{xxwomymkwwvovvm}|fzjztyjqwix}{ptwuouwm|sjlrxyovu~wvrs|x~rzwuzwy{wtzuy|xqp{{{zxmpzrns~zjut|eryyuxuvw~uw{y|wuowu}xon~z{u|]}vDvvxrzt|vpkv~{y|~x~}{{ph{{w}w{ww{m{zo}soznxox{sqt{wwwpyouxrl||}}~|{u|pxt|bkro{~{|uzv~~}wx|~zs{uvsykv{w{~hwow}vtxs}v{|~rv{}yyz~mz|o|~}js{xnz{}}zwyvazztxz~}umx{}yww}z~{|||{xr~|z{yy}}tyxwos~l|tz~z|~{v~ty{u|{z~~{~untwmyzxtvy~ktswxi~x{yz|xxpp~{}nx~xv}~z~}y~{l|w~~ywwszsyyury~{~~s}xuzvv~r|su{{vyuxv}u}z~yxv~rs|zs~wuyyq}z|y~|zu{txwuwwu|~~{x|}~nw|}jozo}~{|xy~|wrm}o}q{|{s{xxos{y}xzum|}rm|~~~wo~|}zlsxz}tsxz{|yxuyp}u|}yy}i|~}vwy}r|}xywxxv|t{~w~{wv|}yy}zv~|ixxz}yu~{z~}~uz|{vwxyyorrwrrsu}{ywzzi|y{|vmoqvzqry{x|u|y~zw~pk|yy}swn~yx}lx{vo~{qxy~}~x~~v}}u}}~kx||vqr`{zy||utzu}wxxqqyztopyv|{}zs}|}nds~{trqx}|zv}|xqy{xt|{lzxyzzxz|~}~}zxvs{~{{wwmy{}xyw|ttvux{u}~u{{kttvzvxywz}}vvvyy~y{n~qu{tk~t}~|}~xy}cxz|us|sxvw~|}z~{rt}~|x}}{}|}~y~x{z{u|yxxrx|tu}wy{|{wt|}z}yn}wtz}~gl}o}|yu{||}w~{wzs|}vxvoxhxrywsurwmyw|xrxs|xrplmn{unvvsyspvrurx{swy{{uqwiw}i~py|q}wwum{zmvw{zqzr{{}{ty}{}|vz|upx}t}m}}y}~|szrqz~}|sy~mys|tzzqq~vzy|~v}|x}{v{p}zw|}zz~zzuv~{w{t{~zy{n{{}ywvtu~zwz{s}{rs{{xq|{z|z{|~{{|wbw{y~us~zu|~~|~}u{}w|v|||~{{z~w{z~{y|q~{yxv}{zxn~|z~wv||xxvzm{|}}r}{zm|y{yuxn~uxxww}nvushxq|x{xyt}}|kwwv{xp|vw}m~ve|zuyz|w{v|}l~xvxywxys}u}w~kulzxzzxv}wwmxks|rkynytwztnozsus{xuyyrt}x}}no~qv|{{t{q}vtt{vwtprxw~twpmxuwtt~wpqzwxp{tptxxt{vsup{~syry|}nv~ywvy}t{~ymzyzss~~}sxtp}wy{|}~x{{h~{{}{zxq}t}~~zw{hy~xx{p}kv|x|}{z|}{~|}l~~u~wzw{v}v{xt|vw|{}qz~y{}{|nuysz{p~wyz|z~{yvhyx{s{vivz{|yzwyxw~|}|xzxid~}~}wsyz~xrzvvps{rx}ut}~y~pswxy}~s|~vywt{v||uxu|tv}yx{~xyx|s}yo}z}qyyrz|z|}ytzww}vxr}ww~}qqzd~n|o}qos~}x}wvqtv|mt~}{x~mx}yuww}s~x{k|x}mzzvoyrus~vy}y~vzx~zazrz|{zrttz}tws~p~{yqx{s{~zvzzyv{yxyzy}zxu|~~zw}t|ws{|xowzxys}uuvwv~}|z~~|}rxuq~|x{}}}{}}u{wuuy~x~uux}~wy{}vxzntz}xwww{|z{~xwu|wf{|yz}z}wv{tu~uxx|}yx~v|{vyzx}|xmr~e|~yyrx{qputfrsm|r~zyuxpuzw}r{~|qz{uyrk|zxw}uxt|twy~~ywqt|s}zwp~yk{xuyzx~n|x|vwqyzzy{p~{zm}{w{|{z{Yfjrulzx}}m}~p]y~su~{{{uzy{~rp{||s}~}gx|~z{p|yvkw}x{p}|xw~|}ys}sfi}{vuqxx}|g|tur}p{x|svr{suyzyrk|tr~ovzu}wktyzsxlu|px}uryzv|xvv{z{ysp|rqyxzpxxo~g|u}v{ktxly~suywyxysz|voxuy|ry{yxuv|vs{vvvv||y|{w}|{ts|||{ntyspu|yxx}mvz|vyxzzyxv{|wxyu}y~}~mzxt}zz{xt~o|{|u|y~ywyj}y{sv{sw}xwz{xv|{|xcyq~}{{ro{uz}~|x{{zyt~vvy}ux{yvvyuw}z}}}yvyws{vx|xynz~}pws~vu~wx{|z}pu{jp~~vrowvw}{y~w}~{~|y~w|zzniq`z~kwkx}q~}}u\}{xmrt{dt~st}youszt`zn{~hzgxy||v{xWspxxsttsv~zx~v{vju~xl|pwzz}ymrr|z{|||~~w~{y|}wx|{vz{~~zuwvm|{|w{vot~z|{}|yyx}~y}|v}ftx{|qvw|rx~yxsy}x|vwy{~}yxwdup|sxst~jozzsz~vxw}svztyx~{x{yzy~uzwtxvxzu{}wxvy|t|}qy}stym|yy}|y~ymvw}|}yvu}rv~x~qtpxywyx{s{i|z}~tvvtx~tzry{put{q|o||{u~{zxr~x{ta~~q}iwyri~xo{xqywsw~}x~wu|}zw|{ywzz}wxv~}ywns}w{rxg}z}uuxpxtsvxxu}{u{nr~u{hn}~p|u|{yvw~nz|u~~qo~}~~y{v}|{|yn|}wuywu~|z~p|z}~u{{{mzr{v~vnpyuirzc{vvvz~p{|t}z}us~x|z{ys|}~y|~wx|yuytut~t}v~~x{yxs~}{t}xyvzzt{w~yj}wy~uz{}uuvf}ty{yx}uw|z}{x}wgv~}u||ow{st|zlx||~styy{urtyu~|u}t~{y{yw}txvzwuuy|r|xxw~r|uuxw|vxsq{z~}z{~}wy{wxr~~|wwzzyxz{ot}qzwzx~z~nnx{~s}sw|owz|~ui|xz~|vpxyguy}pwy{xs~|w~~xzthsx}|ws}wwst}us}r~sy}{uurts~yuxvv{v|yuxw~zvy~|}syv{}s}v{wzw{xvy}{|{v}wsv|rvsxry~{orim~o}{|xwx}~|{u}o~n}~xzns|~il|o|{~y{{{{~}|~x~~v}tlsy|z~y~pxfop}ux}|w}wypxy{|}vt|}~y}~o}s~~jmuo}uy}x~||v~~~{v|~r{n}xw|}|{n}uh{muo|wy}zyx}uw{~z}|~}~vyomy{tu~v}tvvq}}szwwv~|zwvxyq{|xyzw~wgy|x}}zvv~l}||yyww{vv~}yrv}|i|y~}z~tvt|v|zzr~~~vwz}~uuzvu~~qxxxz~t{|wsrxyyu~|xw{s|wuyo}zlz~wzw||zzv{v{x{vtyh|txzz|}tzts~{z{|{sz}{mv{zu}s|yvu~}{xux}qqz}l{zyzyz{}~|}~ymq{}w|w}tx{~uxyzvy|yqh|~}xwz}~~y{vv}zo}v~~~~}}o{t}y|z{~v{p{luz}uljp~vs{v|u|~zm}v{|m}}}~|}{uyyqo~yq}{hx|qgutu|tsx}vtv~}vp}{swnv}}}kuw{p|||lt{qr~}vyuf}~rbz}z{uq~{yu~qs~zv}}tv{sor}|}u}p{vzxwx~x|ru~w{vp}{{pt||{wuwyx|~{}fx}~}v}r}pv{z~~t|z{|y{lxwzpv{vtu~y|~~v~uw|{xj}szxrsxt{}~rzt~{t~~{{v~vz~wm{v~xyu|~}yxwq}yzuztz}}}xu~{yzy|}r~s|~y~|qwztq~~w{qus{|{vvvow|t~{py{|{~|o~zfzm}s||}lqs|uwyr~vzyov|y}}rw~qr}}~{||w~~{|zh{|z{}x}w|{ps~{{~{}uv}zg}s}wqvqvy~q~zz~wx}ww}}}e{gyx{zyq~w~uzy}w}|uz}}zt{xvzz~uux}z}zwp~~|yrus}~|uzspy}|ruzy{u|z{zs{|zx{ty~|yx|ytz}zwysyvzx{zy}zzx~lyy}tvuzuvzyw|wwz~z~|x|phtzx~zm~{rhrq}~q~z|wqz{lu}yv~|pvynz~n|xrxxtx}u}~{}~zv{t|wvw{ym||}x}ysxvuw{v~q|x~d~w|{yy{||}y{{unv~x~~||zyzz~q}{{n{t~|~{{y}~~yz}}~|||vyyz{znywyougpvp|x}|y~~~~{y|}rwu~r{i}}w~}q~xx~y}p~{u{xn~{w{wz{sn~n{y~wwxbx}ouzny{|h}zryt~jv|}u}q{}us{}|v|s~}}q||{|u~~z~|~xh~~z~i{zvkwvv{l}}yuz~}}|zt}slg|vvkxvzl|tt~ssyx|ut~rystyzyvvk}msp}u{vzxkyxyvxlt~qy|tqz|w{vv}uzzyxso|qtzxwqyxo~e|v}wzkvxmy}suywuxxx{|toquy{qxuxvvv}vs|wv|z||y}yw~{{sr}}|{os{rou{oyv|muz|vyw{yxu||ww~r}z|n}yuoh|m}}ozny||w{{~|yxvq~mhxutsuq{{o~qrsw~{v|~ywx}qszsy{xxuwp{t~{ls~|vxtvxywxys~{|y{txmnw~{wz|uzyr{p|povx{{ysr}~~sl~szpyu{zowyrw~x~~x{t}u}quqyzsy~syusz|t|{yy}{}u{y|wwys|}|{svvk~wx~x|oxzw{~y|tww|v|w}~qrz~uw||{~}~w|wu}yv~yr~~~ouwxwztxx}|vx|r{t|~x{|~~}urxk{s{~}~wmor||t{}{zxtpw{yv~us{w}|~wuv{zt|zr{vxtz~~szvz}oou~yvs{|ryk{~wy~t{cxyuz~x|vvj{~}~|~z{y}}v~zup|||{vwx~ye}~v|ulvq~ttvtely}{qyxuv||~~|~su~px|w~}rvxnor|}vrusrwrytw~wyum|s|yu{vzprzvzzzx}x{t}nsx~}nxst{}wx}xvx|~y|m|v{zx}~xxum{ys|xx||w}u{pulzvy{{|st~w{xr~tz~w}x{v~pwx~~|y}|xyzix|xxsuywtszvu|op}|umsy}}|ptzv~y~~u}w{u|~w|yx}yux{~yvws|zr|{rwxp}}y|x|t{w{|vr|}}x|lz~yruvtqxsqvuzqx|z}tx~}w|}wx~}}o~}x}yzyt{{yvt~r}{xz}hs||~n~z}{u|~~~t~~~f|v|xtzz{qp{yzwww|{|}y{{{|wy~z{zr|}}{{y|z{v~{{|nsimo|~y|~{}y~~z|uqnr~t}~~~~xm}|yzzu}z|{~|y}u~yx|pz{wo}{v~z}}x|vz~w|hzz{v|wq{vr~~v~uy}||wzuz~{wzy{yy~{zw}s{vwuy{wn{{y{vswtx|{zlxjw|ty|wzxzzzy}{}{ywpt~oz{xyy||z~~w|xfxx~rwts}|nzu{}{zz}x{vryu}pz|}{}~z{z{z~zm|zx{}v}~z}}ks~v|vzxcxv{}{n{wvw}z{zxvzuiezxuvunsxxh}rssk{y|uv~q{swyz{ri}psmv|yzvnly{svmsqx{ukzz}w{uv}tzxxxtv{stwx|ryxr~}fzv~yzotyoz~}uwyvrwxuv}tqowyzsxvxtvvzwr}wszw{|yuxw}|ztt{}}z{qsvsruzxxw~qty{vyxzxxv||xww||~}}xm|yvgmzn}w~||{z|{|~xytox}|tns}zim}oz{~wz{}}v|~t~}rm~zozvwvkzx}{zuxvt~~{}~w~{{|yttz{fm{ox{xwt||vv}nwY}ht~tzuspxxunutr{}rq|zyy|z{||}xzy}{{}u|~ss}~{zxx}~zzxl||}{vwxw||wpw|{z}xyu~~|{|c~xwyvzuooxhq}}zzx~v}{zwmonzvxy||o{{}|~}n~{y~in}tx~pvn~w{wyrww||xz{mt}uxu}xrutuu}yqbn}zzvyy~skv|rzyto}u}}wr{yzxoww{n{wzzrv~yk|xkzuzy{zmyy{{y{~}|{w~xw~yyypz||}ys~wv{z||r{|m~z~}}~~rz}}|{~q{yzvv{wznu|in}}q~}w{v~sw~|w~sp{wu{~}~y~zw}stn{ywrwv~vz{}s{z{t}i~|}wo~}z}||o~x}~|ouuw~vs{}}ww{tyv}pu|~~z~yr~~}nvtzwuxysv~}r}||~}misxx}xwnz}xx^x}x}{vzlffo|quyv~y~sx~}xxozsp}~|zmrzhlo|||{zzxz}~~wz|rnr~~irwzx}u}~yxp{u~}|znyy~}sp|y}nww~qvz{{zww|~vz~|s|}wv}{vv~}zw~y~~yssx|vzt{|y~vz}|t}v{ysy|ww}k{|w|||ny~pzyxx{zw~|}ywtkuzyxsvsuxtmv|zur|~smw~y~}xtv~qv|wuxy~}{vwy~|zwt|ytx{~wn~zz|z~|vxsvs~usznsyxwvrztzwvxsq|v~x~}y|~}{ynsmxz~uuzqp|w~mw~||uxt{|~tv|ztxn|tz|{u~{|}lhqspptzzzp~|x}~}lyu}e|m~mtxz{vrxs~wx{{x{{~nsnjz~mnnxw|{fzz^s}trrwzl~vi{r{mns}vz{vmwz{vwzuzy{zvixyqymy|o|}zzjvpp}vx}{xx}vqqu~zvlwrwww~v|||q|}p}y~}s~{|pv|tzz{y{ysf|~xxr~~yvxwy{zs|~wv}tz~u}zzzw}zzzw{y}}~{x}t|v{{}xp{~{{yt|u}ww|o|xp~|lmq|~}}p{t|y~{~|w|uq|{{~z|yx|wz~y{ux~yw{~}{nqq}~~{x~{rxy|y}||y{w}~thy~{y|xzwpp|}v{~|~~{tv|uvy}|v|wxxyh}vvsuwzwt|ru}xi~~uvwp~y}mq~wv|t~zt}x|~|qzv~wwuxu}~x~|yurs}vvvw{~xpxy{yw{mqw|vr{vxi{oxtnnmpss|}~z~s|tu|y|{}zwz}ivs}owvyvpvt|yxw{z~vs{nxvvvz}us~~nuxw~sq}y~|~}}|xyykz~u{{sy}zy}v}yz|}zzshty}vpuv||zw}xw|||ynx{}wx|~{usxzyztzww~{|}}x~zv}w~{u}}{{u}z}toz|pz|y|z}yxww{xuj{~x}zv|vws|}~}}{{un{xp|{|vr~x|x{ww}}|eurz|wstsxlw|yz~y{{}t~|yy{uww{xzz|zy|~~}xz~v}w}}z}wl{}}yk}un|~vv|{s}z~zrsquzzst~o|xlnkyx~wr{xvx}w~~~z~exxxv{}hvx{dr{}yh{uzw{vu~s}ynpekk|z|ns~|xr}{hs}p{{~~}zuqont{x~yx~w|z~txwvyxuww}x}wutt|}{o|y}xmvxz{|yi|y~qvv}wu}xxn~yp|~|hm{o{x}~v~vrw{|s}sn{x|zlofm|t|z{}~|xw|zuwsqyqktmx_rl}vmt|{fzrxzmhptuu~vrzqt}di|xpymyss~syw{iqhfzxzwkqu|ozfxlwwdnjvwyo}zlhvgq}yy|~}jp|{bmGc}sa]ha}Sx|vzttpiq[onimhw}pqyrx}{sSspqozl~yz{qwwo|q~~vu|xv}|~tyiurv{pz|}zwspxoz{ry|wxx|w|otyxx~vz|{|xyiq}x{{z|zutz}|zw{vxuy{|z|w}r}tyvs{{|pyv{~x|m{~y|}}v}y~~{{xmx{pytyt{y|x|{x}|}x{y{}yzv{||{zqum~ky~y}ty{{yx}}~xx|}mz{vutv|kjwtpxbw`quspyiwq}}ad{yrn}vp{||w}mtpqsyfttrpqw{kvblep{ybu_srk|y{uwpzxqp|}fvo~ovvqypwjqd]w}ydopxtlpw{ouw{zx~ovkzzzofTi~wvjw~zyxxY}xh~luy~y~~|uk{~~xzw{~~sw{z}{|~xty{kxy{z{}}y|s~y|~{ty|uxwr~{yt}p|v~vx}}}y}}zzyutuky{vr~w}{v~}}|x{uty{}}{y{z}~~{}jvw|}n^rpsq|trQxx}}|}vu{~x{~vsyx`rp{{nxy[swzyzuy{ys~\~}dqwq}xs{}z~wyqsq~sw}pyx}zw|v{rpr~wvit||xyyhxpu{u}v|uxg}vxwtu~ov~dirp~{zz{x}l~~wvr{hu}}~k~xqyttzwyq}~z|y~~|}~{}oy{}z~}qlzo{vz{~{z|~zz}oy~\~}ls~xyrspqztozr{twu{{}zxxu~uw|z{~vyvwzzx~x}yq~wi|{~wyu|tp}vvx|yynpimuo|v{~w|uzz~~twrn{{}t}w~zzyy|wvvxt{{zuy~~yy{zt~zz~|x{iZs~z~mz{ytrx~~tswp}~jsyq|q|}nmyjut~wopunqw|}~wqs|yu}~a}wr|r}~|zz||ri~w~z}yztw|xtv{xo~|kv||vxu{z|v~{{xxz|txxz~|z|~}}{zfw|ywqqn||wv~rv~vr{|xvr{pvxotwwru{{}vzwoy~}uzyr~wz|orh}v|w{yw~{zwumzzrxzx~os{{~v|rwj{|zvyyw{vonvwmzvuy}pxyyzzos}~nu}w~~usq{{vyqpuzrzr}tz|t~|ywvqwyytvuywvuzxwvrvtutu~wwzu{ozuvz|}{u}r~uwp|yhx}tx~qs}{v~~}|pkzryu{}{x~yud{~||eszxtywy{lyyv{o}{mv{}~uy}|rw|y~y{uv}~j|yyzr~}|}yz|{t}|l~y}~}uxt}{{w}}}~~ly~}pzz}t}}|~{{y}}wzvwbr{zzrsy~u{zv}y}}}v~vu{~{tzwwzts|vz~~}zvwus|uu}vzwm{{uytxv}vz}xz}tw}m{}}zz{ywyy{~g{rzyyy~}wzq}{xp{to}}|}}~}||hsy|~}uss{sr~}}{vz~x}s|{yy{|}uzzv}syvxr}~}~}zqu}wy}y|ep~qiwsf~~v~}zvyxwzuy}ql|mvtucxomwqy~{jqur|vqaxxsm|orw|p~l^yy~qnxx|}vusws}ovrrj|zthu}pvpvyrywvvtqwqpzxptwnjzuzwykrr~nwpryuowsp{}tlkyrusz~uzvwpzt}nvsspxyzyut~{zqvxwvqx|vrtrjo|wjuuzptxstszy|w|tzxw{|~z~xy~nr{~|i|losx||}|s~}pz|}z~~x}vvlhntvxly{}fsx|nyi~~y~cz~|xwk{pcyotkrs^d~n~}|sx~rwssqqm~u~q~ltrvp~}{u~u~w|zz~~|xxywz}}un}xsxu|qdusrytqlzzxu}{qyx~yx}pht|pwllwvxv~spll|vuvt~mxjwx}ru{g{qw}pzu{z{wnwvvtjs}utyv|}}{sws{sn{sz{ttyxt~xvuvuv}kz}zqsxbt}yzzvmqypywyvkt|sw|z}yzxxx|rqvvzyu|}vwr|~}~psztov~~wmrc{}xs{xz}|w~}yx~y|{t~vwut|xl{vz{yyzwity{uxzr|nwx{~}~t{msso}zrmp~a{~y}vv{t~qyqszqr{|j}|n~vttt|{tvoqt~|uz~s~~v{\~s{voxxuevpmqsw}{ymvvw|~zvpsqqwj|wtmn~|p{stqy`tt{nu{prvxyxwkgsp~iqzwxw^yvwswkr~m~{rhytzsxq|rzyzwonzqqwvxoxvl|e|{{u{hrwjxwpsvtluwz|smhswxnwlwsstzsozvxw}z{vvu{{votz{|yynqxrnrzpttzwsxztwut~v}wtz{~wuw}|yqs{zlq~s~~sx|y|t~nzz}u~|vo|vn{}xz{k{mjstx}{zk}wxr{}yy|~wvwri{j{wvultu{|j|rqp}ezvypw{o{rqxx~usg|sqmnzw~twkyxrwjq}oq}ui|xuyr}rsxyywppyqtuvuouun{f{x{x|kpwmy|{stusjuwt~{rnotwxpvtwrstys~qyvswxzzwvv{{xru{z|yymsurns~|vst{lrxztwww{v~wu{{|vv~|}w{z~x|}}txoru{{zsg~u}w{}zzmxtzxqq~gx~s|{{x|~n}w{bvmjpvtp|v~y{xpl|t|thtv{}|m~xz|}|{wqwswxm~ysp}{i|qruql{x~}ts~srrxyzypk}nrnt{v}vwhz|yykr}ozsg||x{wu|u}zyzrm}ot}yypzxnb|p|tykvykwxsswxqwzv{}vnou{{oxpxquu||r|yy|}}}y{w~zyrr}|}{{nq}spwylxx}swz|yyvywyv~zwyzympywovzvjz|uywv~}sxq|ztuzyy~}x~|~|t~lsu{u|xslpxtm|{|q}|qmrwy|uxx|zp}r|x~~yoxs}wyy{{xppv{~}yw|}yx~y~||}q|r~o{~r}{vs}|{~n|}u|s|v{yy|~{{zwyzzz|u~~|x}}y}x{sk{klry{yn}}~txttypt|}x~~sy}p{}~tov}zjlpo}xx}}}|}y{|u~u{n~~|tw{|yk{z}~x{rxv{}syh}w{wy}m|qw{uy}yq~|||z}~~cx~y}{~tru{}~zpwz|w}tx~|{xz{{~w|~~{y{rt}ty|ynz}y|qvzwymzmuztzm}|}|~{ws}us}x||v}[~y}{{r~pr|~j|{y}~~t}tcy}|xs}vvk{}~~|{v}q}}z|{|w|y~z~v|{twv|wwz|}{~vmw~~yzzqyztzqmjvv|uqszytucpto}z|}pywuy~|||s|}iz{xx|}s}kyzznwx}vrr~y{zyu|}rr|x}w|xy}|tw}lxy~z|vvw|n{}xzwy}w|x{cx}}}z{qqqvzw{xty~z}vz|x{x||{xz}v~~}zxs|~|~{wnyzz~|qs}wtu{{txv|fzt~}}]tr|}{yss}ozdBvow{{szyzsje>nymnzz|{{rxz|t{z{sk}~kl}~zyqxiys{o~viw}}b^uzx|v~|y{stywvzo{yztj~y\z{|{zzwv~~yx~wnxrim}p|~zxyx~|~u|u}ro~~txxyzyy~twzzzy|}y|xy}r~v|nshlwo}~~{~{}~|~}zz{wsnyxx|ot{imwq~r{}}zz}n}}}y|to{|y|~six}{q~~utf~y{qq{swv~}|zkxwzov}}srywz{v|~oq}|iys{ukx|mtxol{t|tsyxywt|x}zzz~}ysx~~}~lx~~}uzyn}~}uy}n~y~tsh|m}|p{wz}}uy~|zzwqmy}nu{ilp}z}{z{o|sz}{z~w}{um}w~y}}~}gw{{}}w{{r~{wz{~|}{|~xx~vktrv~o|}{v{w}{{~|yw|vgyy|qq~zulsyq{|y{~zzw{x|}}{ztkw}v}{t~uwy~yyms{|{xzyxwbvx~zzse}tgp|uzwhwvxo{|j~{nl}xv|vmz~as|}}{xjyjvxwf{ynvxx~z~}xvwzv{bmf}~r~tzv{}{w`~rj}||z爚|quw\n}w~w~{v{~ssywzfrivyyxz~}q|~lu}zy~|w{rix|~xz~txwsy{|xx{sz~suxsv}{{s|~|y~~|yyvypyv{u|vk|~ys|~zp|vg}}z|uor~v}|w{y}{xxtpez~qlt|}ts}}nvx~lysy{|pfm}vtx|~|uzxrzw}~uxvqv~zxzyyxs|whyzzr|xot~{uyqz{l|vu}xwr~|yv~~|{}nr~}|{tt{zu|t~w~}u|}~yw}zkp|k}winuz~{oipzju{ny~x{r|quvzz}s}x{{vmvy|x}|zxy{}|x}|zyxw|{s~ixz}~oyx}tw}x|}y{y||}z~{|b{u}~r~zp~w|t~~x|zzuyww~|w|w}zyy{w~|zvv~s|~u~zx|yp~yz}|rruyvu~xz~t}ot~~jl}p||z}}}|x{~n~yw~~mx}|xyum}{y~por}}im|q}~zz}x{x|~|}}zp}xwrnz{~wnx}hmp{}z|{|v}v~sl}~qwp~zxruw|w~v~zpwxrzy~wtvy~{xz~}||||ntr|~imp}y}}||~{k{u{z}~xv{yuny{n{jmuz|yq~nyu}szw~wz{rt|{fqzwqxssn}q}yn}~{xqxxwz|yvsv{uo{x~yxsmr|su|rw~}y|||k{xq}r|u||ztvkzppw|{x~il{{}|{lqxw}|uxes}~|}ryy}{|pw}qsp|}xu{|ou{{wy{pmzo{zzwzwwx{}{t}z|r|wqr}~}u}t|vzz|~nvshm{o{~}z}y}~uz~wqm}n~uvu|uzs|~~xuwftx{~~vqz{s{}|v{q|}~vx}|{v~~{ttvv{}|{~{wvyq|w|{|}|x|v~xyyl{uu|{}}|{txvwuyuum~~|}}z~s{yuqf}~zxz~syzuvr~w|u||~kxzy~~vzzwtok|~t~wszuyvxyw|t}|xxyzgvqz|n|u{rsyyrrx{r~zyv}|rm{tus{}wwtvz{wy~sytyvz}wxxmu|w~tzrymz~{yt}{xyvzyy{yxv~axxuty}|roy~u~vtuvw~v~{xr~w\yw{x~{zyqwwx}~z~{y|uvzqxp|y{x{|vt}wz~|syx~p~tz}|xu~wxwqq}}}n|}{r{u|{x}x~~n|w}|{vh|}|m~}zxr{y|ywzxuzy~xysw{x}upz~w}|}vzxvpy}xzzvy{vy|tzzyf{z~y|y|}tuypz}y{uuyxvzxvx|v}{wtzoe}zzqrv}rts|lr}{mmz{zpr|z~cnyu||~ytuxyq{~wr{uxy~zuyu|zxvss|xl}}vwwyk{~vypyzmzvt{vpz~y~x~uzv}x|{|}|{v}{~{}|||uzy~txux~u~~pypxyz}~w|p}|x~|z~}z}{w~}z}u|xorxzhmyo~}w}}w~x~qz}}v}rm{d|yxvsztyuxv~{v{x}~}v}urx|oxy~}s}uxz}w|yvv~xyu{ywxx{{z~{{|y~~uxtq}||wx{q{z{y{z}s~}uz{|zwwtu{{uw{yx~oxszzw{wxi{~xy}rx~uzsl}x{vzuzvxz|x|u~v}|x{z~qzyt}~}{prvl|t}y~nyzx|{~|xts|}hzzwqswqwtozrwu}zwsqrwyx~lv{yuvr|{p~rkx~uzxuyvuyv{|||x|~yxok~zzy{m{w~~|zv}r{lz{{zx}vz{{}oyw{zxzvs~|uv}p|xlvxmwy|pyp{ysqyw}yy~}~u{v}}|xux}~}|yk{n}q|xjx{z|x~~|y~wvrx{}xvyu~||tt}rpv|}v~y{}q~~~yz`h~onwlmq{wzfzy|f{s|yw{vruss}qzzdyynqfx~uxzpqo~cxvo}om{y}ozv~q|}{i{mpx~s|r|yovg}~yt~rwz~{xylq}yo~zqv||t{ur|{s{wz~{ynzsrsv{{ns}yw{w~~mz|ou{{srpyy}zxw{yp~x~zz}~`qqhx}s~it{xv{u}v|v~wyvu}|{~r{{yxpzw}}w|~tzxzwt|wt~uzyp}{~u|}pnt}wxx}{vx|~z}}ms||o}{}|y{y}suw~|}v~vy~z|l{yszvz|ztp}woyrt~zTtysez~{nrvm{}uz~||~sz}z|||ut}|otxy}|v|vv}o~~v~|~}{~xytns}xilo~~z|z{}}}{}~xzvsmyt}tsuot~|}jl}o~}}x}{|z|q~ywwyz}|wz~tm~~}wr~yx|o~u}jmpz}zz{y~{{w}~y}wrlw{yv|vtwtqz}v}}q{lyz~qrv}z{{xwyvixxxxsr}yxqx}f}|tzxpyx}vttn}m{yv~u~w}t{yvm|y}zvz|ag}sufutwzuttysmlqyizm~vx~s{~}gkuwtt~yt}w|xm{vzs{uwy|stzxqwzxx|t}xbzysxxpsx}vyszzq{jxwtqxov}||_{wt{zxixqxwxy{}vo}hu}rvytpuofrxno}~u~|vwrbvpuryzt|uy`t^}|zn|t}~vwxdyyvywouysurtstiv}{ruuvtmtfpwmvn~|qdsx}xqgszpqu|zrqmw~}qzuxppo~t|um~~oqqq|svqpowzyspp~|rqxttkuuwsszs}lrntzl{wrxmx{tw{p{ssrt}x}pzywju}ty{{v~zv}qu~|}r|y}}zyz|{r{{{p|{}}y{~z{x}|xvluZ|~t}wt}zsxw}x|uwuxwxi|wx}{{||wvd~ypw{ytzvz~wqz}zxz{wyz|~jtw~uxx{zxtpy}nx}zyw{r}{|}swvv{xnr~wu|xuxxxywvt|}wv{lq}y{k{|i~{lw~}yy{}{z{{vzuw}rn~{|~}zo~vrimpo{xw|w||tw~~~xvs{p~~n|n}~vosim~o}||z}{}}~q|w|}v~sl~dw|pmnytsszy~s{ouw~ws}x|}}u}{{yp}zv{tzwwqn|r~v~vu{|zwypw}}}xynxpknu~mzzyxy{}p|qrtx{zy~}lr{}trs|jx|{xfu}nx}x|{uo}ssoyzyv|oyv}{{u}z{z|{tz|sxwv}~{|{hxttrx{v~u|fwzwtw}}xvumvr~ww|~yk{{{vyzpxutzt}~ww~}z{tvy~|fn{{l}|}~wuz|yy}yp\l~m{ts{}{xyj|xx~yxpyyzyx~}}{zy||{z{rt~zyvx}whz}{~~|~v}xwyzts|zq}muzxvxvbwtjt|xxq~}}}n{~|zt|yzw||~|s|_qz{nzxot}z}{lw{{{x~}yv}tg{f{uvxnx{yc|wwv}syy~uw|rzsv|}zzsistq~r||~{woyzsymur~{wf~{{~v|svtv{zzyrq{qs}yqrwwo}e{w|x}osynz~svywpwyyt|uqtvx{rywxttv{uszwvvt||yxx~|zss}}|z{ptvov~zxvxzouz|vzxxz~xwz|wxxkwzz{{mwtw{wszyzp}u{xw||o}}z|~w~qr|}x}|~z~uzz~}{u|wmy|}{|pt}o}zy|{q|txx{~}vn{~}oxi}y~u{zusr|~xt}|uh}mwy~||y~zw~}s~qxysu{x{z~yv||xxtrxl~{xys~}xzv}ttp|u|wol~z||y}|~~}zp|wv{j~nqv{~|~||w~z}}}ywnqm||zpqzq{xuowv{vz~}v{uwoszt{v}{~{{zo}{krvz{uwyrssys{{yj~xutu~trukmtz|pvxx~us|}jtu|}ruy}nyh|yzs~yzsiwgyqz}u|fqxwzvuyyx]{}xzywqqektnnkqosxwsbm|rzbtu{xuw}y}||qpym{}w{spxyu{}yzatyvowx|nmyw}pw{lpx|kn|s{yv{n}ust~}i|s|ypww|~{nxy{|zzysz}ox~yz~l~yy|tzys|~|xw~{x}x{t}xbuvyyzqiuzyo{||y~rz}}x{~{uz{~wzwuzzx{~x}~zxyzt|ws|~v{xmz~{ymts|~vwws~vtkzy}}|x|xs~~~pz}vw}~}}vuy|}nwozxe{~~|xq|{}vx}wy`lr~w|vs~|hs|xlspv{rtx{|}zx~|xu{z|z{yt{~|~w{z|x||x}vwr}|}v}swxvu}}s{|}{m|~{svu}zu||x~~zuw~{~|n{z}~}n|y|r{~|}}}z~z|{{{w]rvy}~rzqz{wx}s|wvzu|~}w}~~|t{xxywwzw}{w}zw|t|yr{|wpy~zywtt|~vttp|t}}y~umtvryy~zx}t~v}{||||~{{~hw}v~so{{y|q{}z{~~y{~w~r{^|os|z|wr}mqz~zrs{tz||zzwzvz{x{s}uuz~y{||zu~u|uwwjvw~|m}uzuuw|uw}v|}~rtzu~tszq}||~vs}}{zr|{|zu|uyx}}wvu{xkzyzyz{{vtvvm|wv{zswivuz|{|zwcr}t}wtsusqxvvnlx{t~ovwzttzt~u{wu}||vsxyx{zuyt}}uyv{{q{tk~n~mxvtz{w~}xv{mvzvtu~}x|uo~p~wjlwp~|~}{y~x}w{x~{v|un|jzrz~usvty{~~~}yztz~|}{vz|v}{h{u{qylawvsyxzu}xztxnwyvu{s^}qzsvnnu||kyrrs~h|wwru}pxszwwxvug{qr~lvyw|zvnbwvqwjtzos|tt~zvvyss~syuwwrpzoqwwwnvxm}k{t|wzksxly}}rtvtsvwr|tootwxnvxxtuv{x~pyvtwv{zxiwv|zxrpz|yz~mrsqmqzutr~dsxyuwv|w~wu|{}vvumyhsvvts}xzo|qt~yo}wtwxz~}{~|{~t{}quyuyfzrstpy}~r}x~t}~s{|}}}v|~{|u~s~~yvuvzyrpvy~|ypy}sysvmp}{uw}nivz}q{z|y|yvr|}ptlzutpllr|}xtevz|o|vzzwqoyoutxwutw~v}oum}{yzyvwyyourmxnmwrjwwz{lt{zo~v|uym}vmxw{qgs{uy~trxu|zo}uwqzuvx|~zt}swzuyu{sxuwt}{soxsznzuxvqy{x}szpwwzy~v||}|m}|{~{uyuz~xx~s{}z|rys}zvty|x{{{}{{z~{qf}yz~{qxtux|}swy~u||szts{xwypv}x|}}{w|s{px{{{yp{z|rrs}vxt~|x}evtyt|}{x|owxy|w|{}y~|syozz|vrx~yy}ruw|m|xsuuuw}}}|zx|op~zs}k|xzz_qmyq}{~}wpzs|u{n|\{{|oyrr_|u~~owwv~}q|uz}uoqvqqu{sozp|~pl|soou|}vw~tt}}sgv}ysuun~t~|ozz~wzzu~w~||q|u~{x}uz~|~yw|{uy{{q|zur{}}px~p{zzu||urdzstvxscv|jt{xx{xy|~~zs}}~lvu{y|yzxx|}||}{yzu|~uwl{|vxw}uy~xx}sx||sxyt~}ryzszz~~}}xzvv~r}ov|z}}}q~yv|xu|{yzyx~{cy|{|mx|qwrs|utw~yw|yy~|vz}}}u|xw{y~|w{}|zwt{xs|}}yj~y}t|xrr|}~uu{[~x{}uxr}|ty~vwsimuvy|wuy}wypi~{ltw}xy}su{x}qz|twpnstyr|s}|u{~{{|zx}}xnu{wu}r{wzzn|p{~sv~u~{|~|zs}w}rv|x}z{sx{|}}~{~}zuuwr}yp|zv{~}{{~}w{}q{ypowjm{o||y{|~{~{}~}|~}}x}tlvsy|v}~}||~|q|r~qz~|{}qy~r}~x|}|yt|u{~xxnu~il{o}~x{|zv||{~uzw~yxwsmwvu|w~wyxy{~|yxz{v|y~~|s}|uzwwr}x~z{tl|x~|yxqyx|q{zv|qvwzxsx~}{xuigyzwqwtzts{zrtnjqz~w{lq|x|jtyvv}vrz|{|wzuuyywxvz~{{~{yv{t}snvwwq|~yyww|{v}~vr}y}z|}u}xwvu{y{|}~{~z~uvn}r~imyp}|{}v~||j~v{|qn{x_yxsx{~t|{~}|sƐrw|y|qsx}{rr~|wyzj{x{}w||m|tt~||v{|{{kyuw{t~{{zlw{szw{{s~w{z|xy~y~k{z~}|p|yvqu~wyzy~w{buz{{r~try{}w}~ry}ww~s|~|y|{~x{xzzywxw~~}zwzs|zuwtwrz}}sts|u}t}vxz{|{rs|t~ox}k|k~yzrb|l{y|ww}w}lz~m{z~l~zz|o}pt|n~wy~k|~Wxsmq{~z~s}z{}yz}|owv~twxrvwyqwvu}u|pv}y}zpzy}ovyim|~p|z~{~zv~|~}w{rl~w{zy{~}yu|yxt~wz~vyuixi}}{px|~}}x}yxqsv~~~y}xt~xx~k|x}}xqr~xx}ww}~{v{{x}v}||~wyys{y|y}x~}}yyw}|vzzo{v{w~{ssz||wuv|u}~{nvz}tzt{vyv}{~~vs{|p}p}{oz||t{{{w}xz]t~uwt~zv~vwy|}|r{wx|{~|{zz|w{vy{zxw}}}yzpx}|zw{yx}w}~|tzn}o~~~imp}{z{~|nxqyo|y{|}}v}~uns~|~y}nwthmxo{||}}z~}~{~}w}}~yvvrm|~g||uxvrsx}}|}{|{zt{y}}qxyq|zzz~}{vq{q~~p|qyz|}yz|zo}}|x|~puxxd}}}wzwwqrxz}yqvw||ytyp~yuthtw{xx|upxx{{}w{x}~z~stpqv{ruwyzz|}yt{xly}}kzz~zwvxlv{i~t{z}jzzzu}{~|u~x{x^pvo{|uzpmxX~}rxsvyzoml{wzidzxtmrm{o}|{}lrwv~|}ruy}z}|~wvnjo}|zexnmn~{sy}|ftykdof}l{z}zzzvwrrzxxm}vv|}}{n{zv|{{wt{~`muv}|k|oy{s~|xzt~}]z{os~vywq{}}}wzuyv~t}||}}|`xrz}tfyujwox{dy}z|uz}~wpzq\cxuxt~wv~b{suwk{n{x~nt|otqr~xyypg{zp|osxizviywzpwjp~n{spzzszsvs~rzyxxpkzplzwrpwvm}a{n|vyjrwhwoswunvwtz{rmvrxyow}{wurt{opywuyw{{xzyu|{xpoxz~zznrwmuzrvu{ssx{uxwux~wu{z}uwm{v~~~r}{pt~zj|zrw|v{nyy{q~|v|wtx}{yyzvwjz{z~ztrv{ixw~}w~{yxuxz|x~|og{zyyvyxutsxpqrwwxxy~x|~povp~y~{w|vy~su{yyxyvt~y}u{}t{}y}y}vxqm}wz|z||wtsx{wt{|w{rn~}wqx}jly{Ssnml}wq|}u{uvt}~|zogrxai~|wx{~w~}~|z}rpj~~~txoltzz||o{wzity{v}u~o}|{t{x|z~~s{{~yovimp}yy}|~|~|z~v}~~x{ulzn|xrwp{|w|tnxvw|~||y~~yoxz~{y|~gtwu~|{r}|tyyr|s{}xq{{~rlzox{wwzpzv}wz|}}yy{v~yzt~r}{t}z|{~~v{}}x|{vuyv{q}}xxxt|~ts~|m|u~ty{x~|x~xxya}w||kn}~o}xww{x|z~w{wv{x{}||}sl|~{yz~|xznw~g~}x}||x{o|t~xyi|xv~o|w~w~xxr}w}u|y~xzvrz}y~{xl}b~z|uouvr~ssjtrxssqwzrwwwy~~xswz~tzwwwzx{~vuzzxuvmt}xkxvt{zh{zvx~zy~xpwx{yvtr~~kv~z}vyvt{{|zyq}~}~nbz~r}}~~wv{y}qw{yxt}z~}py~|w|||oy}y}gv~p~~r{|q|wtystt}{yxox}~~vxvrwu~}ytyovuy|sw{||srtxzwqy|zy{{}w{|syuyqzy}xw~yxput}|}rv{qy}r}y{uw{s~yz~j{y{|x~}swz|j~}|ryx~~{o{{euuw|{~{|{hwu}sr{vu{r{x~}{zo~yv|~u{|~{wx}z~zxz|}~wzyt|~}}wo|{||}ups}uuuuxxyxq|{ywztznx~vxz~wpvowx{tzv|qvz}j~v{zxi~zz|{{zxw{j}{{u{wtqxszt~t{zdqxxwvuqrws|}qutw{v}u|{w}s}~sq|t{||r~wzuz}ywv}vwtw~}}zv~rs|~t{|r{xot|{xy|{z}{ttxx~zw{y{u}y{||~zz|y~y~{}~yxx~~~zx{zww|zuvz{~l}x}}ytws~|x}{xuw|{wz~|xvw{kzxyzzuut~wtxqq{~t|vv{~nvzwx{~ysyxy}}t{|w{tx|~}u|}}}ywxt|wu}|yp~yn|{z|~yv~twz~}wrz{|||y}}nw~}hm~p|~zw{||}g~v}pn|ny_{rzqwxr}lkipe}|{l̄{sq{ozb}yjwv|{p|Oxnv|_qsriovs}{{xq{}zez}}wyzww}|tp|}xwrkmyxt~vsx~zu|y{~~||~vx{|nwx}lov~wu~jm}wo{|yxyz~|}}~yy|{v|ws~m}yp|q{|}quxrz}ywuzs{|q{tv~z|~||||}}ppw|{sop~}tywmyx|v{yptwq{~sy~{|tiw}xx}xyy}w~yyqtuox}|w{x}y|yv{|{{ts~vv}q|}p}p|pz{zz{u{t~~|xss{rmwr{}{{|xvyzt|zu~vvzqvrwyx}uyv|{yt{}{}{{vx{q{z|{~pt{l{nz}txy|l~yww}{{m}vx}|}mvtp}t|wquys{r~u}}}{y}|}}lr}|}xjpyzy{utut|y}psy~vsyjrzzot}zqjt}ylxmzvmzvvxw}w|zw}txy{{|{wy|v~}r~zwo}w|||t{to}y~uzxzntsuy}u~sz{y~xwyt{}zrxvruv}{uy~zz~{{~ws|||k~}xxsio|{u|zt}z{zo{yyqq}twz~~ryx~}zpy~|yu{vj}xww~svtuxylzueru{{z|zvusx{}|~st{wu}vy}wzwtwqzst~|zz~sw~{uuuezu{|zz}zuzs}{{}{uynwwwrwov~nsswwwn}y~tttsvtwr{utruwou{uzxxvx}zuy|sx~p|w}vz{p{{y{r~|xr{{rrg~w~}q|~y|sw}wmw}l|z~rw|}zb|zrz|s|{vx~{x}x{~}|s}{lxw~v}|{{qizu~|z~w{|ut~}~y}|wswz{u|xz|~z{z~}yuqO{p{z||m~|||z}zpy{v}|y~y~~reszwuvjy}xj~}sw~yv|{|~~}z~yw||~}|{zz|x{|t|{trx|~|{x|uvw|xvvmv{~{`wxuuxtp}mqxnx`oxyzyq~tzzwwkqq|usw}yoy{t}~wg}yumgz~vycw|yuxv|yj}ww{{yrq|lqtmow~uqtxv}z[syvv{~vxxdyo~f|zu|npx}wywky{|ryu~w}z{gz~l{}i~oy}w{hx|v}|pw{vx~i~xx~zyxtn~~ty}u}{zw}~{ty~r{|v~wyw}y}{yu~~|~|y{~zuyy~y~y||}wywmy}~v|{tvx}{|u~yyyy}}||wzv}|uwstzx{|}nyx|v}z{p}y{y{s{v~|{|~{x|~}t}~xzyx~~|xuysw|{qz||z~}~yxw}mz{|vznq}zjmzp~y||}|}qz}||~~~|~u}toxu{}gyrq}axzypu{zz~mrw}t}q}|znzxwuuvwp_|sp|{x~wo~zh\{|ynpw|l}pw|w{rv|sqwr~|xr}z~|{p~pn{imztrwrx|X{wy{nutz|pq~u}vvqptsgxqwxmpzmwp{vusvmz|ynw{}~~m{z|~}~|woxyy~wvo|i{}~zykm|spk{y{qlxzpzu|wyuwquz}y}{xyyvwxrwtzxsxyy{}z|~{vy|z|z{vxmyq{y{o{y{}orvoz}|~y{xw~z~w~y}nt{hl|o}~~}zz}~}z~q}wsn}~x}{|z{|wu|xv|{}}~xvy}~wwy{zzz~w}|}pmx}~ur~xtvmx{uox{zy~v~x}yzzfy~vw~}zrzuvnrx{ot}ssv{uw~{r}xw|v~xy~rv~~}|zwvs}yr}yyszp{|yyxzu{vtv}nzx}gzyzv~zu|x|yx{{ot~oy}sqy}~z}|~yzfzttqvsu~zq|~vy~z|z}v}zy|vxz{z{|}~}|vzzs{u}z}vsx|szv{|vx||rz|hx~yxz}vr|zy{}|wk~p|~o|{uyu~{~{|xtyd{vx}zvrvpyx~{l~~~wxvuv}}wxy|ypyz|}xwx}z~|{y~q~{~{zutx}zwry~{{xz}|uyx~|h~x{xtwvqs{}}|{}}xrqxmz~xt{yy|~{u{y{{va|qvw|rxsv{lyx{|w~x}zx~zxyvuuqz|~w~zz||~|wvtuu{}|vnv|o|sp|wu~}t{}ur{zvpowq|}r{|}v||m~~x~~x~{{qy~s{or}~yutzu|m~{}w{srxwqk~zsiv~x{tup~|yv~~yop}|~}{}x~cw|~u{tr|ystur{{l{zwqxzx|y|}yzx{y|yy|ypw|mr{}wyz~z}unu|v|w}x}t}l|}|qswvxv}w~tzvxns}t{}z|}y~x~|m|kv|{wnusy}tt|wt}top~w|oxvxz}|~{{~{o}mv}lryy|~oquqmg{{{wzly}o{|zl}w|}~{to{~{}{t{}{x{x}ttyys~|~}y{|w~zxz|yj}{|{vyzl~|z~wyvxxxxyw{z{|{~~rzx{|}x~z}n~~|~||us|s}r{{}z}}|~z{v|~s}pywp}}y~}y|{}v~~{}z}x~~|}x{{rs|~~~v|s}}~~~zzt|~zkz~vtq~up{t~v}skxzxcq{~x|swt}{~veqsp}zxxruw{yuxuvf~uu~t~y}{spvwrnxvt||{z}yqw|~|}wzzn}{eq~}|~|~y~ds|~r{~y|xt}zsqvuyz~}|}z{~yz}zzn{xhy|yvvwp~xm~}zrryg}{u{r}z~o~sz_}qz|yytwv~yuxr~nxxyq}y{zv}s|u|yn{yg~|~z}w}~~z{{~{vywzrt~{zs}~qyzxx{z~wxww{{~w}~z}~~kycou_xwwq{rdq|jyqxv||{iyiy|rpjsizoT~v{lw|uvf|}pj{u}i{qml}yzka{y}jhyyj|vumxuszkykynrpyyt~qvfuy{utugstqfqyaxrtrvovptpunlzduwqr{qtwwvvsvmpqptz~yxy}lhv}{lu{fvyoxwtqv~mwlp{vzkuojpqdmxwkutvsnwwt{swwxo{{x{lxws{wwgzpxvv}uyv|zv|vwzlyy}vtstlykurxyv~|}fyxts|i|yvqy|zpyrr{w}vd{yq~o{qz|{tyrw~rvtxkm}r||wgwurvus{swvwvpwuqitvpqsuqzvty~zypixqzyvvrqorwrtzuruxuvruzz|xsruuz}qwxuswywv|uyw{trxywwww}orosorzpr}txuqxyrywqv{t}}wyzxyt}~zv{z~~wv~|wr~{y~z{}}}}|x}y|{|k~~}}qpw{~zu}tvs~yjr}mw~}|t~znx{w|vy~yx}xr|s{~xw~t}{{zw}}}zx{lxltyk~xkz}~w~v}wz{|}zwl~|~{~rwxy{z{|}zs}n~}{yyw{zx}{sv~~vtqzy{{~z}y}~|~{~}rvwtrxtxsngthlywt}vptsoluvnslpu{ofegpgzmo{ywyus}j}pwohroutxgtf}q~mrv{wwztj|ywytqev}Z|vrqurzxzxtuupu|fiuxorrm}jft|vyxvkumpf~|xwyqvx~vtlnoutyot~xtptpntx{zw~mjzxz{mrqu}kx{tsuzjtgumnzvmtzwxksqox|~r}~}vh{w}}lphstz|}{vq{lsquz}xxn{|s|{}{xpx}|vruskrvwywy^ywsxr|mxykxzw~ovqoxv|{zbyznpnzy||}nytywts|ilrv{ut}}ypvtr|rvwuukutodtvonnsnvjytwu}kfu~mzwttqopqvqwzrnruuvpu|}{vsotuu}txyuuuyvtwxt{tptyvuvv{lrpwnpy~hq|tvzpvwpwuluzt|{txwuwswi|{|z{xk{sovuvwztuvz~wvjwv}vquskpyvvsbxvs|oh~xvzlv}yovrsyxxlex{nmpyq{}vxpvwt{inp|}tt~wrwvq}tyxvwnpwnjvviortnyj{ryt|mkvlxz}rttrnswox{smstvwovv}wpqtw~~qxwtwzzxvxxx{sqszxxxw}lpromr|~pt}tzsrwyrwuov|u~~xzxxwt{{~{|{}{sryky}{tu{}ry}u{}}x|zzm|}z|}xz{|sj|~|y~}yxz|}z||vxvj|xt~}~|t}{|x}||z~yzt}{}oyy{yzuz}{y|~vv|xqt_}vv}y{yyx{}|~zyy{}|~{||}|xm~|}xhys}wvtyrnxqyyzqyuqz{~yfzz~wsvtrtxvxy|k|yv~v~kxymx}yqvszzyx|e{|qpsyv~wytz{svr|kqs|vm}ysywrzsxxvwmwvqguwopsupxj{zzv|njvo{zutsrutwux{upuuwwqv}y}xvquxy~tzyvy{zxvxwyw|uqu{xwxx}oswvor{}it}txyrxyrxwtx|v}}xyyxxtwwy{zyj{z{s}tz}zs~s}yqx~}}yu|ul~ywzx{xm{lzl|{uv~qy|vy{}~swtw~vv{jwwszx|}yszsvssppsu{qv|wvpzuyyxxy}zuuwxpw{zw|zv{~wq}x}~~z{wwtv{rqzyyu}wxww~}|s{ywxq|wuw||z|{y||{xx}|z}{{tts{txqwu|psz}x|{{{vx~}|zz|}~vv}x{yix|zru}~|z~~z|~{zpyzr~zzvts|zzozzlz{uwz||vsyvsui{v}wtxrk~qxuyvmy~_zusv|j}yusx|{qzr|zvnd|wrpvz|}~xrdsurwlnq|wiu{svst~swuvvq{vrisvspuurxlxy{wqkyr{z~vvtrxsxttytrpwuuru}z}xtttu{~pyvty|zxxlvxy{usv|yxxx~ornzps|}kt~syqqwzsywux|t~}xzzyyuq~|}zxwz{qw}v}z{y|uw|zz~xu}{~rsw}z}yz~muctytoeyokwxwxztxyqyvwsgzv}vtxsgznvuwn~{y}{zsrskvvqx|yotqwywtrb}zxpovqz}ywstrttzim~r}veu~rvpq|qvurunwspcsulopsptiyxxt}peuoyw}vuqoxqwqvyspkuutptsw{wupsvx|rwwt|yuutuxu{tpt{vuwv|mqlmnozbq|qxrovxpwvqwzs|{zwxvxsy|x|x}{{q|{w|y{}~~~{|z|u|o~|y|xy~|}|~w{|xo~wqrxyifvywzxsup{u|tzj{y|xuxs]~tvyyuz}e{usu}p~xuty}{puryzvwyrdzvrozsz}|wsoqtswlm~r}yh~xzswrtyrwvvvqzvqitvsqvuqwiy|zw}pkxr{ywvsryswpvzurqxuvtvyz}xvsuvt}rywuw}ywwqvywzxsv{wxxx~otsspr|hs}sxhpwysyxtx|t}~xyzyzu}}yx~suwznsu{x|w{o}s}xzop|||t|qzpxyzvxw~|p~sp}oz~}~}vn}wq}|~xutut}|yyz{|~{kt|~vyuv~~~}}htxk}{z}ry|z|zwz|ykwx~u~~zssz|vryxv~~~{~|ty}~~~x}|x~{mvw~}~|hv}u|||w|ttwxz{}|~{|}}{~rzkz~{wtpu{}trc{nsw{xtxpysqxw|xhx{|vsuthvktywxuy~zu{wrr~kywsy{xouruzwxb|zpp|oz}rxuxtst{jnt{}whvxrvsrzquwuunzspetvpppsquoy|xv~pev~pzwvvqooqvqxytqowuurt~v{{wuptuu}txxtxzyuuuzu{srw{uuwv|nsornpyjp|rvrowxpxwrwzs|zxxxuxs{}xyz|zyw{k||~|v}t~~z}~z|m}}ut{~}yx}|r~{|zossyv|t|~}z~p{}u|zsw}~vx}||z{~x~|t~~~~|~x}u{{nkzqmx|vwyx|wt{u~vey}|wsxt`ttxzt}w|{k{wq~s}o|xvsy|zptrszvznczxqpsz|vxt~wptswkkrw}xpx|svrtzrwvuvqyuphtvpqtur~vlyyzw~pixr{ywvrqqrwrtzurpwuvstxz|xusuuv~qyvuv|ywwuvyw{urwzvwww}orstpr|gs}rxkpwysywsx{t}|wzywxutrz|zr}}qntv{xxr~wp}v}|xfx~wsztfqvzztzd{yryt|rxxnxzxpvspywz}wcy{pqmzx|iystwst{jnr}|wm|zqwtsyrvwwvmwtpftvmoosoumz{wv~nhv~o{w~vuromrwvw{tppvvvqu{y{wuqtus~tyyvwyywuyvyu{uruzvvvv|nrvwopz~jq}tvvqwxqxvo{vzt||uywvyt~~}{wz|x{ut{{yr{z}~}|~~y}w|t}}v{|}~{~wi|z|}wxys{~}}|vsxy~x}}~ov~q}|j|~|zzx}}z}qxxtyw{|ty{w~u~zu|x}u~~~|lzz{}y~q}{uzvsz|}pz}xy~t|f}{}|zz~v{}|~{wuyk|zyx{vy|{~h{zpwqrxl~|yzyxl{xpyxvvyvt{tz|~znzv~xsxtszww|vyq{|vezvvu{k}zwry}zpvsy|wxf|yrorz|}~xwqssvsxlnr}xovtwtsswwvvqyvrluvvrwvrxuzy{x~qlxr{z~vwtrztxpvyuslwvvrvv}xutvvxrxwuyzzwwxvyx{tsw|yyxx~orryps|}lt~txvqxzsywsx|u}}y{{yyuu{|zz{gzxvzx~ruyytx{u{wj{v{uqvsj|nv{uxts}wzfxtrr{g{yupw{{oyqxzuypc|wqotzz}yyxs~qvurvjnqw|wlsysvrt}rwuvvqyupjsvopvurywlyz{yrjxq{z}uvsrurwpoztrvwuvru~{}xrsuu{~nyvtwyywwuuxx{psxzyxxw~oqkwos{nt}r{upxyrywvw{t}}v{zyxu~}{~~{u{|kutz~{s|{}}|~}~}{zz|x~jz}{wz{yzuu~x{s|}|x}|xz~z}{y}~|wj||z}|zx|~~wtwx{|z|u}}wv}wzuv}z}}~}t{v~qxzul{y~~{|u}}z~u~t{us|}ywx}}{~||yy|}~y|{}}j}}~z}|y{u~}z|puvs|tzxs~~~}{|~yw||{{}|{~}yt{{|jz{btztrixpuuzwuzr{r{swufzw}wwutp{pvuytz}~n{wtq{m~xvqx}zpurw{w{{d{xqp{pz}wswnurykms~}wcwvswsszsvvuvpxupivvnprtqvkz{zw}piwpzyvvrqrswqwztqmwvvrur||wurtwx}qwxuw|zvvxuyw{urv|xwww}nrrunrzns}swmpwyqxwrx{t}|zxzxxti~}w|~swtt~zs{xxz}|~{sopk~wyxlky~xw|vux|g}}wut}|p{~zxuv{yv|lx{m|vhoqqxttnysw|w~xx{||~rkmykszyrwi_|vf}lu|otw||wpvs{rz|w}tyr~xvt~~o|}vvuv~}svzr{|}x|{}uxszyrzuurvp{r~fulux~zqu{mqv{vrun~wm}|{xtzxxzlwsu~~l|qx}stq}kvy|lju{~mv_yr{v~r|p{rutait|ukmn~o~wss{q|j~l{vs_{}ykp~rw~r{y|l|p]}x~k~ovyo|yvmwrwgri~sc{~qxsupvwlvtu|usocuuip~sa~viqxwsynqlxutsrvmvxlwfyosml~vr~xptnng}|cutgzx}wqtvv{g~qo{vqtvjjbqmowmqxxqttupuss~|l{xx~tuvpwxsx{rhvsqkuty{ouxurw|vsnsyzmsrz`yqq}p|v{vpwy}ug~~tzzlh|rw|e~^}wz~lny~w|vw|xjpyiqrl{wovwovk}t~pyvtuqwwsfqyrxlrnznyqwsznalt}lz~usvqvssoxppnzpwpw~t}yztztwr|~wuft{yyytwxysuqvztqsvqnjtgoxozruvnlru}wtupn{vz{w~q|yykz|~o{~~vuys~~|wcv|zywn}}oq~i|qkt}|}q~xqun|}z~vts{w~{zk|w~zv}puv|q{yv}zw{x{y}~vt}yt}ynxmp}slwfw~py||vs{xlyxrl}{y|zqx}z|y~v}f}ox|~xml{pl}uvpy{pqvyu{fu}|ysvsdzri{s{rty}vxvvwixuw|mnys|}m{q`yyl~pz}|}uwxyxqstyirmxyxg|}uqvpu|ruwtuq|zxhnyrxmttroz|yr}riv{nz{xuvowtsqytpsmyrulw~r{}ssyqrs|rxvms|y|wztyyxusxzsqrv~sokrqpy}fvzsxvrtvxxuv~}s{wx}wwqtrs|vupzonv|yxyuzwq{svtmzx{wuwtgufwxuxtv~}qzurr~mwvpy}z~pyqy{vvc{vqqxpz~ywulptsxknr}x^v{svqs{rwvtvp{upjvvoostpvey~yw}qiwpzx~wvrqtrxrqztqsvuvsux{|wurtuw~rxwtxzzwvquxw{usu{wwww}nrpunqzir}sxppwyqxxsy{t}}yzyxxt}}zy|}x|z|~|~~u~{}wwx}wx{{u}|{}{|{|~~~wxx}znz{v}}xxy~tlyg~|v}xp~zxjpz~rrovujx|}}{wiot~n}{sys~{otx}vti~{~v~pzxqv}}o}|}lym{jcs{vrvxn}wvv|}njw~]{vm|lrt{o}yzuvqmo~yvDypsoqrypxt~roiezltuvt~xz}oszdw}usos|zqpcv|io~~y}nwsq|m|wyhy|xyz~u~~y{}z~vu}u}|{|w{vz|{lt|~z}uw}~|}~}ht|wm}|z~sy{|zwzzzkxy~u}~{sv}{vrywu~~~}~|ty~~x{}y~{lqt}}~}hw~u|}}w{uuwvz|~|{|~||r{k{~{zm~zz{u~z}buxs{}yxs{zr}|yyy}|{~~~|}|}{z}zy~z|jvu}~t{uw|xyst|~q{}~xyufy|ykw{w|zyzq{~|{zx{y|{p{~vxzsy}|yqt||uvvwt~z||~|~ux}~}}vv}|vzv|sq~ty~}wzy}~~}xt{}ww|zswx{}{}|{xyxyyzs{~~~}|v}{~}}x}~}x}xy~~|~~}{|~|y}|}w{z~~|t~|t}uztyv|||{~w~vv~o~zowi~ywlzz~}x|zx|x~u~xuwzzq|s|z{{~}~}|z{z~tzy}{|w{s{{~xv||w|wr~qrns}}zujysssy~tty|wr{twm~}z{wrysc~qw|vyvp}udzxts}kzzvty}{pxru{uxwe}usq{u{~}{xskvtsulm~rv}yovzuuqv}swvvwtzwrluvqrxvszxjy}}zrmzt|{xwssvtxsryvtvyuwsu}~ytvvuyp{vsuvzxxpvyyzutx{yzyypsmwqt}nt~sylpxztzywy}t~~w|{zyvx|x~{zyupxkiv|uzzwxuu}tt}lzw}wvys^}tw~yxnvhzrru~o{wvpx}{pvruzuv|odzwro~sz}xxqyutsvlo~p}}xht~rvps|rxxwvq{vrltunpwurwmy~zw~skxr{y{vvsrwswrt{trowuvru|v}yttuvv~pxvvz~zwwxuxxztrwzwxxx~ornpps}~gt}szopwyrywtx|u}~vzzyyux}{xswzw~~zf}}t~xzso~}v}zk{|rhwzosyv|tz|~z~p|y~~w|mww~~zzzzzk}|{}p|rqsvty}{r{z|{vwp{yxswtty{wwq{fywu}qr}v{ou{qytuzzurixyp~nryt|~{xovyt{kq|p~}uy~ztywsu{zyxpo{omzxjprvn|k}q{u{lqwly}~quwuqvxr~}umtsxzqywyttu|szwww|{{xzy{}wrs{{|zynqyunu~}tvu}nuy{vxurx~wv{z|wv}~{t}~|~ttz{r}~{~}{{|y|}}yzx{}~z{}}izujvzryut`zqqx{uwzvuwqzu}qevv|vvwuezkwxwrz|{{sps|l~~wunx|x}pwrr{v|ncyxporz}}pxsstr{klpw~wi{urvqpyswwuun{uqistioorqtk{|xu~pgwozx}uvqooqvsuztppwtuptwu}yrqtvy~rxxuv|yvwtywzsrvzvvvv|mqmmmqzjr|rxspwypxvqv{s}}ywyxwtvslzvnjwogxxt|ytts||owyzsept{zujlmyus~|ut~{srpu{t{lxm{qwupyy~}usyc~|x~o}pzs|v|qzxzppnvs}iyysupvfx~q|usuitzmiyvgqpjrzbtwuw}qitzxhuuzsu}lus{psywiqtrwto~ruwqspqy{ow}vyxw|puwyz~ymvzvrvzpprrlyy{qu}rwsrvyvwxzxq{w}szsu~|~ztv~u{w|}y{u~zkv}wwvyw~w}~jux^~|{|uyz||zy{~zk~xyx~{vs}~vszxx~~~|tz~~z}|}qy|kw}v||~|w|vuyx|}~~|}|}~|~s{o{~{y|~{||x{yv}ztvwttt~zr|}{w~|sz~v{xs{~{v{~~z~xr~kz}}{w{|~}ov}tyws~z}~}}z~|~}z~~yw~xx}}j|}xtv|yruzqdumwzw|mt{uvvfz{~wsyqfvxwwozoyvt{r|o~twnu|{otrwxwwpsdx|o~nryv{~}xptruqxion|tr~yrxps|qywtvmswmduvdostmxd{lyszkkvly{sssrytws}{smmrvwow~w}wxqsyv}qxuu{zxvpxww{uoq|xxxw}mpvunr|{et~rxmrvyswusx|u}uyxywt{s|r|xtxv}u}z{ywz{j}z{xxtkz{yzy{~bzxwy|pzzytx~s}uz|xtzvkzxu~ov{}|zpisysvoq{s|wu~yxuyuv}u{x{xut|stwxytyys{}v|}~zqt{t|wwxw{wyt{|xutzxytyz{uxyyq|wwuy{|zrzz}|{vwy|~{{ruv|sv~vxv~muz}w{xwywv~}~{yzv~zxwvy{~r~}~w|}oyyzz}fuyyZnw~|~s~oukwmz{w~wrz{~|}|~yv~v|nt||zwy||vu|{~t~}~q~||}~}|~y|}}}{~~~~uk}~~y}~r}v{v|y~U~svtb|~~pzv~uz}u{{}xukzstzs~|zx|r~ux{s}}wt~}z}{uur{s~|qzry~{|{wzusw|}ymqnu}}utmy|}yzww}}w~zzx|v|upy}}z|yq~zz~ypyrwupw{~z{}y}|u}zyrvqX}zsu{{l|~}x\]tzt{}stzz}{zpt{s}xwys~wtx~~`voy~|zpy|r}{{}~{v{z{stysz|}t}}|s~}xyw{{}{{{{vjyrtx~||qu|vuz~nyprx{ty{ziz{~yv~}xrz{~|}x|j~}v|wr~vupz~~}{xm~wrknwo~}wqzq{zmy~vy|syx}~z~y}x~|{qvrug}~avyvsnythvywzywz{s|vyp}euv|wxwsl~twwyrzz~ztrt~j~wvmzzypvpwzt}tubyzqozpy~~~xtppsqylkry~wbu|qvpszrwwsvo|sqjttgpttqudx|yu}rgwozw{vvrpvrxmrzsphvuvquow|ytpsvt}rwwuz}yvvtuyw{uqu{vvvv~mroroqy~gt|rvupuypxvpyzs||zxywxuzy}rx}~yw}u|yxm|tl~{~|zyizpy}}{~xy}{y|qpi}zx~vw}pu{~swwyvzz}|ytw{{m~|xxuh{z{{{j||yx~u|zyuzu{v|}zryzn|vw~ry{~zqoqyswqt|s}yp{{w{ux{v{y}zwv}uwyywvzzs~s}|~sw}v}xxzyxy{{z}yvx{y{v{z|xzzz{s~xxtz|~{t{{~|~xx{}||tv~|tx~syx}kw{~y|zz{yx~|zukvyuxhzrjxxtwzw{zvywstdvr}vuysiziyuwq|znysrs}i}tvox|yowqxzvutbyxpozqzz|~yxsvwus{jnq}vf}tzrvrq|qwutunxtpgsvlnpspugzxxt}pgvnzx}uuqosqwpu{soputuptzv|xtpsv|}qvwsz~yvvvuxw{rpt{wvwv}mojpnpy~ks}qxqpvxpwutw{t||zwxwwszz|{yxzux~uvyu}z~}}r|{}}z|~|~|~w|}mx|zr|yzs{srz~uxx~}|qv}ryz}h{x}xtzuh{ku~xxuszzc{utt}l|xssy{{pxrx|vvqe}vsq}rz~}wxs{sourulor|~ygu|svtu|rxwwvs}uqltvtsyur|woy|xskyt{{|xwrrrsylrzutwyuvsuz}yttuuy~pxwuw~zwwuvyw{tsy{xxxx~prnuqt|js~r{oqxzszxwx|t}}u{zxzu}}r|~{r{xyyyuw{v}sz}}vz~~}v~ww~{{p}os}}uy|vz|zz|ty~y~~w|uwzvzskvxp|z{ur|}{xwwx~}{|yuxy~s{}zzqpx~uutxs~~x~||~wy|~~|tu|xw~uzws~~su}vz}}w~~{v~z|w~~x|sxyy{}~{~zxwx}w~z~~{o{~}|}}x{~vqs|ozrky{sox}v|tv|~szxrzgrz|rwvwn|qwvywxuzur}v{m{sr{}woxsyyrxa{~qpozy}rxxowu{horp}wnvxrwrr|q{wtunxuqesyqnmrowlxvwu|mguozuvtslpqvluysouvqvsv~w}{{vruty}svwsxyxvvxwzvrt{vrtv}oqnskqylu|svpptwtxusu}t{xyyxzumw}|ojzzrrx|ryy}|y{v~z|dyz~wsytevsxxux|{czuszq{pzw{trx|{otqwzvt}nbzxp~nryx}|zxswlusvjl|rv|wt}uwsvrr|rwvuuqwupgruvqutqxvmx{zvohxq{ywvrqrrwjvztrpwuurtyy|xuruvw}pxwvtyvvvwyv{sqwywvww}nqqqor{hs|r{hpwxryvsw{t|}vyywyt~|}~|zzs}y|{tt{uqx|{y{}|~|t~~}{}}{yy~wi~{hry}ytx}qjz~vy{{mrv}~{wdoyxsfxyqvw{txot{{~wv{}wr|p}|xx{{urqmn{o}wn{xvwn}v{zinvl{y}~{z~ho{|stSi{ifzoc|~vy|~z}luwyz>hyxr}~~~}wav{uyzx~z}xzwvz{z~}~~z|uw|xzus}~zz{wqv|l}zzwuy~}yyxzyzzr{vw{rz}|yps~}uuuxtz}||}vy~}~ww}{{w|uv~vw}~x{y~v}}zt}}y~|v}{txx{}|}~||xy~xz}zr{~~~}|w~zsnn|~}}f||cp|zwzy|{~~||zy|umzz}xw{{vt|ts~m}t|t|q{ryr}tm}x}y~~sqvvzxv{pxq_~}}lz{m{rw|}~~ynt}y|yv{~yz{|~}~y~wv~~~wuw{yw~}{~|zxv||}{{||vwz{{~vp{|z~~~tzmxywxn{{|{vqy{~zx~w|}|z~n|}|}ytt~tuqzs}u}~~l~{{ruoe}w{t|wz}zl}t}z~u}}t{|zt}v~yo~}s~~z~|}|~{y~u~~~}ry{{{|t|z~y{q|~{wzu|~~yww~}~}xyy~}xvs{l||~ut~crhuzyzxwxxzx{tiw|~wp|th|uywyv{Qzrptp|{~vynxyxosr}wvwebz}noozyx|uwuzutzhq~r|{uy}xrvrsrvxvtkstobsvvpnsovrzyws~kfu~mzxttqorqvhzzsoruuvqt}{{vsotww~tzxvz|yvuxyu{rptxuuvv{lpxzno{~pq|sxtqvwqxuouzt||sywuws~~v~}yxvz|~tquq{yv~xy|w{u~us}x~vz~z{l|ulj|{wfqyol`trw}urtuqvwys~cww|wsxqftvuwr}zyfwroztr|twqx{{ntowwv|sn`wvnn{mx~{zwutoupzilpz{vk|w{qxpn|pwvrsmwtpdqumpkrpv`yszrylivn{y~strpwquhwyrnostuqu~vu{vtqsur{t|vt}zuusvxuysop{wuvx{mqslmm|}^r|tzhouvqxwpyyt|{vwxvwsz~{sz}~vtyrr{y|{}{|{{}}}zq}~}oiz|uszv|szv{pvsyq~m}~v{{~{ow|z|xpvwpuywx|{xxz{qpmryʅ|yl}vpxyzzpwzwsp~yi{xy|y}y~~y}y|~qw{|||{yu}~l~}~~}}z{ypr}~|oq{p{q|~utov~z~~v||}}z{~utq~zq}y~z{|}}v{ww|~t{~{}}xuzxuz|z{un~{}y{zltg|{x{qz}x||vzwxtypyyt~{|zts|yuutvtz|qy~zzru|v}z|{||~wz{zvy}xu~xyy{{{{~z}wu}|{w}y|x{~~w~{{xrxw{~~~~y||||{}}}~~vxyw|}x{x}qw|{}}}yx}}xzrz}zkwxwb}w~qw|xwnwy|sv`t|{{nrwnrq|}~{z~|{zq{{x|u}~}xo|rjvpq{zr{ycz~fqxvvvx}dwymssz{ix}u{puj{nurupvunivspswxiwzsfpvurtuk{{puw}psorr|xruavkprqxxx~mw{t{qh{{nustxxktvuwsv{uzvt|gouwptv{du}vwsttxwqq~}xfywxwv|lsrxx}uxpzvmyvxvws|poxztz}gwv}wtwtm{ntxwvugzvstzlxvrwzyoxqxyx|oa{yplpyy|~~twvzqtr{ins{whwxtwvs{ruutukyrodrvvomsoulxuxt}mevp{xutonsqvrwzrpsvutquv|{vtmtv{|twxux~yuuvuyu{tpu|vtwv{mspsnox~jq~qwspwwpxurv{t|{wwxuxqzf|{u{fxuqvvxxy|p|uzusukzu|vsvtqsxwwuwqyusom}uwovzpzqqzxvpexwnmryy~{wrsxs{in{pw~tn~wtwtp}txwuwnrwmjwvnnounzzjzuyv{kkwly{rtssnswqy{smttwwpv|v~wrrtz}sxwuu|zxvwxw|vqsyyyxx}mortlr{mt~t{kqxxtwuqw}u~~vyyyvtzu|z~wwtx~|qz{zzxr}tt`u||wtwqzxy~{dwmvl~yvzsv}u{{wuw}tguqw}y~}yysuyrmvstu~w{{xou{y|{xxxs||wv||~|||zbn|}sx{{yzu|vrqvvy{~~yz~{x~|}xy~yy}}m{v~kv{~wv~|y|{vzyt{tys~}|u|}{z}|ryx}p~x~w{}y}m~~z~j|y}}{zzzwy{xr{u{}zzsz~}~~{u|{~~wzx}~~{~wuq~}z}}zzy}|zz}~zu|tr}{yyw|}ygt}~v{sv|~{~ziuvp|{xxpxx}|zxyyxj|ww~ww|}{trz{tqyvu~}}}~{rzx}~}x{|v~{nzx{}~{jv}tz{~{w~{tswwz|~}|}y{{zq}znz~{yskxz|xqnv|}qwi|||zzfwyq{m|twwv|Otqs|}_zzrveuyvqz~vwsvuxkv}c}}uxt{{~wghvs{{|sgszzu{nltxxwxdx}pf{t|gqt`sgyjyv{unvcyzwik~ix~Xnqoxvxlxxwwtiw~vvrvv{yk{vwrxtr|{yy~qk}fwmv}wyvx|{tyt|{\xhzyt~||~xqrwxqox|zvuvo{vwgry~uuj}z|xcqqd|{wx~suy{ysyvwg~v{v~~s{~zr{zsnyvr~}z}{w}{sjv}}}~w|{v|{vs|~|~~}}~z~fs}~rz|~ys|zsrutyz}}}z~yz~|{{ozxiy}tzv|x}u}|wwtv|}u}{yx{y|w~~uy}zxzo~|{v~x}{}xlzzu{|ytps~spzy|xvyuz~xdr{~w}twr~|{zeruu}zxyqvx}zytyvwhvvv|z~ytuyztoyvu~~~|y}zrw|~}~x|zs}|ryy~~}}~~z~ft|sz{}xt}ztrvuzz}|}{{~z{~{{}o{xjy}zy~||}}uv|xszwv~u~|{~s|~}|}z|}xyzuw~}|{iky}uiqvzrb}|}lwysyq~y}ruu}~uvb{{z~|zz{wxvlz|tum{p}xir}vy[||ugyd`~zsi{{uy|{qbp}vy{|wiusth[u||{vw{j{y}txrotp|ntonv~{|tsyt{~|{q}}yiw~yos|z~vvt}y|~}gt~u]}|z}sw{{zsztyiyw~w~r|}}{rx{uqyxt~}|}{sy~~~x{}u}{po{~~|~|gvt|}~|t~{utvuz{~}}z{}~||q|zi{~{xstzzow}~~{qrr~ty}{{|{v}}||sz{v~v|tly~u{yxu|yxzxr~x|ui~z{rv~w|suzwnvz|z~sz~~~~uwxs~lv{w}||xv}zyz{y|}z~~w~p}}w||nx}|}t}s|v~}{|xntx~ssrb}zop{sw{}|rwx{|}zz|~{{txzwywy||{{~xz}u}{wwyvxr~}{nulsq|yw}twqnyr|x}xyu~xy|{st~{tz|~y||{v{ywvvztt~|s~~y|}|}z~zx}y{xy~ltxv}{v{f{zovt}{w~xypw~t{zownyv}vrutg{mwxxt}jyvsp}p~vxmw}y~puruyw~zodzyom~qz~|~vxowvszin{p}uo}xrvsr|rxxvvnsvnhuvfootnxkzwyu|mjvmyy~strqmswox{snuuuwqvv}wqqtw{~rxwtuxywvwywzuruzwxww}mprsmr{qr}synqwyqwvnv{u~~vyxxwtwz|kx{t~ovuwzyzlyy{yxx}xptsxn}vvtTxxvvq}ox{mu~yp|swyz~rhyyonpzs}~qxqxyt{irzq}|s|}}zsy{suyxyxmnznkzwvopul||s|oyuzhovky|qsvtmvwn}{tlztxyoxwrruy~tzwurr{zwzwz}vrqz{{yx~mrtwms|}{uv{lsyztwupw}ws{y{vt{y{|}~}}}}vq~}yxqxw}}zvv~su|yzty~|zyw~nqw~yv|zx|q|T}xztxnzyt|xz}xru~rppxxs~|z}rvzsmwzzvw}uyrxy}ix}}wswul}rvuwuz`zuo|pzl|wvmxzxo{rvyu~nbyyoooz{|}twtqrurxknq~yvn}v{rvqs{sxuvunxtnhwwumuso}yhyzwv~niwmzw}uurporwtsxtovutvst{{}wuqst{~qvwvt}ywvsuww}uqtzxwvw|losvlp|jr~txqpvwqzvqw{s}}vzxyyuvw{|{~w~tsSs|zs|swop~rR~nqsjqw|{j{}uoyopAx\}l~vtyzur}{|x}k}wwxz}~zvp{v|guno|yvnuz|}suufx}}l~x|zgx~}v{ksj}pvtz|||zxvubuv~|f}|gsv}}pvy{yzyuoz~xmwesw~tm|wlym{n|}|~|zttzz}uu{zrz{}|y|}||{{}z|}||~~}~yj{~vszzz|ysznxqqtmow~ux~nmzy|t}{{xx~~zr|x|{{rv{|u|qz~zu{u~{}tu{|s}z|w~|}z|~~~{{y|~}~{j~}{z{}xwuy{xs{nyx}y~|}}}zsw}~{~t|k{twy|xupnsn{qsuuxqyytsly}ov{woclcjwlyujvt|{zyi}k}ts~cmpml]v{nqi|pursz{rv\m_phuroucz|uuwuls{|fy{hjlmyxvvlzohruc{}woh}vxw}wqlo~tu~xzqxlygu~z|wvf]yxrvwtxxzmsyutit~qmek|sx{~tylmwspuyu~zsk{trvvgp|z{{v|y|vuvs{|zzs|~{|}|{{z|~|||}||}}{|j|{}{x||wzstzsy}|w|qw}wv~w|~}z}|ujyvsv{xt`ypour}tyyzrtxwvsnsvyrmptgupov}muuv|uqytj|ztqw{s}jwhxk~t^tw~l{qz~vwyvuktrsymoioztf}ysyrtew{pussthwufgplerpswqeytvozlcvvxcxytsvpwtxsuurmg|qycu~uwxwpvqyw|yvtkh{xzosu}{ztpuyvtlummjuhnxqhu}qwkstwwwswy}e{wywzpqzv}~x{ow~uu}bjov|v}zzp~twus~mw{nw~t|v{y||gxr~}}yz~|~qxs}{rtt{fmfwytzR}luBrjxsyixtqqxyo`wKdt_~bpsw~rvu~~pmel{q|}kqp|{vzz~vdqhfwoqgnpoq{g|zh}lusu|}|q}\~ywv|yczu~wzsylxst}yyt}{|trzxjx|t{zzu|wzwkzw}xvxsjxyxyux{gzus~u}o|xtsx~{pwqyzw~|odzzrqsz|{wrlmvqwlmr~|xt~wtvrssxvuvrwvqjsvxquuq{xtyxzw~okxr{zwvtrvswn{yurowvvru{|}wutuw|~qxvuwzwwqwxx{xru{xxxx~orr~or}~kt}ryjqwysywux|t~~xzzyxu~xtt|z}~y}prx|wvyuquyxzw~vtsn|ruvzu{{{}sp|ozv~w|lwvzw~s{ynz\s~rq~mm}qt}i~~zwiyp{|ww}x~s~l|mtqt|vs|z|zp}uwxz{vtjxnjy}}vvyrxxnxv|t~hyw|tqtrczrvuxs{~dytpu|jxwrv{w~nzpvxvjayypmszz~~txrvuurzin~p~{vkyv~rwtq{qvtuumxtoervtnqspupxtxu}ogv~nzxttqotquwvzspqvtuou|z|vsqsv|}qwvtv~yvvvtwvzsquzvwvv}mqmpnp|}gr}qxpovxpxurv{s}}wyxwxr~w~|x~|y|tuztx~~~x}y~}{y}wx~~yox}y}|}y|lwy{z{z|v~t|{|s~yzx{}wyzv~yqzj|z~~~z~vk{{w}{~|putzxs}{{|{~|{s}~~z~w|{yj}~zx|zpe~|k{~{y~w{~}[zy}oq|x}mrz{~zxm}y{yxux~{yu}z{u~~~~{vysy~txtysz}}}z{||m}yq|xx}{~t}}||rkzt{}zzwv~}}}m}}wwp|}lxxwyz}{w{jzyp}~xz~t{vv}tvz{~ysy{~}zi~xzqz~w|wt{zw{|x{xwx|zu{|{uzto~|}x{psqz}zys}|zwx~uyw}}z~wo~wvr|{~}yjkwyuwrs~r}xvywztzv|yz{xw~tv{ynv|{ts~y|}tx}u|}vyzzz|~z}yusyz|v{y|w{y{}r~xvzz}~|s{z|{xw|}}}tuxty|yzw|rw{~z{zz|yv{{z{~{w~}}uu|tzxr~{~{{|{|}}}}vx}~~{~}i~z^|p}t|rw~}m{zy|s~~}rvtsxi|}zx||riyutvyvy{pv|us}jy{r|yxftsv~q{~o{szy~zzufp~usw|mtl]wvg{hw}msv|xjpr{|zyzu}wz{{|xvottt~r|t~}r~~xw~~}wvz{vnytp}tqt{uyxysz|w{t{|f{w}yvtsp|pwwyx|}h{vt|s{q{yvsx|qur}{wxzf}us~ooz}~wu{lwpvlp~s}}wp}wxtwst|sxxyvsuxooxwtr{vq|yt{|y~ooyr{|vvvtruxjxzvrmxvxsv|~xuuvxuqywttyzzx|wyz{vswzzzyyosy{ot~~vttz_rx{tyxvy}t~x||{xwkvyv|kyz}}r{{z}}zy~~}tvtqw|uv~~~{z|whzywwzu{tvx|yv}n|{r}{yitzv|t{q}v}|z||{~~ylr|yvxrkp[|zl~oz~qvz~{otv~~z||u~w{y{yyrwxwvu~~p~zz}xx}wp{}xtvyshxxvyyy{r|sxvzi{y}xvysg}lvwztx~z}s|wqtm{xuty|{qtry{uzrd|xsrxqz}zwsspssvmmr~}yiwtvpuzrxwuvr|urkuvorwvrvny~{w~sjys{z}xwtrtsyotzvtmxvvsuxx|yuuuvs~rxwt|zxxswzxzwsx|wxxx~psrwqs|~gs}rwmqwzszxvy|t}}x{{xzv|{}|z~x~~z}r}{~z|~}}u}s~}xx~z~y}{x}{v}zyu}tx{}vs{~{t|}y|{||~{zvu~s|j{|}~~|wzwv||yy}~~xtx|~vyth~{}snuyr|yzz~oy~|zyx|yv~{xvvz~rz}{znsz}uvuwsy{}|~v~y}~}vu}}xzvvul}tw}~wzy~z|xu{}x|w|xtwxz~z}~{zwy}xy|~zn{~}}}|w}{z|{tz}{z{s~xzuz~v{usy~unz|q}{|{sy|}{y|zy}zywv{uz~w|qt|vxwwuz~}~|vz~}ww{~y|wtrm~uw~x{z|}yt|~y~x}zuyxz||~|{yz~zw}~|u|~}~}x~}t~y{~py{{~\~vw~uzvsj}rvvo}~}w~~n{}|~|xxykro{zz~|yx~~v~}~pv||{{}|w|}~y||z}s{}~~r~|zn{}uqizuvxtxzywto|nzvzc~z}ws{sk~guwxryx|{tp|nxvpw{ypvrr{xxwdzzqprz}ryrttnssxkn|qy}vh|ztvuuxrvvtwpvuogtvjpqup{wiywzw}ojxqzywvsqpswsyzuqtwvvsuwz}wurtw{}ryxttxzxwqvyw{wsu{xxww}orsxorz~hr}swkqwysywuy|t}}vzyxyukqtuovxqf|}x{p|ozyt}oy|zxs~v|t||u{zutyuyxxzmvh|z|m|r{zw~}sus|v{uzyvf|y{vwwsiywd{}dhui}rworkirm}qv}rswzu{zln}uy~z}qovyno}wwzoy}|tiqp}~y{u~tsvtjpxq~xwt}wvz|}lywz|zx^||xz}|yt{vt~rrr~|tx}xq|yrtu||~vzr|ywyr}s~yu|}~z{u}yylutx}s{z|~|{|~|x{y}w}y~v|v~j|}{}}|v}{w||~tuyt|~~v~|zp}zx}{vz}{}~vu{vykwow~zt{wz}ut}{t~~x~{|}{{w~z~~}~~v~kwu{~z}{wsy~o{}szz}yt~w~vi|x|xw}sh~vzxxvnz~ezvt~v|o|xsux~}qyrz{v|qf|wtqvz~{wuclvqvmoq{|ypv~uwtttyvuwt{wrntvxrvws{yszy}yqnzu||xwutxtxqszvtqxvvtv~~yuvvw{pyvuw|zyylwyz{xtv{zzyyqsr}qt~~lvs{iqx{uzxzy}u~x}|{yw~z}|zx}zzwuyortwtk~{}vv|}~{hzq}a}vz|u||uz{yxwuutm|||w|~{wfvxvtws|x~www{voz~wyyyy~z|ut{o{}{~ypzu~}zw}w~ll{}rww|xwy}w{tyrzwz{}|mx~}yz|{}{|xzxyz{kws}xv|~z|x|w~}ry~s||}|~|{u|x}nxzsn~a{s{pyy~z}{xsxr~y|}{sw|luvplr{||~hzvvytwwzxz~uv|vsyv|y~wvzui}qxyxxxxzySzuuuzpzzwvx{{qzsy|w}kf~yrpt||~~wytwwuxlq}r|xm~x}swsu|twxywqxwsktwwsuvsxvz{yqkyr|{wwtsusxxwzvtoyvwsv{}yttvv~~rxxwv{zxwvzx|tsyzyyxx~qsqxqs}}lr~u|wrxzszwtx|u~}vz{zzv~~{}{u~wvtzqs||}zyw{{z||}u{{|zl~{~|j{y~{~{{v}{~ut}||s~~}}~{z|xt}|~|xwut|~|xjww~{szou{{~xq~z}uy}~x{ug{|xpv{zp~zyxlz}||yx|yyzs~vw{sy}vzpqw|uuvus~yy{~{}vy}~}~vw}|vzwqpp}tz}|xzx}z}yy||x}v|ytwx{~~{|}|{xyyzt{w{~~~~|w~|qox{psyletkw|yv|zzwzutxczwvsvrg|vvxpysyvt|r~otxlw{yorryxxxotcx{o~nqxsz}|xoxuuqzino|unwqxoq{qxwvvmtvneuvdpstnwczuxt{mjvlyz}sssqwswp{|smlrvwpv|s|wwpsyt}qxvv|zxvtwxw{sprzvwww|lpwtnq{|eu}ryprvxrwuqw{u}~vywxwtt{|yr|{|{{i~b}|wpoxmy{|kz|w{}y{x{|x}~x{z}toz|~~~qux}|yxxysur~}|xq|yhz{jt|~xxvvp~y}fzr~uu}|y}pwy{|zsz~|xjwyt}~~yttu}tqzwu~~|w~{tx}~~x|{u}{pt~~{hv}t||~|u~{ttwxz{~~{~z{~|~q}zl{~zv||x~oihr}x~~}`wiwm}ur{{l{}|ynz}~wv}nv||}xtwzztum|rzwwyzz}ryurz|}qu{}gy}ypyvkxtnqxyr{x}|o{sxxx|w{y}~tgv{t{wx~q|{nwvs~u{rwxwr|zpzyxw|wxny{yx|v|uz{zxu}z{z~stw|wxmzyv}rvyx|{|vvqn}yzyww}zx}xuvk|x|vw}|rwzq|yhozzzr{xuz}q}~n|u~zuyyz~z|w~yy|vzv~yyt~}p|{}x|zzuz||~m~{yyxp{|rz{{zn~y~|t|nxwnf|u|yyuiz}xwqt}|zvpzrk|{|{zx{{}~pzy}{~q~{zx~r|x|pvz}zvztmxy{{jp~i{|vv|rxz}uyz~tyu}}vvulvw|t||~yqtswtsqqrx~ywx|yxp{u{xyzz{}uuxy~rx{{vy~r|~vv~w}~y{yy{y|vr|zxv{xzvyz}v}y{xp~wvw~||}v{{~{zy{{}}|ttxvz~q{v~mv{~y}||{ww|{prv}ytmyxoqv{xwyt}tpyuquhyx|vxysfykwxxt}wb{vrr}l~vvqx{yoyqnyvwxazxppxoz}}vxu}}rtsyjmru}wd{wwrvtr|rvvtuoztpesvpnmsp}ufyxyv}ngvpzwvuppnqvorzspvutuqt{z{wsptuz|rvwtw{yvuyuxv{tqv|wuvv|nqlpnpyir|ryoovxpxvtwzs|{xwxvxsxwyztpzrkvpw~zwvu|uyvn{z|vqvrfqxvwotrywt{qh~swnv|{otqswwysvcx{n~o|qxu}{~vyq{nqtszimo|to}yrwqs|ryvtwlrvmdvwinusmzwgylxs{jjvmyztssrxsww}zrmlrvwowyz|wwpsxz|rwvuw~zxvnwwv{voq{xwxw}mqosnr{}_r}swrqwyrwuqw{u}uyxwwtpu}~zwspyqd{vxxxtzsqwxzw{ezw|uqyrk{owuwr{x_zsq~u|mwvqv{y}oxqzywja{wonsyx~swrnsurzioq{vl~vswsr|rvttulxtocrvrnqsouixsxu}mgvozxutqpxqvtxysortutpu~z|vuosu{}qxvt{yvvouxvztps|vvvv|nqosno{|br}qxtovxqxutwzt||uyxvws{po~xnkyicw~tywswxqzu|pxbsy|uuxtbstxxp}y|s{urx}o}vsrzzwnurz{pzwk`x|qmqyy|ywrtotsyhmpvvf~}txqumqypvustkxvpdstinpspsiwxws{nfwmzv}vttluquntzronwrunsrv{xstsxv}pwvqxyuvtuxwwxqszuwtv|mqoloq{}fu~nwhpvwswusv|u|xwzwxrqg~syyvizrovuwzuqqywzvrzx}vsxrkyszxvwnty|~kzvqt}jzywqw~zpvrr{upd{uro~q{|vvoyvtrwkmqy}wotsuorswwuurxwqnuulpwuqwrz~{v~plyrzz{vvsqqsxpqytrqxuvqt{x}xqvutwqyvryyzxx|uxyzusw|xzxx~nonsor~}ms~rxlpwzsxwrw|t~~w|{zxu~yx~|t{wxyy}tux~t~z{|~z}~}|yuv}{{|{}~zukzwzyyiu~vry~yxxx}szut~z}t|szxz||}}~~~|n|y|~x||{w~~xu}vt|}xwq{yxdt|~y{tw~{zerwj}{ywrx}x}|zxy|xj|vw~x}|}{tn}{tpxvv|~|~{px|~~y{{v}|lz~{|~~~|gv}t{|~{v~{urwwy{}}|}z{{{rzlz}zxr|u{w}|zvx|nzvyxv|l}kz|wo|}c|zoy}w|vxzv~~ntxz~}}vnzv~r~~ozzz~yr{js|zi{two|toq|{um~{xuzv}{|ztj{tu||}vst}zt}wy{w{{}yr|wur{}~wpx{~|yqu|xxyyy}wz|wxwzxr|oxzxww~}zy|swuuuswz}tz~zyq|{~w{|{z||x{zyty{z|v}~{w|~}yywx|uu|{|ryzyy|~x~{yzu~zyy~}|}|{}|{z||}}wxzwztyw~wv|~z~~~xy|nkz{szk{nmxvzuyq}wrvtj{|mys|urysnr`wuwq}tfzsqr}iwwsw{yozquywub|voovoz~}qwszuuu{inq|}wb|vrvsq}rvutulxsnftvsnnsouhysxu}mfumyw~utpprqvnxzsoutuuptzy{vsosu{|rwwsz}yvuxtxu{sqt|vuvv|mqirmoy~jo|rwpowxpwvtwzt|{xxwvwspz}v}}zbszrR|{s|w}vwt[|xv|yv|yjr}cmwzxy|yd}|kwyznzk~j|x~y{yxt}|~}pstk|y~{mzuvywj{vx~vz||qzjhvz}xyzw|x}syw}w{rmtq~zt~vjq{w~txsyZy{iavyt|vHr{~~xy~j~nzzr[zu|mxqr}~fx}{{u}vw}xxxxn^rztjxlv~~xlz{yryx{~zxtt{m|t{}zwwy}zwjpz|{~yvyqtt{vwixsqzwuroyywsvzcvx|ur}vzr}uvp{qlvqyzzxr~ko|u~y}eyz|wuvti|mwxxxswnzyu}u}lwwoy|ypurtywztc{zqo}pz{~}}uyuytrss{jnr}|va}yzrwtrzrvvuvmwupftwmpptovezxyv|nhvpzxvtrqtswtv{tpnuvvrvvz|wvptwv}tyxtwxzwvqvyv{wqt{xvww|nsstoqy~jr}susqwxqxwrx{t|}wxxwxtwoswumjyikvwzxzpxvpyo{t~e{{|vtxsftkwuwo~zn{uoro~vwow|x~ovqszvqbzxpp}pz~}mws~vqtrzinp|}w`wrvqqxrvutunytofuvompsoueyzwu}ogvnyw~uuqoqqvvvzsopuuuqtxx|vtpsvw}rwwuz~yvustxv{trt{vvvv|mqqpmo{bq|rwpovxpxvrwzt||xxxvws{{zy|sz~{|{}xr}|~~r{{{~u}~y|tz~y~zz}z~|}|}lzdn~z}x{z|}~~}{r~z~||{|w~}z|uu~y{t|{~~}y~~}~z~~~z~y{~~~k}wzvz{ux{p|{xsx|{|~~|{~{puzw~|t}wy||tzv}|}s{~{y{y}y|stzsz|~w|~|vy~~{~~w{{|{|yx||}jtq|vvvwlzvov{tyx{uvt~uvrjys{vxxrc|pxxxro{oysqs|mzwunx}{owrv{u{{sc{xrovqz~~{wsurtqvknp{}wetxrunr~qwvtvrzvrmsugpsurwh{}{w~rjwrzy|vvsqurxmnztrqxuuruyv}yrtuvw~oxvs{{yvxvuxx{rsxzxxxw}oqotpr{~mu~qzqqvyrywuy}t}~wzzyyv{zq~}o|}|{|}xw{t|wyyz}~{wyxz~}}zx}~{w}}|~x~{z~~y~{t}|}ut~ysz}|~zvzz|v}|ywyu}jwjy~{ut}vmwzwUt}}syVrwy}prfqzf~yyqtw}xzp|{wuwxvoyy|~~}~z~mxw|nttpxoz~}ekr|xoyyt|~u|xfu}~~tz}}}~yx}|vwupx|wtjyokyxvvzv{vqxu~xhyy}urwsiznx{uwo~zoztqu}hvvow|y~oxqxzv|pazxooqy}~}txr|otsszioq~|wg}tqvsq|rvutumzspeturntsotlyywu~ofvozw|utporpwwwzsppuutot{y{vtpsuz}qwwt{yuuqtxu{sqt|vvvv|mpjomoz~cq}rwsovxpxurxzt|{xxxuws{qxz}rvvtd}zwx~xjx|}oyf{l}wyo`~c{w~yzi}dt{|ww}t}x{nyzzuuyymz|xqwxxzvwhz{zua~~du{|wsq|}|nv~szu~~m|}p{w}nm{ws{w}yyizzxnvywzyzu}jx~nvu}w{||}{w~~}xu|tzzs~~zz}|||}zxxz||}~ru~j|kmyw}xwu|uxzx|}v{{{k|~{wzsl{kyy|xd{|x|s}mzyqz}{syt{|{pth}}uv~v{~~zzrxt}nstwp|x|uzzv|u}yvxttztjz{wrrws}zq||zw}oo|qz{yuvsrvyw{|vrtxuytzy}}{yyw|{~sxywu~{y|~wz{}ytu}{xyy~qtzwqtzkwvyqvxywyxsz}x~{z|yzvye{}wstyonvpx~zt|u{v~w|j{zwuxsruxwwoozvu{s}m~vyov~{pvszyy~rvfx|pnqyt}~|xs{vvszjq~p}uqx}syur}sywvwoqxnhxwiosunyl{tyt|lmvmz{~sturwtwq~{tnrswxpw|z~xvrtz|}rxwuz}zyvxwxy|vps{yyxx}nqxsnr}|ot~syoswyswusx}v~wzyzwu|v~x{xxw{x~suys}z~|}{z}|qv~lsww}|~z|z}|xj{}u}}{v{|uutzvr~~~{~}|{|||{|zzxx}o}j{~}n|{{{~u}zz~}y~}|v~{swuty{wyxqwo{zyt}q{{zsxuv}|ytzozv~r{|}~yotuyuupu|r~}wzxxzv|v}{{{xutw|yvv|{twzx|~rx}u|vy{zz{v|}yvxzz|u{|w{y|r~xwvy}~}{|z}zwy|~}}tuutz~~{xsw|~y|{{{yu{{|~s}zy{}uk||xu{~tush~{}uzzuzz|vvsyy}zv~{y}w~o}|zzhtwwuwp{s~yvzwqsyy}sorW~|pr|qw~k{ryx~xz}~vwz}}z~xvxz}xv~}~}||z|~r~~}~xzt{{po~ot|{ztpuyw{{z{~{y}{|t|~{xvwrvrr~xm|{utr~vxtzfq{}t{sts}~|~fqxuj|zyrvty{xryxwguw~r{|yqrv{spwyt|}|v}zrw|~}}wzzv~zmm}~}|}{ds|s{z~{t}zrrvtyy}}z}~zz|z{|p|xhy}yutn}}{xvq|ytvssw|yytxtpxkvy}xqvlrwpx|u{tozzu~hzunw~h{yvsx{yn{r~zuqd}xvpxp{{~~yvwfqvvvnnovxwht|suquuvuuvnvuumvs|rptwvzzpv|zy}rn~ozy~wvuvwsztquwoovsvps}yzyprqw{qyvsqyzvzpu|z|uqu{xzvw~qrpxpo}zotryrqvxr{wux|}o~v}z|zu}]uv{{qwznzqx^~wz||~wh{p|tcxuyy}hzthzqyzx{~|z{|{t|pv~}x|{{{wy{{|}smywzv~vynhqz|w|{oksrz}}ucj|q}i~yjoxvrnvz|xkjtzvixvt|x{{f}{~}|~{w~zo|}{~wx|{}z~|x||zu{u{sy{w|z~~z|y~zy{|{}~z}ir}zoptzn{|yt}ysranz~zqyoy}|}l}zryyy~uw~|w}t~s{}}mxsmzt}qrytzuxx~qz|z|~|}rsslvzpr}zy|}xd~zxvwxuyuvw|xu~kzzr|zhtxs|rzo}t}{y~z{~~wjp~}uz~pnnZzxi}ny}puy}zm{rt~}z{zu}vzw{~wwq{vw~t~t~}l}~zy|wx|rzw~|zss{vqlvv{yuyvq|vtwhyz|xwzsa~ov|zx{x}}^|vqs}u{yvuy|{qsss{v{ke{yrq{p{}}vwtpurvmmr{~yq}ztur|u{sxxvvrxvqlsvprsvrwoz}{w}qkys{zxwsrosxluzusuxvwtuzw}ysuvux~sywuw~zxx~xzxzwsyzvxxx~pswsqs}~ks}ryhqwztzxtx|t}}v{{yzv~rm{}pys}x}|s{{zywy|x|zr}wzuvtq{ywyt{z~ozywv~p{zzqw~s{u{|yw~vl|vt~nwz~}xnttytwns{ry}wxv|vyvvu|y{ywt|svyxvtxys|}x}~{~ru{s|uxxwzxyww|xtxyyzsyz{tyx{}q|xvvz||{|zz~|xuxz|~|{rstxrwyyw~nuz}xzxvyxv}{yyssy{xm{sovy}yx{w{x|uwwnyw}vuutl}syvwryhytsqi~uwow{yoyqqywxobyzno|qzy~}wyrsxvs{il}ry|tmurvqp{rwusumwtoeuvonpsoujywwt}neu~nyw}utqppqvnw{ronuvuptyx{wsptv~|quxvy}yvuuuxu|rptzvuvu{mqhsmpxhr|syxpwxpwunv{t|{wwwuwsuov{}xsxrlxw|yzwtxvvvjw{~{uxog|q{zvyvu~{i{tttk{xtsy|zqvsy{sod{yspzpz||{wtsrwtump~r~}xk~utupt}qxwwutwxtmwx}tozwryqx{x~ro|r|z|wwutssynrvvtvxquuu}x{{qvut|pxvsv|zxxxvz{zxtwzwywx}prprpq~~ktszlqwyszxpx}t~x{|yyuzzvyvukysqw{vxzvvu}uxu{izx|wwvtf|rvxzsxyozutt{o}xtqy}{pvrwzv{|sd{wrp{sz~}wwszmusxlmq}}xiwzswrs{rwvvvqzvqjtvnpsur}wky|zx~qjxq{zvvsrtswruzuqowuvsvxx|xvsuwx~qxwvv|zwwxvyw{uswzxxxx}orruor{is}syppwyrywtx|t}}xyyxyu~{u}{}|~v}tyvs||~{zz|||}~}|v}x}~{{y{jzztvevtz|~oktzr"{pdpqwwq{s~zsxy{ury[z|l^zszssbe}w}{rn{|wx}vpu{kwm}y}yww|vt{vet[~qjzr|fwnez||xz~~~wy{v{~sz{}y}qztx~}}~u}}~~|z|}w||}vxr||{~w|~~{znvtwus}zzu~v{y|}t~~xt~~~}y|s}j}zwk}uy}~|vvw~~xxw~w{|mtypuyypq{wnw~~~{|vzu{~|zvw}y}}{tx}xm|o|}|{w|zv}|}x|{~wyysu~}vztoz|zy|zo}rzvp}{y}ny{~zxxyxvvtxzq}|yrsw|tuuvs|z}{||s~x|}}~yv}|{{x{s|~xz~y|y~pv~}|t}{z}|u|{{txwz|}||}}}xx~xz}zpz}~~{v}}{r{t~hj{|xt{{zqz}fmvyq|p}p|w|~{my~~{~vy~~y~wz~}v}zvxiynxzyxvzw{xz~sq}{xszyqtmvvplz||yojz}m}xxtz|ywzz{{xwpmf|zuu|{rwwpwswuo|}|wl|o~yjvxsu~|}l{tz{yqw~s~zr}~yr~|l}|w~|y|yw{xq}uyy|uysx|v{w{yv~~xthwl~rwtn}lvtxzt~{z}ry|uzvwizkx}sqrto~up{i|{mvy}x}xqsz{zw~{tvttx~su{x{ty{{wwyuxxy||zwty}tux~|p|stuxzt}yuwtzy~q}x|yuxtfzzzyx{{^yyw~x|s|yxux~rxuxzxw|wi{xs~py{{~|ypttxuxmq{r{ws~{vyuvuzxxxstzrouxxstxq}u}w~z}nrzs{~uvvv{wyu{{wrwxxzty~zvwxz}s|wvuy{{ytzy|{{ttz||{zqtu}rv~}uwuzkty|vzxyy~wu}|}ywfy}z{xp|ztu{yul|}}u}}~yzwq{zyqqz~}u~x{y~s{y~|vx|zz}}xsxy~zy~px}w~yptywys{~sy{{}{{z}z}~}yon|}ww|uyjo}{rzs{}s|w{~|us{~yy~x}}uxy}{}vzxwvxzvxo~zo{~~|||}vy}zxx}~xq{s}wv}y|}p{v}ot~z~zzyxm}uzzw{|Z||z}{}tw{qw}s}u|{ytl|~tpv{z}zup|u}mwzt}wm{w||uw{yzzrp|rpzzruxq~p~}|z|mtyqz~wuxwryz}{}wqzwz{tz~zwuw|w{zwsx}|yzz|}{vu|}}|{rv|wpv~vxx~ov{|vzyxzyx||~xx{pr~|~xzww{~v{z|}x{}s{}xyui{||{{~Y{{zzy}xy|{yzv{w}zqzvp~yx}ry}~zrzz{tusw~s~z~|{y|u{w~{{zvuyz{|y}|u|~~t{v~yz|{}{|v|~{xx|z}w||~x}{}zsxyv{}}z~|}}yz{~~~uww{|}{yny||}|}{zw}|ww}}}uzuw||w}|~w}~wzumz|~tz~y}zyvq{|~wxx}yz}|v{v~yy}r{}zzosuxuyr~w|~{v}~z~~{ru}xyusrk~|qu|~uxz}}|vzz}w~x|{uwz|~{}{xwy~xz{|s|~}}}}x|{rzy{v{~y~ďttzs}}~vv~{x||zx|sz{y|z{~{{~wjv~}m}~w|z}~~xyr}o|xpsntswqsv|tu|xwwwl~^}}y|y{p~zv~x|ky}}~~q}szvzow|u~}m{}xvw}|~xr}x{~z|~uzx{~ynzyxr~t~}xr}w}s|~ywww{{}|{{mxe}|zn{~}~z}|xyv}|~{yl|~y}vzpxpu}zx{zxn}~xwvqzrtlr^}|~zxz|}{{|zzvw}w|xvq~{{rrr~uz}r~{w|y}ttzs~z||{~{||}{}yz|~z|j}wruzw~mxsmyrztyyy{zst|rss{eys}vxvse{hwxyquzmzsru|j|wuqw{{pyruzw{zkdzxqn}rz{|}~uyq}ttrxkop}}wbuzrwtryqwvvvp{uqirulprtqvlzzzwrhwp{y|uvrqsrwst{tqtwuuru{t|xtrtv|}pwwuzywvyuxw{srw{wxww}oqloor{~ls}r{sqwxqyvvx{u}|xyxwytqjv}{ywfypmvxvwwrswz~t}jpx{vsrwgufvuwsx|{ssvygxssu|z}oysutu_z}uooy|ztwy{ztvszjtiv{wfyuuvpv~qzvsumyvrjpynqqsrvg}uwv{nltz~iywutyuprurzsrosxrynx~zyyytvtrz|pvvmx|y{z{tw|utqr{usrv|spjokrxgw}twoouwwwtvx~u{yy|xtsqwt~}|umype~v{xu|tt{yytrjuw{ztqpnzkt}uuu{yqzswx|g~vrs{tv|muuv{k{{_{|snmx~{}zyutuwrxlrp{ug{vusupyw~nvuuqywpgsxpnxpiwhwuwuzojv}oz{|vtsnquuowwopqxszqx~xw|yu{sou}mvwk}}yyyuux|uvsq|utxv|mnishtxmw{tvtptxzwupuq{vy{wztupqy~xssyunh}x{{nxmrzzwxjuz|{rxykzppwxq~u~hwwv}y|qzsqvw}m|x{vtq`ytpmx}~uwy|oyuxiqmx{wk{wpwvw~qzvsunwzrhn}wqorkxe|uwtzljqzsy{usyossvl|woouwrwlww{swwrot|nxvp|y{vzuwxxtqu{usrwzprsojrz~bs|vxpmvwvwus{}|v{~s{|sur~}~s~y~usxxyvw|{sw|}~~||}|}z{zy~~~}{xsz{}}zo|}x_|zpxaxguvvzw|}znsytyqvtpzt{wuxsixlxwvmvy|}{rqol~uxpv~zpxrwyw~reyypm|tz~vrvtszipzow~tox}wtvsq}rxxswqvwnjwvinouo~ym{syw{mlwnyz~tttroswm{zsoxuwwqv}y}xrrsy~}rywsz|zxwwxxztru{yyxx~nqmqmr{ou~s{cqwyrwwwx|u~~vyy{vuz~|s|r{|wx}|n~~}yp{npz}uzxh{~{zqz~{{~y~v}y|~yr~~}}{mw{zzjwmzv}yzuys|z}{{shll}no|xx~uny{x|u}w|vv|r{o~}vy{{xwztz~{z}mu{~z{orum~swj|wxx|m~zv{nx~}zx{zrju{}ysiy}|gu}xuz}vpunp⍠nyYksxzhw~ocUmp~du:ɸL{{cjw(Z횚U܉VAqm~mEnn|R+~sեV^6pptSpGF~'ѕP+)@:0q>y:P43DEf2HD5H?% .;^RzZ|JhspnUVt5/i&Y=( יPai|72.>qB%AZ3]Y2_TsoQ A:DmcFz&T=(YTlQfXIEFS8mcaQ2KQXsgJ2,3DX<>JAlO[v|eI^b,ENCJFddSC[ZXM:Yr; 4AKr_]LgP;FKR8<:Q4dfRJg=Y;MW +-XM?97Ӥ!QcV_k1@R5pPPLLVs&L[Ap;?& :}PNdq:4} oECm_yrEn AdIiV,ZXƩFW^Q+f̣!eZ|RKClajQ}Y(msMIFK;NnݟN{c`~Li;9Uzc`$CRHdgtx?yw\K`Qcj1oXdaGvp>b_JW4FpH6TPzK-Z$ii?[`ec`hch_dflfY]h]cdcdef]`^m_cpfifcabn^^hjjjj`egnege`cnUdm_cYeb_gZdXe`g]cd]bfkdd^b__]effi]b_hh_bchccmieg``gaiffcXdghkffac`[]bgibaWjg]Thchfafe`kec`Og^bebd^_dcgbdhah]cgihic_\\ibb`^[_]kjjblUZpaggceg`b`_iadla]edbabcZji_`ZYeb`bl__cafn^ae_^i`ff_\eedq__]bccfgffb[f`flcegafdjVkd]Ym]^h_defdZfd]dnlRfeb`bhdk`Ynbbsa`mlgclimdjihXei[bf^Vo^^W\jd_mo]iZde`^f]aki\hlhekbfdod`]o^d[f``WcDfb`V\k_bl^^oc\\nT[da[jctcch`q^[ch5_cgkidmbej\l]bd`fabecd[cb_ce^bi^ahggf]mbcp`a_accZk``a[jp\cafmb^mb`baej`cgWcp_ld`cdfcgc]ibhik\aq]g`\bil_e`cTc`dahaYac]gfcpZdbcab^gn`^^ehfdoidaa__ke]df[chjadae_e\ch\bdi`Qe_c]`[aam^ib]^^coh]g]d]ea\be`V^ie^bdf_i\\fffae[l`efjdnecd`c]\degYZai^^qg`gc^`dbd_X^b_haw_`ci^a\c_cXacifd\]c`dbeihl]fcd_lckj[c`mej]bcdfe]bm_blYedj`jgdbfkh_iae]fZaj]Ydgnelc[`ddeckdafj^cbjajfgcm`caf`ccehgmdijbahddj^`b_]eh]baei_g]^_^bqfc\ab]hf\ifcoi[jgj^Wipc^`\rgZbigggbaeifj[Xich[]\n`e\`d\gbfjnbej[cgbdc[oc`jhhlTeg]^lgebdbd^ahbf_f`d]c]f[ehcnb[`aRU_efj^ghiZbcf]_Zha]g[]dccfecj[bjeadf`ajcaObc\ld^]d^cfbiZU[gcfd_odaf^c`dRb`jZcha[a`ea^[kg`^]e`bbem_aecbb`b]hg^eabd`befZhcb^hgcbb\bY^de`bd]gcadcbeb[bjheda_cddbbccf`cffdhcgefj^aiifg`\_fb\_d`cjif^gkjehai]kkbndhcainV`YeebXigen^had`jefhbcecb\]h_jTjgck^ajgiehf^j^afbdegldoagdc`dfbh\\`aifkdg_cach`acgehggb]a[_a][\fbe]ji^`abdi^\abbah_bb_hcdacnfedaf^dakhg_bf`g`hh^jie^dng\gjafa]l_c]f^Zk\fd\[bb^_afie`\_kVia_`gr\heb\i]`icdk\^plia\gcZbhdd\abt^d]m^h__bfZpcd`abgdla\fcf_^aj^baefbdmae\`ceh`acYednkbd\][``iY[^e`hq_Zhcjeecea]da_]hqham_]fge_ee\\bZbbrcc_ZfZc[beg]^lcch`e`apdm[e^aZa^g\gabami`e^g^_che_`di\_do`ab`hcb_i_]sbhe_`geafj_c^_`add\hb``aj]d\fg]`^hbifk_`gccgcbb\hcfd_eddbf`^bdlej_ghdcea_f^d\`dd^_ac[dbeab_d`bcfbghmbdeef`ec_`bcjgb[bbfaj`bceb_`ihfeb\^cbf^ia`b^d`i_e_gaec\hbihcgYca]_`Wc_bc^bqe_f_ebdh_idhdhggc`c\`kgibedb^bbckeh\]b_``aa`ccdgecdackdcl_e_fehfkc^fg_^f_afe_dcb`aZ\cbbcecfacgg_f\hbd_bbbb_]_dibihg\b[gYa_b`]aic]egdedhjb^``cdcf`hg^ab`af`fda\bkkgXiica`[dajhakdadc`fg^ah[adbgddf`hlaaj^ade`becbddmtdbM[jdpbeb[__jcdhf_gn^]gkg`_^g`fcad_ab]\`ec^dbagedcc_c`hbe`dica_df_^^f]`\cf`d`iab_]deWficbcbigfcc`g`_]^h`bgc`a_hgdZ_b``iia`f_`deoacag]jdflgcfkiihabgZUilkho_dd\^beaih\bk`xkcbZkf^\f_[f\dd_\eafae\glfYihafZIf]ghbkmaf^pfc[diZZfc\f_hbbgi\``eii`^f`Yf`ga[^lgo^cc``ccaa\cedniYbalacc^_a``Ye]^ebdbb]kZdej\_ca_Yj[fa`fa`jd_cgkjcfa[gfbfa`ebc^i\ldadi]`bjdbj`ffbc^ii\`jbdg_cdedie`cdg`a_fejhgdf\cjNjaf\ehfeaachb^i_\_eeedjdfcbj]fige`e_bao\k``ce]hdf[h_e`^e]engabeZ]cb_bba`cfhfYdc^_ddedeaajaidabagd]icZga^d`c`df]iic`aih^idbe]_ideddhbckiZ_fa]dhcd_e_acfl]gd\gbcbdecdkdoje[eiacaa`ob`gfcgc_`Z]ca_d^ai_cngfb_eelfkbbdhgbcg^lp\acaaZde]kZ``gc[`j`_faebb^ee_cicdfbak_jk^Wecb`iZbjafj`e`icg``aeade`c^b^f^_ecff^afbeffd`bec_`bceceeccc`heehdfdccccgf``aelbc\cfgdk`bcbaf_daccadfeedf_daffdd`adfacaaafdgbdeb_cef`dbdcc_bddecbfb_^f^c^bceegcbecafdbk]bd`dcdd^ccbeebebc_cbe]ca`fgbebfeee`cdbh__cg`babfdaafehbgfccabfedababicb^d^ccgeaaadba__bccbbbcfceg`f_c]cebeacicZ^ebhi_dgg^e`dbhfc\ba_gbpcd^ceja`gfe^_eldhikdidjh`id^b^^b\f]nac]degagigfnfa_`]fabZ`gb]bYab[aichb\]_ca``djab_heee]__l`ejX`]h_cicf`fdajfcehcahbaXfbf]jh_acbl`c]gfi_b]f]dg_d_bn`]a_de``h^]jZfgd`f[ab`]ed[jd`c`\a^ceglgc`efed^defg_e[^fdleZceiea^hca]ddicbeahj`a`iddl_`ddggdidc`eh`jgeib\beedcejmd^d_`[^je`fb_[kg`^a]^k]cccbnmdgm`[a^cc_e[b_cXae_fcbd\`ecej_bbmjb]_gbbj^ch`acmb_mgjkjcddgjane`_ghf^c\_hib]_gofahci_ebcfdeSaegdbbi`d_ceb^edcjgadeg`ab[ek\pdcc_abffjcec]gaWbc]a^fV_g_b^_mg\hdqbfa^Zhkja\cl[]Yba_d_aa^fgi]\\]dpakagfcdddddcddcddccccdcdcddadcedcdcccdccccddccdccdcdcbecdecccdcddcdcdbcddddddddddbdcdddcccdddcdccdcdddccddedddcdddddccdcecdbdddcdddcccccdcccdccdccccddccddddedcbcdccdceddcdcddddccccdcdccdcdcdddfedddcddcecceddcdbdcdccdcdcddeddcddccccddddcdccccddddddddbdddcddcdddbdbdddebcbcbcacabdfcbbddc`bbbdadedfdbbddbccbccd_bcbccbbeccaccdbcbbfccbbc`ddccedabdbddacbaceb`cccecbcaadcdebfbcddbddbcccb`dccbdbabfebbdbaacebddccbcadbbcacacfccfbcccdbaccbabd`bccadaebbccedbbbcbbccdacdabfedcdebccbbcebbcecaccedcd`babfcbcaaaddbbbcdedacbcabcacaaabhd]j]ece\bagfedlqgf`i^eee`_cddfg`bje^b`fqbc]^ihi`ja]`lWX_^b]\akl\^^iiddbeg^gacZ_g`kccinh]jg`bZ\dfb^l_fecamaa^b_cd_lhafdafcfnchZk[e`j`a^nc_gfW`hdge]ea_cnh`lfd]hff_]cicjcXdcjjmancah[e_`c^_UelbjbheX^dhd^acieefd_h[ideedcpic^dbcf]ff_Xfgb`^bbeihc[^fXZ]bYh^lficdccdcffccbdcdbdecdcccbdbcddcbdcbddddcdfecddbcccccddcdcbbabdcbcccccdcbcecddcbcecbdedcfcceedecbdcefbbcccdcccdecdbdcccccdbcdddcddbcbeeceedccccddbeddcecddccdecddeacccccdcbbebcaecbcccdcddcddbccddbdccdcccbcdccdcbbceddbfdcddccdcdcdeddcdecbddcbdccdcbcbcbcceecccbedbd^cdfccccffa_bcaeeda_`e_^g_dcbcfhdf`cbcbgdfgffd_^cfee_jh`b]_bc`d_`d`ai^agda]bfhcfafe^ecc`gbdecehiaecacdaebccgcgcehdega]fjdbb`cZfdggfd^ga`ffcffh][ed^cdelZh^[deabbdceabYaffcebab[dcb_ibedgha[gced_bajl`fga^cgedega\idde^gb^f_dcdek^dac`_`^`_adb__cc`gecfecef]c`hcbbbcabbccbeebdcedbcbccaaccbccbcdbd`dddbbdcbccdb`cddedcacddc`cbaccdaaadbebeacdcbddecabbbcbbcccbcdacddabcbbbcccdaeecdbddbddeecbbbedabcdcddcbcebbcdbcaacadccdcecbceaccdbcbacccebbbbdccebaebacbcdcebbcadecbcccadebcdcdcdcdbddccbbddcecacdddbcebc`cccdbcaccdecddbbcbcb`b[Zf`ef^e]jamaafjfeZebgoagcd`^i`eYbXhak^egiTiciXgl]^jhidbn^_daeedc`ekia\icYc^e[d[cc^ddgh[cfoefa]^o]_cb[gdltfZvdhchcgdigb]cefc`f_]mfa`eccbh]ge\ikelefd`_ch`f]hedak`e`^^lhefd_niYnc^befc`fdX`\ilahied_`l\cg`e`bfcfiYf_dj`b\ie[f\gagW^^abhdldhee^bee\se_edfdeg[^`d^b`iil_cbaccb_ec``dagcc_`_i_k_bccebdgggbeg`bcY`ec\ijiVjfce^^^b^hgcf`_acaaadg\^]d`ccgec_bc]hch]cefh_`_fbgca`YagUb\^^aaYie^i\e[`ga`ebeaa\^Zcbfh_gem[a]b__n\hfdf^``igie\chkgc`\d_`a]idfff[bidig___ij^eadb_becbibiagpb`fc`ac`j_]c_haf\cg`]biccbdecchag_ea^d^a`lbhegccccccccccccbccccccccccccdbccccccccdccccccdccdcccccdcdcbcccbdccccccccccccccccccddcccccdbcccccbccccccccccccccbccccbcbccccccdcbccccccccccccbccbccbbccccccccdccccccbcbcccccbcccdcccccccbccccccccccdcbbcccccdcbcccccccdccccbcccdccccccccccccbccccccccccccccccbcccccccdcdccbcdddddcccbdbddccbcccccdbbdccccdcccccccdcbccccdccdcbdcccccccdcdccddcccdccdcbdbdcccbdcdcdcddddccccdddbcddecdcbccdddbcccccbdcbccceddcdccdcddcacbbcccbbcccdcccdcccbccceccbcdcccdbdcebcbccdccddbdebdcccddcbbbcccdccedcbbccebbcbcbcccbdcccbccccdbdcddccccbcdccc`befa`[eag]iYddiWdcd\c`jbgd^eih]j^_Ze`hgbefacd[bgijX^hd_ckZ`]hheidZakabgk^lihjg]fdgl^bdgdbd\`\_jfn`cchld`_fiqcdR`zjl]bb[aUZ`_db^\cblghdncahcgefggO\fb_dbX]edaa[lYba^gdelbXagd`ki`ih_dbekebbgccY\dfc`bed^cdd]bj[biabf^`cf^g^fnic^X[dbal`kf_jchedlga_pefbf\`cobe]bba`i]af^beh\clSdZh]d_mff`^lh`e_f\fhbeh_c`_a`Yd]^gga`ff]hbae[^`\iqhcaaZafe^gcjf_[g_iebccVcaddjlfad`\g_ga_kdac_df[c`fZghZc[]f``cdi\hafcbae_ei]]g_gax^djhgdda^adf]`][]onmi]gbj]ei[_gdcc^jh_dahmbih\bcYg]i`^h_\\c^ibjlbdehT^_dbU^`cxae\geea_me_`gibajhaeYYb\aagfbf_hhcilcbfg_hcfcdejd^fj`ecbcck\fbeqm^_gl\ec`^h\gZif``eZddakhi^oihapd\accj_\`kifge`_gfaccfcnbed`a\`abeeWghkdZ\fijc_geljnfdacjfh_chcgcZ_W\l_kg[fe``cb]]kdbbnbO[be\h_j``_X\gXeWfbfekben`^]g`dnocbZeb\edcegcbb^hb_fea]dcfaffe_caq^ciZe[g^eecimdWZi^f_ij^^gi_`[bcdj[ciac^`ch[_d_bd`g^ngb[g^jdje^begdap_biZe`f_ajebWdj]dbff^chimbbg`c_aghjZ`ecdidh]gjYc\Za^_g`hadbc^gfkioc_ejef]c[jkkf`Ydbmeocbc^b`eifkdd`cZc`eabhbddY_degheggkgeafhiib]i[_db_cbfcchbcfbnb`_ed_d]b^bTb]bei\Rj`ekba`]a_b`dkm^fdcdefcgdhaedbYadebc[a[d`dl`ih[ci_`dg[bgf^]^f]^b`mp^h^afT^gi]bf`lj_abb\Ycbf_^cagbhehfg_ibcdaig[jg^ejfdeecded\gfbacgheecm\e`^fcheijcd_cdc`je[]dh`\dfcde`ab^hane`c_lde_ibkcdge_jcYfjX^`_a]]af]fdff[``]ag`dlsbaadeg]dmjZee]f_ldbdhhi]c`d\jfY^dnmeemXgZenh]eibdagcmeeg`f`ajdb`ebdcbabd[le_dfggcdaekdd\g\d`[`^bcaVccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccafcbd]be^`fdcbmbef^j[```aadcd`ecbag`_`dbhj[l_ab`fbecfafdd_`dc_gef`ebfbc_d`_\biebcgcddefcfgdgdkifjdhed__gea`cadf`bf_hi]gdbdabc_iae^_bgbde`af_egd`i`mbbifec_hca`ddledajbaecegh_egbcjcc`ceadiiabcbb^ifecgh`beae\eb_i^aY_`cd_aedhge^\_`ga\`eb`fja[daab\lag^b^_`cb_^gfe`cifddje`gd_agab`a^f_baZYggmfbh[[d_jcj]elhehab^c`fgdjjgc_cdla]^`_e^^ZaeZ`agbd`mdfgb`_gd[ii`^bbfdh]^bheaZkhg^cVjefY`jaebbbhg`]aUW`cjeagXadcflg\gGh^`_abdcg`bf]b`ch\\]Yf`f]ff\cgfdbgidgjggac^[]d^bd]dX_[ghe^ehna_f`f_`ia`fgbg`afiZ_\idgl_W_dhg_^m_a^cf]`i`\^clc`_\h_jc^b^`gdh^gbkldeeYd\fbh`d_g[a]ljk_aghadeeddfcbf\[kga`Zbed_^ehjkagc^bgcifdhf\aib]hdfgaedc`[]gg`]cf\id`f_d`bcgcabieje]]_]`ag`\aZbacacflc`]_\bfegcbiac`^abf^bdd`eZ_gddadd`[dfegemciZd_`jcdm^idjfa^^^dc`cgi_\cfcg`nba\`b_hbi\debedgg_`bm_hfaj^bgf^nf^b]g[f`b^ac\nkfaahYjmd_leX^df`i\`dkd_d_f[^rdbh`f]feiZfhgdghhcihacgf\`gg^mo^e_aZc`k]bekhabg_feedd]hXndXg_Zd_W]f`a^bah_^fchbbl]dcd_ffheaYhafghfi`_djroa]copafgaKf][\fhcbfcecaj`bi_U__a`igheaabeZ_^dcafk_gaf^^Td_kec^chf`cchf`fYcbg_hgbdcjggd`cikdd`icf]f`Y]cbg^k`cZbg`n_jZg_ebcbccbcdcdcccccdcbcbbcbbdcdcdeccccdccbccccceaedaddddcccecccdcbccbccdcdcdcbbddddecdccbedcdcddbbbebdbdccccbbcccdccccedcdccddccdacbcdddccbeabcbcecdcbbdcbccceebdedddcccdccccdcccdccccbcddcdceccbdcbdcbbcdbeccddbcdcdcccddedccccdccddeccbcddcaccccdcddcccaecbccdbdccadeccccdccccbdcbbccdaccbccbdcccbddcdbcdcdcbcbbcbccdddcdbdcbccbccccaddcccccdccbddcdcccbcdbbdccddccbcccbcccdcdbdcdddcccbdccccdcccccdddcdeccbdcccccdcdcdddccbccccccdbdcdcccdcddbccccccdbbdcdbbcddddbccbdcdcccdccccdbdbcccdbbcddddbcacdbcdccdcdcdddcddccccecbdcbccddbf[c`ccd\g^\[aihYadafil]cgl_i`fbdccdeVdkdf\]_beg`[eejZ[cVgjc[Zgbdcbbamtndi[f[X_\[]im_hg_f[\`cqabY\bndbZZdf]cajc}ehbfhVXbc]lfcag`lbaug\qQebgbV_i_qzdh\je]YfcbdihdTYfmK]Z^kdmiWceaie\eebiVPdb=nleZebjcge`vXYclbUcqaUh`aieai`backbhka\df]e`gr[bb_]o`d`bnge`dhec_[bfccccccccccccccccccdccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccdcccccccccccccccccccccccdcdccdccccccddcccccbccdcbccccddbcccdccdcccdcbcdccccdccdcccccccccccddccccccccccdccccccbccccccccccdcdccccdccccbdccccccdccddccccccccccccccccbcccccccccccdccdccccccccccccccccbcccccccccccccccdcdcccdccccccccccccdcccdccccdccccdbccbcccccccccccccdcddccbcccccdcdcccbcccdceccddbcddcddbcddcddccddcddccbcccbbccdccccccccdccbccdccccddcdcccdcdccccdbcccccccbddccbbddccbcccddccbcddcccddcecdcccdccdccbccbccbdcdccbcccbbbdccdccdcdbdbddddddddeddccdccddcdcccbdbbccbbcdddddcccdcdccdcdcccbcccdcdcccbddbccdccdccbdcbcdcccdccdccdcdcccedcddccdcbbddbccbdbdbeccccdccdcdcecacdcbddcbdcdddbcbcdbcdccbbbcbbcddccabcbddcbdddbbdbcedbbaadccecccccccbcbcdbcbcabbddcaabdcddcecdcccc`dcccccdbcdabbccfcccabccbbbcdeecbdcdbdddbccbdcbbbdbbcbccddbccdcbcbcbcdbccbbbcccccbcbdddbddccbbedbbcddacdaebcdccecccbc`acbabebdddccbaaccabaddbcc`bcebbccaacbcbcgcacdcaccbcbcdccacbccbbbgdbccebcabaabbbcabbacddcbbcbcdabdacccabacccbdcc`bccbccbcf_dddbdccbc_cacdbcdbccddbbdbcccdacaacbcdccdadecbbbbadcacbacccdcdde`ccbcdbdccbacbcbdddbabbbbbbdccadbdabcccbccbbbcbbdbaaccbccbbcccbbcbdbadcbcdbcbabidbc_gcdbccbe[c`fcbabfgddca``e_cfdadfaadcceedebfdceeaaem`affeejacebbfcabbe_bfc``ead]ac_bdfded`a_cace^efeccbaahaacacfbfbc``k`cb]ccbgbeb`e_deeaga_``bb`de`b_jbddadc`ec`a]ed]bdadbec`cehbdbabgdbddae_bccdacbeddhbcedeab`be_c_d`e`d`cadfabechcac^adcf`d`bddegg_cle^hcccccdcccbccccdcccbcccccccbbcccdcccbbddbbccccccbccddcccccccccdcbccccccccbcdcccccdccdccccccccccccccbccdccdcccccbcccccccccccddccccbdbcdcccccbdcccccbcccbccdcdcdcccccbccccdbdcdccccbcccccccbccccccccccccccccccccccdcccdccdcccccccccdccdccccccccdcccccdcccccccccccccbeebe_ceeccbdfdebjac_f\dedbfeca`ebbebdedfeceffggdccecd`dbbedbecfiabedccccagbb`eebcddbcdehaedagdiecebdeffebbcbegccbc_iefadebdcca`acbfjddgbfbaecddecedgeac_gacadecgfded`ddda_bffebfefd`ceaafg_ccffcbcd_cebecgbfchbf^dgafgcbbdbefeaeegeffcdb]_ecccbc`ce^`_`abfdeafcZdam_ac_h`b^fbh]a`gedgc]_f]agpf]`\bYTbccccfaaffg`]\jdeh`Wdce`gibb^afeg^`gccco^c^d^chf^f]ggdcebb[_edj``\Y_hncmgg^`iebe\abdafe`_haahel_egd\ajhhnfa_Wfibgd_]]dfhh_^hgafai`Y_hhgejilhc`_kgk``fdZgcddf]_fe^d^]bfc^g[ggad`ait`fep^ka_dc`fachh\bZkgdi_ei^ccii_db^gh`_gpZibY`gdj_iagn`]gcTib_aaa`djbdc`gaccdofb^^j\efldUjedaghSd`giWf^_[elc`e`agfb^dg_aqicbbo^fdbc_dc_hg`cln]ac^fb_fnggkdfda]b`^\ihhcgifbkshef`mfmdffcg[[[a]gaab]he^_Vc_ifcae^fcg`^kj\_Y`_Yedin^bZTmccg^\Uddab^eba]kef]``fgXf`S_d\h]dkckagheg]d_f_e_Wca[d`\fbifmkh`eia_cccccccccccccdcccccccccccdcccccccccddcccccdcccccccccdcdcccccccccccccccccddccdccccdccccccccccccccccdccccccccccccbccccccccccdccccccccccccccdcccccccccccccccdcccccdccccccccccccccdccccdcdccccdccccccccbccccccccccccccccccccccccccdccbcccccccccccccccccccccdccccccccek\Z`]g^_i^`ibba_[ff_^jhfgk^d`_nid[^o[iagab_hc`aj_g^YZ[edmc_g`jiefidaf\j_bYb\_bedd\b_^jgh\^bhahcadboegacac_msh_hcb]kd^`e^cie^ib`dmicbifllg\a_gcef`_gfmn[\cfY_b[agbYadaf]b__d`^hma`Zbcm`ehUYnb_efa`egcac^[`]gc\Wicmf]f_See\\Ue^ccZXhcch]_kwelhde^^f_ch^dlh`fdeh]\ccccccccccccbccbbcccccdbcccccccccccccccccbbbcbcccbbccccccccbcccbcccbcbbbcbcccccbcbcccbcccccccccccccbbbccccdcccccccbcbbccccccccccccbccccccccdbdcccccbcbccccdcdcccccccbdcccbcccccbccbcccccccccccccccbcbccdcccccccccbccccccccccccccccccccbbcbccccccccccdccccccccccdcbccddcdcddacbccccbccdbccdebdcdcccdadcbcdedcdeddccdececbecccdccccdccdddcdfccbdbdcbcdddcbcdddfcecdcedcdcdadcceddddcefdcccebfceebcdccccccbdccdcbebbddebbcccdbebbdbddcdcdcdecccdcddadeedcdedbbcccddcccbcddccddddcceccdfeccedcddebcbdbcddbecddeccceccdccbdbdcbbdcddbldae]je]ch]b_a^k]aadaddcfcfVc`eggldebhcbb`ebag`dggedbef^ggacaddbeida_ccefhbbceeh`cgdbcha]^bi`hjafbfgd`da`cbcicfcidage_cd\cjbbdbd_cgdebc_^dfead^cfcbcfaf`hbcdZbhaadf`[caagd``_addd^eaaedfbefa`hbf^bce^f]eb\^hh^ecbec]afcgjc^ffdj_b\bfdebcggeca`dfdb`^`ffbe_c]bbc\cbdcdccccccceccdbccdcccccdccdcddddccbcddcccddbdcdccbccdeccddccdccdccdcbccbccdcbccbddeddcbddccccccddccbcdccceddddcdbedbdbcbccdccccbccdcddbccdccdddddcccccccccccddccbcbcccdccccbdddccbbdcdccbcbcbcccccededcdbccbcccecbccceccecccdcccdcccccddccbccddcbdcddccddcdcccchfgdU[iceb`bgeefdcg]g^g`ghb`bc^__oab]i_daa^k`rZg]adcjijf`emh_Zcd]kg^ide]afg`dj`kf[dia`efjbfeY_je]aijed^`cdcafgfchcchg`badciidf]heide`aiej_fW_\Xie_c`]_b`fajgcXdakZZgi]hha_^gieghk`aic]h_c]b__boYb``d_^ejhdfhh`de`df`c^ebgejegc`hbg`eOhc_if]jae^h\`le\dbcad]che]dceebbadcaccabddbccbadbcaddbe`addagabdebccbbcabacaba`debbcbfbbacdbbacbbca`cccbdbdbbcgcfbbbbcddacdcadadb`adbdcdcddfdcacbdddbdbbd`bdaddadddbbccadada`fbaba_cdaccdd``aacdbadbaedcedcebdbd`abcc_acehbbbacccfccc`abfadcdddabbbc`e`_cacdca``dbcccaebacbcceebb_dccbdbab]bc_]md^dXejebjlcbd_i_Y]_c`Sc^]e^gfnkefifb`c]_i[d`ak^dqo_e_gadefgmc`dgifdeZhjZ[`d[d`jitf`\bbd_fkjj]jaTc`hdegYcclg_`gZ\aaccZjac]acbjemei_blac\ajijb\icZa`iclhbekXccd]Ui`b^hagf^fijmhfhgdeZdlZfi^j_aaZdf_fd\dgcXhd]gh_g`]i`kfkWgeb_`_jh]ajdl]a_]ec`\e_bcb][hb`cbZ^a`eqfpdeebbia\hc`ic\]gccbg_e^^`dfkhd^madc`_aab`h_agggdn_af`addea\f`f]faeeb`e]md_ebdke\^ii_i`\chechhf`bg`bfldc_[\hd^[[eldji_hcae]ch\dchd`h`cp_imbdY`ca_bhh_gdl]iea\gab_afaheac[bb_ap`c^bc^icWg]`^lf``]dhgefbd[hbe`Vbncdm`ob`o\fcdaaZ^hd^^aZfb_cebc[dgge^cfdfdbkgfb`^_h[hfccfame_e_cc`gbbhakgjf]\eejacidcc`dg`g\e`bcjcbc[hacadg`facifa]chdaffaaddh^__ceb^dbbe_cbfbfedd`bdcbf_afh`wa\f]afbea_nd`i[h`addajdc`_c`agia^j`bfh__gkbbhdccabfc_ah[cad_fca\_cgeaipbaigej`c]cghahdei^gfcg_feicn^gebcia_cbcjeeadbfgdlbhie[adaefbcdladei__ha``cccdcbddcdccccccccccdcdddccdcdcccccbccccccdccbdcccdcccdccccccdcccccccccccccccdcccccccdcccccdcccbcccccccdcccccccdccccccdcdcccdccccccbccccdccccccccccccccdbccccccdcccddccdcbccbccdccccdcccdccccccccccccccccccccccdcbccccdcccccdcccdccccdccdcccccdccccdccccdcbccccdcccccccdcccccccccccccccccccccccccccccccccccccccccbcccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccdcccccccccccccccccccccccccccccdccccccccccccccccccccccccccccccccdccdccdccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccdccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccdccccccccccccccccccccccccccccccccccccccccdccccccccccccccccccccccccccccccccccccccccccccccccdcccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccbcccccdcccc]\_kq^fd]e[hfYZeedfYa`\dacsfY[i_e`\hkck[d\cgRsda\chg]bdb_fgfbc`][e`X`ehcga[Vi]ibe``dej^j^gdqdadhc_lgced`h]acfgpfZfklcah_agbcca`kc`k^f]aZd`fb__``zh`Zc_a`cZ\]hi`_h]kfe^bjcadeh_\_gc`\ce``ebedbdZb^gfleadgbmlgZmi\_l_`hdeg`gfdajkchfd^cf`ea_ge\ejaldd`jf\j\i\bdl\b`bc_be__bbc_aab`ccfbeeaadbfbhgkab_aYcad]`fcc]ded`ababbd^_e_a`ebbcacedc^_\ebga_ba\icbdaa_affc`c`d^ddb`baacecdebh`dfcba_bfccb[a`c_`fdadeb__dagcge`ccdjd`cafbdbecacbce_ecbdcabd_]_db`_bjb__ae^decbc^_cadj__daacb`eahaefccaf_gbdbdifaaadfe^dh]e_dcbf`fabf[`fe`ecb^_beccbdcedcdddceccdeddeadccdcbbddcfcddccdcdbcbdcabdeccecbbedcbccdedbbbddeccccdcdbbbcdbccefceccebbbecdcbcaccccbccbeebedbecccbeccbeecedeeedfcdecaecccdcdcbbabdbcbdacbdbbcdeecefcbccbddccccbbccacdddcccccccbbcccbbceccbddeccddbccdbdcbbbecbdcebcbbcdddbeebbbcdcbddcddccbbebebbdcde`cbccdadedaaba`bagbedb`d`bbbbb_ddbccdaebfecdbcdcdacbeccbdcagbc`ecbfdeb`ccfgbbdbe`accdcecccecd`bcbdbaecccedbchcccccebacddabbfdecbfbaeccdaaedbfdfbdcdcbbeadebecbbf`bb`ebacdcbecddb`abcdaeb_babbdeedebcdedeeaeddcdedacdeegfdcdabcccbddcbdabcdcbdcdcddececccdccabdecdcbedbbbcdddbcddeabedcaddcecddccccdddbbcccdacccccfcdccbddcccddfddaccbdecbdabcbbddaddbbebcbdccfdcceeedebcdede`ebdcccbeecddcdddeccdbbcccdccdddbdcdeccdccdcadccbbfbdddbdcdbdbcdcccebbbccbdddcbcdccccbdbccbdbeddcccbdbcdca`cccbbcdeebcdcabadddbbfaaeeb`dbYibfYiX`^dc^c`bc^ih]bef`]g_ZgbZbabcabklZ_`^ach\Y^jZiYgmgaiZa`^_m\iZ`dfg_dZR]ggi[koafjaed_ghdjdj`dd`egdbdadW[\kS_e`gbgfg]kiavcf_cb`ejkkd][ebdbdah`befYe^akW^gOib[Ye[p^b`ebd\dfahe_`jc^kfhaeT[shebg`fYWbc]eih`agbcl]ff[eifZb^`figeeivfwjWdhagf_g_c_bc^a\Z]f[ogiccddbcccdcdcbbdcccdcccccdccbddcceccbbddbcdbdcdbbcdcccbbbdcbbcbcbbcbdccebcccdbdbdbcddccccdedbcddddcccbbccedbcdcaccbccccdceccccbcacdddccbaccccddccdddcdcbcbcdcddcccbbcbbcddccacccccccbcbecdbcadcddcccdbbddccbcbdbcbbcbcbdccbcbcbcbcbcbcbbcbbccdddcccbbcccbcbcbeccc\a_`id`V^abuZcgh^ab^X_YffncZfaobeY^h]fd^id]mh_[^_hUYkPcbef`ca`eebb\l`[bfbhggb`e]eX`rihkgg_^ceem_mi_hZ^fmdWidYo`]h^ie_db[df\fis`_aVcgdf_jg[\diapiddahh^ij_`gdfe_]f`c`dbfekkc`^cei_maZ\g]f]le\ddY\qgia`Ogh]Zla_agaifeaUa_jc[\Zli]V_\gaobafj[ef_eZ`f`gZfhfbe`e^ifZcdcddcddcdccccddccdccccdcddccdccccbcbbddddcdcbcdcecbcdcdcecdccdecdbdecdccbbddccddccdbcdccdccccccbbdccccdcdddccdcdcccbbccdcdcccdcdccccdcccdecccddcdccdcccbbccddcdcddddbcdccccdbcccccbcddcccdddccddccbccdcbdcccdbdccdcccdcccdccddbccccddcccccdbddcdcccccbdccbcbbccbfhc```aadged[djeb_laeZ`cecba^bcccadcafcddeamdbafe_befl`bff_ddZc^age^eac_hb`_feagecblaha^d^eacfhddbdcfbfceeffec`ddfghd^gbcheh]f^id`d`dfhfbb`d]c\gbbe]_c^h`cg_chde`hZfe``fjced^gf`hhae`ddcaafhbcfbbY`\hbgdabgedZbc_b_iecbfd_chbdbj`e^b\gc`i^aabdffdbeeh_ebai^_g^_cccccccccccccccccbcccccccccccccccccccccccccccccccccccccbccccccccccccccccccccccccccccccbdcccccccccccccccccccccccbcccccccccccccccccccccccccccccccccbccccccdccccccdcccccdccccccccccccccccccdccccccccccccccccccccccccccccccccccccbdbdccccccccccccccccccccccccccccccccccccddcdddccccdddccddccdcbccccdcccccccccddccdccbdccdcdccccccccccccdcddcdccccccddcccddccccccdcdcdcccdddcccccdddbcdbdcccdccdcdcccdcccdbddccccccccddccbddcccbcdcddcdcdcdccccddccccccccddccdccdcdccccdddcdccccccccdcbccdcdddcdcdddbcbcccccdccdddcbccdbccdccdccdccccccbabbccbbbcdddcbcbbcbccbccccccbdbbdbbccdccdbccabcdbbbdcbcacabcccccccccbbcdbccbcccbccccbbbccbbbcbbbbcccbbcccbdccccbccbcbccbbbccbbdccdbccccbccbcccbcbdccbdccbccbcccdbcccbbbcdccbbccbdbbccbdbcdbcccccccbccbbcbbbcbcccccccdbccbccbcbbdcbbbcbcccbbccbbccdcdcccbddbacccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccdccccccccccccccccccccccccccccccccccccccccccdccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccdcccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccbdccddcdcccccbcccbcbbcbcccdadccccbbccccbbcccbcbcbdbccdbcccccbdccccbbdccccbdcccccccccccdccccbcccbbcbdbcccccccddddcccbdcccbbccbbcccdbcbcddcdccccbcdcdcddccccccbbccbcaecbcddbcccccccccdcdcccbcbccdccdcbccccdbcbccccbcddcccdbccacccbbccbccbbbbcccbccccddccdccdcbcccccbcccccccccccccdcdccccdccccccccccccccbcbccccccccccccccccdcccccccccccccccccccccccccccccdcccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccdcccccccccccccccccccccccdcccccccccccccccccccccccccbcccccccccccccccccccccccdccccbccccccccccccccccccccccccddcbcddcedcbdcccccccccccdcddcdcdcdccdcddcddccdccdddcecbcbccdcccccddccddcdccbcdbccdcbcdcccdddccddcccdcdccdcdcddcdcccccccdbcccdcbccecccccdcbcccdccceccdcccdcbbdccddedcccdccccccbbbcdcbcddccddeecccccdcdcddbddcbcbccddccdccbddbcccdcbdeccdcdecbcccdcedcccccddddcbcbcc`]_g_cdch^gdag^]cge[_megdehf]ie_egWfVac_`dgdgkcUVcnXceYdfcdef`]admeeb\gcg^c`bdkW_da^cfngfdUekabp^dajpgdk`eda_\ac^ccccaik^l`ceid__gc[Zba^bbjglacdeadbafce]kh\edbfeZZ^cbpb`_fagcdj_d\hXbj`ecbjdcakk`\h\gddfab^hdadeeakdedgg]`_gbc`[g_d]b[[g`fgVcaahceimd\hdbdl`cccbcccccccccccccdccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccdcccccccccccccccdcccccccccccccccccccccccccccccccccccccccccccccccccbcccddcccccccccccccccccccdccccccccccccccccccccccccccdcccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccdccdccccccccceccccdcbccccccccbccbcccccccbbcccccccccdccccccdccdcccccdccbbcccdccccccdccccdcccbcbcccdcddcbccccedccccdccccbdbcccccccdccccdccccddceccdcccbccbcdcccccdbbcdcddbdccccccccddcbdcdccccdcdccdccccddcccccbcbcccbcddccdccccccccccccbddcccccbcdccccccccccdcccdccccccccccdccddcccdcccccccddccccccccdccccccccccdccddcdcccdcccbcccccdccccccccccdccccccccccdbcccccccccccdcdccbccbccdccccccccccccccdcccdccdcddccccccccdcccbdcccccccbccccddccccccccccccccccbccdcdcccdcccccccccccccccccdcccddccccdccbccbccbccccccccccdccccdccdcccbdaagj`ef_aaedd]\dd][__a^f]]^le\dbj`fi_gbaece\ca`ebeib^lf\chmegZacbe_eebbagafhciabbfdfg]fekbi]\_[Yai]`ceada_db_maaca_daebachfe__ibdh_ea_Xjb`ai]gfgdfe_e]c]ldkd]hbdca]fad[igbdcbdceaWhakbWgaficbac_dfle_fmmi`edcgdcbhYgdaeibace^b_db\ecffkeae\feghfj[fh`ffd`^aaeh]^[]mdej__bZ`i^]c`^j]hjYdfifffce^`[hfcbafd]]`Yl`_ja]j`7^magiY^k[`af^cdc_c^ddg\Yefa[eabfdg_b]fYl`_f_lffdg\^\\bmcoc^\ifg\a]a_bcd`^idgi`eck]`_`\edhfz]fcd`aedcb[\hh_lYbm`tcaZZd`gPdga[hendd^gZagece_lijed`bfgmcZhdheefjgSdfib\hkdfVh_jbe_aluhbg^beeh`]dab_mdgfih]cdeecccdcdbccdccccccbccbdccccccdcddcdddcdcbcdbcdccccdccdccbcdcdcccdcccdcccbdccccdcccccccccccddccdcccdcccdccccdcbccccbddddccbdddcccdcdcdcdccddccddcbccddcedccbdddddccbcddbcccbdcdcbdccccddcdccdcbdccdcccdcdddcbdccdcccdcdddedcbccdbccbcdcbcdcdcdccdcdcedbcccdcdddccccbdbbcdeebcccbdbbdbbbdbdebbbbccdbbcccadbebcdeabcdcddbeebbdfcccbdcedcdcceeabccddccbaccadeeddcedbcabcbbdbddbcddfcadbccbcfcacdbbcccddabdcbbccccacbbccddcdcdbaccdbceedccccbccccccb`cdacdddccbddcddaccdcaccddcbdcdebdccdcccbaebbdbcccedcccddddabdcdcdebcbebbddddbcbcccccdcdcccccbcbccdccdbccddcccbccbcbccdbdccdcbcccddcccccccddccccbcccbcccccccbeccccccccdddccccddbcbcccdccddccdccdcdcdcccccbcccdcccccdcccdccccccccccccccbcdcbbdccdcdcccdbdcdbccdcdcdccbcccccdccdddcbccccbddccdbbccccccccdbccccccdcdcddcdcccdddcdccccccbccccccbdccd`bc`bdb`ebfagcbbcdadbccbbcdbbacacccbbfaedaecdccchaadfacgb`deccefe^eadbccbbbebddbbfcdedcdfcb`bdea`fbaeccdgbcbd_aeahccc`gcaabad`ccbc``edbadcbfb`ccdcdcacbdeb`bgbcbcaacdbbecgfddecdecgcdbdddccfbbbcbfbdbf`cdaded`cbdadcdic`dddgb`d_ecabdcdgaaeffebaca]facabbcdcaehedcccccccdccbcccccccccccdccccccdccccccccccccccccbccccccbcccccccccdccccccdccccdcccccccccccccccccccccccccccccbcdccedcccccccccccccccdcccdcccccdccbdccdccccccccccccccccbccccccccdccccccccdcccccccbccccccdcccccccccccccdccccccccdccccccccccbccdcccdcccccccccccccccccdcdcccdcccccdcccbcccdcccbdcccccccccccccccdccdcccccbcdccccccccdcccccbccccccccccccdcccbccccccccddcdcccdcdccdccccdccdddcdccbdddcccccccccdbddccccbccdccccdcccccccccccccccccccdccdccbdcccccdcccccdcccccccdcccccdcdcccccccccccdcccccdcccdcccccccdccccdddccccccccdcccccccccccbcdcccccccccdccccccdcccccdccbcccccdccccccbccccdccbbedcdddccccccccccccccbcccdccccbccccccccbcdbccccccccccdcccfccccbccccccdccccdbcdccccbcccccccbdbcccccccbdcdccddddbcccbcccdccccbdbccdcbcccdcccccccdcccccdcbccccccbccbbcccccdcdcdcccdccccbccccccccccccccddcccccccdqe`iafdbhJ^j]_mcfYnchfk\V_p^Yig^\YbiVi^df\m[_ccga[_}f^dc\egngfd`eodid]\bad]hh`[ibf^g`gbc_\kicae]bbdc^dfic_edTlmdQa`i_ghgbbkcbccalpZb\]dfkjchc`Wa_op_gm\]`gcf_bdlcZlc_]g^e_e`db_cadhZgW^iNfcerd\k]e`abefaaea]jdp^rg\s`aXbcdhdcUcaggr^Zf^iefnf^hbc]ebadb[^djf`dcecdeccddddaebdeccdfddbcccdcedcdcdcddabdcebdcbecdccbeebbddedcdfcdcbadccccabb`cbccceddddedcddbccbccddebccdcdcdcegbcccdcdbcdcbcccddcdcaebdccddccdebdcccdebcbbcdcdbddbeccbcddbcdcccccccdcdbddceddcbcddbcbdbdddbccddbcbdcdbccdeebbdcddcddccbcebeadecbcccbbaccfdcddddccccccccddcdcccccccccdccccccccccccccdccccccccccccdcccccccccccccccbccccccccccdbccccccbcccdcccccbcccccccccccccdcccdccdccccccccccccdcccdccccccdcccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccdccccccccccccccccccccccccccccccdccccccccccddcddccbddcbcadaaacbbedecabc`bdadbebcdccdccbbcbaaecbccddeccddcbbbbcadcadbcacddaacddbddcbeccbbceddbdcdddccdcbdbbddddccbcacbbcbbbcbddcb`cbcccbcaedcdcbebccdcbgcgbcbcbcddgcebcddacbcbaccccbaccfbacbccbcaab`dddcdcbccdcccbdebdcdacccbadcdcacbbbccbecbbdcbfcabacdfcbaeccccccccccccccccccccccccccccccccccccccccdccccdcccccccccccccbccccccccccccddccccccccccccccccccccccccccccdccccccccbccdcccccccccccccccccccccccccdcccccccccdcdccdccccccccccccccccccccccccccccbccccccccdcccccccccccccccccccccdcccccdccccccccdccccccccccccccccccccccccc[bcedckha_hdbabac_eadge_d`ebd^d_camee^dleb``abea`^e`_bcZfg^gehbgfb]bYijdia`bgei``e_fe\cih]edafb]eZ^daedic^g_c^_Z^cgbcheheh[ijbae_c`fbfffdgfbcabbhefbaca`ekcfejeec`^fbecca`g_fjac`l_feb_gajbheh`efc^dcbg^iaf]e`ecedcceicefc_gh_ibgdecfcfefggdgifec_d`b`f_e]daadb`dccccccccccccdbccccccccccccccccccccccccdccdcddccccdccccccbcdccccccccdcccccccdcccbccbdcccccdcccdccccbcccccccccccccddcddccccbccccccccccccdcccccbccccccdcccbcbdcdcccccccccccccbdcccddcccccdccccccbcccccddccccccddccccccccccdccccccccddcccccccccccccccdcbccccccccdcbeieage`bic[ei`ca\hb]cdeb`^Zichcaigebd_a^fkchmcfahh__hef]\ff^\ghodbdi\bbbbbedZlbc^d`b`b`fdba]bjif^_c_ccfcdfbc\ca^abd_[ffjed_bgYegce`ef_a`gh`de__dbamaddcihbgbl_^hgdheg\`bcefaabfdd`kgl]Vhafe[dbejbia]`g[fde`cec`ebfaidd_geag^[akeg_g_ae_agaechbhegd[da^bcab^hdefcbbfcbebageeahbbebd`bc__b`dbdd^^fbcdadeje`d_gdbabagfbf][lca`cc`c_ababbbbcedbddd^iaab]\cd`acaaf[afgccbba`dhf_cdcbffbcdbfbhhdd^_hY``\ghjae`_fd_cbgdaa^facdbccbbbfb`debi`a\bbj`cebfdg`adb`jcceaejbgf\bc`e^deckf`c`decbeded_e\dicdg^eedcadedca]daae`bddbdei_fb`__g_ca\c\h\_hXc`l`pgjc`f`qeCbZeTageiaWjX\^j[^kbgour]adegoTdlixhm`bmflP^gq\dV^dilfeijaZUebVchagYgn_a_Yon^fbdijfee`fcod_bf]bd[__dU\OZf_g_\`_[gdeqa_^Vodeeceb_`balXg`Yeh^e\db`ealdgkdZb\\_dgamZ_ioaXcle[ak]]emqkW`e^\dVcpbaiaicWpebbdeYcdvWbUbfce_bhb]`ad_^gady[_^tXsct_eccccccccdcccccdcccccccccdccccccccbccccccccbcbbcccccbccccdccccccccccccccbcccccccbcccdcdcccbcccccdccccccccccccdccccccccccccccccccccccccccbcccdcccccccccccccbcccccccccccccccccdcccccccbccccccccccbccdccccccccccbccccbcccbcccccdcccccccccbcccbcccdcccccdccccccccccccbddcccdcbdbdaddbbcdcbbddcecddeacddcbccabacbdcddccc`dd`acbddbbdeebfbbdbccbcdbecaafbddcdcdbbccdcdccebdcacdaddcbdabcccdbcbdbeecbfbedcecbbabcbdcddcccaddedcdbbcbcccccdddbfbeccdecacba`acdccabcccdbbbccdcbcbbbgccbdcccdbdcdcbccd`bccc`bcdcfbbgbccbbcdecdcddcbfdadcbceahdb^Xf[_]^e^]iekehbccbphgd\\eb`^cc`c]deidg\d`[def\_e[df]ibck\c`d]^ake[n`]Tg]b_edlYgdheab]bi^fkTakhgfkf\`Yf``_`aga^cb`icdmfgqbmgfdc_h`hfnZ\d]g^ed^id\b`^dc_fbd__ff_dXj^lacfibhjck^cedadefg`a`afg`gc]l`c_dcd\d`haihbi_fiecdha[c`_c_bdfoei`ddbgchdcaf\iZddckdhdhlec``b`eaebcdhdeddddcdcbcbebdadff^ceadae`c`c`ccdffeed`fecehddb`edcca`cabhdcccfa_hcbdedbcadcebhhbabeacecaeebdbbcbb`debaa^gbecidaggdb`dcedaacafcbec`gedbcbdchddbbbcd_bad`cbecbab``debcebc`ba`bd`cccbgd`dagb`ddbcf`cacddaabecdfcdddebdbdcddcccc`dg`fee`bbcddcbe_cabdcccffcbcmf\`ayh`YY_gj_fpdWa]ujbgmY^a[__bjb_dd^RmWmXa\chj{bRqechjhj\e]kgWXb]Z_zc``dil`ef[^\^\iehdUdWjco[bdffTh`owke^[diX_de\^^_^`ljKggd_elX`f`ggbiZbdZmhm_U\k^Zr^`^neecYUa^hfjdi]]el\\glg^yerchbbeifali_mWbc^]]f[]wfcL_~XUVbv_jache\ei`cbXdfcfY`gZ^bYdg[b[^]iRX]^idcdbcccccdccccccbccdcddcccdcbcdcdcdccccccbcddcccdbcccdcccbccdcdddcdccccccceccccccccccccbcdccccccdcccccdccdcccccdbbdcbcccccbcdccdcccdccccbcccdccbcdcddcccccddcbcdccccbccdbcddddcccdbcccdcbcccdccccccccccdccccdcddcccccccccccccccccdcdccdcccdccccccdddccdccddccccccccccdcccdccccdcccdccccccccccddcccccccdcccccddcccccbcdbbcccccccccdbbccccccdccccdccdcccccccdcccdcccbcccccbccccccdccdcccbddcccccbccccccccccccbccccccccccccddcdcccccccccccddcccdbcccccccccccdccccccccccccccccbcccccccccccccccbbccccdddccddcbccccdccccdcbcccccdccccbbcbccdccccbbbccbccbcddbccdcccbcdccddcccdccdbdccbbccddcdcccccddcccccbccccccccdcdcdccddccdcccbcccccdccbbbdccccbcdccccbccbcbccddccbdccbbbccdbccccbbccccbbcccddccbdccccccbccccccdbdcccbdcdbbbbdccbccccdccbbdccccccdccccdccccbcccccccddcccccedcbdbbdcdbddccccdccccbcbccddebbcccbbeccccddcacccdcccdbdbbdecacdacdcbdccagbcdccbecccccaacdbacbdcbcccddbcdccbdecccccbbcbcbbaccddcccbadcbcecbcbccdedabceaddbbcddcccbccfcaabbcbbccbbcbaccdccabcccbccbbcecfcbcccbcbchcdbccbccacdcdcccdbbcccccdfdbcdbccccccbceebcccbcbedcacdddcbbbcaccbacbabedbdccccbcccbcccccccccdcdcccccccccccbccbdcccbcccccccccbcbccccccbcbbccccccbccdccbccbccbcbcccccccbcbccbccccbbccbbdbccbcdbcccccbccccccccccccccacccbccbcbcccccdbbcbcbccccbdcccbbcdccccccbccbcdccccbccccccccccbcccbcbcbccbbbcbdcccbcdccccccbcccccdbccccccbbcccccdccccbcdeafaebeeccecgcba`ccedbcfehdbfcbbc`cgacebcbaddfbdd_bafbaccdccbedcccbdedecbcbcceecddaeba`fdddfdcfa`af`ecb`ed_bcccbacd`bfcccag`bced_dcdeaabefcbbccbgccdcdc_bcdeeccbbedddecb`ec`caabbdeccde``ffafedddcebeecbgbefaccdddd`bbfdcaedddecdbdegaeeddb_ddbcagfbabacf_fccacccccccdddcdcdcccccddccccccccdcddcccccddccccdccccccdcccccdccdcdcdccdcccdddcdccccddcccccddccdceccdddccdccdcccecccdcccdccdcdcdccdcccbccddccdcccccdcdcdccccccbccbccccdcccbcddccbccddcccbcdcccccccdccccccccdcdcccccccbcccccccccddcbcccdccccccccccddcccebccccbddcccdcbdcccccebcddcdcecdccebdecdcebbbcccdcbbbdccbddcccbdbdbcdedbcbbccbcebdcbdbdbdbccdfccdbcdcdcbbdcccbabbccdccccddccdcacbccdcdbddbcdcbdcbcaccbcecbdcdcdcbcbcbccdceccccccccbccbbcdeccdbccdccdcdbccdccdcddc`ccddccbdccdcddedbdcdcbccbbbdccccccbccbbbbccccccebebbccdbcdcbddccccdcccccbcdbccccdccccccccbcccccdbbcccccbccbccdcccccbccccdcccccbcbccccbbcccccbccccbcccdccdbcccccbcddccccccbccecbbcdbccbbcdcccccccccdbcbdcccbcccdcccccccbccbbbcccccdcdcbddcbdcccccbcccccccccccccdccccccbbccccccccccbcbccdcccccbccbcccbccbbbcccdccbccccbcdbccdcccdccdccccccccccccccdcccccccdccbcdcbcccccccccdccccdccdccccccbcccdcccddddccccccdbdccccccbccccbcbddcdccccccdccdcdccbcbccdccccccdbccdcccdcbccdccbcccbbbcccbcdcbbbccdcccccbcdcccbccbcdbdccccdccddcccccccbdccdbcccccccdcdccccccccdcbcddcddbdccbccccccccccdbcccccdcbccbfebZa]j`_gbj__^g]\fe\^cbicagmgjja_`ecceg\fXkagbf]VVf^_ihfbed`djdY`dhk_g^^gdne_[_`jckjff[\eeha\abk\h_d`\]Xkgrkdedbkledd[cbgeaVhjdbdaeWgcYW^g\ecej_eeedp`i\g[defhadb^e\dg`bfe_c^]jic`jdbhcff]fec\]dbd]dal]^ikddhfaeag^[ak^h^ebindd]heZ_ahe`oig^eafcdbfbleZk_eee\c^g`ica_af^^bcbhgeja[eggeZ]V^a[Ze[sg[b`^e[e`QbYeh_hgredehSbm_eY`YmdhXjWem__addabhfeka^\aah_eY[kxd^geeba]b\b]gghfY^b`b^hgdoijboh[fd`^ZZmbffj\_lqcfXgbjrajpgndj_dgfflfhSiZ[[ahd`dbjjY`Zkg\ccbdb\cbihimZacghg_ic_]abQaib]pdfna`X^cecee^bcaScgbnminedhbfb`dZ`daec`dYVaeddccacdbccddbccdbcccecddcdbcdcccccdddcdcccdcccddccbcccdcbbcbcddbddcccdcbccddcccadeccbccbbcbadcbcbceccdecccebbdbdcbbbcdcddddddbccbcdcbccceccccccdbcdedcdccdcdcccccecdccbcbbccacdbdccddddccdcdccecccdccdbdbccbecddbcdcccdcccecccbacdcccbcccdbbadccbdaccddbdccedcccdccebdbdbccbcdcfbdbcacceddbdddabdedfeddddcdefccacccbcabcdcabbbdaeccdddbdddaccdbdecbfecddddcbbbecebdadccabcdceccdbcbddeccdccdccbedeecbceeecebcbcbdfcdccfcdbccecdbcbeccdbd`ceccbbbeedecbdbdcabbcecdecdbbddcacbbcdccdfccdddececccddbccdbbgbcfcd`cdbceacccebcccbcfao]dcp_YZcfgbShZn__P`cV[rk_i`eTgXnekeUcl]ddeceg_^bmjgX`edjk`]c_\\]ghbf_kchpifZbj\]eQcebdZ]keXl]foe^b]]lk]ccdYe`W^`hf\kfX`XZc^gmhbUv\iehf`j[][c]hbabX_N[_dqh^de[bg\ZYa^cfga]_Y^a[h`_lgbMiaVoWg[g[][g`lchbmbcfgmdmoe_]lePnqabMcbdbfgkecbaerbkc`kjddcfgl]kjch]jqmfjXhe`a_g`jV`lm`nj\\__p]df`bYYhbe_fc]ldb_fj\Xbafaa]cXaf^ijvbddnea]Sagj^[cgdacfabZd^Zeg\dbe]Yi]jjh[de^cgghdZgc_m`fbeojccha^ae_]ebgcZid`c]g\d]gh_Wabbiofc]p]ag`geinbg^[\Y_nfaiaag]akgdkbeiZ^jjlbWd^fcm[Tcbcd\jadgc`fdjqd__coljc_jdb^am]_Yc]a`ia`ahdddhbmchngccY_Wdedbccccccccccccccccccccccccccccccccccccccccccccccccbcccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccdcccccccccccccccccccccccccccccccdcccccccccbccccccccccccccccccccccccccccccccccdccccccccccccccccccccccccccccccccccccdccccccccdcccddcdcdccccccdccccdcccccccdcddccccccccccccdccdcccccccdddccccccccddccdcccccccddddcdccccddcdccccccdcdccccdcccccccddccccccdcccccccdccddcdcccccdccccdccdcbcccdcccdcbcdceccddccdccbccdcdcccccccccccccccdcccccccccdccbcdccccccddccccddcdcccccccccddccdddcccccccccdccbcbccccccccbcccddbdcaccddbccbcccccdcddccccdccccbccbcfcbcceccccccccdccccccbdcdbccbbccccdcccccbccbcdbbccddcccccccdcdcdcccdbccccbcccccccccdcdcdbccdccbbcccbcbcddddcccbbcdddbcdbdccdccddcbcddbcbcedcccbcdbbcdccdcddadccccccdcdbccccdcbcbbcbbccdbdccbcbccbcbccccbbc\df]\j`oj]`eafebjchgff`dm]ipfd^eW]becdhc\f__`aiib][_ee_^d^c_^beec_]fiegeefa`dXb[`bgd\bcfcbaaa[_gdidah[k`dceg^hagdda^^]cehd]^]eee_akiceg^fgbda\hbehigh\c_ffg`acb\h]bgd\k_a\Z^d_`fhcgfaebeadadcddifge_Zdk]agcndcaf`abjglf[adfecj`edeb^kfcggfa]dfbacbediedca\cf_fgcdccbcdcdedbacbcddccbddcccgcfccadcccabdbccdaccbbcbebddccddacdbbbfcbbdcccccacadcbdebcdcccccdcaccccccddbdbdbcdcebaadcbfccbdcddfdcbbcbcdbaeddadcbccdddbdcccbadbdbccdcdedcbbcccccfbbdebcddafccdcbdcdcbcbdbcceacbb`dccbbccdcdcbbdbcdcecfebbcdbbccccccdcbccbdccccdbcbcd`fcfd`bfbace`fdaadgi`a^beacgf```bffbeadebb`hhaed`dccceebc`fbbbef`cgadae`dbdfbgf`defbecadkfaacegjfaaef_eefb_b`hefbga`caiebcb`bbebe`dagc^bcbbfgbda_^hagbfeb_bahfabacaddda_ecdc`fbcbaibb`cfcbf`bbcbhfacbadbicdfc`abebedceadbbfjcbbbebabdbag^adb_bacdaefcebcaa`a`abbccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccdcccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccddcccccccdccccccccccdcccccccccccccccccbccccccccccccccccccccccccccccccccccdccccdcccccccccccbccdcccccccdcccccccccccdccccccccccccccccccccccccccccccbdcccccccccccccccccccccccdcccccccccccccccccccccdccccccccccccccccbdcccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccbccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccdccccccccccdcccccccccccccccccccccccccccccccdcccccdccccccccccccdccccccccccccccccccccccdcccccdcccccccdccccccccccccccccccccccccccccccccccccdccccccccccccdcccccccdcccccccccccccccccccccccccccccccccdcccccccccccdccccccccccccccccccccdcdccccdcccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccbdccbdccdcbdcccccbccccdcccccbcccccdbcccccccbccbcccdcbcccbcdbdbdcbcccccccccccdbcccccccdccccbcccccccbccdddcccccddccdcccccccbcdccccdbcccccccbcdbccddcccccccccddcdccdddbbcbcddcdccddcccccccbdcbdcccbccdbcddcccccccccccdcdcccdcdccceccccccccccbcccccccccccccccddccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccdcccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccdcccccccccccccccccccccccccccccccbbcdceedbccccdcdcddccdfcedbbebcdbbdbdbcbbddcddcc`bcedcbadcdecbecbbdddccbdbdcdeccccddbcbeeecceeddfdeebecdcdccdbdcecbdecbddeddbdceaccecdcdc`dcdedbdbdfccdcbbcbeceecccededbeeedcdddbcdcbecedccbddddeecbcdccccde`cacbbcbdddbfbcaebedccadadabdddedceececdbdbedbcdcdddccdcdccddcddbcddddcccdbcddcddddcdcdccdcccdcdccccbddcdcdbccddcccdccddddcdcccccdcdedccddcddcdcdeecddccccddddcdcdcbdccddccdcdcdccdcdcccdcddcccccddccccccdcccccbccdccddcdccdddddccbccdccdcdbdcecdddcdddccddcdecdcdccdbdcdccbccddccdcdccdcccdcccddcccddcccdcccdccdccccccccccccccccccccccccccccccccccccccccccccccccccccccdccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccbcccccccccccccccbccccdcccdccbcccccccccccdcccdcccccccccdccddcccccccdccccccccccccccccccccccccdccccccccccccccccccccdccccccbbcccccccdcccbcccbdcccdccdccdcccbcccccccccccccdccccccccccccccccccccccccccdcdcbcccccbccccccccccccccccccccccccccdcccdcccccccccccccbccccccccccccdcccccefgfeaa[difa[bbj[d^acghf`g`]edebiilaeeegk]dbc`gaiedcb^jcd]bcddonf^`dlgfa`ehb^def^`bfefcbj^g^\fib\bebefdj[de`be``ibfbgfdec_]kihVcdg_f_bd`ZdchefeaZc^fgfec_[bf\Xbgfih`]`^gbac\d]c\fhadhhc``eqgbddeW`ci_behgbdcni\dg`dffabd^_bcbci`]hj`bcdcbfhbYjf_^aYb`]hcdhb]ikgdccccccccccccccccccbcccccccccccccccccccccccdcccbccccccccccccccccccccccccccccccccccccccccbccccccccccccccccccccccccccccccccccccccccccccbbccccccccccccccccccccccccccccccccccccccccccccdcccccccccccccccccccccccccccccccccccccccccccccccccccccccccdcccccdcccccccccccdc]`fdi[_caaei^ed_ceag]hccglfdaem\bija_le]cbgie^dfglb_a[]obafbcahaiegejbbhceijZdfjg_[higi[j``cd`fcaacgicbaef^bc]bf]cge_ec_d[^f]ge`eddje^dd`b`fb]`j]cfbodceda[h`^bc`eacjmggg^ajaeg`]bab^agd]_df`ce^fc`cnjajfbaeggcc`klZca`fc_abid^_\dah\fhcblc^dhacbacf_b_afhccdbecccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccdccccccccccccccccccccccccccccccccccccdcccccccccccccccccccccccccccccccccccccccccccccccccccccccccdcccccccccccccccccccccccccdcccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccdccccccccccccccccccdcccccccccccccccccccccccccccccccccccccccccccccccccccccccdcccccccccbdcccccccccccccccccccccbcccccccccccccccccccccdbccddccccccccccccccccccdcccdccdcccccccccccccdccccccccccccccccccccdccccccccccdccccccccccccccccccccccccccbccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccbcdccccbdcccdcccccccccccdcccccccccccccccccdcccccccbcdcccccccccccccccccccccccccccccccccccccbccdccbccccbccccdcccccccccccccccccccccccccccdcdcccccbcccbccccccccbcbdccccccdcccccccdcccccccccccccccccccbcccccccccdcccccdcccccccccccccdcccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccdcccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccbcccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccddcdccccccccddcdddccccccdddccdcddccccccdcdcdcccdcccdccccccdccccdcccddcdcccccccddcbccdccccccccccccdddcdccccdcdcccccdddccccccdcccccccccddccdcccccdccccdccccdccccdccdcdccddccdccccccccdcdccdddcccccddcccccccccccccccdccccdcccccddccccdcdcccdccccccdccddccccdccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccdccbdcccccccdccdcccccdccccccbccccccccccccccccccecccccccccdccccccccccddccccdccccccccccccccccccccccccccdccbcccccccccbccccccccccccccccccccccdccccccccccbdccccdcccccddcccbcccccccccccdcccccccccccccccccccccccccccccccccccccccccccdcccccdcccccccccdcccccccccccdcdccccccccdccccecccccccdcccdccdddcccccdcdccccddccccdccccccbccddcdddccccdccbcdcdccdcdddcccccddccccddccdcddcccdddccccccdcccccccccdddddcdcdcccccccdccdcccdcccccdcccccddcddccccdccbdccccdcbcccdcccccddcddcbdcdcccddccccccdcccccdccdcbdccccdeccccdcdccccccccdcddccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccdcdcdcccccccccddcdccdcdcccccdcdccdccccdccdccbcdcccccdccdcbdcccdccdcddccddcdcdccdcdccdccccdccccccdcddccccdcdcdddbdcccccccccccddcddccdddcccccccccdcccccbccccddccccccdcddccdcccdccdcdcccdccdcccdcccccdcccdddcccdddddcccdddcccdcccccdccbcddccdcdddcdcddccddccdcccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccddccccccccccccccccccccccccccccccccccdccccccccccccccccccccccccccccccdccccccccccdccccccccccccccccccccccdcccccccbccccdccccccccccdccccccbcccccccccddcccccccccccccccccccccccccccccccccccbcccccccccdcccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccbcccccccccccccccccccccccccccccdcccccccccbcccdccccbcbdbccccccccccccbcccccccccccccccccbccbbccccbbcccccccccccccccccdccccccbcdcccccccccccccccccccdcccccccccccccccccbcccccccccccbccccccccdcbcbcccccccccccccccccccccccccccccccccccdcccccccccccccccccccbcccccccccbcccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccdcccccdcdcccdcccdccdccccddcdddccdcccdccccccccccccccccccccccdcccccddccccccdcdddcdccdccdccddccdcccccccdccdccccccdcccdccccccdcccccdccccccccdccccdcccccccccccdcdccccdcddccccccccccccccbccccdcdccddcccccccddcccccccccdccdccccdccccccccccccccccdcddcccdcccccccdcccccccccbccceacdcbcdcccaddccdceccddcdcccdddcdbecdcdccdcbbbdccbdcdbdcdcddcdcdbdbbdccddcccbccdcdcccccccbfdccccddccacdddeccdcccddcdcddccccccbcdccdbddcdedecdcdcceceddcccccdcdcdccbbcddcddedbcbcbcddccccbddbdcccdbddecbddcccddcbcdecccbcdcddcdccccccccdcbcdcdcddcdccbccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccdccccccccccccccccdccccbccccccccccccccccccccccccbcccccccccccdcccccccbcccccccccccccccccccbcccccccccccccccccccccccccdcccccccccccccccccccccccccccccdcccccccccdccccccccccdcccdcccccccccccccccccdccccdcdccccccccccccccccccccbcccdcccccccdcccccccccccdccccccccccdccdcccccccccccccdcbcccccccdccccccccccccccccccddccdccbcdccccccccccdcccbcccccbcbcccccccccccccccccccdcccdbcdccccccdccccccccbccccccccccccbccdbccccdcccdcdddcccdccccdcccccccbccccccccbccccccccccdccdcccdcdccccccccdcccdccccccdccdddccdccccccccbcddcccccbccccdccccccdcccccccccccbcdccdbccccccccccccdccccccccccccccccccccbcccccccccccccccccccccccccccccccdcccccccccccccccccccdcccccccccccccccccccccccccccccccccbcccccccccccccccccccccccccccccccccccdcccccccbccccccccdcccccccccccccccccccccccbcccccccccccccccccccccccbccccccccccccccccccccccccbccccccccccccccccccccccccccdccbccccccccccccccccccccbcccccdcccccccccccccccccccccbcccccddccccccccccccccccccccccccccccccccccdccccbcccccccccccccccccccccccccccccccccccccccccccccccccccdccccccccccccccccccccccccccccccbcccccccbccccccccbccccccccccbcccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccbccccccccccccccccccccccccccccccbcccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccdccccccccdcccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccbccccccccccccccccccccccccccbccccbcccccccccccbcccbccccccccccccccccccccccccccccbcccccccccccccccccccccccccccccccccbccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccbcccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccceZcchbgdbib`a]abcb_^gjblb^`ma\ao\__f_b_[bjccbaca]UchXgga_ifamdanf]el]efcbc]^cZdfd^``b\]phcchbcf`fbe\fae^dkjmcXaf^kgaiga`hh\bc`j`Whaeecd^ghbdeecY^bhe\i[c`nca\]bdd^gncgeblgbee]_be_jgfk^fb^Za\\df^a^aiadce`[igkbj\gidaga[dbb`kgbclek_p]ddchZh]ice\ade`dglgYfeRgi_ecdceecccddecdbdebbcbdbcedeecdddcbcddeccbdbccddecdbcddcdcedddccccbdeecccabcbccbdbdcdddccbddcdcccdcdccdccccddbbddeccccebebdfcceedcdcbbdcacbdcaddceecbbccdccbbbcdcdcddaceccccccdbccdccdccddddbbdccfdccbdcddddeccbddbcfcbddgccbcddeecbccdbecbfcccdbeedccdcbdccccecdccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccbcccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccdccccccccccccccccccccccccccccccccccccccdccccccccccccccccccccccdccccccccccccccccccccccccccccccccccccccccccccddcccccccccccccccccccccccccccccccccccccccccdcccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccdccccdccccdccccccccccddcddcdcdbcccdcdccccccccccccdcccccccccccccdccccdccbcccdccccdddcccccdcdddccccccccdccdcccdcccdccccccdcccccccbccccdcccddccccbcbddddccccccdcccbcbcdcccccdccccdccdccdccccccccccccccccccccdbccccccccbcccdcccccdcddcdcccccccccccccccccccdccccccccdccccdcccccccdcccdcccccccdcccccccccccbcdccdcccccccccdcbdcdccddcccccdcccccccccccddcdcdcbccbccdcccccccccccccccdccccccccdcccdccccccbccdccccdccccbcccccccdccdccccccccccdccdcccccccccccccdcdcdbcccdcccccdcdbcccccccccccccccdccccbcbccdccbcccccbdccccccccdbdbdcbddcdccbdbccbdccccdccccccddccdcccccccddccccddcdccccccccdcddccbcdcccccbccccbcbcceccddcdcccddcdccdcccddccddccddccdcccccccdcccbcccdcddcdcccccccdccdddccaccbcccccdccccdccdcccccdcccccdcccccbdcccdccbcdcdccbdbccdcbcdddcdcccbcccddcdcdccccccdcbccdcccdcccccccdccdccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccbccccccbdcccccccccccccdccccbccccdccccccccbccdcccccccccdcccdcccccdcccccdcdccccccccccdcccccccccccdccdccccccccddccccdcccccccccccccccccccccccccccdccccccccccbcccccdccccccccccccccccccdcccccccccccccccccccccccccccccbcccccddcccdcccccccccdddccccccccccccccccdcccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccdcdcccccccccccccccccccccccbcccccccccccccccccccccccccccccccccccccdccccccccccccccccdcccccccccccccccccccccccccccccccccccccccccccccccdccccccdccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccdccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccdcccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccdcccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccdccccccccccccccccccccccccccccccccccccccdcccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccbcccccccccccccccccccccccccccccbcccccbbbcccccccbdcccccccccdccccbccccccccccccccccccccccccccccccccccccbccccccccccdcccccbcccccccccccbccccccccccccccccccccccbcccccdccccccccccccccccccccccccbccccccccccccccccccccbccccccccccccccccccccccccccccccccccdccdccccccddccddcdcedddbedddcdccccbedcbbddccecdbdcdcccddececddddccbcdbcdbceaedecdecdcbbeadbccccecddcccccddbccdddedcdcbbddccdaedfbdccbdedcbcbccbceddbbacdcddcdcdccccabbbcdddecccccdcdddbcebadcbeccbbcdedefcbddcdcdecdcbbebccbcbbcbccbccccdbeccdcbcecddbddddcdcecdbcedcbebddccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccdccdcdcddcccdccdcccccdcccdddccccdbcccdccccdccdccddddddcdddccccccdcdccccdcccdcdcccdcdcdcdcdcbccdcccccbdccccdcccccdcccccbddddcccccccccccdcccccdccdccccccccdccdccbccccdccccdcdccdcbcccccddcccdcdccccccccdcdddccccccccdcccccdcccdcccdcccccdccddcccccccccdccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccbcccccccccccccccdcccccccccbccccccccccccccccccccccccccccccccdccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccdcccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccdccdcccccbcccccbcccccccdbccdcccccccdcdccccdccdcbccdcccdcdccccccbccccccccccbcbbccdcccccdcccddccdbccdcdccccccccddccccdccdcccccccccccdddccddccbccdedccccccbcdcbccdcdcdcccdcccdbbcbcdbcdccdcdccdcccccccdcccbccddcccbbbccccdcdcbccdcdccccccccdccccbccccbccccdccdcdccccbccdcccccccccccdccccccccccccccccccccccdcccccccccccccdcbcdbccccccccccccccccccccccccccccccccccccccccccdcccccccccccbccdcccdcccccddccccccccccccccccccccdccccbdcccdccccccccccccbcccccdccccccccccccdcccdcccccccccddccccccccdcbcbcdcccbccccccccbdccccdccccccccccccccccccccfbccdcccbbcccccdcbcccbcccccccccccccccbdccccbccccccccbccccccbccbcccdcccccdccccdccccbcbcbcbcbcccbbccbcccccccbcdccbcbccccddcbccccccdbcccccccccccccbccbecccccccccccbcbdcdcbcbdcccdccccbbdccddccccccccbccceccccdcbcbcccccccccccbcccccdcccccbccccccccbccccccbdccbccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccdccccccbdcddcccccccccdccccccccccccccdccccccccdcccccddcbbccccccccddcccccccddccdccccccccccccbdcdddcccccccbccccbdccccccdccccccccccccbccccccccccccdcccdcccdccccccbcccbcbcccccbccccccccccccdcdcccccccccdcccccccccccccccccccccccccccccccccccccccccbcdccccdcccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccbcccccccccccccccccccdccccccccccccccccccccccccccccccccccccccccccccccccbccccccccccccccccccdcccccccccccccccccccccccccccccccccccccccccccccdccccccccccccccdcbdcccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccbcccccccccccccccccccccccdcdcccccccccccccccccccccccccccccccdccccdccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccdccccdccccccccccdcccccccccccbccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccdcccccdcccccdcccdcccdccbcccccccccccccccdccccccbccccccdccccdcccdcddccccdcbccccccccccccccccccdccccccdcccdcccccccccdccccccccccccccccccccccdcdcdcccdcccccccccdccccccdccccccccccccccccccccdcccccccccbccccccccccccccccccccccdcccccdccccccccccccccccccccccdccccccccccccccccdcccccccccbdcdbcceccbcdcbdcdccbccccccdccbcbccbccdeccdcddccccccccecccccccdcccbdccebcbcddcdccbbddccbcccdccccccccbccdcbcdccccccdcccccbcdccdbdddccbccccdccccdcdccdccccecdccccccccecccccccbcdccccdccbdcbccdcdccdcbcccdccccccdccccccdccbcdcdcccbbdcdccccbdbdccddccccddbd]ekmg\``]_]_cY\^d^^mfe]cgjk\_ng]`d^b`ckgidghf__dki`lhhgdcfap^fdaPe[ad[jfWbedid`mijegb`_Y`dg^dYa^ffbi_cdbZid]e^fceeo_^hc_fWahde\baiadbhYjc`ii_gaZaa^le`dij_bj`d_a^nd\d]_ia`dae]beef\l^debbh`befjgeimhf]f__ggdcgf`eb]fcface`bk^agadYefd\`fdpcecc^becafk`aXibZ_c`cdddcccdccccccccbdcdcddccccdccceccdccccdcdbcccdccccddddbccdccdbccbccbcdccccccccccccccccdcdcccddcccccccdcddccccccccccccdddcbcccccbcbcccccdbdccbccdccccccbdcccccdccccdcddcddcbcbbdcdcccdcccdcccceccdcddbcdcddcdcccccccdccdcdcdcccbdcccccccccdcdcccdcdcdcbcddccccccccccccccccdcccccccccccccdcccccdccdcccccccccccccccdcccccccccccccdccccdcccccccccccdccccccccccccdcccccdcccccccccccccdcdcdccccccccccccccccdcccccccdccccccccccccccccccccccccdccccccccccccccccccccccccccccccdcccccbdccccccccdccccccccccccccccccdccccdcccccbcccccccccdcccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccbceebadce`dbfdbdbdbcbdbcfeefeccdddbbbcdfbdccebccddbddfbbbdcedcedccfddbcdccbdbcededbdhccedbfbcbbccbeceabdcdadfddhcbecddcfbddbdedbdabfadccbcebdbdbdfbdcbddec`dbcdeebbecececdcadbcfcccabcccdddddddbcdddcddbdbdddf`facbfddeaccd_ddgeedccccdcafecbdegcccd^cbeeddecde`cccccccccccccccccccbccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccbcccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccdddbccdedcccccdccdceccbdddcecdebccddbccddccdcdcccccccdbabcdeedddcbdcddccdbccddcdbcdcdccceccdccccdcdcddcebdcdcdcbdcedecddddcddccefbdddeccdcdcccdceededddcbdbdccecdccccbedccdccbddceceddccbddcccddcdccbcdbbccccddccbddcccbddccdddcddbcddddcccbccdcccccbdaddcdccccaccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccdccccdccccccccccccccccccdcccccccccccccccccccccccccccccccccccbcddcdccccccccdccccccccccccccccccccccccccccccccddccccdbcccccccccccccbccccccccccccdcbccccccccbcccdcdccccccccccccccccccccccccccccbcccccccccbcdccccbdcccccccccccccccccccccdccbcccccccccccccccccdccccdcccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccbdcddcbcdccbccccccccccddccccdddcddccddccccccdcdccdddcbccdccccccccbccccbcbccccbccccccdcbddcddcccdbcccccdbdcdbccbdddbbccdcccccdccccccccddccccccbccccccdcccccbbccdccbdcddcdcccccbcbccbcccccccbcdcccccccccddddcccccdcdcccccdcdbcdcdccccdbcdcdcdccccccccccbdccccdcdbdbZa]b^ed`^jef`d\c[`i[^bai^aVmZWbgXc_]fi`ig`nc[cdjsWp^ZdbbnmicdXb`i^e]hgacf^\dbdaaXXYigbd`_aZfoic]ke`ahbgc\cblagacdfUd^fi^eg]g]_`ccicbhdhdgZ_aafcbhjhjd\adae]`djniaiabajtffck\^lkOebhcb`hbf\b]cni\cjYibc\pk`jabehgi_ggeckf\]kf_dbic_[he`bb`fecdedkafed^caghgj`[bccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccheacch`ed_[jhbad``fa`b_gdceb`ccaidbdfhedlcad^bg[fdgc`fdcdZdddcaiecgif__eceeddf_b_bjacd_d^ccad_ifdf^`d_f`_fg^b^\jh[cacafggccc_c_hg_ej^da^_bgba^cggn\dl]ia`jicZbd^dia`cc_e^^dcf`dfkhccb`a]ffcbdncbea`g_^`beddabageifbgf]dcgdg^fmde^\ccbhe_jab\dfdfgdecb`fggodel_ddccccccccccdcccccccccdccccdcdccccdccdccccdcdccccccdccccccccccccccccccddcdccdccccccccdcccccccdccccccccccccccbddcccccccdcccccccddcccdccccccccccccccccdcccccccccccccddccccdcdcdccccccccccdccccccccdcccccbdccdccccccccccccccccccccdcccccdddccccccccccdccccccccccddccccccbccccdcccccdccbccccccccccdccccccdcccbcccccdccbcccccbcccccccbccccccccccdccccbcbccccccccccdccccccbcbcccccbdcccdcccdccccbcbccccccdbcccdcccccbcccbcdcccccdccdccccccccccccddcbcccccccdcccbccbcccccccccccdccccccccccccdcccbcdccbcccccccccccccccbcbcccccccddccccbccbcccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccdcdccccccccccccddccdcccccccccccccccccdccccdccccccccccccccccccccccccccccccccccddcccccccccccdddccccccdccdcccdccccdcccccccdcccccccccccccdccdccccddcccccccccccccccccdcdcccdccdccccccccdcccdcccccccccccccccccccdcccdddcccdccccdccccccdcdccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccddbdacbdcccddccedcdcbcbdbc`dbdccccaeddcbcedbbfbbbddcddecabdcbccccfddbdddddccdcdcbbeccbdbbccdccdbeedcbccdbbcdcdcebcdbbcccbeecdbcabdcccbdccccceeccabcccddbeebecdcddccdbbccdcccacacecdecddccbbbcddccccddbcdcdbcddfcccddbcccbdbbcddddbbbdccdde`dcaddcddcacdfecccdccbbfe^_bbkad_kch_mifbadg]dZh\^`f^]c_ageedbe]f`cj^ead]hiahe`_f]bh[cch]fdf]cjeditfe[dke^`^cfig`bdhhamol_cflha`c^`dcW^ada_fa[jeag`X_bb^c^_d]ne`iYw_`_`Oabgec[fi[gafdjgcliqYj`^iaagblcg^`l^fi^l]hbabddbe]afhagcnfd`mk`bdhdfehgchi_arfhcgicgadecc^i_b_clac\[cfk`a_gabd^bdZ_de^dcbg[ckb_dedg^bfbmf[jagbfdagaalb`ah]aa`ebe[agb[h[b]eheZlhd[j^nY^d\^`fZ[_f`aigei\begeagfjcbg^`hddccmfdeahf[hbbedf__bgZ^becm_`bcY`\daj_^_bd_oq_ef_fec_a[db`i_c`gglag]_e`cZaakcaW\cadhbZdabaghjhd`hb`ei`__c`had\^`e[g`g]_Zhkacejigb^j\Zd_ljaeadehfbbgd_elcak\hb__\iababZigd`ZefffYjlb\hcbijZb`diQ^\agZcamhc]g_bd^aphhcpb_abWaaf\dh_``f_e]fo[]acdfYnd\ahcaabbd\anhfbii`X^gf`WeVf`hdbdf[febghh`a^gahfljkdapb]mfeWcbk`dajddht_fdZbn`hWbm]lab]ei]gXji`boa^XUf^fcdgcd`e]gfj^_djdd\[b]bh\bdmnblh_lnbc`ecc^``ciffcdb^g]akfhccf`cieb_c_egonQodcZdk_Zafak\ec]beabe_ef^hcYflbZegah_me[pjcdje_g_ffba]kjkcjg_`ebehee^c\^ee_eh^fYcbhg^gh`_``doj^c^bi^^__^fTe`ee]ka_hghacnY\_e\dmfc^bab[^bljcgolldc[jfac`^iek_gfaZbgfcai^Y_iaieW[edjd^cib_]`Wiaggbbf[f`ab_^eV]^e]gZbjWkcjrhZadagd]i^jeboZhjebbg]dbbf]aajcio_^modaa[hhuaddak\acdihj_ehXe_dcbdia[kZf^TodbeYk`mdrWfVdmZ^hkabnXbbgfa`^fnmjag^V\^ja[]aYbcg_iegkUi^[[g_lgh^f_c`V\^gf^`le\Wfe`Yhmfha`bhX]\Zpkacgkrh\ig_oa]cccgabiV[e_hgfaX_a\d[dl\a`^g`mgZd`oak_^n]e_`eb[\`d^ag\ThahZ[bj[ee^qg`b\UbfcenejdXdUSicjhbmc^djc`ccegadfece`faedbcbc`dehdedc^beddefbfeedb`ffdbbegeegg`geb`g^fagcab`i``fgbab]bbd_ahkaccd^ccbbecafachb_gfcfaecebeeddfcabf`fgbgebfae`bceeacb`ab_gdffced_``cccd__e^cebaefacfadgbhdge`cci`gdbee`fa^ebecgfdbcb`gcabbecfdbf_cdddc^d_cflaic`bfabaafib`ce]a_d_ddeaahc_chbagbchcagcddcbccdbdcbedbcdbcecdcccbddcbcdbeddccddeccddbcdbbccdbbcbccccbccccddcbcdcbecccccbdcdddddabbdcdcbbbccbedecbcddedfdcdecbdbccabbaddddcbdcbddcccbcbcceccbbbabecddcdcbcbdcbcdecccebececedbdbdaccecbbbcccbddccccacdceebdcbbcbbdeccbbddbdacccdbccadcacdcdbbdccdccddccdbe^bdhldiV_fg\gnpnkfe\wbbcicZccZieVbch`dWih``]fWea[\fgRfpeSZkg`c[idfb_kee_\_ecjgi\e`c^_]jikggbdfbhb_]fac`iZe\b_l^oaceekn`afS`ghh^bZUZlbR_gcmhclgi`bd^knhef[dihc[ejegWkgghfo\[]ip`_gi`UofaidjV^dmnch`Xch\il`ceddi\`ccbf_h_caj]Recc^dbgeg_KgCa]cdaWfiddffem`_]]lfYZskmehb`h^cfe`X_cqfaiaddgehfce]cd_lfhee^ggZ_ajgckV`g`akjWcZejfl^_c]k^ac_j^Yaeecef`elgaf`d`dge^aaZ_ckZe]he_i^]_bddg]jffd_hdgXf`legcah\]dfdgdiZed_kg`acdcaeWg]c]dgibcZd\gfb__\agcccjlRfaZccnki_^d`kefdabbdhbXjenmkbd]gdbbaciee^dhfjdqfi`lcbWUe_fVba^fo\aid]h^bZqbfYfddbaaabb`afacdec``de``accfde`e_fe`feabdcdeaebbgeeedahe_haeecd_bbe`dbdecbfcfadecaf`dccaa^afdacbafbddacbdac^ccccac`bcdd`fbc^ccdde`eca^bcafadbbacedddcbacbfdefdbbdhbdacccdbab`e_bedbadeaccdebeadceabbbedbecacaeecadedabddjdgbace`aedhaceceadf``dcdaddecaidbadb`bcb\^f`hb_U`_dgiaidXg][hWf^^fZep`dZfbXhj]hcegkcec^ghjj\fb_\_dV]\]ffedfcneci`aeigf\b^eacbiaZ\b`afWdghbi`]cghdfapea\ag_f^gg]bddg[a]_gc`eji_d^^\c]Zkcd]a`e`gg]j^`lclff^WeW_`Zkdehebf]_c\gbfXaf]]henghYbecgh\ijboi_g[a^a`^nddmk`e^\]fi\gb_gajb_pc`gjadnagggdcljb[`i]]Yf`dbbcYd[h^]cN]hdgadh`nWfdvbfk]bg_bU_\ej^_\Z[mmbedfghh\bW^oj[ehedl`WfbdehjcY_^fhkeh_kZchegXb^Yjh[S_fhdf`Xd[f]l[`ggc_cebcuocakjqi_k_bda^pdd^balZ`cgYga`o^dhjhca]e_jc_e\kbfe\`ic`Zc[]hbbXaahaj_gfpg[ofhdbYbcbYpdd\maacj`daknVWYko_hl`o_^r_bac[fneadjecfd`ibf[h`V^nbbejf_gdpb``cl``_]f^cmhde`cmfgibejfa\a_hh_egi]_dgld^hccjdabcadge`ahada`dbiag`g]]a^eaddbde^__cff^d^deh^gg[kfcdee`ljeffafbec\baeaabbdgdja_ecbfgedhba_ddfb``^\be_ke_fcdeech_i`blcbbd[bf[jqicddgdgb`Zcdaaddcdfd^^d_^cllaahlk`cafcje`gbbdcefg_bkfdfaccfhbacbaeccc`da^eeeccc`dccbaeabbabdbdfcdcddebde`bcgdcfbcedcdbb`cdceddcdafbbddabbccecdcaea`dbacc_dcadadda`abade`ecbcde`bcdccbdac`eedbccceeedccccceaagbdcacdebdbecefdbecbd`_bdf`gcf_bcdcabac^bcdbedebbceebcebbcbbcfcbdecddfbcb`bddbdfcbae`adeccbcdbbcdbddcededcaaeeeab_cabcbccbeabcXj`bc]i]e`]jhY\[`aq]_lhddmihgfajahbdf_o]hle]]\ed^baa\X\[`[babcbpaiY]X^facboca`]gYc^_^i^qkYh`^`cdbe[mfjbhckbch]`k^`li[ddg`nW\enggeia[`edlkfda]lZkcff_npdkib]leY]^`ed_egra^[jea`cla]adUmWahb`qj]\d]mpekhdahSaac\fj]gii^_hpffTZb[j^ZZhe]sf`eaj\bgj^`en[]Xgcjkdh`cc`ccbcbbced_dedefbdfbaccabdcccdedaeecdcfdbbcacbcdagceecbbcdcbdcc`cfdcbacedeedcdaeccdecdbddb`dccabeadcbhbdbdcdddabbfdaedbeddcedcebbfaddfabdeddccbdccaadc`bddecdebceeebabbdebceeeedfcfdcbbgdbcddecbbbcdecdcebcbb`bacfedbbddcbebceddbebcdcccfcebbdcdddb_ebbeeccecbdcd[cgZpa\ie^ebekak_bb^cgob^dckefcR]`lgZk\dbh`jabc]]cXdjdhjac]cdflej^`_cgcd_fe\fdikrddmfdemhefadb`c^_]]egek`dZb`\cjhWcZdge`bc_cgajef]]ifa`dchd][]ecfrc`bb\fhejedc^`\ccil^bajdhZelb`]e^d`ccfUjfg\a_Z_lc_egX`cafhcdkWaeWk\f]c]l`gYbc[\ecfab`ehe\`ngahegYeh`acn`fk_ffhbbcccbbcccccbcbccccbcccccbccbcdbbdcdcbdccccbddccccccbcbccccbcccbccccbccdddbcdccccccddbbcccbccbcbcdcccccbcbccbcbccccbdccccbdcdcccbcdcccccdcccbccbcbdccbbbeccccbcccbbcbdcbcccbcccbcbcddbcdccccbdcccccccccbcccbccccccccbccccccbcbccdcbcccdcddcccdccbcdbccdcccdbcccb_WkNi[Tbdda^gm`gdb[d`Vbghc^obWa\m_ciVdiWbhZ[]MkdagehkNjfXhZi_SVke[Zbgbdcgmh^_if\`pV]^kRYUadjqojp_h]]f`e`kf_bhe]_T^`gheZgSbZUj[mdaiNnYnkhg^X\eb`\hrjpPekinghdieYk\\q\ida^gu]kX^mig\obcFf^ckfnk`dRZvejl]kegdocXgfR]f^]a[etZo]dYrjUl[hr`da[j`]ijebh_lhecauwbncncYegdcdaeabfcdc`fa_ddcadb`cebcfgbdeeefc_^bbbfbd^b`abbfehbdbehbbfgcaabcbd`baaceb``cfdddbd`cacd`dga`abh`bbeaaee^aadabbc_`cebbebcbafbcbede_bbdedfdc_cdceha`eefeebcadba_abcbeadddcec_bcafcd^ccabecbiccbbag`addc`dcbceadadb^b^gdifbb`cdcdcfdadcccdaecbfc`cbadbcdcbabcaffcccbccddbbccccccbcccdbcddcbcbcbcbccccbcccbadbcbdbcccccbbcbcddccccccccbcccbcbccbdccdbbcccccbcccbbbcbbccbcccbcccbcdcbdbdcdbcdccccccbbcccccccdbcccbccccbbccbacccbcbcbccbaaacddcbccecdbccbcddccbdcbdccccddbbbddccdccbdcdabcccccbcbcdccdcccdcccbbcccccccbbcdbccabcbccccdcdccccccccccdccecdddeccddcbdcccccccdcdccacbccbcdbcbccbcbdcccdcadcccdbcdbccdbadbcbbccccbccbcccbbcbccbcccdcccccbdbbcccedddbbcecdecddddccdcbecbcdccccdccbcbbbcdcaedccbbdbbcdccbbdbdbcdbdccddbdbcccccdbccccdccbbcbcbcbcccdbcdcddcabcdccdbbccdcbbccbcbbebbbcbcccccdeg\^e]`jY[kkmgim`^fo_gb_[YqSe`Zkshk`kY`jcji^cbbSgfjcZjhjhcZhbb^_ggh]gjeo]bbj\hf[b[ee\hcdddd^ddjf]rbgghjiiTfinamj[ldrcbj[[Z[banh^ipYea_[egehaacoj^k]]befgJcddjY_k]^^Xoekjg`al\dbf\epXdemee[_bYe^iZadjckjblbg\dgS^djZidi]cdaikoYk_U][\bNcikbaecjdf^^fwb]_`h^iiri[mlhggiadfkbk^l^```ie_eabg^bja]_c`_bf\bb]ghanf^ndabhic`jeh`Zgcegeedeg][c`fi]babibgca_de`aa`eahdeaXhe[cdigdhaa`cgb\f[ee_dgcaak^d_ce`b]aedaefcjdbcfickcbgfjfae^aceai_dcekbd^fgm`bgcdjlgcchcaededckhfi^_ddab_eb`[i`e^lcceeb`Zc`^[e^ao`ebeddf`b[laegae`ee^c`[ddb^dee^g`^hkbb_`hdb`ujmcnbn]b_hZZY_dcjjWajfep\pblhe[]`ifjWi]edfn_a\_c_dm`^adefZfed`hif^ed]na_g]o[g^]a]]vcjb\bdpkVdfeg`Z`e_ada`fflfSXdUjhk^lhib^bi_efh^d]`Vlddap^^_icSb`\ebf_[aVhVddooaf\\i^^mfcffjh^q[Z_fh`fnbn[]ga[e`]c`g^bgeeZejoedZ[Wl`ecca_h^bgmWdck_W^hd_]aav^tWgcggcejddgei``ik_ef^_bddeiaaci^aahkcacgp`bgid[ia_g^a]^dge^ebeafa]ahbkmi`g^e_c[YleXbc_d`alZj[Vd^_Zgmc`ij^gcf]eVn`[_omWZb^[ebmf`gae`^gWqdb[fahj]dReieZsZendh^_\_bYd^elj^i]W\_f^^`q`icWa^\icZejhakf[]obffce]eZ\`b`a_bWbiibhgX`ehd[gd_gec_g\][`gtl`_g[]^_\\a[WZjbddafd]Yd[a]fia^`hbadea\ccppc`bfg_fe[g\b]fgi`dgg`eflYg_aaac_a_nl[medhgbfc`dd`^j__djg]fi]a`\offgk\bkeabgc`]hgeba]haecefjbaddcgldkgZcdgcfd`hhe`^ife^ba_[gagb]a_`c[d[f\d`]df`f\a^bhd_akcng]eiccdgaa^fghgjf\\fh_a^fg`icf^dea_beei^]ef^h\]cedec^]eaX]e]``fbddf^^d\eZ`bl_`^g^cdccddccccdcdccccbddccbcccdcdccbddcccccdccdcccdccdcbcdcccdcccccccbcccdccdccccddccddcdcccccdccdccccccdcccbcdccccbcdcccbcdddccccdcccccbccccccbcdccccccddccccbcccdcccccddcdcddcccccccccdcdccdccdddcdcccccdcdccccdccddbbdcccdcccdcddeccdcccccccbccddccddcccccccccccceb`mcafs\falrfk_ka]cbhm\^bYgdXdhbdacuaZU\nZkGhg[omk[feil\`dk`fnnhjcdSmei^TcZlgqoep[]`^cq]cXaY|dV^gddqa_c{d`\^ccek^dafVmcfe`mhhqm`\U[gifdeaekq^kW\dp]}p`boh`ccjbhcsoSrS[kc^]LYg\bbaWdX\^Yabl^nkoTjemd_chX^j\nc`cYbe`RfuT`XX_Y^edb[]^pcZbf^_d]fe_ZdfYjmZdkOb\bm]Tf]l]c`jecfe`mfhdb\ci]bafbebb]fmdWcaWghh_mcghadpad^eY]_gfeaa]W[cif`p`g^c[bid]hkf_cc`bigad`_hgab_jchcfgfki`fdddgb`Vfdd^_i`]jbldbc^i]gi^kdba`jiYbf^eaMbbebbfdeafgeckg`a_^bac_fgeedj\dcaff`d_l`feegf\k`Yi`eh[cfg`c]_deb\rd^gaf[b]ieai`V__bidbhmfdadbaj`l\k_egk``fck`fb_dbjl_afdfcpeX_m^acdaj^\Uc]f`e_bjefihdiddee^dc\k_]daffeVg[b]^gkjhiZb^`bfchbj`Yaedl]beel^ee^ceZmgjb_eekblbf_\^[ad]f[dgbYb`k^Z`eff]h_bbegi^gWdhee]ackr]dbflcgVgiVbdae`iid_c_egh_ede`i]gd]d_as\i^af_^jia`bfgd^a]dghoh_jabb_ba_`]ejYgaei]ghfeeaa`eh]hf`[fel]l\eglfdaekZc`c]ijd`_[beVgddbemeafahd[ydgibbX^gc`a]ahie`fd\dgiqccdoWaffdc[`cbha^fgeeb`gkdfcbilaac]fcid^[bcjcd`Za\e[_icjldbYcrbci`f]jceclhc^_`foff`XaoeihfZb_Yg`__```bag_e]cdOgbddhgb`f^]a]_akaffi_dYeagX[dkge_g`ad`dekcg]c^ddfagfZm\fb`[hcc`_d`ddici_]dg[gda[ej\j`fcZ_d`eaceajhZbai^dfb`bbcif`Zaajbhea^accbgh_ka`e_ah\Zb_`j\ag_^f]ecf`a__becccef[`fgf_ajdgc^cccef``e]_iiegad_`b\akgbalifachbfgabhiZdaacd^hcfb`Zfebb^abc]]bfgdd[a]i\f`[cfgchih_gdc`e`m\bddcgkbdgbfccsd_^gaZ^[fdagi^^]`\ff^adgef`^cg\a^a_egc^bcihh[`ee`_eg`]e`Zbc_cdfj^dg\ccdccddcacdbdbdceccbdccccbbcdbbbcbbcccdccdcccccbbcccbacccaacbdaccbcccccccdcbbecbcdcbdcdcccbbccbccbdbcbccccbdecdddcddddcdddbccbbbcdccdcccdcbbecddddccbdcdaeccaddcdecdabbccbdbebccddcdccbcdccadcdcccbbbadccddcedcccdccdcbcabcebcccecebbcdccbccebddbecbaccdbbccbbcaafdc\ea`he^c]cmdb]cebb]fga]cbefddacaabcddb__af_a`a`eb`jeggb]ffabbcbegdelafcf^cebddddaabdc_beeeaf^cfg[gbfbgegdc\_c`dff_bfceleidebfh\eec`caedbbffcfdegbh`cj_hfddbac_ce`__bff`h_cddaee`da_c\_bbc`icecfcddee`e]`^aae`bhe_eededgeffcaec`ai_eca`^]ceehfdbdfbefahha__deccccbbcccccccdcccccbcccccccccccccccccccccccccbcbbccccccccccccccccccccccccccccdccccccbcccbccccccccccccccccccccccccccbcccccccccccccccccbcccccccccccccccbccdcccbdcccccccccccccdccdcccccdccccccccccbcccccccccccccccccccccccccccdcccccccccccdccccccccccccccccccccccccgdmgf\jodhbd_Wdeddebcjbbjbg^bfaefei]cdX^Zddg^ehgfagc]ndMk^Xiba`f`]gjbagc[eib^egVdbggecbdfeaiddcYf[a^bbge`cja]d`_c\cefebecgek`hafaiiS^`dee[`ibXaahhde`agaicg^m_ckahcZpklda^ebgfbfeiSbdj_a^\ac_ldom`cZZef]^ff`^c_]lZbfddgbgbekbkbbafega\ghaar_e`cboYg^`_f]_caii`^cbccbcccccbdccbccbcbccbdbcbcdbcdccacdcdbcbbccbccdcbccbddcccdccbcbdbdcbbbccbbcbcdcdcbbdccbdacccbcccbdcdbbdcdbccccdccccccccdcccdbcbccdbccdcbbbbbbdcccdcdccbdcbdcbccdccccbcdbddcccccccbcbdcbccbbddccccccbcdcccdccbcccaccbdccbcddccccccbcccdcbcdedccbcbcbbcccdbccccdccccccccccccccccccccccccccdccccccccccccccccccddccbcccccdbcccccccccccccccdcccccccccccddcccdccccccdccccbcccccccccccccbccccccccccccbccccccdccccbccccccccccccdcccdccccccccccccccdccccccccccccccccccdcccccdccddcccbdcccccdcbcccccccccccbcccdccccccccccccccccccdcccccccccccccccccccccccbcccccccccccccccccccccccccccccccccccccccccccccccccdcccccccccccccccccccccbcccccccccccccccccccccccccccccccccccccdccccccccbccccccccccccccccdbcccccccccccccccccccdcccdcccccccccccccccccccccccccccccccccccccccdcccccdccccccccccccccccccccccccccccdcccdcccccdeebbedebbccdbde`cgdbbbedbbdbadececbdab`bcdcdccddcbbcbcbcdaecbdbcccddbgceabcbdcbcacacdecbccecbadbacbccbebddgdeaebcbcddcbddcadbecbdbdbcabeabcccebca`dcdbebdacccdbddcbdbdccadcbcddbbdbecddccebcbacedacaefddbeddbbddbccbdcddfcdcbcbdddddbbacbdaddbdbceaacdcbaccccdcccdccccccdcccccdcccdccdcdddcdccddcccdccccdcccdcccccccccccccccdccccdccccccbccddccdcbcccccccccccccccccccdccbcccccdcdccccccccccccccccdccbccccccccccddccbccccccccccccdccccccbcccccccccccccccccccccccccdccccdcccccdcbdccccdcdcdccccdcccccbcdcddccccccdccccccccc\Yj`teb][`ihj\uQTsajl^\hm>aoT^oheYN_R`O\]gXWAeNqUccUshAZU]HayUpXav`gelZ8K_Y\fZi^XqrP]wcTR_Kv`WKcL_eV`me`i>]jLcf:]gWwb\`UmaeiV\_lvPdZooTzVtjXKKfMkhYobKz3tiZ`_hqNls]wdlkuMuYWFViGwWgvffjjan\ZlooM[UkXZtbe=fU?eVipp[j]ylGnYghBPtWe4cqrk`}Med_\Vr}]PNZW@jc]Zycccddccccccccdcccdddccdcdddddddccdccdccddcccccdcccccdcccccccccccccccccdcdcccccbcddcdccccccdcdddcdcccdcccccccccdcccdcdcccdcccddcccbcddccdccccccdccdccdcccccccbccccdcdcdddcccbcccccdcccccdcdcdcddccccccccbddcdddcddcbbdcccdccbcdccbcddcdcccddcddcccdcccdbbccccccdcid^feebdYZeo_X^gee_`cedb`_f`h[Xmeb^ca_a^bed`icc[`ccmceg[kebf^aa\ac``Y^ab^cZahkle_maci_c[]ab`iakXm[n_abd`pb]jjbbeeddgfeahdgkagel]^eg[`_cabqe`eggcig^b[gc_ed[hchcdcaYdgbf_ba`ackbeacjg^d_dli\oadgl^ia\bcdff`_afigfgWeibd]ggdXdif\feb`[dbeh`ddfebc[`ia`Xfh_jW`Y\`_\bdbdbdcbcccccceccdccccacdbcbbccccedcdbcdccccdddbdeddbddbcccdcdbccdbccccecebccdccdcdbcdcbbdccccabcdacdcccbcccccdcbbccdcddcbccacbcdeccedcbbccdbbccdfcbbdbdebceecdccbccbdcdccdeadcbcddcccdccccbbcbccccdcbebccdbbcddcccebbbcdddecccacbbbbbcccbbdcbccdcceddbbbcbdbccdqibghfahcSZ`j`\ea`je^jbebeecZbidmnocl[e_jee_VibZcUgaZ]jfg^`di]csedm_\c\kd_ahUl_eWblkXcZcg`cege`kc_cnlhlf^bbcja^`bd`eddcdgee^ec[amg`fce\ebdfa\^chdjYf_fg``h^hf_be_e\`af^afdaceloaak_ebbZdafgj`egjaZ``jagee\`\dbig]\c\W\d[k]l]e\af[jkcb^_^i^f_\occ]e`geUbdipkckdab`cbcccccdbec`haebfbeegacedbfdd`_cbdfeefccdfbc]d_bafc_f_ha`a`fceeeabadf`fh_dejbeabbdefbb`dfa`eacibcbdbddbdecb`haabgcb`ebdgfeafcd`g]degcdddedaaddbcaea`b]fcdedcbdcdaicebccbcebbabdeidd`cebbcc_dddgdcciddb`e_aaabcbcdcdc_cddfcd_dfeaa``ciccfb``acd`gc`dbbacdedceac_bcbccccccbcccbcbcbdccdcbdccdbcccccbcddccbccccdcccccdbccacccdbcccbbdcdccbccdccbbbcccccccccdccdcdccdcccbdcbddcccccccddcddbccccbcdccdccccbccbccdcccccccdccdccccdcccccccccdbdccdcdcccccdbccccccbcccdcccccccddddccccbbbddccdccccddccbcbdcccdcccdcdcdcccdcccbbdccdecbcc`]h]qcf`X_]afdbhgdcace_bcjgc`ahahn`i_echbej`cfdf`\gd`qhh^`Yfc`cdgdfY__]ff_hhdbcddfghcjd\hdefe^mf^ddjfb`dh\]d]_^eqbo`bfckb^a\hbUcc_iedfbddc_k`ef_\chc`\`geaidnhdkgelaoemfddkbfhbckheagbffZd]lhhkee_Zcbieg^^egejk^`fbmegjb`ck`hcZfgka`\_^Y]bg\aceeacjbgcd^lc\d^a`[jan`Zhdgha_kbfckYiqd_W\e`k_\cb[\dgni`efmegeg^]_[``___bhag_Xg^b[d[f`aZ_lfd__jcfb^iY^\fjhgh]aaobhf_emkigfee[_ckj`fh^i]beebi_`jj`akob`jc^]fd[i]`\dh]ajdmbbuk^fqpicbd`fha]elhbjbgdaiXcf_dVclbghh`fqbe\b_b`__ZaabZgk\ae^joadcSec]Ybbgjkiceb]cida^gmb]dfbiUih]plddnbgp\n\sW^c_qdZ_jih`jad^t`m]iggh[__eWp[S`lbf[c^zfiZ_fhacfalZ]ahc[`g]ej`he^^glh^[egckWYdnWZjvliafX`yhj[`Yja^`dc]UjfgebaZof^^^felmZjY\bdrf_fmp^e\e]]LlcY_cWa^febffVR^coXUb`_jka^dp[h^\nhcffemUeVd`^`oPb]YZgVuml^oiph^hcUla\[bZlcfdkcgmc`\bW]r^d]fl[]`hh^ieddaie^Uhul]b`aadod``dabd^l^`e_jca`fddfieab^]c`_bd_da^eagabd_ae\^eg_c`ca`beclbcc`cbj`bdf^\da^cfid`bid[e_\f[]ffae_egbafbcg\d\gacffd`bja``hf[gbdeeaeecia`]b_^e_facc__ajaifb]_abb^d\jbecdcof`g\]ddcabchebb_be``dYb_fdcfkeei__`k\fblgcf`e^_`af]bhbgbace^ccdZ^ecedhchde`^gdc`bkik\Rcmas`^baZnefkseTYbr^jib\\Ted^dbjike^bhniahf]jfhgej\hoicg]efpqo\bZSdfjihkahp^Nda^bYen_gf_bcl^jkag`dfimfcfjpYmZkecekPWlcbdijmq[f]dsgfknbpeUmSfd`j[[fdNcU`PnfkegYb\f_Wlb^X^_fe`etjggdniahY`gVmh\sdegYehY_VRabLS]nQmdgcg]ecn_i\idedW_icZhnipdYWWh^_Zk\`\]_Wjlc^p\bjceabecld[`m_fcjd_baa`_gb_^cdb__odacYZadh`_eck]d]mgeadlbfe_^_l^aa][cbcjbmacih[iefdkekc_lcahbhf_`coh^`afg\eb__g]\da]Y_]eann_eefcc]ghd]biam]ghgffibRjaffdlmkc^fYfig`l]ecdk_]cfbah_iYdd]UbcjbdXckcfd^aac^fjefabdnhe^d]fiedjhg`c^lcabaf__i[c`]ebchhbc][ccch^cc`^^iadbc`[``heb_eff]ddgcca_]\`c[\ki\dbd``dcaa`_c^^cc^j`g]becidm_ee]ccacchgf`efb``ndeae_jccdffb\bd]cfbd_hfde_hb^fefbaa`f_i_cabd`ecb`fdecgha^bc`fa_bi`fhdkhmYd`eufadc`cdecbfba^cagb`kc]i``eieZhc_dcgd]idccacf]cgbheid`edd^jie\dj`gecai_i`ik\`cdfa]ebcdde_be`\gggchcidde`dccccccccbdcccddcdcdcccbdcccccddccbcdcbbbbccbdccbbbddccecdcbdcdcccccccbcbcdcbcbcdcdcbdbddccccccccdcbccccbcccbbbccdccccccdcecdccbdbdbcdddbcccbcdbbccbbccccccccbccbbcccdddccddcccbbbdcbbcbcbbdbdcccbdcccbbcdccccbcbcbdbcdcdbccbbbdccacccccbccccccccccccdbcccbcbccdccccbcccccccccccccccccbccccccccccccdccccccccccccccccccccbcccccccccccdccccccccddccccccccbccccbcccccccccccccccccccccdccccccccccccccccccccccccbcccccccccccccccdcccccccccbcccccccccccccccccccccccccccccccccccccccccccccdccccccccccccccbcccddcccdccccccdcbccdccccbccbdccccedccdcdcdcddccdcdcdbcdddccedddddccdddcdccccdcdddecccdccccddcccccccdddcccdcccddccdddcdcccccdccdccdddcdccdcdccccddccdddccdccdcdcdddccddccccddcccdccccdccdccdccccecccdddcccbccdcdcccdccccddcddcdccccdccccccdcdccdddcdddcdcdddddcccdcccccbdccddcccccccdddcdcccdicc_bqcfkkdWkaZabfajd_giiXgkhbcg_g_TgebgcckcaVgmd`geecX]a_h]ncf_[hj_c[fde^^TUh[icdg]ZdcVddgmlj\cj]X[bfbdjigbj`glibeifd\j\^`eaTb^i``g[j]]^[ccZhc]h{ged]`]]_dY^[dbgeahkhi^i^d]ed_Xihj_[md\bmenmaiccb^Waab\j`abbcockc`W\\[_fZ^`f^ajefhgchc\jYbbddahdqhefkadfb\a]`cedbcdcddbcdcc`cbdcdeccddecdecbdbcbcccdedcccceccbdbdcccccbcdccbdecbedddcccccccdebcccddbcdbcdddcccbccccadccccecbedbccaccebcdbfddbdbbdcbacbbdbdacdccbddcccccabccbbddccbddddcdbcacacbccdbcdcccbcdccddeccbdcddccccbdbdcbcdcacdcbdbceeccbbedebcddccccbdcdebccbcfcacecccccde`ecccbdcdcdabccddebdedccdcccbdbbdbcecddcdbbcbcdccc_cbecbbdecfcabccbcccdcbceddcbbcddcccdbdccccbecbbcdcbbacdcddbbebdcdbcbcadcdcceeddececdcddcbbddcccccaaeabddbebbcbcccddbcbccbacdaedcbdccbcdccddccdddbccdcbbddcddbcbacecaaddcdaaacdebededccbddedbdceb`ddcbedcdZc`aab_pc_de\kjhiac]edcbce[^``^[j]bnafd]ca^b]abbbk^ed_j]^a`baf^_ggabZdfck`gblgl[fo^fbhdbdaaW_keefqj^bcjk_dl`e^bX]^[h\_d\ac`fd_f`amYX^^h_eUbhlb_c`\e^Y^cgnp__iZ_pfctbsblg]`cjhgbgkWei\Sj]g^h^`b`\kadjecfs`dfa`og`[c\ei]fpfWYoajgb^goic`]ac]dn`a_fcehkabgfhegche_egg_df^haeefbbc_bech`^bcgdccedfcaadgbafdbeeafaebdfehihd_badeacceaiccdadg_accbbfhebdceigchdbdiaha`ciafgdbc_cfb]cek``h\bcfe_hZfe^bdaddcebhbbcdi`af`fhfccbbjgafahZac`dgfebaecae`bh_`b`acaca`bhbc_cdbbeeacc`ggggejefada`Y`dac`f_c^`e^efaca`d`ddafgbcabd`cb`ccaegdaefhXaf]o[]WdY[eZdbefXd^khd[dhcfiY^daRVhagcWltQ[cefci[SZnWkZ^ma]fcdhXYeb`Vf]jca\ZS\clc[snagm_cbfnoklbj[hiighj`ZnhKW_c^agbjbjerdrm\uhl_WhZkriib^^k]`Veani`ge_]bgdWfdUr[UYd^oaa`mfg_kfjgbbgjYjkdbYa[VkpjbnSf]Yabeogf`[eY]fXil\if`YZYaedchh^v`l`_jkefegg^_bhh_j]]ilUrghccbbbbbc`ccdcc`acdcdccfbbddccccccbdcdbdbdbdcdcbbbccbccaccccac`acec`cbbcacbccccbccdcbccfcdbdccccbcabbfdc`bcdabbbdcddcbbabecabbdcddaceeddddbbbcbccaecbcbbbacadacbbbddbccdddcaecfdbbdad`bbcbbbdddbbccabcbdccdddcacccdcbdcabcb`_ccadcdddbedbcdddbdcbdbaecbbbbcbdaadcZ^jflgbc]`VoVdjbUh[\`hZWcxdabcl^hWakZ`e_ib\mia]b`f]YpVWfa_il[`_b_a^`j[YWgckk`bgfXeXesbhgdd`]e^gefa`bgY_`ljSbfYe^ZbiiagfecaS[eqi[\eXkkehkdjbdb[Xqk]edjiZi_a`ghce_ctb\aadc_ofcoadpcYehdTcejdonfcj_[nkf^fXcfebn_ab]b\dcdTgif`ac^h][Y_jnKwcKWhd\glc_gfbd[d]]dpijqhd]ccbcbdccbdbcccbbbbdddccdcdcbccbcdccccccddbdccdccbcddcedaccdbdcccbbccbcddddccbbcbcbcbcbbbcdcccdcbcdbcccbbbbccbccccbcbdcbcccdccccdbcccacccdbcbcddbcbdcdddccdbdcddbccbbcddbdccbbbcdcbccdccccccbddcddbdccbcbccdbdcdbbdcedcdcccbcdcd`ccbbcccdddebdbcbddcadcccdbccccca``hb^gecgcecjdbbc_agfacedfcidbe[abacfcc`ab`bc_`bdbbee`bbadddebidd`dgjedf``kedbeaab\eddc_effibccbefcbhe`chececdbj`fbh`dgc``_jecfaea\daffec_ge`adddfggddb^c``_`edebedad`ejeai`ddcgaccccbgdechbgc`aea_c^ecgbbdb`dcab^dZfgd_cabbfcfaac_iag`ccae``f`fgf^cdhac`acabfafbc`ccbdbdddcdacdcbccca`bbcdddccacdcdddccbcccdddccbcccdd`cbcbecbbbcccdcbcbdab`bdcbccceccbcabcbdcbbbbbdcbbacdbbbcebadacccdddcdcbbcdbcccaacbbccdcacchccccccccbccbcbbbcbccbccbcccebcbbbcdccdbccbbdddccbcbcbacdccdbdccddcbcccdccdbbdcdcbcbbcd`ddbcbcecbccdccdcccddbdbccdccdbdcccddcbdceddccdccccbccccddcccbccddccddcccdccdccdccccccdccdcccdddcdcccdbdccddccccccdbbcdccddcccdccccdccddddcccdccdcccccdedcccccccdccdcccccccdcccccbccdbdcccdbcdcddccdcbccddddccdbcccccbdcccdddcbecccccccccdddcbcccccdcecbcccdcdccdccbcbcdcccbccdcddccccdbcdcdccccdccccccccccbcccccccccccdcccccccccdccccccccccccdcdcccccccccccccccccccccccdcccccdcbccbcdcdccdcccccdccccccdccccdcccccbcccddcccccdcccccdcdcbcccccccccccccbccbccccbcccccccccccccccccccccddbbcccdbcdccccccccccdcdcccccccccccccccccdccdcccccccccccdccdcccccccccdcdcedbccdcebdccdccbbecbccdbcceddccccdcccdccbdcbccbddcdcccdddbcccbbddcdcbccdccbdccbecdccdceccdeddcccbcdcddccccdbbbbcdccddccccddddddcbcccccccbcdedbbdddcdfbcceddcccddbdbcdddcbcdccccbccccddcccccccddcdccedcccccccdcedcccedcdbcdbbcbccccdbbccbcdddcdccdcdbcddbecddccccccccccccccccccccccccccccccccccccdcccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccecfebcedeabbhe_dc_`cdddab^a`aacjdcdbea^daabe^aedff_cbh[gefeeece__dd_aaabc`bbfc^eebc`bac``bbecaf^]`dec`bbeafbbdaee^daccbfa_fbcd_cbchdfbd^`ffcccehb`cddae_accaahcaaddgbb^^aa_beeaccabagegdgiafccc^cecedaha`gcad_addea_cm`b`dkdcd`gfbcce`dahecc]``aaaeaccabacdaefbadccdcbcdcdcdcccccccccdcccdccccccdccdccccccbccccccccccbdbbcccbccdcccccccdccbbccccccccccdcbcbdcdcdbccccccdccccdcccccccccccccbccbdccccdccccccdccccccdcccccbbdbcccbccccccbccccccdccddcdccccccdcbccccccdccdbdccccdcccbcdccccccccdcccccdcccbdcbcccbbccccbbdcccccdcdcccccccbcccccbcccccdcccccddcccdcccbccdccccddccccccccbcccdcbccdbbddbcbccccccccdbcccccccccccccccbbcccdcbdcddcccbcccccccccccccccbccccddcbdcccccccccdcbdddcccccdbdcbccbccccbccccccccccccccccdccccccccccccccdccdccdbcddccccccccddcccccdccccccccbcccdcbccccccdccccccccccdhehh`k`gac`[hf\hb_d^gV]ckY]cgghei_gcd^\ffZkjbbqcf`Y`fejb^[`cdf\_`bfc_ae`aa^faee_cjedbe[iUcf`]`kdd`m^fmhdahfbg_^cda_ahh\lgelbhX\gbbhc]]Xh`c`^efdg_a_f`\abhmg__]ejhced_g\cZdcejajdjikdm_ggde]^]bdlkb\mcUfeaYb]dgbngcegjg_de_^egX`gmg_\^Zea]\_^eae`efafbhgg`cddckn`cccccccccdccbccccccbccdccbcccccccccccdccccccbcccdccccccccdccccccccccccdcccccccbccccccdcccccccccccccccccccccccccccbbccccccccccccccccccccccccccccccccccccccbdbcccccccccccccccdbccccccbccccccccccccccdcccdccccccccccccccccccccbccccccccccccccccccccccccccccccbcdccdcccccdccccccbcccccccbcdcccdcccdcbbdcccccccdcccccbccccccccccccccccccccccccccccccdcccccccbdccbccccbbccccccccccccccccccccbcccdccbccccccbccbccccccccccdccbcbccbccdccdccccccccdcccdcccccccdccccdcccccccccccccccdbccccccccccccccdcccccccbccccccbcccccccccbccccccccccccXgkWf]`_degdbec`efeiYx^ZcUbf^b`iViheeec^\iaef]akdenfldTigdhag[cla`\W[aj`jadk_`ihXa^\[j]fi_f[mZhl^aomgceee]`dmhbb]eh`fiaeYfWljebYlcYkejgkihhgabf[fvnf^sra^dajc`fjZ_ijai`b_jd^b`cXf^Yfj\cY^a`ljbnc]Y^\njV`ljabgWdeZ^kdQgZej_gg_g_mVefWq_h]cgTf_nYgem^^][qk\rf]\j_\dcccccbccdcbccdcccccbcccccccbccccccbccbdccbbccdccbbbccbcccccccccccdccccbccccbbcccbddccbbccdcdccbccccccccccdccbbebaccccdbcccccbccbdccccccbccccdcbcdccccbccccccbbbccbddcdcccbbccccdcccccbcbccdcbccccccccccbcbcddcccccbcbcbcccccccccddccccbccccbccbccccbccccccbbcccZb`ctiff`dafYdgZf]jg^saXeil^aakmWi\cmh^Xfe^UZ]mZhq_Uai)cZ_feh```hclbYc_e``^ic\\km]Zi_dlgiV\_i`lW^f[rkabik^\[bhie^``fffe`Xdbkfad`cmp_ekjm^b]nRfheev[hig^gfdgebXma`lX^khse`TVe[iTagVXegkgf]MX\vmcaYfkdp`]beimlU`^ibfehjJ_r]ajapicXacoaZc`ndbfecebwdXf[b\omdjkq^gccbccccdbbccccccccccccdcdcbccbbccccbcdbcccbcbbdbdccccccbcccdbccccbccccbcbbccbbcccccccccddcccbcbbbcccccdccbdccccbbbcbccdbcccccdcbcbdccdcdcccdcbbccdccccccdbcbcccccccccdccccbdcddcbbcbcccccccccbbccccccccbdcdcccccbcbccccccccccccbcccbccbcccdcccccdbccdbbbdcbdcccd^icm]fd`dgn>nnf__q`fefaecng]dfXb`le_cc[doV_b]hi`fg_Zcfchgkogbab\sYofeh_m^`chigwbn_icl[hb`k\gfqad^eWmj\``mh\Wekhgn\hfpl^ZgijYa]hieZ]`nd`incl`lin^kfagibX_XeUbgdbam]gZo[b_oa^ckf^g`r[]gkofeZXeaiipbbeeidcfhcdagn_`af]YofIfS`f[e^h^obcjcVk[Zabo]Z[f_`hadfXi]`i_l]idccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccbcccccccccccccccccccccccccccccccbccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccb_ffbg^ff_be\me]d^ece_]bc_[hdb_ak``i]c_dee_jdgbijji`^ekdk]dg[b]kdh[j`_gbbe[d_fieblacXcddaff`h`bddc_dfj`abh`e_`gjm[j_c`fhaa\e`j\d^d\edibebekcee^b\dbf_jZeb`Zcbedai]aabp]Ye_gccale\ck`]eibageaj_ffdha^c`efZccaagfZheabWdjX[Y]l[bXhaieZhbW``d`db`i`c]W\jb`S`\e\`af`occcccdccddccdccccccccccccccdcccbccbcbcccbcbcccbccccbdccccccccccccccccccccccbccdccccbcccccccdccccbccdccccccccdccccccccdccccbcccccccccccccddccccdcccccdccccccccccccccccccdcccccbccccccccccccccccdcccccccccccbcccbcccdccccdccbbcccdccccccccccdccdcdccccccccccccccccccccdccbbcddbccccccccccdcdccccccdcdcccccccccdcccdccccdcccccccccccddcdcccccbdccccccccdccdcccccccdccdccccccdcccccdcccbbcbcbcbccdcddcccbcccccccdccccccccccccccccccccccccdccccccccddccccccdbcccbccccdcccdccccdcccccccdddccccdccccccccccdccccdcccccccccdcccccccccccccdddddcccccccecbbcdccdcdcdcdbcdcdcbcbcccdcccccbdcccccbdbbddcbcbdcccddccccdcbcdcccccdcccdcccccdccbccddccccdccccdddccdcccdcdbbccccbccddcdddcdccccccbbbbdcccccccbedccdddcbccdccccbcbcccbcccccdcdcccdcccdcddbddccccbcccccddcccbdbccccdbccccdcdedccccbcccccccceccdcddblkcmdgsc^i`iI[aeaghm[x_\`ajAWr_zskfcch``fabkTu__gffcYhfje\\^iYrame`kigfbS^]k`Ygf]ZfauVohsa[ggnnfcfaredY`hgi\ZceVkif]hehYdfogdiZ]Zva`lV\S]fhbgbcfm_^bisfjo_^a|Thcbf`b\pcW_e[g[fYdf^[`\nXeU]i`]iiwcWi_^dfha_`a][^gWk[l`Ri\c^n_cncbF\fjf[cQasudYo_YaZlV_RXejjgbcQgccccccddcccddccccccccdccccdccccdccccccccccdcbdcccccccccdccccccccccccdcccdcccccbdccccccdcbcccccccdcdccccddddcccdcdcccccbcccccccccccdcbdcccdccccdccccdccccccccccccddcdcccdcccccbcccccccdcccdcccccdcccbcccccccccccccbccdcccccccccccccccccccccccdcccccccccccccbddccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccbccbcedccbccbcbdbccccccdccdcddcbcccbcbcbcccbddcccccbdbbbccbdcccccbbccbbcccccbcbcbbcccbbccbccccbcbbdcbbbccccbccbcccbccccbcbccccdccdcccccdcccccccbaccbcccccecccbcccccccbbccdcdcdbcccdcbcbecccbddccccccccbdccccccbcbcdccbacbccccbbccbbcbccdccbdbbcbdcbecccdcdccccccccccccccccccccccccccccccccccccccccdccccdccccccccccccccccccdcccccccccdcccdcccccccccccccccccccccccccccccccccccccbccccccccccdcccccccccccccccccccccdccdccccbcccccccccccccdcccccccccdccccccccdcccccccccdcccccccccccccccccccbcdccccccccccccdcccccccccccccbcccccccccccfhgmemjgdbdgnXcVh\fibe[^m\bbW\ee`kgfd`im\aeS^Xfjchq_]dXaeidejaTk]h\aEda[ho[ehhb]]fWa]WjicSe]^f`eePfhabib]UeadfZijia\bicmk_Ysefa[mjnectnstc\na[dUoi[e[`b[cbfgacjfbfSbcpik\X_dmZjdgg[fi]bf^dcrvk[h`^[[eccc_ZbchTjm^^kmgm^kki^dfibcq\i[dadqaq\dhbgij^fZc]mjdo]bVkl\ccccccccdccccccccccccccccccccccccccccccccccccccccccccbccccccccccccccccccccdcdcccccccccccccdccdccccccccccccccdccccccccccccccccccccdcccccccccccccccccccdcccccccccccccccccdcdccccccccccccccccccccccccccccdccccccccccdccdccccccccccccccccddccccccccccccccccccccccccchmk\a^SigUWldV[^`elXas`a\[[wfdilLhsd_haeSec]oioe^clrjm_bf\rVfkcucWdpLmfXdb]cOfb_NZhbQfiipXdg\YbhYTah[_lbaaa_X_W`dhddQ`ilnlfqe`^eedqnhfqblid]mV^i`bmh_]`ke``^oa_u_c^xS]\`gohfe`c\]dj_mVK_\`j`\egf_`Yd]ZYenlcjc^`l\]doXccUr]mm]oajnkZZaZ`hej[Zihige\^deYgXjne]m`jfdcdebccbcbbbdcbcdcbbecdbdcbcccbbbccdcdbdccdccbbddcccccbacbccbdcbbdccdcccccdbdbcccdccdcbbbbbccccacccccbbcccbccccddbccbcccccccbcbccbdbbbcccbbdbdddccccbccbadcbcdccdcdcccbbcbcbebdddcccccccdcccccccccddcdcccbcccccbcccbcdcdbecccdcbccdcccddccdccccccccabccbbbcccccbbekg``d`dfa\kb`fb]hih]ihdbgfgd`]`ceacbieaccak`bgibdckcdfcgcchbe^aefcgaeadge_dbe`afcdifb__dgjb`egdagc_ibbbdad_bekbcbe_faad`dZbhi`ce^c\fddi_`^]ea``eec_dfbk`dg_gdbdbjebgefa``ecb`bfce`l^bckgafcgaehcbcdfdd__bcgd^c]b_`edcjbcfbackab_egc_eagchbaief\chf`figbkagbgccccccccccccccdcccdccbccbcccccccccccccddcdccccccccccdddccdcccccccccdcccccccccccccccccccccccccccccdccccccccccbccccdcccccccdcccccccccccdcccccccccdcccdcdccdccccccccccccdcccbcccccccdcccccccccccccccccccdcccdccccccccccdccccccccccdcccdcdccccccccbccccccccccdccdccccccbccbafdbddcdeeacbfbdddbdcdcceceddcbdcbbbcbcagdccfcbdddbbddcceecdcefddddc`dcfcbbeaccbdedcbbccdeedhcfddcededccadcccdccdefeffacfegebecabbcbdbecfefcbfejgbi`dgbdaddeceedceedefbc^edbdeadecadbdbbcddfbbdebe_dfabbfbebefbccabcbc`efbaadcbabdcdeecbccdcbedfd_abbbcdcbej`X\X]raUX]]iQZ\i^jml]_zfFhU]_kcWXjdW\brsdjKWeT]hoaebWisfreeeScQbjac~j[v\^ErVonklrX]acjW^^df[ekJbdX`jljXrCii_cc``rbjc[aae_kdncccseiXc_i_i]`ZdmupkeejN_g]efcamn\PlfXe`bPhcdlchgphZ[kiakpemsboOach_hacqaqW^XhT]bgWmfc]Zbe`Scy^d`Zbn^cihgagd]dkfjba]aa]_Kh_ajmdnfr_dbdeddcbabddbccecd`d`dcbdedebdbgbeabd``cfecc`eaebbb`eccc`becddabfddcebcga`ccbccdccgdbdecbbcccdababbcacfbcffb`adcfdcbabdbbhecddbeadecd_dcbde_ccbcbdcddbcddcacfbcbgehgadadcdbccbaceccbedc_bbbdbch_eccaceadcdebddcddb]cddcbde`caddddeeddcdac`ccfdi`dfgbddc`cdb^bccdqhoi]d`fi\XjnkWX]`fdcWfj\p_y\bqk_dWUljk][g]^Wk\ckieiwn__effmVnbgV^m][faf[abk^nTagnnj`kt][]bcZ`g]dNcqdd``pn\dda]ee`d\fWsZhg]cZgb\hfTcOQfTbaZel[bppjcZeXfee\ca^b]bbw[hh_qj[r\hhieXb\ie^ffT^`^ffrZfhie[fmcVmh_[bgau[^cZ[eOhrbcfguf`r`ddgc[`iu`fYbkj[ajaqcgaj_^kaas_\^tWt^phhccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccdcccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccjljcdTby^YfjccU`gcs\^o\X[UaggwndUVi[SfVg]ke`Se`feabbgeT]^_fcm`eYcYkajf^[\cZgcnbd`_bfdgp^bgVhdn_]^bcjdWX\dda]]og^^mbla`achcja`^uZd^lj_]cgeil_gYkj]xngh]ceQ_a`wjk`Zj`wlX_ZcgleYe_dj`__^b\S]hfa\^d\okcfWgcNgnn_idZZj^iihllJ^bodbe[eYf]fcVfd]_mdWm[aXSabg[^W_hcpqecegg`_\Xha^\`agXa\jcail_dmfRf\`egaY^e_Z`cqkejV]l_fdo``f]ka[p_]a]iX_fbaldaq\aPgZkjimc^cb`l^aXde[doWadVdkjdYkJcc\bc\ge`_]``]dgjkt]g\ngiZf`kidb_]]boflacjTYe_fcdbgiaZhc^c^]Wkcefcbdld][ddfijecf_bWadejh^glahXX[g^\cfaj`]d]fbaYdk^b_`eeaiehc_ic^bfjg_hh[``j`d_dhcbmkpcdccccdcdbdddecceddbdedcbbcbcccc`decdccdcccbcdeccdcccccbbbdcbbccbcebcccccddbcccddedddcbddcdbdccccdcccdcccbcccbbcbcbdcccdcddcccdddcbddddddebdbccdcccccdcccccbdbcdcccccdccddcdacbcccdcdccdbcccbcccdcdbdcdccbcccdcddccdbdbbedcdcddcbddcccccabccccdddbcccddcccdcccdcccjkibeeie^aaj]]\Ygpceo_]bbwchmg[\a[dfah`[ka]\o[kWXXhibW]Tn[^inilbhZchT]i]^Zxechkfl_d`Z_i_amhh\WgYjcpabcdeVcTqose_X\fWdhe_fgi[dplBlfeccrTyb^`fZeYc_Sobh\V]k`Kt_^bhclhNV_^efeakc_Zr[`ftg`kildjg_]ec^oiemPcg\[]d\`xjgGa|PMXbr`e_dgaaag_f]ehe\c]bcR^\UagUY\Z[eVY^cibdbc`acedcaaddecadccaeeebdacae`dbfbcccecddbbcaddbabadbdddgad`baaegbedbcaeedeecbagbhe^bdfafbacecc_cfdabcbeegcdaeadeddfbcbd`ebdbfad_edbb``bbdccddbddgaacccddgeffcdedffgcedcaeadb_ae_fccef]bccacaacbeaeb`bdddb`adedc`bdcgd_aaccddeebddeddddc`acfcced`ffdcbebbce``cdTgdmhtQ_f_emkhefea_`ifad]hi_flcp_ZQdsi[Zmc\c`ffhYYWfm\\b^p^ei_iiaYU`i^jldecbmj]a[e\WiibYfdjc]odpj`e^gkckv_fcbafe[idZbZaX]^lblan__h[^\gjjnghaYgdfkemcjf`sgg\`doajeW^nchgjdfcjbm\fg^t_^W]afhcnd\l[`\nn]diQc[dWc`f]ahiqYceZhjebd^X^\Y^al]f_b[c^^njN]daachbiddg^ckfgccbccccccccccbcbcccccccccccccccccccbcccccccbcccccccccdcccccccccccdccccccccccccccccccccccccccccbcccccccccccccbbbdccccbdcccbcdccbccccccccbccbcbcccccccccccccbccccbccbbccccccbccccccccccccccdccccccccccccccccccccccccccccccccccccccccdccccccddcbccbccccccccccccccccfddd`^cbl`c\_djkaib_bd\bddbYded[fb[`cai^i\gabcfcerh`hcca^bhaddf\e_Wcnihdf`^g\ccnhhbccYf]d`jfe_d\\c_ele`fkVh`bi\\eTe`ieafnhhfag^lcdacdeng`b`_kcbkca_bZea^aZifacXecabXadb]Yfcedeeb\^b[_`iibe^^dhaleededYfcbjaajbadh[ehbic_ffkYabchffjfdcacac_m`iaeccfbhd^adebibaliccccccccccccccccccccbccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccbccccccccccccccccccccccccccccccccccccccccbcccbccccccccccccccccccccccccbccccbccccccccccbccccccccccccccccccccccccccccccccdcccccccccccccbccccccccccccccccadccbcfcdcacbbdecdabadcdbe`cbddc`edb`ccddecbbc_e_bdcbbfcaadfbdeedbccbcbdba_bfeececddddebdece`dabbaeedeffccecadceccdbbfceeccdce`dbbcfacafhb_baeaabbbdccdcddadcbccbcfdcadddcbcbbcbeeceddcbedfccbccefaadebcgccdcdad_cbabed_dbfebcbcaedc`cbbe_adacca`cgc`ccbcbdbc_edcjomincffinangi^cfaZehafhc`b^`y^\foag_a^ji`dVc_c_aeXda[aReZahgir`]aaca``geme^g^`^`dcbmmWejgcfdi\g^`jk\djbgjb^gdmfhd^jgXg[Zah][Q]ag```m[aa^ak[gbeYmke[`Y\d]Z`dmb``ZgrbijXdb_jb`[bibTaiedWdfdiUa]ifXfmegi`h`e]eealkigVqch_K[]^k^Z^ZdSkc`dea]]_fdldcfciZ[i`aagk[qdccdbcddddccccccdccccdcccccdbccccdcccccdbccbdbcccbbcbbbbbccbbcdcccccccbbbcccdcccbccccccbddcccccdbccccdccdcdccdcedcbdcdccccbcbbccdbdccccdcccccccdcdddcbcbbccbbdcccbbccdcccdccccbccccccdbcccdcdccccdcdcdcbccccbccccccbcdccdddcdccdccbccbadddcccddccbddddbdbdccbbcc_h]e_pm^chfV^gf^hb[a]`f`ekfa^`\ba`bjk^_aclZc_\\^^]bZbjjogdki`Zeeifs`cddlS^bb[[beg_ao_dg`fidZdbf^c_dnfiXiZiWegcdilXcsha^h]ane^ndgelaf_ch`a_`dYh_hh~Yhai^aedhhd\gfai[ahfwb[ae[coYbbfcdc^^f]d^`_f]egVem\khg\\ej_`hicb`l`_ecjdb^a\cb`lbaZfe\gglco`fj^hkbdc`XoXgebb`ijib_ijbmghfeh_e^k]bnk_]ehebcbaeeUlfZbffciXi_kcebdjY]kY]aWakbffeUbfnejfWrfehedk]kYXX_bbjdgePc_dj_Zm[keheYrgef`lko_aib\[cdo`iek_jke[ef\Wfa__occba_aji^c_Zhgae_m_e_bf^aa]_^njgdgd[`a]dc_h`[adj_[blch^ddZ]_i`Wbaf_^dc]fbgebRmPlicb^h_fhigec_[jYUgd\^b```njXbjeaOzeemab^ea^fbdfcgcebi]ffcae_bdebegjjdda_`bjah]cffal^f\hadfdeXb`b\fag^bebfeaaf^gbdcggei`cdgccaibcbccfcjcgc`d_caf`medcdbge_kba`fehacbccadhcga_\Xcd`dg`abgc^he`hg`cfehhcfafo_`feedc_d``_]b`__idc^f^bd_cXdbc^e`a^ckgdhggef_e`_`g_i]g_ad_^\a^\fjga^f]d`b_caf^fej`chafddb`daSl\dW^kYfie`s`mr`Wn_kaZdVb`\Rfcoc[_Y_\SifRcTelbmkdca_`kcp\c]`YsjaSiX`qZgem_^ddXcmW\_db^Vj[[ltindim[k\hZ^Vhneg]\Tf^`mdco^^rhcanag]QVfbidqX\]v[f]ahjdbpvfkbj\abhke]mQqc^`Yfj_Ugcjb_[b[SkTac]abaicru^bbnmi_u`gac\R_d]_neaucc]aZsjZc^hjgT_^cfhdhjdmfdfhb^pn\han\T[bcbhadchdbc_aXbca][f^Vg\_cl^dddfflgc`\deZ^]\addkga[Vck_n]ahc\_`e_`bbgZcd^Z\dp`g`[ceZsmafeha^ffcch^ei\b`^hahcki^eahcefbfaiddfggXa]cgZ]ee_`h`^gggdabdjh[_adlZhekdhg\eaed^db]gccbie_ae`^dh[b``c`adgbdhcgd_`lcd`pdm`j[b]ib_jhpbYg_df`ij`b^icjfjb`nhejbffbgc``bdfe_ejhcbbccbbbcbcbcdcbddecbbcccbcccccccbccbcdcdcccbcbccbddcdbcbccbccbcdcbccccccccbccccbccbcccccccbcccccbbbcdcccbcbcbcccdccdbdcccaccbbccbcddcbcbcbecccbcbcccccddccdccbccbccbccccbcdcdcccdcdbcbdcccbbbccccbbbbbbccccccdccdccbcbbccbcdbcbcbbbbbccdbbdcccbcbccccbcccccabcci`d`ca^_dphXVc`e^[TagQ[lhge_a]b`pbclSgdc\bcfhk]a_mhhYZU`gilbb`ecWcd_e^fffbleaghhdlZdd_e[doaYjfimdhfZRcfhjkkYka\\]`i_hj]_TdbbfefeR}X]b]jcqU]]l`haf_h_VechjmZ[fSdcm]b^fZg_^_c`h_^fg[jgeSkc^bXiZ^dc`igpc\dubed[jfgia[ZniLmydbNefimcahqebcfkbhhikdcgfib_Ynphkdgdpff\h_[`_fanViaoeoo__^_h^n`dfeajYdZeh`ga\`ibaU\^j]ebgUdfYhkqZd^fkZQX`bceKaca`dgZ\^hZbdci_affcd`inh`ei_]gmm`W_[aida]ppeedf``dlmflfelTkd_bgb]ia\ghWb^[kqfabp[`da`dgc^lZ]\\`ncbl\[gfbpc_lXYh[df[laUfimkk]Vb`k\ded^k`ebcfaicTltls_`mkk``h\_[becib_Ydndfby_d`fo_egSaWhYg]ojgam^Zifcdfjkdi_aXe``]echad_dactj\ekZdg\bk`c_io^g\gdbgg_e[e^caacf_^`^[ekbcbZ_aceg]dbf\a^edhtk\j]eted``bgllcgdaedaccg^^jeglapeZ`bk_df^\c\\b^^abcgd[iWc^obid]]ebbfgbcgm__iahdae`aaY]ck_kgRie]i]eYgh]^``jfUfceceYecc[ligrcgbea_\`ca_gcifag^[[\]ddidjeedhbieba^]`cabccccbccccccbccccccdcccccddccccbccccccccccccdccccbcbcccccccdcdccccccdcdcdcccccdcdccbdccccdbccccbccccdbcccdcdcccccdddcccdccbccccccbcdcbcccccdcccccdddcccbcccdccdccddccccdccdccdccdcccccccccdcccccccccbccdddbcdccccdccccccccccccccccdccccccccccbcdccccccccccccccccXbiik`drdocX^hnbRgq\Qyelc^ape`aZ`pa`gh[]fQbag_j[[W]mQ[ajlf[kesk_dqjZi[\`a`ikY[a^Qead^hnjc_cb]VybgUV^^`Xqmlfp[cUj]`x]hi_hX=K]dr`fZ_`bhZdgerhlje^^dcdmjjiLbb^Zbf]k^dnp_]XYachjY^`]dg_di^ffX[neWd\c{eWxd_ufeZe`]ckWfZihUYkV\vkdgaifgTZpcaIUaDk_W_]`me_bddijteRbje^Ybbl]iXocWah_gVY_jagtqqkc\YykiajL\bc\bhmSd[`]d]dgVTk`jgnchgWfgqdd_Tnqjhef`mXmJ`a\Xof```k[]ad]XVk_cWWf]ebfed_Z[\cc_a^XXd`o`iYUngf^Xun^jaY`Zf`a]fabak_n_cfa`b`YnUU]^`hg_v[aV^\gcR_`bg_`jcla_]egc_Zmjjfb`fP\jgj[a[hfldtccqNblueqq^md]W^qoahf_aVjaghk^c`knd]XY`shheilfc_]h[g_]^ca_\g]_Z\c\\riegcdUk]dlbhc]hhjTf_uhhV\sbceapSbijehfUUaj_`ja^udc^^Okhc\gb\^jY^]be_aeeg_`hj[gdidZU]gjdtc`[dia^j]g}abqdeflbi^hhhelgU_fcqgoP_K[^b_he[bedbZcWgMXN^ulceb`]]b`j_cMkaYef^Sgl`V]egc^Xrha]_fcjdfffg__cg`^aieg\affddaiY^qjc_lZ`i^o_dfjl`jcjWkefYdcedfaaffd``dggccecbaf^_cbdebc\ldc`_`b_[_ec]`fdbic^e^dn_`eee`bdegXecdghde\ccbagehicdec_hdf`dfgbi]fgbl_beeecib_gabgadbcfgfbccjbibh^aejddabi`gdcg^c`fche`en`dbedec`ce^h[de_d``agfd`ld_ab`cigg^cbfleidbbaj]ag^hbe_`b_`^fj]`def`f\baiad`b^`j]`e]`jfgb_Yda]`b__``Xc]abcc_^daide_cka_a_cdZcjbdca^ajjWbbgeakchmo]\WT`i``mjfkkXbf^cbc^jZ_adbdbhglk_eb^d]bii\amdd^abdd\did_cqb[jb`__hiWVgebbh^eX^gl[aU`a]fahm^a`e^]ia_ki^Xkg^h\ka[cgcd\bbeliih^jYecbYafaamUbdebic\gcshck^_]iic_aaalkdd_dbcV_dfgebbaihkbha\hddfebcde`^cddb_k^ahfgbXhjia`m\ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccbccccccccccccbccccccdcccccccccccccccccccccccccccccccccccccccccccccccbcccccdccccccccccbccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccbccdeeeddeccddccdcdbcdbddbcdddcfccdbdccddcccdbdddcddebdcdcdddfdddaeddcecdbccbccaccfceddedcdebddeedcdcddddeddbbccfeecddcccfeedcfbbbcdddddcdcbddcccbecdcccdcdcdbecebeecccbdddcdbebbcbdddbedddcccdeddccacddcceddgccdbdbdeecdcdcbddfddccdceebccdbccdcdcc`ecbdddcdccaW`]cYbja_W]\fhfZbecm^WjtgbXqfia`^an];kbddmble`abkUo]c_hc\a_i\^khbijhfehgafg\calcc]hdZTehY`fXLo]Sn^AJghf\fWgcjfhjggg][ae]n^ke`bucXZflbhmmm[gcm`T]dcjdib_hjdcio\f^cjjfqiicae_``^cloeefV[`aeh]cqX\Vbr_^jccd_klhfjgh^pWX`YbiWaecllbijc^jjrnbb^fcohehb^ial_caegbcieddfg\]Lmn`femcUNjZacejf`dgf^]jieTkQXaUfZrZ[][lhhbbiiiYdabb_ejlo`kjeb^WahnU]Zbadfhlmndedga^[hailj;ecle^Ze_hZc`enre]e`bc_iejghkgk^YqimVm_uX^]ddhmkX_hbj\iY[`bW[__hk]j`mYi`eii]t\`_fj]Xc``hdlg`bbdofYccUh[kf\kh]aqlkodcfbf`cjSbnscY_bfcfjddd^ff\e`mcm`dgemdZq^aUaTl]ccbccccccccccdccccccccccbbbcccbccccccccccccccccdccccccccccccbccccdccccccccccdcccdcccccccccccccccccccccccccdccccddcccccccccccccccccccccccccccbcdcccccccccccdccdccccddcccccccccccccbccccccccccdcccccccccdccccccccccccccccccdcdcccccccbccccccbdccccccdcccdcccbccbccjg\aab`r_Xqclcllpcqhgcge^b\iqcRie`QXd\hlh\Saj[thnlfY^fgkiijX^XZ_hXUdlbcfock]abXie^\do[fajf`okeigladmjcjdZOeiWod`igepbanl`oYZS\^cqbpnhpiXll_pii\q\jYWloQkkj`kfReOiq]gscjeZfckflhb`\ephdS_cl\\iWbnh`fh[ec^[_ggxfs\iegddghbQlj_adjb`hUmmahc^`\[q_[BUqibiefegftblW]i^biY\e\dccjk^dlchfd]vdijabbqk_][_Z`_vckaeho_gg]Z_Us^`ane_ogg\bfhgdn]f[mdbpaYqkbi\fh[eagZp[Yhaj]cijod\g\eXqtagndicfdjhdY]`i^p]Z`rg]>hmff^eeeWhZ_ie^dT_eiejc`^haa_cfTdccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccbccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccbccccccccccccccccccccccccccccccdcccccccccccccdcbdccccccccccccccccccdcdcccccdccccccccdccccccdcccccccdccccccccccdcccdcccccdcccccccdccccccdcccccdcccccccdcccccccccddcccccccccccccccdcbccccdccdccccbcdcccccccccccdccccdcdccccccdccccddccccccccccdcccccdcccccccccdccccccdccddccccccccccdccccccEYe]gsecWg`W]obifj`e]g`Gg`Yffoe`\i^gjfYVgabXa[odab\gqc\mer^h^\U`k\eimorja`bkj\b`o_[\jp`a\m^geaSd[^lf`^j\fYnnhhgfcffgvch]QYaiamdabcYnjTicpoReq`cU[rrkg\[b^cgc[_d`\yYbWk]bkd`X]fi[glge\c]b_a\l\]k]Pddfgf_hkikiiidcZhl\nlaeahidm``et^]`t;hnbjhejffr^ac_dQZgQ_ch\ec]f^ombd[dYcRccifrZcafbh^qgpg\aoiUlchh[dn`nl`j]lW`aca_p:]]g^[ha[`R]_igffZ_Ye]bfj`kS_W_ojada^[h^Vaek_UUphhe`j_el__dk^hi_g`^_cPVhdjTd_adgjiddtnbilfiXeZfanXi`_djcf^\m]dadjcjajgbgafil`gaa]mgdkmgghhT^ppelb`cb[ebc_jib`bdbYlh^]gg]aj^i_]e[njXbXNd]g_^khad_e]feccbhmdaddebb\cecbede_`cgdbfhdbgbcecdacbdfddcdadbefbceccdeecafccabbcddbdc`dcdbahad`abg_ccebeeebdaccbdf``aecddefcdcdbefgcbgbdfead_cbaacagbdddbbdeccebafbccb_cbedebbedbeddbdc``geefggbcedeb_fccbfgcadceeddfbabdcdcbbeecdcbhdccedabebcgac``hbdccdbdeeechcfffcfcgeedfcadbecdccbcbccdcbdcccccccccbcccccdcccbcbccccccccccccbcccccccccccccccccccccbccccccdcccdccccccccccccccccccccccccdcccbcccdccccccccbcbcccccccccccbcdcccccccddcdcccccccccccdbdcccccdcccccccdcccccccbcccccccccccccccdcccccccccccccccccdcccccccddccbccccbbccdcccdccccccccbcccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccdcccccccdccdccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccdcccccccccccccccccccccccccdcccccccccccccccccccccccbcccccccccbbccccccdcccccdcdcccccccccccddcccccccbdcccccccccccccdcccdcccccdccdccccccccccccccccccccccccccccccccccccccccdbcddccdcccbc`qmgaZbrd_heaefdi\bfamdZcb^d]hk]\`gfdZcbYfadaffajabcWdYhid]bbh`fa^hi^mTdbgg]i_bghc`]dYebagbmd_Aj_ddbhb_ee[bYkgcej`d_ndeV]mhj\id^cdkefof^n`qd\]e^ci[ebdbd_\bgd_hge`\^jgl_aU^h_d[h\gR\^]lbafaleln[b^gd]ejW^adfhV^`hg]ctejbhclmdgkjhebfcWd`jfafm^eedgh_cb`\khfghbdflhdepm`fX`]a^aZihaaVbgbZbah_o[i`hb_bjb[dcp`g^cdddiZffgZa]`^ih``^`_ib_aX[mcQ_abchhe_`gk`h[aeeekfc_baab_[igigheSZ_kgfh_acl[gb[b]ocdfk`aghcg\a__bdefr^d[[bghag_[]l`gjXcmjobe]cdfbdgjccfbegVdihlie\^ho_c[ddd_WddebaTgd^if\fmdah\\\c`mcgkefejf]s]gfal]dea^cb^cdcojhlccdcccddddccdddcccccdccbcdcdccdcbcdcddccccccdccdcdccccccccccdcdbccccccccccccdcdcccddccdddccddcdcdcdcdddcdccccccdccdcddcdbccbcccddccccccccdbcdcccddcdcdcccccbcccddcdccdcddccdccccccdccccccdcdcccdccccccddcdccdcccdcdcccdccbcccccdccbdcdccdcddccbccccccbcbccdcccccbcccccccccccccccccccbcccbcbcccccccccccccccccccbccccbcccbcccccccbccccccbccccccccccccccccdcccccccccccccccccccccdccbccccccccccbbccccccccccbcccccccccccccccccbcccccccccccccccbccccccccbccccccccccccccccbccccdcccccccccccccbcccccccccbcccccccccbccccccccdccccccccdccccQk\k_]hcm]\a]hk[khe_c]`[mlcWhmknacdda\eidWZ]`ohhje[d^gffd`f^dbkYbadchogdZg^k^VhbVj_hjdcXTj[Yhkdi\Ybhimflgb]]fYbiiaeeq\abbXZ`[iflgd^i__U^m^Zhu`fkan^lkdcnW`fefgbl^aWd_fbi]YZl[cdgjjhc]jWigVc_geruflg\d_[a^bddif`m`iqgl^fblcqaijoYneiak_febfelhodh_deh^Zbec^ghNYhTfajinUM`NMe`cWefhj]amhfnW^clrpfUw^oek^[lWgfhe^_ba_liY\\dka\ibjTNhbaoc`af\jhpY^kjYZ[alvZgV`_ktXScZOkq^op\^XT`YfQcldcikag\cocpcrZV`j[kiZnenb_cadecZbVhBebho\jefhn^_cV\Sncdkl^[\Wjibl]dhdghd\``[_a^rPehhiiV`ck_jb_dy]foofo_o\qb_diioapfgYbliafb_^gihcf[gledYlabosVbdcddbcddccbbcdbcdcccbcdccccdddcccdddddbdcccbccccddccdcdcbcccccdcceccccdcccdbeccbcdcccccccdcdcdccddccccbdbdcdcccbdbdcbdcddcecdcccddcdbccbccdbbdccdcceddccbdcdcdccdddcdbcdcbbadacdccccccdceddbcccddcbdccddcccccdbdcdccecccccdcbedcccddcbdccbcccbddddeb`dbdbddcbddafR]ckZd_W[a\l`dfd`]Rhg\gkqYrjk_[l^Wcd^jVjliToa`[c^mijhcZdY`gkg_ffdhbubhr^jXk^iiaqkdelq^dgc\naR_[b[fkfcec^hbl^keiSbamegcXUegU]df[gac]dKknbh`^[j_^dh^d]W^Wdgebi[X^jmTlpeciph\^i`jkkpjf`h_i_c[f\Y_e`^h\pjggldiZdgd[kms\flfh[acbjeaZb\`mZ\`ge`hiieekgcbaafileXkhceb]cccccccccccccccbbccccccccccccccccccccccccccccbccccccccbcccccccccccccccccccccccccccccccccccccccccbccccccccccccccdccccccccccccccccccccccccccccccccccccccccccccbcccccccccbcccccccccdccccccccccccccccccdccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccYZ]jsogjYVfi`_Wbcg`hmdRgc`]lffaf`]adfddegacicljkk_`[fVihj]ihb`g_ldadeTYf[g\fgd[a]h^dqo`_gff\ginJghkcdd`gSkUmbeZeTfZkfTcghd`]jnec`eba^a_i[f`eaokig_dg`_baf^ge_l`g]^`]b`fcfdlhyfcqldm_g]daX_g]dagdlZga^]abgadnX]\jUieibba\T`V]igf^W^[i_fld\N^e^cacc_Sefg^bdh^^bfjghfmfjm]hajanW\e[jcbf_jc^^Y\mgV`bZa^j`em_f\g^cgXl\g`f`jlne^bilibohjjf_rdfg^hfcfa^h[gelcbjgilec_bpfd_NiX^lbni]^Vhf[gmfna^di\ig^cfdebdb]``[_ncbak`ZXdd^`oaY[gaggiYb_m^Vbc]_h\aUdfpklW^cV\bab\idedfZd\e`kRfa_jcab_c]igipb`fYchgajdYXfehgehmWke_ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccbccccccbccccccccbacdebbcdbbdbeadcefbdecacddccbdbcce_adcbdbccdedcbcbfbcdddcbccdcfccccbfacadcecedce_ccbcaegddbcaaccdebfc`cddecdfdddddbdbcddbcfaedafccabacdcbccdcceedcbc`dc`ebbcbebbcbfbbdbbcdbccccedeaebdeceacdcccdbbcdadddcccabbebbddbbbedaedcddbccdbdbecacacbddaccbbbccccdbcbcdccccbccccbccccdccbcccccdccccddccccccccccddccdcdcccccccbcccccdcccddccccccccccccdcccccccbbccccbcbcccbcccdcdccccbbcbcccccddcbcccccccccccdcccccdccccbcccbccadccccdcccbbbcccdcccccccdcbcdccccccbcccdcccccbcccdccdccccccccccccccccccccccccbcccccbcbcdcdcccccccbccccdccbbccdbccccdcdcbcccbcccbcbcbbcdcbcccccbcbccbcbccccbccdbdcccccccccccccccccbdccadcccccbcccccccdcdccdcccccdbcbbccccdccccccccbccccccccacccbcccbccdccdcbcccccdccccbbcccbcccccccccbcccbccccdbcbbccbdbcdcccbdcccbbcbbbcccbccccbccccccbcdbcccbddbccccdcccbcccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccdcccccccccccccccccccccccccccccccccccdcccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccbcccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc_bXQbjkhZcbda]hbihab`fW\YdcYo^Sfg^iseZhe_Vc7[^_ia_a_^V[\\[_gabeedkfZ_gid[]^j_Yc_\lb^\gdTVaffu`fbn[chebgf_gblgd]hkh[g_ddfd`Zg^_l^b]]gsU\Yga[ahmoi^awddgekabW]ej\meed\ak\^dd`Z]dYflcc]lgZkfgdpgf]rdoa[bp[ahe[mcfZfc`Xhkcbfi`b_\]d]kbjhfbij_i[cfhd]p_Zbk`ehjf_fX\ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc`c`deaccb`f`ddee_dcfacebc`afdccdb\_fa`fgbddcccea_`d^c`e`cfcdcdaadca`bh`ggbdcbbfccedbcbdbbaecdaabb`dddedc_c`edbabffeccebbdebccdheb_chddcedbfd`a`acddb]cb`bbced_`ddcacdaacaddk`hfcdcaecbaeafdcaddbaaaab_`bcagcbaef]dabdac_bh`dcddefacbbddbbcebbdbcaccgdcacbadeccgacdccccdccddccdcdccccbdccccdddcccdccbdcdcccccccdcbcccdcbcbccdcdcccdccbcccdbccddbdccdcdccccdcdddcdcdcccccccdccccddddcccccdddbccccccbdccdccddccbddcddbdbccdbbccccccccccddcdccdcccccdccccccbccccccdcbdccdcdcdddcccccccccdccbccdccdcddcdcccccccbccbdcdcdcccbccdcbcdccXYQ\ekgf^edffcacfiocc^egZeeb^^\`Y^[ax`cWSqakkfe[g^efocmg`dadbjc^aUrn`bffkccgc\\bccnjb^[^gfmgY[hhincaegbcZ_`lcZmajl^i__eX\fgogWqf`]gh`abh\cpgagVdfbm_eebdea_^c_hhibi`jc`dlifhedn\f]c\jjhll\]XgpcfaU]Wjd[j\_dabdabTdfkYih[ra`cZglhce]cbl^reba\niax_f`dcjfaibcd\\kcaUXOacd]b_bb`d^hdh`_pZkjdSbpich_lrbm^reZ]_mc^flgpglib]bkbcZc]e_lihcjdmma[bj_lsd]khfhfra]d\f\][ndhkaah`egd\`\ZheginkVehdfZ^k`a^]lmbZcc_c_ah;_db]dZeiiR\_`]hdfeck\hkm`[fd]kiTe``_e]ckcg`_ZXkegomb_ab_^oambjicdmidena]]dgWdcaaa_Y_jmb`_t[hoge`klYgiikgh^b[l^Xad`Xega`fbdfgfcddc_agdacfcb`fdcagddcb_aedb`_cdddcd]aab]]`__ea^fbacbef_aicdabadcdckg_bacdfjgd_a]fa_dfa^eedc^eff_cgcf`a`gfacbb`afa_b`gecfdfd_db^d\hccgdbdagc\b`bgefeg_dcdgdcbjeedaehcfebdbcdc_caceabafacgacad``cdegbbaad^bedebcaba^ecghbcagebce_dfi]agabdefbdca`dfbabcdfcccccccccccccccccccccccccccccccccccccccccccccccccccccccdccccccccccccccccccccccdccccccccccccccccccccccccccccccccccdccccccccccccccccccccccdccccccccccccccccccccccccccccccdccccccccccccccccccdcccccdcccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc[c[`]^jcc_ikhdf_`blga\ifkfdYf\Y]a^ccZ^[[qq`ml_dcfo_pbgb^]ucikgWbggbhXjh_cmcZgebVdS^cijdifdaYeqmihdc[`febg\bWmah`d^]Wg`gac]eabkeel^a`ccf_h_Wddd_g\pdbeebegadnYdnf`idcc]jwfj]j]addNien[^cfd\^aZ_hf_^cZj]dcmd]icleYjhcccqnj]]_eadcdcd`Xc`Vh_hXhdai`ncdide``kfikdYb^dcagYhl_ZdXaeXd_iffcjhnlbmre`ajdbo`Uid_bbhkQab`]lY_Xn^]_^g_jk^cgecdRfkcagg[gahYf^ga^oYYcdde`bUPhaaifhefZc_Whg^fd__ae^d`^cq^__WeYVaibgh^dZi]kRe_dgk_`Vc^eg\ga^kf]e]gj^lWm[haXaU_l`hdafcafgfwTgdj`lddf]`UnhaZckc^_`Ye]n\pf__bqick`a]apiiij__g^adia_sa]aieYd]^\ad^cdcbdccddcdcccdddccbccacccccccccccccbcbcccccccedbdcccdcccccdcdccdbdccccdcbcbbddcccccbcddbccccddbcdcccccdccccdddccccccdddcdccdccccccbbccccccbccccdcdcccddcccccbcccdcccccdcdcbcccddbccccbcccccccdddcddcccdccdcddcdcbcccdccccceccccdcdddcccbcccecdcccdebcccccbcdcccXbjY]jchmUdmjecgiba^nRgacti_\e^Nc[ajbZap_bm`j_YdUbgO[ai\d]r[`d\LdWhdvaahi^oqk`g^poYaV]a]fmdZfgOZ__hgWX_`Yae]bzje[^\c`g[\bncn`_^`gj^cdhgefd]g\d_nhjij__bZfcbo_Zh_an[j\hfjifnhcad`kVW_gfk[b_q\_nbddVgZZeeddnfbhleafelcjejk^fY^cZa__kegXggumbt[ns`i\brfgc]`kebeSYchdg]hShhb_fmb`cfZeelhc^bfk[sP\aii[ihhbb_cbZflic_iai^_in`bfknadlXk^njWci`_[b]^galYig_\caiicc`^[mgYbgbgd`__dg^gdhof]geem_je`]a^`cdiq_i\g\_g_bXg_ccig`jglgf]ij]ggg]bhg_abe_ljd`hh^gde]a_jmYc^QYZekoukk[ck_]add\`ddVnglcYikV]dd_mh^Sd]eZeami`be^hlcfma\faac`edbm^ZgfcccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccbccccccccccccccbbccccccccbccbccccccccccdccccccccccccccccbbcccccbcccccccccccccccccccccccccbccccccccccccccbccccccccccccccbcccccbccccccccccccccccccccccccccccccccbccccccccccccccccbcccbccbcccccccccccccccccdbcccccccccbcccccccccccccbccccccccccdcccccccccbccccbcccccccdbcbcccccccccccccccdcccccccccccccccbdcccdcccccccccbcccccccccbccccccdbcccddcccccccccbccccccccccccccccccdccccccccdcccccccdccbcccccbcbcccccccccccccccccccccccdcdcbccdcccccccccccccbcccccdcccccccdccdcccccccdcbcdccbccdccbcccccccccbccccccccbbccccccdcccbcccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccckcaYcYdo`gbTbbjjh\`ebbfnj^bam`eeb^ojX^dk`d_jemmedhYif[[]d\fbb^\jegdikocaai^Yco`bYf\`\c[chni]fd]mVfZZhd^a`anggVgbjdadfi`f\fQbbfX[idj[YdYU^Ze\cgjdZ^`bda]idfcgi\]\siZWmbmhh\]gc^gf_bfa^ckeeidcbZde\ofdYPdYcqjjdl`W`h[_uXe[[_miaejfoccjY_bgga_bji]d^jmibbbmf\dalgl]bacdbicjbdh_gdk`\`_k^``ahXmac_kfbe]Z]cW`^^\a]_el\Zbcaklb[gdahgjii`na\fe`bUg[Zbf[f_lmYbcdi_q]dj^`[ie`\_fejb^_gc`i_\bd^eedcefld^ca[hY`hab^`XW``dc_ee[gc\c`g[gYn[lbfgacclfobikdahea]h\_gh^c]`[bdca\bg_Z_[^gbjfi^k_n`^\bibjgj\blbaZ_`kcgla[[]aebcd`kZo_\n\\]qdY]eh]dccccccccccccccccccccbcccbbccccbccccccccccccccccccccccccccccccccccccccbccccbcccbccccccccdccbcccccccccccccccccdcdcccccccccccbbcccbccccccccccccccccccbcccccccbcccccccccccccccccccdccccccccccccbccbcccccccccccccccccccccccccbcccccbcccdcccccccccccbcccccccccdcccccccdb^e^hnk[\lrgbgrnc`n[YZvlF`gbc^dacdZe_kj[^oifb]cfjcgpeW_bdVamcggca``ekniZbV`]bZTYi_OQ_fgbjtiYal`w^eY^hnam@eojelS]l`^bWk_a^j``kLZ`[`VfcWf[Tpa]aZql_X_kjjkh\f\bfZlgx\]cehe^[^beeda_`q\i_hdekdkcdifXeXZc^d``ZlXi]_aimfgeheo\hnelh[UXZ\UgV_idUY]tpeflpigej`[mY__ktqfgij`TnbmdiYgbqdlm\ffheaelkekW}kYcnpjkggjYc[\ZdbkdT\\jTfg^g\b`aWX^Ygbdo_eX_gfk]hVcbnbYm]k]_]oeVXhkb`hadj`b[i_ia^SVlhYbe__`pecfpmidiVUbapeh\g_eo\a`V]e^oYocil]d_Mceg]cWbk`f^`]Yaajcc`hb]f_[Raeeg`ZgbfclqgVa[[\gg`c]_gaecohehgai[`ngdfrpVidc^Zbghlds]hX`hcjbn^bkg`]^]]`blib^cgdfhji_h^e_cge_Zeceadfgb]ee^ag_^_ec[ab`bfe]gbVfhgce_i`bfh^jbkbf_f`c_fc^W]ckdc_eZdahkbfef_ffd]dZc]llaegh\_cjdf]a`gdedhc_bYe^idfc_ddabf^dc`bdgidn^n^b^e_]_b`idfcbcj\aafb\febbmhheebd`]`_ic__`dlbecge^fbabccekafecgZa`bdfbd^ead]ej`fh`eekdcjalfage]a__e\hcdde\cabfd[lXcarhf[fgaZg^\hWdhiWbh^hj[_a`gjjdt`ehmfjlhiblgcWdn]cd^Y`gdecg^bewadebi_Zie_mf_beZ`mffggbffp_dfc_`XcHa`e`]ccake]ha_fiXae[ee_k^lg^nZ_d`=e^aa\]fjZcX^`emb^ikadc_^Xfmh`bkg_k^kecj]gkfecjeb^_ecc`cbd_hhkdXfc`i_deikYacmaibkc_egafXdage^a\cWUa[edoXife[e`]b[chjg``ib`abdb^eehqcfiflgk_bffd_cnaZ_jgfig^dcgic^egXd^hebfj`]eaf^g\]ab_dbjfXXce]`ghhd_^m\iif^_bgfYafghaYfeghcfkgdagk`da``hcbfdb_]kcgfd[kafd`]c[cficddc\XYga_ge`^_X\_mg_cdjk_kg[\debcabgf^ai^gc]gaf\oajkdcdea^`ecc^ga^gde\^deZaehegcbhbca^i\ddhe`kee_d^\ih_^dgbigddfc`bfgbcedabbd`b`dd_b`aacaeabbfagfaddbdc_afad`efceab_b_fdcea^_bddaacdbgfdcdgcbjaadbaa`^bffd_cccbdbfecafe_cb`jfaiab`eagc`cfea_cdhbdebchbcbf^bffgc_]caeciagfb]edefff_d_de`ejecddbcc_aeadh^jc`bdddbdghbbjfidicia_cdeaecfdkdbhieecjg`aegdb`cadfb`c^cgebddcdelebecadcbgjj[aee]eecdhfd[i_b[eb]ak]Zacja\r_jeea\l_`ajkbgfqe\kich`cbaeeedgdb]_ccbcd`bf_d__ddc]Ygbfddfkl`igZc_dgc`a`eadf`c^bhdfdbc^X]]baahce_ea]aed_j^`hiccbgd^g]lg`cd`fe`d[\haea\^ebbb_hgbhfehgid^hYcc`ba_bhd[bbdaa__cicfVbbdhfbgba`eei]abacecgaci_g^bciodijda^i]gf`f^bbfbjWgbefgc_hacaebmdhldacd[jbgfiaib_ceac[mgacehd_^i^`ggh_caaemhb\bebecacbehhdgc`aaeidfaf]`fj]b`b_h^kbegfghd`\k\_fcbhdc_b][d`d_jda]e^\]aceeZcZafcfeekid``h]iddcb[efhei_b^Zf`d`bfdj_fhjee`gdcafgcjgc`cahaffcakgd`j_]^cefccajc_^i_`_mb`g^c]Ygcbg\eb_^c_ba^`^^X_e`fcccccddccbcdbebcbdcdcceccaccccbdcddcedbcbcbcabdbcbbcbdbbcabdbbbcddcbbcebccbcdcbbacdccbbbcddccbbdbcbcdbbabceccccdcabccafcdcacdbcecccbccbbcccdbcccbcccdbbbdbcccbccccccbddccccccddcbeddbbbbdddcccdcbadcbaecddcbaccabdbcbdbdbccdcccccbcccdbcbccbccccacbabbccbdcbddcdcdgchkcc`ead\^^bccd`]gbi_aaeadek^ama_bafg\`ib`dbbe^h_^bmk`]bk`ekc_ceea^ajh_^_ebac`gaddc`ceebfb\ae[d^geeccbapl^mkbaeshdc_b_dgbh]dfbia]`cb_bg[jXgc\^a]jbbdYk^^^beYcdfjc`_aece^k_`^ce`_bema`ffc`^dea_akidfghgeaji`\``fba`^[`Zd_bb`[_kfc_`ieaga[aai`fe^ba_dcbdk``acfcccccccbcccdccbbccdccccccbcdcccdcccccdbcccccbccccdddccdccbccbcccbddcbcccccccdccccccdccccccccccbccccccccccccccccdcccdcccddccccccccbdcccccccccdbcccbcdccccdcdcccdcdcdcbcccccccccdccccccccdccccccccdcbcccccccccccdcdcdccccdccdbcdcccccbccbccbccbcdcccdbcccbcdccccccbeae`hd_dfe_aad_daibdc_befcaffad_cfdeccacdbbbhahbagcdf`beeibbegbd_dcebfefgda]afffcj`accedbgebafa^daffdacbb_afcbfad_fbbafce`cdbafg`ccachf``e\bh_cccfbehhb^`aa`bcdfbbecafbdababdc`cdbcebb_caeafebbc^imdcefd_bdcccbe`a`adaac_eeh^gcebbbed^bd^_cd_fccceb`eef`dbfdbb`cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccdcccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccdcccccc`^[Ykzd`gc__efi`_`]dd_gccefgaa]`_ia[_jdldeg`hbhgd`igecb^__f^_`dch`ecZcbbf`h`Yef`a]lp_`jacZhaig\dcdck]e`di`h\fef^db^Xbaf``\Zig^c]^lXec`]hk]dbbh^[a]fa_\ccnSoWma`Xaeebbkakcdceala\_cfXijae^e`hldf[`b`[ccclkf`kdh^dabacd^ej`e^iZ__gfdbddr[`^bbajaeh`g`iib^^g`Z]bbmgcccccccccccccccccccbccccccccccccdccccdccccccdcccccccdcccccccccccccccccccccccccccccccccccccccccdcccccccccdccccccccccccccccdcccbccccccccccccccccccccccccccccccccccccccccccddccccccccccccccccccccccccccccccccccccccccccdccccccccccccccccccccccccccccccccdccccccdcccccbcccccccccccccccccccbccccdcdccbccccdcdcccdcccccccccccccccdccccccccdccccddccccddcccccdcdcccccdccdcccccdcdccccddcdcccccccccddcccdccdcccccccccccccccdccccdccdcdcdcddccccccccccccdccccdcccbdccdccccddcccccccccbccccccccccccdcccccccccccdccccbcdcccccccbcbdccdccccbdddcdcccbbdccccddccdccbdcdccdaedccdcdcbcccddccddcccdecccdccddccedccdccddddddccddcdbcdccddcdcdbccdcdddcddcdcdddddddcdebbececcccdedcdcdddccccbdbcdccdccdccccbccddddecdcbdedddcdccdbccbdcddddcdddddccecccdcddcccddbdcbbdccdbddccddcdcdccbcccddddccdbccdaccccdcdcddacfegb\jdc]dngibjgajbccce^_jjcf^ifedbfcbmaiiafd]k_cbZ]heeaeaf_hgcagoabgceddZe\bg`[adc`]c`aZecgd[_iibdfbf\]^h^ebb`[hedcd\f]ea_ceh```bg[h_bab]^dc\bdef`]ai`e\lb_g\c__``_kbff_m^`begdgbheh^]e_``cdW^cb_ehf`Z`akb`_j^hZk^]afYkdh^f\ic^g^`lfafccbc_kec_`fgicbcbe\fiebe^eeedbc\b]dhahecded^ah\_aa]gch`]^kcfafcZa]b\`bba_hkkbab\cbchffc_bcccbcg[ccece^flgiiejg\ebccgfZd\ahcce``jZd`Wca_dh]eca\bbijYia]bkgZh_jhd`gb^bgjfa`bdi`adelfamd^ddheg_ag^bYbc^`^gb_h]biVh`ggchgfdeddhhkfe_dtcheec\hYe\Zf_k[kd_fgb^dbd^a]hh^bicf`fe_^aZbbgffbd`Tdjddecacabdbbccddedbbcdbbefccdccefecccacccdabc_bdecbgabcbbdfbfbbcdedccdbbeccbaeadbbebcdaddabbccdcdbabdcadcbaabbdbbdcecccbccbbbddcbcefbbbcdcccabddecbccbccbc`aeaf`caccbcaaefccbcaace`ad`deeccbbcdbbcedbeedcbccccbfcecbcccecaedcdedabebcdccbca`adedcaeceeddeacbbaeaedeigdfddakfb_hbfcgjd`egedfgacd\ik`da_a`ba_cg^hbcec_^f_c_ehaadic`jeka`bb[eaj[`d_^g^_dYf`b^Zf_djab^cajeZbab`ababbhlg^_^fcdjbacc_e`debi^hbe`e^h`bbcbb_]_`[db^bc``[dcih\g\`cW`Z_fe`fajfeb`kclbcaec]`g^`ebfg^bbhfcf[fj]f`_daach`hg_a_hfahg`cedgk`]`[afcmqZbgaadicba`d^`caS]g\d^f__keccfYjgg_`hbeeiald]eia`cdcchdad^^lbbecac_`jcd`][]]efq]iedkddeaaag`faghd[ae_]g^eaef[a\cecec\dYdgmc^hek`iaa`fcglde_^bmX`ga`f`acabahaachcobafb]cj^[ad`hcbc[[]anehd_`jbahabbej_`bhXmbjZabdhdZecdjdfc]`eheg^abbdcX`hiafcg_icm^e^ciabid\ibg\fe]]hgfcb_Wfgdgf_]eebabd`eic]fcgaf``edaaeada^_dbef`efedcaabhace`hb^efjc`d_edibc]a__ead^g\fe\a[idacgdbac_caddi`a^j`cjfh`\e[ldjg_^Y]eflagddg`bgj_gde_]big`egic``[ahcceal]d]\ffhj]gib]a`dh_f`ddd^gj]_j_hd`cbfbc]ebcegbacc\hcc_fbheh_kibhi\\m^eehbbd_gf]cmibef_fiefd[bbdbcg_daf^]cdcccbccbbccccbcdcccbcccbccccccbcccbccccdcdcdccccbbbccbbcccccccdcdccdbccddcccbcccccccccccdcccbccccccbcccdccdacccccccbccccccbcdccddccccccdcccbccbccdbcbccdcdcdbbbccccddcccccbccccdbddcdccccccccbcdccbbbcccbccccccccddccccccccbbcccdccbccccccccbbccdccbcccccbccdccccccccccccccdcccdccbdcccccbdcccdccdcddcdccccccccdccdddbdccdcccccccddcccdcccccccccccccddcccccdcddcdcdcccdcccdcdcdccccdccccdcdccddccdcccccccccccdccccccccccccccccccccdccccddcccbdcccdccdcccccdccccdccccccccdcccdcccdccccccccdccccdccccdcccccbdccccccccccccccccdcccgZfdabd`dgijdksbcijda`ae]``l`c\agkhehfbd\a_]]`]\pnre^[tcYqT_dbb\i`Xchhsi\^eQW_mcpcadf_deaXh_Xhkn^_YfzZ_Zce`QU\ZRknWmo_e]k]iea]_`gc_jf`\dY_`dahif_aS_ejgdoeg[ba`]YZt]heigcghfg[^\ek_[Wpi`ijbjcVXemd``fk`\iiaYekkafrXdpobbe`kbcaMe^a[fYVqPg_^a\mi_cRtkj_cOg_gch^odfecb`dcacdiagccchbceefcceeaceeb`gebf_ceeacccef`cfccedebabebbcc`cccfcdffcbbdcfefaddbdfcbaaabffdddbacddcbcebaccc]fcbabccdccecdfbf_eda`eccecadcbbbbaa_e`ccebbcfbfbdabcghgcceeb`bbabgbdbdcebdde_cdfdd^aedfafbddadbeeaebdccdcdb`gdcbc`dddecdecc^`eecdbfbfbcbbcafhc`c_c_i\hdfjcglbfjc[daa_gae[_gahgb_geac`gbc``_f\[fjcfa]agf[cgdd_eebd`egafbb_dc_`hddgd_f_aiee`l]_cjd_iedbccidccaie`eeiib_debfh`f`a^f^_\_fiaabc\b`dfdcY_ccfgcj`fgicegbbga_fekXfbdabjg_`bacdeedee`jadchd^f\ae`emdg^hcgi`aci\ea_kaddh[`bagaadgcb`bfff`e_adfdea_ffe`dd^c`acbfbcf``ageceddf_fece`cdmedefah]fgcbjcfblcdX^`_ddcg^ifc[`j\_aff[cecbgcbZnedj`a]`cecfg`iea`jdcekee`hg___ediecb_dmbkeba`a`^abg`d`c]cbhaffdaa]d`cgibgbjgaYbejacdbccj\dhdfcljgcf_cadga`cdgcfecdlbd_f_`dfk^gdca[a]ed`^ca`ff_f]d`]`e`bbd]eb_^Xb_cgabehffccbf_hb_ga_hdcgaddbbffiadd`ffa`acd^aceejfbcbhc_ab_ddgeh\hdcdc``fdc]adecec`fb`fcdafbac^eabbeg`d`edee\e_`dfe`addhb[`d_^ddbf^did_hceaabedaaeed`_de`bcb``ad`figecmecdccaaadddeaaeeabdeecfcdaeea`f`cbdiecde]bb``ahbd_iacdbeigibhgadechbgeiadcffejdhd_cdgbagjcachceijbdd`^fad`edc^ccbbcdceafcbbccbebbbebceecdbcbabdceebbcddccddddecdabcebch`efebbdbcccecccefcdcbfcbbdcecbcbeeadbcccdacbdcdaebddacecbfddbdcbd`bceccedccaddeeefbebbdchcfbcdcdd`fbadcccddcbbecdaadbdecccecdedbfbdcccdacbcfcdddadcedcbadddcbcbccbbcededfec`dfabcd`dfdbdfebacfeaeddbaebibbab]adcceddbefebec`c^be\a_a`jbffbdbecgfcd_ai`i_fcbbffgifcbb`agchdeebc`befcbbbejgfaehfa]]dbbbca_ga_a_ded_cghbc`bcdofabfbejgacdahfa`dcfa_c_edaeedidg`cef[acaagecebaaedaacacgea`e^e__aah^aa^d^c__hddbbbcbaefcdga_abcdbdd`dh`befa^dfcg^]gfcbbea^`bbf`dcmebe`ide_dedbehldbffaeh^baddg]ffif`cd\\m]oladdejaf]eeodhf`bhda\ic^fd]d``hfhcagchd]]^_cciaXcbbddca^egabc[\jba`j`afhhg[affgcU^a[Yaggga_Y[bhfc^b`_e_fja[]bgl^a`Ocdddhhhge^`[cljdbcel_`\dXefchc[difk\bnhghh^`[eZfaajdgcf_c]d^b\eo\`k_a^bcfd]Yakh[_fagWcgaf_f`d_[rbZna^ehc_hcmg_ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccae^]YdcamfabV`e_`^db^[ag`d\iflha`\`eYdbeQb`aidbdaWcb`dm[Zgn^bmeb``bbb`iafZibaVbaebpf]ddng`ng]d]cVebkZ]`d^i^ddfh_adc\alec`qgg\g[ebicibggg\^Whgq]ecWgadc__lchdhjid``]aPf\`afdb]cbad\_dlegee_Zag^ZVb^bjd_`\ck`eaogo\]hfbhr^hbjlfgfhg]_YhgajcddcgYfjae_]ml^fhcbb`dbccddecdbcccccccddddcccdccdbcdcdcceccddcccccbccdbdddbcdcecbcccbcccbbddbccbddbcdcdbddeccdccbcddccccceccdcccccccccccdccccbdccddddacbcbddccdcccbcdcdccdbdbccdecbdbcdcdccddccdddbbbbccedbddddbcbcdcccdbcccdcccdcbccccccaccddccbdcddcccdccddbdcacadddccdcbbaccebcdcbddacadbdecedbccdcccddbdeddcdbbdccbdccdddcbbcccccbdbeccccdddbddccbcddbcddccccccccbdcdcdececdbcbcbcddbdbcdcddccdcbccbbdcbccddbbbcdbddbcbcccccdccdccccccccecddddbbcbcccdcbbdddedceddbddbddcdcccddcccbcbcdcdccdcccbccecddcccbccdecdbcbddcbddccccbccdccddccdbcdcbdcccbbca\cgd^``_aj]fcYabb^egbnglgb]j^eh_cn`]_gebb^gg]c]f_bhcaggka_h^Zebca^gcfjjcedfa_ee_b^acla]c`c[kgg\ca^_di]`\e^gdddr]hljj]ahfd^a`giYld]ibXi\^d_db^^aa{_m^ghi\egcfgdhYanke]d`i^k\gdcfab]ga`iedia[cbedcfc^keegeYf\iebdoec`dabdb`^hbceedce_gcfZccjafmbhba[m\bfYeeef\bjbccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccbbbccccccdccccccccccccccbcccbcccccbccccccccccccccccbcccdcccccbcccdcccccbcdccdcccccccbcccccbbcccccdcccccccbcccccddcccbccbcbcccbccdbcccdbcbdccccbcbccccccccdcccdccccddccccccccccccdccdcdccccccdcccccccdcccbcccccdcccdbcccbccccccccccccdccccbcccccbcbccccbdccccbcbcccccccccddccbdcccccdbcbccccdccccbccdccccccbcdccccbccccccccdcccccccccccdbccdcccdcccccccccdcdccccccccddcccccbccccdddcddccccccccbbdcbcccccccccccbcbbccccccbccbdcdcdccccbccdcbcdcbdccccccccccccccddccccdccddcdccccccccccddccbdbcccdcccbccccccccdccccccccbccdccccbcdcccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccadiaebcb_dc_kd`ea\]c`afc^`_fddd_fcfhabaac_gahde]gb`hac`qaaca_ag_e`f]_babcbeece^d^bbaiaebeg_gbbbdcagebcbcecbdbfej`dcc`dbead`bibd_a_gddaedbh`_a`\chbcdd`ccba`cbdb`e^ddca__aecjaggbehdaa`bhbgdd]`_a^d^hdc`ebafeabadbgc[]c^cbfff_bieibdbc^addgb`__f`abadd`bcbfda_ece``ddecddcdae\caadhfebbeccgaccdddbc_c_eg_effcdcabacaeaababfcb`cb__dai`ce_fbcbe]b]b``e`bjb^d]b`cbbcaafdgc\dcdccfc^]abccbdfcd^fiagbbccb`bhda`aec`_adcadcbcfg_gaedchbffafeceghag`cadb_acfbcccca_bfbbdacde^^ceaaaded_e^efaZccabeedif`cbcfeaaaccbfig_bf_fbeai`ifbei_akbccccbcbbccbcbcbbccdbcccdbbbbccccbcccbbccbccbcccccbcbcccccbbacccdccbbbacccbcbbdccbcdcbcbcccbbbbcccbccbbcbcccdccbcbbeccccbcdcccbbccccccccbccbccccbbcbcbcbbccbbccbbcccdbcbbddccbcbccbbcdcbbbccccccbbbccbcbbbcbbcbcccbcccbccccdcdbbcccbccbccccbcbbbcccddcdcccbcccddccccccccdccccbcccccccccccdcccccccccccdcccdcccccccccccccbcccccccccbdccccccccccccccccdccdbcdccdddcccccccccddccdcccccccccccccccdcccccccccccccccdcdccccccccccccccccdcdccccccccccccccccccccccccccdcccccccccddddccccddccccccccccccccdcccdddccdcccccbcdccccccbcccccdcccfcdb^\^g^d`i_\_`bba`igfidgbcgrcmccicXecab`hdk_`\ei^hjf[hd]kf^ah[_deiZb^`Ycabjj_c_c^njZaYjec`hbcbiafe^a`UmegfbgeiXn_d_`^aY]mggaefccggZgd\daei\ed^`cab^jgg^`gbffWla]bg`g]bddlbagabfYladZbc\cahb\g]ckcbic_dchfgb]cfjgdf^_bclca^df_i^bd]fhbXhag]efc_e`eknfdbbgdfij_igd`e`db`bi``]^daeb_[diaecjefeeY\bh^fcg_`^_Zbdhea[jpef`hb]`ag^``a_cdheeg`bkdVafefeebcgbbddbdg`dc`cb]e_g\__cebckdij_fagcb_fmfce^_^`dh`ccfedbacepb^_ace`dcc_obc_a^balbd[[cfeec]f]baiiXhbbdY[bfef_jm`\hgcbeiamddgkh^bZ_cigd^_```ieaaibecc`habg`dd[_fc`a_c`hed_ideb\^cccbcccccbccdccdbbdcccbcccccdcccdcbccccccdcddccccccdddcccdcccccccdcccccccdddcbcccccdccccbcdcccccccdcccbccccddccdcdcccdccdcdcccdcbcccccdcbcccbcccdcdcaccccccdddccccbcccddcccdbbcbbccbcbcccccbdcbcdcdccbcdccbcbcbdcbbdcccdccccdcdccbcdcccccbbdccdcbccccddccdcccddcgc^g\h`blab`cc]`gZbfc_fdb`heb`ZaddZfeac_kgc_ehh`b`q^]bab_hhc^bhj`b`fedfgbdhc`ecc_ecg^`fhca^ddefbh`cebhiceYgepgb_]k`h`^e`afei^bb^c``agihiiid`bjhcd[hh`ek[Xbo^\aeca[bdb`bcg_i_`djgfjcdcb]`d\bb`bafcdejfbhffga`g\bhf\ddac`fidXej[^aa^f]bd__`d^bh`bb_l\il`dhdjagbd\hcccccccccccccccccccccccccbbccbccccdccccdccccccbcccdccccccbcccccccccccccccccccccbcccccccccccccdcdcccccccccccccccccccccccccdccccbccccdcccccccbccccccccccdcdcccccccccccbccbcccccccccccdccccdccbcccccccdccdccccccccccccccccccccccccccccccbccdcccdbccccccccdcccccccdccccbcccccbbcccccccccccccccccccbcccccccbcccbcbccdcbcccbcbcbccccbcdccccccccccdcccccccccccccccccbcbccccccccccbcccccccccccccccccccccccccdccccccdcbccccccccbcdcdcccccccbcbbcccccbccbcccbccccdcccccccccccccccbccccccccbbbcdcccbccccccccccbbbcccccccccccbcbcccccbccccccdfcebacbddcecebdadcdbdcdcdddbdecedcbcbbcbceeebebbccddbccbcdccddebbcb`ddbdbecbebecbbdaccddcbcdbcfbbecdccdbbccecdfcebfbdccbdbebcbdaaccddcdeceec`dcdcddebbccbbcbdccebcdccbgcddbcaddcacccdddccdddbbacdbddddcccddbcbddbdccbededccddcccbdedcbbccbbaeccebaebebdee`bddbcccccccccccccccccccccdccccccccccbcccdccccccccccccccccccddccccccccccccdcccccccddcccdcccccccccdccccccccdcccbcccccbccbcbcdcccccccccccccccccccccccccdccccccccccccccccccccbccdccccccccccccccdccccccccccdcccccbcccccccdcccccccccdcccdccccccccccccccccccccdcdcccccccbcccccccccccccccccccccccccccccccccccccdcccccccccccccdcddccccccdccccccccccccccccccccccccccccccccccccccccdcccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccdcccccccccccccccccdcccccccccccccccccccccccccccccccccccccccccccbdccdccccdcdbcccccccdbcccddccdccddccccccdcdddccddcdcddcccccbccccbcddccccccdccccdccccbcccdbcccdcdcdccdcdcccddcccddcdcccddcccccccdddddcdcccdcccdcccddbdddcccbddcccccdcccdcddcdddcccccccdccdccccccdccccdcdcdcdccccccdccdccccdddccccccccccccccccdcdcbccccbbccccdcdcd`f`kcccedbc``debac_fibabe`]g]dlhjja`icfea`eaci`k^eac\^k\_behgehdag_bhaeeiacf_c_k]affgbcicaahcabbc`a]cfeb_ae^`jhe`]`ia^`calcged`fcfdd`g`_adeaeacbg_]bacbc^j^g^dcfd^ac^bcbcbcbb_abha_ijjgbcjec_\f__fcef_gbYgceb\gceacbab^_]cd_adacaakbe_gcbedbbfccb`d`^cbfa^cbgghcebd`gaebccedhbf`bbdb`adacad`caededbdb`edebdbd``afcbecbbdcbb`dbaab`acddgecce`cgbcag`efcf`bcacddbeedcbdcf`decdbchcchdfdbf`bccfbbdae`cbfadd`eafebcbebdcacbfebecbdfcbdeedbbcbcab`cebgaeccb`daafbbeaddcegccafdcbcgdcacecdcbfdebcgfccddcagegccdacchcebdabcehbebefcbbb_erVoTgYS]igqorWWl_idcodkdOal]`gigXH[[e\hbgekljbdpcccccbccccccccccccccbcbccbccccccccccccccccccccbdcccdcbcccccccccdccccccccccccccccdccccccccccccccccccccccbcccccccccdcccccbccdccccbccccdccccccccccccbccccccdcccccccccccccccccccccccccccccdcccccdccccccccccbcccccccbcccbccccbccccbccccccccccbcbdccccccbcbccdccccccccccccdccccdcccccccccccccccccdccdccdcccccccccccccccccccccccdcccccccccccccdcccbccccccccccccccccccccccdcdcccbcdccccccccdccccccdcccccccccccbcccccccccccccccccdccccccccccccccccccdcccccccccccccccccccccccdcccccccccccccccccccddccccccccccccccdcccccccccccdcccccccdbcccdccccccccccccbccbcccccccccccccccdddcccccccccddcccccdcddccccccccdcccccccccdccccbccccccccccccdcccccccccccccccccccbccccccccccccdcccccccccccdccccccbccccccccdcccdccccccccccccdccccdccccccccccccccccdcccccccdccccdcdccccccccdcccccccbcbccdccdccdccccdcccbcccccccccccc`]abekkh\`k`bb]`c_ggkghacgfpb^^jaeecmhhi`f`gbZh[Y]_]`eYWdcbei^id`hja_gbda]^Wbebb\ci\be_Zec^^df`ae`_mbfa_]i_bcl`gdYajl_`adeechb\emcafab]_bca`^Zjdae^_f_cbd\be`ebcb_efdd`j`ccfcd]fd_hhhaa`jajabcah^bbhbccfbce\_nc^^i`b``eifcabbfnbrilah]^`\e`_`ci[fdabbg```b^gadgccccccccccccdccccccccccccdccdbdbcdcccdccbdccccbbcccbccdccdccccbccdcccdcccddccccdccccccccbccdcccbddcccccccccccbccccccdccccccccdccccccccdccccbcdccccccccdcdcccccdccdccbcdcccccccbccccccccccccccccccccccdccccccbccdbcccdcddcccccccccbcccdcdcdccdcddccccccccccdccccbcccdcccdcccccbbcbacdccbcdcdccbdccbbcdbddbbdcbcbdbbcccdccdcccdcccaccdbccbdddcbcdcbcccddbbcbdddabbcccbccccacccdbbdcddcdcbbdbbcbecdbbbcbccccbcccccccdcbbccccdbdccccdcbbcdbbcccbcbccccbcdbbcdcccbcbbcccddbdadcdcebcdccbbbbdcdccccbdcdcdcbddcccdbcdbdccdbddcccdcbcdcbdedebc`bddddadeebcbb`acceceebbbcebcbecbccdbddbdbdcbcddeacebcdfbeb`cdbba`eaccbbacecfabcccccccicddacedd`ddbfgggcccccchbddddcbdccdddbadbeeccbbddbbcebfeedfebadabdeaccecbbebddeddbccaca`cbdcbabadcbddcccdbecdeccddacccdbcbddbcbdcebcdce`dcdcddcedecbdddcegbbcbbebdcbdccdddddccccccbdecccccccddcccdcddddccccdddbdddccdddddccdccccdcddccccbddcdccccccddcccdecccdcccddccccdcecccdcddccccccdcdcddcdddbdcddddddddbcccccdccdcccddcccbccdddccdddbdddbcbcccddddccddcccdddcccccbddcdcadbccdcdccddddcdccccdddccdcccccecedccccddccccdcdcccdcdccj`bcbh_]g^[ee`f\e``emhb`defde]W_ed]`jba`emWa][[jh\kdgbi`gfcch^]dajYec[ffcfc\bdc`]nec_ecba`[afimi\Y[dadiblbfmb_TgibcbUcbhhchdhbgimk`c_afnba_g[fa^c]hf\bm]`aed`eeahZc\eejhg^Z]ihoee^g``bdbda`\b]ajge`^bebfde`dbbbej\``hhfekcdd]^dgfggakjhdfafmcedbe`^`afdk_``dfk`^ccdccccdcccccccccdcbccccccccdccccdcccdcccccccccccdcccccbcccdccccccdcccccccccbcccdccccccccccccccccccccccdcccccdccccccccccccccdcccccccdccccccdccccdcccccccbcdccccccccccccccccdcccccccccccccccbccccccdccccccccccccccccccccccccbcccccccccccddcccdcccccccddcccccddccc^eegdheaccYefcjgae[bacechg^chabd`_abc`f\hddgdee]iaacbbaYabeachgfhZea]b^^efd[[edbgh_`h]biagdaa`cdb]aambbi]`^da`fef^_kcahcdcqjca`bab`hhbieb`fgb\fcbb`bga_i^``ec^efgn]]d^amaa_k_cbc`bdbbZckg`bh]ehdc`egee_bhb`f^_fabj^`dgbdd`dfhkd`a^diZee]cfe\k`e_dhZg_ad_cdb_`jigccccccccccccccccdcdcccccdcccccccccdcdcccccccdccccccccccccccccccdccccccccccccccccccdcccccccccccccccddccccccccccccccccccccdcdcccccdcdccccccccbcccccdccccccbccccccccccccccccccccccccccdcccccccdcccccccbcccccccccccdccdccdccccdccccdcdcdcccdccbccccccccccccdccccccccccccccccccccccccccccccdcdccccccccccccdccccccccccccccccccccccccccccccccdccccccccccccdcccccdccccdccbcccccccccdcccbcccccccccdcccccccdcccccccccccccccccccccccccbbcccccbccdcccccccccccccccccccccccdcccccbccccccccdcccccdccccccccccccdcccccbcccccccdcccccccccccccccccdcccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccdccccccccccccccdcdccccccccccccccdccccccdccdcddbccccccccbddcccccccccccccccddccbcccccccccccccdcccccbcccccbcccbccccbcdcccccddccccccbdccccdccdcbccdcdcccccccbcccccccccccbccdcccbccccdcccccccccdcccccddcccbcccdccccccccccccccdcccdcccbccccccccdccbccccccccbbcccccccbcdbdcccccdcbdccdcdceccddcbebccccccbccbccccdcdccccccbcfcbceccccdbd`cdcdcddcddcccdccbdcdcdcddcdcccccdceccdbcdccdcbcdcdcbbdcdddcdccdcbdbddcdcddbedcccdcceccebdddbcdcbcddebdccddbcdcbbcbddbbbccccddcddccccccddcdbbbdcbbdcdcdcdcbcddddbcddbcccccccdcdcccddcbdccbccccdccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccabggaccfabchb`ceddaef`ddaacbbgccdg`cddcdecfb`cadjaecbcb`c``ceacac_ccbhebcc_abd_bbcbcadcc`cadfcbagbbej_e`ecdacec_efbfc`defaba`dacgdgchcbahbaeebce`_cgbeeaefeddcadgddb`jbdbcbcbdaadeabccdecccadf`cedcbddf`agbdcbbacccaffefcbfdgeaadbacfccd^`ca_acc_cf_hfbea`cfdg`acccccccccccdccdcccccccccccccdcccccccccccccccdcccccccccdcccccccccccccccccccccccccccccccccccccdcccccccccccccccccccddcccccccccccccccccccccccccccccccbccccccccccccccccccccccccddccccbccccccccccccccccccccccccccccccccccdcccccccccccccccccccccccccccccccccccccccccccd]aaedYif`dekg`e_`gedhag]gjcfdjefedbdacab_fiea`b[dfdkabkq]bdgagcfdibg_fhg`b_a`eggdf_cgc`mccc`_^`a^_efhcgegdehaccec`bdc`jahb_fgeagf`ecg]b`lkeifcc_c^gbdafeef^cbjchdhcfcc\hiiefeefbcagadadiefd_beebcglebgbchlgeccabeebXajdc`Zedff`_bbbgfeaZ]j_dcj^ac\[dc^`f`f`cba_fa\a`bcdfdcgbd`^cbcbbhbcbefdbga]eb_bg_`c`_ebbbdbee\eid^cfc`ce`cea_`df`bbac`dbfeg`agaabbebchcfdbbbfcdbbahgfddccebbebeccbfbbak_a`ddfbc^`c^`ccadkbdc`aeb``cbaecaaebfigdce_ddce`aeb_habecaef`debafa^_iehacdfabggddeed`acdfbddacheebikbcedg]ac`aaieafa_bf_`ebaa_bdeccbccdcdcccdccccccccccccdbccccccccbcccccccdccccdcdbccccccdbccccccccccccccccdddcccccccccccccccccdccdcdbcdccbcccccccccccbcccccccddccccbccccddcccccbccccccccccdcbcccdcccbccccccccccccbcccccccccbccccccbccdccccdccccccccccccccccbbcccccccdccdccccccccdcccccccdcdccccdccbdcccbccccccbccccbbcccdccdcdccbcccccccbcbcccccccbccbcbbccdcccdccccccdccdcbcccbcddcccbcccccbcccbccdcccccdcdcccccccbccbcbdccccccbccccccccbcccbccccdccccccccccbbbcccccdcccbccccdbbccbbcddcccdbccbdccccccccdcddccccdbdcddbcccdccccccdcdccccbccdccccccdccdccbccccccbcccccccbccccccccccccccbcccccccccbcccccccccccccccccccccccccccccccccdccccccccccccccccccccccccdcccccccccccccccccccccccccccccccccccccccccccccccccccccccccbccccccccccccccccccccccccccccccccccccccccccccccccccccccccccbcccccccccccccccdccccbccccccbcbcccccccccccccccccc^cj\ad\ge^ddb^l^Wicagchc\kchac]bfaccaef\\l_^adgbhde^iak\_]ggcifbdhdgaih]agfbd^dak[bfcee_i`_cf_^d__acc`ac`c_a`a_ccaebW_h`c^ajd^e_p\_cbdgk_[bcmai`ahheddfaj`ccgdYh]jf_a_^i^fndfddecac_ncc_ecgci[^am`hbhnZbirc`gf^[^k^e_caddh^a_hfda^ciak`cbjihjadnghe^fbcg_`g]`]\hcccccccccccccccccccccccccccccccdccccccccbcccccccccccccccccccccccccccccccccccccccccccccccbcccccccccccccccccccbccccccbccccccccccccccccccccccccccccccccbcccccccccccccccccccccccccccdcccccccccccccccccccccccccccccdcccccccccccccccccccccccccccccccccccccccccccccccccddcdcbcccdccccccccccccdcbdcccdbccccccccdcccccccdccbcccccccccbccccccccccccbccbccccccccccdcccddccccccdcccdccccccbddccdccdcccbcdddcccccbcccdcccbcccdccccdbcbbccccccccccccddccccbbdcbcdcccccbccccbccccccbccccccdcccccdbcccccccccccccccccbcccccdcbcdcccdbeccbcccdcbcccccbceccdccccccccbccdcccccccccdccccdccccccdcdcddbcdbccbcbdcbcdccbbccdccdcbdcccdcdcddcccdccddcccdccbdccdcccbcddddccccdcccccbdcccdcccebccdccccbdcccddccdccccdcccccdcccccbdddccccdcccbbddceccbbddddccedbdbcddccccbbbbcbddcccdddcbccccccccccccccccccbcacdcdcbccccdcccdfbcededccacabcaabeddeccecdcecddebbcdadbcecddcaebbbdbcdbecccccccdfedcdcbbeedcbbdbb`bccbd`bbcdfbe`dgcccccdcdcccbceddcdbbcdbdfcbadbbdbedcddcecbbfcbecfdacacecbdecede`badhcedecedacbaccdcaccabebdbccbcdadaddbbddbeacddfcbcccdebccccbbefcddebedfcecbedaccccccccddebcceceadcdbccbddcdccdbcabdddddbcbebdccbcdcddeeddeccccccdbbbcbcdbcdbcccdbccecccffcedcdcccbbbccccddbbccccdcbcddcdd`bdedec`dcccccebccccccccbcbdbdbdbcadcddddedbecdbdeccbdcbgceddccccdbcdecdceccdcfeeddecbbdbcdcbdebcdcaddcdcdcdecdccebcdccfdacddfdccccdfadddcbdbccdbcccccccccccbcccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccdbccccccccccccccccbcccccccccccccccccccccccbcccccccccccccccccccccccccbcccdcccccccccccccccccccccccccccdcccbccccccccccccccdcccccccccccccccccccccccccccccccccccccccccccccccccbccccccccdcccccbcccdcdccccbcccbbcccbbcccccbcddcbdbcccdccbccdccbcccbdccdcccccccdccccbccccccccccccccbbdbcccccdccccccbdcccbcdcbcccccddccbcccccccccccccccccccdccbccbcbccdcbccccccbccccccccbdcccbcdcbccccbcccccbccccbcdcccccbccccdccccbcdccccdccccbccccdcbcedebbbdcccdecbdbccecbccdcbcdcbcddccccddbdbcccebdbddbbbcececbdc`fdcbdbbeccbebbdeddddadbcddeecabdddb_aachbccbfbdcbcbcbcabcecfcbdcbdc`bddbccbeedbccceedddbbac`ccbdbfcabadbbeba_febbccdbdaacaddccbcbccebdd`ecbcdcdccfdcdcbddfbdabcbbbbeccedcdabacadeaabebcc`baccf`ccccccccccccdcccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccbdccbbbddcdcdbcccccccbbccccdbcdbdcccccccbcbcbcebbcbccddccbccbdbcbbccbccebccdbdccbccccbdaabbcbcbbbdcccbcdddccccdcbccbcbcbccccccccbcdbbccccdcdccbdccdcbcbcdbaccbcbcccbcbdbbecbcdccbccccccdccdcbadcccccccccdbcbbccdbaccdcdccddddcdbccdbdccaacdbccbbbdcddcccbcccdbccccccccccdccbcbcbccccccbbcdbdccccccccccccdcbcdcccbcdbcdcbccdcccbdcdccdcdccdcbcddccddbdcbbdcccccccbccdccccccccccccccccdccdccbdccccccbccccdccccdccccccccccbddbcccdccccccdcdcdccdcdccdccbcccbccddcdcccbcbccccbccbcccbcdccccdccbcddbccccbccdcbcccccccccccaddcccdbcccb^dYb\ecabfid]]idbi_gc]]eaaee]bacjcfbebaaf_^dc`ce_`bfcdmcf_bekabbf[b^j_hmfe`e\_gbjfccdeWeedidk_]dcafaakcj[`cgjh^``bc\ehe_cbiikdc[bZb^_jcgbbefaicbe]ca]^_adhcaf]fabcacj\`ca^\`^^l_aid`b^gi_f[ed[ihban]dca`cldYhfcb^]mh_`ik\df`i]fecihbfdalk`ebclc`gbf_geihibidig]]ccccccccccccccccccccccccccbccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccbccccccccccccccccccccccccccccccbcccccccccccccccccccccccccccccccbccccbcccbccccccccccccccccccccccccccccccccccccccbccccccccccccccccccccccccccccbcccccccccccc_h^cgceddgca^fc`ca_^degcdd`cbccec`b\kedbcfa^aahg^f_c_hbhbgc`_aecgageadagbbbgf_llib`h_adfebc`egef\cdibcdac`ebhabdbegd_ebf`fgjeebc`edcegfadf`adcgdc___dc`gedbdgc]cdb`hdacc`bdd_ee\`c_bkda_cc_kdbgbd_chdcb_^abafbZcbbdcff``f`e`dbdac`fhccfebcf_fkc`bbda`_fbhbbdcdcccccccccccccccccccccccccccccccccccccccccccccccccccbccccccccccccccbccccccccccccccccccccccdcccccccccccccccccccccccccccdccccccccccccccccccccccccccccdccccccccccccccccccccccccccccbcccbcccccbccccccccdcccccccccccccccccccccdccccccccccccccccbbbccccccccccdcccccccccccccbcccbccccbccccccccccccccccccbccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccbcccccccccccccccccccccccccccccccccccccbdcccccccccccccccccccbcccccbcccccccccccccccccccccbcccccccccbcccccccccccccccccccdcccccccccccccccccccccccccdcbd\\dab^idgjicgjTab\fafd\hg^bdcdadpdec[]a_cfdYheg]adhj`aX_ca\cfalfe^ikad_e\ej_eaaf_`c_Ubgfcccfj^`hg\fhef\kca]`__gd^jlfeb_a[dSiZd`]eaaj[\g`a\le`l`_gbac_`dbgfbagbi_dbd]clbbdeefeZgbicmfefadhacce\[e][lafj`Wgl`cgbjamcibbgjf`jehf_c[h_c^cadija_hccmfhp`eadafglhd`efh^\f_`aibicmhff`gc]_feY_]dci_b_cadeajaejffbce`km]bhkjefa_bdh^igkdh`faccbd`iccecg_fcecdclja_edebb`cde`abd`bh__bfaadfheg`fcbc`cadgahgdefdeg]ddba`dd`]d_`^ddeee_b\b\ce]iefgfbgb_afc`j]agi_cdgh]f\]Xcbii`_fe`_a`dd[dbeeb__cjhdgk_k_^bf[cificdc_df^`f`dld_kibceicfbddbdcbdcccdcccddcbbdcccbcbbccdcdcdcbdccccbdbdcccdcddccdeccccccccbccdccccccdbcccddccccdccdddcdcdccebcccedccecbcbbdccccccccdcdcccccbbbdbdcbcbcccdcbccccdcdccbcbbcccccdcccccccbccdcccbbbcbcbcdccdbbdcdccbcdccdccbbcabdbbccccedccbbbcccecddcbbddccdcccdccedcdccdccdddccccbcdcccddcccdccccbdcccccccccccccddcccccbcccdcdddccbccccccccccccccccddcccdccdcddccddcbcdddccdccccdcbccccccccdcccccccddbdccccccccccddddcbccdcccccccdddcccccccccdcdcbedcbbbcbcccccdccdccbcccdcccbcdcdcccdddccdcbccbccddccccccccccccdcbcbccddcccccdbcccbcccdccbfbdedmfcda`]fgccfgegedieacda`_f_agf^bedghcdb^\^_gea\c^cc`ecZa`lbh_dbbf_c`e\^_e`dbafh`_fbecad[fddcb`ahgcba_cddebcdc^_b^ecc_fhbbehdcadecbfeace_`bc^dcceb```_f`cdbba`e`fidlbce``ii`bck`adigcgdhdeea^e``ebihb\dc``cbeeddfdbbcbib]agcab^gad^bdc^fa]bebbdgfc_bee`hchhf`bhbkca_egd__acg_bf_aa^caebicbedc_adbbbga`hhdbeddb]a`^fd^abddfgeadc`gdc`ba`baeded`ddcdfdecg_cfgfdabbbdbicbbadgcbceccbe_dbbfdcdc`ed^abb`b_^a_dcbcd_cbbd`acfdgcggegdbbecbbe`c]d^cbceccjeebecicc`ccagjjdeachge_fb`ej_`dbbca`cefcdd`ebhj`ibbecbecbpeaceg_ccfe^cee_bbcccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccbccabccdccddaacbceebcdcdacbebdbcccccccdccdeaabdgcc`a`bbdcaddbcbcbcdddbbbcceccdbacacdacdfdabebdbcccefcbedcbcdabedfecdeccccbbceecdddebddccccdacdccccefdcafcdfedfccccacdbdbeaaddccccad`dcbcdccdecbcbbbcbdbcddbbdbaeabbdcbbadccadbcdccdbaeabcfdcfcbaccbccccbbddchcadcccbcccbccbcccdccccbcccccdcbcccbbcccccccccccccccbbbdbbccccbbccccdccbcccccbcbccccccbccccbcccbccbcccccccccccccccccbcccbccccccdccccccbccbccccbcdbccccccccbcdbccccbcccccbcbccccccccccccccccccccccccbccdccccccccccdcbcbbccccbbcccccccccccccbbcbcccccccccccccccdbcccccbcccbcbbccccccccdcbccccbbcbcbccccccccccccdccccecccccccdcbcccccccbccdcbcccccbcdbdcbddcbcddcdcbccccdcdccccccbccccbdcdccdbbcccccdccccccccccccccccbcccccbbbcbcccccbbccbcdddccccdcdcccbccdccccdcbdcdbcccbdcccbdccccbcccbccccbdcbccbbbcccbbccbbcccbccccccbcbbbcccbbdccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccecdeefaabcc`ce`cbbecdcccdccbb^cagbcbcecbcd`ddecbfcfad`b^ebaceccacde^aceadbdcaaccdddebdccbddcdaaacbecbcbccbbafbeedbabgacedddec`fcafdbcfcdc_gagbbcfcbddab`addb`dbedbcchbd`cdfaabadcbddbcbaebcbfcc``ccefadedcdc`fdbddjceccdebbcdbbddadccb`ffbadaddfad_hb`bdbb`bdde`cgedagchdhgV`hcbdbZ^_`dba^_lbe_cdac^hec`gbc\cZiZcaqahh]]b^^cdeb[acf]db_aaaie`gcfchlbbea`d]afdea`e^b^fcccei`f]d\hbgc[]\hke_ee_a`adcbeba]c^ffdhe`a_bh\dbggk`jkbdhf`dgcgbfcd^ebdabjaedi_ekf_abegbdbeadgafcbgecjgge`_^faWgg_\deefba`hbahah`a__ifjfg^afachbakbffbgffcddbdccdcccccbcbbbcccdccdccccccdcbccbccdccccdbddcccccccdcccccccccddcccccdccbcccccccdccddccbbddccccccbcccedecccdcccbcccccccbcccdcddbbccdccddbdcccccccccdccbdccccccdcccccccccccccccccbcddbccccccccccdccbcdccdccdbcdcccdcdcccdecbcdcbddccccdccccbcccccbcccbcccbdcddbccbbbaebbcbcbebdbab`cadbbceba_h`dcbc`deaddbecdgbebefccddbchdeb`abcdcedfbabdaddfebdb`bccaedbgddcdedcdaedebedeacadcdd`bbfddccbba`c`edbcbbbaaccbedge`lbdde`fa`dddbcccedbaeddabdabhbbbcebcacdbccbec`cbcdbaddgcceefbcbbcdccbcababbbdccebcccb_cbccebdcddd_cabdbcaddc`dccccccdcccccccccccccccccccccccccccccccccccccccccdccccdccccccccccccdcdcdccccccccccccccccccccccccccccccccccccccccdccdccccccccccccdccccccccccccdcccddccccccbdccdcccccccccddccccccccccccdcccccccccccccccddccccdccccdcccccccccccccccccccccccccccccccccdcccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccdccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc`ca]bcabac_l_d`c`da`Z_b^f`bliikghcb`]iYd_lZjj__[f^hbddjff`gdf`edcckib[kcdcegfa[_afkjkke^kaf`dfgak`fZa[^_]kcli^h_adbaeec`aa[`aeede`^b_bdbZ`jdg_^geegakm`bceabeefafgm]`ea]dbe`fbaehl`c_cfcefgagea^_\`abe_bckcbc\cXj``_[\ihe^bahjgaacb_cbh_`deijeaff_]`_pf^iaeec^d`cccccccccbdcccccdcccccccccccdcccdccccccccdccccccbccddccccbcccdcccccccccccccdcccccdcdccdcdcdcccccccccccddccccdcccccbdddccccbcdcccccccccccccccccccdccdccccbbcccdddcccdccccccccdccdcdccccccccdccccccdcccdcdcdcdcccdccccccdcddcccddcdcdcccbccccccccdcdccdccdccccccdccbccbccbccbcbcbccbcbccdcdbbbcccccdcccbcccccccccbdddcccccbcccccccccccccdcbcbcccbbccbdcccccbccccccdbcccccbcbccccccccbbcbccccdcbcccccccdccccccccbccccbcbcccbcdcccccbcbcbccbcbbcbdccdcbcbccdcccccccccccccbccccccccccddccccbccccedccbcccccccdcdcdccbbccccdccdccbccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccdccccccccccdccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccdccccccccccccccccccccd_acbacddec^_fcbeaZegYehhbiebdg]hebccbejccbd_d_g_ddhZd`\gfb`ebbdacgca^bbfeg`achgckbaccebddc_gceeeiaaagkedegbfd_ebacdida_`cgeabbdcibaabdcid`eciccdfaf]fbebaeba\dcf^bbl_gagcccagaiccdc`cc`_b_d^_abaaidcbgf`bceedgeaaebb[bhd_]efbdc_ogededee`ffeebcdhdc`egcgad`hfab`bbbbaccdbbcbaebacdbaccbeebccdedbcdbbfdcbbdcdcbabccedaaccbbcbadbebbbbbcbcbcdabebcbcfddcacabccccccedcaacaabbbcdbaadc`cae`ebecaccacdbdfadbaebecccabbcccdcddbdbcccdabcccdcbcdddcdbcbbdbbaddcbcacbccccbadcbdeccacbcbcbdcbcecdccebbbbbdcacdcdcbdcdcacdabecbcbaccbcbdbccccccccccccccccccccccccccccccccccccccccccccccccccccccccbcccccccccccccccccccccccccccccccccccccccccccccccccccbccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccdccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccbbcbcbccccbcccccbccdbcccbcdbcbcccccccbbccccccccdcbccbccbccbcdccbccbcbcccccccbbdbcbccdccbcbbcbbcbcccbcbcbbbccccbcccccbbccccdcbdccbdbbccbccccccacbbbcccbcccccccbccbccbcdccccbdccccccbccbccdcbccbbccbcccdcccccbccccccbcbccccccdcbcccccccbcccbdbccbbbccdccccbbcccbcdeabccddccbcac`cbcdcccceccc`bbbdcbccdbcccccccabcebbcbadeccabdccaccdcdbccb`cdccbdaccedebbcdbacbcb`cdabcccbdce`baabbabadccaccbabccbbdb_bbcce`bdcdcbccecabdcccdcdcbccbcabcbbcdcbccecdaccdbbbecbbbceccdbbdbbcbddbbcccb^aebbccbdecbdbddcccacccaadcccccabf_ebcccdcbdbcbfd`f^^blg_ag]aacfcfbcfcmf]ilef`dX^^eabdaaj]adedhg[b_ahfbce``hgdfk_\`rhkhdeaYb^l]a_h`X`_caecce[^ddg_bhagcbbhac_aaeab`faccde`]aekhecgacjd_eYe\ea`d`]gbfbh^pddZ`fbY]^cdacp]_^\``f[cg`dd\d^`^cadigfdgepf`ef[\c`ebbbgib`ggnh^cXbd`b_iaaaekobmeg^bdbeabgii^ajda`co]af`ccccbbcccccccbcccccccccccccccccccccccccccccccbccdbccccccccccccdccccccccccccccccccccbccccdccccccbcccccccccbcccccdcccccccccccccccccccbbcccccccccccccccccccccccbccccccccccccccccbccccccbcbbcccccccccccbccccbccccccccccbccccccccbbccccccccccccccccccccccccccccccccccccccccbccbcdbbdcccccccbccdbccccccbcdccbcccccdcbcccdccccbcbccccccbcbcccccbcccdbccbbccccccbbccbcccbcccccdcccccccccccdbcbcbdcbcccccbcbccccdcbcdccbccbccbcccccbebdbdccbbcccbcccdccccbccdcccccbcbcbbbdccdcdbdcbcccccccccdcbcdcdbdcccccdbcbdcbbbadcbcbccccccddbcdcccccccccccdccccccccccccccccccccddccccccccccccccccdcdccddccccccdcccdcbcccccccccccccccccccccccccccccccccdcccccccccccccccccccccccccccdcccccccccccccccccccdcccccccdcccccdcccccccccccccccccccccccdccccccccccccccccccccdccccccdcccccdccddccccccccccccccccccccccdccccccccccccccccccbccccccccccccccccccccccccccbccccccccccccccccccccccccccccccccccccccbcccccccccccbcccccccccccccccccccccbcccccccbccccccccccccccccbccccccccccccccccccbccccccbcccccccbcbccccccdcccccccccccccccccbccccccccccccccccccccccccccccccccccccccccbccccccccccbcccbcccccddcccccdcdccdcbccccccccdccdcccccccccdccddccccccdcbcccdcccccccccccccccccccccccccccdccccccdccdccccdccccdcccccccccccccccccdccccccccccccccccccccccdccccccccccccdccccccccdcccccdcccbcccdcccccddcccccccccccccbccccccccccccccbccccccccccccccccdccccccccccccccccccccccccddcdddcdddccddccbcddccbdcdccdcccccbccbdddccccccbdddccdccddddadcccdcccdccddcdcdcbccccccccccecbdcdbcddcdcebccccdcbddcccccbbccddcbddccdcdddcddcccccdcddccccecccccddccdccccccbccbcccdddddccccecccdccdccdcdccbcccbcdddcddceddceccdcdbcbcccdccdccccbdddcdcccdccedcbcdcccccccccccccccccccccbcccccccccccccccccccccccccccccccdcbccccccdccccccccccccccccccdcccccdccccccdcdcccdccccccccccccccccccbccdcccccccccccccccccccccccdccccccccdccbccdcccccccccccbcccccccccccccdcdcccccccccccccccccccccccdcccccccccdccccdddcccccccccccccccccdcccccccb`ielchfadd[gqjgc`edhlijb]jej^l]]clYjeaegi\a`_bbibk`aZhqj_q`f_i^`bga[``hi_abbkZZei`g`d`Vp]gdcae_g[`\ag^e_che`Zi\jZWjV]abZnf`o`d_e]Znfgkajij`f[o^`fh\iedbcshbiib``nXiahjaVXeadcdbdd[]lhYjfec]`be^efdb_dggc]`\e]bbmiab_amedbbffW_e~h]a[`jk^dfd]Xhgfe`^Sidbc\ligah`kcccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccdcccccccccccccccccccccdcccccccccccccccccdccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccdcccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccddddbbffeccdccccdcccbcbfccddccddbcdcbedcbbbcccfcccdbcccdcbbccedecdccccbebcccdecceccddccccfdceccdbbcccdcgcdddcccbbccdabcddcbfdbcbcbcceceadccccbcdgbdddecdbcddbcecbecfdcddcaccccefcbddedbcbdebcbccedccccdcbebdccbddccddcdcce`cbcbdbcccbbdcdecabccecddededddbdcbfdecebdbddcbcdbbcecdbdcbcbcccbdbcaaccbbdcbbeccccdbcbcbbcdecbeccddbbcbeddbcddccbbdccccccaccdcdcbdebccccecddadcccddecdecdfcabbdbbdcdbdccdbdaebccbddcbdccddcdceaebdbcceeccccddcccdbdcbbcd`bdbbdbccbbcdbcbbcbcddcacdc`dbaccfbdbcabbfcecdcdccecba`bcfdddbebecbccdcbdabcdcccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccdcccccccccccccccccccccccccccccccccccccccbcccdccdccccccccccccccccccccccccccdccccccccccccccccccbccccdcccccccdccccccccbcccccdcccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccacaaad`begbb[``b`a`be`addfb`ce``gdee^fhdcedbfe_e\dejbceZ`bdcacba[bbd`dcbdfddb_bbdbegbdc`bbacebfbefa_\cegedfdbcabdefd`a]dddebecddadbe__cad^eb_f`aedee_fdjafceccbebbe``ec]bbef`^`bfcedcabdaa`bdddc`ceecbdjadadcccea`cg__egccabdecbcb_bdchfebdcg`bdfce`_eddhadcdcd`ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccZd`efeegmfdNakd^[fggZdabbm^icid]e^f`[^chdcfhkdjdgb_f_bg]df`gcXfj_ajkehd[dilaajgal^adcZdb^bb^clZocbd[co`d]lkaf`dee^bclpe[d_ZfjbkeY__m]beob``Zl``Udc`glged]a^b[Zec^fjbfd^abZagc^]`bf\bga\[X`X^m`]b^h[ebbjh]kecgcgm\`aghY]ndfcklbibh^aZbffj`b`e`hbfdjqg\]icccdga\e\cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc[[khja_ddi[c`\ccacjcin``aei_ojfkagdddg^Z^ifaahbh_`cfcZjpebichhiibaedidd^^m`eele`dfdehm`Wcg^cb`jbh`e`^_k_eea]__k^aidn[Z`d`_jc]`gejeca^WbebbdaicidW^fjlbbfb^]g]_dakd[l\Z_laiadlabho`j_embemdif]_dlgaim`i^bmd]`igdechida\c]e\if\`dc_]eibbgZ[^cf\Zccfead\_ghXig^b_]`cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccbccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccdbdbfcbcbbbbcbab`bddcbccbdcccbcdcaccabccbdbccccabcbccbedebccccabbfbbcbcccebcbbacbbbccbacaccbcbbdcbcabcaddcbbbbccdcbcbbbccbabdccdbbbcccbcccccbcaccddabcdccdddbccbcdbcabbbbbccabdcddddcccdeddbdbbcccccbaacaccbcadbdbddcdefbdbcbbdddacbbcbccacccabcbccbbbedcbdbbbdbcccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccdcbccccccccccccccccccbcccccddcdcccccccccccccccccccccdccccccccccccccccccccccbcccccccccbcccccccccccccbccccccccccbcccccccccccccccccccccccccccccdccccccccccdccccccccccccccccbcccccccccccccccccccccdccccccccccccccccccccccccdbccbccccbdbccdccccccccccccccccbccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccdbccdfbddededcff`eeecebcbcdaaecddbdbbfcccbbceaceccadgcbcebcdddecdcedbcccdbbebc`dfbffcdbhefececdabaeceddccddgfdcaadcdebdcecageccbcdcedfcedcdbccedccdeebcddbb`fbeeffccdgbicfdcdddbbbdbdcdbcbecdecbecbadbdccefhbeaccbeabdbaeddadeccccbccdcaaddccgcdccagecbccccbbfdecccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccbcccccccccccccccdccccccccccccccccccccccccdcccbcccccbcccccccccbccccccccccccccccccccccccccccccccccccbccccccccddccccccbccccccdccccccbccccccbccdccccccdccccbcbcccdccccccccccccbcccccccccccccccccccccccbccccccccccbccccccccccccdccccdccccccccbcccccccccbcccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccdcccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccdcccccccccccccccccccccccccccccccccbcccccccccccccccdccccccccdcccccccccccccdcddccccdccccccccccdcdcccccccccccdcddcccccccdccccccccccdcccccccccdcccccdddccccdcdccccccccccdcdccccdcccccccccbcdccccccccccccdccccccccccccdccbccccccccccccccccdccccdcdccccccccccdccdcccccccdccccccccddcccccccccdccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccebddebcdcdbdcccedeeccceddecccdecdcdcdccdcddccdcdcdcbdbcccbdcdcccedddcdccccdcbdccccddddcdddccccccdccddccccdcccccccbdccddccccddcebccccdcccdcdccccdcdccccceddcdccddcccddcdddccbcdbdccccccdecccdcdcbdecccbddcdccceccdcdcdcddddccbedcccdecdddcddbdcedddcccccddcdcdccccccccccccccccccccccccccccbcccccdccccccccccccccccccccdcccccdcccccccccccccbbccccccccccccccccccbccdccccccccccccccccccccccccccccccccccccccbcccccdcccccccccbcccccdcccbcccccccccccccccbcccccccccccccdccccbcccdccccccccccccccccccccccccdcccdcccccbccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccbccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccbccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccddcddcccccdcdccbccbdccbcdccdcdcccccbcbccbcbccccdcccdcccbcccdbcdbdccbccbdcdccbccccbcccdcccbbccdcdbcdccdccccdcccddcccbccdcccccccccbdccdccddbcdcbcccccccdccdcbcdbcbccdcdbdcccccccbcbcccbdcdccdbcdcccddccccccecccccccbcddcccccbcbcccbccccccdccbbcdcdccbcccccdccccccccccccccccdccccccccccccccbccccccccccccccdcccccccccbccdccccccccccccccccdccdbdccccccbbccccbccdccdcdcdcccbccbccbcccdccccccdcccbcbcccccdcdbccddbcccccdcccbccdccccccdcccccccdddcccccbccccccbcccbdcccccdccdcbdcccccccccbcecccccbcccccdbcccdcccdccccccccccccccbcdcccccccccccccccccccccccccccccccccccccccccccccccdccccccccccccccccbcccccccccccccccbcccccccdccccccccccccccccccccccccccccccccccccdccccccccccccccccccccccbcccdcbccccccccccdccccccccccccbcccccccccccccccccccccccccccccbccccccccccbccccccdcccccbccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccdccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccdcccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccdccccccccccccccccccccccccccccccccccdcccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccca_bedafcech^ed^dadcbdgfdid`ihbafabadb^f]eficbbeee_cgbeccbfiabedeeaf`cbcgdbg^`cacecca`fcdcbddffcd`cbhdbdcaecedeb_a^ecdcbd^dhdeche`_ccgdedfeddbac\cccebbdafdeg`bbdaccfdbcbcddcgacbecafgcacda_e`dd_bcdgegef_fcea`dbbdccbg`ibda_d^addccaj^edgciacdececa`cbgeaeef]g_bdccdcddccccddccdcccccddccdccccccccdccdcdcddddcbcbccccccbcdccccddbccddcccccdcdcccccdccddcbccccccceddcbdccdddcdddcdcdcccbdcdccddcecccdceccccdccddcccddddccccccbcdcccdccccdccddcbcdccdcccbcdcccddcbccccdddcdcccccbcddcdddddddccddcdccccccdcdcccdcdccddcdcccdcccccdcccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccdccdcddccccdbcccdddccdccbcccccccccccbdcdcdcdccccecdecddccdcccccdccdcccdbccbcdcbcccdcdcdcdcccccddccccdcccccdbccdbcccdccccddcdcdcdcccddcccccccccccdbcccccdbceccdccdccccdccdcdcbccdccccdbccccdccccddcccdcdbcccdcccddbcccddcdcdbccccccbcccccdccccdccccdcdcccccccdccdccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccdbdbcdddeddcebddddccbdccccdddbdeccdcedcddddccccbbddbdcddccddcdbcdddcdecedcdcbfddedcdbdedddccddfdbdccccceddcceddcdbccccdfdcdedbcccccbecccddccccdeeebecfdddbcccdeccddccacccec`cbdeccddcedccdcdfdeccdbceddcdecdcddddacbdbcdbecdcccdccecccbbbcbdddccccccbdbdcbcbdcdaccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccddcccccccccccccccccccccccccccbccccccccccdccccbccdcccccccccccccccccccccbcccccccccccccdcdccccccccccccccccdccccccccccccccccdcccccccbccdccccdccccccccccccccccccccccccccccccdccdccccccccccccccccccccdccccccccccccccccccccccccccccccccdcccbccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccdccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccdccccccccccccccccccccccccccccccccccccccdcccccccccccccccdcccccccccccccccccccdccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccfcbcdccbccbedcbdbcacddbcbdccdcddeeebcdcdeccbbbbebdcebccbeecbcbbdccbcddcdcccccdbcdcbbcccdcccdceeddcdcbdbdddcfdbcefcdbccbccbdccbdddefdedacbebdccddccbcbadcbcfdccbdcbddbccdddbcbbabaccbccdbccccbbbccedccceaacbecdacddbeaccedcbadcbccabcecdfcbddbeebcceccdeddadcaccbccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccdcccccccddcdcdcdddccccccdbccccddcdccddcdccddccccdccddccccddcbccddcccccdccccdccccdccccccdcdcdddccdcdcdccccccdcccbcccbdddcccccccdcccccdccdbdcdcdcccccccccddcdcccdcccccdcddcccbccccbcdccdcdcbcdccccdcccdccccdcdccbcdcccddcbccccccccccbcdccddcccccddcdbcccbccccccdddcccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccbddddcccddccccdcbdcddccccccdcdddccccccedcdcdccdccccccdbbcdebcddbcdcddcccccccdccdcdddcedcdcccdddddddbddecdcccdcddcbccdbddcccccdcccccbccccbcbcdddddcdccdccbcccdecdddcccccdcdccacccdccdddcdddcdcdccceddccdddeccccddccdcccccdcddccddcddcdbdcdccccfdcdcdccbcdccdddccdcccccdccccccdcccccccccccdccccccccccccccccdccccdcccccccccccccdccccccccccdcccccccccccdcccccdcccdcdcdccccdcccddcccccccccccccbcccccccccccccccccdccccccdccdcdcccccdddccdcccccccccccccdccdcccccccccccdcdccccddcccccdccccccccdccccccccccdccdcccccccccdccccccccccccccdccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccddccccdcccccccccccccccdccccdccccccccccccccccccccdccccdcccccccccccccccccccccbcdccdccccccccdcccccccccccccccccccccccccccccccccccccccccccccccccdccccccccccccccccccccccccccccccccccccccccccccccccbccccccccccccccccccccccccccccccdccccccccccccccccccdcccccbccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccbcccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccddccbccbccddcccdccccccdccdcecbccccccccbcdcccccbcccbcddbcccccdcccdcccccdcccccdccccbcddcccccbcccddcccdcccdcdcccdccdccccccdcdbccccccccccccbcccccddcbcccccccdbcbcccccccbccccccccdbccccdbcddccdcdccccccbccbccccdccdccccdccccbccddccccddbcccccccbcccdccdcdcdacgcacfaeaf`efdcia`ckh`agee_e_``accffafbg`feagafbdhbdf`^b`a`c`cfbbbcdc`chebd^cbbai`_dfb`edbdag`efadbeibahc``Zidea_e_e``dc_d^aaeadbd__dcibba_bba`b`ebcbabef`f`cahdgbchdl`abcb^ace_gbed`abcgedaedbedaf`feba`cdfbdbabcccbeiffbaebbfdf`ha_eiabfibafga`gbac_c`cfdddgaccccccccccccccccccccccccccccccccccccccccccccccdccccccccccccccccccccccccccccccdccccccccccccccccccccdcccccccdccccccccccccccccccccdccccccccccccccccccccccccccccdcccccccccccccccccccccccccccccccccccccccccccdcccccccccccccccccccccccccdcccccccccccccccccccccccccccdccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccdcccdcccccccccdcccccdccccccccccccccbccdccccccdcccccccdcccccccccccccccccccccccbcccccccccccccdcccdccccccccccccccccdccccccccccccccccccccccccccccdccccccccccccccdcccccccccccccccccccccccccccccdcdccccccccccccccccbccccccccccccccccccccccccccccccccccdcecccccdcccccdccccdccccccbcccccdcccddcccccccddcdccdcccdddcccdcdcccdcccccdccdcccccdccddcddddccdcddccddccdccddccbdccddcccccccccddcccdddbccdcccdccccccddcccdccccddcdccdccccdcccccdcccdcccddcdccccdcccccccdcccdcdccccccdccddcccccccccccdddcdcccccdccdccdcccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccchihh``ibca[abhag^egi^faceacdghhdkfdce`dgcdff]daed__bddek_ibbda`edhegjec_egbcdc][a`jb_fegV\dkcf_fd`fd``e_aabde`fX_\f]gd^cflZ_``ke__fj_lh^badd_d^djgfgiacefn^jflncaajdcc`fjgcb_]_fl]dgbe\dba^agabc`iecadk_dgZbl[dc`jXfacgheeehdcj`fh]gdii]ch^faedefhc_^cnebeehkbb]cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccdcbccccccccccccbccdccccccccccccccbcdccccccbcbcccdccccdcdccbdccccccdcccccdccccdbccccccbccccbbcdccccddcbccccdcccccdcddcccccbccccccdbcccccccccdcccbbccccccddccdccccdccccddccccdccccccccbcbccdccccccccdccdcccccccccccdccccccbdbcccccccdbccbccdccccccbccccdcbcedcbddccccbddccdccccccccbcdccccccdccbdccccdcccdcccccccdcdccdcbbccdbccccccccccccdccdbdcccccccccbcccbccccccddcdccdccccccbcdcccdcccbdcccccbcccccbccccdbccccccccccccccbcccdccccbccccbccccddccccccccdccccccdccdcddbccdbccccccccdcccbccddcccccbccccccdbccccccbccbcbcbccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccdcccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccdccccccccccccccccccccccccccccccccdccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccbeddcbccdbdc_dbbdaecdddcddbbbdeadeeabccdcbdccfdecbcebcadadgddddcbcdddceabgebdccadeccc`ceedcdbadacdbgcceddcbbaccddceddcdacbdbdbcfbebaccdccdeaacdeccebedaba`aaaeececbbcbcdcdfbeeabedcacaacccddebcbdfcccdcdfebcbcabccacbbdcdccbcbedddcdcbdcbbacdedcfbfccccadcdabfbccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccbdbda`dbbbbdbdabdcdddcbcccdbbbcbdcbccbcdbbdcdcddbbbbaced`dbbcbdcd`cbdbcaabdedcddccbbcccbcbbbcdabbacbcccccdcdadbbbcbdccacbbabbbbccdbbdcccccbabcc`c`cddbccecbcdcccccdbdccecceccbccdbcbbebbbbcbbcccdbcbdbcabdbbdd`dcdcbdbbddaaabecbdaacdbdbccadcdccbcbceddbbdacdbbdcccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccbcccccccdddccccccccccccccccccccccccccdcccccdcccdcccccccccdcdccdccdccccdccdcccbcccccdcccccdccccdccccccbccccccccdcccdcccccccbcbccccccbccccccdcdccccccccccccdcccccccccdcddcdcccccccccccccccccccccccccccccccccccccccccccccccccccccccccdcccccccdcccccccccccccccdcccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccdccccccccccccccccddccccccccdcbcccccccccccccccccccccccccccccccccccccccdcccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccdcccccccccccccccccccccccccccccccccccccccccccdcdcccccccdccccccdccccccccccccccccccbcccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccfcc`d`bedcdfibecaccecc`bcdacfdicdccdcgadbdedbedbeacbbaadccb`c`aceccccddcbdbddaedgaefbbcbdcbcbaeaecbcebbeceacc`ecadcid`ceeebgecccddgdhagbacdedbed_cc]dbcbbdcdbabbeeadacadccddcde]ce_dddebddccbfcddf`dfcdbdcacdcddfbebdb^cbdd`dedbecdccdcabdccdbecdbZhededcacababcccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccbccccccccccccccccccccccccccdcccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccdcccccccccccccccdcccbdbcdbbccccccccdcbddcbaccbbccdbccdddbcdcbcccccdccbdcccccccccccccbccddcccdcccbccccccdccdcccbdcbdbcbdccccbdbecccccdcccdccdcbcbddcbbdcdcdacccdcbccdcdcdbbcbbccbdcccddcccccccdcdcabccccdbcdccccccdcdcccccccccccbcbbcbcccbcbbccdbccdccdcdedcccccccdbcbcccdcbdcccbccccccccccccccccccccbccccccccccccccbcccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccdccccccccdcccccccccccccccccccccccccccccbccccccccccccccccccccccccccccccccccccccccccccbccccccccccccccccccccccccccccccccccccccbcccccccccccccdcccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccdccdcccccccccccccccccccccccccccccccccccccccccccccccccccccccccccbcccccccccccccccccccccccccccccccccccccccccccccccccdccccccccccccdccccccccdbcccccccccccccccccccccccccccccbcccccbccdccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccdcccdccccccccccccccccdcccccdcccccccccccccccdcccdcccccccdccdccccdccccccccccccccccccccdccdccccccdcccccccccccccccdccccccdccccdcccccccccdccccccccdccdcdccccccccccccccccccccccdcccccccccccdccdccdccccdccccccdccccdccccccccdccccccccccccccbccccfaake^fmdY_bigbb]ciXaZfjkghfagiTp\_bd^dfj`efafc[b^dd__ie^[b_g\ahcaWalZWejfef_jccVbf^bf[ifhhemhiih__hcZsjddV]_cU_dbkcekggdega]efjceff`h_k`[gYkcbhiYad\]gb`_dgibeeg_Wb`]^Zf_f_cc]bca[d_^lgdhhgbmh]`haab`fb`gdeechbpf`fbWfnbabe]gif_behZniTte\Zhhdehhe^bciehtceo__bbgcca`ababcc_dfkfgg_abcca_bbfed\ehf`cah`fdb`\aeeggcedecaddadcccc`ief`he`fa^cbg`cedfdafcb_hdbfdbcdfjdcgef`cdcfcbadd_bdbbbaefdebecbbddedcafafhcibfcccc`e`jeaeeddgfbbdedfecb`ed`ecabc^af_fdccbebcebdeceeif__gccce_`cd`ccbdhcaaggffZbbcdd_bdecc\bcebacn`i`bbfc_g`faccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccdccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccdcccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccbccbcddaccccaceccbbccbbbbcdbccddcdbcbbccdcecdbccbdcccddccecbcbdccbcddcdccbcccbcdddbeccdcccdcbddcdbdbcbccccddcddcccbcccaddddcdccdcdcccccccccccdcdcbdcddcddcebedccdcddcdcdccddcccbcbcbcccbdccbdcddccbbccdcccccbcceccbdccccdcdccecddccbccbcbcbcbdcdccbdecbcccccbcccc`bfRagc]c]x[e^le__mj_Wj]^e^lfrjqk[mddd]_^ndXqcZiccd[W`al_YKiqUf\eZ^c^`kj[]lsgn`^k_Vlcge_YYdajjdfbkb`emprg`wschLXnlt^_[Zf_dedaeaUjc]]akhWgjYzQYY]:\Xjcabe~Lf\k`flbhenZjYbcT]a^\^keahYlhae_gaid_\bY`bbbh\\c]_nnp`[^_^ub^m[b_aeii]bhg^oahbTm`d\fXZg\NkX]kr[dhkWidWbbcccbcccacbcccbbccbccccbcdcdcbcbcbcbdccbcbbccccccdcccbccccbcbbbcccbbcccccccccecccbcccccccbccbccbccbcccbccbcdccbcccccccbcbdbbccccdbccccccbcccccbbbcccbccddcddbccccbcdcccccccccccbcbcccbccccdcccbccabccccccbcccbbcccccccdbbcbccdbcbcccbccccccbdccbbbccccccccccccc\fd^b`h_mjfnei`^Yfak`cagl]]^_igug_bgdc]m\dQa[ebbdaX`\^k`fqaf]Zff`j`f_]o`cld^aZbZc_Vifdbh]ed[hccogpe_^ddl^hk]fZfki]deojf]Zajlflfjci^_[fZYlb`dj[paebc]knbmR`fb_f\diW_gXgkeb_mZgZcj`ghc^be`hjVe[ZZbjhpg[b][itie^fna`blcYZpefu`\fj`iRfhU_ecgh_hmgia\h\gfaijj__h`gfiakb`^]ag[gbed[[hcubbqd[bcg]a^cZ`kaW_iriheaj\eh^bfe^j[dVbTe`Z]fXdgbhiobeg[^de_`a`daa_]VdcddehgZ[dlkVYYem_`cceqa^egce[j_eikkoVhbkcfdb``^hg`dj_caa]^^]oa`j_f\dd\^dg`pca^U_h`Ub_gbdeaXZfe^gfef][_ce`h_^e\ZYc``dhd_edaXlbc_bkhbXikaeifedegeoZfbfWi`Zb]cbagZnh_`dafiim^mjaW]]a^Sab_p\]adca[i`fh[]hbkY`[^ho`gdhehe`pg]j\gkqf]jpggca_ec_rhfeaohjfemfb\ib^a]g^ccmfc]^aei`k\d\hjcYchbYfbaef]bibd_b`_`Xga_ihcjWrc`]cdhk`b`\afvg_baqmhcdfi^j\_gffaW[^`eVUaZm`Vncabdch_^jc`lYmWa^^af^idVbjhjZ]fbkeghYjW]f\f_mb``X_Z_gjjiejfr^gY\Z[YVnb^d`kh`__bebbbd_bcaebchdbfcbc_ehbdnefdh`_ebaaa`egd`jck`bege]faf_ccag`_ee`cbebec_ae^_hgabch]`^cbbaacecedggeacdedabbg`eaeeef`bd`bdefdhhb^a`\adkccfi`ddfbc`d^d\gd^^bh`_b^bhadfbafcdbdcdcfda`cdaaecdhba_edfd_b`bf`e_`b_ah`c^gfghafgcdf_baf`cfcgaccibgfhiabfdaefbadecbdcea^jbe`efdibececc^ebhcbjebbdad_df`becdebcad`dfdagebbhbbea_eccaaabg_baef]ca_a_bhd_^bcfdced^iecbeabdbb`dfcfehgbbabafbbeifddkkbhf`dedf`\`gagfhedga_af`\^afdda_b__``[d^cebceaf`badggde`geadgcdeeeicccecbad]`gfggbdebebbbcbed]cdebaddbafba]gc`fb_ge\j_`aaagedafaiccg_bb^e_eccccccdcccccbcccccccbdccccccccccbcbccdccccbcbccccbcccccccccccccdcdcccccbccccdcccccccccccccccccccccccccccccccccccdccbcccccbcccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccdccdccccccccccccccccccccccdcbcccccccccccccccccccddcccccccccdccccccdcbccccfjmfge][jjabVZeej]e\fl`Zaq^\ilio\eY^fe\akM``crdgchccehglkiqffn`pha`ddaUljaaj[dcifXxeg_e`ojfhea`c`bik]bZi`fcdcgeQ`[blnW_b[hoi_]efgb]_ccnk^am\Zfkend`ghnemVlgec]ja^__bUUfZ`eic^d[aei]ga`c[cdgjTdk`aYdr`eWilP[cba``fbkb]_[Zja`dcdY]`bebdfi\`V__ga_^hgll[igabij\^_habedccdcecccacdeeecddbdadebdeecdedccecdebbbdcfbecfdebeecdceecbbcdgcebdcdebcacceeccecbecdeacddacddaccdebccdfccbdcebdcedeadcfbbdcdeccaeccbcdeabcbcddbcddcbdccddbcacbbceaccdcdegdddcdefdbbfdcbdadbecacbdcdccbbccbcedeebdeddddcccdcdcfcaacbcccdaccbceebcecdcccebfdcdak_dWnmV_Zddgf]e`Z^Vke^jh]d`jhadhhj^brgV[_aV_`_dh`]Zkm`ilh`cgh^Vpa\[sqXje]gkfZeXZd`d_\ibbSajieWei`ghaZZ]hYb\ydKkheR[]i_bkc__ge`\kafZdU^eaNfo`Xbifesj^bjgk_]mbkhhYh`mb\de_ds^]g]db]KW[j`ldji^]]\idgWjc]TqehvgegodT``Rh_iqfeomeYm[dbb^l_m]UiZebrgaliqcVi~aeaUc_`Y`mddcdecccecdffcbccbcbabbddddcdcdfecddedceccecfadedcfadbbccbedfeadbadacedccbfcecccddedcccccbbebacddceccaccbdadedbfcdbdceaebcedbddccbafcddebddacabcbfdcdddcgb`dbbbecedbddceccaceabcfcaadbddeeccecbbccaebedfcbcbdcccdc`cccedbcbbbegddaeceebebdcbddedfcbdadeebccbbccal[e\[`r]coakbb`hiP`baf_h]^jqdobg]ecijWdw_lhcdf]q[^Yb]^`agi^c__je[mgmc]c\c`^Ydf[ecb^agh_[^c\lc_]an_qfLgg]enli\]e^cXbOcY[b]ihegf]`gfhVZ]cT_[kWbmleZdZoUcdfffjf^[i^i]affcehg`fcn_eegZ^ev{\Uio^j^_gcqe\fXbra[o`ahebgicbfrVeUai`_Yjafaf_jbi`ogggWWLdj`moaga[jdanbcb[kdedcdccbaccdecacccdbcdddccbcdecdcbabdcdddcddcdcfceccddcbcdbedcbbccbcdccdcdddaecdcccccecdbcccbccddbdddcdccccbbddcbecccccdecdbccddbbcdacedeccdccddbddddaedcbcbdcbdbdcdecddbecbcdcbbbdbdcbacccdbecdcdddddedccdcccbcebccdedcbbcbdbdcdadbeccdddgddcdccccccdbbcdbeccdcfgfd`in\heZfqb`i_U^gU]eie\oebbpcdh_djbYuofsdfi`fUalVWjkgfleblaekb_dd`e[kc_fd^`e[\]]hie[dk_gp^cfhgi^h^_fc\amhl__^_hflm\ZcYhaeafiiRdic`ucd]ie`\nY]cOiq_ec[mdsdkZ\`dU^cgl_^gatddXg_e^cahp\df^Wj_aQ^YeRkaajgdWhYpaee^dY_Z^dcj]`^bZ_lbm[Zbie\gka][ak`[uf_pdc^iqnc_shkfciejeb_iZ^_Yqeibjhc^dea][Qedfa[`ceic`q_f`]c]^_mbi^kedfY`_\wfc[[fZ\ag\gWjfeebkSagjlkde_Zdhcdi_]egje]deg^^_f\Ni_be]iRb\fdajje`]cdaXgcd]\ibW_eWXb_o_lcecgsmfg_^alZbpcblde\c]fYe`vj^jmbScfgoaeackk^i^fe^_ngh`_akl\d`_[[igdcx]bVsacbfi]^\ml]Vf^iadjckob_bfchhih^^ga`cdfbddbfcebdccdfcdabeedccbdcebccbbebbdbddbbcccebcdcc`daabbdbaeccdcedccaececedcbbdccbccfddebdddfbcddbabcddbcdbcdcccabedddcabcdcccdddecfbddbcececbdbcddddbecccebccccbcaccebaaebbccdceddbbcedabccdcdbcccchcacdbdcbdb`ccadf_acdbf``decddbccbcedcdddcebddbedbccdedcacbcbcddcdbccccbddcbcdddcccdbccdbbdcdccdcdccdbddddbcdcccccccccdccbacccccdbcddccccbdccdcccccddcbceddccdcddccdccccccccccdddccdcccdccdccdcccdccdccbcecdcbccbccccdacddccccddccccdcdceccdcbcccdccccdddbcdbcdcdebccccccccbcebcccdcdbccdcbcddbccccdbcccdccddcccdcdcdccbcwjio^b\ana`Saf^iVgc]`jceccd_fcbdo`W_[TlYl_kh\Xj`j\j_a[gceegeil_]_X\`kdgca_fcda_^Yhejkejb_cYggfce_`^afg`_fd\aasbfel`f]c_ld`fU\[iXeUagceelaffaadhbeacpc\\\Zc_^UjfifX_ebeafggfq^l]knfl`bc[iagcbfgb_khldjmeb`YZWb\b`olZXbk\Wgc`kg]a]iYd`heh^^dlfcdfg^m\l_bW[ceicd^Z]_edbbggaegdb`eabbec_edbfddcace_d`fbbdbeccfgebdccbffbe``djde_e_cd`abccfeadefdeccdbe``bff`bdfedbifdacbcibbgcdbecdaaf`ddc\bab`bc^aebhabadacadde`eba``ddcac`_efahfadaacceggaeeagdja^bfb^afdea_dfhfdbaghcgedf``cfa`ab`a_`eadef`e^difbbbcebbb`ed_be`defdedcfffeeddc`efcbddccdcdcccbcdcdbcddccbdcdccccbcdbddbbcbecccdccdccdccccbacbcbdcadedccccbcdcecbcdcdddccbacbcdccccdbbcbddbcdccccbecbccbdcccccbcdcdddccaccdcbdccebccbbcbccbccbccccccdcdcdbdbbccdccdcccccdcdbcdecbccccacdcccdccccdcccdcdcddcddcbccbdcdddbbdbcebbbcdcceddcccbdccdccdd`gdia`je_bth]VgfakYbc[iWagu`_oXc^lhf_hfch[_dgjefbZ_^mlooac]ffblcal^Xechdgbdb`cbh]_fgk^`^`[bdmf\_]che`oYRjVv\^^\Y_cYU`^dhcikg^jed_lfe^fjfebdjbaX__bbhVicyc^a`[``gjYeg][dilc^ggpafkfhbn`]`gpXd`daqfXYad\d[hg`aejaj`gdj^`Zf`_eZ_di`jhb]fduecf]dbcadgTd]Zjdcgga]d]_dbfbcfcaacda`ccbcbegabbdabbddedaccacdbecbecbgbcdabfcdbabafcbbbca`bbcdbc^dbccaebbccbdcdcefeefaaedd_decccecbdeadcedebdec`dfabdcec`dbdebdcdccdddc`c`db`cbbddbabdccbfdbdddceafbddebaccdba`ceeddcedbecbadabd_bccfccceddeddcdadaa`efccccdgbcbbbb`cbcdbabbcacacbdcc`ceecccabcbbabccdcccbcdbbbbcbccdcccacbcbcbdcbbebdcbcacdbcccccbdcbaabbbbcdabdccdcbccdbcabccddcbbbbbaddbcbccc`ccbccbccbdcccbcbbbbccdaabacdccccccbbdbabccc`b`ccecbbcccacbccbcaccdceecdcbbcbbbcdbcbcb`bcabcdcdaddadbccdcaccbbbdbcdbbbdbcbcdcbcbc`bbcccbbcbaebccbcbdbcbabC``ugb]Toc`hNmhSz`bNWcfZir]b^nfXWdgcbhjec]adjdOihqp]TWjf_[mDc`qnakla[eLhfUVgfogah]`cblbFhe]\k^fdodQeoc`cfhZbijdje[vfjjleb\biW[jl^aba\memce[akdjeejVdclcajh`bflUecca_\_chekccifebkn]Zfl`jhY`^jfirjd`gi_a]rYcbaif]dk^bbe`o`cleUYkda\oZhhWU`cdced`a[dmc^\_f`ecZemfc^Z`ejf[M\[fa[QWVham_[ckUl\n^fYd_g`ad\iX]keh^[kgjYcb]hZWQddkc[ic`^h[]i^]`]i[jilfccWahiZgcif^bsXej\dajX]rqhbj]ddagllcjfa^^u\]ae]b_heqtceafe_ahSbofc^gZ[jeWl^pi]l^ohgch^qld][pTZphZeU`hYjdie_v[g_l\hap_\HcibSe^^qik]eZeZXrb`_]hfejjniW_n\dZfmmfjjbidx^bfbjp`h]dVW`edU[`m_\u[XaVqkcY]_agd^mlqpcQ^_on`mmdVdjZ^ka`mg\ecZ`Vgk`^lLdibehdpcdMfd^\m^[`]``ag`]]qhUZPdX^SekZZ^d^`jfe]`gZ[g_\ckg`nch[\]qelamjcYTdoigi[f^kgmdfdp]diiqk_chX_kgfcnmVcWv[uY^^_`bcT\c\idfd\g^`jkjcYae`b_i\j_iaZalg`ae^Wcd]bbd_clkdkeik^^^^qeif_eighcif\gXeodah_aeT]go\dfijbe^jXlac_cseddjhk`ceg[b`da_hjc_^gjj^geae_e^bbigiTd_onugf_iaicce`hf\bfbj_gYjlgfcT`f`]n^[hed_ddfgaf]^ijfbWXc``c\eZbSnhhi_\Ze^adfdcdh^i^`eaWadnmicb^kbg`^vdighXjbmklccbcbci]h]cebg`elhrh[aib_`k`X_fge\chikcm_a`dmbf_c\gYdb[`]dakfiXh^g_hbi`Webddgbf_^b\hkcfg^ekchb`ahgg]hgYmg_bcc`gg]f[^gffhf`nhhkjflajchebkjhefb^e]d]gmid_Z]eca^jXaenfdagdidiba]if`_kd__[_ae_ae^i]gnj]m_``][_bRgfa`m^d]iiX^d\a`jdbk]eYau_efckcgad^fdcb_ecehgaccebgVdO`hbdcbfoh_ckh^cjdqc`cZ_fbeai`geb_b`Zb\de`hYWjdfh`Y_d`jadce`]^nc_[noe^epe]kf\ajba^[`Zm[_ebf^c`dd_^ga`ebckeihabcjkada]`b_`jccm_geehng_aidieaeggn[k^[hfe_ac`jhcYt`cagbff_g_\dbbgdTkjii^Ybcb^_fgkZcfe^_c`Zh`eMiefYj_Xaejbj^f_\bciae^^c`dbad_c_ZZb^`la^XafcaZhgbajbej_\bia_caid_b_]ajaeWeekdSYhbdct]n^kl^bha`^gmfdan_\bd\e_ed[c_k`Wfb_fdbafeeb^\dWcbecfi`feeek``fdfcce]ggjZcbfhi^cdcdafopdef^Year`dYcqh`hhpaa]d`\ci[g^^Z^Padgd^bU`ghfbb[`[fbcb`dk`cco[fb`_`]eYka_d^gddUgaf_kpbhheoafgba`_afb\gaidegc\pfj^Wg_bdbjXa]V`edYX^ctbiacYehb\nigeg^c`bbg[jb_ehecf__]`ddf]cikddiX_foladla]eg_d^a\^_dgdahbjanjeak`d^hgd\__cjfbeacaaahaheb`e_]k`cck_`cgj_aaeccaeddbaeec`cbcbbebbdgfbaddgbeabgbabcbddfecedfddfa`aceddgcddcceaaddcccaddgdbecd`dfd`decfdbbfe`bded`afbbccbdcgdde`ffdeb`bdcdadceeddbfcaddda``dgcbcabcdbgaecaddceaacacbd`cejeegcbbddcfbcfcd`c_bbdgccccadbfdcccdcfbdafdediadbdbledcedeeccedeceeef^fcacdebagcccebccccccccccccccbcccdccccccccbcccccccccccccccccccccccddccccccccccccbcdccccccbcbcbcccccbccccccccccccccddccccccccbcdccccddbccdccccccccddcccccccbcccdcccccccdbccccccccccdccddccdccccccccccccdccccccccccdccccbcdcccccccdcbccccccccccccccccccccddcccccdccbccdcccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccbcccccccccccbccccbcdcccccdccbcccbccbcccccccccccccccccdcccccbccccccccdccbccccccccccccccccccccdcdcccccccccccccccccccccccccccbcccccccccccccccccdcccccccccccdccccccccccccccccccccccdcccccccccccbccdcdccccccccccbccccccccccdccccccccccccccdcdccccccdecfbdbcdcabedeaadcbabdccccdbbedcdacccdcdcdeccdbcbcedccecbccddfb`dcebddbdecbceacdbddbcdbaddbecdbcccdffd`dceaceabdcbedccdddaddceaebbbdcccaeccedddec`bbddfbdcebbcbcdccddadedefccccbbbddbdcccecccfdeddecdccbcccccabbdecbccdeddccdfcadccaccdacdceddcccccabbbccfedcddc_dbec`dgfa_jchlhe_dfcdbbcdbahdf`ie]hcldgafcdgT`cgibc]hbmc`ef]cg`agafdg^fjk]anghk^aad`j]b[`_e`^j^c`h]bb`bldf\c_hdagc|d`a^^delcdlibce`cafnkig^ej^`]_b^`kXdkhbb^b`cefcehjafmeai`abcYg`dcehad[]Xifa]cch[eaf_cYd`dlj\bh[bm`b]a^`]c_lifkbebc^Z``ch_bgchhbbfee_heefbmkbcch`]fSZfd[_eUefZcbefn?\bt^dWbck`bX]dagr[`e[dg^jbbhn`cdb`g`bgch`gl`nj[ee_Vb_Ul`^^^YddhZdgfe_heid_]kh\hem`ffhaiiYfj[`bbim^`gc]^[cfjcked`i`]hdZjW_[calekcaa`a]j]lgjcpaqaitbe[f_hilic[fh_a]ogoah^daY]oeqd]ahkbabm[d\qhc]]kb^akf__\c]eb`dlchVg]cb_\fagb`defe]`ebkbccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccagcahegc[g_^cd`dX[^a[cgdeeQag^`hgehggc`efa]e`]fdcdaac^`fac`baffe]a`_accbcbc]bhb\bga`fejiac`bbf]i]_jgcbedfijfgbdacbcjcc``^b_dihQhgdbf^ge^abbcfjgeZbacbh_db`e_ba_adhgef\^cbdebcab`g`idhce^ahhbh]ad`bbdc]he`cjgdfn`hcdjigb^dcfhhjma``a_d]`fda`i^acffh^fh_eg\aae^ghibcaccfdabdccc`cbddbdcaddcbbbdaabcbccdbbefddceccbcdceccbdbcccbfeccdccbcddcbcdcbbdadcdeaececcbbc`bbddbbaddddfcdbcaebbccdfbedcdddacceedadaaddcddedeccb`dbad`becccebcdbbadbcccdfddccaccbbbbbcccbcbceabdbcaaecbdccbcdafaedaddccedbdccdccdccccdcececbbdbbbda`debccdddedbcbcbcbdcdcdbcdeecbdbdcc`bbccbaccbddcdccdccbddbeccdccdbbddfacbacdcccccbbdbcccbdcbcbcbddac`ebcabcdccdbccdccaaccddcccccdcdccbcbdbabbcdccbcccdbccedbbcdbceabdcccbcbdbcdccdcccbbdbddbcebdbcdccccccbdcddddbcbdebcceccbbcccdbcfdbabcdcebcdcbcbcccdaddbcdccdadaddddbbbccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccdcbabcdccccbdccacbc`dcecacacbadbabdbccbadbbabbcbbbcedceeaccdddadbdcdcbbbbddbaceecdcdddcdbb`dcebddbdbbabcbdbbccbcbadbceccdccbebbdfdbbbcbcaccdbdcecdbbgbcgdbecbbcabdadabccbfdbcdaccdcbcadcbddabcecccbcecbccdabdddbdaacaccbbabdbcccccccbfcdbbbecebcdadccaadcecccaddcccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccdadbddbdcccecdccdcbadaebccccdcccdcbbbccceccccccbcccecbbebdcedbdcacccdcddbcbacbccccbbddcccddcbccbbdcbccdbcdefbdbcdbdcbddbcccdcdcdddceecccddcdcccbaccdcdcfbcbdcccddcccccecdbdccbbebbacbdcccccdcdcccdccccbcbdcdcbcccabecbeccebbccbcbccabcbcbbabbcdcdbcddebcdbdcbbcbad]eacc[cafcccacedeccbf`fcdebdbcabdaceddcb`f\gd^`h`^ceac`bhcaccc^cacc_bb`gebegc\ebegabfec`ade`ciba_dcc^bcaadddh_bfaeeaaefZcah__^adaedcehbd^c_`c`cdaceaedgcce\a_ae`bccd``lbaidccegag_a_debddbbedbcb_b_eabaiedcdcaabfg`caca_bdeedeefc_gdc^bccfdcbecaecaeafccceacbfkfekde]hcldfi_^YcchcYde`igda^ikg]]d`ebhd`e_ffdfa`Ya`f]ld`cg^]ebi`gZ`lc[heehaFfkb_a]gdad]`]hjbc_bdg\fckjhj[^eiefdefagdcjh`befgheYe]afb\jd_hcib^bl]_cdX[dbjeh_fcn`m[e^_abjgaa^dcgb`jc^]c`f^Z`cbXemgeb`cgjcba`a]ba^b`faddhcc`_d_dlib]gakc[hhae_ccdad`d^fkc`edhbjg^ccccdcccbcccccccccbccccbccccccccccccccccccccbccccccccccccccdcccccbcccccccccbcccbcccccccccccccccccccccccccccccccdccccdbccccccccccccccccccccccccccdcccbcccbccccccccdcccccccccccccdccccccccccccccccccccccccccccccccccccccccccccccccccdccccccccccccccccccccccccbccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccbcccccccccccccccccccccccccccccccccccccccbccccccccccccccccccbccccccccccccccccccccbcccccccccccccccccccccccccccccccbcccbccccbcbcccccccccccccbccccccccccccccccbccdcccccccccbccccbccccbcccccccccccccccccccccccccccccccccccbccccccccdccccbccccccccccccccbcccccccccccccccccccccbccccccccccccccccccccbcccccccccccccccccccccccccbccccccccccccccccccccccccccccccccccccccccccccccccccccccccbcccccccccbccccccccccccccccccccccccccccccccccccccccccccbcccccccccccccccccccccccccccccccccccccccccccccccccbccccccccccccccccdcccccdcccccccccdcbcdccbccdccccbbcbcccbccccccddcccccccccccdccdbbdbcdccccccccccccccccccbcccccccbccccccccccccdcccccdccccccdccdccccdbccccdcccbbccbcccccccccbcccccccccccdcdcccccccccccccccccccccccbcccccccccdcccccccdccbcccbccccccbccccccdcdccccccccccccccbccdcccccdcccccccbccdbcccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc`dcb_dgYdbi_c`engbYWZ\``mZ^`bge\ghdk^dlh]e]QUidcd_ekj^a_e_a[bkbped``\eoecfkf`c[Yifd\icnk]`bnegjc[_aaaScb_gahgba\g\c`bocl`efcg[c_]dbjecei\jfh[ecle`bbd]hj`ag_gii^[bjcfbca^blcfh\X`ahefcekZ_e^j_kN[d[aY]eagdYj]p_feaae`\cbYe_n_be^e`[bj]ddd^ZX]jihf\ahcdfmdfc]dp^eccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccbccccccccccccccccccccccccccccbcccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccbcccccccbbccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccbccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccbccbccccccbcccccccccccccccccccccccccbcccccccccccccccccccccccccccccccccccccccccccccccccccccccbcccccccccccccbcccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccaabfacdc`ddbc`accebadbdddaccbadddaccae``bccdadbccbe_bbde_aedcdfddfccbbdd`cccfdcaccadadecebbaabbabebdd`cdec^dagccaccdccccacabdccb`cc`cbbbecadfeccdcbc``dc_cfbddcgccbdcca_cdddccccfacdbfbad`b`bbcceabbcbadebdaedfde`cddbfdcabacbcc`ebacaaaebdeeacc_cdcfdacdbcbebdecccccccccccccccccccccccccbcccccccccccccccccbbbccccccccccccccccccdccccccccccbccccccccccccccccccccbccccbccccccccccccccccdcccccccccccccccccccbccccccccbccccccccbcccccccbccccccccccccccccccccccccccbccccccccccccccccccccccccccccccccccccccccccbccccccccccccccccccccccccccbcccccccccccccccccccccccccbccccccccccccbcccccbccccccbcccccccccccccccccccccccccccccccccccbcccccccccccccccccccccccccccccccccccccccbccccbcccccccccccccccccccccccccbccccccccccccbccccccccccccccccccccccccccccccccccccccccccbccccccbccccccccccbcccccdcccccccccccidg]iEdh`Srcei_]m`hda\kecfeflc`abec]Yicmdigcfd\a\`d_`hgfd^caec]kaZd\bifbeegeb\c]lj`db`il]ebkjZbgha\ba[eb^eN[ei\c]f]ajgYebdaaf`k`V_li`Y`mn^j^^odnjdnachema[f`loh\bZcdigkadok_cfYc\__b]d_bi_e_deb^_k_ac[kek`^`\d`figabfaia^ac^Y^b\i]aace`[]dif_d`nW\gafhf^hde\faab_mjkWd\koklck[dmVefkf[`rrd^cpac^UqWcW]e\ggi_jl\aflYdmchcebndcaefcadbcm]haehYZl`Y`lhe_Zi`dcab[ni_gio\a_ihcgibcgdaa[_`]fccj]\cl[mjjd]`afhj]\hbgi_al_bbiaidf\fah\fk9iiUg[][f\f`bc`_ghdef\\b`hdgliejc^^]^cX^YcIieejhfdac`cbg`cidbCdgadckej^WjbeYddagdjdbc_li`cj\ihf[cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccclQ\e_fcch`bdf_\hXh]e`mc`dgdadeb]j^^khc`gdjfbedkfaeicg]cfdcbjbdeahiahgckf`gd_bgahb^gael[_iZd_dM`]_eficci^egicd_`d]g`hcjbcfgd_ak_ca^b`eek^bf^``eg^Pdja]c\Aa_a`_dggecgd]backea_bah^bhld`dccahhg^fff`dfd^^befld\`ccUbfU\_m_`i_f_knchh[_cgccec^^f]`dr`^gcgd_]]agddgehccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccbghd_ag\\dciogclWfe^bed^il`fk_]_alY`f`gchOdRdgVf\Vebhd^f_ecZY_f[`dV]ikUhWbacbp_dfdVUglfadccgcoh\l`rdmbnifkifcf`afagcccndhfai^ba`g^ihj^^j_\cmicj^fdcod[``aeai`gjdU_dq[bXYldfZ^`dc\bglecfl^d]feb`_hkebZhqbdpcf_bbdkbefma`hc^ifbkfdd_d[ame]fbTaYjfQocbgbjbbk_Ylgb]bbghgahYgae`eaeebd_XZgb^\ncagNa^_c_hftbjps[cbckhjda^Vc^gchhde`n\^_\`ogccaghYc_[hmhafflkahacYffcOdgaedmhcbdek[hedd^ffck_bfcX`cmje[bcad[_g[n_eedchhmheehce_dhbdabc`p`]h`h`b\^ha_dge^m]dgXcgabccRgUbcdkiicd\sekZ`cd]ageehgd`fhc_qqgdf^a^adc_flgbec`Z_fa_codeb_if[__eRbZe^bgg_`Zdkie^e^bc\]bWjah_hfa[_bdgbg\g[\dXbeede_fc^^ehbahfafhad[`ifj`fXgcdh]im\j\ceedg`ee`ek_g`f``jbnhdhZbh^biddidd]k]__ZiZh`edd_cc_VdiaX\rh`cagejm_iga_fibjfecgccbc\eYWc\bfkkegfjZf`djbdggkoj^fb^d`a]cfn`hcadbfpbgc`aheh^kakfc[aZkcjjd`]hgicgdccbWbgjeae`S_d[cccccccccccccccbcccbcccccccccccbccccccccccccbcccccccccccccccccbcccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccbccccccccccccccccccccccccccccccdcccccccccccccccccccccccccbcccccccccccccccccccccccccccccccccccccccccccccbcccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccbcccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccbcccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccdcccccccccdcccccccccccccccccccccccccccccccdccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccdcccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccd^Xhdq`eaV_dk^[`agi\mlcbbchbhY`_gdebaib`ad``]]esf[bjhl_ag\fgbh^^idb]ib^iafhmffhfkhejccbmjbiao[_Wgidc]]baa\eaj`abcfgS\Ye``ba\]e_U[ajf`deebg\a`_]^cc_hdZ[dga`idbhUf_]`dhfneeZSc[joY]fcbd^g^g`_cfffg_c_hdlZi`kkce`c_haag`cf^\eaebd^^\`^dbiWck[ahwb_`fZh\\Y]e^bkbn`Xfbbn[_ctglPahfdaafecb^ejlfb]efib``od`fVcenlbmeafdidig^ccdZkh`_h^c^abcL]nfZ`i\_[`[`jhjgPhlnfb^ja_aeodg]`f^mdfdVRhkfagaZboPig`X`]macbfcnaTc_jd`h`[]aadW`lWa`^b^fpli`e_g]Vc\egb`d`f]XXeef_focecklf`_bc^`j[aa^nk]naacbcgij`ahclad[ld\Z``fUdebcbfmZfumiaedgaj\eabf\faZdXkeiieb]p`iWeemlX>X^dZjaSa]^]_oT^cje\^cmedXd^kakb`dmej^acibd\kd\lg`adfxd_W[fdil]`[cfwfch\o\k`mSbc_]`ZxXkd`ndd_gXhhdillZi`biUcZ_jfmbeab^cmdk_mmqgchq`gfceg]bjhW`meii[k`lge`dg^dfd\aagabh_c^m\le\`ih[bb^_lcgmd_d_ahf_Yj^Ufg]`c_jbeiUe`^ep^belfgcXe]`beeigg[kh\fmkdm_Ocejmc`^jc_\[fk[nd`hl^\^dcQaZlgcgbgib[^gcfkicfXei`bb`^beZZbca\gbeThhnc_c^]fPjh_gdic_gbgemilbVegmcgheeldb]^^eXe``a\cYfkk[]o\bbd`P]eebbb_a`fc^[idceg[Tdabd_afrk[hiicdld_gbac]a]`i^o[ffc]`aiiZg_g`d^e\clt`[cj[][c_]hggdedejg]bdS^\_edba_bdfhacnW]n\fk`fWjaddkocadcfi_dc_d`h`dgfcadb]eabacabbacbh`aeeadbbb`ddgfg`f^bbdbacdaefddebdd`eaa_ee]eabbadbdf`cbfefabee^ccggdda^e^ddbb`gaagcbfbhcbbbcdfaa`b^becda`eagab`eh``gbdeegcdebbcbadaabbcdc]d_bcbgddachecbab``_dbgdeadeaaa`dcdaecdb`bfc`dfedacecbadac``dcfc`bcdbdaadgcibgebdec`abdccccccccccccdccccdccccccccccccdcccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccdccccccccccdccbcccccccbccccccccccccccccccccccccccccccccccccccccccccdcdccccccccccccccccccccccccccccccccccbcccccccccccccccccccccccccbccccdcccccccdcccbccccccccadcbcbbcbbccaccbcbbcbbdcbbcbbaccbcbcbcabcbbbbccbcabbccabcccbcbbbcbbbccccccbba`bbccbabcccccdbccbbccbcdbbcccdabbbacacbcbdbcccbcccabcbbdbcccbbdcabccccbcbbcfbbdbbcbbcbcccbbbbcdccbcbbbcbcbbcbbcbcbbcbbbccbccbbccabbbcbcccbcacccbcbccccccbdabccbdbbbbccadaccbcccbbcdccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccgcYeZdff[iV`uhWg^cbgn\^dmc_bii]gjTfacmadWjjmaa`eg^gdk_`gae\c\hfc^`ffSRgcUfa\`mb_dja\fjabjYf]^dg^WWcgbme_lgohhYeoekfenhdZffXmdga_efa_b\ajafa[edZfagakecc\Za^aYhenccohk^`kdY_cc]af^i_bbg^^bk_e^_^VZekfa`g]aceZihcip_^c]j_Sb`n\]ggZdgbcoke\[g[nffagse```_]^mcdn]h\gfhfecx`eohg[debd\h`labeed^[be^^mf_cficbdichmdbamee]`mf_^fg`g^_idiZdb`fcimb^ead\ee]nibVqcgfb`ac]eclaXgabefbeec_dbcele^_c]ib`fgcbga\g\]imadce^\_m`hkgad]Y\jh[ccZib_gbkke`mia`^dc_bh_bff\[f_hcjfdajc_gb`ZjaTcageZj`bgUc]id_fka`d`gifjkbdkdfg\h\f_aaatZdha_c^[a`mjigccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccdaj\leLkggj[ag^mgdjhfdhWqdciXiac_i\im\pdio`bqhacbZ^^e`d`^dm^cc_]b[ajlb]cfc_kaa^ad`^ibflhfkgflkqdiicf_^aY[nab\bhaHic_m_agjUh[d_p\ccaj[cjaU^ec\na`pbfggnglcamicdlTe_c^el_ddWkbjdX`ck`ecm`gblf`b_Y]aj\iWhiYafZ^eb`h^ih[_Zb_g_c`giGc]daj]caUac`\fb_Xaifdghch^fa\`b[[ccccccccccccccccccbbcccccccccccbcccccccbbccccbccccbccbbccbccccbcccccccccccccccccccbcccccbbbccccccccccccccccccccdccccccdcccbcccccbcccccccccbcbcccccccccccccccccccccccbccccccccccccccccccccccbccccccccbcccccccccbcccccccccccbcccbcccccccccccbbccccbccccccccccccccccccccccccccccccccccccccccbbccccccccccccccccccccccccccbcccccccccccccbbccccccccccccccccccccccccbcccccccccccccccccdccccccccccccccbbcccccccccccccccccccbccccccdccccccccccccccccccccccccccccccccbccccccccccccccccccccccccccbccccccccccccbccccccccccccccccccccccccccccfmg]`jXghcX]cmhn^k_ei`_]h^f`Y`gaZ]_aqYl\]fbm`cbW\X]eagZ^l]b]_^ogaaicVk]h_g`fXbgndnVd_chch^n`ami\dl[Yoin^ge`i^ccdnab_hbfhcbli[p^ZfZ^^\je]^hYcf_d`dijd\ccZ[Z^j_hcji]Wdddbba]_]`acias]^ecsg[\\^hbgjabbmfifefggUa^cd`^ejkZ`ci_n]ae__egdreYeghafn^dfZcmp`ed[aab^dpfbgcbcbccccccccccdccdbcccccccccccccccccdcccccccccccccbccdcccccccccccccdcccccccccdccccccccccccccccdcccccccccccccccccccbdccddcccccccccccccccccccccccccccccccccccccccccccccccccddcccccccccdccccccccccccccccccccccccccdcccccccccccccdccccccccbcdccccccdccdccccccccccccdcccccccccccccccccccccccccccccccccccccccccccccccccccccccccbcccccccccccccccccccccccccccccccccccccccccccccccccccccdccccccccccccccccccccccccccccccccccccccccccccccccccccbcccccccccccccccccccccccccccbcccccccccccccccccccccccccccbcccccccccccdccccccccccccccccccccccdacama^f]l[[bjcd^hie\W^b`ia``eim_kYZdedWjae`ngabbfb^iic`b_Vg[bhaj^aZWbjcd^aagen```k_gheZc`iifdl\\ccc_k[Vic`\nbX]hZe_bhp\`big`nk]jb_`lkadab\ak``c`cg[bg`Sgjbcggc^eea_fjmaeie`hlbemagbdfgdh^cc`ihgebid]hlfbYg_eih^[ia]^ljkfcb[afg`ebj^f^^g]`YbgpecUZbrg`eda_kbl_c^`hjaibdmbbfnYaejbfdk^fqf^\YccccijVk]elj`ekdd_djZ`cd_nmgdZbYghlbd`f]kfcpf]g]\]_djYa`]im\Zhdc`ebpdxbcfe_cdi_bm_f^kah_gdg``Y`U^i^dgdcV\gXibnk\\_fa`cghck\]dbe`]_c^icfe[^cW`ZXTap^cbgo^_Zfagcac^\eZcecdX_]^d^hfm[bajU`^s^jYd^hTabdfoge^`hf^eeb\jlfjed`b`pf`^`]i]_d]\fa]^cdm_[acfd\hcla\ZgXle]^\aYbffcbV\`ZpXjcfdcg\dcY\`_gdccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccdpVmhfbabnfibljhd\c`[e\bbebc[fdcmab[e]^_c_a`ffbi`iZdgk`b_l^`bkc`bdcae_dehm^b]d]fibkaT`cbjfjbiebmYdpg_hbjXdm^fgb]dag[mbedVewge_Zdgeabhd]_Segi`c[YjZcacb^js_g`e\c^_dfacjja_ZgeL_cc`ccbebchSc^heb`]de^bd]a`Ndag]_]f]iai^`geheabf`j`dT_`mmgfkbe_]fe`bhkgr_ecfb]iYedjcccccccccccccccccccbccccccccccccccccccccccccccccccccbccccccccccccdcccccccccccccccccccccccccccccccbccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccbccccccccccccccccccccbcccccccccccccccccccccccccccccccccccccccccccbccccccccccccd_dabgljgcd_^eVhf`g`a[X]h[bVjk`bja]g]hccp[]\b^dYbsi]j_abcdaebeiZX_i]qihede^_fan`ibtae`cidk^b\ZgdgZ[`kZ_hc_\^nm`[jjaudbabZ`d^ZVddf]ai``iedbZf_f]e`naei[cePc^]`_k_adk`bf_qbbjfgg`e_cffabcibdea\e^ccj_fcb\^]^dk`cYhdd]Ycid\ce\jtmZ^b`[bdc`Z`Z_Xceihebaj\o`icjd_Ue\ZZY`]ig]abOc]gcgj^e]m`]e[f_eheae`fih_l^fehb`^atgc_^ZWbh^bed\Yei\dhbq]dmjim__fbYefmhfcbcabW^`b\d`cakecYVshcacjgb\hdeack]djkam_egbbQ`ck`]```[lheg`jhcnhd_bbfZjbafc_aqajgZb[kne_]Xacb`cc`dk^dRackb`d_ecgebegj`a`]fbhcefafhef`_mejncqfj`bh`adoeaWbffhaffbkfgeR\]b`adeccdcccbcccbcccdccccccbcccdcbcccbccdccccccccdccdcdccccbccccccbebcdbcccdcbcccccdbbcccccccbbccbcccccccdecceccbbcbcbcccccddccbbcccbbcccddbccdccbcbbcdccbbccccbdccccccccccdcddbcccdcdccccdcddbcdccccccccccbdccccccdcdcdcbcbdcdcbdcdcbccccbbcbcdbbbdcdccddcbcbcdbbcccc_eb]Vyifb^^jaegamdeflcdbhXah]okY\iafhbZ`f_ld`fe`m_aflegen`[he[WZc[]_^deoZbacjYY]fllncfal[]cg\aiYd]if^bialamdfcde_db]kf^jefV]ki^hacTTg\jdfk`c``aal[feaigdibffjZMngi^cdi`X_gZegZtj`p[fdbdb[b]aijhc^_fjgg`eo_`^`me[l_`hdejh_k^_a_bkfegriVhcodafih^hoccWl^eaa]ejf][f㨓lvPœ{{Rcbwy@wQ`tnpqm+y_NgvZ^ Q\>w{|ss]gٸY[tbsʕ[N{RhT%<}AJr}㰋xogp{"{nyZqpjpvy8ІzywsuA6*C191-1GCPF}I$,E(@?(,2@:,?9.5F7(JIZ%h)7ܭB?J(X2{.*64,$(,ATq4/=NS"\eEL5D'%4&@J?JJI *7 A:+P'+@@?R-I(,2GMX(;24] +u';B 8 A)Q+?a[6-&+"NdN%U5kX? 37!T1?$=9/:&M9=6C,D'3+:9W+0.T4J8m=QC&;-0Q>53: +4,AjCs1@>6C;Ck|p]Kj`fUM}@jjtL|upgJuv|Bj||_(RUKgzBt_v}lrlkoX6}w`z|V^IbHynTPWNusGk^{Mjd9vmiv~mCBzxypIwWe6ZmhtW^izvjWVEeDcoY:hwmo]ǭHY_~6vn_knsƼıÿʹƳøƼ¹¯Ÿ²dzЫʽŖʸͽɹŸիīʮѕųwÞ˼Рù²ʚ̨ʀȭçĴʲŷ¦кƻ¸ïɾȪưý̹˿ĿúƬñ¸ʺŶɽÇǾѺ͹µòʳøŨɳйȰǷųÙû¶yñŻƹì˻²ôȼį­ļƺտˮºƠ͵Ѥ³͹ħϲŮ»ƬŪŴǭǭȲƩŦ˼µϦĭŰåÖƴɰȨŸĺ~Ǵа­ʭ´ЪǿȪ¯̵͢ȻĦϮǻDzú̞Ź͹ѶԳđIJŨӪļɸĝǹƳȺªƻŴҸóúŽǽűʅùǫŦҩƳɩģñƺ˴˭Ժ͝Ȧï¥̷ĩ÷ľȺɩ½ƢĖǵůûȼĴûڨǼª°ίֺǷʪȾ°‹˽ªŢ¨ɨ¾çĴ˙ǺŠͦ˹úǯ˧ȽãļƾøΪŽ˼̴Ţģãǡù\ȧͱľäƻΡźƴüΧøŭîãçĭʰɺǵ²ʦĺʥʳ´ĬȭʗŵÝɼæȘŮʹsŤǨɴʨŶʳïò¢̻ÛͻΥèʥƼĵǺخƾƢøµʥïƾҰ˸ʶĹ˕ɴ}ĩŸ—ͳѳƼýɶƵŲʰåǩ˽ęϤ¨ȭų¼үʭҴį́ͨ׼żĶ¶ĩŝŷʱEϲ§ɲģ֯īƻïŭӨóĽůƺ˹ţ°ɶͫƺťȹġ˭Ť̴̯xʶçǮÿ¸Ұþĺ­½ɲˮiĪ´ƻ»æŶ¾Ļjʰʱ¯ǵĦӫƴķ±ʧǨƽϻŽűл˦ŸķǷī˪ȵüҴǶøЦϸ˲ǿƼ϶UÙģź¡DZлĮǖһթǯǩϟĨ¦ҴįǬƶ¬µųȾĿøůǩǷĵȫǣŹĿ˼ϧì¸ПĹóѬȑǺϻȯíñɳòͬȽӵ¾˨þ·ά̻ͭҪӤǬ±Ƽ̬̫÷ÿƙ̡̹ơȸƒžĮ͛Ү˶ǭ˦͸°̳Ѹǻշǿʷþ̹ƻòǴˤƻåïĬĴĴųȲбìõüȵʹŬĿ¢¯›ŵǎʲƼ}Ҵͷ¡«¬üƪü¨žɽŶüø¶ƧĻïʪ³vğҳȷ®Դ³ͷùƶѹԬǰƫȱŪɰʻԻ̏Ǹ§Йɶϱֲƽ̵̢ЦɥʹͰƬеȸǷвŦƩѬݳ¸ŰŘ˝ոлݺ¨ʭپʲ¨կ͵ȴճʭ®ȭİʹǸ׻ɶĢɵº˫̺ƫļƢżúǾ¨˻ƴù̲ɻ˺ůž¬³ʭ³˾ǻǶê®ͧªŸǟü̪·þťźIJȭȰ֩;ȿĹɯʳij½¥ʴر®ø¾¸ͰŴúŹұ1ξĠ̠ƼǮϮķǛǷƾ­ô¹ƳĺȳŶĴ´êƵûĶǭ­δʹ¼ƹ̤ФʭéĕæʱƤ;ʾijʮƻ׮˸˿ī¼ճƼɸƶüþýȿȮ˹űëģò¼²˹ųźå·İŸѦǾɲݲˡԸŽЧŠ̾ūʪԮġǨҨөŭŵƺ÷IJԤƮĮοȵӯпɸښ̿ͲԲƧΤʶڡάƻ٘ЭױͽĵؿñǷɬįƳУιľƺٷϴĶô¡ñƫǸŽ̝ƶȸȕǻȣï̼ͧƺý¨ĿŚëùͨϴʦǿǺ»ƽɝ¾ȿưϳʭïРôͮĩĴ¸ìƫͮŹj±£ǧ̬ƯΨըʩž´̞¸ɸɳ½Žȵ˷ƫǯíůɪø˾ʧ/̦ʶȯ³è±©٧ūǡñʫҾɻƾŵ¶δ¶²ݦ̬øŲŴϽմżþûųȿмάĬǥ̵ĤצŸơºιϷö°ŵû’¹Ǻó®Ⱦʯī²ijęȭŬʱķıąĿʼƩǦʮ̸8Ŷĺ½ŵ³ǯί¹ŴƳΡɳʺθ˷ķƲĩűǾžʵʮʳƬçǮħ½ûҿìƸϧǨ͸ñɘ­ĺïҲĤǵʿ¾ľƯpƱˣ̕ɸȰ»ŰǨ¹ŭƣ“ƹɻúʦ»ȻŸ·¼ȪȞ³é$þɰƺ¶ťȷ˸œǶϏºƮͯʠͰʰϿīѻººųʴɰ̦˺ܮûɷǺǬş¢Өʦ˼нƢ̮⾿˲ӖˬҰѸ‚±¿кί¶ǽȹǹſdz͹Ϳ¬ıȶ¶Ǫͥëʷ½õŵŨźȫ~ӊȳʭ̨ϧэìšƦƲıД¶Ͽǹё͸®îȫͶȱIJųķĸɺĭǺô²ɳþΦçͲдʝ%ͬdzЭϼμž˼˿ʫʽȫٲ4ʨͤϺȘѧµĝ¨ɟ˷˺ͺ˛½ːί̻ƫɻ˷Ÿ˿;ӽDzǺʸưƩϥºѷ٭̳ǿ̫ܲͱӌſϓͮŔΫҷͨƐǫϥȴͮȴӰԨdzɰΩ˪ͯ۹ø¢ʷʶƯȸɸ͵àɹźƗ»´ɨĹ¹ķ+şŸܯŞʰ϶̶›ʗïƹ̺ŭ«̻˫ͧαȷΝ͝¥ĸ·ŶĪɷöƭêĿèΤŷǻvǘýťֶȰǾðȸƷźͼ̵ѽũé̸Į˷Գ³̹ΧƹǷϴƯ͟ʺé̢Įƫķɰ¸­Ǽź´˹ʬ°̭ŲܺȧúƺĶŸȼ̾úªȻĵŞŸ̩Ÿͭ¬džûWñÞ°Ǯƿ³¼ȫîĵûüͲòȬ߯ýôͽǺаͼ³ȦúɿʳЯƧǶӜŶ̶ǝ÷ŮƿĽƝèˤƬ»ǽūÞʛªŠůƽϭóĒĿƻ¹ǷƿĕͰƴȰūĶǖɲ̮ҷƷĸɩȶõһķƭšƵ˴Ȍ÷éîѺµ´ř¸Ɵنƽ̼Úóҿǽþк¼é×ɰǼԯį÷ȭ͵Ʋиέÿ̱dz³˷DZ®˸ʹ°ò´žοḲΨѠȦɱҬə¹ĿĸҰ˲ţħ¹˸ԪŲʩ;Ɯ«ж΢èóѴľȶ̥ƽɲƽ¸ͻ÷٧þã̽ѼմͿǷߴϼ˷ßϯĥįȽŦǟűŬªͶֳͯæȥê̼˥͵¿ήƵ´ŮİéʱȺ˻ɵ̱Š˥÷յ˼ƢˀڹƸг˻ӳïv̱ŸĵŶ¾Ȥȷ´ɹƲзūžù̴ʺƮбƴɸżɷȮȾɴ˸ɦĿîǭܞ´ŵșǯǴùҽ´÷ŭ֪˨żçɦȟɽǪǹ©ϳʸ¨ƯźΘñ|ȨŹ׸ʽخ̬²½̳úåͬʺ˨¶ȤÿƴѺȯʸ¹¾ӯʱƩеכĸ̶γ˯ʸºĦԫի̷ʮэƹϯƢ͵ʵ³ɨƫ¶°ĬЦñʽı޶dzjùǛˮìϼׯͫũìëȨİǴɺȤĥĶͧŷƬƳµƷ˺ɠ»˪ųͽЩԪůۺm¾Ŭ͵¡ƈµ«¥ųÞȢǾƼĜóҲþȰżijĴDZ÷şŹĺηɬ߯ëǸ٤óȴ˰Ħʠɼìɣќ̧ȱƵƚǽ˱ʱóêwȖŽϽʼũþɣøȥ̸Bڞȹšñՙĭ˾ǠƫɬϧijͻƯųϳȮǵü¼ǽǶȷ̲ͺŧĵ̿Ĭӿʾ÷˷ɬĦ׳ɠàƤ%ŨͲֳ˿űȺơȴ̝ĴžӸĹįɴʸɴǴ&իǹ¯ƩЯľɾŹŘǫƧ֦Ⱦ˧¤Ğаºպúʰ²ìƿŵȼ©ŽµɲȩƵǾɣźͦƳơȸȾǽ½±α¸ªɽȾħǻººǤŷŲľʰůǠůԫȣŹ߳̽ɸ˻ͼǸ̦ԥż̯ǦϫȵؼŲԵҮԲ߿ʱʿǦʹʯ̤Ƣȹڼӯ¨ϰĵӬӭޯʬȹȸȲǾ±ѷͱЫӳDzǤӨǮ϶þũ·˚óǿŬ͸Ƨưöķź˷ŧùßͨǼѻǷƹµ´ķҝµνDZíıyȲùʚáμ±ƌó÷ÝɸƼεȨ¹êнջ̺ƪƺǴ̹ԵʰпȽʬ˫ǿηɳǧǷ̸ı¿ϰɥ͸Ǧ®Ö·˨ͻ±ʖŸɹŝճɩѹĤïǸϯԽטžȲͿ̴ưų̨ѹżܰͶ͐˭ŠĮϫӹñȡ̫ŝΰòƭϰɿſǺɯĬƿƼͿ¶ѫΡѯǦҵºʥĭٸȾ©ƴʹé˯ѹеи޴пϭҷðحԮĿǶŰ㵶ýǴйˮְɬǯܺϿ¯ìϡµȵ˲û̮՝Ĺ׸¯ʹ˩ԿܬƽĨĦǻ̸޶¹ƿñگ²ƯȺľͥ͹ȲǵŒưŹϹξذҺ»İşОǯͼŴѻȮĢƿʲַ̪Ƶη³ɥí̫ͳçɥþȭü´żǰɵ̡ºzθ³ɿĹڦë¨DzƵįݸȷDzʱθ٢֤ţȵ¯ѽij¡Ǿòªȭǰأ͹Щŵɹ˽ɺżϹͯǾȼǸɳʺįijŴ̰Ýε÷ʳ̸۳ư٭иɮȵïɹ±ðʯαǠҺ՛ĺǯüƿȾЯñòׯ˟¬µʷͷ̽Өǵ¸š»¨óʺůʯչ´Ƶʞ~̵ɾŻƸեʹ㹮ӽם϶ͲƺžΜäüƹɬıºȴЯȬĩԵƩ̱ǞŨʱĹ۷ʴaöğò˰㻭ǬƵļǡҝŶĩߞŖȫԭǼĻ~ʠǽ̱¸úͬ´¶ʺúç͑κý̳ţ÷˞–НʶŰǶ®ƭĶķ®©ưfʮŵųʿǹŭʿ²²˷ìͫŻýϫķţĥù²ƹƭǴ½­ʵªūxȗŲɶŽĵûºŽƷijˬ°þòͳɨı˱ȮƪļðǥµǛ´̕ʿܼįÝѵмǛ©IJdz̽ȶӿγĿDzԨǪƬìǫijåƿ÷ijƺʿèľzùƜî¼Ƽĺ«ŴğżƞĸƴβKɷ̲˺İ˗¼¸ƼÛijɬԭūɝĦʦĽôIJ¦ॿ¾DZ±˻ƹϨͲŲʡվDZҰȽ²øŷҫ̲ʤ٭ˣȬƵΩŲĵɗǾŵΰӳ̨ƞ˵ɵɷ³ΨƯ¿ŬƝĦӳϲǤƹ¾ʼºêıȤʩëĹĥլκĵŨñ˺׿øMŷӦʭͽưɼưΫԴùǸȫŻɵôɴ÷ȷįȪ½ŔӞŠḷֹ́ɲúơȣȸĿڦŲȣ˾Ȟ—°õœƧʺʸɸ´͸ϭȻɾƾƛŲĨƬ¨ƻɲƫäȱtŵͫóȳǯǷГȲϿŋȼŸĮĶDzǺɽƼѵ÷ƺ¶ļDZ§ê(ƵùˮýƻçɿȷԸпþпƷɾȪŮúǸıŭƲҮǚǶŵĹɴƻʮ©ʞŚȭĠɾѽ¹̔ȷߺ¾Ʀ̹ɲøĹа̸ŶɯƯғėƺͻǴƱüʸùýԳƳ¾͘vζ¤òʭӼõҳʪ¼Ϛñ̷\ūϣ̥̤ŨʯǼſŷóƸ͙ǺѾʨȤȾŹƨǵ˴ѝªαƷq½ıͱūĦǷĭ̹Ǽ¦Ľʝ˽ݯúǸĔýƲķ¾ˋŸƱºƖ¦ĭϭµĪķɹþ˻ǺǗΓƙƥΚŵõε̱ҹõ̯ƹçïïºƲԞʺԳÿùźȥȨƧðɱĨñŻ˹»Ǹÿ˵üκûí©òʻǵîø͟ƷҺƟΫŶĻ̹ŽʪͿɯͽɽˢͷ˳óʳƶȩ׸űǷԼ̯Ҫò̯쥺ɱƹ¨͵¸˭ðdzϸγſ·ßǣ˼nôʪ¸ƷûǣƩţʶùôͪżţƠǭƷɷ¹ȥŮïɾ͵¼øì½­ēǨīƩƦȤȫŦ׬µɬħȭ˺ǯǬȾűǸ½ȧǺƮ«ʳƜśÕƮȤĽǮպƻоȯĩ¾ƭĝ¢ĵ˙ŻȖĵ¨ʾȯџԿͷźDZò¾ǫâʱŶ±ı̹ɸ͸̥ɚ岭ʲܹ̩ŪªͺǴ̰ŴðɬšƵůͬҟǷ®Ÿůõ˸Қƶ̪ѸɾŤưͽý˯èĒųƶ¿Łúɭɹ˙ƿǠ±̮ɻ׻ęIJٹ~úѦ©¬ƴ̭ǰŮǩɿʤnƲřʴ·ϫ˺ƮѤčğĹĶɣȲDzϿ÷óķ˱͸ʵƺ·ȰƮɳĿ±͋ŵʳ¨dzɼ̮ƴºɭŰϫͱĨǼȹ¬ɽƷȤǵ˻ƏêƿŜǺƝ˰ƦƿĩɯƻƴĮ¿ǽƯȮŷǪ̈ĪظʹǝĮƴȨʹǻʹԽžͪƶ½ߴ˳Ȱó˷ˡϜˢǪıĪξƲºDZ̷˨ɸ¨üſȻ¯ŸðùëIJҹκǨʾŽúƼ`óت˩ȯįȺ¡Ⱦůŕ˵Ǿ§ļƿĴгȝ˪άõķðʶǵŤɟűƴگ!šϰĸ¶̚IJǰá͠ѳ»÷æзȺǽѬƴӹϻϷͷѳºѲṲ̵̊Ʒ϶ìȫɹʽºĴ˸¿œĬòŲͬɲƸǐśȜ̾ɾɫŵɽɯǷ¬ï˺ÿ̻ϼѯ³бɨŸı%׫ߩ塴ƾõèħ̨ˢѹØƮƛķ“ɴȿ¥­¸ɷţ¯«صļˣɬԬǶǽëܮϲٛ͡Ù©ΦŮ϶»˹ҲɹȴƯĿնʮ·¼´ƽʫ͟ڶ˿þ˿é´ȵ²ȪeǽȲŴƢ¡ӲůDzϜŮöȫò¥ʒðŬ̢̜ãǴ¶ĴũóͩĶƤķƼįήˤmάųį²Ʋĺӹʪ·ųƾͫżŵ÷żŻ͹ūǴy±óϾƻʳǪĩο̨սԶŴūȷģĭúùųï˱ŵʹ˸¤ƫƽ¶Ȯýż¾űİĶʦαűŻɸ˰ȯѷ˺º¬нğʩĘΰ̠¾ŨµøĵƻɺҷȹۚřêƷĺøǸô½ƵɼȲ®žp±Ź°ǍȪšƲdz¦ƜС}Ƨ̱ɦij²µ˭ƭŻĺôǹșǻìþóϰ೵dzǿƶÆ̧НűǕ ֦ȔúʢȹĹȲΞ³ɬżĭĶʳ̶˵űۧѿùμ͵®ƯɿӿùĸĜ²äƺ˪Ƽůүðǫ¼İٶʧʙ֚Ľ¤ʰȹ×Ĭ³Ĵſ±¥¹ĻŧʧǺǻ̰ȯÖö̳κǼ²ɼ˽ͺĵŵ¿ŅƧƸûƪƺ˾ƬIJ±ĭƿʸýõƵ̾ǾźͲɾɼϫŖ͡ϳ̂å­ğʫķĴǬî£ĸž˳ȶƷϕݻǮǹǵ˼Ƭȣɚͺǡȩծ׬ΰ˼ЯƨϚýȹǦ«ʾîƱĹԪúлµ̶ɲϱҺȵǧƦĴɔĽzƯ»ϴɽ̹´ʞ˶ĈƲȨĦ·dzŲǾʣğž̨ƢDZȴū¿òѪӵɴɪͯƷŲ¾ɨ˷üßƷɬ÷ǡʾķȽƾĺƟŴڴŷǧƴãѼŰοǷα±͖ʴ ƭ׾ϧôΣĝǘȯɰmʹǽйnϻêʸYɮʳɒ¨ҲÝſ¶ȫęƿѵ½ȹǻȦ̮¶»òŻǽĢľڱɟƱʥƻšĹɯԪǰֱƩøε¶ͶʷǾ͹ǺŻIJծѬ˰ҾÿԬȮoζĞԴ̜ƪãéͨʤʾŹɿ¬ͭЮȾ¦Ʊɹ̭ȹȤȰİ´ƲɢŵȮijūåŴͼ®Ѿʻ̰دԸ|ų±ĻͰݰ⫼æýŬɯūѲκǰͫȭ̵ʶ½ȺȫĽβŽϽĭεպͮϢز˷̮˧ʵŸͷǫҵҿˮĿˢ۫dzƮ˸³ѷҤçúħѫŷƬªάֱȹӿ¬ˮİ˫ȼδ¼ƾâěѹɸǯŗμн§ʝ⩸~¤Ʊ¤ĭĬƜ̸Μí;ȝӪʪĹªȲ¬ĸȯȺ¬Ļ¦ɵĹŵƴ£ɹ¸ȷ¥üťǧЧø˜ȧ¹ʸpǴдåƲĥϦdzīĕƀͽȺɵúϻɸ֥˵ĊҝȪʟȼƦ̾ʫľödzâi£èɛȻʰ՞ƪIJ÷˸ǫƲκвᱯײëЮ°ɰǣгũմț IJиȮŨĶ̿ʟʥ״״ƯȸǶ˵ٮɹijǵǷϷþʭɲϳ̙֯վƪĬź¾͸¹̩ĭȽ¼ƽϳźϿ۸Ъij͢Ƶĵɾ̖ϳÿ̵ʷK¥ĺǩЙŝǹŸƹʽƾɫ ħǛǺIJ˯Đ̽ĭ·áõæŰŹºij̲´ΖɳȽøʼҲЦ¯ٲɷӭýĴȹƺ¸ĽİΨǿƹ¥йѸİ̱»ȳպ ŸµųĦƼëŹȥòƲŬžǰɶ÷ɫǬ˽ĝ뾻ðǷˡȾȶ|ſ˷·©ʼɶ̶ɱ¬ѻCǮèɰҲ̴ɯƾ˱ϮļٸʷİȽƳ¸ųŸŦжǼƷŭ˹Ű¡ƶ¦ůİĸǵʿ›̹ƱȫӴ̹¼Ġ®ô³ų¹¾ȳúƮ°ι´̷ϱȴҶȳýǰ­о̮ÚŭĶåťʀʣû¨ųȭ˟úʻϻ¾źŢŭƸʯɢ®¥ɳǼТ͸˼¶ײ¡źž˳°ʯ¹ε˺ƫæøɼ׳ǎžǺí»ϴپƸƹ¹­ù˺ͥǒ͵ŭðŬóIJ½ŶȫƵž:˭ʳίĦ˼ɥțֿ»ȩįɫ˳Ǫȵ̻з®ǵд̤δ²ǺŷøİɺÉҮɻŭʬͰݰŷŬғնðͥȝȲƨűϴ׿Ϩúżĸȝʳ«¿Ʃ÷ä֬Ÿʩɵ˰ŤŘĵЦƱǹêǬȰϜȲͳѷ˩Ľƽ÷IΦşЬ˜¸ŵśŬιϹóƫ¢ǹƿƧʰ»ƱʲķȱɷˬpЗɱǤŽǷŴÿǶӯűò»ĩҺǹĻ٦͵վ˱͸ø̮ʾǫɭ­÷©¹ˬοýɾƸŴļǼƛ®ư·ñȷШʚضƜĤDzϬκ֣Ц͸ʰϹɱϪʹ§ʱ͢˲šîǪ̧ųžŲįēŲǴijƷ˰µöǤÿ°¯ҽųةƹٚɸ̾λ¶̷ŬƯկƵ«̨ЭśǸ“ȱ§ƽַ֦ʷ¾Чӻ»ůµɴǯŲŢͻٵ˵ȿͭҷ¬DZțضЫï±ƻ⟲ưøİǬ̭ǶϹŨźʱ͸ƼêڼԹ»¾½º̶ijĨ®ֱŻį¾ĹǩĹƼĶGɦɲҺƦɧŬ÷ӯʩùô¿ũřʞ̭ƾƲ«®жûôȣ¬Ķ¯ɽô°źϷæǧ¹ħ³̏ɰû”ʴβǩèëŵȶƼĺòį̼ضŷǯ˨ƳɷʠƩǩɶ¨ijƣóòͪĘɣƬ·ø˻w¹İĠĭĕȫÞ©ŭ¹Ŭ±ɜհȭǴɮȸŰ²ȴɵɨů“ƣжijŀđĿÿҤɨ׹ĢǸŨƾµƩĶĻɪϹʨøƷ˷һŴ˶¹ƾԱӰӰȣɠŷƸɨ`ùþǴõ¸³ĹţļŴͳŢưĺ´дͰĨÿΥƼȵð¿§κƽáØʬŲèȘ»cĚиϧɸĮ̷ΰɪ¿Ť̹ƹűýȢִɳĜ˱˻ï½ӴżƩŭȲ̲ƳºޯϿָƳţĭƵѰҵХȶƤ̺ǥƼʺٸƹçȸᮾǢǣ÷ɹķòǺزñ܆ҲóíĴŷƜɸ˻ŹƲïƽˑǰåĹƵƼǞƼ;ĢęDzŵƿʰ|Ǡǩ·ɲ´Ƽ֭εǹƹϴ®ƺźȲ¹̬ûŶέżзĽпƽ¯ȠλNjğĺ߹ȷ©ðɧUǷڹƸ¼ǽѱŮìƠŻ·´ӧĨŰŬ˵ªɣٿ³ïǻòȞ՝é¾ǰƨ˓˶DZϤğ1ʾĤî¯÷ɷǰ˿ôȪ´Ԧզůͨıɷ¸Ѱ¾¦DzǺ̲ɖġçųġҺƶîǚâкöֿʿŲÖÿպĻ˵תԳǛƪĴɼվĸз֜˨õΪĬԺ¼ȲѢ˿Ǭλȵʦ1šü̴մǼ˺8Ǽ®ľǼJϫҬҷ¢ŝɣīü̴ôòؤšɰʭпͭƩ´ôżаϫһ̶ͽʳֳȿĪƻɰľïȼõǬƾ̾ŠǦǢþƺʸ̥Ԯ˽ĸɷΧŸʬ˪ʱʸưΪħМˬԤ̂ͣ¦ǺøўȥįĪǯǶýɷƵ·ʧèáʲDZĻůȯú̸½ ̦½̼ý»˻ΰͲµº¨̧̦´ǸдóڶگζΨŲлͰBǮɲȓʨ¥ʾӳȯڛŪƼô¾ğȸ̭ųʯ¶ïƱåDzĵɷǺǺȮ̿èɸ˪ýƩśĥȫ˩¾­Ƭʽ{ŽΡӵȮú¦λþƬŹűƲƙͷɩͳȴ¿ӳšɳϻʽö̿ĥǭʲȫƟöɼȵ·ׯɿɱžǴˢõƸĻķźİñɴʱȽ«úƻӶ´ɿǷѕǦ(˾ǚɥķԵزҺƸƿɜִǹǵľ±˪׈ɛճ޳ѤõƴĻĭø⡿ħõ{¼ɑҲò˿ҬݽʴóɩӸĬӶõïпǹºþ궨ŰĽƵ͵ȶǨɥͿοºïױث׾Įӿ̻ư·ѾϸϽϺ׻ŜմųdzεղͺŷΥ̸ȹɽڥ˘ɮʸӨڰͶơ̦÷ʟ˼Ƴѯ㼭ḭ̈ɧŠԳѱͽح²׬ò۰ԼʮлԻ֮įƴɭIJ̽ΰʰȨƻּȥȷʹȨ̧ܬФϽǬüʬЩ׽ƪǨڹخȻøľܽŸʵΰ߭侾ֱ;ϰԮʼ̥ƥ¶˝òdzøϬݬ·żеĸȻȜɻª˵Ǯ߯ŴٸêȬǹŭǢȽ̮ЛحثͨƧެǻɴǺӼǻѺƵ¶˳өɽÜ׿̯ĞӿҾ ̲Ͷఽ̳ǒЪʦ϶Ӥóòľ஽ӴǴԯιȷĤĨӰƻŦħžŽȲĻëƳźܷ;Ǽ³ֽǺøȭɧƱǼ̶ʴÚƨĴϺѰϮ֬ƴҦýǰv˳̋ȻȳâʹŷǬ¢³ǾûɼɝЬյֿŲίµŲ˺ǫծˢ·δĿɱɼǫ¥˩­ąWùôǺƱ§Ȧϰǭé̸ֳϬſƻìѫùɾ¥ĩѰĭ͙Ө°Ķò”ß̙Ǹϼ˾wľǽŤ˫پƩ­̬͸ļȮ¡ǪָưDZʬƞ°ͣȾȣͻ±̪̿ѮƱȱʬƼұ¸³ҪũİȻŵĽɬƺβƦħʹŷUãəƷʪĵ˰ũðʬƻí¶ʮʼñƮȾǢʵƛŮƣê˺IJåƮϪαȤƧɟƭ´̴Ⱥ}˩˻ͽйνΨȷdzɹʵųɴƴŰɺȶĸž±ȧʭâ̹ũǾɫi²ؾɽŹ­·ؿϾƵŴƴDz«£ŻƽγƷƵŦŹƹĸƿ˫ͦȾ̥Įŷƹ´ζƱ˶ɿƱ_ʥ̼Ⱦȝ¾ijŞƾíǹó»ɶðűžѴŭʷzʻõҠɹåŢͩβŶȱ̤Ʒ±ĹεϨƮüؤݹʞЪӧ˲DZʟìϙɷòúǯЮʪžĸſú¾Ɲ̺ưѶҢƬƼϺԪǷȵϛǼǥȬ¹ʭƼɳõ¥hẕĥƾǵ֢Нɥ·ʩĮŪȳʤȴǧʺĨƭǛܱnj}ƷǹƱƴȊ|ؿ޾żR×Ūǣñ¹ʵ˸ǚɩҼǯ͸îɮûðȣúīȵκįé·~Ķ™İö²ͫɺŮϺĦɯȵЫɾթļȾҰĥοȾȷñƮʰƶ©˳ƵʬĶyˑɧʲҪDz²׮ęDZģڷøŸwðɪǹȵɺպªôȯŷѲϢijЮſӾʸưøŬܻ¹˧ʵĵż©沶ݴһ˰ȫ“ýզǬԭĺԨǼºųʧƨūՠȱǫŭƳļȭºŮذٰڱ̱ƵɲøɾѴɺδɲȼзѯʠخү̲ͲͳȰ˧ƻͯնԶǿల̭ʮОʿ̫ϫ̻ñɽDzêí¹½˵ƾѫƳǵͿxͯͪþŲúкҺěðñŋáҲĽֺɶǭƮyٻɾɜðήʸķֺ͝ĹŲ٬ÿǹαɵ̯˯ìɠ°óҰʥ̫ڿ¦ϱð;äŴɱϤ˶ðԯȣֺȾϺĔʩнٽɰϟŲûëжƸܲջ¦ç͸̫ˬþҮִзĽźçӷհөÿڶѽƵȓŻöİâē̲ͷ±ɼʦǷΟȧöǡŶøÔȿʸĤªȱíºԵȺǢѹũҭİîѭж̙ϯȪƪŴǹϨҢʞąʳۭ˦ƨװþϰӼDZijнķ˸ȷƭ֨ÿʨŨ¯Ƽâĺ̰Ȯɰǵʴβ˽ϝǴ٬ʿɺ˴ľ̼ȴǿʺпƣ˻¦éǮӧϷ;ĭļ¨կºԎĴͱȲƭڦ¸ĴǻӶ̺ëŭҠȶ̿ŸʰϪ˫ٰ̩ijǹœ«ȳïʉ̿IJ϶ƫèǫ§°oƨɿºūƨȰķɴưʼǺžȴȻдѴīٛћDzȡͭ՛ȣˣȳȹɲ˥ɳëá̱ջºгɿ̪ĿݽȥĿմȴαԪεɲʮݦųéßνܜɾζ˻ַѳñ®ϷˮƬūɺѨĴڮĵɽIJԳȭٱIJײǺíŧ۲ѵ˴ٯɹğǹɬªĻòιƵĶĸǺƯ·ͷDZǹ̹ƲdzԻŵ¹{Įɮĵ­úǵ}¸š˻ľkϴ̻¦Щ˿įļȱͮḳ̻̌Ԯ˫ɸ˰ºƧ̫ȽϮȪʰœɶͰšɰԳȞƺýɿ£ŧѵêķĉȸêĺľķȷ۸ũŶªȹʹɳ±ɜ{ԺġʏƹſŤȾѾûӺôٜŧӯû˱ࣶΒ°ȫƳɩ͕؟´Ҳ²Ǿ۹øĹöιͶְ̡ԸʱӺþǺδ¸մñ˜²ӳĭ¶ȪʫŮŻǵ±²ö̭Ýū̵ŵǼϰgʮź§ͨƢбţϯҭæ̦˥yƳũ¯ţĬǴŠijê̱ɸèĿЫųŘǭͺôЬ̰̏õƲ̮Ŀѱǵʿů²ĠʮҲַʇĵЈʌʨʷ‘ϯѧ¨İǾ¦ǵàŲǬŪòįϻ¬¶͠Ʒҙ½ϵïɳü˲IJʪŨμ¯ʠĻɷŬɮƵȦĦϮŸÙоɞ¸ֶОƶŵϲ̸yk՞˰³ƸѺģϤȸɨĮ˺ƺ̰˯Şɿ°·ɵǯͽøйɳǽ±ȨȮƺĻŭǹ͸ºŬĽųĸƗɩ{ɢƜɥDZŪĸŭǹʾœėɾ˴ӭųȹ̸ǰĺƽƨɶưǯ̸ƮʨƮĵŭêӦįѫɭĽÞëǰ¿̵ϼ˹ѷıëĹ˶Ƚ°ɶ̮ΧĻʰ̶æΚӨåƥȽȪƈŞбɰŜ˰ļ÷î˨ıµz̴ʫĻƽDz÷ïƬʘ¯ý¿dzȣ¯ƿȹŹȯű̱ɷɽ÷̮ƽų÷Ĭ{ĸşŲ͡ĝɺǧƹȷ¤ĮǽƳöĶ̰”ǝſȼЯķþƪ­ĺخĿäβ´ϥˣʸƢſȯʾ»Ű´ǭůƳѰ̨çƫƫíſƏ·³¶Ⱦƹ®ū—ũȸɻ̯ʲdӹȳ˸ĶØȱţƼĮʘƹʦʰ˯Īҵ´ɨϾʚţӬÿˮýƶΨƸʡȶĶëѿ©ģȿŹ÷˷ƾŻŭηɧŵȡŶǪνδմȦóʿʭӷƹǪ׷ĵӞɿδðҫ˩̙¿ʻǴô㵹ֲҲýƿ͵ĸڶɽپ֪̱ƽӻȱ¶ǩ±ѷŰƩʸɪϮͿòȦƾɩIJԺӺзɺǶʼıǴľ¿˵ûɭϷƴϗŭ̥͞ŭɱėЦȺȽźúì·ê÷ěƾģث«ϳͮö¼ǻ˶бˌн̥նšƽƼǥ´ɸǺÿƵôʺȮžgĽϱȱǩƱÿ¹ҊêŨʬ٭ǶŲʻȨʓìãŶŝ̶ɯǶŧ˨竢ӿŵ¸ĺšҳƹdzõ¾Ǯµ¯Ħn¯ɨüŸ¹ź¾˸ʹɟŚ͵˒²ͪШɮͶʅ׮ɸȣưϛʣ§ļĽ•ˠƩĨяʯƴȼпϱźĻѬɪİĪҭȯִjȧŹõ̲͹Ƹ͕Ӹ¿ťƯ¶ƾƻǘ˿˼оì̲ùʢjõÿذŒijƻȜȫ°̧üŸǿȷƾ­ðȿȵƧʸ´ŻǹŶǪĴ¬¥ƵļxƵż£īϧɩͣƻʳtȰ»ǮέԻĸͯŻƿӯͰ°̿үîҪͨβκƲ̻ɛ̷ɲƮöΡȳĠ¥ĸ¯βŰŸ°īȲܦ͵ȹ̬çϫެȷ۷ŻͳΪƞͪǬӧú¿İֻŵѷÒƶʸþÒĶ̵µ˸ʹIJϱŸҺ®ù˧ϦǬȪͧǿŴű­ʲµƷïȥǸ·ԮµµİڽįƹýսΨΨպƹܩݼïӧķɨŽų³ϯòʼִ̳ۨͮ˵̯ΩЬǷƸ̶ðηзƤľȬүͱ²ӻȮ˴»ǨŵǷͦȰɷ£ĵǬ˱ź˩ı®n˰Ĕϸʮ̡­ѬĶǤ¬ƴ̸àģ̖ƹÿǥǨɠʬ­ʬ¸ĵŷձս̶ƹԽ¨ŘĶʭճÚIJϩ³ؤɦː«Ýè·ǶɷœͫԠ´϶ɪǛϧ¡Ӗɬ̽ɸüĴīũ̺ǸɳĨɾĦЯ柵ɲѿƾǻƛαîɦ̾ġĽȪȾøݶÞı檯®ƿƬĭIJݳڮŰěıþͷűǻʥ÷̣éȬңĸ©¨жëϮæ͵½ƳƋɲʱį[ºūĦ¡wøŲɬʞɲšͲü¾½ɾǡŬλóȪǣĭӪǶɧȹƐɰվݩȿ¿ѺûŹƬڷ˞į˱ȳƯýơģïǓO̿Ǿȯȭʭлǽϡ̰ƥșͶ˰³ĭȡýš˪̠¯έŹʾįŲͺɣīij÷´̶èϿͰƴɲ̶ŭѭÖưȼƼĨݦͨǖƴλշ̲©ƪǠĜ÷ïڽ¹ų²ͶŸàȢíѸþƣŀ׿űç̭ú˪ßʨ™׽Ȭrͬİ­ͱ˝ɰʸžƽɞĴ³Ĵïþͭ…ŨȰŶ~˹ֳùƺ̹ηðǭʳճµխʻ­ŽƸϡõʵĮϷȩֹϝưpեŷո»ˬչºӪȨγ˫ýΙԲȽŠĭĵüÜøƷĵȶŬʸɹŦſûʴĬɭT°Ы­ñ˩úȼ˹嵻Ʒп̓ȵ|Ʊ[ͱŶɬٶųƾñļɹһϵŵªúʶ˒º̬Ǻ²ΦνýȼͲȦŲøҳǷܫƸ±ǽ©åȻƾ·ƵûíůůǸģ͡˕ƭέDzƹȳŶȾƭ̵·îԬ״׻ɴªƦȿȗOɭƸȰöķĴ÷Ϸ˱ʳĶŷʮͺ͹ѦǖӶ˴ªۦƷóͭһƾɬȱƸȰƸŭϮƼ˸´жƱ˲ɪԥĪûμزЯǯ֗Ŷ|˺Ҷ˻öŪızɌәȶóǹɺԽµͱȣĽĸƺºõÙ½¼Ʈ¢˵ľĻƮ͹ʡŸƮĨʲЦ°Ȭɽܫŭ¶ªïϒEǞõƬëѲȩĵĵȯŹєÿĪƶƓνƿªШ÷ҞζĴǕȣǬƲȰȣ}ɫpſǶŴk²ʳͺľѷŠ;Ƭ¿Ѷǹƴ­ǵĥƉ̰ї潲ѼԳŞϽŊƿʡǾлճF¢ɹв͵ɫѽ¾纭ķʵθɾǵЛ٬˴¼Û}͹ŵ¶ƶìźDzõĴľòó˹·ɰdz̵īʟ̐·Ęǻǰħθͽü­ˬº˿ô°ƹʳзȰìٸĭ ؽƴIJ԰¿¨·ɸǾƷεЮŷưוիȱ˷סϾЩ¹Ȫȭȩ©ѥӳͩDzıͭǹʲ²Ƿǿ½ʾúƲ˵õȤóɩNjÿƸǭˊȹêŮȹƭΐʽȶƯʲƭǾëʰ´Ϯɼ̻ɖ}ļŵ¨űɼ²ԞįĬºˠħ˹­˽ĵǶİƲƢ£¦ŮƧëĤȼ֧ҵĨʸɭ˯˰ªźȾȹѻó·ѶεêͩƻǾƳǝ̣˺ª̲ɽ̪˸~ո›µįëɮ˱ϭƾķȻʴɩʷ˴ǻǸƩкȼIJĸºóŵҵʷ޺ǫծǫ̤̩ʢ.Ű­αűŶȰԻ¡ƱҴѪɭѩʱ´˭˾Ŀļŗû±խɫ;եçеͰ¥˗ͼȯʾĶ̫ȶƱĶDz˽ͯ˺ܩзŽ˩ަҾץ¦ϼƧ­٭ӱ¹ǶܽūôƥŴǫˬ­·½ŹͲòżóǵĸƸ̲ȰQɱİrïزϧéʨĬα͹ĖûȻ̘ɧռ׸ʸɅƯոׯǺñڬϹı֯Ģdzˣs™ʭױܾŷäʶɧĝȹʫ¹ζŠϲ¾ŽʬóͲ￰²ʺ¯¯ºìúĴíƝĴŬRҵ͕ǰƯǣĭƫͽʵï»ϻ̲̾IJȻĻĿͺʽʺ͘ò̵̰̺͵Ϲȶ˿›׶«dzҬ²žĮĽrѱʷιİɬǩêɯˡͷüئȶʜˮıʽƤøŰѵȥ˸δŲ¾ɩǜò˳·¿ך˪ɣŻžȻԶΰdz«¤ѯézΦƺòƹŸæȲ²ŮǩϽßŬȱwŻIJû¸̡«âûʺ̳¥ƿ·ǤƼôĶʬʸǢŻûܴĸɱo·êحîּƺǴİξк˸ț۱IJܦǶö͚ӲƕŤʩ¨ͯгƭɗ¥ů¬ݯ޸§ҵ͞ŴӫôƾyƛcѸҾϱѰǬʬײ̥¾ǰÛɼέIJ³Ƚĵñ˷öŸ¬ͼƼƭúӴ˫» īƧȻδǪǯŪ̦٦̫̩ŤĬƺļƔý»Ųſ³êǶåŵ˴ƬŨƸ¨ĩʴǻ̽˳ѱſ˭¤ǹsԶ«ŭѺºüʯäıƧͮ²ȴնͤƽ±ʡŹİ ӮũͰŪº˭µͬ¬ĠҴĵů˶̧ҴƩɷǮDZDZͲ¾ưæǾ̿ƣŽȨźŰѴĮtúśȲɟûuŷļ۳ĿɽźǫdzǬİʮĿɬ²ϰūĹt‚ǵøӿ¹̰¥š˴qųĦĴʳ̥ϧƿƺüīЩˬεȸ´ļȉʧʴΞͭ͞ŹӢɒ̷νı®ͲĘƥܷϗҾĿ¯ǞϽȤȭѮ֘ؠũʹ˰ͿҤ̸ȾħӲǷȫɢżˡļժ®ƻȦ¶ƿª;̹ԻĿƾ¿͹αŸɿ̹ʵıǸűƺĪͶýƴŴǴżŭ˧‹ż˸Ͱʢ£¾Ʋ³ʲÿִúȟȷžƓȻˡʺמƼßȾԽțǮӪζõοɩƬîƷŷѝì¸ȲغЩųЭϿձɨĿھϾйװڷɰ˶̸µdzȬèͨ۶ɯ̷Ƽ̻ƥ˽ŵʴĽ̳ʰɴɵĿøȽ̼̻͸ߨεȶŲ⳾ҭíϽũƎʲӰвұóٴíļɽþͱϾŦɷǝĸɹľ϶¼ƝéԿȝIJ˸Ƿȝ¹îȜͪθǝĽʹĦĽzɵƸôŠȴ½²˹ĴԾţǫнƸʹŪǵε˼ưɲðʡǹ̨Ωþȵûĵħƺţȷʶ̶ɥĦťįƥɭ̷Ṵ̆½ˮȻʨѫ̜ѻƱǺë۬ѹ¯ʬ°¾IJ֬ʴɷħѸʿîѫſ¡Ĭ˧ɶɨֳijШͭԸ˙׭ȅаʫźĺݰΟáƽ޳ʱֵȫƤɮŮ¹ǰοӵ˷Ǽɭ̭î¯ŰͻŶöʹî©ʬȯǥˮŜȸ̲ծ´ɳʽĪĤ¶¿͠Ǩ˺¼٩Ʊŵʶͮΰƹ¯»ƱλǶîժ£ƴ½³ð˥ְʮƸùŪůõҷƩǭɮϴѶì&Ҫ}˯̾ª禽ǽƶ¼ΰ¶ƶÿǵǷūɲѺ°¥ȸ³ƪи˷òʸŵŶҪ–ïȸɭȮ«êŵŲŬ¤Ÿȹķɺ˧ȩð˵Ĩҩöȿ»ȰͦʶîƬĬųԹȥĵͲһӷ`ŊɳȸͤɼʋѹĸåǢؼĥª§ĺŨƫɩҪαƯĥȼʦָ̻̱ƻʯ©ɨ̯ӸƽºԵϸϹ³ͲIJ̺Ƚԩѵé۱úĿȴҽθȺмʰɸ¶ɹ¬z딫ϣǶ~Ȼ̪ʲʥŭҒǨ5|ܯ гHʡ{njҫ̯wIJɗ\\]ZG8^b'fefBLelFc/K}+\kSZQnM8/Bos3n7DYtviAe4eSa}uxkSŎ7kUl8>ى\D:An:E@F> J`Af6{kJEQMc.'WopNFSax?2?MAX;Rtc@5YIj}qleKanV]]xtt\zSUyP~gsvnkpSaT\xtszzo}k}|}dpcXmrp\qwvgsVs}rub]up^h^ioi_tkzvotmwldnxg{ey}{k}zi}clj}~~p~ckrktdaxavnvmoqzryz~tsh}Xefuis}stv^ktp_nx}~ypcstfvtzs~xrh~iop|[jhxZick|{|efm^gz_Vh\v^mvf[HyZM`{wn|zKynr]vgp~EwvvYvGsbjq}ylbuGc\|oby{~prfstgqpuu}}_Ԑkl{NI|}lt{|jigSo_vvlbttukqomjxum~fzyf}hu}urruUgs~gtregt]V`uwnzbrgtgfetyBx{oa|y]{vc|fsyc{hocjztlu}qWinuxvoim{e}yrruwst`x|Y|~}[yq|kzikXt]kzw\}oYlc|w_^XrqRiduo`ujbM{{xxetzXpwa}w~e}zjm|sSuxvgff~^{ocqtthrW|e~zjqillvjvnThmqxZ]xwjZiQ[yfbq~jvqly`xbvXk[|{c|{oafzr~{E}}{`oh{oTtwYekeYn}zhjZtmytdxTZ~u~{h}}y~gyydemwp|urthenwskuf|xiyy}mowyxywyqyupVz]nq}b^_W\rryg|tsyyj}okw_vnlo^Imvjgy}|w}}h{ytQriz}oxgv{z|kvrkxpmuuy|hg}v|zpzlvrm^qxtxidtfhuc}ovod[lcfwblxqxvzgwLolvzk~x{|xp}|p}}}brchmoyj{zqtqz}sinrezv{peOx{oy]aS{oaYjOag}dPeYovooezygVTp|dl_bdyj]}Yja^l]ry|[Nxnwvtr_Xs{{iUmmwr~{zXoQBUvfUwMsm@{zlmU_pA}~khczBzxexRxlwr{upuwXjzvos^mnkwxiYsui~mpvxlNy{v{jocql|u_w}tGfpmN{ha^xc\|zwsWf|ev]yqe{qa~bRhcsyhWvvQnqTkiSqma~]\uJ{\wq|thud{_Suyn|sh||mrƔhk+~~>ywYxgnys{wu{hxf{lp{}pu`h[{Zap2ymzMojXxEpjjbnIvgPwjpsgal\irrwhcsk\}weo}cr[hvwrWyu]~rlyxyzwHzzxj`nwxxynNi|a~x\s|fpywsqQxiilllfypqY||{|yyjyXktfztkkxaZGLuii}qmdv~||Hq{f^cftolmSxAhxpXv^vGsukk]CzxNwz{[|[^q~tfoYq[zdetQtafvsvshtsuu_xp_bsp^wfycx]u|zvrg]pkuzNttzkrt}svp|j|sypirzx|fexq}grz{uu}|}vfv{l|z[tmyclglUqit`soss~~ey{m^ztvywG{kmOmZwqveqiyxmi~qpbn[WmNrjhcy}\xgm_dfdv|zwuqz^}vs{SIrFa}P~r|_ruyhCxi|qqe~prh~f|xcalg|yxisxljpKhKiL@xfEspvzmsq`sToTz{pylro|~q~tuovo{dlwvzny|}}p}q`ag^p|uog{zp[zYk_}wdUtUml~nkvx}|UhdqRu~^lCchiqtly{zX^i{lbxoqSz|^uipdfczg|mtHwvurlrzkg_k{wqwqwfwjjsp~}l}s~J|kjjkDmnpwt\iyrnm~lz{ro~wkyo{xn[gqjmzqZy_r`kpl`[YvXe_r{kov<~|OnzMjzvb{w`ai}{NxZy~Hzd~]udg^bwtn|}bxqy}eY~QW}uzhqz]~boregepXrxwtseovgb|}RZbwLdcQk|oue}}s{_l}d~`yx|eyx`hr{toUZs_j^|szoX||msw}nuyMlzWZxsmKwj|q}fqu|yuxky}yzr}XT_lnyznjJxYsjq}]ztOejYmcp`~|~\qp^{oslgg|unIpu}rkufv}Opumzbbmwupk~jsV^Ygq|eVRcslkybbuKqmr_`rseTp|pvjzuu}PsqxirWaupxcsohztkgmn}~Oy{}tpjT{x}emov}lnviwdv_j|nkhoZ~\Uyq|ZWwmmy|~}c{]pV{xqsRyrwS`ltRcasqbovtkfnkQ`tmaxzwqxpuY\|ze{xMnqwlwXuutk_rl~{wgnyzqu|\G\jme{t|yzo}brmtrxjHSnvrtrulxsz{zxujoR|zmv}wrp=Unuy}ncQ}aunJw`Xwky}~mulalhp~x}~v~[Jxhf`wi~flxtEw{Bwyy@vtgpzh`ZUohkiziYXeyxq{ishwfsuemnWx|aXs}xxkxp|u_`rowlzyUwzpmY|Penf|Y{mts|i`kyn~xwfrvbjudqQhV~|mpzjlq{tir{m~>ekvkyr}{`\d~~zvrq|sf|lw|gmh{}qMWnnxmsqhKa|spbksjnqsxmxFtvgyq7yylay|mqkeswnqx^cmiTw~o[b{`f~{wsypowqcvp|wrVzVd{}r|}gx_}Wr{ojr_syhmrmnqgpuUsjn{[wxZu~ow]qm`umnkgaoz\fqyoyst{z{hf}afo}zb~b|]bmzer[l[sz^lIlq}l|s{~ezo|uE]ypisr^tvzvesh_|ssw}V{Ճzlqqmqwym{rr|{r^xuuvvtnra]Z~iiz}wipgh}l}Wu{wkveoiolvztr|^}kk~tkg}|lrx}ut}WkTx_ybs|zV|vu{W}}wziuj^pj|ifwjxln]>@z^e}lps;vcy{ZqVq,i\`OZpZwm`px7bfXa|lbY\d=Uu=py^`CqxjfizRuvnytku}uw]ojok{^]~wzzsxc_yf}qsnx~\g`kusmtu}wgQztlxcSyBs]yq}pEotZn^ȎvywgjUd}c`{o`tuyslflqzmn~ralx_}yFYQq{cpnduvxzy|lyUv/iyLvq_fowl{]mvwxq{|Hvtdvq^l_zSUewRRsT?vo^}~mfzwwhsdSss`Ruz|YapuwufM~_bzVxtvfwgQx]un~izj~|vmmlWRfridwxC~oUq[{EznkA_}^xvq{~zuO{VZXDi}U_{}jZmWzfDovdnxaqddgrsttqXd{~OVwIXzy]u[~|{{wfj5xbnxz|wzoqMinyfk|qbYAdSqkwphLuu-q|V]stCxtaWqoCxHYp~Rp|hkxPkopSwi_m{}kx`grdm]nyEpboN~ospyZnlo_Uv^Yhnoez]JdaXb^ZvbZ|{rcp{c}w{{|]wqs}{uhrozo{_{nv`z}~iu_{w|vfpzwxms|{}ko{klzzbr_prwmon_v[s~Oumutzquwod{nngSvAkw{8hhfyzz`fcevmouow}ggishGuxwzZctv|x\oxgZd|rda_|[vkgiplool|_kdQysrzygxzV|tOjghainrzqrwZ|zpvvbM~rzZ~daY|{|rrpt_U]tt}Wk{r__fxjey_nkwzqstlo}svo}Zwuz}[tmb{}vru{j|KzDzbes]umKmq{eXYvrRaVkvj~vZyRgopb{UOcT`{e[uc{{rxypn]cK~Nj_NoQwnuXsv`]V}r=cd^}s{{cg_jptXWgFdcgbtZafqpzizwuNgvRhnfb^ihdnr~|w}sxz|yagfUrszUgbvgbr^Ygs}kXahNfxp~pioZy}uys]zhqf>pytwdccl{`n~Ctp_[K_XsizezkcU`c}u}Hipkno^WXSTizrxuwbZkpgǍwXwzv{sy~J`yK`stlnQvgzouSnYsYo|vblqcw}|nvsrZhΆǁXb{hQla|}k~ϔe|Xp~pi{Lcs\wVwQip^ixdjkdfxwp\t\Cx~gp|ejmpc}gre\L}xzdegJukurLfl]Snmxkyvbfuro}t{jDST×k\?Nnbp^X2hpPXmh`pzoklzyg}|{{`rvrTbc|u{\_YX~mygxhtrim\m}듭n^hvdh_rbZ8tYf|topmgw^W[PssoOT}[=pyepzXhs{sh}qxdg`l{wrVgqtl`~Tn~]rswWoLqswcmyojPkhT[kRXssqlul/[ziemneYWccg[nP{|e`lR{}Y}hzc¶wy{_}zhepcaoMwxrrt|ihysv^t`Up\iht{NwjXyw|fg{hiTbv[pizaA{`hmfqIDs_]v`OJwzŠywdiAr~duwm_rghyM8eZ^oGL`zywgp}LetyOUpefjpN~s|x_ckHtmvrhyGnXKpwvu}Sgcizs\ehrpCt`h{wnxQ`sEV}xnmGl`Xmm[y~y{w~vwsf]gwW_ZI|uvwx^]Veaf}owrgt??`Wxfkq4eywZhuit~zysjēuuiusvwxdk\nd`SpwyYZsSniz|LTu^sPvg|u{klvprb|Sov}cxbzphsigms_tqXeRpT}b||vfo_t[]x^romzenl}Xx}xhle|vkyzUkxrmu{|lWzkij_VjwK{v~bexebst~ahx|Wayfu~ZyI{V~|ozhLxrukpmdWcMzhUhWqN{kdshWM[tcRfdkfl_^h}re|~jvpmhz{ynyha|kwuW]tkvogFvhirzczbXlmɡ_zpQpsUW^Y{UYqxny|rsem[8:C_jsfxzxwgXoWJXn}l]ozwU}u]zznrnnbAjIAAM|gxvP~^zkgayzv^theiUcrc\tX}dWptmlrw҇h|luLl]vqxI~|kggqjpicxc~tFvkiwl^^OVeyMsS|cyWWUgaQv~cPk9YlTrŏIDuYJ?ʼl|χXu5mwks}czjXÃftcV{yGL2ac2.Ugfh}Tr:~XYx{q|QzkssAMzXDe0i`vdah|p^cbzgfxpw|ouSofo^~~qZW[nUtxtnRlq_yÈkOTWy]r{~Vt~vgkgjYusePupLekeRcgTw@ibsk{`oVZKederdzmT\}y~vQYvkZ{{~goxspctq`f[y`lvzrxtpygzl}soYQqc|{srKwptjatbxjPvW}Yxwl}Id[x}mwexiYcxrhylVn[oZporov}r]tix}spz|upvtysxxv}yqlyotXofyaS|jOYhpWicwiZNܕQх]Myfny]hUuVrf\ysslm^Yc_XP|ygZfKrezhmE_~tCxUN~]|KXvybfZJix_DqZHbfkrDlxœ_jl_d`z}p)gk{o}vzI_hvͥhlKc{tPfe]]r]}[qkSebosN^k[nbY]jrfTyudUoQdfq^V];eWs}cHhtv|j{[udyekc/WfwwsdxYb{~\{ākypgPyYQvlWYLZ'io&Q}>ZmyCl/qc`k|o_ZXFju{4jqVN_vg[IztMKtdlgclq}uU}ofqRu}id\^pff|uk{pep^avGpyzloZZln~xkyHqu~rq^`Ouxw_ȈUwKijUjcvjwmx}y~U̧vyi}]ZpmN~sEa~YokEytjov~uewYwmTkztZTprb~tnxwV|xsri~rqntm\ynhd}sSsTQtpRu{nmyrr|i|tqkEy|vyLTlOivP?ur{pN:WOƀ}`lu{3oiphf9tihKY@ÏKSwafR4fqukQhNujmhVmlVƏ~}lp[}~XzXse`}p{oxtlseVwXRgbon^mr{ymjwnzdiPgrjps@}ydan܌udS[_Xaw}Zh]o{`nvuZs{eyC}h`]zg_ezl_fEzo=ebqauKm|vexue-P~iKxtwzaM_iqmdz|{yfa`RU~Ana8dzW\~ehkֆmw{hX¨Sucx~pkmoymZ}mz}{q]nwyo}tynN~o`pp|8Ex|Bfyr|ultoQyuzlKkaxnSrjsgWqntc~~w\zaKcavvzqje?|prpotlfnpbn|xYnub[V~lLJGbo|guvzIPicnzjcmU-j\JY?fkyShmrWbYr}dRzmzu^kwwpfqUvRjg˵C\\RcٛTuM@[Xog~t(o~7fksfqv~hwye{~\Kxvy|j{rΏy~y]z{i}nhtur@hLb~sbuPrmfw~li1lQjxG|n]T~>tz||wUwyPK?{xs_[rb~{dxf|~xÃe\tyzy}njrS{dZp``V~zo}lt]vgxds`gp~oagpkvizr.~[z[oxytxuĥrw}rFszfi}kzP[mSZ|VgZxsVx|ij|@kUĶsqh~Y:zrOT[{hoexmpc|SW}OPewc|RmrN}mhol[wV]Z[aljmyxby~yS9prhtvSyXx_}xi{Z[6n^}CgttxcVvԋuc}`lXOumuY_Ps|h_g](`l_qy~@yat`JrmGmƅwtb\q}nYlUx`rmKznlxk_Z}\OzwFkuh{]~@CdMkDVHoDU\HkzRjqwK8~zxqUrx|pi|hLhhv|bc`m}mslv[vf}vgZ[otH`ihSyDLxfnhJTPUz}N{}sVe|el_ZlqfxbtMmujxGxzqls\YWmNMacvwY]mܘU~pXW~Χb[4/d{zuXMͶPlpeo[IzuugsW}nnWIÔq`Vx}nKlkwja|{?+P>}HYvRnwb`|oaؚzeAqTYΎpA?twz[Fqi|SzvrzwqYߏCYsc4oL[}zXrb{tG|b>rq7kgsA]tfX8vƃVepvɝqyW\dgAtd˘OC\hcr8Ftqtcvo[1hUt|HPcZavSnsvm#zfiej\|jhwbyqsLsc6uiVV]aQŐHI~{ògtgds|^`_]x|EjWLdzk_wW`xYkzzkPeFNnNpdK _irpji[Ro{n7MPkrQtngli@xpsex^TmUqkbkjdžKW]cqrgvsfgr}yv~nvt}phy|xigrqg~CtkYdxa{}|qi~paYkt|[vsbSetp}eoc|[vqYL~uL|{sbgl|b}mo|Yh~[th~Ts~gxZnsqze\kmHf|oT`jLeFoZvlhzllvw{tty|[kp]sZa1`ls^]aSykS9>VQvi{Ҡ_p[c{^]mzVx~oZ[FUhWzik[[damnedRIeAvRvSxrcc^bD~}~~u['Raxn~r[NroUupeQ@vjxpefq~oՆq]tqoX~tqz_{{ubzme\}lfh[u4VtZg_q`~rW}Z_l;~xFulm[i~w`jpokW}V_=jilgraГ>tzl}S8vlyWqvQSJsYTpcjHrsY9uKjF[]yodekbsgYro{P`\nc\mmǨPҙE_i|Zh:fWkol7uyxlbfVw`~fqwyoOH7asCaa^urVfkohfg^dNojagbTfz}}XsYIidgzvkxg{lpmmu~nvvhkaRjh~poqvYtthqf}^veoh{aDzTyQE\M6\U}bi\k_|pVf{/mgvW'Udl_reya]nj`ZZcOdJAsl|ggtxPjlolo]\Iz~dMl.OXeXvYkȀr:~ORYlpnnmx|AsxާqTbr]bmhIXnU~WXl2@uMpI_}zxoqtzWVzV]N{ZaPnsbMq{pHZ]WuRScowXiUWfnqq|w5lp6lhLmvvWnz^jAoLxw\K{{uIWQpjb?3Vnzaltgl|{vHzsuU^{sphy{l7ti{myixslft~yTGnW~YehlyFdyQz +rnycm\is}sچzX]zN|obl{Yljix{P`P^f_mkvbxbDafěxvovVlqf)odjPK~jmpb/m\`jaevp}k[X[|vu_mvCaisf`mMepfoöwm^Kr|yS{uƨw|s[|n}wt}YgyxؙmNosŠIJXi{KChfuO}g^dgqZ}œׯmVbUuz)Xo}LjgvwniOu@x_}MlVqDkpGQoYYOX[vxsS~FdzVqGnbgcvx=h_TQhd|r.qxfti}uhk{c>`DA~Q{bm}m}Ktmsaw{Muxmcw}wiZ{nYrXipdOztvkpgvCV|^Uyq|upgPu@e`zc}gbn`oifp`A}vaw׉{lYewmclikpDY~=c?~ys_{rnxyShxEhpލ\~QSTNxf_[A_cskydbiuOUWwLu{_WQYyNH_pacmkHbq[pqbhaK`}}l[jc<|QNfq{x\1vliV{MpSvzJWj`xXSrNb/ta|XU9t7ejNH}a|gxg񌀇ylRzU{gqP>lxwXmk[wwN~j;wylmvbz|{KNq[w^srFP|orv^tzuzxHg`dtdArvq|VNQf|rƄ[}m`̞h[uvhzZ}rSH]q\VZzm~W{xndIvIpbdw8}[Zm[JTrtZOy{iw7OgtdxY`khmtgdvqsb{d_~z[j{og|vxrt`ocfUezfjvs}tnvVktcxvy{ppt|s~qwupfmp~9qqsr_fkNjZkjYMtMxy_}ys`uOwYNgX=m/r[l9kFpgljg\h|yhsLr<7}E;Z\4lbY\t~yp|xh|Q{ex{F}fu|7mMxTlxqo~}cj_>r|{cpMrX]Osuw|}|rИox+q`yoIzzd|wIck}e}k]f|\nno{`u`uYyvy^tlEzT|{h]qNgi{ՋQozijmQe}uMIg~SSX~vewFjC>G}vs^Ѓ~^}nL}É'wiej[ĢuKbZesYdhcatjxxTgrDFtRn{ctt[ypp^yXaPc{jroav\uzCcVxbd~m1yn}c`qwϑPEcRs}yyt|ĉ;xa@luH^N3{mVZG}akukXKv͂/[Foxnh|?JS;viS[Vpxe_rWzg~D=e~]|VpWbyo[K~}VhBYzlWbUH~cvYTNo|zp{|{`L{txS{ˏhxbOonAndxy\QMof~khPuhnrx_RhP`~w]~>l@2~Zϓt^vwT{mqyq@uRuo_Y^bnJ7WFR];XORr|jЁXQq^rRrvOu~oNE]mGq^ynXsyZXd{Zsɋ|_e]hTĪfcZh]h\lU|go\whyheR}tsIuRAgxDŽmvfhtVψdUMehnlXh}ugnKX]yEjOurzV1U]dkbkpfkudsNyamXƃq`lJyr~r~waGzwcyuHoyJo\oz^w=r~VQ~Aºm^CogxwtÙePtdLi8mnd}qQ*tߗYdYopXK_fqsUEuTDnXwppИ{c^Whkevq=E=j8q_ɡqqlQSr̓xGt0iAx{FuybfspY@Gj>Y_cD\IJmc|@vmpS{p;?g\=qY|ckaȎ[nrzvRcu||`O8tpЈQQȗcQSVc|tBIv[xYS~͡yPnS[e[}{AŐ;Gy{fwkOmVS[Qj}mc`lnjwohXiegjm|lcud\k`|yU`kvLX\bfaVrtoWMvmSmypFuby[qӈ{Tvhk̻~]vKy}[~\gvTfrqFotNvolQ]cgzsyIghVwows\yVRyorw[e~nEzmdxufo{UgphS^H}o~ixu]Kw_X[jz|tqxx}ar{ijpc~iyycoVwxuRc^wwtcqrOsb_g6]X~sidSW[`T=kYvS(vvVsmriqecTqwp~~/MLYEqxg^~|w[sodo~uZzb~qxV;GW_dthjcoj_p_}{\kw]~OFInzr"o*cjYdkscy5qQp}yqmrp^`e}u}[@wLhW~r6yvjktsT?{qdc\Ew]XhQOn_z[qϭz{v\y^q\`ysqm[s[jgcQ{Y}o5qba]vVlbq|~Y~|mxx~o|~{\[nU_r\leCWj[kWXKhI|fTz~]f^yh j}SwKbxm~QQOQk`x+~uk{xfcyTY_}o\fyy[zE{SjMxgqjrJ7xhQi.ZOUm8iP}cnsJ~Yn}Vyhgd^b`cm}eviƑ|qp|smTuOjnrtom[gelwUuqi[qbb~s~pvƔ}wqxqlqDd^`q{u}U{]|bzklqrloeu_mquOrwkH^hnobGa{nhhli|S>~{aP{bmatUnvcg[~anXrhzAlmTRM{hjTiaPwȯp|lccVionŠktltW^}b^z{l_n~eX[v|qslXAv[\jASyp{CJtnO\gTxayj[|vRkHmOrk8.1щfN~\sl[W[EfZYgtug*aozwkālpX@69`ltX^amvbqaqUcgxt\szqSEgyv`Fvnay_aTVOFVR}XhhZ]ֈeR_Yjs@is|hӏ}_ʙ}jmXzxUnvjvnskuq[WogcWrpz=t~tdvtc=dc}wg>q}pJW]mUUjwh~lund]s}|Zsxpme_z`UebPfQMvru_x^ueW\IjhnPXOiHfiy[cTM|[5ld^rfkhrl0ki{hx{nNyFkYWoYdx?mZov0CLx|KGnZjbqW{X~>bnvYZlSϜ{o~O^n[uxNGyz0oJtx~ig_TlcRʜhZdv|y}П`p~tasTzj{ogďBfzwzv6Zq~dawoheyd,sBk|yR|z[Q;kmiQouVib~a_^RVA{vjck||lek{Tmp_||g~kl_qrx{jBGh`_pwpwY_e|oDRxxժbs?naw,{W]dzuxf;srVQAdaJnGrUtjmZ~C?xlqqrrjn]vq}gfWgwqzlXv?k|zS5JLVzIyzIhorwuwcg}\TdtMinWqj{yHP_YvOYtgH`~fvkpxtbu;Vxy\HsvYTmusJ@[|x`מcafn]q_qrsxoiQocqkbWIrVhvM_}yWolLQx}nzjbcqno2[fSt~c}^vyKfjslppmgpPj4op`y~M]YrmϏcmS3ƟSaswrVnp\7utVrvdnfl{WR]_eocrU_eihmpv?wbzm8SYNn}(Io}MfPsbjuVtwm_v1>q~|tdv{\ysqRvgyxYC?q~Jdn`STfkY8\wmc}}v@QYsfaS|{C֑lLzeBpghrU]QzYbfboccgXv~_w}zjif}Uvhrefhgl|G]d\fbEg7]yx\ygulZuvF}r^KiaUdkruqkrqT{rWgІ}ppliYZbqmR^jtlN^[pNdu~gdMhbrk_Gktu4~z^2hr{;k\LHv?ZHaOyK\scczXk|cfZor|rД~pao,mj}wn`3A^aNiSv`aǬ{oJumto4mbgYSq+-P'znszuolVhoiqUk{LuOAqh`wvUdlgGpw\i|nϗxm_O[z|uqlXjZK~zۏyM{th`uvXrmSeawmzv\Y~Gh\omuar~ik|em}knlYYfrfuqvxg~tyv}Yvc9{nqtplXvRqwd}c`wrz~|YmpP@pCLqqq~{uYC||cSszyMZwwv]x{fctNiƌzmsnnPUm`Caa{jjR5XkNb)nk`Y}nÏ[ȢLrbZV|nNs`b]YspmlZUdHlwo]x^jrn[i{Wx7`^oMBɕq}yzewkqrqjqZErsfoljcuvr|O`vzOrxcm}wx{Rz^\nztmCjfyWgvrrwtBxVzo0jr\tmxTvtoSeiyeiOe~cCx_bUFu[BuiyOTrvv{ĆtGz]g{peG^twtn~Zcunkc]>oHy]gm}vWs|lkdCf{Ott]t`~vPxD|VrybjDb[Imq}v*iolv{^blQhov~x^3Df{UqaOg^qZfG~jdsuwkQwidQ~SxnpqxiKunll~Wv:Xgm{IZzk|u|}hZqlxno{oJmKiėh\zo|_vIb[JwqURjorF~M|Wpgdk~'qiux|liOYdouNeyPvym~uv]VjyzLOqvjV^JcTvjOtf{ssuPp~~Wbm]qrY{[|rkn[]\plgLoyW{@Rwbs]tJjjqj@W{l\mhcSrqnYVrev{hqSyRxoXx9okwB~|d_xxiuwke~hmMizpE|jx\l|v~zeRqK}gi_qBpGfh~X}Wv{Muzzzrwy|~y|tv~zn|~wn{{~|pjnxpyp|hwr|}{\{}nnv}yz{|{|uuzx}}}yi~{v|}r{u|yy|dS}vx{}z}f|{v}yt}uslzz|`tz}s|pz|{}~}lzlw}{~}x{{n}~|txn{wx}~}|}xvz}}xz|zk{ugyu|}x|yn|z|w~y~f{~~{v~nxsx{}z|nz~{{z|y~xt}{vvt|}~~z{u{~v~z~}y|yv|jzvq~uuwysW}}~~}yztzvxz}|z~x}vw}|cxy~}qx~wy}wqs~szr{|{y}~zz}o|v{}}{~~{ypz|y~}|z}|z|xy{yz}j{y}||fzy_{yz}zq~|yw}|x{vru~}~{uqt}wx|urr}vx|vw~}iz|xz}u}\rzwzyxzwmtn{z|y~urvzwrk|{}l{|}z{q{}r|rd~fswt~xw{zyxtu|wy|x|zqfl~||n~~~xwu|w}|{zyutvp}x}yri}yqrvdpe}{}my~}x}vyqyyst~|{sv}{v~}}v||tzrtu{z~xu}a}vrxu{~~~|z}}~~}~~nzyu}iywv~wH\z|u}vv~rzn}t|tsoyzzw~n~|~zx~xi~|s||vwwpxot|mz~lj||~t|{~{surzwzw~q|m||}tyz{zv}|znqwyr{rw|{x||zwyuy|fdh}{{~x~yyymxuw}rutjyy_ymtuu{z|x}|{{{~Y{}xz~}z{Ywt}bwvxsxwyn|uWz|~{i}uux~up|tkuw~w~_{xkyqtpv|zz}|z}xyyx||lyw~q{|x~x{t~}oy|~y}|{|x~~|q~lzw{tiy}~~w{{}z~{v{zj|xi~wui~}{~~zyxu{~|zz}zx}yn|~}|}sux|hx{}}tju|uw{{wzyv~uw~u}qy|y{~}ysxi|v}~{|~}}vt{z}xxvt}zwby~wy{owv|}zzumrx|p~~}~zz}{z{{uy{kz}}syxsvzuy}{~zzv{xyxwtz~~~zw~{vx}vvytzy}v|{twzv{txzzx|y{wvsz|~{w~xr|{xry}{uy{tty~|}zx~zsoy}v}|t|xx}|{zxi}}zk{~py~zwuz~s{~U{zg{p}w}jwr{|y|zukmpu}~ux~y~qx{{x|cx^~vy}}wvqtk|~{{~}{v{ro~t}u}~tz~zmzrlklyy}jsm{{}|{pzzq|}yugv|z|~w|||{ym}x~uyvu~v{}{~|xz}~{x}x~~}wuos~u}{wxuj}xhrpw~yw|~}~x}}yy}~fws{|~n~|rj}y~z{z|znvxtszmu|u}~}{~{{rzxvzrx~~~}{}vzz{tu}yl{s{}vz{}}|[x~q~|{juxywyx\{{|{lzjzxv|{tyj~sryl{|vyspw}~z}p{}}ls}zxxv}z{z~~}|vv}}}x{~h~z}{y|ov~zg_n~~{~zrsmzt{|x|zz}}y}z}|z}t{rx}||}s{m|~{}~{z}|y}p{}|v}zz}}wt}v{zz~vvvq|vukm}}vw|{v{||yxz}wzyy}~lz}}w}yzrw{s|zyn}~xwy~t~k||w{}tyvx}yx}uu}wwwqvt}i~~~~tx}|zzyvw~zx|{ppxyz|zx{w~o{zzun{xy}v|x~zw{rwz~sw}{{rxy{ouv~~}zt~}zxvu|tzyzo}{m|q~vx~~}~xh~~n~tw{x}}~xz{}wvzu}oz~vuu{~o~yqr{u|~xxyz~r}zx~yy~}uy~~zxu|uu{|r}|~}z|~~xuxyv{|xwvs}v{{z~{i~|osyi|wqzuz|tu}}}yy|qz~uv}qyq}~y{s~ywyx}ln|rw{w}zu~||~}|yg{|w}|wov{{l{|zxr~qt}}x}{}txz{{z~}x~qy{w|x~~w|vwyt}kh{uw~sw|w~y|~x{|y{zu|~~}{w{}}ysx{|~~{p{{zi|j}x}qwp|y}ls~xyz}yzo|s{xspvx~}|yvtv|~||rn|oy~}v}|v}s|z{}w}y{xvrvw~|p|yx}}u~jwy}yz{|q}vx{w|~~ywz{ylt|z~yr{{o|xwy~~zr|q~tyzz~~z~xz{wyqj}~k~~}~zww~x~tw|}x{{{mpuuvxy}~ny~ty|ivyx~|}}wyy|v}~}|zws~~s{vk}xuxz||wyvMv|iyyjxn{zwz}mupy}vO~g}|yz{i{z`z}|l{}x}}{n}o}{ww{|swrs}r}h{zzu~w|{{vw}}}vy~}uy|{zwyxxtkyxsytoctwx|z{w}y}~|}|~x~vwvw{x}xqw~z|z~zzYzy{wz}{}|~l}tx~vv}{C|r}wzztonkx}{{vs|y}w~yr~~k|xy|}}yy{zuy~~yuz~}{y~ytrzo~}zws~zkxwx{~vwy|wv{v~{{w|sqz|{uwrx~{}uzy~zyuqv|}el}p~zw{}wy{{wr}}|~x{}y}nuyrtr{l|{zy~zwM~~}v}xzwtqrw~~sx}~i|ovovmufwxv}l~uw{~{yryty|tw|rp}jxj}nr|}}r~||wy~q~suuzyxw}tx|~|{}yo~q|v{qw}{nu|lzxxz}za{q|p{y{vlzww}skr|}z|mql~~{vvx{zrx~z}uz|xu{ezz|w{w|}|kg{{zztyrk~zwy{ky|{vvu{zvyf|}v\|n}}t|w|zu|z{w{wvy{y}|t{zxpx|qm|z}||{y}yu{xvlkez|}zyzyzw||w}|yp|}|ux}P~py\qyjz{vu{{wzzur{y~xcq{rzwv{xY|xusryn|swUwftx`xw|}{}ntztx{u|}ly|ynq{yeyw~zuvy{ylz`|xxxu{zt|w~~yxx~|zz{tzq||{u~vuwsypm~{yxwwwut}~{}zmwq~}ztr~y{}x~x}qyun~wm}uz|vy~y~r~~yxztvs{tpzwqyrv{~sxxz{h}wy~w|tv{r|k|x}z{x|u~qvy~|vy{tygy}{~{~ru}ux|sywoox|y|}{|{uz|Xyzyyxb}z}yzyvxy~w~~vz~zu}ywsxx{uszw~{ry}}rs~r{~||{~||~|~~vyv}zyzv{mq||l|ixwvtyzzt}{~m{u|w~z}{zyr|||{yvyn{y|wn{stsm~w{xyzz}}v~pzzw~wpt||}|}uw|zxw||~x|xu^ywt||z}yxuotjp|ups}{q~~l~s|n}|~}lvdv~~}~z}wk}v}}yx~r~}{zvtrv~z}~usxsy{zr~zm|~{vgty~}r|wy|i~o~}}s|wnvx|{~~}ykz|xxuztpzor|w{}yt{s~u|umy~}xzzz}~wyxsp}|z{u~~~{qv}urvu{nxt|{sr{{{~j~zw}wzxsv{{m}uoyzv|zwozl}zms~}|sw{|{yoxxswx}z{y}|qj~|v~zr}wx|xyt|~{{}{rf||~}rnus|uss|{~}|}z}v|lwputr|tytr|zxzy{wk~zrj{z|k~v~wvsqm~~vz|uy}zx|}|yxlw|~w|}~t|x{z|hszv\zzireyvq}wwz~xk~~~tz~w|yjt|rtwz|w}xnz}{y~voxrzuyz~pyg|yxrjx~z~~{lq{|{y~|tzyz|xopx{~nu{|{vuzv~m~|oz|}|zt~vy~ny}|z~~x{yyw}|gwvy~v}||x}ui~~vxr{~||sm}~uv}|{y{s|ix|~{yw}{}r{~{v|~|wz{{{}ux}}uqxxzqyq|z|{pxp}wxkq~mzr|xw|}}wy|ysz{xc{x{v~z~y|it~~{yxzy|u{wqw~~xz}{zwzmxz{}wk}zxx}~}{yvw}{~yz~y}v||x|{~q||}~t~||y{{pww{{~umx~txy{y|s|v~y}~\xrw{x}h}xt|x}|~uqz{|}y{~yqktw}u{x{{|nwrwy}xyty|||z}lzy{nu~xw{tuyzvsn|upz{}w{z\~|msy~zUyyx}ysy}y~{zm}~tuyuy|youyv|v~w{t|]~rr{r{o{ru}xqy{yqsvyuv{}{zzz|xo}~z~ztqyz}y\}me|~vizyv}l|sv|y}rw~}iz}z}zw{}|otx~{qx{swx}uy~}~z{|~}}|kysory~w{|}{{|ux{t|xt|{g}}}~x~|}z~}w~vty}~zvy}yyzx|~{nz|yuy}qmx~r|}xszz}{|u{}}~z{xp{xz}t|}~|{}t}|vu|~}{t~~~|jy|yyz|~}y|xx||~r|y|}v~yzj}wuw~y}y|y~~txtbv|vt~y}xgp~|~|{wy||}}|}ytxyyv|}|wy|~~w|~}~}|}}rrzysu~xuw|on{i{tq}{{|zo~~tz}{}sw}zyv{uzx}|}~{v}{}|v}spy}u}~s}pmsiu|{nvzwzyty{z|rh|~v|}~~~sn|urznyhrvvpzzx}wyxwz}vtxz{wx|{zyxvvxwmps~|vywwjzwxszu{xxy{wxqf}|st||z{x||wqw{n|tly|y}~{zw}}u}vg~z}{s~|nzxy}z~xx{tx|w|qs}{~1q}yq|u|}xr{~|ksf~yy~}o{{w{sqny}x~rvtz~|{wx~qmssvuy{xz}qv~~~}zyy}vtp~xzywx}a{u|tx~~t{uy}~s|wr~zvpzz|w|{xw{~v}wh|r~}y~|y~v~o|wvnrzp|{u{~qxz}l|tjv{}v}z}{fywzx}{~~us|w|o}w{qs{}{|zv}x~w{xfrww~w{~vlo}t}~~yxyt{z|zt}}Upyh~a}{|}{~wz{l{v{d{~|utnx~}|y{{z}v|}xo|~y}iwryz}}{~wyyuy~~v|izz|~zyzz{}zz}m{zy}|~}i|{w|{{ppaxxt{{u}}qzsyUt~vvq{wux{z~~{yzo~wmoz~x{~o||}sy~r}lztspyzs||t}tx}y}}z|||xz|hx|zy}u|y||~x|wn|p~~}yy{|z~}}}rr~}zy|u|}nz|yt~}xzw}w{yvz~{~e}~t|vxxax~|{{y}}{{~uvj{~{|l|z}{~S}y~}}|{~{}u|ysqwz}yv|rzf|{{~r{yw|{o|ssuqyqx|cuou|x~q{zuyz|zyt^u|~s}oxyr}{m{xz~s{pvvzv|xyu~eyxyjx~||svmxtv{s|}Y~|}{x{xmr|yt~jx|{}q~ef~X{v|x~wo}y}}~jrxyz{kx|wg|x~{||sx}{s~o}}z[t|uup{sq|g~}o}xz~izvxsxwtuwzzz|ssqxw~z{w_puy~}}u|c|v{tuzwy~yt{py{~yfizhxs{ov{{{xs|sptmu~{twyxx|z|zwy{}tozxbvyu{nthuy{Umlyzeuqe}srvy{~y|||xy|xz{|~|sy|u}uwlqtu~|uzz}uevw}{||~vyrw}rxowz}s|i{u|xzp}tbzy}uu~qwju|}{z}~{~mx}thn|{ynytp~~ot|ns{z}yvwzrx|stz}x|wnw|tw|vz}yg{~y~wn~~pmv||fkz}x}~yzrvk~~~vq}m{uu~t~uiuynyzq}{i~ut{z{{v~v}|}susx}{ttqx{~x|||oytss}{z|{hvy}wyx}{lxy~r{||qs{u~y~wu}~_}|vz|ouywsv{{~{}zzwyymjzvy~}qvxw}|w~jzxvtyzvx}wt}vxsyu~q|q}v|x}ruzxqvs~m{}wxtvwyq~}nvm|vyw||v{}yzhsz~xr~vy|~z{}~{yv}}wxtxq|xypz{{v~yvws~ytv}|uy{}xz{zwbw}}t~}||~~moyz{{s|xvyjzvq|q}wy|w{s}z~zztqx~z~wpzxuzyhqxy{{w}vxxw|qxzx}uxg|~|{z{|{t|u}tzp~w{zzx}xvpxuxpvwn{~}h{tx}z{z}}}wr|qxwyxz|u~wvw~mzxk|{wwyy~|wwnov}y~~|~zh~qxp}w|mwzks{p||~{mz{~s|uzm~|yx{{xr|||y~wwt~|iz|{|rv|y~{~y||g{vy}}{q}{y}|wz{~yrm{p{{{|zy{tw{{~ty|zvpiu~fv}tfiy}zu~zt{tov||xxwy}||~p~rvs}}{qzt{v~x|~y}pv{vvyzww{{wxr}|kz|yrzxu|lz|}}}mm{||}xqyyszxwwnn~u~|pzv~{nze~~vxxvxoz|zi~bu~~|zw}~xwt}zyzvxys~u|ifyzttv{}{z}r~yt}uz}t~~nyvnmwoo}x{w~|~ys~t~{qvyy~xvzz|wz}~xm{yawzxt{{|uzqr{|xv||yzyznzs|ozyyw~y~z}x}zwv{zzyp{xxgvstpyu~yx{{~rwy|x{tatpyy{v{s~tyyrYz}xyx~q~xsx|r{}}v{ry`t}azhzw{upkq~yuq{~t|wlx~~}k{zolux|y{}|s~p{w{{~~lzks~x|~|}}|}z|||}{su~wszqr}z~}wvuty}|}wyivt~~}|}{|zyptmxp{t}||qy}{w~|s}{|hl}uz{uzu~|z|s~s}wy}yv|t{w|}}~~j|w~~sxr|{yr~{xw~w{z~{~~wv|zx{}{p{y}}{{|st~w}a~n{{x}{tr~zj}{yz|u}~v|syrzwzyr}x{IU{~zz{{~y|}|zxqtysg}|}vu~~{z|tszs|syzw~~n|t~~p~tz~s~{r}tgyo~|~u~|~mr}yws|~~u|{up{oi}~}y|ny}q}}}xrz{~~~v~~|nuVu~{|z{r{tu|z{zwrx~ev|wx{~rz}y~~~{y~ywvn{x~|rz~w{xt~{}q|z}||zryzzz~}}|z}{zuuz{z}{zv~zsn}pyyly~|~|~}z~}}}|~{sw|r}~||x~~wo{~rhyrt~~~{{x}xwxzw}x}yx}rzw~o{|{x{w|}xzwzw|y}~z}|vz}w|}}zv~~utv~}|{}yx{~y~{{w{zvzr~{wyx~t}}||zy|u}y~~w{{}op}v~}z{yw|v}~||~zyw}z{yv|}}}tx~{yyt{tzw~py~y}~|zs}}yvu{{|y}}xv~z~|~|h}zy{~{s{x|w|}}zv~p{vzx~}{~}uwz{~xyy}u}||s~z~xv|x}xvxu|kjvp}~r|}wz}yx}{~u{|v}y}||r|~xzr||{{tq{{|zuyysx|vr|}}}y|}r}ztx|y}}{v~k~}ch~}~xvyzrt~v{z|}{~x}|t}vvvxxxw||~r{{{z}z~z||}y|~~~y}{q||z|uyxt{|zx|}|s}w||w{~yv}mtr{v~||~f{{xr}uxo{z}z{xpu~hv|}y|x{x}}x|qx}zzy}}uyn}~qx~yk|yzzw|p~}{{u{|zlz}~yyxxz|wy~~|tz}{~yxv}z{vp|wy{pzlytgzn}z}}k{z|zq{vutzyw~zwyyh{zy~s{g}}vxox{||xzhzx}qvwzx~}{x|zo}wox{c~||}}r~{x~~z{}{|u}u~txd|{s}y|}|zm{_{{qy|~~yul~{~~}v~y}rs|vl}v|wtry|j}~|}sy|{x~}j|j|etx}v}}v~u~n|~hq{}{y{xxv|zw}m|rwu{~{}hz{myp}wn~s||vyotxzw{v}zxx{t{}z}||r}c}}|~||qwy}{{wrs|{||b~|}y{~xx}~r{n{z|l{wr~}zx}t~ydtwp}{pp~}{}~zyxy~q}|u|~}yrzytk}~~}{x{ozu}|qk}~xy}{|z}vw|tss~{|zoz~}xy|}}gx~|m{}|wpyoqoywy}zx~u~sxt~gu{vyrqzxw}u}~{vx|hn|syt}}{w~~~{{{}|y{y~|}wy~xk~xxx}n}|{}z~~|~z}x{wvv}{~||wy|R~y~~~wz|nw{v||s}q|~~s~xsz~sz~}y}~y|}{|nzznv|dq~}|{{r{|qxx~{y{}w|r}wzu}vps}|{xpe|~~}uym|{u{~y|{vj~w{~}~z~}my{n}~{j{{zwn~~ysxz|{|gt~z}q||zn}x|m|qjuxm|{e~bv||}t|{y|z~~wwcwi~x|{{{}}|x|ajjx}v|}{}w}|o~|z||}p{x|x|}~{~{|||yirx|z{{~uv{yy~osgp|hwuz~l}{|z}|s~~z{uz~uzvxwy}|~{xu{yz{{}szy}m|{ysxx|~ryp|y~}xqwyx~w{}u{pvwv}lzxsooqzu{}~{~x}{uz{pw|~wuvzyr}rzzzv~~n}xe~wv||pwtv{t{k{xuqkxxpxzv~~x~|ultovuwpx}|zzuv|zwvxr~vo|ywt|[zmx|o{zy|||}|x}hyy}}y|zu|v{yx}fpjhqv~~{w{nk{tg}|nvu}xzi~}~zlzy}ryum}||vu}~o}{wvstq}w}ld}z|q{u{zsswt~tzxrvyfyv{zzud{{|}z|v}y|v{piwzztx~wzz}}p}|h{rky|x{u{~duj~tx{{||{{}x}tz|w}Qzs~r}|v}~}u{{~zmy}txzysqxwysvqt{yz}~vzw}q{}}tq}wxvpn|}|szyw~zrzy{nzzwwp||vvxxy|wn{z{x|xz}z|}}|~wptquums}ztm|ww|zqyt}xyu{}qw{|}w{rpzquu{zyz{}~yu}yhx{y}}y~z~z~}{{vtwwzzw}|}}u}|{zwz{zz{}yvsuuwx}}{czy~{|yztyxu}r{||wuxy|q|}vvqwt~l{syvwxtwrxzy|t{}|wunyuw{u{y{{zx{q~zvw~|~sstz~xzvj}pzvzr}w|u{w|~w{m|nprytzyi{z~}x}zi~vv|{~|}y~wx}x{so{y~|{uyut{|z~y|tzs{|q{|v~y~~uuys~}so{|xozwu}xpvs|{qyy}uz}{{{{~v|r||u|zfwyyxtwsxn~wxr{yp|zv~tum||{~||z}rx}wpz{}v|~|{{xuwoz{~uV{~}|ty{||l|jyy~|x|t~~s{|~|z~}~v|z{t~m{xw]}|{zvyey~j}}zvqpxmzs{ysrw{}~xw}}vus}u~gsox|m{}~{uz|{st||ys}}xsivvu~zt~wztwvvvuyn|{yzzt{}pw|}~wmu~~t|{~|pxvsp||zv}wy~vuz}swsqjyw}r}}{ur~vu~}mwwqy}d{rzv|zrzy|x~ylsz{{z~vr{|xwz|vv{r{t}n|kv{{y|~~yr}|{u{~i}{sqxy|z{t{v~||w}|os{~{|wyx}yz~|}{t}|{{|v{}}zywsqx~{x~|zv~tt|v~s{zqnuy|vx{yy|y}wtuw~{xzy~}z||xw}~~{w~lvx~w}~{~|y|~z{|}zxzrz~utz|y|{~||~}~wy~u}v~y}|z{iq{x|t{~sm}~v{~||}u|yzw}ox}{yxzn{zw|zy{r~|tjugvw{zx{zwwv|xr~y{}wy~{mwvrt~s~z}z|{w}xy}||}zy{u~qxx|yv|yr}t{vy}xw~x}w~q||~{wv{stxv~}}{}v|~z~{x~|~|xy}rwx}o}{u{yvz|{z|w~}zv~yw}wy}{yyy|z}vxs}~{y~y||sy{v|{w|{zz~~wvu~{vyyky~|q|~}wx|tywyw}zw}|t{}|xz|pzx|w{{xz~}ux~zzyytzxxxxzt{yvx}svyz}o||y|}|wyypvx}z~rvz{x{w{w}x||}|~~{y{yw|zy}||{}}|{zyy~ut|t{zv{u~tyyxx{zxw|nv|uwnu|zwt{wz{}}}wyyzwx{lu|v}|{vy}v}~z~v~v~zz{y|wy|rz|s{r~yxrxx}r~{qwtuvzr}z|~t{b|upzz}qxsi~s|xuizv||mt{{|ru~wq{{~zt|rm{v}|tr~}x~}}}qz~~}d}gpv|q}cz{ixvs~yuxymyvsw}y}r|pqyxz}{zxy}|uzu}v{~~}zzy}y}`z}vuyu|}uzo{{zr|{r_~Lt{{xlx~|tu{yg~{y}zxsot{}}vwyvtwyx|vwou||y|xy}}{|~ms|{wusy}yvtx}}uonyd~~~~y}{{lw|yz~~su~w|}{}osgrgzu[ms}urox]oqt}wx{sqwx~yywrwu~s~yyyzzzt}j}}Gx|~|wrz{p{u|{|wz~~~|yz~vx~xzm}{|z{yvyuw{qyw|}|x~z||nxyw~us{zun|umwxvx|w|rtwzz|wu|zqwu~zdmrwvtv{|y|}}wxuw}n{~}zr{tuovrxz}ziy|}~}xv|yw{yw{{|yv{}ysz{zwzzww{t|zsw{{{}t}qV||zz{zr{xutuh}~yzw}v~|yz~zw|nuz{q|||w~x{pootz|{t~u~vn{xvzytpy}yx|wx{|w}}}~||~{~wqzw{rxiw~rlvzyq|zpxvy|s~|my|}oyxzyw~}o}{|wy|lx~v~uyr}||z|r~g{w~|z~vr|zvz~|v~}vy^~{{rwxsxzw~~{~ww}|~~pw~ovwxp}|znv}~}~}|}|lv{|qy{z~}rkuo~r~||}}zw}ttx{z~}~||}|zzy~kv{{}xl|~uwuyzwzv|tt}|nyxe~tsny{}}~ltw}z}z|s}|z{~vkym~}zzwtx|s|p{}b|}{|}y|}|fsz|}}e}y~zc|x{}ywz|y}w}{{zryz~zxwuswu}w}qi}wt}pu{|{x|s}w{s|kx{{|{|v||zz|{|x|z~v|tzv|~zu}~~m}txx~{vz~yezkvsybzv~y~x|}}|xzzylzy}wp}}z}ys|}z}}|{|~}p}z}z|zy{vt~|||~{}x|}zx|wvs|x{vrmknzyzzx~|y~or}}mwv|}wwzyzzx|vug||wx}|~wx||~~xxs}rq~yp{w}~t|~{~s}{~}x{x~z~z~}}t~y|}uyx|{x~{|sz}uvq|~yz|u{s~}px|{x}|~{s||~qmt|xw|vy~zyzss}kssz|w~iz{|u{|xq~y|wrt}{v~~}j}{xzp{wh~otdxtq~ozkwxz}y{whm~d}y{}z{utn{u{vutuuwxw~{x{~v|}~r}|{~}m|}{}sz|vxvxyvzyzzwvuv{}}~y|sp~w~|u{tvj|v~{}wwyw}~xmt{~z}}}~ys{s{|yxy}rvs~}{mw~w~f~uty}{x}zz}`|~zxwtizzr}~||y}{pyv}qvx|m{~}{zu|y{}z|vo{}k~}q~{~o}{}}v~{w}s}{Zzo{~xyt}z~zz}y|zryz|{uz}k}|x{tfr}z}||a}~~z|uy|~{}|h{|yzux{s{xw~}}|~}~|wz|}w}|{w|}zsv}|o|}{{opvw}y~z||~y|k}uy||{~~yyox{wx~~u~wzsozv{|n~vx{}v|x{tbw}q~}|{n}{v{h}x}{{}~|u}|~z|kut}v|}|}{}|{|o{tyzf|xvh|tx{yqc^}~y~xx|r}||}~wz{z{|zn}}}~~y{{{wzx{w~|}~m|~qq~{r{^}~{~q}s{zx{zyq}zvw{yzyr~x}y}x|usxsyywtlx}}|zw|{ysw}|{{{r{s{r~tuq|~}{{|xzx{~t}p{y~|z|}|~p~zyyy{z~t{wwrx}z}{yj~y}y|{{}|{wz|}h}}yw{||yyozs{x|{r}~x|s|}~~|}}}vw}~xzslrwryv~z~{}ug{yvx~z}}xj~yrxt~xytx}wu`{y{yx|}yyv{tyv{y~v}~x{xwsut~{|qss}w}{zj}wxs|~xwy|z}z|psxz}|||vyy{xyw{}}~}~}x}nz{|w|pyz|ny~y{{zvv~v}nu|t~}~y}{{z}yzzzawy{ty~y|szx~zu}~{zuw|x~vzpxet~|zy|}zxzq{v~zy~}~ywswu}|v|~wx|pt~rzw}{v}u~{~v|zvtzzx||q}~{{|{rzqum~|xo~yuo}xz}~|ww|}xop{vvu|{v|j|w~}vou~zr~}s~m~pt|xuwwy}r`t~{s~|~turv~t}w}~s}qr|zyvx}|up|wgx}{~ztzyx~o|o}e{}{{|z{|ru~z\yr|p{s}y{{x~t~z}xipx|~zoyun|`s}}zq}x{qzqfywu|}~|~q~uw{zx|{}|yv|xy|y~u|nse~y|tuvy~}}~}}|qw}|yr~~xzz~v||xyzvy}zt}}||wWx}w{zt~sxw~~{tx|x{|my|{pouz|yy~t}t}v}yszu{{~yx}x~yx}}~xtw|}kr{{{t~yyx}ypyz||xxvy~uyzy}y{y{yuzy~z}xr|||z{v}~|}xvv~zt}|~y~~}||}~ym{usxxwyy|y|m|~vx~~}zswy~|{y}wrz~|z~}}t|~vw|y}|~v{}zxzv{~xuwuqz~ww{|wv{z~x|{~z{{yvx}x||sy|zvz{y|rxp{}|x}us}{z}~|}~|{|~p}}}x~z~|{xy|owzuux{{}u{wuzuu}zyyzz{~y}w|z}~tzzr||x|wth|s~}{zkvyxs}}zzp~xy~yzu{}{{{z}q}|}~{xzy{qwz}~yyv}ywrwy}rx|{}w{tov~|zw|zvyu{pn{z}|xxz}ywz}yyusw~||tv}z{}ruuyvv}~{z{z}v~|tu}}yw|{zzzt}~}v{|t||x||{s{|x|}vyzx|y~vn{z~|~o~|r~wyx}w~zs}~{n}}}}|a|}z{y{|yu~}wuqz~gx|~~z{|{wyzs}|z}t}v}vwzw{y~|znp|xzuxyk|{{zy|z{z}vw}w~w{{|z}w~{|zxw}zw|}|wz|}k}z||{yt{{}z}y~yw~w}qxx}~zswt}}}~~y{yy~x{x~vyzts~tz}}|kw|z~rwz~z{|gy}}}{x{~{yzyzuwvo{u}~}r~v|oy|xv{x|vwqvptw{~}}zuli}msn|b~zzs{~|{we^yxx~|{}}g~xmv~uz}y}|z||r{yx~z~}}z~ht|}sszvwt}iz{qzxxx||wvuu~}~wywvv{rj~yzu}zv~yv}ny|v{vj|{~{z~~wt}}ty{|u}zz|v}ll|vy{xwwr|{|~~wyyf}hy}{~t}gw}zzt|}}}tvyh{}{yj~~wwzwv~l~{|x|r}z~r~wvy{s||||V{k}|}{zjzx~}rf{}{v}~xr^xw|{xtwv~~}{wxo{w}x~y~yu~|tz}zt|{psx}z{p|zv{~kzy~{w~~uxt|||u{t~y}t{uz}trzzv{|zy|z~z}}xzz~|u]{sy~s}u||xvzy~}|y~s|zyyyzh{|f~yzzu~}}xz~}wyv}y{yy{~~zu~tzmxu{yvy}x|}z~}~zyx~}xx||xnz~rr~z}|v~~y}|{zyy{x{ww{o}w{w|}u{{ww~}u|p|||x{v~z|~}}}~|}||}x{z}~~|zyx}~wr}}yqs~y|~yzywrz~w{x}}|}}}z}|{u|{~}yuz{{{}wx~~qwszqxyp~u{xx}w}~~z|y}xq||y{u|w{~y|v|z|s{}x{||xsyws{|zu|y{wsboyw}yvzzy{}~}ypu||~r{r{pr|xoyz{y{{vx{{}y}qx|s~}||~yovvr{uvxzzvvxwo|~w}uz~uz}~~ltyzwz|ryyyyx`tz|{yuy~x{{y|}tw|{v~w{|yy}u}y~n~eyzs{Utzy~w|pz|s~w{o|zyw{suqh}}yzxytvyn}x|s~~yywzx|z}t|z{{z{z~vym}~}voyyvz}y~z~poz~~{x|~}x{rz~urz}{uo}y~s{{|~}{~r~|y}y~st}|sywwz{}vww~xyw|u}{{ze~{~~}|ux}{rl{}{uw~zwp{~~|s~|z|m|}hwwz}vvrqu}z~y|y|yzoyxy|~y|yzxw{z]}xt}{v{|{q{sz}yvt{~{wzqys{z}{~uv}z|t}{vu}|~zqduu|uszqqxzyuq}nxzyzszq|~r{|pr{u{yyur{qruzz|x{z}|fw|}y}w{xzrs{tz{tx~~s~}x|wrsw{x{xxtgyxyty~~kpw~z{}s~x{w~zuuzyuzyo|yyuvhyq|ly~{~|ykxy~}|j|oo~{wtsvvv|n~rrY{x}|zrvuxn|yq{xp{~hzu|~}ywz}vk}v|}uww{vy~x}vq|p~yp}Ytv|}{}~pjxp~syt{}wytsw|xz{kono~}n~y}|}}u~{tzxxvxux}qtxw}yrxy~yxp~wtuqtyz|u{z{t{yvx|tmuzx||vx{}ov{v}||{jv{}v}x|y}}yzxmp{vuu|zm~nnx{zx|}~wy~~r~~r~q{x{r{lvy|u}z{yv}vq~|}w}{|}wv||q}~snur{znn|snq{{~y}uw~}|t~~lx{{pqxy[zp~|tv}x~}v_v~}yow~t{y||xyzw~zwz|vvYl|vr~{_|sz{{zz{qz~|}}zz|z{w|||u{v}wvz|zw||t{t~{{~}qz}|~ytyoww~{v{}uv[~mz~{||tx}~~r|zj}xw|oxuww|{wtUwzvz~~pzx~g{x{]lx~zyl|x~|xolyq|gy~z|}{~y|{~}}sx~qw~in|x{~qv|w~{xw}~|wzkwxvzy{x}~z{z~}zyp|wtv}vsrxxq{~lo}}wu|j{ntz|~|vx|xyx||uxsu{{~|}||z}nxx~cu|y|u~~x~q{vzc~vxs}zw}woy|v}Ywy}}}r}jwpr{s}|}~q}xx~r~l{|}hyi}yy~ot{y~}zv}xx}~||}wzywr}}~uz}}}}}e}{zmu{t}j~|}xv~}is||zvmxwv~r|}w|x|~~gz}xuzxzz|qwy|}z|y{~|y{xy~py|{|ry}{{|}t}fyues|{|y}t{tvlz}z}wvvvzvzn~z~}|~}yzi}z{p~~zx|yv|}{}wwz{s}|}wnzwuyux}}z}j~hx}|jt~}}{xx~}w}{swxr|}ndz|~|~v||{}{u{~x}y}|z|v^~|x}{q||~|~z|s~|t{k}~x|z|zw{}{}}|s}y}wqu{qwvv{zzv}|{j|}~yx|yv}v{}n{~tz~rz~}y{lz~u}|z{zz{zy|{}~|}{}|ty{oue}xt|lzmr{~~}~hn~|y~wg~~~{s~{pwu|y|}zz||uunt||}}~z|az|z|uzr{|{{}{~}}yx~yzx{|l}lyv{||ps}ru~}y}r~{nyy}vv}{||u}xvy{xoz|x~|l~o}{}}|{m~|}{w{t}{}|v~w}{}|x|yxvd~~wx~{}wtw|~}ra{utulo|{zxx~y{~{{{}~i}}vz{x}n}x}{~x~jk{bn|}t~c|z}|~~{uut}j|~~~~x}fk~~|q~|xtc}h}}|}y}}nvjX{u{tu|pu{{ry~y}~~qwx~}~u}}yzrp{|w{t|~ux~~v}pwz~}|f}}}{z}|s}l|soiv}vvyvxv}v~u}|v{~y|n|{piuyt{}wgxx{z|}wn|}yz{}qxv`}w|}}}~pr}y|||y|r}v~ntvxx|k}x}}vr|uwxz{{~{z}}hz{}{|r}{q|st~y~}|vszvwvp}||{wsxsz~u}z}{b{x]szzn}}~lz~|nx~ojh{~sy|}f{tozx||zv|{v}z{{}|{xq~t|wowzsrwtv{v_~y}woy}~}{v}kwZmu{m|kx{|zv|~zkuwt{v{{ot~n}x||ymwz|yw~r{kvt|v~{{{vyv~~yxzxm|zf|{ww~}~z~y|tiq|q|x{|vwxyu}jwu~|u}~}xsyr~tl{s}yyzzqxwvy~|}y}}v|kw|r}qt|uto{{urrx~z}yz|yXv|wkx}|yvy}}|}~xzzzs}~xuuytysxz{xymhv{v|rzxz|wjzzz~vpxrzxuxz|m}xtxwsns|~}|vx{~|~x|zu{~sp{lz~}}xzwyutu|wr{|uu}rycwlrzxnsxv|t|v|tvp~~}xwsw}w}`~twq|z{}tx|~zzx~uxvu{{~pwpvzzo~~~y~{}yw|{o~}p~~{|~x}~~z}~}~wyytytyoz~|o}z|j{{{|xu~~{z|tu~}z}{}~qy|||x{xz|qvzwxwtxr||x~|}x|{}|~z~vu~}}i{|tt}}|{~|q~||~}w~zvw~x{~~tqq|sz~xz|~~~{~}~xzqh}t}|u|}yv|j~}yvw}rxzz}x}~~zu{~z~|rz{u|wwz|x~sitvz{{vqy{|}ud~||~}yxjvq}{rf}}s~|~jy|ov|zsyp{~~|~zx|pyytw}x|vyzme{|~oww}s{s}~v}uqyzytyz~}~z~np~xu~|{|{{zy}}~}t}x|}x|{zx~~}~~~fp}{yd|u{zo{v|x~}}lz~}www~q|}x}~z~~|w{|}s|x|zzo||bvvyzw}|sz{yyr{vz{y~}z~tsjz~|~~yx|ww}ov|{p}qzyytx{u}}pyw|~|znk{zx}z~py{}}n~||{{|{zpy}{~|w}|zl~w{v|~{{vszzvts|zx}}}zv|vx}yoryxos}Xv}|}xp|y|xww}xwy{{}z}y|y|r}p~~{w|~t}z~yvyzy|}xiyzsr{~||{}xy{||{{l{z~|||zw|x|}{}u{{yzur|t~~~zq~q|{~||vvtvxxx{x||zwi{{||{yw~|mx|}sv}d{z{zs|~vw}|{{z{yz}p|~{t||~yvf{~{zv{yrzf{~z~y||wzprhv|xp|t|zot|nr|uqrr}z{z{em~o|zyuzxtuyjh|x~gpnr{rv|l}yqtkw{nz~zn~hv}xn||znZ}vlv~|svf]|d{z}vvxm~z}zz}|buvw~uv|}p||}{}oxx}{|x{k|zwwmm~uv}vzloevs|~|z{|y}ptwypn}{y|oy~|w{zwwux|xyp{wyv{zuzgyx}}{r}yu{s}unuu|s~ssuzzznzx~}ru||}n}}rzznsz{{us{~~|p~oxs~wt|zrsly{zw}vW{q}}wq}|~dyxvxxxzpq~vo|r}xjt~||~{wxv{zsy~|~x|{~w~mf|rwwvn{}yx|~z{yx}w{{|ut{x~{r|o~|ut|{i{}|xw{s~~pru~tt}kxh}~|yx~|y~vszx}|~zvy~{x~zrrr{{|}v}}|nzx}z{~|}y~z|||{|{ss}~un|{tw}qq}vz}wt{}|~}}zvz{|{w}v~uz{x{}}~e}}~tv}}tz}zy~yxz|`|}~|~{}w}|xxy{t|}xz~{{|czx~x~w|t|}}||yyqyo~}}uv{{wt}}y~}~lv|vx~}{ky|{|yx|~{||~v~x{pwv|z~z||zyz{qyp~ytp}zv||}|yzytx~~rqz{v}r}yok{y~ztj~yy|~vsw~zz|wzz{~}{|{~z{so~{t}~m}tyzwf}~zx{ntsp}z{tuqy|z{|p}v{}z{x~yw{sutyp}puuqvxq}wnnrp|zxy~|oyu{}~yyw{sz~y{{yz|x{z~o~k{|~v{d|y~~~wx|vlvy}}jyu|yzzs||}xyzt~|qu|rvpz~yw{y{xvxxzwxvtrzdxtfx|tv|zz}|~zvxo{k~w{|u}nzvsz}s}h~ql{onx|twtwj\}w}zxy}su}|yt{n~{y~p}pwzzry~xu~}|n{vxvs~|z~zvzpn|~y}wv|~yx{uzzpxw}ztyzu}|~pr{}rw}k}|kz}typxovq~}}zwqr|s~u|v}yyuz{vrtrlzl~h|}xlwry|vwn~}xfy|~zw{ry{z}ppq|~~uyvo}~|y|~{xkyzvy}~u{uzvvy{~vzds~}y}s~tw~{txt~~|{o|~rzsyj~{}yp|}~}ytoxtzm}k}s}t}s}}yyqxp~w{t~}|}lxww{rb{}z{znq~{xwt{zty~w}~}{f~}yxtxy~|u~qs{}}}~}vt|qu}|v}zzx|~zvUt~t~xsz{{|~x}zz~vkx}|vv{xjo~}v{wzywysy|xvw]v|{zzumz|~gq|}||}~{|uyy{|{wsu~rxyywts~{|y||~}yu~w}yyz~q}~z{xr}}xzt{vysyzx~}zs{}zxk~wxuvsy\~y{wwvxz|u{~uuv[ysl|~|y}}|z}w|~f}}}dj}y~}~c~tsys~s}|wvtiryo{u|~~}}wyw{y~xv{xp~t|uv~w~zvw~x|zzss{^zr{y~|wwh{~z~udie~}{suq|~zxu}x{yzq{{v}|r}yz}{uo}}yjv|}nuk||p|~}zi~r|owu|yxp|~wy}|tt}l}tz|zv|my|r{~wjhl~qv|xx|yx~~~~|yr~ow~{{}|xu|{uxq}rxr|xv}}zjx}vw|~}}~ugt{xx~||v{v{p{xuxvytxx}vzouxsrvyv{z|uhm~|i}dywq~|zry}vz~yyyjz}~kux~rz}|s}|zy|}hz{{~gypuJvwnz~{s|{h{o}~|zz}tz|}}~{~~wtxxxw}uw~t{}}rm}hf~~}}}~y~|}nr_t~{}yy}|wz|hzTpqw}|yz{~yw~zOsv~~x}}ooz{iyxcx|~~xzmy~xt}~wm~zv|yy}~z|q{v^x~|}~|}}}~~tz}mywxpv{{x}xu||zuzuju~zx|~}ul}~~x|~d|{osqf~}{{z}|}~zys|{qzuybxmz{|~~{ux{yk]{rw|~o}n|}fsryuy||y|xwpy~{w~y{~vqy~{|sz~qo}xvz}ys~{z~}yl~|~zu}mkz~~}}y{|x}}s~}k~~k|zcz{zyx{}xu{uy}{}}x{qx~rwxz}yyczyz}D}s|}}}yxz{ug|vyv|n|m~}vswz{rs}|}p~~wg|rFcwvstt}{|z~x}izxzttz|xw||ww}ywstsvs|zyxuzx}zs}}t|mwwwu~vyxszuwy|x|}xwwvz]rnxz|u|x`zvz|~uytq{wz}vw|vq|rtqn~~|p|~zq|y{{z}p}{z}w{dx~z}wzxyys~z~Svzxss~wdzw||bvz}}b{u|ywq||y}xz}}~}{xhn~{|{}`kvo{t|yy{wl[sv~|y~y{}~zs~g|ox~{fv}}tsutx{{t}|}wfz|}~}Ezvyyu|}~|~~}~sz~zykszx}||{~i~~|vyfwh}om}|`ws~yvo{pynpra~{ul}jzgw|n}{||zuuvrxmswvvrx|higpxspv||z}y|}{z|twtsnsuyz|~~Mu|~u{wonvxrt}yr}s]wyip~j^xu~~equzwz}_xqxCywzq||]~}zdxz~ex}\vn|toyoyxy\wo}`tqom|ntk{xx|}py{}t|w~lz{m~ozt|my}rzw{{|}{u~Tt}~ytwzt`{ut}n~z|{uvqvjzsfru{ztpmvx{qvh}yqjxts}}n~uaryzstdrywywwqp_v|y}wruv|~jnkxwf|ra|diZpu{x}owulr|}`{j|u}\p||y}~}Ssz^~yzjlh~|e{z||n|lv}~xu|~z}f~z}z~}}y}e{ov}~y~wv}t||t{g{|z{~}{~}yxx{tyt|x|yp{~~km|vq|{d~}rve{{vpk}x|v~u~}{}jn~{t~~s}~k~u~xzxsq{|w}wq~qh|qyvx{t~twx|h~}z{|yv|}zzp{~hz~|}v{w}ryq~v|{}yZ~|ls~v}`y}}~~x}yj||wy~{xz}wx}bm||}}{w}t{e|h{o{{|}{~^}zev{zvjxs}l{}|s{~~\n~|yyq|}~z~z}Z~zu|g~{krxv||||uivyzu~zo~|~{s|}|p{}{|yz{||~|w}|~}hqz|yvu~~vzpytz{yx{pzzyuwvt~}wv|z|tzw}vmwpu~vxyuvo|}{|w|x~y|y{vx|x|{yz{wr|wzxrzv|||zxxtx|thyzutzzzl~|yzwyuwyz|ypv{ywy}zqx|}{qx{}}uw~|}|{q|juji~}p|wurps~ywwvnu{xuuz}t|}{zg|yxzxg}}wws|{yvuxq}{nt_~~huytmiwyyu|{v{}t}zx~~~{|lkxlvs{xzyy{psztt|xzwov{|~|wyoqrt{txy}xx{|w}yz~{quy||z|w~~zz}n}{rxwyyn|z{l}||xwvryp~tvvuv}{nuzyy{zxqsvtzyz{u~~wf~uwqzqks}yttqu||zww}|wput~{pyyuv`uz~ywu|q}dvx|J}r{}~s|z|z~vt|k{|vx{{p}t{wqwr~x~znx}yrxrjzy|}~ytz~q|roxz{q|}~ut}~vzo{}||}}~~y{yq}}~|wx}krw|wt{}wy~z{}w{y{zn~wxyyxy~|ez{o|{{~~|yw~|vwj}~vpx|xqvxz~{{w~|w|}~x~}up~{y~}||xs}~|qxzlsxwxzyzz|pz}xz}x|}ry{xzzj|y~{vs~|x{|yw|mx|y|zxyy}y{yv{{w|zyt}o~t~u~{{szyxx}~ywws||zzw}szwxw|yqy{|}|~{wz}}v|w}~qz~z~}uz|b~y~hr{y{xw|z}|rv}{zlu||yx}xQ}y||wt{reyzvy|xzyxwr{|{~||h{l~|yzzzw|}pz~wy{}Oy|ys~{|~z|wsyr{~vw}~}u}~womy~}xv{{{~~or~muw|yu~yz|wz{y}~tu}}~w{ow}nx{}y~skt~{}wrsz|zv~||{|b{|}yv{fs~{nxuet|}}}{~x~ru~~y~wr{}iww}~r}|v|~|v}{{v}}}|v~{kq}}|qz|z~vzi~s~z~}w|~}}{xv{|{||~}}{|tyxl}}~xz}x~z~{{t~~z}~|{{}x}}z}|||x}sqb~t{twx}|yw~xuv~vyj|s|~}}y|ul|vvxrvzs|y~{}~{~}lw~xvxzjkv|}h{y}|rxz{f}f{n~x}}zwq}|{~yz~e{uw{utt{{i}|}t~x{|x||}s~zyx|x|z~vvyywnzr~x~{}}twx`y}}}~|}~|~]t~x}n{~|yy{~|v{u{}{xpt}x{{}{}j}|yuem{qw~~}}vy~{||}|v~xsyxz~}~tz}~wvio}x|~{}o}}}v}~}gvyh|uvwtuzsaq~zw~z{{{t}x}zwx{~si~tyxp{{|y}{}{z~~{{}ymwztz}}|{ztyp}ht|}}~}o|y}zy}xsu{{vzurzrz|vng|{}t~xo`iy|{~z|yx}u{}twv}z{sux~xxwy}cxsl~y|{w~|}~|rxwz~w|n|a|x}s|yzyvs{z|xv{qx}z~xmtu|vvwssy~yr||zyz|z|~xurvu}x}ziv}wvzrszry~||{|{|vk}~{u}~st}}{~|{w~~n|}}|~p||~|~}uzwxt~w|up|uyv}|tmmtuy}{ywz}|rzyuwwy|m~zz|x{|{s{|}x~y~p||cxstw||yqu|x{xiz}yur}zyr}uw|zs|{}x||wywwyt}~ytz}w}sx~{~qxr}z||{mvxw|{w~|s{{~x}y~zu}xyrwr|voyxuvywqz~~{ttr~|~y|vwx~|||www~|r|z}sz}}zwsn}~s}yphx{{xyqv}|}s{x|zxzww}|s|vsz~tz{|m~}y~y}vvu}~~vzy|xx|wz}~~}q|yv{}yymy~zzo~}z}r{x~xwt{w{}~rqt{t}x~}|~wuy~|{~|}suyt|~vuzy{xqwz{z{te{{qzyw}}un}~w|w|vswxhyw~zty|{hx|l~u||t~~t||s~}z}|ktu}xyyyv}o|}|s}{y~uyz{zz}~|||x}xy}~|~|~iz{~{~xvy}{|~}{~}q~}yp{xxzwt{y{w~}zzwz}xyz}|z{}{~}y~vv|}q{}|}z{~}z{zz}y}x~~c|xx~x}vzxvw}{~q}|z{zvwr{z|{zu}z{~|z{|yqvtx{{~yw}uw|uy{hzvr~~|y||}}{}{xz{xryw~zx|~w~wx}|}}}{y}~yo~{|}z|y}ysv}w}{r{{u}w}z~}zzr|~{|yv|z~tzpw~{r}~{}o{~x~|~tu~}}}~t{zz{xzxy}|}}~wzzz}{z}|}x|{y}{|vwtz~w{~~zzuz}}|x|z}~y|v|||~uz}~z|~~}zzyoz}{fqvzw~v}}|xr{v{~}~}{z{{}}z~~zyz|z|t{xiz~msztz||y|yy~uw{|wx}{|n}~x|~z}y~~v}~}}z}|~vy{{z{xy~qzs{{}~|~{xx}xz|~y~x{y{wtx{||||}~|}x}zz{{}}}~||ww}}u|{zwy~z}yuv}|zz}||t}||wkmq~zz|||kyz||}v}|zy|~t|wu{|{~{o|z{|}szq~{ty{}}}t}}{z{vpx~z{wzy}ry|~|w{|vww~||~|mx{w~p|w|}|~x|}usrww}~yz{ul~{{vs}|zytqysy||}~~|y~~y}~|{}tty|yzy|xyz~}w|yzvu}v~vvyyx{{|}{}s{zv{~z~u}|z}sxz}|{t|{vx{|y{zu{w|z|{z}||wu}ny{no|y{{}}|t|{~||}}{|z~v{~}pvqy|}~{{}{}y~~{}|vrsxy~}o~z{zsy|~|znz{y|zzs|nzyz}t~vq}}{|yzhw}mzymu}x{z{~z{}|x}~~|~h|v{y|wx}uw|y|y}y{zs~vz}{w|~{~}{y||~{}z~zwy~}~||sttzz|w{yu}zm{wx~^~s{{|}~}||{ps|jsz~|y{zxv}{q|xyz|ppzz|}svyz}w}~tvy}|}}zwi{{z{{}x}unxxxxwuyvx~u{y|z}{{xkx{z||xnwu|}~~z~yw}}xzz{{}~z}txw|~z~}z~~~y}{~{{{u~o}y|}}y{s|zwm|}|v|uvjy}yq|}{{~~~}vn|{{{{r~{x~{}x~xxnzz|z~|zz{{{}wvop||xy}~yu~x{ztw{{{|zvr~upwrw{}{{suy~{~~|~}}woz}y|uzz}}y}qs~}n}|z}y{yzv{|tt~~y}yx~{~~v}|x~yzu}|ux~{v}|zyx}t|z~{y{xv}s|punt|zo~z~~y{r~|y{{}txvn~}~~|z}~|}}{}~n{~}|yz{{jwzupy{}~~v}~|pw{{}t~zw~r{{}vv~}yrvvx{}z|{~z{iy}uuysuyqu{|}{|x|~}u}{{}w|~tz}||{|yx{v||zv~{yy~wzvt{t|z|y~j~w{sw~u|ux~|{}s{y~{z{sw~}x~{wyu~w{w~~{z{tx|y}~{~zx|t~zurxmq{{qv~{~~{w}x{x||xv{w|v|}q~}z|w{}||{zxw|dxyv~x}~{z|t{{~uwu}t|zfpzwz{}{~{z}wr}rx}s{~x~{yy{}v}v{q~tyr|}s{|z~{}~|yysp}}zz}}w{n|}y~~lw|}yt_}~v{tv{vv{x~q{vy}x|zqywvvqv||srwr{~{x_xtxe~||y]t~{qy{}zwy}sus~xz{y~zx{zy|v{{|}ly}~}z|vv|wq{ou~}|v||q{y{tw|w~z|z{|~~vu{}{y~v|rz||syzyypyj}wxy{s||~wy{~}t{fx|qrp}x|d}xxz~~pwxz|}yunz}pr~~}{wzxn}qq~|xr~lvwzqtwry}wrtwwv|r}{y}~zt}~y|{|{e{u~||tv{~zw~utnylzvsvmvw{tp}|r|z|xuxzm~~rkz{xz~{mzy{{pwzxyzz~yxx~v|~utovzyl|v}|z~zuzul}{~}}{~x{y}{}yr}xqy}yu{xn{}t~p{|t{{t}y{v|}y~z{|{u{~Xy~ty~y|rrzv{}tzr~|}nxi~~x}|{wxn{~p~u|~{v|}|}~]~{}}ju~y|||}|w{_~yyqy||~wqyv}}|{zwx{x|mx|~u~{xymrw}yw|{xx}|zw}q|v{r{y~|{~~|xzy|~y{z{vzus|ttx|~}o|}}|r{{|~umsy}mzwx~ry{{nyws|v~|z~wu~y~~zxy{{rxo|{t}}y|}~z|t{{u~}{ytoyvy~|~r~uyvztz{y|zx}{m|wyx{{yxvv|~~}rxwz|x}swzwl|kt}|~{u{}~i}~}yy{~}u}wv|y|w}}}}|~iywxzstzv|}x}x~zxqt}||~zw|x|{z}tyz{zy~m|yxvz}{}z~vxxz{z}wtv||zx}z~y||u|xx~}v~~q~}vy}zqwuz}{t}t{~|t{~zy{r{x~x{r|~yz~}}u}ts}|~~yt~|~wz}w}}vywy~}}y}|s|t|s}y}~{}{}|t~x}ppyx}}{~~{|rzv|{tw|ut~u}u~|s~}~z}qzktxyz~xu{xx~}~{zvwt|uyq}~xy~w~{|wzuy}y{z{{z~{~||w|vvy||zm~~~qtxmy{|tptx}}}xvyx{m}{w~x||{~|{ysyyz|}x}uzs~z|{uzt|}ht}F^|yz~}|xz}|js}vm}}y~}vu~x|{sbymu}ww~xxsu~z{vy~{|~~||o~vvyy}|{~s}zr{}x~|rrz{{~}z{ryx{|}zx|}~~t|l~~y}{wvo~s~}~m{v}zq}wx~wy|}qw||~~v~zz~x}x~}{x{x{}~}q|z|{zvy{}{{uzy|}}|~tw~s}|i~~wx|yyyy{x{}{~yq|^u}z|~{td{{}{s}|}{}{|vz||z{yzz}lv{zvy~s{^|~x~yzlv{|}xxz{wz~~vzzx{v|op}|tvy{zx}rx|}x~y~x|s}{|{zty|x|py{~~}~zvz|}{~|zzn|rzzs{}||{z|yz}zzzu}}{}{y||x~yx|}w}|}|}xy}w~~}xy|{}|}~vzsswyu{yww~xn|~tvz|{{{w}{z}}zo~xr{}n~|}{}~y|}}xwh}{}||}~}z|{ywwxzzz}t}x~~}ytz~|~{|z{q~{t{x{||ywz|}w{y{}w{|}|}~{~x}vv}zz{w|y}st|y}vx{~u~~{yw}~||~{v~~}{v~}kz}||{x}}s|sy{wyy~wu{|uz|}w||zw}r}w{~{|~yy}w|zy}~oruu||wsx|zwz}x|}}}vzwxxywsky|{|sw~{g{|wxzwwx}~}y{~wzzxww~s}~|||}{zy{}u|yzxyt~{ytz|}iy|nx}cy}}|v}~zyp}xnrz{mw~~|mfkw^|{tj{t}}es{{y|{p}{xw}pwzw{yv[{wywwm~{tx}{~syxx~vu~|z~}ljxzx{}ru{|~sn|xruxxs|~z{ss{yry|{}{sypyzy{{|z{}xy{zlw}oz{suuvzzax~~|w~uw}zmpuz}|pzrz|~w~w}v{|x}u~{z|yy}|t~yuyw~lx~n{|~[tx|bvys|nz}~|s||tw|vw~xw~~kzsx{{u{y}zw~}|qrxqot{}|z~tupu|{u}n{x}~wvn~{du||zw}vxuz~vpspmtyozttz|~uwzs}{~{mq{wxqe}z~~zxucy{{|{{{ttt{u{||v}w|~z}}{mxy}~zsyt}v}z|vz~~y|}~}~zyrm|~~~{|{{~}|yzv~y~x||tr{|zwz}wz{{q{|w{yxtiu~oqy{t~xxs{~x}s||tyw{~z|v{{yzy}zu|z}yzy}}u}wwy~||vuzv~z}}~z}|z{}|{z~py|{}y{}w{|yz{zz~{zv~|y~|zo~wuuyv~|~z~{o|z{~}w|t|wvz}ys|z||u|}ru|{~}}}{{wk{}v|{x|{{kz}{~z||rzy|v~ww}{kz}u}{}x|xszx}~}~{|v}~}p~yv}}|y}}yr}|z}uw}|xz~xzw|y{t~{mvzss~}t|}}k~zzr}{y{}y|sx{pxmw~}l||}ysp}||pr~~~|~}{ys~y~fxw|~{x~x}z~t|{~wv}zzxukwv}xy|wxu}~~}s{}wx}w{u~zr}yw||{~}~tz{p|w}{||~zzyy}x~~yv}~|u}}}}xys}zt{}zw{{y{}|}y}t}x~}~x}z|wy~xy{v~}|{z|~pk{~{}xuw~}ztw}|~~x{xw~z}xszu{}}zxvvxvxg{y{w{|wz||z{~lzzz|{~~|i}}|~x~}||}~su||{}r~{wn{zx}|{{p|mx|{y|~|}|{~}{{~p~}l|}}zt{wz}{{{pyzsxu}}|w{~|{}}thm|m~z|v~z}xx~vv{v}sy{vo~{{s|r{xwy{}n}pl~{yywyu}u|xuzz~wq}{wxvzzyyx|vw}l{~wv~y|x}vwz{|x~{w}qyzwyyvy~d|}|u~op}vu}}~ysjux~}}yxh}zyy~w{z|}u~|}z}|oyy}}s}y|uuuzr}{m|yqr}}{{tx~s|q~{~{g|xzvkxu{i|}uyy|x}z}{{}|vv~z||gzovw}~}{w|wwt||{vxx{u|~r{}zw|lr}z]|}z~}~svstz||y}uryx|l}w}|w|y[}w{lz|xywlvy~z{~~wg{|n|vl|v~u{wz~xx|wp|w}w}z|{r~yoy||}|~yur|n{yu}~fzozuv{|yswx~}wxzl~ywt{v|yuty}mu{u~}xxzx}~{z}zz}}||yyw{qy|}z}|z{xzvxZxy{n>t^u|x|x}{y~{r{z|~|x}~v~|y}v{}w||~wpx~zxn{truy[zv}|w}~{xx|z{~|xy~}~{xy}r|h{zwz}~t|zu}r~{{wz}}z{|~wxz}|yyy{{}x}}puy}{v|t~zxr}}{I~|ww{~|{|}yn}x~{}qyv{owywt~zt~}~p|t~vu{Zxs{}iq~x~v}qzxeyqo|s{}|uu{v{z{yv|uvt~qm}]siuYxqxw|zwor}}}s}sywu}}yzxzyawz|}|z~~t~wyycsny{rgwz~r}{{rw|zvs|l|zuwcstx|~y{{v}||||yy~}zwz~~~|y~x}~y}}}}yvwu~[||w}|yzs}y~wpnxl~~~~xx{uxzh~z|~}}|~~~}p}sy{||~usw{}zx{}zx}zr}{w~z{zv}yx~z{kus}v}z~z}~~y}uw}z|u{||{{v|y|~}~}x|}qynt~zy~w}zzoy~~z}{~{yztzx}|yry}~{}}z}}~z|u}y{{{}{|}}x{y}||y~~|zy{~twwz}x}}{k}{}zv~|}y~|x||}}xsv{quz{}t~wy{yt|{}{yz}wzv~~utw|}{yz|ux|}wy}z~{z}~}vw|zv}}yw~}{}|v{t|yy{s{|~x~}zw|rotyyuwxw~ytt|}x{zy~{~zx|~}u}xx{yz}~~~~~|v{xc{{tw{}~{}}~pz{xxxo|~}|~|{pq}{u{w|~y}{w~{|z|{phv|}zws||{~xpuuzzs||{{xyu~z|{n{z~~x{}zz{|rvy}~~{{~|yyvwwr|~{yj||{yw}vx|~|{z{{~wz~s{|v{}tyuz{w{{{xvz|j{x|~x~~yuuxy{|t~xozz}}y~uz|v|q{{|y|xv}r|q{|}ym~zz{kwwj}{~tyyzxyr|~u~ky~x~qvswmx}}|nx{zruv~{mztk}xy~zsrv~|w}}y~{}t~s}{}~lrvn||y|xzy~z|}~}zx||u}zz~z|xsyx~{yu|}v|z{}}{y|||~|tds|y}{zw}v|zz}myvxuzrx}utdy{q~ppt{~_w}q}my~~o~vx}O~~~|sr|ry|}v{zz~y}p~}|~~ky~|vzz}xw{y~{yxo{yt{wsv}w|~xzy_{ux}{y}{wh~||}p|}|qt|yyr~|}zx{\|dv~yn~|uo~}~Z}v~~i~|rd~}y|s}|pz}~y~sy{`yz|w|z|o|s{~xwz|uyyr}{y|s|w{{wzwyz}vyi|{ss|~W}}fzy}u}wzwy|s|{}vzsx|Rrrxw}~|}~z_tzp~{r}xw|uxv}z}l{yv{q}ix|{iho~wywuo{{~v~~xzyzz}~x|x{xy~yx{{|}|zy|~swr{z{jl{wy}}||}~~}s{uw}{t{zwrp}}}|wk}|{ut}}|~|gwvsx|}z{x~xw{{~~tq}}{~}}y{~|~}{w~{~|x}}}o}j~z~ttow~sz}xy|}z|tu}~}}uxn}tx{}}}~yw~{voy||}~~~|{zz|vw}{}xyxw}}s{{rxyy~xzzz~}o{y}}{}~qz|os{~{y|zr~{{x|v{{|~}zyvsz}yx~{zx~}z{rzyx{~y|~}~yy|u|z~~|}z||v{xf{stzys}~z}y|w}|}}~|~{z{zt|rx|z|v||ov}||zwi|w|wy}}v}}r}}|v{uq{~~wx}v}}{{}xzz||||evy~|o|y}ox~{z|ys~w~~{wtnvmx|z{}~}}}z{{|~wzz|xzsu{{~wy|~~x{x|w|{z|}sy~yu|h}}wxt{xzyy|vs{}{{zz|~ys|}~{}{{v{w}|{}y{zyu{|w|~~{z|}}|z|rtvv~~{||~xz}~{{zzwviwuz|u~vx~ty~{~~|~qu{y|}ovz~vwyy|x}~y|xz{}zvv}|{v{y~}t{zsxy}~|}y~j||{t~u}yz{{{y{y|zz|yyz}}}~z~zsz}}}~~zy}wy|v}{z{~}xyvzr|~~z{u}}}tz~zw|}s{{xwx~szxy}|y|}}~}~{}ztv{}y~y~|{vxpw}~zz~zz}t~zq{~t|u{|}y{}|z|}zy|}k|xtwvzs}sw~v~{ft{}u|t|vuzox~w}tt~{ktvzzzy|qyttlpun|tz}{z~y{~}sustr~}yt~y{~|}nyxx{lsx}~~{s}w|utyvx~{y~xytm~kux}r{z|}{uzz{uryq~z~uwo~~p|{t||~{yxz{t{yuzw|ohx|v}u}tfw~vlost|z}y}uczx}ywt}}qvzxsw}zw|zwwxs{}w|{~p{|~xfz|}|}{x{s~{v|zvw}wx{w{z{xrxy~~uzm~z~x~|~}qvvwzyv||muvz}nw|zzzv~u~ut~~j}{uyozy|xy~xt{m|yz~swvuv{~|wz{}tt||xrz{wqvwyt|\w}x~w{{u|~}yx{|z{~||{}}w~|||yz~{s|qy{{}tuxxtx}q}~v{x~}~y~||{|s}z}{|w}tzw~x{wtzz}}||i||{|zwy|zv~xz~~x{u|{wxz}|n||}z|~{x||r|~~~{~x{{}x}ypm{~}{}}}wpw|v{{}}pz|~~~|wy~|~zy~xz{z}|yz~}}sv|xyt~wrs{}~{pu|}zrt|~{mm|w}rz{vi|ux~zzx{|zxx{~zx~o|{{~yz|yzszxx{u~vwx{~{zy|}{ywy{{|{wzz{{x~{~w}~~y{xsyyyzzx}z|{t{vo}}|srw|vt{s}~{z~{}y|z|i|}x||rwx}yq~v~{wrv{y}myn~t}gtu~q{{w~zu~uz|u}{~x|x|wywz}|~{r~nyswy}{q}}{wzzzzxyw{qt{}}|zt~[xstzu}~z~{|zjw||}yyzyy}zt{tzywy~x|~}u~}yy{z|vv|xyzy~i|w{|~}~u~zu}{}~}um|{|yq}w}{z{yxyes}y~~zwe{~|}{|~{{~u|p}x~}}g|y~|s|p~|wz~yz~{}s{z|}qt~ystzy}v|v|||}|{~~|r}{v}}l|x||~w~~ys~y~yw~rtyyz{t{zzzyz|}|x|~`zzwuuxzzs~{y}v}~x~vz|}|xyw}{}w{|}y~s{~}{}{zwx{~o~w}{yp~{xv~w|{y{ts}u~|tv||{~~|x||}yx~zxzzy}yx}~zszzyu~|wzp|}z|{vx|u|~|}|t{x|ymy}|xv{yy|zv~yx||}xzsv}}}}zz|oyz|yxv~||{z{}{}zz~|z{zm}{x}y|w|x{jwzurv|zx|w~{|t{q{zx~yzt{}|k~n|w{{||{xtz~|}{{pt~zp{z~s{}~z|x~~mx}s}v{pu~yyz}}zqo}|v{|z}~yyy~{zy|zvr|h~}wxs~ys{x}|vm{{~v~}z~}vyy~}|mxyyu~||~}~|vy{}z{|{qz{ru~zx{~~~zz{|{oy~s}wx{v|x}x|zyyxk~yg{km{{{~~{ul}t}vrxr|~z{xz}zxzsx~|u||}|}}}y||suyz|{rwy|zw|}{}{~~r{wk~}{~q}}}y}y~wp}{~vxo}y}xz}|tyzt~dy{ru{xt}w{h}{{{u}}z~|u}~y|||z}}{{{}{|xtzz~|{|tw}|w||ut|wyq||}zJw~us}uz}~}zs|ygzuw|}y|hy{zzvg~~vwv}u}|y}t{bpzwt|{}xq|wwp}d~k}~{yn}z}~|~v{x{|z}zzyko}d|w}znuv}vx|x|~}y~~{zwu~yx|y|ury{{x|z|tvxy~z|~w}x{v|rz{r~x~}yt~t}{|{|vywx~~t~uz{||}m}xwv~z|{|e{|wzi~}txnUum~vs}{]z|~o~{yx~sx~{w|z|yv{n~~yv|ux{trzwyr}zt{~}u|x|~v||{x|xw~vuv{{n}{w~yiyyzp}~||x{{tv}fx~~~_}zz|~qw|~|zu~w}{xx|ut}t{|w~nvv~x~q|qx{ztzs|}x}}yqz~~z}z~x{xx~}|}|wt|v}y}w}||Hy}x~~x~y|vng|{jyspwv|~rx|~UxZu~}~s|{ynztt}wvi}|z||~{~zvu~x~|zr{zuwdzw{ujuzyzywv{suy{xwxzvxzu~{|y|vzz}s{vo|ttb~|{y~doy}~xt|zwx{|xz~w^{xla{n|z{qu}s[y{|s~|}sr{~}~oy}t}yt{{|zwz~}v~uz{vg}w}}}~}x~|suzqsm}~|~k{|vd|||}}x~qy|yY}z}|~}}x{mr}zw{y~uo|y}{zn{zlu|}|zsvwzz{{~oonxwz|sw~yynt|x|{}z}~}~r{}{y|}{|}~s||||}xzw{~zyn|ouu{}|~z|y}}|}~~zunx|yr||wsx}{ux|~{}{{{|yyy}m{v{}z{tz{tuz|bxzt}||z}o}}z|{{wtz~yzzx~rwwxl|u{~|y}}uunyy|xy}{vv~}|zz{zpsvv~~|~wy~v~}x~}|vxz}yrw}~{|w|orwtywwxw}{~|yyp|y}y~u|z~|}}j|yy}jw|~y}xw~ztt`}}}x~c}y}uk~|y}u{}~zw}xykzy|}xz~|~~xntx~}~}~ztssmdt{o||}~}}u}{oy}~wwu{z|q|p|}awx}{w}{}xv}s}n~}s{x||~~zz}}}~xryx}y~{r~zz}ywz||~|}{}{~~zzvp}tx|{hzx}}q|pyo|~sry|y~{zz|}~}{m}}oyu|wmw{z{t|}{y{{}ty~|x}n}{lwyz|}xy~zrj{u{y~}xn~{~{zw}~z}rppz}zi~}zwrk}}ztv~z{~|xg{}|z~~vy{tq{xtz{rk}|}xyy{ryzz|iw|sy|worry|}v{}}r|pzw~z}z{lv}~x}~pw}~~~||syux~zzxz}w}~|mwv{~v~|{{y~zzz~{w~uq}~uxo~t{~wyzu~z~z~}zyv}{x~xw}srytz|y~||zjz{vs~|{~||w{}|stv~yrx}zz}u{}sr~zs{psvxry}{|x|z~~}~uy~yr{svz~|}|{y{yu~~}zws|~~z~|{}|xx{|y|yuv{~}}xy|uu|vz}~q||xx}{}{~wxwz{{}~u}w}zq~yzw~x}~{x~s{z||}uty}}z}{|yuzyr}yyw{y|sv{x}ut}~y|w|}vwxvoxwyz}{{yzx|z{~xszuy~z||wz|x{tw}|z}}{z|z||zyu{m{~}|zz~}y~||y{~|wwt}}x~~}|r}~{{{~|}~}r}~{yx}|y~~~{xry|wlzyy}}zz|ywzrt{}}tw~xu{s{x|y|x~x{}~~s|y{rs|wxyt|z{~ys~u}z{{}{wy~}~xs~sz}v}vwyuzzuxuu{x}{u|wxvxx~zxw{~oxozrz{z}r~}vz~~~xo}}~x{{yz~xx{|z||u||u~|{{w{||szzy~|u}w|u|{|yu{u{oxuxw}|}}{{|~zyy}z|t~|}y}l||v|}|uzx|xo|~}|zx{z}~|uy~vvwz~|{u{||sy~rxwx~}y~|}|ryzzyz{{{w{wy|{}wwx{|yuxz~z{~wywzvt~qyv|z}vsx~wyxx~tuyz~z{w}{w}~xzzzrw|}ww|vtw|{uv{xl~z~}zzt{{uz{ysy}~xs}nzz}xz~uy||}zst|{|~~z~{ykzut}||u|{yw}x||||z~|s}su{|z|zvz{vyrs}~s{f}w~}}~xw|v}w~~{{|{z|x||{}|f{w~yw|y~z|z}|y|z~z~{y}xzw{}|}l{y}{z~v|jv|y|}{vnu}u~{{{v~z|}z{u}s|xyz{zvjx~~v{|{xz{s{y}wvrtvx|z{~{|~|pi}~{}}|z}||~{y|}~}|vwX~y{z|ztx~~v~|qay~y{|qyr}|}}yx{~}{p}}y}z|{yzyxxs|}}|t|xwwtu}|}|}}y}z}||~z}wq}~wsvz{uu|}~x}v~yxcst~q|{}}{}{~zq{z|u{vy{~|~|w|{wz~|pyr|}~~~t~x}y|}w}{|sw~}k}{yytu{rv}{szyz{|~v{|yvwpu}{||~{qyy||tx}pyy}u~{|}{y}y}}y}yxg|zx{~wy|~~uwvx|uyxpz~~ohv||vz~~|mz|oyws~~~p~~wp|}t{{z|uwu}u}xy|}v|w{{~wx|{|ww}y||weuw{{~vz}ux|~xyozzyy{~}zv|~xr}~wx}}{z~~y~s{u~|zwzvq~w~{zr~yqqyg}q|z~uz~oyvvzxy~wyt}t}uyqsv|}z}{|||yzyt|xz|xw~tzry~}vy}yz}yyz~r}|qy{w{t}~{uvp}xzxwuyu~zt||zu{z{owxzqyxwwy{ww|yw}tx|t}}zzzqw~vyzxtryv|xz|wy{{x{}|v{}~{u~tt~z{}x{z{~vyzur|t|tvt|{qv|o~~~|zy~{jxz|oolw|vyzw~~v|ry~~x{}zt{a}uzywr{wxs|~~{{{p}xy}yy}s{uyr~}r~vzwx{y}oyvr~q|{zu~{|xyn}vy}yw|p||xtsq{xz~}ryu}wn~z|vxyxylz|xzz{uz}~yvuz}xzzvyxx}z}zwvf~zrs||u~z|}{~x~uw}z{{{~}}~~}z{z{o{wz}zyw|m|{u|ptwxu~w{}u|z}|ww~syrzuwuz{s~v{yzr~u}x{x~~y{xvzp|~y~|x}r|}y|{u{~{{wz~~z{~|x||{{zzzqkz~~|~{||yrz{{}~yy|}x||xz}}lxu}x}{~~zyw{zw}|Wz|~~~~}}}xzy}|wr{|}~z}}vzz}v~{k~|~||wx~}~|~~~}}xowzzz|zyw||~}}~~~}zyzyt{y{}{xz||s~w|u{{}zuv|{{wve~|{x~}swv|s~yzz|v{{}u||s}}~~}~~w~xy{|}~o|zz}|g{~|v{rvhzyw|z||y|{rs||w{w~u|xxvro{~{~|~vv|z{~}sv{}{||~~v~~v}|w~i{|{~{xzx~yzzz{zq~~||n|hk{zq|{zyw}}}||yq}|t~mxu}|}{r|w|qyuyx~{w}}|}im{x{y{{}x|y~||}||}~{fw{z}xzz~~j|{~{}tz{|n}v~j~}y{tx}}pyu}}~||v|wu~}~v|~{{{vR|~y}~{}}}|q}~iwx{}}}o}{yx{~n}|||~y}m}xz~y~s}{~~|{x{zn~|}zx}{yx~{vv~z{}|xw|z||v|t|}|x~{~xst{px||{f}}|w~}zug~zx||yxd{|zx}~tz||{qs~y}wy~p~yvxv}zx}y}|x{|z}|qz|{|kvwvypuym}qx~~v|~qz{vyyyywz}}t}{{zw~{}{xs~~~{{z}~y|{w{w}{}~{|vu|yzyzu{y~xy||}zz~|yqx}uzd|z}~{}{}z|{z}v}||w{z{y}xy|z|{su~zv||zsv~z{sz}zc}}xxuy{tr}z|xuv}{}}ww~|}zyt|||}|{{}zytty{}z~z||w|}ozsw{}x~{~vt{}s~||ztz{~y~y}}v~y~~xy~t}y~yx||}yvq}xvtzZ~ourxy~w|w~~{rvy|qx~|w|{ym}}z~zywyy|x|}vwv}~|zz|z}|xzxl}z}{u{ps}y~}vxh}|yv|y~|zy{{~~yu||{~z{|o|}v~{yctvx}pyzv}ypq}{}~y||}szv|r{~qzo{~y}||~~}}x~vsz}ryy{{u{{{|s~s|}u|~zi}~|~~lsx}tx~}{y}~t|{y{}ux}uvyytb|u|{{}}z~|zvs}{|}z~z|||~qv~~{{}mz~|~{~~t~tovxt{z{o|k{|wx|~|zz}y|v~wvx~~ww}yo~y~i{ovt{ys~quy|xy~}z}v{}yz~{jtx~~}~~wou~|x}}{{w{zz|lvtyy|{z|zx~}yv{p|yurw{~}pr}y}wly||~x}{wwrwv{Sy{vz~u}ysxy|{uy}|}}yw{vsvz}xyy~s{~{{~{Ry~{{x|{|y~yz}{z}pxtvm|t~zxww{yzv{xz{}zxkyszx}yp~}}xun~|}zjx{M{z~||{}w~su~z~u}|}z{vyz|xyprsy{xw}xk{zsx}y{{xzx}~}ztvu|~yxyv|uyxt~w|yvz}{|{|yzon~{|w~~}s|{y|zxyysnwtxzyzury}p~||zrz|zwy|u|{ww~~x|nzzwowz}|u}z}}wwxs~zxuwzgv}vr}xvw}}{~~xx}~x|}nxxw}}~yyuy}{n|tuy~u}}zz|v~wp|v{~jr}|w}s{~{~|{z~txsi}tx|{zxt{~w~~|{||w|{mv|xz}xu~u{m}v~wzz~x~{{z{}zpt}}}y~w|uuy}L|su~~~~wv~yxpq|n}ryxr}{}xxszxby}yxpwzm}||uu{zw{~{|||zx~|{|{}}{v}~i{{}y}||wlpoyxyyw~wz}{|{uyx||wxy}~}|p}~~yutu}m}}~m~ztzw~}{}~}to|{}~rxx~||{zt}{w{uy|}w{}ztt{wx{uv|}w|mq{yoz|x}~x~xy}yz}~}x~}}}|z}}|}{|{yzz}sxxu}{{|~||~xrw~r~w|{z}~|r{~mw|{~y|w~xv~}|o|~ox|{}}|~xy|}}~z|v{zyr|{}|{uxv{vzyux{}{|uvo|~{|}{}||nwvw}|~}}zzx||vzi~|x{yw|}||~u{|m|s|yzw~x|o|{}w~~|~{r|zt{{sy{~t}x{ux~}}z{}}nuw}~{az||vx}r|~y~~~tvs|}}}uv||zwo~}~v|{}}x}~}z|t}}}t{n}n}qzz~yz|~yw~vxosr|y}~zzs|}{ztxz~~vvzztbzu}|z}}|y|}~iy}}trt}{y~|x|wy}{}{y||{~~u{zyy{~}{|ty~~uxy|{wu}|z~sx{xwt}~~|y}}wvx{{|}z~w{yz{~vr}w{||zuxrx~~t|~v{~{pzx{}uz{j|s~xuz{}q|}~~xx}~{~~z}}}}{w|~ty}}zu|{z}}|~s~sz{i|ryy|h{}}zq{|}|}~~yq{{ux}||||{xz}|}}~|~y}z}z|xx~uvpw~~x}r~z~y|xw{z~zyo{xw~w{v|xz{~}|{|xqvw|yy{vty{{|}rv}|vx}|wy~~x|}vzur~x}qp{}|tyv{g}~x}}v|}}~}xr}u|wu~yyzxvzx}~qvy~{|uxz}z{y~y}x|~~t|}|~uxmr{yvyszw{y~}zxxvz~~l|syw}{vzy|n~wz}|~u}|s}}}rvr}zyzyyun{y~}~}}|xxxvx~||qxw{uo}w|x{}ww|xxv}x|ytz{w|tvy{|y~w|xuyz{}wz||zrx}~{}~y|p}~~y}}~|~|yy}{{}q~~{~|pxz{{}xrp{~~|w{w}w|{{}x}~xx~}px~{ywszy~qsnts~}y|x}y}yys{}wyxwsytzz|s|z}xz~|y}zvqtpvwtyj{y{|uk~}}qzz~wszwzZzywzzyw}jz~|x|szvy|{}~{~~~{~xbzyz{yy~~|v||{{|}z~~|~yy|{z}zz}{t{xz|z{}y{~x|~xzz}|}{~z|~wtz|zvy{~~k{~|}~~}|vuyyxxz~z}rlyr}xyf~t{~{}~|~{|xz}}xz}|z{~{p}}isyz|s{~|v||uz}s}}~|~|{}q|sz}{xvw}{xx|yw{zyhx{~~y}z}}}y~vnrjuv{|w{~z|w}{}~y}}zz{zw|mys~yz|z}|||ux~l~{~t~{z|}smx}yv|}x~zozz|||vywr}{{x}wywtw}y}{~{z~yx{|w~}k}~z~{}{~qysn{~{g~v}|pyjy}zz}}|z~|{}}wzv|oz}{t}|{}~uxx}{x~||r{}yzxv~~ww{|}q||y|||svs~y|{~~zzzph|o}}y~|y~||}{ww|v|{~{zzuux|ty{twt}wy|}{~_{z}|lv~|pzs|}|s~xxt~~}n}{}~~q~t}}|z}sv{vw}|~}}y}{{nzt|||}s~~|}z}nv~~}v|rqryx~yz||v{}~{{~y}z{}qwyrzq|~}~|{x||}|z~zsozy|xv{|}z|~~xz~|}}}pzqx~z~~s}}}|}inf~yzx|~}y~}x}~{|~zw}~wy}~v|}~y{wy{ywvy|||{v~|{{y|kuy{y}yy}|we~q~zw}v~~|~~}q||~yz~~~~qp{{t|}}w~wu{wty}vvvyz{qvz{|{{|y|}~z~}wvyzw{||r~tbmv}z{|{{{~{{~wz{w||x}x}}su|xzvxy|o}}|mt~|y}{|y|~w}|{y~}s}~z}|}zm{|}y|xstxyyz{w|xx|}}{~}vwy{y{|}~z~svx{w|v|zvo{~vx|{zqzxxz}~s~v~|z}}ysx}|}~uz{{}{}}w}{wxv|}vz~~}{{}{}fwr|~}v{ttuy|~u{}~}{|yzyy~x~~~}vukw~{}yx}|mwzqz}{zy{x}~}zwzu~|~~w|v}{z|zrwjxx~xy{vfx}wz|zx}zz}vq}z~v|v|z}n|yx}zz|qz|~~|z|u~x}sx|}}{}tv|t|}zwu{x~t|zs}z||}vvk{~y|{t}~s{{txgyhy}xu~|zlvw~~~q}zzx|~pyy{w{ly}s|rpvy{|o{|vwy}vv}{r}{~xr|zm|pyx{w~x}s|{ywwoywt|~z{||yx~|y{|vt~x~{|{v||y{~{uussy~rzr{os{{j}|v~z||zz{w~u|y}|u}yzv|~x}wz{|w|~vs}}tzyu~x|rw}yw~vv}ut|x||ysvx|os{{x|~{{~~xr{x}|evp{vt}zt|u}tnstw}w|}}||tz|r~~u|zpxupy|~|vz}{|~~tut}{x~~|t|}}zxws~twv}q|{{|~{t~t~yz~v}sy~x{z}yu~yw{{ty}ptz}y}~~}~~w}||}z~v~|}~s}|{ux|z|y|}wu~x{px{{yx~y~w~~p|{}n~v||u~||y{{~}|}vym|~|~~~|rv{z{~s{{{}~xw~}~{{|y}{y~s}y|~t{{x}|yy{t||uxv{~}{wwty}{wx{}zuyzvvu|yzx|x{}zx{||yzu|y~~wuy}rwyz~zvyvyw{{|z|u{w{}~|xy~z}{|x|y}}|~{|{wrywx{{z{rx~~|v{yvzx|vu~w||{{x|z~||vy}sxy~w~~{|zzx{y}z{xx}|w{}~o}uyu~|{yo||w~{yz~~z~yw~y}ytzv{xwu|qw~{uzyzz}}~z{{}{{xu|}|}||{xx|asby|~~v~}p{}{z{uxzvoz|}y}r{k~s}||y|z}z~wy{xxvw}r~swx{{l~~z~z{xut~}}yuyyv}z}r~{|z}zty~~|{~u}rv}uwsynywrx{}uv}ys~t~|}t|pu{||w|}vv}vr{zzxoxw{}~y|uy}z{|ty}x}u~|{{kwzw|y|~w{~tz||~xv}zq}vty|z~u}w}{}{yxv}zt{|||wnww{t~{xy~{w}zx}|}xw|~vxryvu~s{{zrzi~yz}{is}|z}y}}{wz}z}~|{yg|}{ys~vtz~{ty~yv|}}xzx|y~{}v}{~xzzzz~w|v}}~{{{w~z}~|swxzsy~xlj^~x}s{v{yuz}z~}tz|zy{|y}y~xrzux}q~xr~st~}}{ovz~{z~}yup~|~~~~y}~}~p|ztwz}}yly{~w~wz|{y}vyz||wz{~uxxwy}xzz~z{tuz~mywuy}~{uw{}~|z~||l}u}~|qz~y~~}zzz~}~w|y~}}lu}z|~yty{v|g{~z}~t{{~~wz}~~vv}tp~~|wu||~x}t{f|t|owv|~}qr|uv~|{~ww~qrp{|xu}~}y{}sz{yxlwt|~}w{w}x|~}x{zvt~y|zyyu}}y~t|m~|nz{|||z|ur~us{}z}|{|z}yvi|||}{~~y{x{x~v}~x}v}~~vwq{}s||m}{{z~|zwz}|txuy~zyzz{~s}}uxu|zx{y}ww{{y~wiu}yw}~}~|{x~{zzy|~yy}w}z{~||y~~~|wu~z~xzy|~|{{||||vw{|w|xqu}{r||zz~~{yyxt}q~||{yv}~}{yoq{v{~}~||}~~ztxtu}z{}y}~|}}z|zx~wzux|zq||w~}|zz|zwxn|~|~w~v{~z||r|zz{n~}uyzztv}vyy~}|z~w}~|{xw~rt|wu|~~{wt~h{{|u}xp}~}yw}xs~~|z}v|tvz{x{|uz}suq~yv}yzywxyw~~vzzs~~z|zwu{vz{zsytyy~}|vy{zzzz{zzy}yv|x}x}{}~xz~vy{}wz{~|nz}uqvxnlx{}}~}~~l|~yxtst|wvz~y~wz|{|{z}~|xy}oxt{r|xryxyc~}{zxujxyx|}u|tyyyt|~}t~{pu{{x}nxw~|v~ozs}~}zxrv}~t}zxqzw}v~x~~xyx}s{owz{y}yp~|~r~zx{xnw|r~~}}zr}y|{zywp~wzqm|}}wz|{xw|u|{w|{p|}{u{txpr{xcz|y{h{~|x}s{}vzx~}wyyfzvy~t~|y{r~}w}uzz|v~q~}q|~tl~~zyx|v}|||{}{}~x{q|{||}|{v{ww}{~|z|t~xq}}us}}|zztzpz|z~|z}}z~zu}t~|n~urvz|}{xxo}zyxx{~l}}}|{u|wyx|g~~zzr}kxz~}zn|}~}yr~~v~w|nyp~{v|}xz}~xx}qzxrx}|w}}|v|q}|{xyzw}{x|z}p~|}xzuvqri~{{{|y~w}{|zp}}v{{}zuuu{}~wvu{z}||z|~|}~o~xyq|y|~~}{s}zqv{z||{ryu}o}v~|xuq{s}~|}}~w~x~|hzy|z~~|{wz{xt{vzz||z|{oy{{{u{vx~|xyy~|v}}vwuzvx}zuynx|ty}}|}}|~{wo~vz{x}}}y|twz}zrxztzk~|x}qw|{~|~zy}{|}zy}ztr}z|~|vzx|u{{s|v}|~v~y~~~{x|t|m~}x|||~}z~{w~pzxzz~}y}wv}tw~|t}{{rzv}{||zz{y{|||x{x{zlzzun{}x{z}y~{wy|{w~}}}zyvwo{{}hw{uyzy~{~||}z|i}{y|{|rw~zx~sy~x~~ztx|{v{{x~xwz{z{yxoyxv|}wx|}||}}t|~~tzv|{}~wy}zw|z|{~}~z~}|}uz}x}|yzy|z{w|w}~z~|w{w}{}|}{z}|z}yv{~}rz~|}}}~{t|~y}xwz}xtx~||{z}z~~yx{}w|z{}v||{|qq}w}wr|}z|s}{}v}}yzwz}|y~z|xvu}ywvuz|zr}z|yyzrtspfs}~y|m}}y~{wlwwx}{vr{~{||qu}~}}}}xz}}ys|y~xv|~xy{}~|w{}|z~|z~|wzuFz|xz~}txwvy|yxrtyz~yz|}z{tzztzw|~}{~z~zt|xy}ym|~z{uu~~w}{{}zy||txy~{z{y~}ztv{~yw~w}xrx|u~x}}}h|~|~|}ezxuwzwwl}|z|{zr}||}|}j~}tvuyk|{wxw{|q}}y|}q~x|xv}}~~u{v|}{t|xwyv|y}{{qr|~~v|{wz|y}y}tx}{t}|x|{zy}~{z~~}{{w|pq}x{v{{l}uzu|}}l~{ts~wzw|~{}{r{~u~|{r{||}{~mv~}vnx~}z~}ww~rx{~}}}s{{mx}}x|uxzvzz{|x|}||uz~||}x{z||~z~~}{wuy{k}zywzz|}}y~zzx~|p~w~~yw}{z{o|zs{yzxzm{l{~v{drw}w}s{s}uuvvuqyy}syz|yy~~yuw|ou~x}|x|zyyt|x~yz{xyxr~w{|wtqww}}}{z{|suzq~s|~xzyy|zwz}pw{lxsr}||pyw{z~~zq{y~yoy|{r{vs|z}uv|s}w||z|xx{vt{x}y~~s~}vu|{y|tt{{~qxxyt|wyd|vmwwzuxq|~vypx{t}}~p{{~z{~p~|uy{s}{~|wtvw~t|y~u{vz~}}}}u|qw|z~uxtuztvz{|yq~~{rvt}|{~||{~}vzv{yyy~uupv{}y{z~{~y}|y|}}~m}zyz{|u}v{|}xyy|~~w~wq|vy|u|xnxzxzx|v{t~y~puoz{{~|{xq}{x}}|}}|m}~wzx~t|}xz}u}}{xz~~zyu{xv{}ux||}~{|w~vzyz}yyt~w|z~p{z{~|zzxxsuz~x}}}zzumy|q|{|~}xzzsxwy|uz|z~{~vx|w|{|~v~}~r}{|~z}qvvqxz}}||}~z~}~~x~v{t}xwy{qvy{z}~{}m}z}y{|jx~}z}}zs}}{}}z~~zz{{twk{{~{{}qyz}zruy}w{{{x}w{|z|v{{vz|z~vw~}y~~}}vz{xvtwr|~zt~~~x|z~svwzxz}|y}yyt~~y{||xyu|wwx~zu~}{s~}y|}|~{{ztv|v}||}u~w}|wxy|{r}{{|z~~~}{zy~|p|wxz~xz~yxx{z~z|{{wywz{~~xu~z|ww}v|~|{|~{j}~~}|}zz|zxu{xur{~ztzz|~xx~y}~~yw~{|nh|v|z{v{wtv}{wq}}z|~~{{mxtr}}xwx}t{x|zy||txvzzotwztutxww{{~zp}xv|z}~ytt{~zy}yvz~}}rzu~y~{tzvzxy{t~y~}w}zv|{uxz{zxs||z}v}{{}x{z~yut{yx~uw|z|zuz}~}wxy~ox~|y~wv{p~v|z|hzry|}}wr}|z|u~yxs|wzzy~wt~q}syw|ww}|{i|y|yxpu}x~qtu|tz}}{}|t~y}xx}}yx|}|}z~{vyrzu|}wp{u|zu~u~z}rw~m{xq}y~yyw}xswntvvvvp~v}|rynyyk|}}~~~v|xt~z~s~z~xu|{}yu|yw{zxyzw~~{kzxy}|zm~~ysv{xzwz~tx||}y~~~yyyy|{z|}|{{{~~|z~d{{|~x{zpswt}zsyy{{qt~{~||x|w}{{vlwu}~|uvwzxtxttqtw~|}{vx}z{}vz|svv|zu{qywy}~ru|w|~s}vuvvlw~wt|ww}uwtyx}u{|v|y|vwyr~jvz}|ty}uw{|v}vzyywpsx}{z{}}u||x||}{r}|ypxu{w|xzyr|~vpzzs||wx~||z|v{}{v{{x}om~rz~{{}m}y}uwvx~{}y}|km}{}|uxy{~s{v~}||xwz{zzx~}wq|x|}wy{|uyyx|~pvw~{t|u~}z|w~}yw~r{ts}y{u}s|u~}m||~{wqgyzwzznyw~}wzqw{xt|zq{{yyso}svw}}xx~p~k~}u}w~zx}wxu||jzxrutzuzwsyx|tw{zwyr|x|ywx}{w}~}v{vrw{o|}xs}|zt}{to||~vzvwy{|{pw~uoswx~utvnzw|y}yv{|zqxyzsn}}}yz|{tbs{w{~wx}vziy}|uw|}~|zuvv}wuw}ws~~~}|yt|}|ty~x}}t~~xvuyuz}}lv|mtzy{zt|yszzxuz}{i~w}|p{ztw}yn{yz}yqx|zXycy}~t~{zltr}~uwv|}|rtw{z{}~{{~y|v|{~}~ysxzyj|v~qatshvuxw{||}v|qx|ztpszvc|yz}qz{zv|~zzy|{vwx{{stl}z}uw|{m}~z~lqxrqoy}{|s~{n~~xv{}}vywv|rwjy}t}wx~sxrj|x}~~vyzz}{w{{|yrwk}o}uyxzzx}~n~|nyzm~zwryx{}wu|~y}yrjwtytvmxy~x}~}|qn~yz}w}n|rqz}w{w||vw}}r|{{p|z{}ww}y{~q}sv}}~||jt~xyxvw|{}yy{zxz{}||x|{u}x}}uyxz|u|u{{y|{z{osy}vyz~ot|u{|f}}u|z}rzrw{}wz{yz}~qt}uyz}~z{~mx|w{|v{v|~~x|z|~yz|ztz{{}ss~wy|txv~~zyr}x~x|qj}zk|yvsv||~yy}y|~x}}s|}~~}uy{|x~x{|}|w}~{ywb~}x~uq{}x}{}}{z{yz{}xnwz{~txu~{v}{}}||}|n{zu~tyy}yyy{~v~lx|v||~|z~r{x|syzz}}{}nzzv{y{zyzak{z}~~yv~x}|wxvx~}wz}y~|xsou~tsy|tw{tsh}w~xz{z|ynxye|wtzr{{|~wu{yzz{x}z}~{{}w~yzv~}|||z|yyu}||z}wxfzuy|zxt}~z{{}|xz|z|y~}}}yyxw~}}kvzv{~~z~tyzw}z{dz{w|~~~y|||xu|v~vz~s{w}z||{{~r~~||{s|zyy}u{~yxv}~}x}yo|~}y}yv~w|}}}j{}~z|vz{{}xsz~{~~|}y{qww~|}t{}}{xv{Uwyz}}zruz{yy}{}xpvx}wx}}z{~}x}|yyr}~wt~}{~v{zxwtzz~ux{qdy|tz|x{{y}~|s~zrwy}x}}wy|[||tzx}u{p|mx}yzvo{}{v{y~~{|x{\~|~{}vxvtv}~yxyrz{~}}zzpwqjze|xzv}~|up}o}w{}|x~{u|wqx{wm~q~w~|{zpwx}w{{xu}srn}|{~}yz~}rxoxzz|{|uv|~xz}~xxs|}{z{p{{}mty~t~o{vz~{ct~o{zyy|y|}uv{izxt|rry|{x}z}{~|ly|qyuykwz{szx{~}~}}zWqz~zxl{~y|w|z~]o~zpztR{|rz~mxssxx|~{{u{}|y~~xyy|~~s~x}|rz}~w}qw|xy||~~zvx{z|{xy~qy~~srv}vw}|yvvz~z|~}wk~}yy|{y}r{|zsv}~|}ow}z{{~uzv~{rzyu|qz}~r{}xz~sx~t|yxz}rzw|{}|}z{z~|yy~whzzuuzx~}w~xw|}}}wu~y}xxt|t~wyv}wvz~w}|wnsxz|pxz}{}z|}||u}z~{tx|}{~yvo}u|yyxt~{u~}xx{}~{{s{z~zjt|{t}~zw~zwy|my|yu~{xwzy~uv~|wxpy}yot}|u}x}u~}{~|yu}{}}z{}x~zt~{~|txqzvx~{}tztwzu}y|v{yvqo~z|y~|w~x{w}~zz|{w||}~t~|y}}|~zzb~}~wrx|y{yyy~~rz{uu|~xzzw}{yt{{z{{q{wsrv}|{}}}~zyv|{}}xzxw~|{}~z{}|r~y{xw{uq|o}zxyzw{{qx||mqy{|x{|}|x~}~~}{}y|zy~xy{|wr~~vw}{zysp|mz}~z{|}ywrvsw~y|yu{x{}{|tq{w}y|y}|~v~{r|t}z~|~xx~|~{}y{z~w|m|x{zso|}v{{}}}{}vzzvz{|vwq}{~|}|~zo~|x|}{{x~zyurtwuy~|z~z}{x|ivx{{x{}v{q}~||}z~xv}xtp}}{{x|{{{{wwyz{znx|}p~|~}|z{yzwwsyx~}~}||zz|s|z{v|}m~vp|}|~|v}~yitzv~|~{~}||t~zv~z|wwzrz~~}~{z|vuzwxz{{t}xuz}{zzzsw|}y~}~xzyu~ts||qs~}{}w}ys{wwz|zw{x}}x{||t|x{zs~uy}|||svs}x{~||{vt~v}~u{{vwy~{|~yxtyz||y~|wz|~t~xz|{{}~szxs|~~vq~y|xrzxw|~z~~~}y|~|~tz}{x|z~z||z{{}~ux{x{zou}{v}w~|{~|w|xz}ww}z}}}w~uyz}|~|otzzv}|z|zvto||~r}x|s~z{yvw~sus{xwzy}yvyv{z}v}~uk{}y}umwzx}~~q{|}zv}w{|wyyq|w}~w}|||~}~{xvv~r~~|z}wx~yxs}~vzut~ax|~{x{x{w|x|sxx}rvwa~{wv{n{~y{x{t}y~{v|x~|}}wy~|}uyz~{yttzxuw|zw}xuvyuu}ruzy{~xu{yx{}|zzw}|{|z{}}zzwz~vz|{zxw{x~o~~zxm}|w~t|}|}{zy}z|{~x~}~ve{|woyv~tz}~~~u~y~}wx{w||tvo}{}yytx|}wx{|x}~|zxvur~}sw~wr|t|rx~{zx{|}uyv|zzyxyy||~|puwyty}vvy{~{wx{~|}{}xypv~y~r~osttv}~r{p{}ynvz~wz|{z}gzzyw}{}vzxts~xvx{}{v{{y|yz{_x|vru~x~z||z|vz{~|~~}~}|prpww{y|wu|{{{|z}~xwuy}{s|yzqyz{txuw|r}w|yx~p{y{q{p}{v}|{tw|xwyquyvy~v{xwzntzw{q~~y|{~wywz}}}vx|}vy~l~vuqv{{xw{{zwt~rz}}~zxzx|zy|wyu|wx{pvnvttrp}yop~}zyzzx{}w~~~~w|}{u}{joyvy{|}wunyzxxz|zwnzry~~}~zz~}}z}}y}yw{y|vuy~~}nu{_xxu}yv|~rfz{uxsr}zz~~zu~t}y|~r|d~q~kz~wv}o|y||zxyo|v{ww}}~w|z~}x{~|}w{x~yxv|up|~vz~w}vxwrv|vvov~|{x~zyw|syu}v}swxisz}it||\y|yz|}}y}i~yz{lvz~}v}xrxrtor~~z}{vzz{ywz~vzqy|}}t|xwZ{{xu}x{{xvtz~}}|ous}s{}}}zztwyutxt||z|gx{zuwzztw}x|t|~||yvyqssro}v{ortavf|z|z|}y}y||zy|x~wwyyvrw{{l{{z}{my{zu}vls{|s~}xx{~{m}z}}v{|{r}xy~mzrvy}|vus|s}~|qw|yum~szux|zox}{xvtz||}||s}xssyxu{xkyj~uy|yu|vzpx}gjuyx|izvxn\}}~r{zzuw~yr{{x}uu|s{xruwzsoty|{zzybz}e~{~w|q~ruv{l}v|~zr|xzruzh{~omquerz}{|z{w}~{|ms~{xy]}z}wpruqmm}vvo}{x~yizizruy}|y~{xmst~}vz{wyyuuy{r|}o|}~x~{wv|z{p~zox{v~z}u|zwvlsuuzy|{}}~x|}}y~yywp~xzupx{{zv~yhvu{||x~zzu~~|~|~~}s}y}{vwwz~i|zzt}x|yvz{z{|vzqjysx}|}yx}|}oyv}~t~y~s~xxv|}}r~~}s{u}nxy{un~{|ztju}{ws|p}{||{zzyv{{ry}y{r{{}zpxw|~{}~wy|rsxtxrt{zx|r|~|{rzwyu{|g~}zszu|z~vzww|{{~}o~x|}vwzys|||}r~qww~}{z~oq}|wz~zxyy|rx{|r~}~{yu~}~{|ttss}~zzhx}w|~|~ssqxztsyswvyyz}{|xy~~|{y}xqr{~}}n~p|~z}j~x}r~z~}z||yyx|~y{~}z|~~y}|}|~|v|j{~}zur}z{|x|y|}zx}x~{{zvx|{xe~}{|xz~{~~txu{yx}yyx|u{{vu{yt}vxyy|v{~z~y~wzk|||zw{wz~}s}x}{|}~~{{u|}x}~w}z{q~y||v~yz{xwu|}xiz{v{y}}y{~|{||wv|uy|vxzw~w{|{~}vtv|}~w}{|q{~wvso|t|}|u}|y|wzzgx|}||y}~~wr~w}y{{y}yo}oxy}nzvyw}zzxs}}~zwz{}~{xz}z~~pw~}}y~~p}~t|zus~xwzxv~gutz||w~}|vuuxy{y}x~z{v{~}||}{xxo|zy|yz}tw~}zy}|~oxey}v}y{|}zw}wyx}{~|}vrzxzxv~|u~t{tvu~y|~~x{{{}y{s}{v{{}|vy{|~n~w|prx{|}q}{yy|w|vy||}|yx{}{uuz~xq{~tyw|szr{~r~ezz{v{s|}~}vwpzyz|{~z~|{u{{vv{{z{n~}}xxz{xvx{}ow{~xxzs|wnx{{sz|}v}ts~z{|}z{yv~|~zrzzzz}~{w~y}s|{zr~xyw~w~{z~zzzz~~trrx|}~f~}~}{{}~{|o}uy|{z~fx||}{p|{yw{z{s{~z|zuxtm}t{~wut}}z{}}qux{txy}uw{{}}ptx{|xxzvw{ykx{~zy~{y|z}w{tzzwp|}yt~~x}zxw|{~|}|vw|yv|yzuv~}~~x{{|x|{yyzz{|~yu~~pr|uzz|yuzo|u{{|~}|~y||~~x~}}}~~{|~xy{{vxyvytyyrvmt~{ww}{v{}{|v~~~v~wwswx}w~q{~}|~|y{vw}~x|w}w~yzxz~|~zw}vx~xv}y|{k|v}~}zwi~x}~}wxx{{}{yz|}u|{}s~~~wz|{}}~z|vy|}|yzzz|z}~|~}wszz~py{y~y}~rrz|{zj}|yz{{z~}{w}}py~v||~|~}xs~{mz{~~|~vu|~qy|p~q|xy~~u||r}t|sz{u{~~|~}|z~tz~{|s|||s~x{{z}~}~~~zuzy{xxmy~y|{|{p~~wv\z}tu~w}|~~{qs}~t|x|~qvz~}|{vu|{|}|v{y}t~~|vw~||~yvu}x}}yzlxtr}{}z|{y{q|}zz||{}ctwz~t~zr}z{~~~}z{z}x{~}}}ryz}~||}j|~}|wxw{{~~~n{|r~y|}|}}s~o}}u{{|x}~~~{{}{{zmsvt{yzv|v{~}|x|c~u|n}{|}~~x~t{{}}j}x|}{{z{sfu~z{}~{}snve|x|z~z{vw}p~ll}|y|y{u{v{~u|y}y}zzuv|}~}{}x~zty~zv}|{|{|zyw}|s}wy~~~y|x{~yw~~|{~ty{xv}~yv~}~|~xz~~~wv}pj}w{xwysuv{vzvy||{~{zz||x{w}~|v{}}nz}s}us|y~{wy~zzvpwz}{~x~{~yx|~t||}jv}zu}}~|sz{}zy~qxnw}{v{swuwzy}my~swyx}vw{x}~{~yvw{|{~}~||~|w~qs}|}ywu}}y|~zs{s|{{}}||~{zs}gzzwt|z{{ko{y|sw~w{}{v{o}|{~x~v~y~|{~}y}{~|zzuo{mry~|{|zyt{ywj}}{}}~|~u}~ovzu{quv~xx{~u|l{gyzy{~}~sz}~~sy}xu}l|tu}{yx|q~}|}x}vzzq|{{u~vz|x~xx|ot}xyw}u|xyytyvh||{{y}{{{zv{{|~zu}tz}xz}{|v|z~v|u}}x{~}{{zyywzyv}}z}{{{z~}|t}}~~{zz|}yqy|{v~|zzzz~z~pv~z{|~w}|wx~}w|x}txy{v|s|zx~~z~u~{~}|~}|{z|{x~~{|}}|{~rztv}{s}}|||{xu{wz}}|zzq|~{{vyzw}{{{|x}}{vn}{~|wzz~nw~|q{zw}|yw{}~z|~s{zx{}r}|~}{xz}w~z{xwz|~{~yx~vyv}u|x~ow{z}sz{{~{xw{yxyzy~ywtz{}|t|wz~sx}vx{xw|z{}xwtyuu{{}{w{}{z{xt~zu|sx~u}~z~}svxn{x~yw{|}|}|~}z|q}}q|o||ut~x|v|}{|zu~qu}zy{o{{zu{v~}txvy{}}u|{{yqw|{~x}~yst|}z{z}z{~|s~|{xrx{~|v}zw}xw}x{}uy~~t{{v~~t~vyy}zuy}t|yy|}xus{yw|}|z~~stx|}{vw}zuz}}}yy~w~{qz~u~tw~}{~}w~t|~x}rwy{u~|}xl~|}{w||~{yzuv}{vz{|ztxyqw~zvx}}{wv~}xw~|x~}wqoy~}}}}}y|xxt|||{~|}u{|zu{{yyj{zt}xxx~zzx{{~w}}uu|~rt}zym~|z{~{w}z{u~~iovw|w}}yyw|~|{{nyz|wrp{||zzx{~svrt~}t|||{s|i{w||{syyz{zzux{}y}|~w{~wszy|yr}|~nxy~}{s}p^zyvwfz~|s{u{zx~|z{zvv{w|z}yr}wm~~svyxtl}~~wzwzky}xy{v}szy~fuq~{fy}|qzr}~{}yy|tq~|upzvwqm~u}}}yz{~|}go{y}s{~{}f|}sz|y}w}|bvwugpuqy}{l~f}}{xzrmm~xwovaMw~rzzpxz|p~x}vtr~{}|r}|x}w|}sx{z}q|ry[g|vz{x{r}~q~u{xo{{yw|}h~}~nv~}zxuy{y{|t|y}u|{xz{~lvzxz}y{~zuwqu}qw|t~zfsqz}xrv{pyN~uk|yvunslkuwwx{wy{{{~w{|w|k|{~hs{wty|zw~qzv}vy~~}{yz}zy|~~tzyuy}wzz|y{|t~x~t~{z|r{s}}z{u{{~x|y|}}rpprx|zy~~zqyw{v||zz||~r~z~{|us|zzzsvwy~|ou~~vywx||v|}}}zizvzxyxy}zvursvx~|}wm}zz|~mrxx~~v{uzxk~tz{}t}}rw~vzl}zzxr{ys|~}{z{z}zzx~{{x{~~}}~z}xyxv|t{r{xyx~z{yz}sixxttU|p{vt~vsezz}zzu}{xl{~~~tzgzz~}}|jzxzzx{|x|~|z}~~~yy}xxvrvo{vr}zuz|~|}zxy}zzu~tnyz}yy}ywyxzzv}zvpz|y~~uxt}y~zx~{~{otp{y|~|syvx|tzs|~n{{|t{vxu}ny}zxxyv|~}~}qzw~~|yz~ytt{z}x{}|{Nkx}sx~xzp}w~}uyx}}f~x~nz{|t{u~|u{iq~p}st}qs}n}w|s{|zzy|ys}}yq{v|}qwtw{zz}xrzq{xhwzxusxy|{xve{z~wv|y{}|wy{k|uy}||p{n}bq~yvw}yyqszc~|||wutvn|{y}~wt||ln~~~vvvypr}|v}~t~|z||xyy{|}{}y|rzx~|}ws|zi{z|{{|zxk{}yw~jwy~wt~z~}{z{{y{}t~xoyj|w~tex{x|}u}}}r|}k|uzx~vo|xz~y{{~~|rx|{xyw}}{yzuy{s|{}s{|{~quqpz~s{}}|||uy}h~}yzt~uy{w{yv|}w}}qw{tz}~|}~y|zzwxw}}su~uzw}}zv~zg{zt{}z|{m|z|}{|~{zkfy~{y}~~~w}|s{~z}{}{w{ynx}~w}t~|{r{x{yy}}}|zw}|~tv|n{{~}zw||jw~|xw~~{{{xxz[q||yt}|w}z}~}}wpmz|{}zzu|||zptv|~|}||z{szi}z{{}xz~}ti||ty~}{s|y}pw}||{{{yy}y}ztwpz|yxz|tzn}||t}v~|w{||~{xxsz}w~oqxyws}qy|zs}yz~{|{x{ov~j}y}~rh}z|}y}zx}mx~kyn|y~wyq~}s{|wtvt|ws|{}uw{~suw~}x}jqy{|z|~rwqy}wzx{~|qtt}{|~xtv}xr|xvmw|x{{r~ux{{wvtx{hw|t{{vn}j|{{}n~tn|w{zvw~~x~qouw{wn}~r}~q^z||wy}|~}uykrig}yqizxvs|xxrxuzoqmyzrmy|q~yz{|lo|tzvx{wwuzxjzutvx~r{|vyz{}xvy|zx|y}oyy{hs|wq{yhu{m{tvvqx~{~kwe~y~uztzk}||ttytnt}xvis}}dz}s~x|~|{|}t}yw|}xwxr{\zycryx}z|tyyx{}|}_v}uqy{tt~||~{{y~xcnuyyuyy~}zyws||{z~~}}}}ixuuwztzv|}{y~|u|{}rwz|v|vyyz{{~t}}l}~||x~wupsvw|}{|v}}{z|{}z{}z~r~xuxyy}}y|wrzwzwvy~~}xw|ytyvsz|jr~|~{{tx{}}{v|t}{}}u}|a|yyw{u}~|qr{t|}r~u~z|w~z|b|{~z{y{{rvv|xzr|n{i||wqvz{wyys}|t~z{t~~~]~t~{z~~w|{{~y}~y{x}y}w|zzp~}v{z{l~|tl|{~}yy~z|z~}qu}vx~}uy~w}{{uu{zvs{zw~u{ww}}}|k~n{}||{zzsu|~z{yrr~xyxuyynuwyytwrzwYvz}y}zltbzxy}v|~wz||ylyt}vs}t||}rk}x|vsvx~pr~t{x}n{}{kp|j~xz}ywxwwjwt|~ym}pw{iqzu}~x|vyyox|wxxfzyz|yupw{}v{v|tyr|t~}o}}}tqr{z{}|~s}}pzyvu|o{k{izu|}m|zsz~p|x{|tu~zyq~}}kyxwy|tusy}}zs{wpuwuzz|ys|||z~zosx}r}u{|{wjvyr~rfv}ys{|~z}|yulzvy|{|~{p~}qxf}}{xpzyw|{sy|vt~ou|{|o{|~~xw|{}xT{u~b|zu{t|u}p~{x{}yvwxoy~~|zn{s}|}uys|t|{s~zyyxu~|w~x||zuyQud|{zzk~|z{zX{{}p}r{r~}z}wz}y|wv|}z~pzw~yyty|}vx~vuxywyxz{xr}{~x|~}~}z}zzv~}zt||~}{s|w~|z~}y|y}|xutzw{u~~}|}ey}~uy~r}sqy}}|zs|p~|y|{}|xz~a|yy{~rw{}}y|~w{y}{{{z|~|yt}~x~{tuy{z{}vy~z}y}y}}w|w~|t{u|}zx~}z{r}}z~z|~u}v|z}vyy||yv~|x~{v{xwwz}zz{z||}{}v~w{{~{{u}~z~xuvzxu|yu{u~{|wlryy~ty}{oyp}{~}uz{v|}zszyy}|zx|v|x{k{vyyzwx}~}w}l|y}v}zy|z{{{x{}s}|v|{yi}|{|}o{~xr||wz{}~u~xr}u|z}ypsux}y}~{x{qyyy|yxr{~z{|{yw}}}{{vtwq~usvxzuu|yss~|l|{{tyw}{z}~yv}sz|s}zvx|txs|l~x{zqzz}~u{zorlym{~{~|yszr|uzyyvjrvwvysw}zq||s|z[}ryxwu{}b}{~ozy{|z}{t{x~z|~yz~{|zz{{{oz{u{m~wuyuu|{~~v}|ww{ow~~w{zzw|}yz}{}}yszzp}{yyymtw|vuy}yuyxzx|usv~wtt}y}wy{{mv~ywuztqu}tvvv}~stso}hw[rv~zw|Znvtxv|o|y}uf|x~vsv}f~vq}pywz|{zx|~{xypxzx~}yzy~z}|uz{|~}}stwr~zuzqwvyvu}}zumx{}|}{y}~mvx}w{}{ur~zuyxx}}zx{}xzt|}}z|~zxuvxy}}yzn~|}}~vx}p~~{s|zu}~ym}}|}zt{{zv|{yu}z{z~{~}sz}|yts|~}}~k~ppvx~zw}||t}yw~~||z|zqt|}y}vqww~uy{z~yys}qx{xuxmnywxsuxzxxwzur{zyvq|y|}zz{uz{~|{}w}yyz||t}x}{}z~vzxzy{{x|yzwnzxywsv}}{|}|x|tx|stzt|xz~|}z{~{~wzx~|y~|uzs|x}||y~|{u}yzx|zwvl~l}y}r|}uu~|w}w}~vqy|{{xzm|}nzvxn~w~z{{yx~|}t{yz~|sx|}pwxz{{|w}|yq|x|x}y{|~u{~|tz{t|zm}jw~~~p{~uyrs|to}|~z{{y|vz|y~{~}y}~~s|wt}{{wwzyzv~~~y{pw|x~s|~yyyi{}y}x~v|yqxzmryv}{|}~}zxo~z~~~y|uvywyv~}z~~wz}yynxxy~~w}||x~xw{~}s~|yo}vzw}u|wy~z~~~q~|}v~zy{w{z{y{|m||v|zz|~xxy~x{|u~}w|x{x|vwz~}}l|~w~xw|{{rz~xw{py}vv~}}v}tx|{qz{j|ozptuw{|}w}|ruyzty|zxt~~w}~}t|{y~{xwwx|rx{|ym}|{{~spu{w}z~[{v~~uwvy}vqxxw}{r~z{{u}~{|{uy|yz|ls~{x|i{~~tJ|~z{~{|w\zxq~{}{\xux~{yzots~zy||{{txz}}ynvkwu{}~~{~y{~}{og~q~~uzyh~w{w{ysx~{{tyy~vrzov|two}}{xtzum|||~x}q~}w{}y|{||y}}yzn}{sw{u?~x}yxw|{rw[pvwrvy|w}z{w~u}}w|zb~z}yx~|}}{w||gvzvx|wwsug}|w|wl}|yr}x{z~|~wx}w|xjww|yD||zzty{w{{{|zzq{n}t~z|z~v~|yu~|yxr~|~u~wuz|xyu}{{r|~xv|x{z{|{yz|~}vvt{rux{{vw{}v}}}v|}wtz{sx~y|kt}~uz}|w{|qyvz|xzx}u}z||~{}}v~zz}|{yuqz{~wxmwuxwv{vxx~}uwvz|v|y~{{v|y|~l}~}~{xuty{~qu{xr}yrop~}pyz}{v|q{|x{zt}u|{~t~zv~||sv~}}y|{{x|u~}vvz{}|~t}y|}x~zv}o{{y|vyyy~|~y|zxz{}y~|twu}zu~r~|z|tv|tyyy|}{}w|{rzrzyx}{p}}}}}oi~~|o{||wwzv}s}}r{}u|x}{w}o}o{{s~xz}ox{|{{xz|z~z}{g|{wo~n|w~wy}tw}r~xnww~z{yt|rx}|yy}{|wm|opn}}zrys}ysuzqzn{}`|~zuv|swnnoy~syry||}x{y{{lx{v|zq|v}{su|uq}w~u~|t}}|~y||||}u||t~{}on}~pw{xgyy~wxv|ozu~wv{{}yty~h~~~{y}|}|v{z{|yytx~ox~wy|y}z{~vvy}}wo~w`{{y|y~xxz}x|{z{|}pyzz{~{t|~{~yuu~xzi{rzzyw}quz{uvsy|xt~uxvr~}}yz|t~zvyz}u}y{xyzz}{zwuwzsus|yb~w|{{zzy~{jj||z|wt|z|~}t~ktyzrv}luzzyq||~tr}}|~w~r|{|m|to|twqqT}sru{u{zszvtzxvnvsw|y{||ry||uxq~{|{wuzv{zyw{ysy}}v~yvy{z{~~|}tw{uy{vs|vx{|~w~{r|y}|q||{o||xqvz|{}{{{wywzzx~{{}}}z|r}}y~{vz|rypxt~v}{yy}yy|}}zss|yt~z|uv}~vtzwxxl~z|{|~}y}upy~ywty}~x}wzr{xyvz{|x~{~z{}|zuwv|w|{uvstuz|~z}x|z{z{plu}yvwx{p|}~}|{}~{wu{{}q~y|w~k{vzyy~zz~nxxzop{zw|rw|}x}wx{}{w|{|~y~y|x{}}zz~z||oy~wv|}~~{~zz}y~p|}{{}~sy{{|yx}}u|~~zu}y|}~}||w}{y{vqz|x{tsszw|{~|w~f|vwz|~yz|{w|w|y{w|xxttypeyy}{|x|y}ix{|||y{yf{{|xy{|xt~|z}}u|~|}_w|{|z}~vrl~}~zv}yx~}}v}y|}m~w||{||z|}}|v}u{y|yzyty|l~{k}~~~||yr}x|ywz~qw{fszz~~wy{f|x}y~~zwz{uv|{xz}}~yn}rszo{|}z|}z|x|{}w~{~{|~}l}{yz|~}~tu|}|x{z~{qy~wxzj|{vx}{y}{||~}{{ut|}z{{}}}}|~zy~zquwy~~{|t}|}}p~~{ywq~z~|z{wx{}{~|yz}uw~x}}w{y~syz}{~|~oz~xyx||v}~{wvu}{zyn{zy|y~yt}||~vw~}~{|z{}{{}{vs~{~usz||w}y|z||}{x|uw~w~u}|vrr{{xyyvy{xxzzyzry}|ys}~y}v~}{|xy}yxqz|q~}|w}}x{}xwy|zu}pu|{vx{||ztru{}yvu~zko{v~yt{~wvs||ryqy}yl~|{y~w|y{y|}w|}z~}}yuxt}~~v{y}yn|yzz|~yxwr~}|tvu|z~}u{}w|vqz~z}wzurw}w}~|~z|zyrx~zxy{qs~w{|y}{vzz}q|xzzv|zz|zsx~~h}y}}|}~uv|xzttx|}}|yz|z~x|x{wx~zrs{wwxxx{uw}|{r}wyou{zw~|w{}~vsw|}xzt~|z}}}tyzw}yvywvzz{zm{s~umz}{xu|z{rty}x}|vy}}xz{{{|y}z}zy{w||z~|y}z}{~}k{x{gzxy~w|r|l|{u}ty~|x}vy~||vzxxtz{xrvwyrzvswyr~~|yo|tx|p~q|}i~xsuyvv{z{z{{x{|}|yu{}ywzk}t|}~u{{wuu~|j{~yw~y}tt{tk|qrw|{{zzxnrnvr{}lux{~{}|p{otw{|{zx~vxtu{{}w}zls|wow}}{wu{|p~w{~||uyuyu{~{tzx||}x}{ws~|||u|xx~{|w}n~yw}~qx~|xvut~|r~zyw|~{ut}rysr~|}|x~}yu|{tz|tztkoy}}y{~xzz|zyy|ts~}}y{|w~}vsz|{~uyq}{t}y~vozw|~|x{z~rzy}zypzz|wx}i`{~~|{x~vtrx~|zu}}uz|zz{u|}}oz}~|}wr{}|}}wtqwroxynuyutmzv{v~{~xz|nr||uy{xowzzymztz}~z{~~y~||w~|~{~}wyy}vuyy~~~z}u}u~~r~tzuxyvw{}~yn{yv~ywy|xoy}}ns{sw~o}z~yz||xo}v}||{~yzx~~rtwn}yy{{z~wr{x}~}x}}}otyy{|vwv{zy{~ypywwy}mw}~z{|vm}h|y{||tv|yx}vzxyzs~}zy}vz}xuvz~ozzxm|zwy}xrtw~z|m}|vxx}{|yy|y{yyx{|zyvryxv{t~qt~xrspn|zyxwyytqz{t|}x~znzso}yzwu~z{|v{zzy{~{z{}zw~z{z|~x~w||{s{stsu~~tz~{}vz{~v~{~||}xzv}|z{uy}{q~wzux|yy~p~|xyy}p{~xw~wwzu~~zp~xwxy}tx~uvz|~}yzt{xy{~{~y|y||~}xy{w~{xy{y}uysx|ru|}u|~v|wup~}~|}zxy}{vx|}xzzy}{poz|}{x}xvnz||u~{}xtz|yst}v~tx{w}zwt{{zz|wj{u~~z}zz}x}w|bu~yv|wyvb|sxyywyxyuv|et{||z{}yx}|||yz{~z{wwk~}to~yvuuyzy|~x{znyzyz|zxu|~z~r{u~|{}zwxz{~~vy{{tz|nzn}x}pyzyv}w{w~}~w|z~ygz~y}pzyw|{{q{yvv~~zx~y|ex|v|~nyw`Zqwr~||ut~wy|}~ppxf~s{tk{|y{q~uu~n|vy{kzt|uo{vtyw{}}}ywvv{lyszzum{||y}}{x|zp~||||b|{|ovvxit|z|ui||pev|{}ky~}w|l}vwk{|v|u{{jtx~~wuzv}|wyz}z{z~}|vw{ir||jzuy|qtmkvxzu{szt|hznr}~|yrezxxzwv||~~}wyyv}}ow~q|szty{|a~p}pvzy|}yuyxx~uxzzrq{qv|~|{ty~~}w}wz~~qy{}[ls}|x~~xkw~rzxtmyt|h}}}vi}x||}{~}y}}y{{w~}~~~v}xz~z~yz}}xwwt{qzwws}rxx}~}r{{|w}q{t{u{pyw~x~x~||{||}x~y~~{||v|w}ww}~ztx{}yx~wz|tuy}|{{~y}wu~zz}{zzz{p}|w}~y~zzw|~{|o}}{{z}x~~zwz}}{|ytvs|q{~z~{v~s}{|y~u{wzh{|}yv|y~|~}yu}xyyzvx|zztxxy}|~}y|z|zzp~zs|}s~{pu~u}|zx}wj~|}xwz{nyx~}|{y}{{xypu~~yx|l}qs{z~u{~|v{y~}ww}zzs|ytqty}{vz|}t|y|z{wwx}~x~|yw}yq}}q{~{{vwzyy{|}|{|x{wy|~o|~|{t~zt|p~}xtye}z{{|}|{|p|rk~{u|y}y||xw{|y~{yy{}xz|u|}t}{wz}z~{}{yu~yzz~~wy{zy{ys|zv~|xw}{|t|xv{t}}{l~{{|wwzzsznzw{|~yru}zy|{}xy{v~vw{}|~}|}~zyt~wzzz{|||x~~ssz{|}|{zx{qz}w|}r|z||~||{{|tvw}y|z{vi{}}}~v{x{zwuu{w|{~}}z}{z{{}wv}xzyw~v}{}}~~}xw{}q|uzzz}{|}}w}vu{v}{s~wyyxr~{yjxx~x}}zt}u~~|ws}yxw~z|{~}}zq}}~syyy{{}vy~zux~x}yw}{|}xf~u}|}sxxWpj{s~xx|qzyr|uquo{Yq}w~v|wvy~nyqx|ykyx~s{}{sp~zl~z\}wyt}r~zyz|wr}|v|sP}}{zknv{Qyx{wyr~nx~{|z}iz~ht{ywuv~{}~r}zzyyyzxsoxz{{}o{z{|w|}xu~mzzm}zxq}{b|v|xvzwpx|~~zux}{bw}`ww~vWw|~r}{yp|xw~}wq{ztvv}}zysCrxe~~}_|yyzfzv{||zl}w|q}yrtfu~z~}z}sx{xwz{uZr|}un~qzvly}|we|y~mpq}}yrv|ywnhyors{Yy~t~yjnwwuv{y}~}r}rz{wvyf|fgqyqpuwgyszo}}w|{zy~~ywqy~~{sx}}|}z~~vz~y|}}wx||}{qy~{xp~{}m~}~{~{~{~zy|yf{}y~}y}~z~rw{|~}}t{}o{|}|tp}v{yyu{{~}w}pyl{u~}yzy}u}}w}wr|w|}|~||bu{{|~{~y{{~|zu~{z~|}|or~|t{yt{|x~w|~}~~y{~z{y{||s}uq{~m}}yy|{x{}x||zuxw~xzu{z}{wn}swk}z{{|pxvww}{}||~t{~|{~~|zxtw}z}xzx|p~u~x}kv|}{}rv{t{}twy|t}y~u}|szov}tz{xzx|}|{|~z~u}y{y{~vy~||{}{w|{ur}zwx|xxz~|}}{||t~n{yvzx{{|yy{|syx}}zx}}wzu|w}v}|s|yu}vwxy|wuvr|~vx{y}ryxutuwr|~{~{x~xy|}sxz}{zx}~u}}}|{yw{s~{zyzxw|s~y~j{v~}|~{||z}|y}z}xzxyx{~{}q||zw{~}}x~xy}~}~|}~z|{r}t}t~yx|~yu}{y}}z{yrn}z{|~~y}lx{~~|||zzs|x{~}}{|{{{x|z{|z~{n{{}z{{yx~ss}x||zu|}y|szy~}~wuyy{zwz~yxWvyq{~{~w{{}xtxz~|wrzy{zr}y{uw{|y~wy|{|yzu}}}}wz{vt|{x{||w~y||wx|}|s|}}x~w|{|~|xu|}zy|s~{}s~~u|}oyzw}xz~uz~||v~~l{y~}~p}zz}zy}||y~~{}u}~v|rk{~~~|}{|w~{lzz~zzw}~w~|}y{}xz}}|wy|x~|{~~oyq|~v|}zutq~}|||s}zu|u}}}zu{{j{}ruz{~w|r~~|z}|mw{~}z}~vvpx~||{qzzw}yv}v}|sy{r}pqh|x}|}||w|{~|txy|o~zu}{}{|}~u~wvz{|}owf~|}|wv~povyt}zqw{uz~}|xj||}t~}~w~|u~r|~u|}xwwy~r}z~x~~xv{|{}x~syus}}xzuxpk}u|~~wyysw~sqyy~w||{w~xv}xxkvx||}v}yw~}}|{~~|y}u}uw|yxu{{x~ixywpvyw|~|rywxvzxzzzkv}|v}y|mht~y~wu{ot}qo|~~wx|zmu{uzzoytvw|{z}s{~y||~z~w}z|yp|~~ys~wv{w{wxyz{p~x}{wsux{~|z|otz{y|kvvr|u~}}{s|~{yv{t|x~}||{yv{hwx~}|~{}yyyv{{}n}p{zvo}xw||x~~~rzxu~xzw~z}}{z~s{}vvx{{~|z~z}|}yriq}|ort}z{v~z}z}zuzn}vrx{~~|~|{zyy{lw~wxou~qu||yznvx}|yyy~v{uk|~{wyt~{|zkv}vurpy{y{}z}yezt~zg{}}o~}~x~||~}wxz|x|~}}ux}xvwo{s}~~~|||||uxqr~y|{xwpz|x}qvu}{|~u}y|~}}~{~nx~|~z|z~{v{vl~{}|z}o}wy{z|~~x{||~z{yuzyx~~|v|~{s|{{xw~u|w}~}|x}x~{{~z}sy}y}p}{x}z~|wyx|s{wwz}w{s}{uz~yyzyzzy{~{vz|~|vw{|~iz}~z~z{||wszx{~|}xn~|{}}yxz|wzx{zt}yx|~|}xl~{mt}}|y|qzy}|xwzr{v{w}xy|{~q~|~p~swwi|ys|y}}k{}x~w}~|z~{~}oj}|x}{v}{{~v|}|~}zv~~y|{zu}x~{vwuzv{zsuwsutxun{{{|b{~swyw~{}{x|w~{x~w~pz{w||n}zr}{{{}}|}}}{}s|p}}yzyzrtzz{|v~wzm}{nu|}l~|v|~|~}yy{yu{{u|~}zxxwx{~}v{{x}wt|{yq~{~{{|y|z{tyzvy~z|~~x|p}}}uuz{}x}}}}~||z}t~w}|||~}yyy{{v}zy{}|n~z{vumyx~yq}t~z~v{yxlryu|yxuv|}vwx{p~zyws~|{vv|zx~q|zq}wzx{zp|w}{txx{nu}~|yw}s|}~zzvxqrxwx}}vqz~nt}}xyw|zxy|}uz~u}sx{{{zzy~|wyysp}{x~z|nuyuwz{|y|z|}{~~{}z}zwy}{|~vyrp~{y}|{p}|}z{zzyw~|~}y{~|zo|y|xypyvy}}wwzw{~{~~vz{yv~{~|z{{{x~x|ytxw~v~~x{y|z}xyw}}}|}}gs{w{zusu~}~{{~{v{}x|u~s{z{|}y{~y{xyyx~{y{}{|vl{z|x}y|ps~xpz{xz{zz{{wr{x{}}v}{yztq|}||v{xyz{vy~|z{y{sz{|{yy~{{vw}vzt}x}u~|wx|sz{~~wzp~y}{}||z|x{~}~yxw|{p{}~{|kx|}t}|~x}|z}w|{y{v{|z~z}~ytxw|xu{ws}}o|rvyzii{z~o~{~{i~|}x~zrw{{{|}~}u|yw|{zz}y|yy~x|~|v~|~uz~{{{}xri|uzty~}~z||v}o|rx{xwvw}~}~|{m~}u|y{~m||rzz{t|zw|~zxz{||}zy}w|{|zw}}|y{}w|}}}wx{}}}}~uoq|}x~}~w~}uwyturzww|zz}xu~zrzfz{zuwz|y}||}s~||~x{|u~~|~z{zx~u~{|{{~hzbya}h{uy{}znvwqp}}x}~t}sxw}~twvs{v~uux{dvw}{z|w|z~tr~ymvs{}ytyyy{v|yex{wz~}ywi~}yzu~t{b{|m|tx~|v|y|z{wto~||w|}wy{||`ex{||w{~y~|{qvyP}ys||}||}ozzxrs|}yx}y|~s~xwwx}w|v~k}{~}|yv}m~~}wx|{uz~|~~~~zj~xxs}|{w~~|y~l|~zz}|n~{u~cz}}z}rvu||}}||t}u~yy~k}y}vsz~}|y|}yxx~~z{~|}|vtv|~}}}}}yyzq|sk{{}k}}uw}q}t|{~wx}{zy|s}{vxsvv|~o}r|}|zyw{{y|~~sy|lxvxz~{zyzz|z|~}|w~}}q~~|w{}~v|{xw}}|z}j~o}u~r~zyo}zz|j}v}~{xx|yuxxy}~~}p{{zkvzvz|xkq|~}}{}~|z}}}~vy~~uqwju{|n}~}q~~|~vx}||~s|t}{|x|y|}~~{|{tz{}{}|wryw}xowvz~~wyz|~qq~k|y|t{sy~|}{{zzg}~{z~~zq~|s~~~~w~x||xz{{|{|}jknu||}tyl~||xo~vtzzu~y{||muzz~|}{~v~~~tz}{|~z}|ur|z|||{}t|p}qsrt~w|~y~u|z}zsxgztyr}zx~~~{m~v{|~w}{wuy}}y}{|vy~y{y}y~|{x|z}}|~}xz}wx~~~z~x~z~y~}x~s}{~~|qw||sz|suxvww}y|mu|{|s~w{y{y~v|zyvv~y|v|yxuyzv{pzw||oo|{ps|}~zx}z}|}ux|~x}x{{vyz~z~|{}u|}}~|||}{y}{t{~y|||qz~}y|{|~y~u}ovvt{}w~r{}yo~|y|~}y~z|~{|~u~~~wyw{|yz\ezyx{~y{y|}~rw||~{v}|y}vtut}|{|mt|}{|z}vw~}xw~{~{{}{z~zzv}|xvz}x|w~u||mo|~z|}}zt|{wxxxylu|y}|mwyww~y~~s{ux~}ozxuyyzyow}|yywzzvsyztw{}{~{{yq}~tzwwsr|vz{z}xs|zv||\}}|zxxvwvz||{|~||s~~zr}tq}t{~|t}~x}{}yy}w~}v}{{}{xtnvuxpz}}ozz}|w~t}xr|wqy~{~|w~x~~ty||{}t~~}|~y{~|yur}~ku|ty}xyst{yywwx}}r~s}{v{zv{~~xw}~t}}vzx{{ux}wq{~}p~}{{oyzp|{x}|}~{}q~u~{{|tyqvuxv|~sxv}rz}|v|}~z|}|~zy|{y|zy|yw{|suyx~{xzx{}}~|z{u{v~~zzvt||sz|y}z}{~zvt}zyqy}xz|}s{vw~zryvzvy|{w{~yu}w{w}z||mx}v{|y{}}~{w}z|vy}zz}u}tv~}j}t~{tz{u}{}}yr{x|~z{~w~xqv{z{z~{t~|~~u~zsx{x|z~{zu~vu~{x}zz|}z{{|w{~yum|h~pv}wyz{x|uzx{|yuwz|zzvou{wyz~t}}}z|{|y}x{{vy~p}}vy~~}y|y}||w~wzpo}~z{|zq}wux|~u{v}~izw}zyxw~z~|zylqz|xsvvz{{|z|uzt~wm}~}~vqm~~~x}~v~}}~iz}||}u|o}]t|{w|{z}{}x||~yzo{z|}z~ww}zxz}yz{{{yyyxv{|r{swsx|vz|vt}~wuwvtu|~{ro|x}v|r~x{z~}wuu|~{xyt{{{|~{}{u|||}zu}~vex~q{||||r||tz~xvpzxr}}r}s|z}x}y{{~}~|~s{nxzpxvysu}u{z|~v~yzvt}|uzu||w~~tt}y~x|ww~{vs}zrzyzkz~x~m|{|xwy{wx{z{xzlx||tyq{{z|}z~}}z~uwxzwyt|yr}qz}xzywmyuyyy}}{x}}{x}}{~}x}|}yr{z{~y}x{{zx{ttx~|x|w|}{|zo}mg~|~z|vxn{~{|t}xy{y}v{{xxxz~||}yyzsvs{~xz}y~|}z}f|~v{t|z|}|~}ty{}t{}{x}z{wu~{txzz~~y~y}~~ywk{yzw}}z~}|z~~|zzruz|pux}xt~}zz||r~x|vuyx{x|||}~~xzt}~q|wz}|~y}bxt}zy~|{~zzy|yvyr|}}|z~z}~v}s{~yzyt}~yoy{}y~~sxmyz{zzi|{y|w{unx{{p}{}zryy|{urzxyuszsut|{zyvzy|s}~~|t}|yzw|yxuyz}zzs~z~|}w||sp}zy}{}}}|}|{pzz||}x}y}gs}}uyt~o|~{yw~ysz|t{uuws~}xy{pytj~tz|y}zwz}w|{x~tw}|r|{zxw||zyv|w}zzx|ws|t~w}vx~z}w~xy{}{wvw|t}wy|j|zvzzsv{|y}}}txzrxy|trx~z}y~s{{{|{~px{w|z~pl~|tzysyyu|}{sw{~{z~~~z|}x|w}r{u~wz~y}wyszuyyywyuyz}x~znzur|qp}w|vz~|z|s}uqv{yu~txy~twvpuyv|}~su}{|~~zyyzy}{yyxv|zw}||u~}{y|{~}{~||{}{}z~w|v}~~zz}z~|~yxy~}|}|}y|~~~{y}~{zz}|}x}}{|wuz~|z{z}w~|~{~z~x|}{z~}}}~}u}{|~|~|zxzo||z{w~~}{}x}|{y|{z|}|z}|~{~zy||}z}}r{~{w}t~|}}~{~x{|yz~}|wz|~{zz~}}w}}{z|wz|y~|v|~}}|||wz|}{zvv}}w||{z|v}{||}|{z{~}}}}}}}}|s|y{{|||~}~~y{{}tx{~}zx}~w{~|~{}{}~}||}wzw|{~{yy|z{}}|wx}~yx|z}{z~u~joo|t}x}qy||z}yms|v~r}ly~~}}rr{z~{wupzwwoqw}zvuvqjv}kzj~ot|vv|x|gs|uw~~gzwwx~pqsgvy{zw{vv{y{yk|yuwrw~x~b{i~wxz|ob~}vyvvwmtvx{v}wzozxww~uypzynqz{p}quwt}~s}shupu|yyxK~x|wu~nrdt|xv{y}puzux}w{q}hy{xunttwwz~{zzztzhy{|~|xnsyizpn}}|v~v}{{|qve|kidy|zy{o|q]z||nxzjzy~xvwz`rkrv{dlzo}uvw}Qxztzu{y~f{z}}o~}z]z|iqrsxzhuyrsnlwxwzqvkw~px{|}{~u~}wot~]}{|rt|zhwjzttM}z}}{}y|{|z~skvy{}wwvz{ms}}x{{z~}|{z~oz}}|{u~uym}vyw~y}t}~yy~|{x|}x}zz}y}{}{w}q|{~xwz~zxqz||p~~}~vyv}}w|{|szy|{|xlxy}t{w~vx}z}~{|x{wwy||z~zz~||uwz}~v~||~{|{|{~t}vms{y~~x}yx{}izz~z}pm}{ztw|yw~~zyym~z}~qz{z~|}u||{}qwyw}{~v{}|~}|y{~~uuz|}y}uy|}wvwxwr}zxxy{y|~~|~}w|zyuyx~~||}yv{}}{y|x~}}}|{q~zyy}|{z~xyu{{~}t}|y{}|}~xx~}yz|{ww}|{~|}zq}~y|x~{uh~xtjy~~{|}~Ko}wmmxucltt}|jzq|}l}{{z~m{rz{{vuszyyu{zzxsvqvwo|||ow{nwvyp}iz}nuzT^ukyfy|~W}vzmyor~qy|}uuzo~w}yi}~~|uqtwcvyv}ttqml{qx}|_wynukx}xyws}||z|x{xtur{z}t}Wruz~wxsusy{uux}}z~}|t||vuqkqsyzvpius{w|yk~rqz|{twudkl}syq}z`{j{r~uh}}tu~zzvvzzzmz|~|{|sus{y~~xx{vwp~or}tu|{s|xz~{ziz~|{t{sy}w|ntw~vf|s{z}{^z|zsxxuxvpxu|}|wmx{~}h}{p|l{lnUw~}|y}{s{ywzzs~v{|zz}}s|rq}sxq~}z|z}z{{vwzw~vy}{|wfw~}v{{}uxq|uxyy}z{{ttzz}t~y|{~vw|{v~~~wxtzt~zz}}|u}r}xw|{|{y|uzztwy|}~~~|}x{{r|v{symr{|qs{s{~vw||q}h{{j|uww}z}{z|r}}}r}{m}}y|{`~~|}zy~xz}y{u{uqz|~}xvzzyzp}|x~vrz~uu}{}z{|or{{}zytzuy}u}vv~|szu|u~||s}p{|~xyxwzw|z{{|trsyozwx~}z~z|~|{zoxwu}z~|z{s{|yvvy|srz}u|s{x}t~{um}y}{}~yzn}m~{yu~z~x~~y{|n~{y|z|x|{{vx||w{{q{|zuz}|x}zz{tl}}}|yvtrz~szy~}z~}|zxr||wxw{}~}~oy~zzr~k}|xrdwqz~xz}wxz{uwz{w}|s}|yx~o~{x}wtyw{o~z~}{|{{y~zmzxxs{w|qh~}||~xox~q|}|wjy{~}|{suvr~yvv|~{}x~{sft~}|y|p~x}p|{zz~ztv|p|}z|~||~x|rs}z|}yyz||z|xz{yz~|zy|}W~vy|z||ryyz{wzrw}z|`wrx}|{{x{y{~u|u{yozu}yuw}{zs|{zt|}~zvvy~zx~}zzz}|sx|xy{{|zz|~x~{xz}|zwx~|u~~}{}vz~}}{||xx|xt|ryyz}~~{z{~{}m{{x}~zuz~|m}~wn}w{u~yy}z}}{w|~y|p~|pz}}|w|z{w}xtm~v~~{}vy{zx|w}yzz|z}z{z|}xr~yxry|~y~}tup|}|~{{}vz}xu{{{z|~}~}w~|z~{|{}{~}x}z}|z~}x}}{z|z{vs~}}{~{~ox~yy~|vz||}~zxxrzyz|}|z|q~|~{|yxy}t~z{~w{~~xvzzsy~v{|kv~{t{{z~vy~}}ysv~{|x{}|~}{{y{x|~w~~||sz}~~|{nxwtx|~sx~~}r}|wx{~{yw|{y}zk|r~w|~zw~z~|u}~|}z|~x|~}{v{z{|~{|vv}z|{y|~{{x}{y}|wh|~zuv|~{x{}zz}vvxyrz~yz}||{x|{|}}y~z~}zr|ww~zo{ruz}w}}x|t{v|~vy|~|yw{w|}}k}y~~|~z}zwxuq~yuy~~|}|xz{~z~zuz|{iv}|z}}x|}|x|q}}{s~}}z~{{ywy~v|w{wx}{zvt{}~v~~~{{yqqu~wqv}}u|{}|~}wywzwx|{y|}{z~q|~}|}|{}|~y|}}u}z|}}yu}}uyw~|~}|}|~y~zo|wz{{}{o{w{}y~}vw|vy{|uy|{~yrzuy~yy~z}o||~s{s|x~wyz{r}}}{y~{v}{~~~qy{v|ryyq|~~pzwz~t|wxss{yl~x}xz{{sm|}{~}y}}p|z~zx}zu{tnu~|k{{xu{w}q|z{{w}}y||yuzxx}}r~qwtqr|{n}v~{{{yys{|{v|v|}z~{s|xx~wzy}z{}~y}~}|}vw{y}yoy{|}y}uxwu|u|yyzzv{my~|{|w|~xz}vz|tyk~kwv|w~}uy~yvwtvz{s|}~|x~x}xt}xuxz|r~z}zy|vtw}|ww|qx{}}h~xx~|}xz|z}|~}w~}{~wpywyj{w|vrzouy~}ys|rxyz}z{{tpvu|{z}~~z~y{}~zzzpw}||{zw~}ruyt{trwuwrx~yzzws~z}|z|z{uym}|wwzv~}|wi}qs~{}yxy}{z|w}}{|tswtqtxu||y~wsn{{|srz~}|||}zx}m~vx|~}|}z|}}vy}y}|zv\~xk}|wq}~uzw}y~zuyvs{pyvx~us}~{{z~ew}z{}u~ydy|sux|~~z|{}}}yvuz~{}~{}~~{vw{|mwp{qv|}b|z|~|vy~zxvqxyyx~}o{}tb~|}{ywuu~}z{yz{p}~|z~{y{|}u}w~zrr}|~~}}|~~~}y~{wyowz{x|{|y~zyw|}}{{~v~}~}y{wq}p|zz|ws}y~~xvv|xzpy|t|sz|~{z|~~}|{u{qv|||xwjxufs||vyv~yv~~}pyzzxyqv~|}|}~|zyw{yu{z}nwwc{s{~q}{|{v}~x}{{wy{~~}p}~|}}xz|{}~u|y}}}xvrz}u|{v~~z~t}}xxst}}v~~s}}xvzszz|z{~s|t{yn}~~w|x{}z{vzy|{w~|xwzy~x~{z~}~vz}}{yzz~~zy~y}y~v~~yx{}}uy}wuov{z}{w}u~wszxx}{yu{zvk}{|}{}}tw|vv}}~{||ur~~u{wx~szvwy~|zyy}x}}xwx|}xx{{uzr~y~w}{zy}|~z~usu~x|~{ox}v}p{{}xp{xtzzv{z|cv}q{~|{|yuztw|}|zv}y~xx~u{}xz|}v{wyy{v|{yz|z{~}y{l}vtyyy{xwwvyz||{|u|vz}v~{z}{o~~v}{zrx|y{tuy|syyn~o}zwz~{~}||v{{mw}s}{y{~~}}y}~wwzq~~|y~}|w{zxz}uvx}y}|}|ngyz~|}~}{}y{~vx}{|{||{|}uyy~{|{~|kzyy{ww~z}v{~x}ty{z}y{|y~{{}~vn~x|w}{{w}}twty{{}~}|}|{}xx{rqyw}z|e}x~w}}zz}~|~|zx~|}|q{txltyx{y|}yv~~s}y|z}{z|{{kxzqw~|}{{}~~zyzyz{y|}z{u{|xz~~{}zy}w{y|q}~}~~zuzzju{{{}ztwz|{{}}}}zxyj~|~{|~|}z{|{t|yoz~}~t}{st|m{z|z}zy|{z|uz{tuw|~{w{{x{zrx~vwwrtxyo~||{z~~}zyx{~v}x~~}ywuyxx~z}y}m~t}usZ~}q{~}zdv}t{y}}uyzv\~ys}z|}uuw}~~py{~{{z}y}wx{|~{}v~{zyw~~xvn{ww}}v}z}}z~{~rx~xxt|w}yzy~|x~wxz~}}}u||yp}y~zu}~zwt|w~y{ww}f{}x|y|zu|xz}zp|yx|z{ix{wwvu~{s{~ut}|u|}~y|y|{{u|}v}}}zk}~z~xw|{put{|{~|}~w~x{y}|z}~y||}{||~}y~~u}~rw}}usx~p|v{v{}|{}zw|}sz{uyw|v|{ww}x|z}{ww}{v}{y{{~zx}|}~zz}}mxz|v{z|~z~v||wxv}x~koxt}||ywu{uv}x|py{z~t}yy}z{{z}{{zy{zr~y~z~~y||w|}y}}~p~zs~vr}~xtv|w~xxo{tz{|}x|wz{o|gu|uy}y~zx}}}}{y|x|wz}xy{zw}}|{x~~uy{z}}x}ut|~y~w}|{z{|z}~yy~}xnu|r~|z~||x{|~{xw}p}~{tuz~~}{y~~umt{{}||{xx{zp}|~|y|{{ys{z}}xxx{q{xx{~wv~ysx{x~t}{uwu}~|t}}zxv~}w}{}|yrmpx|yzy}zv~szz}}zv}w~~}s^t|j{q~}p{~}z~ww~|yyz|w|gwwm~uyzvos}yvzyr{|ryx~wutwy{}zpzrvzvxu|~~ww{xy|~sszy{yzc||ztx}xylf{yx}xx{~|}yG|x|}w}i|zmu{wy}{o}{|~~}fzf}o~|ny}y|ewrxm}wytz}wKyzzw}v}xu~~~u|w~~{}|zoy}t{z|~{{u}uv|}x~|{|}{{}z|x}y~y{}ywr|m}z{`uny{}wxtu~xtt{{x}s|{~{z|v{ry{~}}~wx~{u|}y~~|y|v}yyx|uqs}zwzg|}g~y{~|xy{z}~wvz~|y~}|wx|v||}vsqyrt|~~t}|~~|yvw{{|{{x}w|~vtut~x|zrxp|z|~{}xy{w}z}yzry~x}trr|~zv~m{|xwu|~y}u|y|x|}{}y{zpy|yyv~s}q|u}}uyz|z{t|y~zwrzyv}~vy}vx}u|{vz{{|~||}qusf}qm~y~|w}|s|}{xx|hzztzw{u~xy}z||}~~l~u|z~t|wwk{yx~~zz{~u}vy}zw|xux|~y~zq|vx{~|ypwu{u}||{~wucqyv|z}wzz{y}~w~~txvqo|}x{|~w~|z}~}zyt~x~z}~~w|~{vws}|y}ygzqyyq|}jt~z{z}{wzu~||z{}z~~}~w||{|su~tuv~{{||||z~|~v|~w}w{vyy|z~}||y~}{|~{t{wk{~}}wzxy~}v~}ws}|}ytw||z{zz}~}}}x{{}~zz{u|w{vy{{~wz}z~~~qv}vstxy|z~|zz|~|v|x{u|vywrzz}|{zxx{~v}}z}x}uo{{}}|z}~pu{z|zzzpwy}~v~{w~~{z|w~m{~|zzxw~|zzzzz}~~{}upx||{yywr}}v|~}w}~x{{ysuvzvz{}}~tt~u}u|}x|~vuw~{y|z~z}t}|vz{ztxwyzvyx|wz|{|||}}xxyznx}~}{~yzyxpt{|xyu~w}{v|uy~s{zzy}yv}}{xt}zy~{w~yvz~s|t|ys|wr~wz~{wzw|~}{wyvvyzu{|ye|||}|}}{|}p{{{x~yzv{z{|{s||}|}}zxy~zvzx{}x{}fvqu}}|vyz|{{~y~uzl{{yyy{{xy|xw~~|svx|{qy~y|wv{syq{hqsy}w}}|}y}|}r~y}{|x{||uzz{w|qps{{~y{||}}yy}vyzyz{{u~|}x}t}}zz|y{|qxw~}}xyouz{~ty{~ty}zz}vy|vzx{{{}z|yt||}u|v{vv}}xysv~}y}y{xt|y}{uy|x~u|~|~vy}yr~vpu~x{u}~yz}}v~}y|}zyt{{||u}|{x~}~{yxt|yw~|w~z}v|}~z~{p~tk{|q}}{{{w{}|xus||{n|||m|y|wv~tq|}uyzt|st~{|~{vm{}x}zzts{y|}||txxzu~x|y{tu}{{w|s||{|}}||~~s~|~}}zx|{wu}xz{{y}|tx|~}{p}v~|z~xz~~u{yzxw}y~u{{jwpy~p~y|xz}~~~nsu{y{}y|}|w^s{n}||yyv}{}{~{vzu}y}z{|~~|wt|x~sut|}w|v}z}{{y}nyxwz~w|zxw|szuy~|}{y|z|~zryyrtvn~z|uzvz{yx{}~{}~z{{}{j|z|~}y~|{zv{uyosy{q~}{{~wwzy}}zzx|w|xv|vzt{}~~~ptwz|}~w|xoyzms~~x}z||yv}z}yp|}~x{}~}vx{u|u{y~{u|z}yx|pxyz}{|}r{~t~x{{}yzvwwx~|{ww~}{}z}{|z||vvz}||xs|}|vz{t~~~{}trpxtyy}{vy|xrx|{|w}{z}v}|wwu|xyzx|wxts~~}|v}x}~n}zyu}xv~yrzxy~xzx~|{un||wuyx}yw{yvzz}}zzn{{zs|~yxzw||w|zxx|xvyyyyy{zu{~|w~zzy}l||vu|}}xt}yxb|~xw~}||h~{yx{}~y~}w~}|ty{wtxxrwvu|tx}~||vv|{p}~~|{}z|xz{}{xy||~}zzypy~xuxv}~vw|x}z{~zjv{}~vmy~}y}}x~{||z~x|~xz}|~~{y|{s|~}}w~~~||}xqtp}|x||~r~|w~|~{q~w{|w}{ww}zs{{{}{~{rg}}~}}{qw{~u}|x|~vyz|uzxxzv|}|ytz|~w{py~|z|uzx}}}}z}~zyy{}||u{{~}{}|~z}~|xz~z~y~{~z}y{~wzw~u|}zp~u}t~yu}xtvw|y~v{u}|z~yw|{{{{{pyyuz|~w{z||{{}~}w~z||~}vty{~~{puy}wzp|~z~}}{{~s}{}}vz}z~x{}~v{{~}|r~|x~yvxzezy{{~}zy}}~w|}~xx{w{{v{}{{}w}{ywzxz}}{{p}|wxsyquz~~ry||{{w}wyw}xyzxy}z|~vzszr|~~wy{zzz|ztx{wy{}xyz{}y{r~zw~x|zpt{x}{~uvwy~yug|ox}tz{tww~za~}{|}~}{~ww|wuzhv{||s}{zyyp|~ps{wiq~|~}}{x{uxs~~~~}|{z|xuw{kw|xy{w{W~v}t{xz}{~uw}}v~svr~|r|}q}s}}~}zu|xx~x}vrq}{~~}z|yw{}zvzu}~tw{z}x|{~|y~y~y~}zw{yt{v}xr|}|~zy{~t~z}}r{yy{yhq{rt{mwwnz|x}{h{{xx~v{|zvys}|~}wx}{{tuuszyjwhzz|}{nxqxr~|yz{~{wks{}||zu{y|~q}tw|p|u{r}wu{yz}}zzx~v}z|xv}yzzy{{w}}y{~{||}|z}z{}~{w~}um~||~s~zx~x{x|}sz~}Yz}{sz{ox}x{{tx~yyy|{n{ty|w~~|ymq|y~px||{yy}|~|}}g~yyz{{vzv}y}|{~~vz}xu~~{r}{xw}~|}xyzy|~s{v{~~~|xzy}z{|{|}o}|{u{~}|z{}z}~v{~sz~y|qwz{z|~}~}|xy}|t{xz|qwsyx{yzzw~x{{zyxwzw|~~y{~{~{zz}|zxz{~z|}wu{~w{z|y{{{nq~|u~~zxwu{nw|pu{zvx}|}}||}{y~~w}~|_}~rz}~z}t~v}z|~r}|}~uv~~}z}|}wxxy{|r||~}}wu~xw}zz|}{rwy}uzt~s{|o|~~z~{{k}}y|ty~{|z{|u~{yzw}{w}z}g}|xq|~y{syz}|w~{}}v|~yz~|~s}}|~~}wz}x{sv{}~~xv~{y|{{h{xvx~|rxw}w~Y}}tu|uy|u}~}}t{~w{x|}|kv|}~{||{}|{~|zy|}ywu{zs|{|{z~|{qx~|}{}uu~||u~|~~y}}}{}z{zx}zvz~}rxz||}t~zs}{y~xpw~xtuzt|s}zxw~z|~{|}y{u{nwvtn{|{}~|}qyp}|v}~{{z}|}rlw}~|wvvl|za||u{zv~}}r}{qywv~x~j}zwUv|mz}puvt~{o|~swypszz~yxv~psxey{}zlor{{Ztw|~}ws}tcztyuwu{|{uwzwvwwvunp{|z~z{}yσr|wst}{z}z~}}uz{~o_||ykngv|}]zotym~iudp~w}~xlt}sut|ktaw~wpxw`sun~znvt|xr{|yew|x{t|~~m{{~}vzw~}t|||y|gqmw~{nzys|xwr}v|}|~w}xmi}znp|xtocwytf{sm~|~Uy~}yk}wz|}}yyzX|uz~~||q}zmjxz{~{uz}tw{}y|j||uzwxo{{]xzxwbtzn{zr{v}zyxzs}~tw~~}}}n|wp{|}w}v|vh}xj}}tw~{u~yt}~t}v}{}{yzt|}y|vv}uuwvks{~}uz|zy{|}yt}zux|~~qzu}~}n{zy|}xuyu||u{{yxxx}}{yv{~yx~wx}v~u|{~~~~|{|t~}zx|~|u|{ywhx}n{|xx~t{v|t{}~x{{onx|s{tvt}zz}y{{xrmu~{y{rzy~xy{{x~r{v|{~z|tu{z{yw{~wzvyuz~~{|r|{~{wx}y|~}~{}~w|~{x}v|s~~z}~ny{}x|yywwy~uxxz{kp|xxlusyz{pt}~su{}~~{|~gw~|x~}tz{~{w}m~v~ow}ws|w{{yvopw{{]x]vxv|yyy{{zwyy|~~|z}~{|syx|~u{w~xzsx{s~xz~|}zz|t~wy|}zy|vxu|z}l{u}|y}~pyw}}{}w}|}}||ur}u{yw}x~}pz|vw|{k{|tsw}~}|{{x{x~x}}|{py{n|||zxz~yw}}|w~vmv}y~~x{xyyp|u~{v{zy{qxpx{|z|}}}wuw|}~s|||yxz|~|~`u}{}g~z~yn}tn{swqzy}{v|rx~~{p|zvzg}v|im||ua~w~vz~||{{}t}{zzys|}|}xz{{tw~zu|}vu~~}z{~sz{w{~vx|~{|u}}{}|~wz}{z|oz|}|~ytlyuwgwY{~}s}{ywx}tkyz|t||zyy~vzv{~y{vtpp{f~~~{}z||y~}zu|~ss}{~|~hxwwyn{~{}|x||v~pz}z||v~xx|}|}}w|y{q|qmq{xrt~~~wx}|r{~v|x{y|szjyy}|s~syysdvy}|n~|wx}~vzvv{wwtxz~|wy}tvx~|}j||u|t|tuzvvy|}zgv|S|vyr}yzwjt}{{n~sz~rx~{nzwtzp}{zu}r|o{z|{l~xwnpvzz{{x~yo]~ytxywxkpwr|ywqztwn|w~wz{z{z}yrwz|q~rvtq{}t~}iwr~ysw{v}w{mutw~|~{|{{xyg~t{}tzv~vwKwxyw~yz|uvq}}}tw}yzs~uzy|[ukx}pmyn}~{{z|z|}qs{s}}vzpyyz~~z|yw{~vzz|~|x}}}~zzxz|~~o|zq|~yw|{zx~z|wy~|}}x~{w{~zx~|s|y~|zx|x~|}wy}~tzk|x~xxyxxt||~urvv~xy~{wlx~y|z~}xwyxvtvy|~z|wzytx}z|z~h~}{|yyzu|}wzxx|uwpurk{|yzx~~}uzy|rr~y|z~zvz~vwxvzx~zw{vyy}y|xyyutxqzv|~{}~~~z{svq}w~xyvvw}xz~wx~x{~sw~~yz}zy{zw|{lz{wtz|q{|}vxzxy~~|zzxwvvv~ss|jsv|~ztyxwzzyz~}zyfxvysyy}|~z~x{z|}y}v{|xt|syk}sz}~|}}rq|yuy}}{vn~z|~~}x}}{~}z}|~}zy}{}y~rxxv}vy~|x|yxx|w{~yu~}w|h~mx~s~t}|}x~}{|~sd~|tz|{}~y|y|y{zzu}~|yxzz{{tv|x}zzq}||{r~{}u|yyl|}{zy}~vzsz|~|}||||y~{~{{x{{z|u|}}ywuqx}z~|{{t|}y~~||~~y|z}|p~u|qu{{|||vpx~|~~|~zwp{~w~xp}{}{~|xxz||o}txz}s~vx~x|{~{~~zpo~}zx{~{u|z{~h}|}~{}~up~~z{x{zvqu|v}k{z{fp|t|~zx{zyp~yt|p{msk}w}zz|||}|y|pw~yx|vz~}|yu|yyy}z~{|{{i~syy|zyqszv~zs|{z{{}y~|wx~~{|}}y{zbv{~wu|||uzix~wx{vpz}~|smy~xv|}~|{w}{~{ziuovz}x|}{ys{z{tov}|j{~ztlxzyy{{w|||{~rvzz}~}ssnzzyuv||k|zqyz}z~}|~y}opy|z||||r~y|j|e}~}fzsouuyx~zt|~s}zk}xpx{|z|}yj~zvsu|~~x{||yxduz~x}t}s|y{~}|y~~u}_vyz{}y}|mzw|}{u|z{~{}wxmvvxwzvv{|uqwos|~|z{y{|~|}}nuv}{~wx~r~t}{~xv~}z}xy|{zg{}w}|{|px|{zq~{}z{{vwq|swmr~zr|}|zy}r}xnv{{x}}yu}wo|yx~k{}w{q{xw{q|q~x~||~gzq}~l|z}}y|[zyruyzyt{x|yu}xt~q~~x~{{xv{|x}vx{yx~w}|yxyw}||{x{~~}}z}~}w~~}{jw~~|z|~}}}{u~z}z{}y{t{~tpzz}}}|vq|~{zx{{zyu}y~|~n~}xq~zk~v}v|~|{}zx{~u|{|~zz|x}swxw|{ty~y}|~gzzyu~}x|~uo~|}zzx}}ul|v~~~|x|}vw}~}r}yy~v{}z~{nwzyzzx{}z~{|y}xy~w||{}qzz}~|z}r~q}xxzv}|y{{|zwy}{zzkx}~zx|yn{~~x|wy}{|}~ww|u||~s}|~~l}qms~t|w{|_{~~k~|~{rjzw~|}n}~~xz{}pxw{}uyzwx|~yz{kmidu{rt{wzyuzv|wz{zwvv}}ngxyvv{}~yj|z|}xyp|}~ozozw}xnyz}~zn|qs~~~zw}r{pt~}~xutu~~u{{{}}j}w|tt|{~x}|}x|oyw{{{~}{w|}ls}{yttpux~{v}uxpxowzxy{vcvs|x}}rzrjy|{xvx}xux|ts~v{zy~r}|kwr}|~ysz{vmzy|zzpx}s}vzo|||z{xpsyxyu}|v~un{x{{uva{}u|~xq{n~{|tq}y}{^uyx{{~ws}vpr~~qstnr`{}}m|o{ux~syso|zx{ox~v|xuqyxv|zxt{yvt||cq}z{~qtl}}~|o}{|y~}vv}|xx}{|w{yqpy{w{~s||yx_~}{xf~zy}{}z|dvzn~t||xvu~tzz|~xq{{}x~~|sz~}}{||~xsw{rzz~x}ryy|~z~ym}}|vz}|z{xt~zz{{}~~}}k|x~~}}xx~{}{}npy{z~t{{xl|x|~}y}}|~{{~xr{yv{|{~x}|z{{w~{|z}vx}zxztvt|z}~~~}z{zjzm~tl}~{n}~mzx|}~s{z}|xxp}w|rp|u{}~|{rz~hq~~w|u}u{|zv}}r|v|{||v}~t{y{ym{{zf{yv~~}w}yys{qr~q~z}y~||qp{{t}pwxzp}}v{|n|~q~vv|{z{|wrsxz|ym||y~{qz{xvw|~{w{~wzwuy|z|v}xz}x~x}yyxy}z{|~~|z|yy~s|q{}|x}q|{z}}y|zyy}~ssuutzyxy{zztqy|y|u{|w}h}{{~tx|yy}{uzyr~{|}~}zr|~t{~r}vt{{~xvmz{xv}s}~}wt~nvzyy|z}zz|sw~w{yz~tw}y|wx}|w}z~xx~|xx{|~xvz|}zj{x}z{}yy||}}{xzy|u~}|ynq~{z}{~}|syww}}us~u{}}~vxw~~~~yztq|r}~|vyu|{~}~y|z}zv~x}|z|z{v|vx~z~t|~|}}|yhv}w|z|~~}yv~{zx}vyp}mms~~{p}~x{zyxw|{{xz~v{}y}yyzrqowgzyzzz|ytu}|~~yzv~{zu}ywy}kyv|j|sx}{y}y}~x}l~uu~wzyux~}s~|_u~}wz~y{}q{vyzy~u}vx|~~}~}m}{v~yz}w{|qwvzw}}}ts~~~qrz{z}xhmyuzwzw~{}{|z}p~xvmq}{~}~~}yrx|{~~t|uigx}v{y{|~rx|~ryp}~z~tn{S~{t|~|zxt|xxzp}{xwyq|}z|z}pvr}zxz{|~xz~rzzw}y}ys~}rp~wtpozp|nsvjpzuyt{z{rv{vw~{wfxoswy|zzx|x||}y}{v}|}vzu|v~~y~}h}ysr{y~zvt|z~~|{z|~v~z}zyy{u|~xx[u}{~{y}yu}x~u}{}|t{|{vzzn{}ywvyrx~~xyzx}||}~~{z~{yy|}~nxtt|~}~}}~~}}~z{uy||||{x{u|szv~}|yy~x|yx{wvn{yz~{~}y{~~~~zu~xu~u|xwye}yw{zx}~}wz{v~s~|p~~yy~xz}w}y}{sy~y|~x||y~x{}~ztysz~}xzyxwy{~z~z}|~x|{{|{}q{v~zyxv~sy~z}zvz{|~w{rp|~qtz{y|~ru|{{{zzz{~|v~wr||~||}zt{{zzx}}z{r~z{~nx{w}tx}{~z}z~{s|ty~}j|w}~y|~{|~}p}w|wz|{}{zs}~vty}vz}vxwwuz}|~|~}|u~|zyzm{z|ny}v|yypywxxy~w||~w{|~z{sx|~y}~|us~qsx~yxv{~~{|}|~}t|y}wx~{}~|{y|xwvs~t}xyuzxy|zv{}yw{y|zq~{y~{|y{etxwz~swzzww~}s}|~zx}xzwx}~|v~z{{y~lwx}{|}~ytly}u|}y~}|}|}z~{~{}~{|}pv~sw||~y{}{yy~}smx~~xvu~u~xky|xuz}r}t~zxv~xz}}my}}sxmxrxy}ty{z~zq||z|opsq}x~~x|vszzzv|tv{}x~~x{yx~zyzt{|~zxt{zzszmd|q~zspu}}{|}|{k~}~oz{vg{zs|}sn~~yzvw}{|zt{{}~{{zztzp{zxz}~|p}wnzz{r}}||{}}}}v{{xv{~}}|~}{~yy~ywax{~y{z}|{{vhb{v~}~~pz~~|}tnu}{s||v~vap|{{~mys}|{}~w{vy}x}g{}ysv~tym~j}u|~u{qrxzx{}{yyz}{w|wzz|}xtz|x~~xcy{y~|fuur}n~zyx{|{yvrz}vfyk|{vlw{|~t}vy{z{tzw||wpz{{|yuyu~zxmjzx}zx{|uzyzrx}zyyzr}v|pwv|jo}wqvzwxwzty|{}w~}zvryvyuyr}}r|t~x~x~xupUy{Hoov|~m{f|~w}vsuwt|~||z{}s}ay~x~|z|wwzyuq|fs}}~|{zzv{us~p||x{s~P~zubtw~}ut{{|yyyw]{}z||zrtvx|}xsxytvxl}v{{r{z|}z}[{u{swz ~q~t|zh|sux}{x~x~~yw{{z}~}|uzz~y~us{u"wqsyusyy~y{p}}||yv{~{ztz|wnrrx}x|q{{x{ut~xxt|~w}{s}u{ww~Pz{xvszyvtvwz~w{syzt}vus{rs{~}}}t~p}Wupsyzlzx}zmvwxtp||{{yu|~~}x~wy{s{}y~|qzosw}t}|ryjw{sx~z|uzu{|{uxt|}yvwjfVv|x{xyw~w~xwq{p{{vwv}t~x}zzrxx~|{zwvws}}|w|tvwtz{zqszx|w}sm{uy|x~~}rx~z}xs|sy{py}~z|zzx~|zulv{|y|wxupvokw}nnsut~p~zuz~sxx{sr}~|yvzswmv{}t~qztwxvytytwy{~y{zt{|z~r|w|~zy}|{myssx~yz|t~~z~u}wa}|x}yo~sv{uurxzxovy~o~~z{pwz|qq}zZvxs|z~z|wtzu}zszz~|{y\}s}uv{s}x}~||}zx||z}x|{{y{xyrz|xxy}xpz|wz}}}y|r{zyz~~wrqy~s~u~}zty{}l}fxxy}y}{~w|}z|}ysx}k~q}~o~}}}}kw}uyznk|xx~ts}vwuvux|}v||~~zvw~ms~yyz{rt|qz}v}xuy|{||z}yu{w|uzzzv}rk\|z||~|}yzt{|q|xv}m{{~v}}y}ingzv~uu~{y~~|j}bqz{{~{|{y|}yyv~yuwvzw}y}vpwtuv~n|z||}vz}piz{{utw{|xwo{tz~{~xuywrt}}}yz|svsvx|yx~|xn}{{u}sz~~|v}z|{xy}wy{|xkzwtz~syqkyxy{{sw}x}}|yx~zzw{|z{|z{}{~{|zs|{t{~m{utZ{{u~|~~z|}x{~x~|{w|j}}}~y{~~}|y~u{zqxux{qzz|~{~rtx|z~|q|}zz~{t|t~vvuzr}}t~x}}u~{|~yymx|y{wuzw|qxz}|~uuow~y~{}ut|wy~wx{|s~z|}vyt|x}}||}{y}uxl|xt{}{zzyxw|}~~~~}~|xzw|qw~~||~y{z~u|}zuzw~~||nzzu{|xv~zz{wx~u{vuzxy{{q~}|qxy~{}z|uz{~||xv{}w}v{yo|u}{|~z}zqzyqw{}wzzt{vrz~y|y~z~{yv}|w}zz||xu}w|{zxnwu}x~}|{}yzx}{ywrzzxyx{xwwy~~prw{}{v|wzvxz~~znv|q|yvn~z|y~pyxt}|vz~tzww}uusn}vvy|y{s{}~x{|{z~|yw~}||t|zzqwtt}vv~vz|{{x~ypvwry{|{|~{x}x|}{{~yzz}}|}wz|}yxtz|yw|{~zz|r{vv}~qxz|wqz~|xx}ps}pt~xz|wz|y}umtjz{{y~y|}x{yuw~||{z|y|{v}}|~x{{m~{w|{~b}yxuzy|w{|{ox}}vxx||yv{u}zz|wun}}|}}uzzrnx~|z|z}{}||z}ru}|xzz{vyxl}w}}}y{z{w~|yur}z}{|r}zwu{{zx~w}vwt}tz}xss{yyvz{y{v|xvo~kvttl{v}v||{||uwv}{|||w{{p~z{z}rz}~uwvvxx}s{|p~}vvr|vxy{x~|ryp~|oyvv}qv{~r~y|}q|{|s~|~{||}y}}sxwk}oyx|q}~~~u{}~}~s~x|~~zy}}qsv|~||uy|~zv~vq}~yzxz}|~}p~}zx{~zpzxx{y~}}|}wx|}~t~~z}|wy}}x}y{}~xx}{yyvzv{y~~xr~{|y||zx|tv}yx{}y~{s{}yzxs~v|~vy|}wy~|y{|}sz}~~}|u|q|zj{}~y|{jzxm|}tv|oyzy{{|x}}y~}wx|{}}}wt}w{~uz{xyxy|muywv|{zx~wzwzr}pzwxy{~u~~wz~zyyw{zu||uz{lv|xzur~tzzz~n{vy~}xww|x{{{zv}u~ut|}|zzsyy|~|||~r|~}{zr{{ywozuz|s|v}wzwyz}|z~v|||{qt{v|w}u~y~x}qy|z}ntrzz{~}y}r}v|~z}yt}p}}|y~y{w~n{|}t~{z~x~|uxqz}y~|}|||~{}~v|z|}|{x}r{}}{{||t|~zz{|uwyoux~}w|u{x{yt|z}~zy||}z|z}|~~v|xyu{p|x|}}y}|u~z{zxrw|wmz~|~|~~yvz{yz{kqz}}w}~}ly|}~}~zxxq|}~v|}v}~owuy}zw|u|{y}njyn|xw{w~||~|{|~x||o~~}{t|}xqw}x{t}{w{{ww}{ozv{|wwx}zys}y}}{~vvss{|r}|{f|{]|{q}{y~}z|~o|v|n}zzvr{y{{u}y|y}tvyzwuk|zw|v}~~z}zqx}|t}}u}}z||zs}v~{{s|~}{||~{y}w{w}y{{tz{}ssz}ww{||~x{|{sq|{z|}}}x~}xv}y}q||{y|quj{}z~z}{~z}~zvx~xqx|v~|~|uvw{|vuwxx}{~yzvw{~~~{w}t}yzxyywvx}}~u||{tzzz}}~x|}o|kypyzzzzn^st~}ou}z|sw~}w{r~{|x}{vzx~xpr}zvz|~ypx}ktyyw~|}w||tw~y{oysy|t||s|}u}vt|t{vxtt|y}pu|~}}z~t~vvuxy{|~q{v}zwz}y~zt~y~t|w}xr{j|~s~yyr|}~{}~~|y~}|y|zzy}y}|yy|zlz{nv~ry|vr{r}{~}~|}zz{x~~v}|{y|s~}z~hx{u|wjty~|s{|}~~|~{wv|y}z{~{~wu|~{qzlzwwv{}|}|~su|xwzw}z|y}wj~t~y{}~z~}~p{|s|||~|wz}}tz}y~|pu}x}|~vxvv~tuvrr}}z||zy}q|}vtzb}ls{~|jq~z{}{t|w{uwsv}{t||{}}}|zt~wyv|s}}z{l~}|}~}{}~}zl~~{|}xy}}lw}}x}{y{zz}~oq~zw{{u{}o}{ty{~}|z|uz{{zywx}tztv~x{~w~~n~y~p~|y{y}{~{{qzz{zt|t|}z~|s}~}vwu}}yu{~z~p~ywx}~x|~|yx}|qzu||xx{z~||x|w}{|{~}xxz{vw}|}vt}x~z}y~o}}rt{w}x~{|~}~xusw}zu}}xvzmwz~|yzzz}}y{wx|sywzr{~x{lz~|~{y~~}zt~qy{}}u}}ys}~|}|}x||oz~|}|{zuy{q{~|z|~}xm~~{|}}}x~||}{z|||}n~|x{xx~ww}wwy{|||~||{|y~~{{y~|{x~om~|t|{~y}s~~}v{y~ywvzz~|{~p}}~y|{v{{x}vxz|~rrx}w~y~||{w|x{wu|{y{}z|}xzzuyy~t{}~{~~zxyxzv{|~{y}t~}}s}}}uzpw~z}~}{t{rtxs}yz}w~~{vu~|}xx{xq}w~zvxx}uy{x}|y}|t}v{{{l~{v|{yyx}tuy|qvy|x{}{yy~~w}~wy{yw|{w}uz~u{}{x|vz|u{~~uy}~{}~~w~nyu~r~u{y{}}|y|qz|~}u}}y~}z~~{}z{y{}{zsw}}v}{xruvnxwu~z{|yvy{|}yxx}|z}v{}v{s}lv}~zzxzx}{sxkp|zx|nyzowzyyuzx}}|rxq~wy{}y~x~~tx{}z}~z|}~zt}t{y|xz~{qyy{{|x|}ty|w~urxr|txy~~{r{}wz}~us~{wqu~}t~~}t|~~|~|}}wyv}yr}wnz||rpx}}v|w{|vz}{|{ttt{{o}~z{|w~{~{{}xzztv~}|}uvv|y|~}z~|wuuuq|xzux}x{svr~}urvp|x|~|||{xuyzr|q|s~~w{yuzyxq~~w~}~}k}u||m~u{|w~ztwwsv}{x|~{||sf}|m~}{v~s{xrwzqzz{y{~||}y}nusu}{u}{~zyxxyv|p~~|z{m|h~~r}xp}z~e{sv{}z}~yz`}xy}put}x|tw~~z~x}}xxtvqwwzzuz|}|xuz}~jss|yw~~x{y{x}|x|vy|zm}wx}~ylxt{s}}}~|vu~|}twtwpuwu}yowxyt`vy}|vyzuxqvzvvy|{z}}uw~}~xw|p{xhts|uus|vr}zttry~||yz}yxz~}q}|}|yruvzwpy~zwpus~}u|qryz{~|{zwtxo~y}yvuyor{|ytyzzw}zqy|~yy|vtxnw}vxzz}q~h{zszir}~w}}{vxzxyz{w{njx{{v}k~}|u|yy|v~vrq}~~ur{tz|{{|~vw|~~pzywn~~{yz~sv{v|}uqpzs~{}vzz~qxszs|zw{}v{t|}z{v{~yx|yunz~yqv|}w|qzuy}zz}~p{|}zhww|ntzx|nq}{~|u}~tzwsx}m|ty{jwnv{w}{rn~txu{txj{~wz~ns}xr~|wxkzznzo~p{wuwx}~xqu}}ox}|z|uy{tyt|pr{~vtyrwwyoqx}}}|zy|~y}|v}yuztu~f}t}vuz~~x~{{}|~z{y{y|wvzrmtsz~{v{|}y|}yy|{l~x~~y|u}|p~{xz}yzy~xw{~|~|{zs~q~vyzo}}twxt}|x|}{z~~~ztz~z}mu{}}yx{~wxt}||v{~{}}zz}roxy~~x|~|}~{t{y}qy}}zwy}y{u{yly~}zyn|qo{{|}~|o{}{w{}{~||{}|{yu{y|yw{~vpyz}~z{~u|zzzzp~u~q~|||}~zrx~{s}xy}zs{}sytwvs~z~{t|x}~|sz~~yxuuzwz~||{v~u}}|x|zxyz|}{w|x|zw~|~{w|x}wm~y}{{zx~|t{{{x|zwvsp{|wwxzy~~{wv{{v~{{~~}zv{y}}wz~}s}w}z}z}}~s}t}}k{vuz}uv~r~}||ytxq{~}y}zwz}vz{rmzzv{wmuup}}vtp}t|y||l{q|v|{ysxvt{x}|}uvzrwyyy}jz{|m}~~|z{||y{xsxqzwx{z~wvp}u|o}px~txzsz~|u}|svw~||}|xvuytz}z{y}{}|u|x}t{|xtu|}zr{|}{~}z~lnwxa{~xv{{|~zx{~tnvtyy|tvu|vyz~|svxzntsv}xyxzz|y~v{}|}uuzgj|}uyxxos~uqqtpy|~{xsvwww~x}{wgzq{zw~zr}w~o|w|}x}x~{x{t{yryzz~~s|||y|{{xn|}~}}{~}}|}vx}y|xzy}~{{|~~~zz~yx~z{{m~j|xs}y|z|}w}|{y|}xx}{{wz~}{y~|y~|~xyzxu|z{z{zswvzx~{{zvty|}y}y~{|{vww}}}{ttw{~{z}xx{{tx}{|{|w~|u~{y}~}~qsw~{vyzzx}{~~v{~wxzy{u|}{t|~u||{}z}}}y{}}w}{y|~}z}|}|}z{~yy~}w~x~z~|}|}~xx~zz|~{||w{}vz~}}t}|v|r~z{v~ys}{~}{tyw~ww~xy{}x{||}y|}y}v}|x}{w~yz~zy~wy~zzx}x~{{~t}~p~zv{~{z~}r~~z|yspt~zqyyjpp|wxsxy~nyq~us|sq{}{~zx}rp|vzr~[w9zuw{~tsz~uz}uz|~}}}x}|~z~wt}y||~|l|}m|{||xr~z|x~|w~|~z~}{}x{}~|n~uz|v{w{}~~|tz~v|wz}x|{{|}}|ozz{}vy}y}{}{~y~}p{~yuvt{~|||{vx{~xxw}{{{x~xyo~}{yx{}x}n}}lyy|{jsz~st}}v~|mz{{{|z|~~~|||zz||~y~~}|{|}y~yzy}{tr}y~}tw|w{}}zvw~~zzyxi~x{|}{||swxy||pv~}vz}y}z}x~zwppr}zsp|}u}wsy{x{w{|~|}{ujrxr|uwq}|x|~{|y~{||uz~ysx{}vvuy|y{|uj{yj~{{u~|{}t|u|vi}{|{v|}|}dp}~zw{y}}nslsztrq~~s~z~ny}{y}z}||ztrkr|}y{}uz}}||}xz}v|~y}ot}|~~}y}pt}}~p}|}~z{uy~r~y~|y|}vvx~z|tzz|w{y||{n||n|~x~ys}yv|yz{yu~{z}yzw}yzxnuyux}ty}yw}}{~~v~yuu~xzzo~zyqz|||}sszq{~}xzyxqk~yvyv~|z{{swrqzyz|p~vwy}z~xtw~zswz||~wwx{mzzwz~|x|~|{}|w~zx{xqzzy~y}~v~{~u}}~}}}ryx~x{{{yxxy|x}}v~z}wvxx|uw}tx|}y}z~w|~~}}|}u{v{xt|}[|uvz~yq}}}||}x{|woy}|~}{}|{{v|~y|}y|~{l}vu}~}~~y~~|z~|rz~{ro~ur~|{u|{vp|ywsv~||z{z|wy|}|}{|~|tx}|p{n{puvz{u}|}uyo}|~{~}{~wz}|z~{|qz~vvztyu{z~{z{y|y|yy~~||qy}|s{l~}|q}a{z{{{|y}v~~y{||{~~}|}y}}~~|}sz|{y}x|{|}|z~n|{r~}z}y|xxz}yt~~~{|}{z|{u}|{ry{x{ct|~x||~x}}x|uj|{q~yyv~}}w~wzy||vyuv}{|}{r}{}{~vo~xvx|u{x~{{tz{y}zsxzzx|yz{~|{yvvxs}rwv~~}|t|vxy}zz{`{ogty|}||st}w^zzw}yvn{}~|v{~t~}}u{~|z|s|}w~|tzyu~||}}ph}{~z|~p}vz{rwtz|zzwuzutq{z~}|}}|x}y{~xyuso{ww~zvwp{{y}~u{z}t{||vvy~}|~}p~z|vv~{}khy{~zvzwo{m{xxxtxtym~sxvwtxwrzxuypy|wy|||syuz}wy}u}~xtnz{|m~v{w{uz|p|~x}}}y||z}q~w~~tvus}xyyx|s|~xpy{x{{x~{~xxyr~o}uzz{ywet}v{{|xz~w{gxwu}}rsy{}v{}}~{|{x||{l{}tz}{vuz~|t{yplqt}tw|y|y}|xx{}||y{pyz{|zxpzzz{sy{{}{{wz{r||zzzvx|}}}y~~j{{s{w|~~~{~}pyxw~r{vyqupxxz~xvv}q{px|}yw}xiv{{}vv~e{y{jz|wrwv}xzz~sw{yxu{{||r}x{zpzzx~zzv||xkz|xy|~w}yyxy{|xzy{~~xnow~z~}~~~zz}}zzm}r~~ryxr{~xryuysypqwn|nvxxw||utrxsy{~}yw|vn~y~vxxx~pm{ht{~qrouvyx}|{{tzu~}vsu~|||x}uy|p{xzy}w}x~x}|z}wq~~vxozz}}x|wxyw~v|x}|z~w~z|lp}|t|~x}uyxzqw{zz|w~yw}{~}yy|wz{}yqy~|{}zw|{|r~u{wwuozw{~xu{zv{{{{}ytyu}w~~~|}|}}{}x{xvw|{v|z~x{u~{xz~qywx}z~zwk|}x|{yuydv}{z~x}~|~wr{xyszzzyz{~}v}vx~x|xs{xsr~qy{~p}w{|~z}zz_|~zu}|}~~rvwww|~|{zx~~xyr{xq{{{uy}vsp{x}y|~{tzy}}u{}{ytzzVw~}}~r|~{~uxyx}||txzt}yvz|~t{xu}u~xm~}p|xu}y~}~qv~|z{xy}}usvz{z{~|rzs{yx}yv|w~w|vx~y{|v|y~t{|zteu~q}~xt{x}vq}|{~wt|t{u}z{k~|m|{uwy{wu}zy~|x~iz|pu}{pwl}y|y}x}}{||wo~}w{}z|~{~x|{uy~}sll||z}|~}|}}xzzq~|||}{j~}zx~qk}v~yxx|~x|u{vp{{{}{~r~~|yz{zzy~}~x||x~}zz~oup~{||~ywzx|x|xzz}z|z|z||{}t}~uo}~u{|s}r|n|~}rp|{}|s{|wr}u~||x|wzt{xxzutkyz}}zyy}py~}v~u~uyyw~v~}vu|}n|yszz|y{|x}yx|~p{}{|}{~~wvyxs|{}}~{syvz{vwvj{|xtv}tz}{}xv{vtyz|ww}~~{r}~x||ryy|xz~u}~}m{vzyxuv}|{{x}|uzwwxuy|zyy{x|uzu}~uqkyq~|}v|{{b}x{~}kxv}~v{}{uw}xz|o|y}~}zxhx|j||u}w{w~p{}{}xw~{~l{v{s{~||zu}x~{pm~{{qq|{y}w}}{{vvr|~js}{ut|z~yv{wy|t~|{{{||xs|y}tww|y}}kz{sr{|z{z}}{u}w|xr}uqzz|~{m~}zw{~~w~x||z~{|{~w{}gu~}{{yzt|{tj|rm|z}v|q}x~~w|yx|sv}}|{x}~{zww}}vo~}~xyyo{yusvsv|w|zx|{vyu}}}{z~rw|{}~{x|{{o{{~}{~lut~{pkpq}uz~z{wxwxq~}}rx|wx{||x{~|f}~uu|~yt}r{~|~w~|_|zu}~~yy{{~z{}~||zz|~~v{svzvt|zy}|}zuz{y~w~y~y~yvqw~}|v~}{z~{{|~w}|~m~z{v{~{~v~}|{ztvw}}~}x{}y{~{w}|z}{{ts~{|z{~|y~~v|zyx}vfxz|||z|}|xuu}|wy_zv|||}zqz||y|z{x~}~p}w}~{oz|u}y}~~}|uxq{w}|uyxwxtyr~|}vx}v}~xwz|}z|u}{x{}}~q{~}}x}~~}}}mi||xyt{r}z}gy}}z}}}|qyzrv{|y{rz}|vz|}rq~q}~r~}z}}kvx}{|}|}|zw|{|tpvy}r{yyy{}~~~}u|}zt}z}y~y}txz}}}}ww}~~~~}~~~~s{z}}}|~|y~y|{ww~}w|}|v||zw|y{r{{yvt}y~znw}}v~x}u{x}{}~{~}oz}k}}{||~rq{{}|}y~|}||{y|z~}|{pt}au|~q{|||{~~}~q~{x|u||~|wrx~~r~zoy|t}~xv~{w~|p|}yz||}x}ty}zu|}z|~w~~ut}}~~q~xtvqu~~x|zy~z}|}w|~v~~u}{~p~}}|w|x}xuu~|}xx}zyxz|t~vw|w|z{v|y}vu|{oy~{xk|}|yuxyqq}{}uwwz{r{z|~}z|~~|yjz{{z~}z}p|us{ox}z||{w|^w|yw}}|sz{znuryw}yy~k~wo}yxu|lvwj~}szt|~xvzykxw}{w||~yyyvuusxqz~{{o~q~vtwz}y{{s|vwz|uu|y{yt|~{||yww~{z~|~}q}yzz{{|~{~ww|~u`~vrz~z}w~z|yv}y|x|sutv}z{vy{~n|{y|~zxz{e}v|zqx~{t}x~|yu~v}x~}|yo}yX}s~|vxyv{u~{~slw{|z{|pruzy~phwyp{tp}uwswwx{v|z}~{}ztq|z{}|ry||ywx|px~|y||{|xvt|txwtxott}w}yxy{yvowxy{vyuxzz}jyv{y|}}o}tk}m|zqxct~ws|z~i|odt|x{}|szqyzyny~}r{\zn~z}vpszou~yttqy~wtuvwuv|x}ow{w{xpanjYzy{us~Qx{zz|ouzociozyqvvy~~szUk}m}xupz|}Rn|njv_hplqxfovv~}u|ht|fg~}{{tu~{y{kd}~{zx{tq}ovy{p}z{l~zz~x}x|stzw|u~{qw{xfu}znlgntizb|qzy~}~u{to|wx}{wm{y~|u}~tq}u{}{v~hvw}|t|}qx|x~~tvrp|zk|iuu~D|j}duy|zugy}}}vz~{zqrtvq{s|otx~zVy}uz{y{|qzfywyt}x~z~zxr}|tz~o}v}~w{}~~w|{|{}zy~|ytvw}s|z{}}{|}zzv|{|~|}xw~~}zwt}|{|yw}|||}l}~{vouyw|o}}{yz~uw{xr{w{|}|{|{xy{xt{y|ts~yy||{}zw~wqxzwwtvw{~|zw~u}{q||}z|}sz~~uxxuvx{}p}wovt|uzvy~{umwz{x|{}|vv~o|y}}z|y~|~vyw||}zt}qt|}~~xz|v}y~xsquy{}~}zxx~wxx}}~{ws{}~|skzsrr~n{}z{}|~}}}{x~zzz}v~zvzt~wy|}}u~qv{{xz~{zyz}{u}~~~}~~}{x}wxu{{pyvz~{~{}{{zyzy}m|sxvo|}yztu{|~r}tx{y|}{uz~~ts{~xt}~|{}|zxz~}|wwy~{zt}s|y~}|xnfv{~}vy~z{}yz~nl|{zlyqy{}}z|}p}x~}z|t~~~wx~~}|}yryx{x|oz||zw}ztu~w|u||u~~yz{tzrzymeo{ys}{z~yq|z~|xs~{}|}|wvx{t|tywyz~l{{||}yxw~~}sz}uz{|~yrfzw||~~{ux||{ytw}yzw}|wq}~x}vzw||yr|{u|{zs|z}~{zwyzuu{zzxvwzm~{v~ztmyxut|~w{z~r|x{~x{yom||{|}~yyx~yy{u~s|r||{}||y|}xzy{~ewr}|p|xwtzun~||zx~v{x|g}{r~{{{|{~vzvsw{}ut{{l~}iy{{}|rr|zcjz_z~zq}~}ui|}~y}r~|w~y|y}{{~vny||y{y}{zy}}suz{v{|bo}}tzzcxu|yz}~|_{s|tu}}su|vr}|z{{~|r{}sp~~}|~}l|y~xzvb~xv|yq{~s}|~~|os~s{wy~{{~z~v}|~r{ykvz}y{znw~}~|~{|{|xy{y~yx|{zwz|q}uop{o}z{z~zo{~y~|}|{y}vyzvw{ww|yr{ztck~t~v}{q~txvu}}y~u{~xz{zu{}w}~v{}l{q{ty|us~p}}{{}|yfwvy{r|||zq{i|r~|wo~~~twoz}yu|}tz{}{v{wy||}x}|tx}yvr{}|y|}yvz~|uy|g|~}{}z}x~zzorz}}}x|z{t}~|}|w||ws}y|{zzy{~{}x{|ys}z~~z~wo|}yz}t}zu|q|~yyqz{|{~{v|yvz|wzuy~|t~q}z{|px}y~yw{yt~s}}}~p{|~y|y~s|}w|z|}}}ztsfut{{y{~q||tkz}{v}~~{yn~t|{~t}}qxyx~~~~~|}}~xy~{~zxx~}~vnu~~|{~s~kz|y~|{}y{|yy|}zyx~zyr}yxz|z{~{xzz}v~r~~~wv~y{|x}}~pz||r~{}q~z{yz}ouzyyt}{}~zz|r|||~}yzyx~{puj{{y{~ms~{{ys~v}w|p|xy~{}t||t||j}}~{xvss|g}~r~{~|t~yt}x}s}|zz}x~y|z{}|||~~zx}{|}~{~{~zk}w~t}}q}{yzx}www}~|zs|v|y~qx|~|{}z}|wz}}yxy|xywz||}|z~~|z|w{~v}~~p{w~{|x}~~}~~|}~}xz}s}{z{{v|x|~tr}|xx{|pyu~}|y||r{|o}{}{}}tz~~~x||}z~x|}t~zw}zrn{u|y}}z{w~wwyz~x}sz}unz~y~}}}|}pw~|z}qrwvu}|w~{z{}y~z}~||y}}{y{}{vjv{yvww}w{yxxvyu{t{}ww|u|w|{|y|{ywz~zswz{~x~uyw|}~x~}}y}~t~|}{|z~{~|a}{|}x}|l{|z|z||{|}ts{y~{xxt}}}zlz}}t|v}xuzyjxi|}~|~{u}w~}Yg|q~rs~ws{|{w{~|zz~q}~y|vzs|{{n{|hl{l}{|v}|qp}~{x|~u{}ny|x}vxxyyxw{}q{~}}jyy{ulzr{~{rxw||t|~`|vlwy{s|z}}}|s~x~}{~ezvewyug{yxqz|y~uwyvyy}oysy|t{wz}|x{~{v{|t|~~~p{kzw}|~wxwz{xz~s{~uyzwz|p}zym}y~xr|xz}n{vw|vsyzys{xmz|w}ytkwx}v~{y{|||{w{~z||p|{~}q~z}{z}}|zz~n|rz|xqw~{|u{wz}x}}~yy}{~v}|tv|sv~vv|~|~~w~vuy}o{z}{}{z}xzv|}}|~s~zzx~wv|~q}z}|~~rv{zly|zzsx|}}wy}r}}{~s|}|}x}{}|}z}~q~vt}o~|~}uz{s|~vy~x{t{~wo}y{p||v|{vy{pw~p|}}w}w}ix}{y|x|}kx~|zve{~}{|}y}~{uuw{tvo~yx~}~ku|{qzxwu{qyvy{}}{{~|}}|ysuv~x}~z{z}vw}~}|uz{~{w|}yy~tzw{up}~{zzy|}}yz}z~~||}m|r~|}f}uz}~ywy~wy{~}~|~~y}x|wy~~}vy{{~xz|yhy{}vy{w||w~{~{~~zzxx}~uz~|ur{yu{}u}~zx{|z~|}vy}xxv}{}}~}xzzyzz}r~{{|uz{z|}}~x}|zu~uw~wyzuy|{{}x}z|}z|{wxz~}~}}y{z|y}{}{z}y{hzuz|~yyv{y~{xt{z}}~}xzwds|}{zw}y{uz|||~z|rux{|||~~{x~t|xz}~}~xz|{}{|s{~ywzs|sz|v~{}}|k}wxvws{x{s~{u|}z{j~y{|xwt~z{}~v}w|zxsy}z{zvyz|x~x|wzwx}zt{swz}m{uz~|]tx{hv}w{{{ytwr|}x{||||xw|zx}zxz~|zrv~|xv{p}w|}}x~}v~xu~{qzzvwy~z||{~{y}y}~xxu|{zw~yw~{}|}yr|xq}v~}w{s}vsyx~|}z~|}}ww}v}uyzz||}~yr}u~xzzwyxvquwzmw}zo~}|rxw~xytz{yz|wy}w~}y|~uyz{{}q{v||zz~{zz|yxy}~nx|{}y|u}zy}||xzwzj}ywrs|uzz}|{wvywyyw|~|~|xzxsy{}ex}|{vzs{w}~~~xq|r~{v|}}x|{zv{{~}}xy~x|{~y}}~~{~vuysz{u`xvyu}zxw~zz}x}{{{~|vv~yy|uyy|{~}~uzwr~ky~{r~~t|~~~|}s{~rx}zy}}~o{u~{ou{||}|tx|{|~x~vyz{}v{~{{|~~{~z|y{v{rwyut||v~w}xww~~z}rwy~~}uz}u~~tz|wzzox||n|}s|zyrt}sw~vz~nw{y~{u{s{~{z{u~x}zuy{xzy~|z|t{vsy|}}uvx{oy{x~{~{y~x{~~twyz}|}us}x~|}|xryp}~vz|zzv||xwzyvt~wz{uvx|{~q|~ux~}}y~k~|{|yzwxvy{{ww|}xpw|y|vxvs~}s|z~|~uy}xqyr}o~pt~}yx|tvysxz|sr{ov|~{x{q~q||}~tz~}oz|zy}u{pw~x|}y{|zyyy}~~|{{y~wv{vw}p||rz}r{w{w|xuzu}{y}~w}z{{|}}}{{st~~~}}z~wzrysxxs{||xytm|}}~]yyrvvo}~{v{xyyyu{x|y{tqx~|}|zwvj~w||{}|}~}|{yuwu{zxx{~|xxvy}~yv|}{|{u~l}ys~y{|~|{yy}wzyz{~}~}k{{~|vy}}z~z|{dvkz~{{{}y}{~|{~~zrvtxtsz{~~}|lyx|~uwts{yxzw}y|{qu{{u{~iqu{y}~|wfttzu|x|u}p|~{vy{|{z|{}d|xx{zu~~y}y|y~h]}lv|~|z}~oy{{u}~~|~|}ozzwez}~~pqx~}zp{|o~}z|{|{sr~zxu}{tv}x~|}v~~{{~y||rwr{v{y}yzyyzw~~uy}~syzwyy{w{~}|~{|~z|xy|~zxz|ux}v|z}|{|v~z~x~~w}kwsqvvryv}lt{~{~|y|x||{zz||zw~wk{x}|qwy~wz~yv|{~qx|~v}}}y{qxyzz{w||z|z|x~|{}|}y}zx|~u}tx}~vxymy{fwz~v{~x|u||vuku}|m}~t~~}yyr}~xx|~{v{nz{}lmy}y{vyqv~{{|vvwxyupxyz~~z|z{~||~o|~x}tzt{y~}}}vu~s~{~{xv|{tztz{{{oyyuuwwz|~w{yx{{|}}u}|yy{zst{yxyyzsyzzw~y}p~|x||vv}v|w|{y~`zsv{~vrx}~z~~wyy}|wnzzzsw|z}{xxv~uy~}}o}|s~|}u{v{~|u{~~u|x~|v{zszy}}|{z{}}|t{{z|{x|xv|tux}jzw}||~}uwxw}jz{~}~}zp{v{vw~|{ywwz|swvvx|~|z~{}}wzn{x|v}y|{tyx}}}~{{x|rs}||wz|~zyxxx}z|~}{zw{w{{w{zz|{xd}vxvxmvuu{|x~|~}o|u}y}~{}x~~x|}}}uxr}y{w~xqxuxs|{{wwwz{y}{m}x|{~zu}v{u{{xyw|yy~s|}yzyjz|yqxz}|}z|v~~|t{y~z~yqvdvv}n~qw{yw{~x}}}xtq~{~{~r{y{|z{zw}yn}|}xy{}z}|sv|}}z~|}pxx|}vy{xyusy|y|}z}xy|{~x}vz{yu}{|xx~}xw{w{rzxxoxz|y}{z{{yztzz|u|wvqozq|z}wxzyz{{x||~x{vs~zyvxuxxz~}z{x|w|vg~w{ozyy{~zy~zy~xvzx}y|~w||~~||v{~|}un}}{|xy}zy}|zzxx|uxv~{|}~yrz|zy~~zzx}x~}uy~}zzzzv|~|you~vn}}~}q~o|~|~~xzy{}}^zy}o{rz}}rvz|||w~yzosuxw}xsw}{}ov|z|w|x|z|l{|gv}|}~yzhzq{{w{~|x|z|{y~u}}{~}kzupy}nsv|y~~b~up}z~|{vy~u}y~u|{kt{{}|y{}|~p~||y~y{~vy|{}}x}|}~|{}||w|zq}xyx{|~o|y|zw|n{vv~wy{}|v~~{z|znyrz{~t~vm|{z~w}}{wxvuyl{y||}x||}so}}{}t{~{~zz|w|{y~}r|x|yz{|}}|aw}o~yrv|x~o}{oyo}~}{vtyzt}}k}~yp}}|z{xwzy~y|zv|}yiz}zsz}|~x~~~}|yv{}yv|z{|x|s|x{|kik}z}zwzo|z}zx}x|w{{y|~y|y}{~{vxtr|t~w|zt{|}zx{y|y}~yw}vx~}|wvtz~~wpzzuw}q}x|xwxxu|~zy~yx{yyx|pq|w{}xvnyuzszs}~y~w}}s{pzzu{q}z{x}s|{|}~wxyo}w~s{ku}xztty}}~~ztvy}|{~ut~p|ux|z|x~z||{~{yznzrzq{~~x|sy}xzuy}{yy|~xr}xz~|~xw}v|~r{y~}xz|v|~xwvtz|w}}z}z}kx{z{z{zwz|{{~sz}}}{|~nxx}yzws{|w|}yrwyn|~|w}}s|{z{~x|~w}|}m}~zzymzxwzyul{{}sx}|w}|jxrx~sux{|q{}tz|hvqo~{q}vq~{twy~}w|x~vx}zy{zzz|z~yxz}|yx{xx}|||{~|u{y{yu|}z}{~}zz|{mzzzx|{}u{y~z{{~y~y{zp~{xyz~~}}zuv|wyvoz~w~v~~t}{~xys|{z~}x~{|~}{}}|wz}vyn}{zzwxxuvsn~~z}vy|tzvyu}||y|uy}wx~|tz{xv|wyqxv~}uw{~{u{qw|wju{q||yzfryryzy}w{v~|~|z||ruyw|q}|z~{q}xty|t~tz}}y|x|}~~}~}st{y~}}{v{x{uzwy{y}|y|my|zzrrm~xxz||t~yjl||~{~}}pstx{wuwwzzs}w}yh{uvz{u{|pwz}y{z}zw~z{y{y|mfm~tqzt}yzzx}}}yw|}{w{{|{yy|zz|~xuv}uy}|~{{~|}v{||xy}~}zyu{~x}v}|||iyj}v~}uqz~zzwt}~wxzz{|zuyz}}}yxkx{wz{wx{~w|}y{}}zw|o~vy||~j}~z|zzv{}}}}x{~u{n~z{xs|xu{p{z{z}{x|}~z}|}|txcvs{}x|~x}~x}}}x~yu}n}v}{~tywy{s|}zxw||y~||}y~|x}{v|wxzt{xztx{wut{~zw~|tr|y~{{}v|g{yz|y}vy}wvy{v~}~{ru~r}s{vxxu~xyo~}|zrytuy}~y~~}|vmxzvvt~xwr|vvsvyq{xusw|{zq|r~{}a~z{|ys|sy|{vt|zvzurz}{|}yxtxz}rq}w}swq~}p{s||r}~ryvww}lx{}}zyyx{{zvqxz~{qu~{|xy{s|v}x~zw`vn||uvyzx{xgxw~wpqw~z||v|xxrp}~}q{{{y|vq~zyw{~}}{w{||o}yv|qyz{{~|~vzz~wy~r{z~xy~|mqow}x}bo{}trv~vt}u~zvw~}txyxw|{}xaz}l~|}}}w}{{z|{xzm|v}s|{{v{vzy~y}{zkl~~`q]yu{x}vuu~v~q{}}xkyx}}}uaxsrwzzo}zgtw{~zsttww|{ywwz|nyW{|wu~{}{wzu}z}}vy}~}{~~{w~x|y}uz~xyr|~trsows||~s~{wx~ztxy||y~z~rtyz}w}y||}yyp~{wsvx{}z{}uqz{~}wt|}yw}v~sw}{yq}zv{xyqu}{~mx|vr~y}u~xv|uw{}|v}wszi~{{||}s~o{|}q{{tzxzqwtsy{t~|l~yzpyywxqmpxw{}u{yy|vw~v{|zv{wz{z}z{xwux{z{~n}|~{yw|{{}u}y{xv|z}w~~~p{|z|~{y{ysvzsztiyz|~|yx}x}|mw|x{|y}{ywuxvwz{y~rx}zxywv}}rvw|{u}y~{tzzv||k~ttomxy}~rz{zz|{{urx|z}z{tv|y|xyu{x|szwy}}v}{~kzyzyztm|yi~z~{}~xv}{}~y}y~~zyzy}r{w|v|~p}tw~~{v{vtxyzz{z{{wow}~xju{{|ztrmvzp}}z~z|}{~vtxx|~z}}n}{zu|~~u{{q~zzkz{}{xux|krvz}|}{~w~}v~~w~~yw|x|~||~xy|xv{{wzjxs{~zt{{~{~~k}}}|tyzwxs|yz~yzrtx||yysu~z~vyty|yvruww~zzx}|}z{yo|z{zxxv}tz~nt}||~}}|wv||}{w~|vo{~xutj||||tx}}x|vy~}x~y|}}|w{z~p~yvz{wtx~~v{tvx~yx}g|}~q~}}y~}pu}x~{}vx~~|{|~}zwx{|~ts}ry}vjzt{wu}o||~p}br|ps{yz{u{y~{v|u~pw}{z|wy{up{~~{|y~|x}w{~|~x|tu|zu{}y~uvzzz}zy}~~}{yxxy{pw~vzz}t}|z~w|v|z}|{z~r|{x}~w~wqpxy|zzy{~tx}~xwz~~z|tmq{w}|}~x~~y}u{~w}~~}{||xy{}~||u~x||w|wy}||}{zixt~}xzz~xww~}{{vuyxvsy}{v~vqxv{yy~~|tw{~xz||}~n||xxw|t~~x}wy{}z|xytr{}~two{qt}|xtu{yu{|~|w|~zv|t|z~yy}zn{|s}}uu|pxvwz{}xl|~xy}uvu~wx{zy}my{|zwyxvw}{z{|yx}{}z|v}vwxxh}rw|zy~}}uxwx~|{z}}{~vfwypt{{qxzv~ry~zq||y~yuy}w}}}z~|tl|}z}z|{xt{y|}zy{z}|qq~~}uzo~{ik}yq|{z|t}x|~~z~{mm|rvp~zyww~y|w{}{v~wvto}~su|{uyozx|uyy|~o}{wz|{v~{o|yy}|wz}y}xxx}~s|tz|{|uuyuyxy}v}|~yx~uv]~e||y}r~xyw}uvuw{x{{~w|~|y~x|zt||z}zxyvzrvv{|yz~||zuw}qqxvx|z}nzx}x~}~zz|~|yxvy{y{yzzyz|}~|}ov~wyv~xt}~mzv}xvu{}~~||xyyt}|w~~ty|~z|{|}~{}{~}{vysz|~|yoz{{}zz}}yy}~z{p~vz|x||yl}{sy}~ww}~~~n|yzkvtu|}{u|nt{zz{z}||t}xv~t~w|y{|t{y|{v{{~|y~|{|y~~}{t}|vtwzy{t{pyvv}~x|t}|y~z|~vzx|zzr{xy~~~w|{~z}s~p}ww}|up~v}|v|{~{{zy}r|zzju~wvv{wx|~n{{y}{y|z~sy{|trus~{vuws{vW|{|y{|}~~yvyz{xwzy|z}yl|o|pu|}|zs|zt~}xzy}y}vyw{t{yh}qv|xyzx{wruvw}~v{}{x}~y||}|{u~x{uu~vy|}wv~|{y{uzy~zyvvz{w}suw|xv{zyuy}{z~x}rzo}}x}}|~z{{|x}y|xyo~zz~{}suytv~|{}t}|z}{pirzs|vx{x{z}|xwz~~w}{ts}x|}||}xy}{|{yssv|w|}}|{}|r}vvrtm}{y}~x|z{zrz|ww~{w}|zrl{v}|y~xoz~u||q{w|quxzzzw}y{x}zzlt}z~{|o{unn}|w}{}w~}x|}vz{{}~Ysx}k|e}}x~}~v~~qx{~j}|~owt}y~|yxz|y{||}{}~qw~}zy~{{}vzyu~x|}}{p}x|}yz}y||p{}x~}}~p}}l~yl}`~}|z{|q~}}q~n~Ux{nxq{zz}x{z||y~{~{ty}tzym{ty{y{|}s|~}t~{x{|~xzqvsrvs}u}~w~}{pz~yx{{}|}~y}|zky}~|tv}}~ox|t{u|}{}{z}|x|uyz~z}~w{v{}y|t}u|~yy|uz|{ze~y{{h~|}{~z}|mm|x}{l}x|z[~}||}~|wt~u~x{}wu{|}vzxvpz{ty|}~~zy{}wxown|{yrosxzwyz}{z~ul{wy}vyvz{|{ywz}|}~uyr}svu{zzzu~yyz~|}~}ywzvwvwvrv}{ux~zzuy{mnz|{}~}wv`v}xq~iz}tx}~ty~zowt~w~z~ytwu}|}|{u~yy{}}{zxozm|{w~{zwx}~zzywy{}xowxyyrxvvvq{ywmr||t|s|uzz}uvyv|{m{}xzn}vru{{tzx|u}|ny~jouzt}vo~yw}zzypz}h{|}zqv}{vrn}~uxvxuz{}z~yptw}z~v~xs}t~frsz~}o}i|tsqxzvvvx~z|}zww{zm{zwz{{oyy|~pt~zuw}{yy|xy}vi|yy{jwzz|~ztyst~l}}ownt|tz~wy|t~wvswlpr|xwxpvqyjmss}r|~~z~u~|wtzucs{u||lsu{q}tuz|}t}pt|x{}yytr~{}w}{|vo{y{zxrty~z~ujxq{}|}oyrwyu~|zo}w{t|zqszww}||ux}~y}}t|ws{sr{yrz`s}~t{vy~_y|v~zxu{x|}q}Zvupm|qsux~~r{x~|{~yyul}u{|ytxu|squvwxrwxwpyz}u}wmy~sv~pl{u}r}yp~s~xzxjy}wnq|}x|q~sy~vvsw}~~wnx}xy}uz}vz}u{~w|}}~~zw|wx~{|y|zxyv}xu{~zy|v|w~z||{{xx~|{txi~~}}yz~|t{~~ru{~z}z~tx}y~||uzv}~vc|wyzdy{~y}fvkz}}zz}x|x}z~}ux~}}z}y|z~~xyy{~w|{||}wwdtxwz}|~wwvv|xr}qszuzz~~sqy~}v~~yk{~~~~lpnu{v}~xys|zzs~t|tvtxt}{|||yyt~|~rxwypq{~w|tgy}{y~}{}{r{s~xzww|xw|}|}q|}zu}{nt~x}}~~|y~wq~~xwjyx{yz~rvuz|}}|uv}~}vu|{qyp|~}w~u{|w|{{~}wvw{}vsu{zx{~zt~}yuzpzhvxx{z|~z{v{u{x}~}|~x||{~}{y|y|sw{~xwuuyw{~so{{xy~}q}|~u}}x~~u{yx}x{}siv{{|}z~||{z|}w{}}{yw|z~}zv|u~x~y|}nz{ww{~z}z}svxuv{{tyurzr|vx}}}~|y~x|zw{x||~|{|zx|yw}|x~yy{y{|v}|||xzzz~|yz|u}xy|x~u~y}r|}q|}x{|ut|yv~x|}~p{}y}w}nzxt~|uvxyw}~y}}}~{yw}{ozxwzy~ry{{|w}|}tx}z{wzzys}ty|v{|quov{x~}}z|~wz|yq}rzu|uz}xwvqxsy|{v}trw{lgywtxu|~|yx}|~y|tw|{v{}x{ysp{}|y}zz||zwr|~}v{v{xvw}}w}}yu|wyjwo~yy|xw{iy~z{}}}}~r~z{}wo~k|}~yu{xzzt}}i{||~}zxzz{~|rxxzxxyy{t}uz{~~}x~{}|w{{s~|}}z{|{x|{xz~wx~{}yfz{z}z{yvx~zy}s~||{{~{v}zzz{tzu|t~~~~y|Y]z}s|zx}|x~qx}tx~z}|zz||~xwyuxq|}{xt}|~q|u~w||s|w|s}}|}zz|x}}~w~x~v~~wq{pn{|uv~}w|yy~{z{|~y}~r~}xxh|{x}vwuxs}{tsvwz|u|}zuy|}}z~}~xsyz}w{z{}zw~{vx|ww{}~}y~|oqvx}}~xuy{rz{y}x|wz}u{vp|{q}{y||s{x|~|~yzv{z|xy}}~zulxuswwz}x~}xz~y}w||}xyjpy~bw}v|{qz}|z{w|~}{t|~|{{zu~|}{|z||y}{qxxzpy{t}zy|}~|x}wp~o{x|||y|zx{}}c{p|~~wx{}}uy||zy~}zp}yx}w{xsw}~}y|~|}{{}[~i|{q|~yx|~{{}|~z~s~y|v{d}w{{}}|zsxxy|vzz}|{~}z}yqu}u|r{zxzw|wxu~yw|v{z|{~y{m~~y~~~}{yzwpus{{x{}z}yywv{{x^zrv~{yy}u{{ytt~tu}|yr~|zvw{y}}|{y}|{z|u~x|~{}z}zwzp~{}ko~{|{|~|{v}|{z|~|w}|x~v|}zx{{u||y~x}zw|}}|~{~{y}wy~}s|z}x||x~z|y~|}}zx|{|}}z|~~sv|r}u~}{s~m{~wr|yxt}}~}zzy|y}u{~]v~}x|vz|v~}{y{}~v|zxyz{w~~|s|xs|}y}~{||}{tu{x||{}x{sz~w{v~}}|}{|}|{tvz{{|uzk}{ubxv|yq{z{qyx{z}zy{|ywzwu|{~xz|vz~||zx~x}~}{z|}y}|yw~{xxx~}|zv~}x~{pxzg~}{||y}}y~z}||yy}wy|ww{l{}w}{~{u~~qz}{y~{vr~}{||y}wpyqty~|y{~~||q~z|{v|}}{x}wuz}}~xt{s|qwz}y}|{~n|~{sp~~vzzww|zt}y|~zsx}~~yvs{}u|x|}o}|~}~|~vv{y{xx~zz|w~|y|{|~~~~m{|||q{~y}xytttz~xm{}{|y{|}w|rv}{s|~y~s}}|~|ixz{zzxs}{z|z|zz}u~xosz||zrx|}vpx{|~}~{|zwz{}{sqwz}|z{~r{ryyp~{{~s{~{|}|{sx|r~{~xzw}yurz~{}y|zx|xzu}uy~zyz|}xxz~{~}{zv|krz{z|{}z|}|z}w~}y{{y~{t~|t~zy|r{z~q~}||yz}z{u~v|z~z~~zyv~{|dx}z}zy~r~yvzzzt}zsw}}{~z}|}qu|{}s~tt~j{t}|yt~wp{yz|z}xw|{~~ryw|}|tytuus~}}}zol}{|}}{yyv|}|~x{|}~{vo{~wv|}}~~~|~p{{oy|x~sw||usn|}}vw}}~{kx}yqy}w}{~y{}|~~y|stut~o}}{m|qqy}}s{|~}}}~zwntpz~yx}}{{xpy~nv}~}}~|t|}v|{~z~~}|v|~{t~}~||~{rt{zuzs}~|}|~vxuwzr|u}lxx}x}t|v|xv|r|~}z}yxwwv~z{{}~z{u~z~~su}xsw{}w|}wuvr~wyy{txiunys~~{q}vpyykt~t{}x|{zz}yr~z}wt|v~qx|{q{}x~|u}w}s~s|}y|upwlq|z~~wul|qzzvi}zz~}x{r~yxotjxxyy}q||swvwy}qdqppr||{{}[}p{}uszyy|x~sxw}{zr{xoorwrp~~~w}xqjwwj}}ystj{ow}m{xww|t}m{|}sp}z|zsryvy}xuo~}uwir~y|~gr~}tww~z{m~q~~tz|g}wxzu}{|km}}}wv~yyzy{z~y|~{|yo|w}v{sw~|cw~u}wxr~uo{y}sips}nzw|yv`yxn~z}~y~~x8trw|tuzuuvt|rur|vw{|}rwryvu]|zp}}zywzyuvsqy{|unt{vz||~xyux}tz{|yzz~s~|{rvwy{}s}xoz{|yx~}wwyx|~~rsvz}~}~}|s|vw~~zx}w~}|ywvz}i}}tts~svx~zyt|ty~}|{{~}oy~}mw}|~{uw}y~}|zy~xruz{u~w}|zw~v{~|~zuxyz~{s~}xuu|zz{xxzz|}}z~{|pv}{syvi}{{uvyry|yo}|yu}xzw|y}uyvxz|x~y}yr}|||{x|z|}v~x}|{}{sy~z|}{v}~{yzn}~}~}|zq{Q|wz{}ry}ovx|}u~~|{}~jww~wbzy|zztx~vvzx}y~{}xurzyzy{wm|{{z~ywuv{}zxz{z|vvxz~|}y~|~{k{sz{}uy~z|qyvxv~wwys~uowzw}x|{vvy}y~p}smze||~yrr~{yz}vx~{z{rv{ztv~s{z|ty~w~zx}}s|z|rzwyy|~}z}w~x}~s{~wzvx}~{y{vwymwy{|r|xv}}|}zs{{{sy~|yr|}v}}wvpyuvnu}|wyx}}zuu~w|styz|t{}v{vy|z{y|vty||}v}t}t{zwxrvy}zzpy}spyyyvvu}o|~uv||~t~uyzy}|w{t{w}|zy|xl|zwuy|{z}}p}}~vz|y}vw|zwyz}v|yr}u~y||qtxxrz|~vysw{s|r}}|vultvzlw|yv}~{s|||z~zy}~rvvzxw}|}~zv|xx~w~|{~wyx|}u|u}z{~z}{{wu}syxs}z}~x}vwy~}t|xsw~}~{~{}zzz~z}}yvzzp}|}y|~uz{~|{~w|uyw~vr}|xryuzxp||w{|v}~|r|u{{wu||t}y~x|zv}y|xwzzzxz~~|z|y{}|}}|w|||}trz|||~~v{|{|{v{|}{}r||zz~}~}{||zt~~|~|zuwz|tt~|{qvqxyv{qxz}~vyxu~~w}uz}r~unuz|u}|yt||ys~~}v|swyzyv}xz}{|ys|~{w}{}yu|}x}yzgwz~||yz{}z|tz{s}zttx}zszvtzx|~z}y|zz}|x{vy~l{{z}~t|qv||~|}|{pw}|||x}x{x{u}x|zzzzmu{u~}~~~vv~yr~~zx~zzz~}|}|z}{~u{|oz~}z|}}{}t~u{x}~x{{wzxwzwz{~~xzzu|}~y{{w{{x{vv{|uy|vy}}wzz|yw~oyz|}w}{y~|v{y~~|{vvv{zw}x}s|vz}z}xxzvoy}z~~s}|~zzx~xv~yz}u~xu|ztv}jvryy}|xz|~{}y|}}{uv|{v~z}y{}}|}xxw~xx{{{ss{|r|~yy}wx{x}{vzty{{z~zvt{}||}wyyy|zw{|m||xroxyyty~q}yz}{xew|~~}yzyu|yyyv~yr}w~~wz{|~xx{t|y{~~w}u|z~}u~q}zy}x|}|~yxru}ytxzy}pxx}}{~||z|t{}}~}{zy{{~nz|t}w~~z{~v}{~}|t}wyvsyz||jv|||sxywrw~{n}~vy~}|z{uwwst{|{oy}ywrz~}{}x}{sn~uzz|{u|xlz{z}zy|hy{||||{{tn}vwp}x|r}|{}ws~yi}|txzyzyzuxuw~lx~}x|~}xyzssuz}~}|z~tos|rx{y|qvzt{|wyzu}{~}zyyxxy{n{nw~u{{}}x~z||yuyys}{tyvyv{zy|{v|y~zo|wst~}~ywxw}zzxzn|~{szyxxwx~x|usu}t{|zvhp|y}wtym~|yqt}w}ww{x}y|wxp}~yx}zzz~t|z}tzx{z{r~{z{v|~ww{~vz~}tr}|{||zz~zu}{y~{}|~kwts~tz}m{~}wzz|zu}xq|z}{wx}}osxvyy{xyyr}~{xy~yxyw{z|yzxryv}~h{r|y{{szy}y~|~ytyzvotz|}xlzzrzw}wy}m|s}p{z}w~{}v}}xyzqxz~q{|}{v|w{}~{}x{y}xvt~t}v~}{z|u~zy|x~{}}w|{w{z}w~|v{~}v{zxz~{~t~~us~y}}}~}}~{}fz|~wu}|v{~v~rtn|x~{}~{|z||x~y|||z{~||qz{|{}zxx{z}}w|}zts{~zzs{|~|{hwypx}t}~ve|~z}{yww|}xvx~~~||zz}zvw|~s}}}}u{xyy~|jrwy|||r}|~}|fz~{z}|yx|{|u|{|ztz|x|zvszx|zxizw}~wz~}zz|w}y~~{|}kx}{~~|q{|~z|yz|}}z{x|~yxx}x}wz~|w}{y}}v{w|yjv|v}x{j}y|yw|s{z|{vzx{o||zu|zywyv~~|y~|z|zt~~u||{~}vw}{}z}~x~vty|sxuwz}{v{~rsly}||{v|x~zxwz|{z{y}{}|t{vywlw}||~xy~{}{|~}rt{|tz|}z||x{y}||zz~qxktt}v~||}~xuwz}s||w|v{x~x}{vz|xz}~z{}wwyv|}xz}z{y}}|r|pystq{w|w{s~uyx}|||{u}}y}tuz|~{}{z|}~|rvv~}r||wqzzp|y|pt~n|{{{ywk|z{}|xywpru|ywvxzw~}{vy~~}z~{{}rzr~~{zy|yy{wqy~~xyz}|zy~u|~y~||}u}uu}{vzxv{{ytxsq{x}}}z{{wzwzz{zu~{y|{z}{~zv{z}xqtw}}}z~y}x}dzz}}u|n{}yt}}}}||t~uzszov|{}mw{}{}~y}y{~}v||{y}}|xztu|v|{wy|{|}|zx~uztqzu~}~}x}{|{|}z|z}|}y~~~t~zpr{x|}ix|}~azxu|u}}|~}v~}|}xyz}|~v{~vw~{}}~{w}yy{wx}~}}}v{||~~~}}v{~m}~y{~|}}~|~{~zyy||}o}{|w|x}|z}xw~}}~}}~|zzzxsv{}t}~|w{~y|}|z|tws||}{n}x|u~m~}}yz{}|w~}~yzrx{|}~||}{x}r}p}~xoxz}vvi}x}}|{tz|v~~|||xz|z{~u~|z{~z}uy~}ywvzzr~y}y}~h|z}}u{}~~u}d~x}oy{}|z~y{~y{~sqy~v{}{sx{~zzxy~y|~zzxrx}ws{v~|}yr~q|z~~t{}{}xwwq~~ytos}trv}~|{~{v~|{xvxy|qyw||}t}vz~~z}v~{x{v|{z|}}}vu}v~~zp}}|}~z{~}yvy{v|z~}|ztw}zvxu~z~{}t{r|{{y|{|{|q~yy~||wvwryy{zz}y{x~xx|{{k|z}}~}z}}{ri}||{vt{ryyu{uuzw{{}vy|yq}uwz|zvq~v|}|zwx{o}{~wxz|~ywz{}r{}zzvoE{y~u{v}vs}z{yz}~}}|}x|u{w||~{{{wzz{{z|yxy~{}|zyzmv~}z}y{oivw~x}wt~{}xrq~v||yy{|swvv|}~|}}}z}usy~|y|~w||s}ns~{y{}~}v}~~wv}z}}zx~z{u|xy}yx|~u}}u}~rvywz}t|{w|u|y}x{zx{u}~z|yx{x~{z{yz~}yu{x~~|o|uz~vy||}~x{~z|}v~|tt{|vwxzm{|z}nzz{t}~w}hznz{yvttzvoo~v~y{y~uxv~~}|}}{|x~s~uv}}}{{{v}|x{zlz|s~yx}z{wv|s~`{|~|z|zywl~}}~lo{w~|xz}~}y}~}}zer~~}|{q}otjn|zy~|{ykn}}xw|~y}~w}zxx{|}|~}y{}||v{|zx|x}sw|u{x}|{ut}w}~txuv{zs~y|yyz}x||~y|z~|v|o|{}Y~y}{}v|y{x|}z|~~{{~z}{x~x|yy|s~wx~m|t|}{}ztu{y}wy}|~}~~{{x{~zlmw|wxu~||u|~|m|}yzw~~|{x}|z||yw~tu{tzu{~}v{}{||z~z~~y|xw{x~}{{|~z|}y~||lzw~u|z{yy{{|xx|z~}~|{uw}y}||}{}{~}~t~vxx~zw}r~w{}}}}{|q}vww}~v{}y~|x|{|z||zw}s}zt|}yy~zz{}y}{|}kys~w~|y|}|vzyyupozww{x|}z~~~{zz|l{y}}qy{yxruz{uw~z}y~}~{{zrvs|{z}{|~|{}t|z||u}~~}vx~n~o{||twyx|~zu}}x|{tyv~v|w~y~|}|ux}t{~|}}v|ytw{{wq{~wvto{~|{sxzy{y|wy}}t}yk{tz}zujg}z}u~su~}{~wq|p|}{~}wvyr~swsxlx{xxxw|}z{wq|{|v|q|}yz~un{t}yvnz|zyzyzx{z~~~|{~x{t~y~}q~|~xqw||yr~zw|z{q||~||V}yzv|svzxtr|z}}sz{~~{}q{uvjyy}~w|ywzxx|xry{{ytvxuvy}{}~{w}uzt|zxy|y~p}{zuv||y}~ywys|~~xorz}{zux{x~}}vtxu|x{wzt}{w{|~wu|||~zqs}vu{}ud|}~z}{wvz~zsx{zz}~}snzxur{zwypus~{{~on|pzpvv~vwysr}ryw{sxsp{yvwvs}~}uz|{v}}y~}sk}v~{y}}|ooyu{}}|~~y}|{~~|u|}yq{z|~px}~z{|w}}vy|t}v|yz{|}{|{y}{{{}}}~xyw~v{qyw|zy~}s}}wyu}~x~zw}|}}z|}}wyyw}wv|}z}|yy|{z}}}~uk}|{~z}~y|y~}|uz}}xz~||~r}|w|y~r~xwu~{y}{yw~w|v}n~u|y{y|o{~}wzpqp}zz}|xy||zf}r}z|{z{}p}}w|}qn{}y~~yxrf~|~|~v~{z}~z~x~z{~tw~|wu{zzn|}|t}t}y}}~|}}w|yz{}}y{}~vs{|||tz}~z~|zuzwy{wwu{}{w}}}xx{}||~|{z}xyvwfxw{|n|y|wvv~}|}wv~|zx~}xt~~{k{yyw||{}z~y{yx{y}~v}|sx}t}~w}}v|ֆ|}zzt|z|yty~yyx~}}v{}~~{t|t~yzz{z~{~xz~zo{z}vvr{~v{~~|{{{zvx~u{{}~|~}z}wx|}z}~z|uz8}{zut~yvzzx~||yzwuwz{~z||w|q}}|~xt{}~|z}}}~{wx{~~wxyzzzz~w}z~zv{}xw|vsvwyvzw|~~~u~~}u||zxzyvy}~}~|xv|vr~z{~z~yz{{}mx{y~zxz}~sqpzs{qyz~~z{|xw}{~uv|}v|}tw}t{x~xz}vw}yxxuyyw{~}~}y{zz}wtq|vz~~||z}~wy|}y|{}{w|s|pxtz}zs{ts}{{{{yw|{zy}uvw~zx|xz~}z~w}~s|suk~yn|suYh~ww~}z~q~gwy|vvt{yrtbo~yvwmv}|w}yr|~x|xv~{}zt~rt}|ww}rz{w|~{|{}||~}}}~y{pxy~zp~|{ww{~o}wyx|zp{}z{u~o~{~yyvx~{vx{{x}}tszyys~{xy|ty}zuv~j|z~}y}r{u~{~{r}z}s{}t|a|z~xpz{}||u}{u||}zy|vzynwx~v}yp~zx}|o~xqxz{{|z||y~zuzzrt}{vxx}|~}um}zuxw}yzs|}suxxy{zvsd{toywynxywuqyv{~nx|w}t~{wtyzz}zuvwy~~}wu~|||yi~uoz}}{wy|}uu~x}t~~|w{|ts}}~w~z{z{~pu|yxvzyxzZ{|zyzt}{xx~s~|ts{{xq~uxw{{~r|~wxvxv}zxn~{x~uvv|v|qpt{}o{~y}qyw~zyys{rz}vtozuzywzss{{x}{s{}|z|{xvop|z|{zrz~w|xz}~|oux}wjxowszq}}~xtnyy|s~}rxx{r~w{uuwu|vw}|vtzqz|zy|uzzx{{~}v}x}yy{l}xxvuzo{{xx{z|~u~yiutyxrqvu||zw{{xxz|xz|yzm{~pzy~wxzqxwv}~}|mux}z~wy}}{|xs}z}~x{}~fkw~zzwt}vso{}||ow}x|sz{mqytw~tyy}~}y~|vyz}|}wQ||}~sq~y{~}~{x}{tz|}j|x|r~}u}zyyrr}v{w~{ww}{z|y~wxvu}y~|ou}x}vzzyut}|~yvwyz|wuy}~~zzzyrw}zy}Ss~|~f{u{v~zt|~my}ut}u{uzt{u|}{Yy~}{x~~{{hnn~ytt}}xyvs}hyx}~zxm{uz|{x~z|t{iw|ypv}zz||yy}zpzq~|v~|w}|~y|yyy||t~yy}}z~xttttzur~{|z}xzhxyqv}{|v{~|y}|~x{vyus~{}~yzz}z}l~y}zeu}}~}u{~zz~vz}|i~wz~{{}xw~o{~v`x{~|zx}v{n}rxy{~~~nw|y~wx|m~z}nzi}~uw}{q}y{y}|w}y}z~~x~~~|v}y}{{~}|~}i}~q|zvywy{lw}~|w|{|h~|{pum{y{z|~|}}~~{|}{}}{{~k{|z~|y{z}uz|{~~}zw|x~}wwy{uu|zz{ts}|v{}y}_xd}xx}}{q}mzw}w||wzyyq|}{y~{v{~p|||~yr|z~uxxu~{{}~z|xxy~|{p~tq~xq~w}zq|kuynvy~z{||}x}~uzq{}uu~yqpuy|v}~z{xtw}|~xxww{sx}f~~|{|r{}|z~}~~{w||}u|m||}}z|{xy}|~z~s|x}|utywxrwv|{{z}|||~nv{yw}zx|v}}|p|zvy|zu}}yz~o~|www||{|y||{y|}w|wwtn~|to~swy}}y}`r}y}v{i~{~m{s~|~w}|~~}~|yux}{{|}||}`}vx|t{s|}z}{}{w{x}{s|{z|}{x}}t}w{|y{uzz{x~z}z~w~zrzy}zy}}t{vwxx~w|k~~}zvrjvzjs{}|rxy{vwy~~y|w}}}x{|vxq|zx~xzt}}wqj~uptpz{z|pz}z{{}~i|||}}s}|ytx|om{qww{p{}j{|}~|u}wut|m}~~~y~yjo|~|ww}~y|w{m}mu|~~z~|yvyr\t~|x|{xyy|uzz|~~}wz{y}zv|u~{~|~y~}}|~}|vwsww}y||z~{z{v~~w{yr|}}z||}~v~vwjz|{x{~vywz|}{{w|u~n}~~y~qx{{tpv{{t{py|~||~{|r}zx}}u}xay|}|~{|z{}y~y||~~~v~~}w|mzxp|{z}}{}}{wzz|tysz{yu|w}r~{~~z}qxu|xt|q~||s|||{w|~}|z}}wyyu||}{z|w}o}}n}r~}xr}yt{zt}z~srqz}}zv{q~vu{}|}~zxwzxy~~}}s|~zyp~wp}w|{~yk{xt{x{{|y|x}v{tzisxu{{vz||}x}}{n{~ux~{}{{wz{xxxv}x|uw||}x|xyt{zr}wyvz}yu{zy~}rzyzt{t}~xz{}yux]wt~w{}zw}w{|}}u{~w{}}w}oqx{z{xy|tzywt~~||{{w~ty|z{s~ytwr~rzuv~}}|~|sp}{ytxuy{u||zc~v||vtxzs~{}~~y|x~ws}|yxx{|usz{}|yyy~wxwz{~{zpx|yv~{}{n{x}||wwuux||tv}~}~lyr|t}z{{nru}|}~s{wz|~y~{r}w|w{w|zyyns|{p}zzx|stzox}w{{{}}~ytyz~{x{ry}||jyx|qvu|x~tu{|y||}{zx}|xw{qyyzxwxt{y}~|{xy~{{uzo~{{t}u~}~z}~|~|zzvvxv}y{~u{|u~{r{|}vzs{s{}~z{|wx}}z{x||wvuzwzzz}t}y~v||}}z{}xz|~}}{q{v~~g~{ysy~}vz{}wz{}~|z~{tyztz}|xyxsr}y}~}~|~}}{ro{x}}zy|}zx|~xmx{{uswz{q||y~}|}y}|z|{{|}yy|}vxtz{wwy}t{yuvt~|{~~x{zwp|q{un~|z}}w}l{n|~~usw}}~zzwzwv}x}ov}{{~zzxo~yx||yzv~|zxwz||{zyz~}~}{qt|}y{~xz}zz||~|y}}yv~~xw|x~~ny{}hw}~x~x|zzw}}}hx}|sw}n~~|}w~{~x~~~z}}y|xx~}|}}}r}{xk|uzzz~}v~zz~w{o{{~y|{~}ywt|ny}}sv|}mz|uxo{t||rw{z{y~~s{{z~|w~puzz}y~}zy{vm}q~|{z|~{ju{{~|t~~m{{|~{yvt}|zs|}z{~}}}~s|~vwwouywtzwz|d{}{~{zy~|x~ow~zz{}}t|~|z||r||tvz}}x|yyu{||}z|yz}~r~wpwty~{}}z}{x{xwyrxy~|~}{}r|||}{w}z{y{ux}z{{r{}{~}wvuu{{wzz~|}zs{{|x{|z|{rv{xqj|{|wu~zyz|}{y|}~{w~xz~w}{|}|un}{zxxx|{|{wy~{}{}xzo{[~yx{{ykyzp}~yj{~}qr{zkz~jl}~rysyvv|u|trkzzw{wrwys}w{vvz~|v{tzwtvyzp|{uj~{zoyz~u|quz}mU~~pmu~zs~{zv6]wuv}|x}lffz}txz}bq~n|lyqy|}r|xt|y}}xy}sxilt}l{yrsvt}r|x~{}{{~}{~|{yyluqz}o|}{q~|lwzyl~|}kWsysvx|}wxv|[v||x|xz|hvt}qyrtp|utx{t~~{|wzz{tzwwm~zyuyyzyqzrywz{}{z}uyuxsh}~zzo|~zvxz{zsre~wvu|yu{~b~svvlzyq~~v|syuqgv|wsz|}vmxzuxyqw|~xvg}|vu|xm|tyv|{sy}z|ktu||w}vxp}r{z}ynyz}}vw{ny||zw}nz}ozyvww|o}o||zy||y{~w}~~}~}~z|y}{{yxtz|{y}}}|~}~{{w~||zy{~|z~|x|{{|r}up~vz~|sp}}xz~~~||z~~|{}{}{v|u||z|q~~{{yw}{z~||}|}|x}}}yxyzk}~~}~}}~tz~v||v{|{{x}|yx~x|}ez}}z~}{~y~|}wy{zw~|ysy~r~{}~u|v{y|yzz~~||z}x}~r{v|}}q}|z}}nx~zz~}x||u~~}x~x}}z}|sx{|t{zv|xv{{x}~}}{~~yu}z{w}w{zu~zxqw}{|wzu}|{|yx|}~tu{yt|w}{}~rwjo||y|z~r~p|{m}}|~yuu~y}|mzyyyz{ty{z}|v{w}zxvyz}ytqy{{sw{v|wzw{zuz}}{}|}~x{vy}|y~ssr{tywozty}|~n{}}xr~{~|{p|~zz}~xwvyzzps~~~|zy|{{|w|xs{|z~uy||~p~}ys}~~|~xz}q~~{pz}x||yn}zt|ov|}y}{~w~{v{x}y~qzy}zvzrvv~y|}||wzw}~uw~{vvzmw{vw|{xp~|{wox}{}}w{w|yr{z{}}v|}xt{~w}}y|w|un|}sz}|~z}uuz|ytzr|}|~{s{|z|yx|}uw{yqxzyvw|wzyyzu~y|}{}wsxtp{~v}lzxzus~{}z~{wu|{{}t~~}}w~r}}w|}zyn}zq}~{w{}{z{q|vv~y}twxyx{}}yyy|x~{oy||~s|uxqzz{{}t{{xv~{}}}{|x}twzyxv|p|~vz}xy{}yuw}x|~}{p~v|z|v{wwxzv|~u}~~rw}nxw~xz|{t~x|v}zx|{y|z}{x{uwt|v~wq{v~vv}us|{sn}}v|wryouy{w}yup{x~|s{z{~{~|jy|||xvx{uy{|z}zsv~}y|sy~x}r~v}|{{gr|nxsw{{}s}|}w}}~ruv|z|zw|~|~xwu~s{zy{y{zowy}t}yxzy{{w{y{~wty~w~xwzzq|xz}||w|{t|~z~}ppv{tz~|wxtyx|}x~y}u|~s~yzm|n~{}}|~}~}~vy{{l{t||~~}}k|wz~}u~|}|vxyyxpw{x~~z~|~w||tw~~y~||t~u}}|~~yzwx{z|tz}zr{{{yx}~mvy~p{yri}~zvmy}y~~{lz~~z}u|~}vvy|y||yyz{uw{~xqs|||}|~j}yr|xx}|{y~zu}zux{q~zx}}yy~u|~tx~o}~s}xons{{vzzyz{}}{x|w{qyw~v{x|}~ywu|{z|y|s|zyx~~}{}vutz}}~}{{q~w}~}}~~~uut~z{x{|{~~rpqz|z|zx{znqrz~zo|uz{}zs{|su~{}~y|{tyxpxu~x|{u{xx{{qy}~t|x~o|wta~|r~~v~{yrxw}{}|zz}y|yz}}~~}}v{vwy~}{z}{xzr{}ti}vz~{ww~~h{{|}zy}vr{kts||y{w|{|~y}~Tw|x}{|}||srw~~xxvw}otyy}~x|}f~~v}}z|~|y}s~~{w{zy}~u|}xfy~{}|~}x~~vo{{}s||{|zx{~}||{vix{{z~{~||xu|~x}~myu~zry|{zw{}}~|yzt|{y||{}wlxrs}xy|{vo{|}rn{ww{~|r}~|l~{jp||v||~x~{xyz|vz~|zy{m{|}~~~}rs}{yw}x~v{v}||{}~|{{}sv}~|n}yyxy~z{yt~u|}|p{{hzr|~z||~yt}yuzvzx|xu|p~z||x|zs}~~~{}Z}zyt{|}s}|r~r}x}uzy}yu}}w}xs~}zvu~~ot||{y~w~~}rjcw|}z~vvy}vzt}{yt}xzzx|puzxvx}~}w|}zuxbwv}x~r|~||vty~{wbvysz{x}xz}}y}{|zz|{|s}u||{|{z}wzy}w~z}|uxx}{|uxy~~uu~|}z}{z}uw|zyz{s|~j{|}znz\~{|typ~x}~zo~u}bvoot~uyux[|vz}{zi|zzz}qy~}l|zxspu}x}{~|||}cs~y}{r{uk}zs{lt~}~xgevstswz|}||~y~~|~tz~o{v{u||||zy|rs}y~hjryq|{~|{|~yyypyw~t}}zz}{~~vw{xzx|{z|wz~|zxz}|xt|xzzytx|k}szxry}yuvvx~z}w~i}~{|w{{{{|xvmv{t{xqyprvxqsx}ry{r}~zw{vyz|~|s}|yvz|~|zwyz{{w|u}}}xyx{x~y{r{z{k||}ky~{zw|~wr{x{}vqa{tx~yvrz|z~~vyw}j~{~~s||qvt{~yiz~}zx|y|zo}|zx{uyyk}x{{~y}z~yy|}wpuwzowqsu|~~v~s~|y|ypz|}w|vsx}woz|xxplvoz{y{p|}t|v~wx~u}xrzv{z|jzrty}wy{o{w{~p~o{y}z}r{~t{~~xvu}y|{|xq}v|{xsk{z{~}y{rvx~|ynj~~uuwwv|py}}u}u{{ozqy}yr|}~}}ut~|y}}uv|~l|{{xx}zj~s|y~y||wwv{~~v~v{bu~}{}}{|~ty}w~s{swyq}~y~z}ow}yw}vuzl|z}pt~oz~{mwzy}yy|~{uqy{}{}yz~ut}r~{}|wv}}v|{z{pp~txz|uv||zp~~zy|}k|}}vqxuv|zy}zn~o}x}{||x}~yoz{{}|x|}fzu}r{v}r|ywy|}z{w~i}|y}y{x|{}z{olsxy|}v}{}kwn}xvy}~w|izox{|ymrvy}}wxzyt}|}eu~ywwty}p}~~{i}zz}{}x}ox}xz~zuzzt{{u}{{yvr~zv~~|{z}y|}s~}}|~{{rx{}}}}t|{t{~}}uw|y|yh~w}zxxz~~{v}y~{ww}||}zzvrrytwz|}|ynvt~zxwyr~|~t||~rsw~}}z{{vzsp|vlv|}zxy{zy~zr}{~{x}}uz|wx{st{|{z~q{~wz}w|xzzzk{zz~ux{}y}ftzkyoo|zv}{}w|~}~z|zq{r|x{w|z}xzyyy}xzuvkzv{{s~wzrw|}z||o}{~qur|v{xmz|x{|vt~|ww{r|yzmwwqwx}||s{|}sx~|r~v~{x~{oww{z{|u{y{w|~x~z}}uxyv}~{}z|zy|m{}}z{{z{vux{yvuspm}wwyutk|w|wswt~{okwy|wy{tyr{ws|xt~{z||x|ww~u{}zz|yyrltw|xxsry|zuwnypzyzxvzr|vv{y_t}vy~~tyy|swx}u{{|~vs{vxyx{wo{}ywyu}k{{|y{{x~}mzwzww}}x{}uwpty{z}~w|v~{x}}s|zzbuu{w}}~{}nx{kz|~v~u}s|s~zwr{||x|~fy||qz{}}{x|z~y}{z~uy~{}zz{||z~{~qzvu}~rp|{u{z{{uwzyy~~oyv{x{yxt}~}|wy}x}||~{y}}pl~}zzz~wuw}x|x{p~}yzvu{y{x~xy}r|y|tu{o~}y|zh|v}u|yt}||zswv|vl~wvuxyy~uzv{|{}wy|xqvy~}{u~y{y~v{}P|}~vv|r}|}z|w{|z{xv~zxx~yu{u{`{zyz|lzv{}}|~s}~t{}~xmx}n}}{x~}}xu|v|{}]zyv~{|~|x~{~}y}}~xx}~vv{px|}y~}|yz{z{v~ouqsv|}}|vx|{{xzz~{yp~|xxzu||ut~~}}}}ztvu~{{z}|~q~xvw}zs|zwqw}}}}~}z|}ov||{|v{{p}u}yo~yzzyuy||xznuz|}}vy}~u||w~m}}x|}|}z}}{u~|vt|}{zz}{|}~}~{y~sxz}}z}}|~{}|||x~~~~}~yy~vz}z|yzxul~ww||zz}qz}w|w}r|v~~z|~{|y}q}~zzwy~nu|w~z~~z|}|vw}|{{{}o}y~y~|{n{u~{~ox}|}{kv~j|q~x}{wrz~v{qv~w|s{sr|izz||w}z|}{xj~}}uyz~~zuysyzvq{q~||~yxqztx}}y|z|ev~s}r}}|wwwy}z}wyy{p{{}z}~|~}|p|zxkq}wy~{|u{{xy|x}}}|w~}~ww~}yv{|}xfr|y~|||e|zw}zl|qxu|~uzzuuzpnry~{{yz{}s|{y~vw{xspx~}zn{}~|~}}z|~{xynsyx{|~zwrq~p{iyy|||{~m}|}x|||wwt~|yyx{q}|ytl{z|~vw}yoil}w{~}}|z||}v{}uvy}x{t|~~u|iw|s|}r~}}wwy|}|}y{x{y{~o|p~{|~}{xztt~}}nyu|zuww}{w{~w|xu}|x~~u~xx}}x{}{~wswtw|w}x~{w{|{p}y{}}{}|w~ow}v}u{~|~}|u|zo{{xr|~|zwkz{ys~zsu}t}}~}uqu{z{~{xxn|v}}zv|}|y{{}yz{~|{}{t~}xyz|~xz||{}~{uyw~|sv|~vrxy~uw}x|~~vxyzqwp}yxzv|}p~|~|}{}{v{{ywyz{{}~u}~zwx{{yzwryyu{w|~|}{ux}|v}u~||rzwx{{s~r~|s~~u~{}xwyz{|~zx{w|~|}yv}y}x~}|~}~|{{~x}u|{|~}zzyw{y{w}zz{{y~wxz}~|x~{xu~y}o|xx{}vu{{zxqm~~{~s{ul|rz|y||}yz||~xxszs{y}z|{z||ww}xu|y}}|{xrz|||wwz~}v}}t~z{}xzs~}v||~~{z~wqpy|}xo|zum{~u}zx{xx}wy|{y~wxwt}|vuw{~}~|}k|}y{zxxu}rwz~|~}{{~w|y~v|}|xz{zvq}z}z{x{~}xs|xv|vy|~{}y}twy|r||w}yzs{}|u~|~}uy||~|{zuzw~}xw{~v|xy~pvq{z~w|}zzw~u~{~~{|~}w}{v{pwyx{{w~{{z}w{|~ww}wz~}zc~{||}{u}yw~x{|zyqz|t~wyuxx}~|~zuv}z}}~w{sw~p{}}{xw{}y}u~}}j|~~{y~x~}{w|zx}zx{}|xz{r{zzzy}~{{}syzu|t~tv~~|}z{~uy}z{}z}zn{w||z|{lz}~|w~zx|zpv}yt}t}|~r~}{xxz}y~~uwzzw|~{t|zqy~xyuv}{z|{z||wy~r{~}{z~||xy}us|u|{w|srv{~v}}y||}~zz}yy~xzpp}y}y~w}{ry~|vemr}{xzx}yy|r~yu|z{y~}xyy|{|z~}{}z}|x~q~ufzls|u}{z}}ux{cwz}p}{y~|~x|z|x{ry|w~{{~ryz{v}}~~v{zp~{wu{zzzx~{{ys|z|x||||~y~|yzuz||z}wz}~|yzzzzty}}||{~}~|z|yw|z~}}~w{y{z~zy|{onx~wzvwx}||~}~|z~{uz||zxzzz{~z~{~}|~~x~y{}ty~~{|z}z|}umz|zyz~y{|}ryt}~u~}y~}~~{|~s}uyry~}u{y~{|y}|}{|}vqv}w~~~|t|wq~vzzy}||tx~www}{{{|{~y}z|}}w}zxy|~vx}u~~|}v}zy{x}w}{}|}yo{}}~z~sxwxr~t{}}u~v|z}}|~y~~|||y{zs|y|}z~}uv~zs|{s~pp}zx~|}{y}|~zz~x|}}w{||u{zw{z{xzyz}|~~x}~xx}|tv{~z{rwy~||z{}ywr|y|n}yywu~{{}}}{y~nswisyz}}{z|xz}}{||{}}}^|wy|}w|y|}z~||~w~y}t|z{~x~v|xy{zyyx}|~|z}}~|tv|xqy{xzq|m{}}{yvtcw}w}s{}|{}x}w|wut~}|x}wh~zz{|}rv{vu~{wq~u~}{}~v|zy~|}~{{}{xpy}pxz{t{y{{~x{yz|{}xqx}z}v{yt{s}~tz|~v~{|~}y|y{{}t{||wy}vy~v|{}}y}x|{zz~wzw{|~y}|x}v|y}uzywy~{mw~|yy~{}~y||}z~y}~{yz}~x~zz|zx~vvt~y|qz~z~yyyxzy}}tyyx~zz|zzr{~z}{{xuoyw|~}zy|}{yy{xy}{y~q}~xx~zvxxrd~xtwzw}y~|yo}}xz~|x}w~~|{~~sy~~~q}{ry~}|u|z~~zz~}~t{zz}w~~upxo{wwj~xv}||tx}w||~|y}zwu||~y~u~{~}{~~{}~w|~x|{}{~}tv}|z{y}vtz|ywuy}w}|z{wv~zu}x~zx{}~}{}y{v|}~~y}stut|~v|{w~~zyw{{||}t|y{~s|{}~w}xv~x}yru~}x~wyz~}zm}w}zy~|wy}}||}z{zz~}~y~~z~z~~~zzx~|yt~{}|w|}z|zx}s~y}u|}yz{o{{r{|}~{~w}yw}{|p|x~~||}xwd~~u}{}ywyy|wsx{x}zxz{xwyz~~tk|}|{wyxwu{~t}}r||zk|u{{~{w|rypt}s~uy|x|~zwtwu|s~y|{wzuv}|}tyw~|ororx}wzy}xyvx}uyzn~~zz~zz}~{}wmx}x~vy~qqr{}o~|y}rzu~vuvzt~}tv~sz~~yt~uuxo~s~znux|x~}~zl~}sxwzxw|t}tx~{qx{~w|{zu}|lwys||qou~|||}n{j|zuy|zqtqzv}{q{u~qxgxuor}|zzw~x~v~jyy~w}~kx{~zy~~}yzk}yxv}~}uw}uzy}wtpv|_}}tyqxzlz{yxr{rxx}s}~z{{}yz|}{}}t|~|t~|xs~~{vzzlt~|}~xvzvl|vuwxy|}z{r~tzy||{{}i~ke{}~zuzuqv{~}{~|z{|yvz{xy~}{|~zpvx|w}zs~|xz}yw|u{zw}{}{vxz|{|z{{u{t{|y}d`x}}~t~}{x}{{t~~}z~zx}z_i|~~|}lxh~~{vq{{zh{yzv|~t}z|~~y~|}uu}~|g~||x}{o{~v}|y~xy{u~y{|~ot|v~||wr|_w{|uz~{~}~|{|}zztt{ulwl}{{}~~zvcqz}zvz~z{}}zxx{z}|{}p{ezx~y|vxz{z|~~w|v{vz|{wty{}{vywt~~|~~|upx}yx}}|q~{|}y{v}w{vz~z}~}jvuz{|xxvw|~~|}|xqzxrtz~}~|{x|{xsy}}}~zzw}uuy{uz}v{{~xx~}z{x~}u{xut~x~~wp{p|f{}yzsw{||q||~z~~~{tw{}x|y~~~xx}tqo{yt}z{}{w{~}tw||y|wzw{~|{ey{{z}}tz{}yzr}u~x{~zwy}z~z{|z{w|}}xvxzzq~~~w}|y~|}z~y~z}|yzwt|}{|~zr{x{{{{i~w}~yz|w{r|z|w|~}w{}zy}}u~zzuzyz~y~{v~w|}~r|yu|{x{|{}w~yvuz{uw~{zx}vw|~w|v{uvy~xy{v{{tw~~t||rv}}zzv}{{zz{|~z}yz|qy}~}}|w}y~m|{s}xvwmj}|}}{opq{y}yt|l||ylt~{~p{|{zoz{tx|zy}ur|y|w}~zv~xt~z|n}vk|~txvz||}v|}|uvzmzz|v}yp~~~~qr{s}||}psx}z{{|}q|}|t|}|~{p~oz}zzx}~~|~~tpz|xuy|xx~}}v|}vzqsws~~{q{{zv~wrx}xy{h|w{u~y|{{zyzjw{~fpx|w|zw|{evpoy|}}k}u|kf}|x}x}x}||x}}z~u|y}}x{|v{y{{k}r}}|zg|x}{yy|~~tykw~|~~yzyr||ox{z}m{p}|w}dwz~|||tu|~zwttvyt~~{~|yvzzly}|xxy{~p{~z}zw|ys||x||z~~x}}~h~y{xy|zq~z~||{v|t{s|~}~h~xz}~|yy}xty{~~vtz}}}|tw|}}w}x{v|q{{}v~|zy~z{}}xu~|{pyyx|}r}z}t{{{zz{z||u~~t~v|pz}}{}wz}~~wxb{|}}|~y|yx~~y{{yv~yz|{z|}yq~}|z{}x~yw~z}~{z~zw}{w}{~~~{}}|w~zo{x|{z|{}}r{w{wyzz~|xy~~z|}|~~~{}{y||v|~d{{~yq}z}{~}z~v|{{~~q|{}w{~{u}~w{x||x|ot|z}pvwzx|zv|{t~}|{}y}txxo~|w~l{|~zp{~z}zw|c}y|x~vx{|xz|yvy{z|xwt{|xwt}~vx{~{y|xn|z~}~|}}z}|z~yyx{o~w}~ku~k~|z~x~~y|~y~{|~{zx}{yz{}yz{r|x{|{v{r}y{|{yzxww{u}y|}z{yw}|}{{~|{vn~|{svzz}zw{|r}|x|zxy{xyt|wyy|{yzvyzvy{||wyzz~{vzz|~v|{g}}pz|t|~zr~x|x~~xnprzzww}}{u|~w~zy~|v{|suv{}v}xxzyr|xzz||x~x~}u}svz{zz~}}{t~{~}{x~~|xv|ntxp}{pyvywu}y{~zwu{|||w~q{}cykzq|yv}u~}{x~zy|~q|{}~{wzu{~uv~y~{}wmxw{}}y}|uvumz|z|{z{{{w{r}{~xzq{|wy~{w}wt|~u}~zz|u}||z|z|}{|z~}z}n{wz}yw|}~zv{~|}|~}xx{yzz}~wxr~{y{{|}w|x}{qy{}zymy~{sytx{{u~uz~{z}v}{u{r{~{z|{}|}x{~}zyz}~~u}zwwr}}t~|zpl|wu{}rz}{t~|z~vx~y|}}||o}|}w|uy{x|x}zz~|x~zyy||~|||y|{{}}w{ywl|y{{~y{|vv{zo~w}~~d~zv{}{{t~zyt{|}~|v~}}xyp|rv~|z~zy~t}}yy}{yuzyyqu~w}x}|{{m~|}z{uy}~wu~ww{||x~xw{yu}pw{}{}wy|ow||uw~q~{vz|}y{|x~hv}lv}}y|~ou|vw{{|z{{|}}xz}yzgzyvyg{}ywzt|z|yw}~~}|{~}xxdv|~{|zw|{~{||yvtyz}{|s}~~~y~wzv|t}yr{}~t}xz}~u~}uo{}~{z}|~}qkz|{w|{}~x|}~z|~s}}u|z}z}wzwz|v}~~~}}z{y}y|yxv|{}|xyt{|}|}q}~x|}s}v|yzv~{}|vlz{{zy|}z~}~}zy~z~}x}{|~~}uz~vzxyoz}y{|}x|~~|{{{w{~|ly~|z~}v~||}u}{|zy|wxuxz~vq}~}}v}|{|z|yr~q|~}|xz~}vzt}|p|x~v|~zyz~|{{{{t~n}v~|{}|w{}|ulo|xn{z|nvyzw{~xxwt|}|}}xvzrxsy}zz{xuzyxz|{woyt}}~|qqz{|y{xy}~{z}~}ovuz}t}w~|}{y~z|z}{}px~w{|y~o|~}w~}z{z}wv{||}mw{}zy~wvu~z}}y{~pyy}w~}{|{}~|yoys|ov|p~z{}x}vw~~yv||rvz}|txysu|tzyzzy}~t~}|xk}|~z~wrw|z~oz~}{xv|{z}{||s{|}~r~~{|y|}|uyey}}s{s}yz|s}zvx}vt|z}q{{ws~x||zq{s~{z~}z{x}wzyzl{j}}wzz{~}zr~xvq{~|{y~}v|w}}}{}}{~}|z{wy~y{}p~}|{{}twx}{xqyy~|}}|zsz~~}y{}tzywz~pr~{y~}v~~{|r{{zt}|||yz|}|~y|}~u|syy|xrz}|{zz{x||z}yu}~}{yv{zx|{~|{~u~y}}wo~|{zv|{yvx}v}yz~u{xz{|}}}~{||~v~r~y{w{}y}lz~s|~{z|{y}ywyyv~|x{z{{|pz~{}}y{v~}||~zw|yz{y|yv|}|txwywtz}{wywwyz}v||x{u~yw}~o|t}{~xz{vswwx~{{}{}zy~|~sv~y{||z|o}zz~z{~v{}|~|x~{wxx~}vyw~|txz~v||yxt{|xxy]xvw{z~~u|~{uyv|~y{~qyx|~x|u||{t~}|zz}}|w}z~yw|z{}~y}|{|yz|z|||}}}}yxu}wy|~}|y~~}{~zt~sy{n|{z{z|{|}|yx~wzs}~|}}}t|yw{u||~|}{}||x|u{y|~{zwz{~{zyy}xyx{sv~z{~zx}zw~~}z{zv{~z{}{|}~~|}}}yxwt~xz~}|}z{{sz{w|}}}~}|}z}qzwvx}z~x~}~}}{}||y}xz{yxz}||y||yw}zw~}z|q~z|}t~}~~{{{y}{~}{~x|yxy|x~}}~zxuzqzx|}x|y}yxz|}}|xytyy}~vxyt{yw{|zz{wywwyyz}|~|z|}}}ryx~yvyx}yx{vwyvz}v~z{zxz~{x}{|~z{}|zzyt|}{x~lz}}v}~o{~x}z{z}zxyx}{t|ty{y~{~yz}w{{x}~yy{y}z||y}v|~|r~|||~h|}uz{v}|{}v{yxy}u|~|}z~zyyyx||{zx|}}v}|z|}}yx{{{zuy~}|v}ty}y|~z||}~{x}|{}~t~yz}wzy{}}|wxzz|}~wx~}||{s||w}~w{|uy{xy}z|to|}}}|}y~y}y~yw{zy~{{~x|}~t~~}x~s{}}v|}{z}w{y|}|{}{{{~|}~}|{|~qz}}}y}}vs}~{tyy~|z{yvzxutqy||w|z}}x{}qz|{z{~|~|xyzm|r~x~zwzu~vvy{pzs|w|}}}~u~{}|}~}~z|yu{x~z}}ruxxqv{{}~{x{|~{z}{|}{|~t|}{{z}xt}}y}}~}yz}{|xr|{x~z~}xc}urzxxx|s~zw~s`~v{w}}yky~r|ry]~y}yxz}w}islws~~}fj||~kxzvzq~x}~{tq~|wtu{kx|uzt|}~vwxr|v}zu|xij{o}x|xwr~zx|{{~x{[zzyur{{ty{y{}wz||~^|li|v~tw{xy~vWy|umw{ts}}z{}ypy~}n}wp{xlwi~}p~vu~}}vyxx{yyyuw}rq}o{~v~z}tzvvy~w{~s|vj}}yyt{Pvt~{uyvzzzt}{pdj~xzzttur~|iy~~~|}}xrgvse~zvydkcsl|gozs|||}~ws{xz|~l{xzjxxw{y~z{pwu~xz}|so}z|}~|}zyw}|r{}{y|r}wzy}{p~|zz|z{|xq|||x|}l{y|lt~}~{~yz~}tt~|t~vu}}{v|{z{t~~zy{r~w|wo~|y{~xvv|}v||rzz|~~}}w|{|xwsx~y{yz|||ww}tk~{}x~}z~y|~}s}z}}y{~}~x{}{sxvx~}{x~o|v{{s~x|qw{us~xy{}|}{y||{}|~|}|z~{x~}{y~}||wyzlxv{~{||~~|x{{sy}}~}~|uz}|yy}oyvy}xyz{w}}~t|y{|~z{u|zqqx{yz|y|{|~~}vv}w~wwp|r|xzy{~|{z|yy~|w{zwr~~wr|~zx}||}}|}|wk{z}w}z{{pyz}|}t{twy~p~}xr{||~y}~jwq{}t{to{w}~xn|vtz|x|}~{s~{|y|{{vt~t{zx{psnk{y{zww~}x|}}~xx}yw}yz{|vw|{yz{u|yu}v|ww||{u{{{zzw|zzzwxvz}z}|y}{|~xs~y~ymvirww|z{w}d|r{|zz~}}q}x|x~}{~{uvt}~{us{z|z{~wzq}y{zh~{zs}y|t{x{yt{~xtqw{b}_t}wrz|r|}wy|}~~{zz~{u|z{zszy~~vz~~~{v}}}i}{z|y{ex|zyz|u~~|z{}p~zv|wtvo{~u{ux~}~~|}|}~|z{}yqts{|~{|cypx~wxmx||}|zz}zqvyx||{yyvy||zz~{s|x|ygs{}}uyx|xz}|{z~~~vv{|zz{ypu~{{{|y}xsx||{{zz|y~~y~z}z|}~~|~zu|}ytx~wz}u{z}wz}u~zu}~wy~~|yww{||ztx}~wxzzz|}tw|{x{pwqwzyzv~}~}|r}}{}x}~{xz~yy}v|~|~xy{wv|~y}}}}x}{}t~zw}{|ytz|}{{t|qj|zwzs~{z~|z~~{y{}{|{p}{}y~wz{~|s|x}}|z~tuvz}xw}}v|ytyvtx}~~{vzv~|x|x}x{|}z}~~u{}pzz~sy{zy~s|r}{y~nz{z{}zwq{w|}~xy~}z~yxt|zw|yxxz}}w|}~{~yx~}{z~x}z{yz{}~||w~yxzzz}xxy|~zrzlvozw~vzu}{r{zyxz|}tz|{zzx|zzy|~}}vzpyw}{yw{~|{~y{{zrzv{z|~w}vu~{zqp|z||}}~}v}{{}zvz}{v{xs~|}v||xzw}~~wvx~||~|v}|~{vrzz}zyx~wqw~z|w{wz~~y}|z{vx}xw{|z{~x}{l|w}{~~|~~x|yzx}{r{zy|}|zs|vzwy|z~zzztyw{}||x}y{|~vz|yxzvzw{|~w{||z~{xx~x}x}~xyzvy~{{~||~x}~~|}{~{x}x}|wy{}z{q~xz||}s~{z~|yz|~y{z}w|s|xq{~uxz}vzqvt}vyvz|z|~z|||w}z~|{}q|yzyvgpo~|z{}xpwso}tm}qzxt{xy{{}~~zr~uut{~{~xo~z|z~py}ysww~r}}wz|}}u}}z~krwz}wyz}|{}utx~rz}{rs|x~y~qn|p}}xzexw{{{x{zzl}yy|~wuz~x|}wrh}zw~|{}|izx}~~z~z{zzy{}y}{rl{~}uv|||v~v|}yz|x{|xvv|zr}|q|x{z}yzw{y{{z}~p{w||{~zyzx|{zxum~|wqw~z}{|~|y~ywxy{~v{uk||t||}}n|yr{~zqo{}z}z}}y~s}||wsxvtol{}}{{t|rl}x{|w|x|z{wxuzszxwzz{uz~|{}||{{ywo}|y~~yz}~~wzyvx}~}}v{zvz{}zyx~v|yrtx{zs}}uu|z|}}{{z}wz}~|{v|xt}|}v{{z{|vt{{|vy}s~|y~|}z~y~~y}|z{zxz}ymy~x~luz~~{|}xzz~}uzsx}y}t}|~}~}|}y{|y{w|~{||~q|}~t|~~|~}{}|z}{q}~yzx}~x~tyw{}y{vt}}|{{~}}y{swzuw}|~wz|x|~~y{rz~u|zxpu{}ypst}z{|{xwy}||}xvh}vym{|v|{t~{}|zysz~wz~|}}zq~}y{}y|~}ks{\t}r{{v{}z|{ruz}|w}sw}~u~u~q{||zzyz{vzvzsrz~~{~nwzwzzx{yv|uwt~{|pyzux~|{vvzy}s|{y}zz}~y{yw}jwovzqv|}zt~}~|sv{s{~w|y}zuz{z~|x~{{yv{z{~}v~~}|wtu~~z~}}tzq}v{}}yr|}}~}{sl{{}}}qy}}}}}}{x~y{~jv|vu}{x{sy|z~|{vzxxx}|x}~zy{~zy|}}}|{}~x|v|||w~s}~u{{yz~|~|~g|||gx}}}||u{yjvur|xy}l|}o~n}}}z~z|r~~|u~y|{uuuxyzw~{~|}ztv{av~|}|ys}z|||~|}y}}xy{{y~}vl~{c||}}xu{r{~w{{zw{z}yuxsszuvusx}|{wx~yz~|~vwzqtxztw~yu|v|}}xxzyz|~~zzw}nu}w}z|}|zX}uxt{~x||u}pyx{{uw}~~|t~vuzzxy~s{yzyv~}ys{~~}ysz|sz{wz|}|z|~}u}{zztpw{ruu|s}w}|oy}{~w{|wx~{~hy|v|z}}|}|{yy}f~u~~zvz{||t~y{zvy|~qzu}zsvi|}yx{~yy|{{||t|wxzx{usyzuu~|v|~vu{qv{|wxzy{zy{}t{r~}xu}qrvyzxyu|zz~}{uwvk}~z~~}u{}z{{|e|v{uzywuw~w{|{|~pw|{}~{~|}x~x}~|}sy{zv|{yi}wz|o|ny}y}|v}t~{zw{z}xz{~zvmzz||}||}yxeovxp{u{zyv{tpzu|u|~r{|~~{|y|ox|{syz|zzv||zyk|zt}ytyw{y}{|vvz|x{{~~x{{yy}{x|~}y~z||{{v{yu{lu~}}~{}}~iw{p}x~y}~x|{}ezy}{zzzzxw{~|{|}~|zsw~}~~}yw~~~||{~~{v}{z{~~~w}}x|u|uy|y~x~~|{|{w||||w|}}|}|{yyz}{}|zxuz~}|~|}u~~zz}qv~p|y}}{~{~~||}~z~o|y|v|quqy~t{}{vuz|yzw}}|{z||{{~zt|ys~wwx{~z{w|b{{}|~|v~w|z~|v|qy}~~}x}zpzt}{|}||}~~~v||{~u|yv|z~~~sy{x{v~|}|}}u{~xwxz}v{~|z{}{|x~u|t}zy|t}}zzr|s}}w{}zxg~v~}|{y~{||{{yxwwt}}z|{~~lxt~xo}~|y|~|}|}x{vxzv}{{y~{z|}}xqw|yz}}uyvt{lvx{l}~}}}xz~{w|zyy}~wzxxnw{z|{otw~||y{q|{}tly{t~||}|}t|{}~~~uw~v}z{s|}ux{x}|~y}}}}}|}{{xtswxz||xy~y{}ywv|{uyp}~y|x~v~}}~w{}yy~tzxv~{{z{xv||~vzyz}}}~s~{s~~z}y|~wxv}y{vy~~y~u{}{}|}{|st~~~}nzzwl}~}q}|~uv{}{}~yo~|t|tyx{zy{}vu|z{{{{x}w{ovx}v}xs{qx||{|~{{u|~t~{|y~}{z~x|}~zy}{v~|yz{x~|w|w}{|z||}}yxyw~{y~|~||}vz{~z{w}{py}~l{~}}}xxx~|x||{z{y~}zpy{{xs|w~||yw|~}x~}|v|{yvxzyw~||{{}w~tyiu|{|~~s}wyy|ywy{{}z}|y|{y}~|~w}{}~xx|}z|x~uw{~|}{|~zy{{z{~}syt{~|~{}}w{{{|~t{}|yvy~}{~wzt{s{|y}|||z}v{~yy~uxsyx|y|{wx|}|u}|ryx}~}}u~~z}pq{w|{z|{z{|}~y}~z|yu|x~{~|}{}}p}}zz~vzys{s|{v{{x{{{sxu{{s~}|}r~y}wyu}|{q{uywy|x{yy{yxw{~py{||}{}}x|}t~{y|{{|vzw|}yyy|x{up~v~}zxu||z~}|~|z{zyu}~{yw}|xz||~{x{}t{xs{}yrxzx~wq|z|||{}}xs{{ysvxzv{v~pv{}{~z{|~v{wy~v~{zx~}v{~~x~|uvxw}tz|{v}wotz{z|tv{|o}u{}y|y~~yx|{xy}wz|zu{tv|x|z}{vz~{z{}zxs~wyyq|zv~wvwz}nxz~xu~~||{z{u|x~|{y~s}~~wr{~z~}u}wzwvt}}w~}|x{z|tx}y|u|s~zy}z}|uryv~}{}~|~y}y{uswyzz}zy}t}~yuv{y||vzzzv~{}~wxz{tuq}v}w||{x~|w{ux}{z{~yz|suwypu}w}w}wow~z~z~}{}~xxu}hy}}yzzwsw~zwx}zyz}y|{}zx|xy|qyzyz}wy{sx~||~y~y{zz~s{z~x}}}w|}zy{xy~{}z~{wzs}n|yqs{{}zr{sqxy{vx{{my|}{{|}}yko}z}wyzuqx|z~~y|xu{}|{{x|pqwpyz|{wd|x|t~|{_{yysosrhzu}xt}q||~{zzx~vyxtn}z~wm}|V}{}qy|x{|{{|y~}ywvv{{p|~}|}~{}v}zz~|~|{{zi}v}~xvu}yw{y|yvzozz}zn}|y~{u{uuzy~xyyo~u~z~zssy}yvu|x~{}t}z~~w{{{x{y}x|y|}~{~x}vz}|fy|sx}tp~}~}}zfxzt}uyzwuw~ws~zuv~v}{}~zy~||z|~u|{oxztu|~yrz{yu|~}z|}{|~w|yzyztr{|yqz~}yzs~~}x~x~zo{yzt}}uypxm{zwy{yx|l{|x~{t~}{zyvzy}x}w{w{}z|}wv|}zv}}yv~q~vu}z{wqx|wzy}rq~|zswl|||z{uv~}~}{w{|wxxu~||xzz{z{y~{w~||}n|vu||{|}|~}y{v{}s}vuv}v|rwy|{~|~{z~xt|~|{}|xy~|x}{}sy}}sy|z{xyz|}htwiwu~|{}s|t~{~{uz{uywvzzvz}xuy}x~{{yy}~{|}w}z~y{zz~}z{zzxu|q|uv}u}x{yxuyvs|{zs|||}|s{twvsyyzuw{~{~zyssuytxxtt`w|||{szwx}{|x|rwu{~xu|}{v}z~vryszx{}{{~||u{x~{}}{x|}~zrwyt{zwtwx~{wu}~~wxw}uquw~y~zw~w|v|sv{}{{z|}fxvy|y{x}wxv}}z|{w~syyz{rq}vv{u~y~lyhyz{|zxn{wxrqot}~v~{|{q}{vz}~mtr}~~{nz{{u~yrru||~|zn{zz|{{vztq~}}}rz{{vg~~xzv{yypu{~{}zw{y}{~wsz{ulzs~wxx{|{{u~{{|xw}}v|myzx}~|~|wv}|ozx~|}po}~~vvx~yqv{yy}|~|{w~vx~zs|zy~yx{qyz~|zyw}r}~}|w|s~z~ytz|{q{{~}~{|xs{xz{e|w{|}}}u}j{xs~{~{z{rzz|ut}{{{x{}v{}yys~~|x{z~{}~w{}|}~u{~{yx~z{{|~|ztwy}|{|zq{}wz{|utzy~~~~tx{|y}~x{xw~x}xz{k~|zz{yzv~~d|{{~}y|{x~}zzuy~{z~{z}yxxzyzz~~~|ow}{~~v~y}s{w{}~~ty{qzx||yxz}q{ys}wz|}|yz|~wwzx{~z}x~yy~y{zyy~}s}x}}~zutxl{wxz{tz{}~w{}|t}}r}}v}u~wt~uu}{yzx|}z}{zxzyxzo|z~~|wyzx{z}z~|x}}}|v{ew~}|y{~||x~w~~{}}}{vr{zy{}}~yv~{u|v|{{ypzyz}kvu}t{{|x}q~}pyyz~~}}}~|tyuwzz~zy{ry|}|y}}x\}|{{}}}z}z~{rwzw}|~z~|t|w}||~z}{rv}y}~|{lzx~|vv~z||}p~|kw{|~xt|y{m~{|x~{|x~}wyu}x{{|~|v}~{zuq||tx}x{rz~y{{}|{nz{zx}|~xk{|xz~~n|z{tpy{wxyrx~~|vz|yy|xw~yz~|}zt{|~yp{z{wyzwpx{}zz}zz~{}wzvuu}y|xsy~xv|}}z|{~z|}t|~}{x|z{|{zu}z~}}y{z~qtw~{~twyz|t}{{{{}}~vuxuqzsyrvhzx}z|{ux|y~{~||{y{~t|z{|~|||z|}z~|wx~~~z{~|s|t~~l~}|uz|r}}wu}~}~w}z}{x~}y~|ywywy}}zy{u{}u{|y|~oz}{xu}wx}~y}vxw|}}sy~x}q|r}z{uw{xuz{|ryvz{{{ql~|v{|}{}|tt{fl|xz~w~{}}}|y{}k|}vxk{{x{|}~vzwx~~x}|w{x{xvw}z~|zw~~zd{{~y|uz|y~}}ty{mzxrm~~|}zt~|x~{vvz|}xznw~~||x`ux{yx~}zxy}~z~~y|~tynwxyvtw{{txs~|wxu}|vvv{yp~z~{u||s|{z{{v~{x}}o{v|{{w{{x{||{y|w{~}tz|}~}~}vwsw}yrz|{z~y}rzy}rvz|~rwtxw|y~|z{t{|}zy}}{zvz|zw|z}}zz}~{~|y|}v~xv|~{~||r~xz~~|pt{xm~{~{{p}{{}}}s}{smx|}u{~zzt~{}~}|x|ztz|z|~|t}v}}v|xy{}r}}~u~]y}yuv{{xx||}|kxzw||}w}|yz}x|~y|x{~v|r~}wmz}zz}zy~y{hkg~xtxuwv{y}uz}z~xw{tsx|v||~yx|ywx|zyz~}z}zxutx|~~y{w~uu{|y}wv~yvzv~p}~|x~vx~ky~~z}~vll}|wz}w~}}ur|{|tztl~~zw|~tt{wvx|{ux{~w}vzy|z{}xy{{~zx{zz{wyyn{{~ywo|zwzw|vwv|~||wx^{z{sx}}{{y~{||u}z}{~{{yr{~zw}~{y|~zuxvwu{v{ly|yww}t~wyw}sy}x{~|x{{svwxm|{|z{{tt|xzvyxo{r~kl|{fyz~|{z|w}s{yu|}{y~x}w{{~{z}zc~{v|zi{u}r{|~kzv|~rqyyx~qzxz}~uvvy|yzIzwxzxy|y|x~uu~x{njv||{{qz{Z|~xw{~~xt}o}~z}v~~{||~~}}~|u|{{}~f}~|}{~}~quu|~xv|~ozzx}~y}{{u}}~z|}|yyy{~}|y|z{sxxn|z|~~y~~xs}}{z|~w~|}ryt}t|y|{v~{x{{{z~y~yx{zwt~t}|zwyy|tt|}ty~xxwy}t|w}}~}t||xz{{|||}}}w||ywv~z|{|z}{~{~~w{}|yyxwz~}wzzzuz}r}{yw|~y{z}zxt}t~}rx||y|}xz{~{|yzw}y{z}||~yuzyxyy~y}zy{z}y|r~|{yyyzz~~tz~z{{|}{}~~sl|~~|yz}zx~p~xp}s}x|z}~ox~|{y{zzsvtxq~yy|t~uuyty{v}~{x}yzzsyz}tx|{|z|u}~wx}{xt{}}y}qv{zz|}w~y{~vv{u{|~s}ook}y~v}~|x{}yxnwv}~uz{||~y~t~r~~{|w~w{~}y~ypy{z~}wv{~}s~o}}zw|xu}wx|wz{vwz}|yx~~}{|}xy~}u}~{}{{wu~~zzzz|xrx~~}yu||{wx}x|~z~yx}y}{|}|y~~|zw{~}y~v}|z}|{q~sz{u~~~|y|~yr||{{{z~}{z|ow~ys{t}}|~{z{~|~~|z{vy~yw{w}ry{q|~}~v~lxwzs{|}~~}{{~z~~~|xy{}ut|{~}~y|~~{~~}~zx|ys|}}yzux|x|{rzz~}||y|}|}~|v}s||w|}{z{}~}z|||x}{z~}}y}{uyxx}{~x}zzy|y|v|}}||xyup|xm||z~xxt|q|{z|zx{~z}}}{u|~y|~zxz{}}||yz{}}}}{yxox~~~|zx~w~}|~w{w}zx~}w}~}}u}}xyyw~w{}yzy|uwx~z}{u|ysr~~z~~z}y}|~z}~zt{x~~s}z~||~{~wz{z~v{}{n}y~z}|~}~ywwyywwxq{y}{wxy}~xwzz{~z||{{z|}~u}yu~|{ys}~}yq}vtz{w{w{v||}|{{s}}~~|}|y||~|{|}ysv}}u||z{|u{{{}z~wsyx~~|zx}{{w|u{}~~utxw{yswxsuswvzx{}z{zuy}z~yz~|}w~wv~~w|o~xzw}u|}zyw|wtvywo}{vu{z}}{w~{wvvz}z~n}wtu|w|~tpy|x{y|}l{~}{{~|}ww{v{{|{{y~w|}z{|w{}z~|}z~}|}yx{}pu{{|~jwn||t~zx~z}t{zkvu{|w~wzyy|usxzt|~u|znpzyz|yz}x|{{yv}xw{rvw}~r}y~bt{}s{~z|~||{}yz|~|zy{{{pu}zujvy|}|uk}}|x}q}ryyxz~t~x~u}yy}|~yyywz~}{}~lx}xzww{|~~~{~~|uuusg~jw|}vx{{}{z{}}|yy~|xx~w}zt|up~t||z}}ozyvwyv~xzx{kpo|u~|~~rw|~s~}xwz}}||vtv}{xuy}y~y}||~{~x|xtypw~|ox{||||{xvlz}wyktxp}r}}t}y|{}~{ws}w}z~{wu~~s||}{l||}}yrzxx}~|~pk{|~xp{v|zz~yzvu|||{yvu}|xx{s~~{{~~{}}tpwt}zy|}w{|z~x~}z{{z{|{t~u~{}uowt|x{}wzn~v~~zwz}~{z{|~wzz}y{{}xyrz~k~|}~|~t||~y}~{}vy}z{n~~x~v{}|~m}vz}{}|~s~}}z|zz}|}{tr{ty}~u~{~z|{zzyy}~wp~yp}uv{zx~su{zu{zol~z}s|u{~|w~rz~}}zq~{{y{m{u~zxyv~|~v}nsbx}yx}~{~u|zw}~xx~w}{z{s{}~z{z~y~|}|u}z~}{~x{m{z|~{}~~}|z~}tm~}t{wn~}z~}{zxprztxq~ryyuU{w||wxzy{ypx{x|{{||{|sz||y{ytyxz|z}u|~z{y{sx}p}~yx|z{q{v|v{z{|w}|uxwz|~xo|wxxxyj}zy}}}}o}wx|{~znq{}}{y~w|ux~{m~sz~x~~u|qv|~z|ztty{|~~yv~w||~y|uqu~z|ryqg|zo~w{{x}tpu{|p}~x|x~~j}w|~x}wyxzLz~yyyux~wx~{~|~v{ps}|{w}k~z{{|vxtqy|z~xz~{~}|n}}xw{|m~~yo}|~|tr~{xz~y|y~yo~|}z}zw}vy~z|{~{z~ywuzwxyyxy|tu{~{y{x~~{|}zy~{mfyy}x{ry}|xy}}oy{xu~}~rttvw{zvn||z~}}~}zww~}x~}|qt}|yqywv{}y{}x{vuvwxyw|ku}vwy}{zuq}ozouxx}|}}|}o{{{~wz{i|{tr|pv}}v~q~~y~x{zxw{zsxxwzxkxo}}uzzv}suwypu}y||l}|s~zx{}}tw}x~~{y{}}{tvzq~u{yq{}_wy}}|wxwru~ty|~z}l}~zv}z}xu|{~s|~||xowx|{}tx{r~||||zz}se}}{~qz~~~rxZ~}u|uz~zw{}|x{zq}ky~uzvttnxoju|{{|w}qu{sxx{uyszxzy}}w{~}{g{y~t~{}|zzzxx}|y}}{~}{v~}~|}u}{yy}{yx}v{{zvz}}{y~{|y|yu~zu~~|{w~~z|uzv}yz|~u{|v~x}~wzu~z~v{{|x{{xsr{{o}wx{{xz||}{~|y{|xw~{}~~~|~sx}|~zxy||ytz|~v||zyz{x{zt}~}~|y~zxz|~|}z{~zzyvz}|xxt|}yu{}vx}wzy|s|~~y}w~vr}}y}u||}}s~|}z~~||x}n{{z|y{|t||zv~tzyz~{z~~{{~|z|~~x|}~v~w{}z|~{|z{zzz}z|{}x}x}|}|~r{v}}|z||z{w{{yyr|x}ywy}|z|}~~|~{xtzy~z}~z}~|yw}y~}w~}sz{zs}rxrww|{vy}y~~}~mmx|vu|xuzu}}}|vxy|tzx~|v~x}}}zx|vm{h{|~yy~~~|y|z}x~wo|vr}yyz~~r|u|yy}v}x~qrz~{ynw~{}|zzhZ|r~zt|x~{|v{|~~u}vzz|nq~{{npxw{y{{~|ny{z}hv{z~xxy}s{|xr{eny}s{qv}v{|{t{vzw|x~}}~yz{xqy}y||{}qzv|pf{{{sv|vs~Vzt{t~|zzx}|~|p{}yt}{qz}tx}w~~}~yx~~}us{{uyv}z~jwy~zy{}zwptytwa{s{oxzo}xzzu}wu}|oyvwh|~}pz{|t|zvp{wz}yx{q|wzw~~x~twx}~|v~yz}|w}y}s|ytxy}w|}|{uz}x|{|}~~zrvx||z}}z~u|z}uz|{p{~{u}w{y~y~zyxx|xy{xw{}q~}o~ot{}~s}|wzyyyu~||~wx{|~{z}z||}y{~xzx}{}x}~{yxo|}y|}}}x|z{|x}~zvy~szw|v~~|~y}~{~{syvuzq|w|xyz|yyxu~~|||x|~}~||~||z~~x|}~~~x{{yy~xwx}||w{~tw}x{|z|y~x}}}yyv~zrx}~qvxv|~u~l{z~q}|~~us}}}{~yv{|~}}y{z|}~y|wz~|}~x~{yz}y}y}}{w{zr|}|vx{|z|}xxt~~x}}y{{m}~x}|x{vru~yz||~t}}{x~}rw~vyy}{}tv~sw~v~~}yu|x|dv}r{}n{v}}}|yx|r}s~ww{~{xp~|}p{{voyu{wy|x{x~~}tw{~|}{||w~{vz|}|}}{uy~v~x|}~z}}sv~{}}v~z}u|}{{g}{}z{{zxtvyz{u|tz|~w}xz{x}w}zzxw}~{{{|r}zyy~~{~vsuz||yv|~|}~yw{vq|~zz~|x{}}{zv~~{{wu{|{s{v}|{wyx|zyu}w{}zvy}vn|{}yt}tw~s}~sx|tww|wuz{xs~s~u|yy}{{|~|~}x{zyys}}{~y{}yuy}~|vxy~qzxzzw~hzx|z~z{t{z{x}xv|ww~}|y~~{zy}p}x{||{~~~x}}~{vz}{xx~y|zy}z|sz}~||xq~~xv|~wxxyr}{}~{w|~{}~t~|tw~{yv|u|}xzzvz}|{~|~hw}u{zsu}z~|}{vzz{~z{~{{z~twx~}t~|wxvTwyz}{}uxSy~x~r{w~}|vx|{~w|}{~}s`yzv}zx|w}~~y}~syz}v|zs|}tx|f}|~}{{|zzwz||pvy{{{w|v{{rouvt~}~zy}nv{|}yq~ww~|lzv}w}{}|~}tx{us{}}{yv|~wlzxg}vyi}~|ywxr}{{|sz~|izx~s~}|wyy|vg{z~u|v}{z{orv~~y{|~u|x}{v{~}{~}~uyvw~|~vz|w{|~~~~x}wu}}y~}zz~~v{||ntt~~v}}|z}|}|x~t~|y{z{y|}}|s}|}x|~v~{~y~{z{~w}f~wy~~w}wl||{}{v}}xz|uww{x}||u}~yw|{{yuv~x}~~}~s}zy|}|{x|y~|zt~~{z{w{wyso~|~z~zvy~}~|w{}t{~}{|~}|||}y~~y}xv|~~}}||z||}qz}}o|~}}vx{wz|}wxx|}x}||vz|}|yywszvzt|{{wyzd~vt~}zxy~wy||~{k~}z{}~}wq{~wzzy}z~zyux~{|}}w~py|{q{|w{{z}}~|{|xvs{~xz|}}~}|}|v||qvo|ut{}y}~~||t{z{y}||~xxu|w|{zsz~{zxp}}}u}{|z|z|}x~}~x~vt~w{|z{x{|{}z||||pxxl|{}~xy{uu|z~zx}{|{x}y~zy{vz{{~}~y|}v||zl}zxv|r|yyuzq}}x|yu~y}~{}}|mpz~yxo{~|}x~{{~~z{}}|x{|{~|yy{x|}~~}~~~w{|}z|z}{x{{|v|xvz}su~z}|}|{~||~|{~}|{zyx}}}||xw~}~|{y||x}{~w{~||x}{z|{|z|pz}w~}}yo{w|z{}{ztv|~~xw|x{||u~y{}}w{uwz~yu{x{}{~}{~|{}~zz|t{}xz|y~|y|{{~~}zqv~z{{{{z~yx|~z|{{||zuz{|}s}}n{z{~}sp{j|}}{}{||~oy~wt}~}m}{}yv|v}zy}|z|{{|yw~z{z{w}uuy|{||yz{~xy{}y~zzw~|||~}vz~}}}zw|{|xz||~yx{}}w~}z|{y|}t|y~{|}~|{}~}{}{~~o~}z~x|{z|}y}||wxw{|~}{t|v~~~|~x~x{{sx|x~|{{u{}{uzs~zyyzw{}~w~{|}{~|{z|wz}yv{~v}~vyw{||~|}|u}~{~z}yv{}w|w{}~{||{~zyoz{zy{w~|yzw{~wz|vz|}}w|u~}~}y~yym{}wx|zyz|wwwwuxy|}{|s|}w{ozwv|wzz{yyx~s{uyx}zqu|~j}y~ztwz}z}t}~wxzy}|{{y}y{~~}{sxt~uv~k~}}wzx|}{~wvty{~wwqtr|zvyzyx||~w~{~uz{~~{z{y}wyy{y||o~|soq~wkmy{{}}z{~mtz|{|z~w|~~zyv|z{~z~z}y}vm}r{z~|{xn{~~y{~o~}}}|}sxw}}x{|uzz~w|{uzyyzx}~v}vj}wyzw{}~x|r}r~z|z{v}y{~|}{zux~n|m{{zy~xv{yp~~s|}~{|~v~{~q}~yz{vsrxxzxzxqjzx~z|vp~zvk}|w|~q~{}}xy|wx~}rvhovz|{w}xn}{tk}|s|vt~}|}}z~y{}y|x|{~zz|wx||~|~y|vyot~}~~yz|}{}{w~{wsxvy|y{}}~t}~|yp{~xz~{|tx}yxz}}~u}~|}tz}}vv~vuz{zx|}xzxz|}}y~~~t{z|z|zz{w|{~~y|}}~|s{v{w}y}ww~xv{r~~}y{|zy|vxz|{zw~~y~y~}}|{~u|zz|~{}}}||zzx}|yzzv~t{|zzxwv{z~||}y~x~~|}y{x{v~zo~~z{{w}m}{s||t|}}}{zysxyzt{~|v}zw}z|~|zw{}z|wvv~}}x{||z}~|}~{y}r~~{xvz}yzy~~{w}}}y~|zy~wz{w{vz{wszwr}oysz~w}x|{z|vz~}zy{u|s~w~y{~{zxy~}x{z~w}{|x}y}y|~{z}}wzy}}{}~w}~{nuyyxx}zxuu}~}|{szvy~~wv~w|{u{~~x|xvxxx~yw{|~xsqz{}|w~~|~yy|zz}z|}x{y}up|oz|{~{z}~~zz~t~}x{xwy~~{{w{uf|}{}z}xzsz{||z}}sw|{s}zy|u{x}~t|{v{vt~|{}}}x~{ypy{t|rwwtz~s~}}z|{x|x|w{ts~~wuqu|kp}u}z~huzzzu~|s|z|r~}uz~}{}xvwq~{|yzw{{|{v}zzy|z}hyq}xx|suyx~{mx{|xz}}xuv}yz|vywxy~xz||}zxy}x{r}rv}|~}{~x}u|ww{}|}|~z~zwzz~|zz}{yx}~w~~{~zs|v~|x~~|~z~}~x~}}zz~wx|{{}vy}~|{{yzy~}zywwwz{}}{}z}v{{}z~}}y}~{x~z}}{y|~x|y{|z|}}z}|{yyy{~}z{~{xzp}t}~zx|}|u}ztxz{~}v{w{oy}}~zws{x~s~xxz|{vq{zz~y||}yw{~}y~w~{v~~}{~x{zz|~{w|{}}zuo|zzyyz~szxv}yy|}~}}z}{{y}xz~~}{~|ww~||z|}{tz|wzzyz~syyv~|zw~ryz|v|u{x{x~|}uv~z{~{|{zxo}||yut{t}x{}{uw{|{|u|y{~}y~~{xy}|v}~yw~y{w|vzu}}xyzx|yq}stwxp}v|wy|{|z|}|w{|tzvyxqz|z|x{{~}xwwxyxz~{}v|~z|x}vsz{~r|{~{t{wvw~z}}x}|}}|z||z{zvxq~{yv}}|zy~}||zqx|}~|}zx~t{}}z}{{|{v~y||v}y|}||tz{~~x}}{v~zu}}}{ywty{~y{}z}q~|vu~zyy{}}}xyw|w{}u~y||{r|}|{xyppy{|z}w~n~|xzzs|}|s}{|t~{yt|np{yx~|y~~qt~|xy||~}zy~|y~u}nz}u~{yw|{myzt~||{zwx~yxwx}|{{zzz|p|z}yyxq|{|x~|zzxw{v}r|{~}zxzs{t{zsv}z}}sy|}~{|y{||t|}~}}yzu{y{xyzz~}}x~pj~zwx|z{w~zwyz{~{|y~wwsy}|~zxz}|~~||w||z}t~|x|~~||~u|uxy|t}y~|u{{}izuw}y~m}uw}{~ys}{~p|zt~x}|xo}}{yvv||x}~|t|vzm~wy{y|~zyu~zy{|xw}||yv}~~}}|~|~}|zuvm~~}zxwx~yv{q{}~wv|tx|uuzuz|y{{~}|~tzx|~{{}z|ywxuysyzv~xw{{x~||}~{{xzw}~u|~||z~zz||~xp}|~xzs|}zyz{|{|z~~|z|}~y|y|{||}m}|~r}~}~x|z}~{}tz~w~wy~{zvs~{s}yx|~~}yz{ys|u~r{ywt}|}|~zus}x{~|{{vxtqxxo~~z|x}|uvy|}u|wqzts|z|}}||}zyy|x~z{{sxn|wy}|w~kvwt}wz{~}z|xqy~z}~z|{|{{zy|}}x~zz}|||zv~zz{y|wwz{}v~{~}{w{z{|zv}y~}op|}}x{|{x|~}yxz~w{w|{~u~x{}y}u}yx|yxszx|uv{|{}zx|zupu}}uyw|{}|x{~{~|q}|wwsz~|j|~}}~u}zxuu}wz}|yz}~{|ux}{}zuqxz{y~|zyzs~zy}z|x}}~}{|y~{y|~v{yz{w~zvy}vy|||||~zqy|r}|zt|tzss~zxx~zqyz~w~u~u~}~{~{~z|}|oxz{~zxzvz|}urz|z}}r}{|z{zzy{}z~~|}~}||xz~{|yt}|w}zq{{{~}~{~}{vzzlyzxv{|}|zuy}|}}~yzz}s|xz{w~z|v~z{}}x}}~yxyzz}x}}}wy}~wc~w{~}xpy||z||~~y~{r~z~ys{u~z|xy{}|tv}}uz~|~zuzy{y}|y}}~|~~|zy{}ww}xxzvyvtz~~{|x{|}|}{l~x}{xz~{~zxw~{}y|twv}|v}~}~yv~}w}vyyyw~}~|}ytwxz{~vz}}|uz~{|x|y}z{}~~pxyvx~{zz~{|x~{{yuu{}}~~~x{{{zvwwzzm~}|zz~|~xssw}~w~z{uu~|~{zw|}y~{~x~y|x|~vy~|}ny|}yyy}x~xx}~zrv|z~}{{{~|}zt|y~}}~}}e{xx~ux}zw|z~y}~~sz||{v{}~zyvlyw}|zx~}~z}}w~}}~{}wy|{w{w}}z~~|{~vw}{|z{o}~}zz~y}qv~y{w|xu||yy{~qy|}~y{ttzn~vu}~q{{zzyuwr~t~~}yy}y}z|u}y~|{}}|zx|}}yz}|z}owvx~v{{~{{}{~}z{z{{v}vy}~v~}{{~v|qu{~u}}ru~y|~v}{yt{x}{v|~|}yx{x{~wsz}vux~{pt}|~{w}~{z~}wx}x|u~rm|}xzvyx{~}wxxxv|x~{}py~rs{xyyo|n}xw~r{xw|zuy{}~}v{{}u~{}|v|zz~|t~|wvu~}}{}{z{|~vz~}y~}z~~{||sz}|zvs~}v|y{{}s~||y~}{u|r{x~z}wztvtw|}}x|{{{yw}}~|}yx{z~~yyus}|}{zx~zz~}{yy|x~}|x}{xzy|j~~{z{}r{}szyx~~z}r{z}|y}zz{~w|{~~{w~}x{~o}}~|r}|z~xyxx~~~y~{{|}z|lz~zzz|z|yk~|}wzz|}kv||~tvnw|}r{{|ryzxx~wux|z~|zy|~w}|}~~v~|{m~{xv}w~u|szn}xy|{t~w~vvzz|~{~pz~ss||~ytv|r{~}zu|r{}}~~z|}wz~u}{z}~|w}s||u}}vx}uz|~z~|x}}{o{~}|yr~w|z~~}vy}{z||}t{wx{y{yxyn|y}n}yw~}{~~w~y||z{~{z~s~}y|}ty|wz{{{{w|yu}|{zw~~z}~|v}}||xpysyz}{y}}s{~|r}y|{u}x}{|~yz{|zuyzr{}vy}~~}{~zr~}~~z{qs|z}~{~}|~w~~zxv}xyx{zu|}~y~|}}zw~yxr}}z~}}}{~}s|{{z~|z|rm~v|y{wy~{~~~{z}x{pz~x|~}zv|||zt{u|{z|}w{tx~x~~wz|w}uwz||{r~x}{zy}}{~ys}ws~}|{{||x}}u|vyw||m|m|{{z{~uy~r~}{yy~xw}{s{|~r{y|qv{xt{}w{w{y|t|{|{}~|yz{}z~}zy}r|u}z}|x||w}zmw}z}uw{{}zlw|{t}|p}w~~wrvxx}xz|~}}uwytu{~{x|{~|y|~t||||~{~txu}xyy~wyv}{z|{~z|y|}~z~zz~z}x|yyx~}w|y}t}wwzy|{v~~}uyz~{sw|t{yy|{}|xxyy|{}y~x{nwt}{}~{|{x}zyt{z}}xq|x|||}tvu|}u}x}vx{x|lz~{}}x|~w}{xz~}xyw|~}}s~wt|{rzxyu}~|xnw}v}~|w}~urx~v~x{wzvv~|z{z}{}}}s|~|zz}q}}}z|~{}x}|}}|}~~t|q~}}wur}xr~~xy}~w|wx|um{x|~x}wwv{}|v{z|qw}{}|{~yuvxz}~zxz~~uz|}{}~||zo~h~zs~w|}|t{z~zr|z~}x{|~y~Sxy~{|zmy|zsq{}usw|u|vyy}}}r{xow|z}{|}tw}z}vx{uzv~{xvyxzus}yy}~|}}yxy||~~y}w}~zuuvtyz}vl|zvw~zxpzs~|~}vm{{}{}tmy~y{vy{|yx{r|w|w~zz{vywxlxz~}tw}h~wizzos}}syv~}n|>v}wzxy|m|~z|yv^uz}r~yy|y|vp|y{w{}|x}~zz|w{ttx~||uyt|}{{y}}~kx~uzxzvz}v{}}tv}{u}}w|wv}{m{sm|}~}|tx~}q|tx~}x}zxz}xty{uvzr{7v}{||y~}x{}zvwx{}|xz|~{p|{y{x~~zw~{y||{x{{}|{{~}|~~{x{}|}}|wyz~~~x|~{kxw}|~|}|{y|{z||{~utz~x{u|xx||}}|v}{zz}{yz{}ru{y{~~~}}y}y{yxt}~~||}|}{{q{x|~~~|||q~w~|ww}z~|zuu}{~|oxxxzyxty|v}ry|v~wv{|}zt}}y|y{|}~x~~ux{|}x}}{zv}syx~y~z|~z{{y{~wu~w|{yxv}x}{zt~{}z}||}y|{{~yn}sr~}ysz|z|u}w~{vz|{zw{{}y~z{|{|z||{z~t{{~}x~}}~x}}{r}zx~x{y~x~~u}yv{y{~yt}v~w|y{}~}nwuy|xp{wv|y{x{yy~|{ueko~t}yt~{t}|sszy|{z}{xxsx~}wt|}mw}zf~q~}ykkyw||}szx{{x}{vz}|{t|uwwwzv{{krzuw~{wswyvxws{m~]rzqw{q}j{|{vxzx~g}v~vnz]n}}vmupzvzy~rs{|s{pzxvoypip}y~{p{zgr{}}y}q~rvtq||w|~{||smysus{w}t~x{xvlzuw~x{~|yz}t~zv}|x{ryty~~ztu~{zru||z}}y~\nxyzy{zuy}}xyw{y|yzz}sch{}h{az|swuyYn~}z{u~wutth}y|x}||_|w|xeuy\wuwwv{u~y|sGxry|n|}x{{p}~wKx~~wzubz|pu{|}|y}zwz{~z{x}}zw{z{}|{~y|v|zz}zz|xz{t|~~~|~~zz~y}|t|||y}}zzos|}s|~{uz~~~}x}~~{y{||zzt}|}zv{yu|||{}||~y{{zw~}~}~}}z{}{||}~x~y~{xx~||{~|{|||}{}|}|{|{zxzy|}}}s~|{}}|zz|wz|~~}w}~z{{{z}{|~z~v|~~||}w~~}|{{xwywvtyy||~||x~|{{y|{|w{z{|zz||xx|~~|v|y~~~z~||xz|z~y}x{}{ywyz}{|qzw{}z}{o{{}u}w~|}~|x~}|}s{{y|~|||v|}{|zzx}v{zw~rw~~{}v~|{}z|{wzw{u{xx}xv}t}vx{~}}}yx}{yys~y}y{}uxxy}|zuyr}r~}w{|t~{}wz~u|z~z|{{}~}~}x|zxsr{{zy}|||{xz~y}y}~}wz{|q{{y|}~~|{y||~tz~yz{}y}|v|n{zy~y~~~}~|x|}z|vu~x{|}tyx}{}~{y{z}x||zz}z{~~{xzs{y|{u{|t}{{wyu}x|yz~}~|}|{ww|}u|y}}|vzt}||}~~~|~{z{uq}w~{}~~}z~x~zx{u~z{yz}||}}|~}zx~~x{~~~~txzy{{~|z|{zz|~yx|z}|}wzw{||u{uz|~}uyx}wz|{tz|z}~w}}|u~}x|~}|{t{~||{z|}~u{zz}x~||}y~yv}zupu~f~~v}rw}yy|}yt|y{~zzwr|u}y}v{~|x~w~|~zsyq~|v~x|}|}}x|}~|xx{s}z{y}v|s~ov~||yw|~{|}}t{n{||y{sz|}}zut}q{|}z}qvxu|~s}p||zy}w|z~}zy~o}z|}~y{|x~{{y}u~}yl|~|}~x{z|xy|}owt{x|vw|~zp{~x}{u}{{|~~||x}~u|~{yxw{tvsyyt|{{z}y~{|}z|~ywyw{z~z||wsuxz~p|y{~~}~k}|x|vz|v{zz|vt{z}x~zu}y|wzz~~yz{xyyxglyu|~}ws}{}}|~}m|}}{z{rx{{zvz}~r|z|xwyu~wytz}}{~~}w~}}v~z|wy~}v{q}{|z{~{~xz|~y}||||~|~}z~}}rz{|~~w}{y|sy|r|}z~sz}}q|z{wrzx|z~vy{}v||}~~}{}z{y~z{|~~t}}}|{yx}}qws}}zz~}w~z|~yz}{rx{z{}}s~rz}q}y}|u{{{~~|{ypyw}|z}x|}}}z}z}s{{ty}|{||}}w||}|~vu|z|~{wzwm}{|ux}y||t~xyv~}w}y~~xz~{}{~}}}zyy~{{u{vv{~{}}{}z{~|vx{l}w~t~}}wzzv|t|z}{zy}w~|x}x}}yz~~yz{vv}quv|~z~}s{zzt{{v}zy|y}yv|zz~z~v~tzv~xz|~y}s~~sksz{uz|zz~w}z|~~{wu}~vyoy}||y~tyts}sy|{zwuz|y}zz}}~ny||~yz{}~{vy}vw{|yyz}z~|y{v{|~y~ypyvxy}{x{~uw{|x|}|~|v{|}my|~z{s}|yzw~|~}}||~zt~||y|}s{{~{~yxo~~}yz~x||v}{ztxz}~|z~{|}z{q||z}}}}x{}~}}urw|z~zvyp|vy}wy}zxy~m}|~z}{~{wvx}~}|q~}}~{{v}ruhz}~{}z{{w~oz}u|u|~zvy~q|v{y~mk{{|}zx}~~v}y{tuyzz}x}{}|y}{{|}vuw{|wyw~w~x}~|yp}~y{|o|~tz~}ypy{}}{w~x|{zy{sx}~x~}}{{~||ykyx{}wz}zw~||zw{w|pt|u}t{pxv~p~}}zwryp|y~|xuwx{|u{{}yx~||w{~vz{|yyzgxu}u~{~~{xx}yuztzx|x~urv|m|{y|tx}x||z~{u{vww{}~tuzy~uut~uyyrzz~z~|oq~wg~{wz|~x~~~}v~xw{{yz~uj|x~wy|t|~}}{u}~x}yv}{}uy{uv|ys}ev~}||zwwz~|q~~~uxz|uy}}~~~r{~|o}pny|tx|u|~|x}}|l|xzl|{x|xw}uy~}~{zwzk~q~u|svxm~~}s}wt|}|zh|~zz~tyv|y{~xy~z|z~{w{~{|~s{|}|v{~{x|~z~|u~x|w}}{}yys~{~{w}x~zt|uv|}~|vzyvzyy|x~}xw||{|~r}zy}}w{yzztz|z}}xz{~}}q}|~}|{v}r{{z}}}y~~|x}y{y}~yy}}~{y~{}~z{z~~}yw||y~{}zyny~w|}xww|v~}}|}z~{|}{}yw}yq{w~xzy{~zy|uzv}|}|yvu{z}}~|~w|u~{{vy|t||{{~}y{}ww|uy~}z{y|{~}z~{z|t}~yty~}~xz|~www~ux||{~u{|}w|{|xwzzpxzx~}~}||{y{{{}{w|t|||}zy~~y|wy~v{~~{z|zw}~x}}|{z~~{~zk{wu|~u~y~{}xw}o|~{wr}yptx~z~~~}{xu|~~|x{zy{q}x~{xx}|x}yz}}~sz|}p|}y~x}~zu|t~{~w|z}~y{w|y|zwz||u{yut{w}yy~w{~|twzot|}}uzwz|y}yx}|}r~}{zy|zvwz~~|~~x}}|l~v{~~~t}|x|v}zwuyyzuxv{d|}y~yy~~~}y{{uwyu}u~tyxp{}s{{~r~w{}{wyjsz}{y~ux{tw|}|z{}zuu~}}|}qz{zzx~yys}vvw}|~}y~~t~|twk~{{yxmzzyz{||}u}uoww|{{|{{||}o|wwxxtu|~z|{~z~yyx~}{|}|{ruix{~w~y~w~rty|yp|}}u~wu|rvzyyxzz|}sz~sxIn~xvx{s{{x}zr||y{t|zx|{ut{rx{}qy{|z{wyxz|zvz~vq~z{xygyw||}yrw}auzs~zzn{ywy{otz}uu~zv}q{mv{~s~yov}zsz~}z{zztt||}}nyv{v~v~w|mytwezvz~}~y|x~m{ypv~o~yht~w{c|{|~|u}}uy}{yu{xt|y}}yx}lsyz}y{~s{y}~Xz~zx{wqwzx|yz}rymwqzur~~~z~n|zy~mrg||}st~uwtuzxwz~yygzz|zyzxyz~nyvt{~qrzvu~ypuzxsqsyy|}{wxw~jtwws~}{{}~{y|s~wz}wt|qxxxz{~v{}~zxxx~|z|{wxyz}}{~w|zuz{y}|~{s~|w~y|x|{{t}|y}}~|}xy~w||{~ws_w|{wwv{y{}~~|z}|z~}{zx}}}r}{r{u|ywx}|~zx~y|}~z}v}|yu}{|~~}{~x}}z~x{||v{}x|~}jt|xux{z}}~}l|zzhzx{y}|{z~z}|~{}w|}|{wu}xwz~zyy}py|~y|||~z}u|}|t{x}vz}|}{ur|u~yw}{xyzxxy||~~|zxyyz}{xxy}v|yzwyyqu|~{y~zxyz{tvxvws}|zyzv|hzx|{u|~yxz{|yy}|q~x}w}}yu{w}y}|}{~{g|}w}{vvxyzywzprr{~p}{zw~~zpwx~wv{{}}|pqxu{r||wx}vb|q|xwzzwo}}y|{}w~wxvz}ub|qwruw{p_|w~{y~vxy~z~ux{r}|m|u~vzmxv|xwv~xw}x|~uu~ls}uuu|uwt}w{|t|dvv|onxovw}|yw~xw~}xty~}t|}w}zu|wo{in|}m~kazzvr|pwwyy{zwr}y}zmwy{|q~|t~y~|s}xtxm{z}zqmw}ywuq{{ywzyx~}{u}yuzc{x{{x~xq~}w~~zs{|n~s{zx~~}|}|{~xw~~vv|xw}~{w{|yv}zwgz~xzz}t~p|u{}|y|vu{rt~{y{|~|{|j~lrw~vvy~|z{s~zx}{x}~}w}qvi}v~~w~yz}}y|}|{{r}~~u}w|x~uty}|v~|~~}zp|y}~zv|{zxzzz|~{~t|~}}pp}}~||y~vzox~{u}}z}{t}zz{u{~||zyy~z}xn~y|x~~y||z~x||x|w}|~x~~xyy|{~yz~{z}{}~j{}}~v|}}}}v}~z{}}|~{yzqqy~{z~~~{~z{y|}}y}t{y~{y{}wy|z}w{||}{||v||u{{~tw{~{zx~{zsz~{zw{}yyz|{vz}u~{x}z|~x|z|f~}||~|~~}~~{|~}||~uqt|}{~|}x}w{ytj~~{~|~u{|vlyt|vy}~~{{u|t}v~}zx{r{|z|qyw}yy|z~yz~w{~{|}vzu|}twz}}}}{~x~vzpv~~}}|~w~~twz|}y{s{}vyv{rkvxy|~}~zs~~l~~x}v~|w{t{w~~{{~y}{vs||xzq~r}zv|{~t{z}|ktw}}|zyuz{}uy|zz}j|}yy|{tt~~yxw|x}v}zqyv}y|a}ts|wxq|{ry|jt~u}~qy|vwxl~~r~vx|ur|{{xrz}|}x||||~jy~nvk{v{sltz|y~yxv~vsu}~~rypz~pr}t{}ww|~yz}u~u{j}v|{|}t|{}y}xn~x}~||xv}zzzxtv~~|z|{lz{}lvxyys|wu{zi|x||~~|l{z|uv|xxu}z{}zvw~ug{z}|v|z|w{xuy}om}yzkyZs|vxyzxvv|uz~z~yufzw}}uz}yu|||zyx~{yrk||xyt}s~}x{{uxwyyuvv~vuvjnx}}vuf}y{wzs}||zxkx}zww|yyzgg{x}wytpzs|}~y|{oqxz}y{u{~}~vvzv}{s{u~szr}|zww{z~~w{yl|z}vvtxzmwwqwzzsu~w||}y~}us|yvdo}wwy}su~~v{zuo~y~|z~|~uzk[zt|rw{zw~zpzxz~sx}u}ytyq}rrwmw{z|u{wuy~j}vsvua{szq}}x{s|z{ww~k~~}~}s{~xxzp||dqzrz|sydu{rpuswzqy{}zsyzysy|j{~wv{yvy|s{|um}xs}|n{~w{}~q}zxwzu}p}zix{tp}vxu}}}ywz}yy~{utxz~vw}uw}{{||x}~zz{{x}nu|w}w}rlx}t}v}w~u{~x{}z~~{s}~t|~vr}v|rua~|py~{yxy}z|yyz{{y|x{xwz|}z{xzz~ut{yxxtz|v}u{p~zzz~tx}~}yz{{|}yrrxs~r~o}}}}zz~tr{x{{zu~zrq{yu{wit~v|~{}tvzyyzuu|{}|}y{~u{lwxu}}{|ulpw|~u}putyyz{z}v~z|{w}{|xyy}~zwzzzyz~y}}y|w}u~{|~{wj}x}}|xvvw}{~|su{x{x}v{zusyuz{{{|z}}{~y|~rv~}~w|y~z|}rxxu{{|xyyzz{}|zty{{b||~s}wuxxzypv{zv~pxv~~~~}z{z{|~ry{}|z|{~y}yz{}yz}}|wu~z}{ywy|u~|~{}}~}y~||wz}n{|v}{{s{tyy|}{||~y}x||z}{}xtr~|vq{}z~w|w{w{|}yos||{~yyyy||uu}z{uy~x|o{|{y{|{}}|~x}{v}{z~{~|zz}~~~}~r}~{|}y}{t~{ulx~z~z~zzy}zs}x{vw}}z}vv}~}~yw}|zt{z{xvz||~}|{~}}y}|x~}~|w||||}wx}|~||z~v}}~||}y|t}}|zywy|{x}{u{z}}|zznn}}{{}z{zxxouzzz}ww|{y|yx|~|||xtzzwzt{{sy|y~z}~~y{~}lx}z~p|s||}z}w}{|zw}||~z}|vo|{szxx{~}s|nyw|z{vtw|{}~{{|wzxx}{u~~{ty|wzu~zvy~}vuyy{s||||xxy|~||s|{t]z|xztvz{{v~{t{{}}|{yt|gzw}z|p}x{uzy|}{yvzv~|~x}|v{xsy{}{|v~syxw|y}z{xu{t~zvr{~yy}ly|z{{|}~~|y}|jv{~~x|{uyzu|}{hrx}||w}}|}y|u~muz{zyv{yu}~t~}z~uu{t~y}}q{mux|s{|x~|~~ww{zoq~}|z|znvx{r~sywo|ctwwi|w|}zxp}{y{zz|zutz{q~w}ynyxoyry~r}{v{w~{p{vw}{|}oxz~w~{|~}}|vp{~~v|s{{sy~w{uu~z{}|t|}~~zx|{v~wz}yv}~}{||t{ytw{z{}{~|u~{}y|z~{}p|}{{x|pt}zy}yw|}{|t}~}{z{~~xw~xs~~zz}xz~w~x}|ys}~rwz}xvz~v}y{}}w~wws}zy}|~{|u}}v}|{v~s~|}~~|~zz{u|w~z{y~pxs}~l}vws{|zyw~}x{}|~zxz{x{}|xx}v}||x{sv~v{}|||x~zs{xq{|zw~}~vv}}p}o~y}|}|zz{|w}~{{p}uz}|||~y{w|w~}u~v{|{{{z{vsyp{z{||{{{z{zx}}|wyx{{{u~{yyz|z~{x{zz~|z}~}}t~{w{~zy|z}wwzwxsz|l~~{v{{zn{vr~~w{{yx|wzvv{v~y~ux~u~||{ox}z}|w~~~r~y||{xz{}rwky}z~~|uy|}du~z~oaw}z|w|}m~yq}x{yy~{~y{~vwuyzq{q~}||xwt|y}xyyvzzl~||{wvz{y}{x|vz|{qx~}|y~~{xyxsymyux{z|q{~wpzu{~w{{~{t}}|~t|wsvz{~|yrv|~}zz{}p{zz~u{y}|z|y~xwxo~tyu{y}zr|zvy{{}z}~{z{}~rzu~{y|yxwyvwz}zyzx}}y|vzvyz~kyvyx|otzn|w|~~{}{{z|t~{}}xx|v~yv|y}x}y~~{~~xt}{|{x}h~}}{|y~||zxp}~ry{xz{n|z{x~wy}}||z|}zzwr}{xzz~{ui]xpwx}~{~zyz}z~vz}i~~x~z~{~yokx}~zxv|r{yytwxx}p{|v~w~yw~zy||~}yw}{~}zt}{y}{ytwg~y{{{xz~z}||{~rqzlz}yw}zzyy|tuw|q}uz~~~|{{{}~|}~|tq{~|zz|~t~{z|o|}~}y~u{_~}}|izusfxxyx~v~{|~u|z|yzw}z~zkzz~{~~|{zn|x{{t~y{}tsppr~r~{zk~|~xtxy}wyo|{}|rvzz}cvq~}w|}ywz|zxz}~}y{|py~w|{~}~|rsu}z|{yz|{~{|}ypzz~xx}|xx}}mzx~v|{xu{~w{xzxy|~|vu~}|kwt{hu|zq~|ur~vy}|x|{}{{u{|sxu{xzvzy}xtyw~w}tryz{w~||yw{zxoty{{w}{|}p~}j~w|xs}v}u~zxrzvwytvr{kzu|~||}yr}x~u|m|}~u~~uyxu~~zv}{{~{u}vxt|{yy{my~qy{yvu{w~~~w~~zv{x|{uxyxxx~||{}|z||y}||~|{~qxt|wz|v{|x}r}{zmy|t}whu|y}wx|tzvz~smv~|zv}vy}~{f~{~zy{r~}|{u{}wy{z~w|t~{|wy{~}x{zqqt{y}~g}~}x|}~{u|wv|yys}~|xs|wy}on|}xxv{|}}xvwx|v{ty~|}~|jvyjrnv~}o|xy}owzzzt}uy}u{{}tr}~{{x~||xw|z|~wz~~}{t{|u|z||~y}|uw{xvxxm~xp{{sz~zyz~py}~uzzvv}~x~z|zox}x|u{}}xyxqnv{}{{z{uwvyzt}|zzzl|}x|youmwywv~v~{|xwr}~y|utx}xy~s|ycrv~yuv{yvm{x~wzyxzk~x~{ynvzxqv{{v~}{||}yrswun|w]t{zyzxmku~zu~s{|xw~u|d~xx}x}y~d|}}uvr}p}ys}r~{rvxou}}|xtu{txnmrw||~v~zw{zzssptw|{uy}~|}q~u|ysr}gm{y{x{z|vy|}|z{}xu}{yzs|~|||t}~~}w}z}|}z{zyrz~}||z}{z}~~x{}~|||{|{|{~|~{wz|zy}}z|~{}{u~{}{}wz{}x|xzy~{w{}|t|zy||yy}}{t}w{}szt|}yx~xy~{|{xu~zyu~}w{u|yy||}|}}sxx|xt|x{pr|~}{y~v{v~ws|x}xz~wv~~y~}}}wx|~u~~vsy~{|}z}}|yn~tu}~yr{x}y}{{y~}||{w~|y~}~zy~x}y}|x}|~|~{{x{~|~x~vzy{ssuw~z}m}~}x|}xz|}{y~{zyvwyz{uyvyzx|~zy|l{|}w|y~{}zx~z|wz{vz{v|y|x~~uyy|{vx~e~~|}{wy~uy}{}zzt}~~ww~fw{|~~~}y{vg{~wz{}}}}}}{zr}z~}~s}{~x}z|zxx~|xry|p}o}{z~~w~|m}~{yy~|u|yzt|swwl|~~|qszz|}|wzx{zn{|vxu|||~|y|}{}}~|}x~q~z{{}}||r}||x}~~{|ywu}v}y||~{s~tu~p{~z~~}}}}|}}|~z|z~t||}}}yu|}j~xwz~z|}|~y|wq{{w{~{~z|~xz~y}~yxz~{t|~zy{||}zy||yts|y{pzw~}~zyzx|~x{x}{}v{||z{}}zs}~r|~y{s|wow}|||{{zvzz~}{yr{~zu{xzyxw|xwvy|x|x~||zy~tyt~}{uuyu}|{xqzf{}wzzz||y{|x~~w{q{z}{}t|}zxw}~wv}|uw}l}}{y{xr~}}{|{~zx~vx~~wu{sy}uwup||uyzyw|~xn|v~zx|x~|{y}}~xy{x{yxz}yus|z~}vz|wzr}{y|{|~~|tyvurz|~}}syzts~zyz{{s|vxzxxwwzw{su|}t|x{}py|~}xz|xuy~~v{{zw|}{vwyxvzw~yzs}~tp~~u|y{yzusswz|}ztx}z~ux{}~uvx|yytp}uvyzw~~uzw|{o}}y{x~||v~tyyqy}ww~}ymxzuy|rzwz|zz|zx}tzsv~tz}|{zx}~ut{~||z~yzqxw|ox|{}wrykv~z~zyl}}wzyw~xzv~~~ryt}}xy}z{~}}}x|zz~{~}zuxzzx{~z~elyttxyzvt~c{|vvtx|~{yy|}y}ux[p`~{v~gx{}z}xl{wzgyx}{uy}||{~x}p|z|~jw{{{nu|ut|}~~gyyxr}xq|zzz|{y~|j||q|}yslwpzu{{nw|v||ry{}{||}}v~~u}|xx}|z|xz|{v~y}|zx{~zv~wsqxw|y{}z{yx{q}y|{yrk{w|xzRxfyvp|Vy}p}k}v}}y}xoxy}}pox{k||yy~}{|~}{qy}}~~zvwzyyz{rz}x||sw}|||s{xzz}u||s}m~xtt}}|~u~|yw~|u~yxl|w~z}trx~w}ywoz~}~xyy{w|~{~zzzv{usrkv||{u}r{s|w|qs~z}{zzz~v~{zr|~{qyo|{v|~|{vvxu{}|nsy{|z{{zxy{|s{u}u{uwx|{}|{y}~xt}|~{|~|{zz}r|s~z}w|}ys|yzzso|}~{{zu|w}}{{xx}}qytx|{t~~~x{{zy}|}}}yx}|su{|jwz}wv~~u~w{{|y{t}vrws|{x|u{|||}vy{|}wszxzp~}|~zvixq~zovp||zv}nsw}{zwx{x|t|zx|zzys|t}xxt~uzy{xy}x{z}zv~~xwv|yxt|~||}}xpw~|~ny|~zz|}{}x{|xw{~{yy{z{zysx}fxzuxw}~vz}{{|{r|{~wz}~x~{}uzq||vw~|rhvyu|xyz{|}wstvz~}u~zmzwxx|xw{wzo~zw}{x~n}|xvvxxy}wq~{|y}vy}{wx}zx}vvvyyyw^~~py}~{~y{y}~}}yz}x{hfy~x||xru{{jxly|||x}~{{x{~zy~t|w}~xuzyzwz}rzu~v~wu||~~}g}~{|{wzuo{{{v{x}}~}{s~xyw~xw~{vtz~~z|u}z}rnvr~{g~pp~t{~}z~lzy~x{|{z{x~ouw|t|zwywr{}z{|y|xww|xyy|s|z}zu{yv}{sv}{ys}|~y|~yr|lxwxx}txz}xzz}yzz{~{z|~}z~w|}z{{~}yx|}}|{}{|~y|x~y}{}{{w{|xzpv}m}s{~y~{}{||xv|||w{u}~|yxv|yvzz|xo|y|}n}yv}twt}szz~|~xqw||{{}u{yy|vu{v{zz}sx~z|l|yzy{w}u}{t}|z}t}}yy~x}}rxy}gz}|~{|x}{uzu~x~~xz~xys}x~~~ytz~x|yrzzw|{{{|~spw{szw}}zvxtxun~{v~~xzyzzz{|zz}xx{yx{||uzvx~y|gu{{x~|~{~tv{~}stz~usw}x|v}|xz|z}{~x~|x~qv{zzy~}~v}xuz}{{||_{w||zz~yyozt}{{}y~~~zo|xyzpeu|tztvqz|x~zrv{z||d}~~xw{~~{v}}s~ywwu}zxp||}z|y{w|yvy}|yz|}{vyvmwyxvtr~w||{nx{||v{xv{~vvi|zu}{vy~|z{z~}{l~{yx}wwsvz{|zu~v||z~w~{}w{yr}urt{{w{uxvy{srs|yt}}uw|xz|yw|~s~}}wwmy|{wvyxux}zr|~zwvzzy{oq{r}uz~orr~w|~~{zzv~~~x|~g}|u|}{m~{w~{~|}u~zs{zx~xz~{ws~zv|~||{z}{~tq~sy}|zyx|v{|~{~v}}{{{{zumww|v|v~|fsxrx}y}vyyr{s|wvx}t{~zx|{ux~v~~zzv{x|~pznzsovyu|x{o~{z{u}zz||iz{{wxz~rx}z{ut}{x}{{|qryyx|~y~}vw~{{zzy{y{}||yx{n|~x|xz~|}|{vu|mxy{yzxzx{~{|~ywzy~y{w{~xz|}|m~{}|w{x~}yx|}}}|w}p~{{u|{{||xyt~~}{}~y~|}{||}s|~zy{zvxy}}w}|tvt}}||z}zt~}y||z~x~}rt~y{~sy|xv}zvxyws~~}~wuu{~s~|||||~{~~{~zuzu~y{|}}wz{z||~w}||{~|~z{{|y|uyy~zt||r{y|}z~wwzvttv~||{xzw|pu~~xwz|{}wy{{s~x~|y{}}}ywt|{}|z}ts~x{|xx|}{~}z}~w~w{yz~~zw~{~|z}}v~gywvxwroz}|v|~nzysyx|~q|}z~nr||}}yv~zszxjq}}v{|uzsxvx|syvzx}}zw{{}~xxm|tuxk}}{z|wy|~}uyzu|twq|qyz}yyzyr|}t}xxz{}~yxvz{~{xy}w}zyw|su~_xkwsv{wx}{wm{|}z~r|ztvf|}y{}||st~alwo}k~u{}zjwuzzooxth}}yzx~{{z|lsyxvmt}z{{uw~~{zvy}uu{mq|y{~rot}~ztxz||yc}{mpy~s}}|qp|{o|||auzy||{}zzz~s{szzzlzw}|~t{vvwzyovxuxw{qxy~y|~}w}u}~|{}xw~}z{s{yv~{{mzv||~y|r||r|x}}x~}}{~m}|{~}zz~zty~|~{s~vzwwzyt}|}{{{~}|zsy{m~z{w~}x}||w~u}{}~~{|{|{zt}{t}|vz|}{|x~|~{rw~~~y~|~|{y~~{|z}{}z|}zy|}z~yxsz~}y}~u~}{|u{{yzut|}ztx~{}}xuz~}}~||}~~}~}z~w~x}q|~x~yq{y{}}||}~zyv}~y}}xx|z{yl{rv}z||r}{{~u~}}yv}{{{u~}||}w~xww|z~n~z{~}}uw|}y}}m}~u{~}~vpz{zzzzvwzq}x}{}~vuzyy}{||}}}zz}z|x||yy|z~|{||ywmx}~{z{~~~}q~|k}wq{~z|x~u}z~w}x~wv~z}~{xry~o|uxt|~~ts|yx~}t{zz|{kz~}t~{z|r|yz{~yu{}|x{x}{{{yxy|w||yy{|svut{uszuw}y}w|~y~y|yz~}t~twv}w{~{|zwzyw|}yz{~~~xx~~~}~~{{zyv}zr{rx}x~x|}zs}|~zpz~|~}}~~yxq}uz~rz~{w|xz}}v|v}z}|{}{zyv|{|~{}~~y~}sxw{{~{xz|v}yy{}~{yx{zyuy{}|~||}zru|}}y{}x}||}{znyyyr{||}|w~y}x}yz|yy}~z}|xv}t{xzu|qzy}xz{}x}{|y}xusy}}}y|xv}z|~}{~|y{{x|{zl~|yvxv{y{}|xyh~|x{{{z{w{~y|}}{su}z}}~~|~|~}yts~w{xt}~~}y|w|}{~{xw||yzz{zv}xyyq}~{s~|}||{}~}{sw|w|z{~yz}xys~w}~y{|}}|}r}}~z|zz|{{}|{}o|zsz}~{{x{qwtyyz{}v}~{X}{~~~{zy~}~zzzz|wxz~}znnvpu}|}v~}{~}z~~yz|y|~}y}|sw}y|{~z|x|z{v{usvq|l}|tvzirtz|x|vxs||}~}|zxx}xvg|zz~z|~qty|ys~z{|y~{z~}}~y}v}y}}vwy}{z~zvp{~y~zmimx|||v~r{vx|wtzzy|}|xzx|p~qyzy|||i}{~yuxyz{{}|sxz~}uyv~|{}r~xpsp}}wt|uvzs|y}|{zxxv}~xr|{yzz~z}ygmrwq||{zizwytz|sz}x{~w~w}~xi{njz{wy{{~}rvtp}||rw|tix|ysq|~~~~yw{hxvzl|zqz|zl|wu{xow~~}oyw}u{~|t|zz~}r{|{~sxzx}~{{|{mzx{ut{yxz}|z~r~ry}~~|}yv||{www|~m{x{xzz|zl}w|yy|w~|~}i|~zy}~zqxm|{zx}y~tzt{v|qz~}ow{}yz}}|~zu~~yyuwvuu||{}y{|z~|}zrzzlwy~}tw|~z}w~ptty~~s{y}on}|yx}{y}swxwepw}}}q{{}~l|{{zy}}t|}{}~|~zq{{n}~|vz~}~}}{x|xvy{{z~{|{|{~x|w~|yuz{|z~~zyr|~}~{}~||}}yyz}~}~~~~z|z|{t|~}wx}wy{{|y|y{{w|x~|~{|}~z{~{|~{z{yz}{}v}~|~y{v{yvs}{{~}v}z|}x{wzyv~}{~}}|swz|{t}wx{u~{|~u~{{~}|}ryy}}{{{}zy}y~w}}s}}zx|{|{}w|{yzz|}~|y}{}v}n|t~{v~~~ywk~z}xwz{|qv}|y|}~}u}{|tz~t}{z}~y{x||{|y||~zx{rz|vwu~{||}o~yuy|wvz{sr|g|zv}w~t}|qz||~y{{nt}yzx}}~s|z{|}{~}x{swzzo{uxyz|u{s}vr}{yx}v|zoy}~|zzu}y|tvw}{~yo|r{{xx|w{}s~z{y~~{|~w~x{uz~yx}|xs~|z~x}v}x|v}yq~v}|w{}y}tvr|~z{|~wv~|zz~w|t|}|zy|}}yv|uz~{}uy}ww~su|{ywy}~}~v|y{}xyx~}|~r~~~~}u~}p{vm}|y|{~wx{z~{}z|~|t~|{|wyvy}x}~s{x|}z{|n~|||yuzv|~uwx~|xwv||{xpx}~{|{z||{{~~|{yrxx{xw|{|z{}v|t~p{z~rxxv}~{{|i{qz~uy|oqv}zx}|vt}z~}}x~~~}o}w|yyx}xvwyy|xx~|vwt~xy}~}}z~}}}xz}|~w}{}}|||zy{{y|||~}s{y|v|~z||x{sy}x}{w|~}}~}suxwr|l}q{}xw~|}{}yq{{y{}}tvz~xzsy}y}xv{||~|||~||wy{}}w~||{y||o|{z}yyu|lv}}pi}|yy|{~z}x{}y{}|ywqzy|{~|tx}y~wpoxsw}zyyyz~{{|xxy|yz~zxmwzx}{|wryt~}t|}zt~}{{|~{|hyxqyyx|y{}r|s}zlw{wyzu{v{z~zz||}|~xw~{{y|~|~sopxuvtzst}~~{}x{y{|~}w}yxuu||}~{}{s~zwsv{|rn{}zx{~t{k~zu~}z~|z~}|xv{uxxy|z~}}v}{w{{y}~y{~~||}zy{~u|ylg{zx}yv|rx|{w~|my}x{r{|y~tz{tw{y{|~pyyr}|yv}vx~}{|~|syvyzw{t~~s{}uy~~z}~{yyzuz}~{}{~}rin}}u~~~}|zt}z}|{x|ur|~||zlzyxx}y}}s{v|z|yvzwz~~|{v~|}o|{~|wz{k~srk|zx{x}uz|p|ryz}}{}~z}{xv|~xuto{t|~us~~g{v||~u}}~z~xwzxy{orx{{~~}z{z|vvszpv~y}x}zz{{uz~q}{p~szd{|ypx{r~~y|~}}y~{u{{{|y|zxypk}x{~|}}wz|~wgkfyyv}~|x~gzz{v}}x~|tyz}y||{~y~{~|{p}v}}}ux}|}z~{zv~p}|ty{p}{{~}x~}i~yy{}}x|}|~l}r|}}zx~}zw|`}xy|qur|}y}yv~z{|vyys|~w{}us~|yz|}z~}w}w||~x}rvz{|~~z~z|{vsyqnzxe|x{}yy~~t|y~~}|uzr}u|z{~y}{{vv~}|}x~tyxz||{||~~u{}v|yy~|~{{wv}w{~{x}}y~u|y|~~uy|xy~{tz~{u|j~vn}q}zzzy}}}jqvzwx||x{}|u|y|||{~s|z~{h|y{~}{yzxrs~wx{{yy|~{y}{}}}y}on~}sfz~~|{u|xtz~v}{yyyttzw}{w}}}||n|y{~~vw{|{{}x~yzzz~}z}sxxt{xyy|zy~~uz~|{vzu{{}~xpy}{{}yw}}v`~}{|}}w{zvu}{|x~wz{~{}}{~~}{vst{|}zwyy{uxw}y|{}v}}|}vtx}}}zt{{~zy~|||~{{vzzzz}|zx}}||x}}zwwr|zyx||~}yx}y{w||qq{z|~}oz|{u~{}~{w{z|||z{|~}||~xz~~~|z}||{|xwz|yu{|x}|xy|~|{~|~{zq||}~z}zzt}~z{z|}}yxvsy}zt|}{s{v~||{w|ur}|zyw~|~{{vxz}~~|}rz||}twy}zy}~~||{z}uyxwz{y{yw}y|||y}zs~s~|~~}z||{|~}{|w|s|~{v~||}|t}z|q~|s~y}|~}|zzy|}|~v}}{~|{}|yw|s~}~x|{x~~w|}{y~~ywz{}}wy||}zq~yu}}|~zu}xwxzzz}w||{}x~|{|{}x{{|~~~uz|{v}{}}}zz{~~}wsu~{|xw|}}x}}~zzw}|}|}||~~ywzz|{z~y}}zw|~}y|{z{v|zwy{~}||}~xw}{sz|x}x~y|~}}{z{{yyyyzoxx~zxz}|}~y{~z~stwuxzx{v~yx~{}zywz}zz~}{yzw}~xx~{{{r{|{yz|x{~z}{tyy||x}}~}y{{wx}y{|uy}z~s|z~|pu}~yr~~y}y||~||y{wz|}zv{xwwuy|z|~|}v|~~{z}w|~~{v||x}{r}}{}zwt{x}|}y}|}z~wnz}{|z|w{xv~~~wu{|sv|~{z}w{~|vxz~~szxz}rs}z|}{}yt|w}{tuu|}uy|zzuuzz|~u~{|{}y}v{{xq~wzz~y|w{~x}{xzx{}~{r}|sy{y|{|xt}zw~~p|}}|{x~}|}tz{}{}~~|yy||y|}xsz|xww}{zy~{pst~}y~z||z}{{z}ur{|{}z{{n|}{{}~}xztz{}vzz~|syzs{~s}|n|{~uyyw~zzyzv|}}{z|xyvwu}u}p}z{{z}yxz|{z}v{~u}~zx{uw{{}x}|~|y~{{l||w}||yz{z}z|~w{}}{}z~|yz{x}wx|{z~~~tx}ysw{w}|z|||vywzz|}uyu}r|z~}u~rl{v|zv}~~ry~t~x|yw{~zmyx{zx~~}xzzyyv~mv}~{|~dq|}}}z~{||{xqyzuwuzz}y|uz~}wy~~urz{yw{|~{w{vuyyjxwxywy}~~{}}~x{w{}}y~}}{~~{zw~txzv~||x{v{}z{kzr}{stc~z}v|zx|{|ozw~sx}vyy|uv{~r~}~vxz{~w}yqvi|vq|w{|yr~y{yr{|z~wy}v|y}{|~qxy{x{z}}y|}wx{ym|{~{yvw{{|~}{{wz{~l|}zuw|{xs}{||nzxu{y{~}y{yr{~zvz||}y{~}}suyz~uv}}}zyw|~|}y|vz{|vz~yuz~wy}}}~|y{z}w}|q|{w|{}y}~z~xy{}zzw}}o|~x|w}z}|~yy|{z}{{y}}v|}z}~uw|~u~~|z{{|~zu{{w~}yr~yy|}}}wxu}y|{zx{u|x|{~zu{y}|yv}}z|~}o~|~x|t|}x~~}|~|}x~|v||z}{~}rut}y~wz~y}~z}}|}z~y|zw~|}{|~zz}zyy{|}y~|x|xyt{zy}yw|tyxxwxyv|x}u}z}}xwz~{y|ut{|yuzxz{~{~{|{~}wxv}~}|~{{~wywzwy}z}|ys~zuz~}{yz~{y}zw|z}w{|~xprwu}}xw|y|u~s~|zzz}{}{|~{{xvv}uuz|}}}zyt}xw~~}|z|yu~}~xv{~{yuxxy|}~z}z~{x}xw{zqx~y~{yrww}{uyq{rv}mz{{~{}|xy}yuvr~wzryx|z}}~~zy}~xwy}~~|xmwz~y|z|~x}~|q}}|zrz~|yfyx~v{|{wxzzr}v~{|{{|x|yv{{~sysuww}uyzz|}ys~|{ws~~~x~|w~}t|z}|~yzvw{~u}}}z~|~|zq{~z{~~~}{tz}~~s|}}u{w~|x}|{~}~x~{tzzvztwxzzyw{}zx~~w~~o~|uz|{y{xv{zzzv~}~~u~rx{}xxv|v~yywy~~z~txyzxzfz~|~|~}z~}|}nz~zyzwyyotz}{}x}~yk|}z}|yu~|}~~w||v}zy|z~y~xzvy{x|~|}|x}t|}}z}l{}u|}vzw|{w{zz}{zz|{vzw~{c{z|p||x{~}y}yz}z{{}~|}tx~ts{z}}|q{y}t{zr|p}||v{z|}|y{|}|{}}~{}w~utzzwz{~|v{m}~y{yt}}|{}z|wnyv~zx~xzyx{|y}}}~|v}{zxy|{w{w{yq{yzx{w|wyv}||}}~~}y~{t}zv}}}~x~{}~~|~rx{t~~~}~xyu~}vy|z~|uy||}t}{yyx}||x~}x|}}utp}|{zu}u~uuz~{|tm~|vu|x|||}|w{oyyy~{ytxuv}|ww|vwo|xw~i{ra{{wy|zn}rzzw}z~vs~yzuyqvw~|}sx|}|{wxvu}{w|w}z|}x{h{{|xx}}x||u{t{}|w|zwv{m~}~vyp|~yvkx|x||~|`n}v{u~xG|~s}x{zw~~~}x{s}ys|~}{r}Vr}z|{ywv~yz~~||}zwsu|z~{y{t~g}xz{mz}~~|~{}~ww}kv{wywyysc{{}pz|{}zr|zyso~{gmo}qtyuw{su{{zyyz~}{{q{zwx}pxm{tvyw~zt{tw{v~st~s|}vt}tpyx{{}xi~y{}y}}tr~~m~Rzxu}v}y}}r|{ulqy|py~|x||ox~}||{|tu~zy{ur|vz}~vxsvnw}x~~z{|}}~~{{|x}~}}yy~~~~x~{}~qyk{~~xx|~}vr{xz|zy}}y{t|}{~x~|}|zzow|y~z~x}|y|}}~~{|xs|wv}u|}u~zzvszv~|v}x}~|{~}s|{|}usx{{~r|wyt}~zpnx|xyz|wy{vv||}ys}~u|}zy}{|o}}{x|zv|}x~|}~y~r|y}{t}|y|y{w~|zv|{ux|s|}~yx{{yx|yxw}uyy~zyxw}}v~v|{|u{|xzu{~w|}xz||~rx|{wx}{~v|}wy|r}|~w~}xtz~v||~|~~|o|wx}xxvxy}x}{v{~~x~y{tovv~kstzwyu~|ynzzzr}~v}~~{wk~{wyvw|xk~r{u|}~}~{uv{{hwwy~yux~t~q{x~v{~x}x~|vx{zwz~}~tzu|zrrys|{uzz||wz~rvu~}tyo|v}yz||~vl}yvu}}{|t}ttzy|y{{qyvww}}{~wugr}|x~x{m}a~zay|~zxv~||ssyu|~vzs{}|wtlv~y}}|ztvw|}soms~y}~y~u~xsvtywtwxvv}~z|dz~z~~|~}~|}y{{yu||n}{{~u|uqz{u|w}~~x}yy|{zr~{xz}ujy|u{iyy|uy{vt}uymu~sy}~ur}x{yuu|z{|{{ytyyuwyWx||}yyzx|z}yzx|wy{v}|zz|xrw}qz}ys}~|vy|}z}~|~yz~~|wz~~|yx|v~xxuzr|x||{{|~{~}|||}|y}z}|}zu|zz{~{x~z{|~ywv{}zx{ovw}}x}v|}}}{{{~vx{x}}v~~xy~~}|~}}v|z|}uztyy~~yw~}zy}wzxw~v|{{y}{}{~~~y}|o{~zv|y{|~wuzo~{~~y}z~v~yxxz~z}}z~|}{z}x|y}{}{y~{y~s||}t{||~~wz{~z~pvpzw||y}y~~vzw~x~q}w}}uzw~|{|~w~~{~yx|v{|||}w}y{z||z~~y}~~}{~}zxzz{}u~xsvxty|wx~}}~}t{ywoxnx~~|{s~x}zuy{tz{}}yx|{z~|z}}{y{~x}{}}~vt}uyz|~y}zy}~v|wz|s}pv{}s|}z}~|x~}t~{~z~~x}y{{}{}vz~~tv{~y}z}{zv|}vyr{x}vyx|~}|y{o|ztw|yn{|{z{{~~x|x}}w}~wso{|y|}y}wqvsx{{{x{ur|gztyu}}m}}}~}y~y~w||~{js{~|}~}vaw}}zx||x~{}zupz}}~|t~ywx{z{|{|}|x~x}}y||}}ww}{yx}hzxxz}z|u{z~xw|y}z|km~yv|y~~w|ux|}||{y|ztyz}z}}~{||~~|x}u}v}~}tt||{wzv{rx}z~~|~wwxtz~}}y{v{{v}~}|zzr{{yz~y}y}z~~y|{}zsx{~~{z{wy}~}oy{yx~{z~o{w|}}~xwv||}~~zs}}yyssv~{wyx~{}}|z}|{t}}|zx{}~y}p}wrz{{z~wzt|}q~}{||{|vk|||xzu~z|}}||v}|y}x{w|yxz{|z|{{zt||yz{~{{}}oz}ry~u~~txwz|wz|zyt}{~yr|~~}{}z~zv|w|yv~~}x~z|{{~zs~|vy}|tx~~|~{ry}}~v}yxzt|zr|zyuw~}|xzvzz~{x{x~y|~v~xt~{}z{ys~{sz~zy|{t~~{xwu}wyv~~|~zz}t~{}zyxzxvs~{zlyzz}x|||{|vu|yyy{~y}{{z|||p~zv{u|~|~~|~y}{zyxy{u}x}~{}|y{~~}|{w||wv}qzxux~s~{z|zr|~}{u|y{}{y{~x}{{uzu}~jy~y}~|{ywqz~vy{}yyy{}~p|}}nv~}y|u~z{yxz|{}x~~zy}}~uwz{w|zsy~x}z}y{}{vz|u|{{yu}z}~tt{xp{~wt{{{q{}w}yuyww|z|zw~~}~sx|||}~xz|}~|}}}|~yqu}zm~{~zy~z{ss}}y}v~zw|v|n{}vwzv{{~x{z~}~uszxy{{|z~}rt}|t}|qyr|w{xyxyv~w|x}v{}}}jxxv|oyyxzz|tt}zvu}~}{t}|tw}{}{{zn~~x{ywtz~{}|zrxw~{{w{{z~~|z{|vzv}|z~xv}xv~wwzs|~~z{~t{vy}vy}|~}zyzvv{{}x}~}{~w{}{xt}}z{~|y~v}zt{ywzr}~{|zv}}~y~}tv{~||z}}{x}x{||{~zvyz||zz|{z}z~x}xv{}{|vtxs}~~~z{~ytzw|}zy~v|{~zzxw}v|y}}{}{~~~xxzxx}~|zxxj{|r~ywr}y|x|yzz{}{xx{x}w{zyy{{|~zzoz|u~q|~xyz~y{}}|t{{z||x~y{}~z}z|~u{x|txxtzzvx}~||||y}~{{x|tszyx~y~}y{st~{zzx}}{|}}m}txu|t~n~sy{~~{xy|}y~u|}zy}t~xz|}~{~zxv{ru|}~}}~}x}|z{{{~{y}vwz~w|}|{zvy}~~y{xk{{~}w}zr|~u|x|~z~zy|y}}|yz}z{y~{zwo|~|y|~t}p}|{y}r~{~nxx|}x}y{y||xz{{xx|}|}}|}~y~n}v~}zyju}z}|x~wzwy{{}}xw|wl}~w|x}~||x}~yy~z{}zw~sw{~||q{yyzw|~{}w|}zyx}n~}w~{|yvz|y~x~|z|z~x|r}y}~su~~||u~zy}x|~yz{x|||zzu~ytxw}~q~{{{|x{x}|z{}xrqw}wz{}{|}~}ny|~}|szz~}}||~|~||vz~x}yzv~}r{xd~x{yw~}y|}~||{wz|w~t|~}{hy{y~z{vz}x~z|zyv|zy}~zx~}||yy{~y|zyz}}t|~}}ypx}|}}z}}tyxu|~uzw{|yw|zw{wz~~{u}{w~|~{w~u{u{yzw|x~y~y}}z~~~}|xw|{|x{{~yw~ztwy~{|~||vz|xy{||wx}||w|~s}}zw~z{wzz||v|}z}{~z{wv{y}ymv|yz}}z~|yvyw}{{{uyy}}||zpx}}}xy||yxyy|rvv{~}v|{|{}s{~{v||y{xz}|uy|{mxzv~v|w{y|vz|xz|{{y~}|wyz{||}}}z}txww|{yy{{{x{|}xup{}v}{x{v}}~zyx|{~{}uwy}|||~qs{}y{v~}zv}{v~}v{|~}}{{zzxzu|vux}}ry~~y}}{~{~~~|}v}{v~~}|~{z}|{}yv~sx}|y|}lZ|kzy{~}w~z~}z{{}s~t{{vyw~{v~z~y~|}sx|}~|x~}y|l|}{zvu|{|~zz}}wwu|m|y~y|}~z~}}{tx|y|~~~~~u|xx{vwy|\v}u}x|{|xv~|w~{{{|~qyryou{}~y~yy~yyyx}{s{~z|||}{~z|s{w{i}~}z{{~|~}w|~|~}w~rwzw}y~z}u{{t{zqy{}|}|}y{hv|z~}s{z|}}|zy}~||s{|{|yz~}{~}}|~xs~{ru|}||v~{rvm~||{u|z}t|}}}{oux{zxwzv{~j{zyy|txzz}p{wz|~zxz{||w{~{}||{y|~zxx~yv~qywowwrzynz~{}|oz{xmru~v}zzp{z}{|u{}zx|}~~{vzx{}xn}~y{ur~xyx|}}~z~|~}}}|qyvw{qn}y}|{y}q}{y~~{~w|zm}v}~wzyw|}}{}wpx~tswv~{vzo{~v{v}~|x~wz}yx{}{~sxzzy|ww}{wu~}~{xz{o}}|n|~~{~~vq|~}xs|wwz{w}x~vv{|mz{{~}z|vwy}twoy}yxuz~~|~}w~vuwy~}|}uisx~yxzzy{~~y{}y~||zwy~|}u~w{|x}y{u}z|vwum~}}uyzzot|}y{x}z~}xto}}|ywy}u|{xv}~u|}y~qy~vw|{z|||w{z}}}z}w}vx{yx{}|~}|uzyx|z~zy~tqy}|~|~y|t~yvz}o{|{srx~xwz||w~|y|~~~u|{}~}~xyz~{}sz~~x}tx|zz~~|}hzuvu{y}xyyx|z|zyyo|}rwz{xyzxptsn|uwx{yz~z|{zw{t{}~{x}xw}wx}{}x}x~~w{x{}}{y~{zx~z~~z}zu|yx~{j{||vz|}{oz|zx~z|{}~~z}yt~~{{|vxx|z}}q|~}{sz|~q~wt~xzwyy}ywyyxyz~|{{y~yz{rwx|z|xxzzx}}x~{zzr}|||tyszxr~{xvy|}yz{w{~q}{|v}yxv{|{z}v~x~}}x|rl}~uzw{~xv{}sy}|~}z~s~}}{{wzv}{u{z~e~~t|z}}zzw~}v}{uxrw}~zw|}x}~~|{x~~|}z~}~}}xxt~z~|q}|w}~xzv||uwxr|~y}{u{}}zt|}s{yv|zxv}y~zzz}y~zzs|{}z}~{|y|||}|{~w|{x~uy||{~zy|z}z{{zvzx|zxy|{z~yw}zry{rxywwxwz{~~wwxxw}v|xzu~zx}{qu}{x~z~}{~{{}~wt{}{vs~{}g|{}ys{|}}|}}}}}szzv}}w}z{{~~~xv{yyw|y{{xynwy|~}}{vt~{xz|xx}}~|{x}y~y}z~}zzx}zjv~yzu}zy{wyx~}xy}{zuy}vx~|ww}~vwmyv~q}z}{{|x{w|y~wy~|x}{}|}~|yz{~zz~~xw}{v}v|}w}x~{~}z{~}~|}}m{}{r}{z~}~~~y|zzypx|z~{v{|xyur~}{}}~w|{py~xxsx~x}y{~w~~{|}s|zzxw|}{{ywzs|}s|{x{yzz|tzz}z}}wv{zm|~|z{{z|{~u}~}xw{s}~~t{}zz|{{l~ozyzzxyz{}s|z~~w{x~zy{~}}yuw{yvy~||~~zxy{{||t}|}}{|vxwu{|o|v}}~{w~z{zu{{z|~x{|~~x~z|y|}vzw}vv}w{yyz~z}~||{~{}|n~z}vu~xux|yw~z~zz||z~z|}|xvx{wz{zx{zr{}ww}|~~tyyzy{{}rzxz|~{}u}wx|}|y{}}}}w~}n{w~u}{{y|~n~~zy}{zrv|zz}qzqy}|vz|z~z|{{|s~v{y|uyvtx~~}z|w|v}~{~{|yyz{}|}yrxzy}~}sw}x|~}y{y{{|s~z|{|z{x{|}z}}tybx|t~}{~~z{xx~~{~}||}{t|{tu|vy~~}ymzzr{~{{}yusp}}}yz{~}mv{|{oj}z~zzw~~yz}~~|z~zz|~z}~uwr}~zz{y{x}|}}~|~y~z|}{y|}{|xx}|}|w}|}y|w}~x||~x|vz~}}~|}uz|}}~}{}z~yx|~|{}}{{|z~z{zy{yt~~{{s}~~v{|{{~yz~|uy~us{z{}zx{y~~|yy{z~rz~|||~xu}{xz}yz~{}|v~w}uzz|yv~wzw{v}}z}|yz}~zx~~y{||tx{v{x|yz|p{rshwyu~|z{~|y~}wy{{}|}~}z{~|wzx}vtu|{xx~}}y|yzw~~{y~~y}}z}}}~wy|pvw{|sz|}{w|{}jvu}u|xwxuz|}}x}}{vz|w}x}v}xxyv~}}}m{}{w|}{{vyzy~{u~qz{}w{~uyz}|u}{z}~{|w}wv|~u~~{~{w}||}~|~}~|||xz|}z{}{x{{{{tr}|x}}|u}|~ywq{{tq~}y|s|}~|{}{y~|~|}vu}xy}{jx}|u{w{|w~}~|w~~|y~zr}svyv||~z~u~}}|yuv}{|z{~|yz|y~z~pw}x|xwux|z{{owy~yz{{~w|~t~~z}}|w{t|~~|uz~~}w{}rv}}{}x}|~}{z||}y|}}{}xz{ux}|x{}x}qzp{q}wy~}y{{{ulqv}{{}t~txpv{uumzuu|}||uzs}u||{}|y|~}}ty|{{o~t}wtx{sv~wyzi}yy~t|{rzy~~|z}vsq{yt{w}x~~}|u~~~}|zy~nyyypyzu|~{z{z{zv~|yur{q~x|z}~~qxyyzyxxv~xz{z~y|z~~x|y~}|~sx|nx}~|w|}}w{w|~|{|yzzx|}v|{y{yw{{}~lz~|{}}v|~}x|u|v{{|zz{~w}yx}yz}{}v~pz|~xzr~}z}{{zu}ty|zv}z~y~}~x}~|~y|zy~q~uu|vx{|}xy~}z}y}z|{tx}w~~{zp~z{yssx~w}zo~|z~}{u{|yo~zxw~|}yvy~||zy|w|{{s~qyz~}}|zxy}r~}}|v~m}{|t{zzmy{x}|xy|wz{zyy|wy}{v~z~}{}{}u{}yy|vzt|zyz~~}tz}~}{}}}|~z}wy{z|uy{wuwzzz|yxsv}z{w}oy{~}z}|yyzky|y{~~~~yt~r}zy}|}}y~}}x}oyu}u{~}||~|w}{}z{vzx||~yyy}~{vozyxxz|z{{z|}{y}yr{z}~xxv}~}{yy{yt{{|wz~}|}xx|||{}}~~{|z~|wzvwx}zyz~y{|{}}yx{~v}z|w|~{~t||}~wxq{z~o|xxvs}s{yy|{|~xz|}}~}~w{}|}}zp}{w~|}}}}z}zsvt{}}}|q|x}q}~v}}}{z~{z{~}y|}||v}~~{}||w}x}|{xv|z|wz{y|{yp}~|~{}usvz|~|~zwz{{wx|x|z~zzy}|vv}|o|z~zy|zx|x~|zuepus|vs{z{x|y|q~luyc}}|os~wzr|u|vw~wvv~~psvw{xwzxx|}yzuv}}{|imz}}|}v|{q~wmsxxwyys~{|Wqz|zvuv~v|{{s|~~zvpmz}yx|}s}~p}uzp~wn}m|wss}}|~}wrzy{|m}}v~{gt~|zy{-|}yzm~x|uwxasky}s}zowwxzu{wk|wv~{y||quzxzozh~yL~}|w{m?qrztxwvtywwo~w~|w{x~}zy}xrqlv|{~~y{~sy~y}ngnpoqzx}p}ylw}~fw~~{yyw|u}y{}|sz{{vnyw~wpnz||di|low||vz~zb~|}uwq}v|~{g|y{yz~ysv}z[syzs||yvz}|z}ruw}{~z|~x~}uzy}yzyx{xs}~~~y}u||{vu}t|{yw~}{~}l|~}{}~v{z|t|wp{x}}}vzt{t}f|ty{nxu{~x|v~lv~qwwy}xyxnx}zy~|zy{|}|v|qxuszs~z~v}|{l|}}}}yu||z|{}||{w}zz~u|{z{xyzy{|~u{zvyyxyz}~zx|}~v}}|vz|vy{|{}yyy~{y{}|~wz|zr|~|xyx|wy~u{}|~w{~{|}m|s}zyt~{}~|wyz||}~xzy|}uxzyty~}~~}r}y}|wqyuzzvv}~}}yvzsxv{~~z|rf|zvq||xz}vxw~~wzu}ruh~}w}iuxx{|}{|tw}~y}|u|q{x||{{{|w|~|w~s|z~~{~x~|z|{yx}}~xx}}qz|}vpgtt|xr~}||t|dy{|{s{wzyx|v{~~~r~xz{|{}ryy|su{{|}~}z|{}sxuww}}|y}~{|x~|~z}|wq}{yxz{}}|z}zx|q}|y|}~~|zxyzu~zy|kszuruxr}{~|r~xuzw~{}oyw{}~~z{~xz|~|~|zvxt}}{{w~{yty~sy~|w}~x}yx||z}~}|}~tv~{y}}~x~w|~sv~||o}}~ztz||yyzv|xyszz{oz}x~{|z~zy|w{|x{|xwr~{{{{}|zhu}ww}z}~|}}{yxzy~~px}~}u{sv}}p|z{w~zh~|{y{~}zx~|}t}zq~}xz|~~{r}ysxw}ly|ywxu{}|x~wxtx||s~r|}pwv}_x|{}xw{z{u{~z|~xvz}vz}pqvxzsyvz{zuyz}~p||tt~v||{p~zz{~Zsu{~~~h}uq}x{{u~|~m|~{r}w||vjx~oqw}}{ux}l~z{{}{|zzw{ve|m~{{~x~x}||~q|}|~|w~{yy}~x~v~|u}}s}udxz|}~wx{{s|ynyz~uw|}rhq~uiz|yt{ymrv|w~by|~yo~zsmuww~}w|v{~vz{nw{{jx||y|vyy~{x~wxwvxz}z}r{|n~}y}e}urxz}}v{ux|zz}}zz~ztz|~vv{{y~tv{s~~|{}y~~tzx{x{~{w|r~~{z{{}yy}zy|~w~u}r|wv|~}uvzt{zxt|xux~vwzw}~~v~}~}{}z~|z~xz~w{~{~z}{tv~zu~z{}}y|y~{z}}}{lyz}zy{~wx~{t}x|v|~y~z~yz~xzx|zyz{x~{}}}}w~}}~~~zx}{|zy|~|zy|~yzx~s}z|}xs{wsy~xwv|~{~}||zs~zyv|wy}~|xu~y|x|zy}}~zw|xtzwqy}~}}}vs}yx{z~|~t}zv{ywp~x{~upi|z|z|v~{{}v{{x~zu}~{|zk~xy{|}~|~~w~}}y}lvxz}{yz}z~{sy{|}}||{{{|}~sxzzwxw{}|xzulqPtzyvzvyz}szz||{tvszz}xts{v}vxtuwy}zz|z}qzzy}|yzw|zx{}w~zw}e|zp{z{|{qy|{srx}~x{|p{wxv}{{|{tq{wux~{||t~y}tu|y~xzyyjmu}yzs|z~~r~~}yvv~y~{ujr}|w|}|zozvi}sq~{y}zxyvs~|xxyo|vxy{|~~s~{|{}{~z~zw}yltxv|vqT~xwp~~|{zu|x}vxtuu||{~q~~qx}yy~{x{z~~zzr}su|pwzsv}x{|yf{{{}~|}but{w|ymuwvqjzzzyw~ovz}u~~|}yxsyxq~{o{~|}w~m~}~wk|zvyzsz{~xlu|v|x{vxwz}z{y}{~||{vn{z}zsy~|u}|||u{}}|{~y}y{yzmyztn|{guy{}~x{y~wvyx~v|wzxxm~||ny~~}yx~{{oqsyx|r|s}~}~|z}u}}}}zu}t{~|~x}~tv}}y|wy|zwy{u}{}{y]s|{xzN|ts|r}xxur~v~w{z~{||txzzt~x~u}uo~z}~{}|~y|||z}vvu|n|w{lspr}v~~}{{}~{|v}vw}yvz}zwuy}}yw{{kyuytu|uveouzxwyws{j~wwyz~y~|~|zzy}uo|x|{yr{{{~ywtp{||]p|}|xz~}z|{tw}|}~{}q|~z|h~vxozzryerxtxw|u|x}y{|w{w{{|wv{s}~zw}~}|xx~|w}~~y|~|{|}zxzy|xq{|n|z}|zu{{y{~vtw~yz|yy{vtw}~y{}}~t{{{~|xv|wz}~z}syw}vx{s|~}zx|}w}{||~{}}w|{y|z}|x~z~}{{|v|v|}~||yz|u~|}v}xz|~w{yyz}y}wws|~}yx{~~~~||{}xp}z~wy~~xxyyx~~s|v|x|w}xyw~{w~q{{zy|}s|~x~~zwp~x~}zn{xx}|v}||~sxzxtz~|~{~}~|{}z}uq}||~x{y}|v}wvx|}}|}~x}~~y~x~}~wx}v{xr~sy{}~||w|xyt|yxtvzz~r}{{{z|yt~{zyv{|{|hsv{}u}t~xv~r|~v}}wvyy|y~yty{w}|}|{}y}}yz~~p~~}vyds{}x{vq{~w}{}~}wqm~u{|~~{~|x}}~}yw{}{~{~w|v|~u|z~www|}z}o||~xv}~~x|ltyv}s}|~y|{{zz|}~}}|u{yz~y{wxzy~}s}|||y{u~z~{uzz}}|~}}v}~txx~|tyy}|o|~xz{wz}}}yz|}}w~{{s|}~kyw|xvx|uy|rv|}v}z|{zx|}t{~|nq{~~yy|}~}n}um||~w{y|z{s{xsyy~m~r{|zs}kw}cq~|o|}yy~|}sq{~p{pzwrv{{sswv~|vszz}{}{uznyww}~~|{{~{{|}w|~vw}}tt|~|zx|x{}}}|~yxw|~~tu}vx~}zv|~zx{|}}~~{{~y{z~r||}|y~ym{wy|s~~{{}~tz}t}yz|yw}yyssrxztw|x~ztu}~v~xrv||}~sq{|r~}ytz{{|}~w{~|}|z}~yqw{t}}}zr|{~}mwuwx~|~}~~~znyxzz~{x~zspm~t~}vx~w{z|zzzx|~}yt~{zqyvq|}|w~w{uwz|v}||u{|s}zx~}}w{y{}|~~}ycu{z~~zwx{x|~~|~y}~||z|yzxwzwyxvz}{}{y}rzwyz}|ws|}~}|{syzwz|~wnu|z}z~|~~{}y~o~}yw|~}~~|{~~vy{{z|zuxy~wz|{~xz|xyz~}y{~~t}{zru{~}~}~~x|}}y~ws~zlx|yzy|~wz}ys~n~|x{}{}x{elxw~e~yrz~dq|z~zzxyywyzxuz}g{}y}yvsx|{rz|uwtyywk~w|x~z|||yrx}z~}pv~zyy{||{{u}{~}}{z}}q|~|psvy{z~~o~}t~|~x{{t}~vy~|j~}xz~w|~pr}uz~{y~y}y|{{v~||~z~y}~{}|r}}{~|{~t~ty||v{}xr}|||z}zssws{|yy}py~s}x|}}z}~vx|~~zy~z~~{u|z|x{x~|~vzvy{}{~x||~{n}z{zx~w}{yy||x}|}wryvxwyymw{~y~zw|v|z|{o{~~yws}~{|v}z~w~u~ywywzvx|~zxyx{tu{{xv{w{vuyzzyu}{||w|{{w{{~u|~tu{{~}}qrz~|uuv}~z~st~wz|||x}|{|zxsxy}zy~}x}sw}q~}{}q|xx{rx|}ss{~{|{}}znwzy~ts|}}|zz{v{yx~z{{}|}u}|{}|utxwpvq|}xy~uf}{v}{{s}q~rsz}sy{}{ry~y|{kzwzuhvz~|wvwxv}|}~~z{|~}{n{py|xxux~}ww~~vz{{{q~~t{{|}~us~{v|}syzy}~~upv}|{w~doyws~zwyxxz~|vo|tz|x{vxz~{wkz|}x{}x~z~}|~wyyz}||uuv{w||xvw}yyy~ry|zzz{o||}~~s|z|zz~{zz|{~x~~}~{|}~~zw~|~|~~~u~}|]xzwq}{}z~|o{~{r~zw}uwz}{|w{~s~}z{~{}}}}||s}~~~w~~{|t{v~yypzy}~~x|}}|yq~}~p}y|||{y}zzzy}y~{~y|z~y|y{||}}z|sy|y~t|pv~uv|}}k~yy{rww{}}{y}zz}~{}{xz}~xxz{}z}vw~}|}~}}||{|{txzyv}}~}z{zz|~{{xozxt}}}|}~q}}{y|||~t{|~}m{xvvj}|w}}{}u{nkyr{t~x|v~}|z{uyt}{}{v|{yy{{tx~zyn}~|}}}}}zt}{q~so~z~}xyx|x|{|yp}v{}u|ou|zq|{}}~}|{v}|z{n}{}}{y{}~yqzyrz|~}yv}|s{xz~}|z}}}}{xy}xz~yugw|~xu{wy{}yx~yxwxv~~zx{nzss}z{}uyvz{uyw~t|t|~{zw}xy||y}w}wqxs}ryr|xyzv|q}}}|~{|}~{|pxyx}~u|}}rsm~}{}u~vf}~~xu{xy{v{s{}}ys}w~y~xzx~qtz~z~~xzow|vy~|y}x|~{xxzxqx~}}w{~|{~|s{v}y}|{z|yv}~~|t}xr|wty~}plrtx{xz|xv~}~{pn{ws~wlz{y{{|xrwt{w|rvzpu|}vy{zu~yyz{~|z{~uvyy}srs~u|{y|t~xxyzw{l~~{pv{bv}yww|yu~s}|y|{zwo}qv||~|s||{yztyz}urwy|}}~~qyuyz}p{|yzy|{uw}}zvzuz}y}vwmyz~|x|x~|xu}w{|ovzvz|~}s~{|x}vuz~~|k|zmx~|zx{oxrs}xe{yttx{{}y~{{}|}qrLyn|mtv{u~~~|w{w{yt{{ux|z}}w|r|`t~v|yz}u}lws~v}z:yyy~~z|~xw}]xwvy{Q|}z|x}vz{zrwQ~~wz}|x}m|~quw~|z}v|}u}r|{{~w~zv~sqx}}}|}zyv}|}~{x}}zuzy{zxy|xu}n|y|z}|wd~|||{py|x{}z{zvxz{}}x{~t~x{|y~~v}v{}zy}{{{|}{|z~xpzuzwo}~|{{|{x~zs{{w}{x||x{}|zwzu}yx~y|yzm~ux~}yq|{p|~w~z|yv}xy~{~{}}zt|~{~|~zvz}~|{|z{q|z{x{|~|t|y}~{tx}~{~z~|~y|xy|zuv~|y||||}~w~~}|y|~t|vwzw}{yx}yxw|u}x}||}yq~~z{|wou{zzzw{z|w}{ys|{||w~qw~{y{z}|}|v|vo||~{|~~~v}wz{~z~|wzz{}zz{zx}y{w}vtw{y~}|~~}zz|o}xyv{}zy~yu|z{x{~{u}~}|~x|t~}zu{{vp~~ww~z{{z|~}|h~|~|u{|t}ut{{z|hx~}|~wu}~~zs|wzz|yz}zztv}}|}}~}z}|zuy}x{w{{|}w~yy}x~z|}~~}~w}{vzt|yz}{vv|yzyt}|~}~y}r{}||}~~vy~}yxr{x}vy}{z{zy{y~r~y{z{}{yst}~z}{t{}}s|~|zwzy|}}yzw}}wv}tx|vz{uyur~qy~{tr~y}||~~vzo~~z{~}o}x|}}}}uvu{r||~}vzyz|z~}~x}~~zs~}}zxxzy|z|}voxwvz|wxs~zvs{yy}{|{~wqx|}|x|~~v}}v{}{~{m}|ws{wx|}vxxy|~x|~v{{{svn|vu~t}r}}t}t}|ytw}~x~v~}||{|{ztpq{|uqt}m~z{y}wxvzx{{v~|~~~fz}xy|t|vu|w{wt~}wzxn|{~zx{{{|ry{~|~z|u~~n~~i{~zy~y|||zv~y}x~ov{|z}vlr|t~x}{w~yvwxro|xyt~~s|~vuyy~ys|z}~uq|r~~~{ys||{{{~|zz|nw~~x}~~yzywuw{wyp~{z~zw{pz{}xx~~s}~}pw{z}yy}pz}~tv{qyyzW}}y}yy|o}z~wy|y|wuu}qsz}}|r~tv{t~~tsv|z}|w}{~x~zn}y{sxvx|~m~y}u|w~u~}~}{}}}zw~uy}x~|{y{yyz|~|{y|}y|z{}}pw|zv{v}y}}|z~~|{yx~wx{v}}y|wz~xz~wt~~}~wz|}x}zy|}}zz}~~}}~|z~|}~m{|~}z~|z|zz}||m~x~x}|~}v}{|v}~}xx|~~y~z~~z~zw{yz|~wzz~z{~x}|{ys|u{{ux}}~~{~yx}zs{~w{ty{|~|zz{~~}yt}y~vwy|w{~||~y|{yl{~y{y|{u|}}v{~|v~}~}}y~z~|{|zwyy~wzy~zyrxrz|}{y}}xyv{{{}|yy~~}~rz~w~{}|ux{{w|syz{{sv~}}z{x~v~u{yz~{{|~z|{~w|{{xw~}}|yztyvxwl{vzv||rqr{y{}ys{|{w}{||{[}xnv~oxn{|yzvtyzy}}xtpz|xvvywz}|{y~~j{x}}w{xz|yZxy~u}~}q{{~|ztty~z~~wwzuy|x}qr~t~lvy~s{zw}n|v}|z}wta{{z}j{y|}{}w~|xv~s{x}w~tyz~svzu~y}{~y{~}zwy|~xyyw~~`}p}ur~|ukxxzu`~x{y|zxy|}s~|y|ztxys{q~pvw}{~}|zpzwz|}z{z}~{rz{v}zzyt}t|wu~w~z{|||q|z{~}w|vz~~|~||z}rt|}yv~zz}qyo~qwy|z~|{ux{}x~xxvm|zuz}s|}q|rs|suyznwx{x}x}x~wszt~|zy}w||~y}x~sx~xtt}}{{|||xv||y|yu}|~yvv~~vty}}yz|r~zvi~{y}{{{y}~yzxxu{{~os~}~v~}rw|kpytr{}~|szy{zjw~u|x~sz|{~|zzzv{}wx|}~{wxyxuytuxpw{yv}}p}~{z|rx|xz~{w~yz{{~{}{~w{yxx~x}~x}qyp}xw~~p|unyyx}z}zxy|y~~{z{}}w}{z{w~wwzvsoyw~w{~~vuz}ywy|{|w}{~qyy}|rx~{}|}{{~{}~x|xxuv~}l|h}|~~{yz{}~zwpwq|{zg~}{s~~|}z|}|tvou|r|{z|}~|xpz|x~{}uz|v}|}}yzx~y~z|}s|y|v}v|zuzu|v|{}~rzv}}wrv~{|v|wtt|{}t|v{{~{}q{z{{y|v{~z{z}yysy|yzz{|vv||~}y|}~{~|{||{n{|}vyw|}|q}{}w{~q|x|}ywzxv|||t|y{sww{u}|}~y~~x}~{{yz|||yx|y~~~~}u|xtyw{~{v~|xx{{{}~z|tr|{{~{{~yzxwu|}~wvx|~tz}z}z~{pz}{|~s{|zvwx~z||ywz{u~ty}{y|wy{w{}w}z|~zxq{zzl~|ymtxz~u{}v{y}y{z||puq~zv~p~|~|~z{u|{~}}z~|||~}x}|{~zzswu{}|x~w~}y|vws}~yyy}{x}{yz{y|zxuz~zy|}|zy}x}{}x}}~wx{~~z|}wt}|r||n}~{~{t}zv~~y{xuy|~{}|{z{}|p~~|wvz}~}}xxwwy}}}}}|~}{v}~|zxqu~s|w}i~~y|{{{}{}}z|}z{{w}z~r~{z~xp~~t~|}xw{zy~}qsvrvy|}ywz{{~|}yvzvy{}|}|s~}|w}~~sxv~|~{|{}y{{x~p{u{z}z}~{|y|y~{r{}w}{uz~{xzs|~{y~{wz}~vz|z}yzw~x~t|~~z||}|y}|yyx~z|~}{zyy~w}}v|j~vyq{z~~{{}~uwx|{{yl~{{{v{|}wzyz{~rx}~yxz}mzyv|q}w}z{}{y~w{{x|l}}yo~y{zv|{w~sx|~|{y}|pzzuu{~}u|l{q|xw}ypy}z}}y~}}u{zxvww}x~~~y}xxv|~y}zxz~w~{u}xzzy|z}}||{s{zy|~{v}vzs{wyu|y{|wvzw~vy~{zz{ryy|yw}{||{txw|zz{xy{{}yy|v|{y{|~}yzvmxzz||{~w|~x{}zw{vuy|z~z~uyx{zxu~u~{~vovw|xn}{z}zwmwzr{s}|{~~w}~zyxy{~xutz{}~|rytw|{yv}yz~}{}zyzz}|uw{||nyz{yu{y~wxu||}|z~~w{|t~z|~{zw|qw}}y}x~y{uy~z~~y|r|}}~{~x~uy}ytz~v}~z~vw~y{{w{g}xy{}zyvyw|sz|}|uw~m{}~}}zw}~z|yyprzw}}}u~~st~~}}}|u}tw|}{}~|x~{y}vw~~~||}}q{~{yz~~z|ys|q|w}{{zzz{xx}|}|{}uy~}{x~w}}}zw}{vz}yyz{{}u{|zzy}|}}|}zvy~{w~|{}~}{~|p{x~~w{n|{{}}w}{x}wuv|{}q}~}}|uokn}wq|xz}wvx||{~|}wx}}|~q~}y}}x~z~x|~v}z|zz}v|}}|{oy}xzu}{}xuy~}y{|xw}kz||v{{zzl~yzsk{u{||{|}xtszw~x~yu}}~{{{{~}~zxz}x{px~}{{qzx|}}x|{{v}oz~z}~z|}~}|z{v{t~x~z{{}}yt~{z|x|wzw~~v{}~}zz{zzzx~uzs}u{vzw}}z}}}||{yx}yzwv{|}w|g~~|}~~z|r|x}{~}|{~{x~zwu}}|t||}u|wx}{~yz}w|~~|{x~rt~|yuz}vx|~z}~y~x}t}|~|u}t{|~|z||krl|v~}o}}z~|wyz~|~u~|r{|{u~v{y}}sx|vzyr{xuyu}|vzr{w{yu|}tz}z{~|}wv}~|~xtsxx~zww|{}r~||uw|~ozwz|y{~~|xxz|zyyu}}{}|~~wzut||x~~~|{z|tz|{|x{~~ez}q|~o{~yx|y||~s}}}~|~vwux||v~~}|y}{~r}~u~o}|y{z}yzv|{x|{u~{~sv{}~|{vn~v{lywty~{|ww|}t{~{yz{}|}}z|~|m~|y{z{}~x}xut}zx|}}}~{|vwz}|}vz{|k}~{tu~yzsuru~z~zt{{y{{ts|z}vzm|y|y~|~}}~uq}{z}}rzu|w{xtx~zv~}~y{{ywqrxt|{}}}{z{z|z~{y}~wxz}v}tzgy||}~{y~|{{{lu}|~zm||xy~u||~|~{|zx~z}~x{}y}|wt|q}wr~x~x{sxv~~|s~{}|q}{ytv{|~}wt|zx|}}n}{|~x{p|s}{utz}||}}v~~xyz|||w}}uz}|yv|}y~|v}|z}xv|{}w|}~tzw|~z{v|z}|~xx}u}zzyq~yv~{}y~~~|}|zo{yz~s}|~||su~}x~{x}{z{{t|}{w~xtwy|wzwuu||x~|||t{~|}w}w}z|~xt}||{{z}v~|xy~|{z|vx{v~~z}||}{txywyzy~~{{}}xo~|m|wzrw|~~}{zxz~}w{z|~wy{|~|{}wumypuyz|{w{y{sy}~}}zzw~}yv|xqr{w}~}xxzzw{||zz}~|ytwz}~}{y~z}~}{v|l{|x~~w|~w}{{~~yzoz{}|~zz~}~~{q~~w||x{}wz|~xw~~~zv{|v}vyvuz{|yz||uw|x~p~}y}{}ww{~x}ww{}y|{|y|~t|}||y{xvuz|v{}z}|}v}w~ut{zyu{y}{{~}~y}ywuz||xxsy{{||zxy|vur~~{}~{s|~{~}~{r}z{~|xz~{~~}~~||}}w|rzzyv}xx|x}v{~}tyrx}yz}{~~ww}{}v~~}{}w{{|y|}|e|zx}y}zz|vt|zt|yz~v|}{}y~}z~z|y{x}sy{uyz~z~{x}{~{zy~z|yyv}zux~z{wx|zxzy~}}y~q|~{{|zw{yz}||~z}xz}|y}~|~zwr{~~|zzxw~zss|~~{x|{v|}x|z~|~{}s~zu{~|o~zv}sfq{}|tw{y{fvo}xtxx}}o~}{~{slv}{u{z~|x{}tz|~w|~~~y}|oz~v}s~{}~uso{{zyw|zyx|}nxrw~z~}}~t{|x{x{l{syyzp}\}x{jvvwv}v}yuztv~{}~t}wzqt{m}|zy~}z|zothxz~ywy{|}|y~~|txt~z{k~}}szsu}zr~yyyzsvxyvtsxpxx|~y}}qZ}}vnu{i~z{{wvwuow~~ryw|xy{}x~uz}uir}z{t~ly~ur{{{zzy~xy|y|z~xzv|x|vsvzxmbwzxz{{~|x}}}wwzz|~ysz|uwvuv}wv~vyoiz{|oyuxw}y~m}~~~{{zs|zy~{{zuvh}n|yw~t}{{|{y|{z}y|w}~{{{~xzx}x~q}x|}xs~x{x{z|{xzu{}v|yyz{{yyyuwpx|v}zv{u{}z|x|}q{y}||{{|}{s}y|u|}{~y~}~}~zyvs}}}{zx}~u}{zz{{}}r|}z~|z|{~vuy}~{~{{x}y{r|z}x}~~y{v{|v}}|v~zvyv~}z{y~~|ww{||zxk~|hxzxtsx}}~yy{~x~~|}yztww}y{}|uy|zx{~z~~zvuv}~ynzr~{xz~|xrxl~z|u}}v~|{|v{sz{qx|t}~wy}w}}{}~z~u}~{}wy{}zy{zxs|{}w}~~{~kwzsxzz|t|{}}}}|}v{r}}{}}{}|y~|~|z}|y|ysz}w{x{t|i{s}vyy|x{}szyzw}}}y}{{~|{}xtrntwxs}{}z{y}~n|~n{w{v}z|vz}w~zx{|xy{~|{y{xyz{wz|~u}vywi}{{}|}|r}}v~w|s|zv~zu||zzrut{}qzz|xtzx~uvy{}z}|~z~vxuyxz{st}{{~vzqwywvqut~yy~{{|~w~~|}{w}~~|{x|rz~|~}}~yy~~}|w~w~}|kw}y}y{|zw|vz{p}{~|{z{~}x{}zy}xtt}{~}|}}ru~px|{}{xu}}{{|{x|xu{{yy}y}||{~}~|{}v}zu}rp|}|y~{z}~|vy|~~hw|y}z|}{yr|wm~r}v}~r~zwanxnxtuz~|xuuxyv|v~zpexptsz||x~ytx|wztvu{zr~tuwuw}r|{{v~ryytuw|}tzjxz}x|xneox}}tzXmq|mwz}}[tpsx~vu~x|xi|wy}}pznytxxy{x~~fvr~}z|{c}~}{gw}tu{z}wz|inswxuDsu||rLqyh|nzu|}}zvyw|{vw}~{{bwyu~|{kvz}~~~|xw~y}couzsrb}qx}ww~wxw|o{m{{xo~trvv~{v~ysz|tvsgplsuuc{}{|aosztx~{{t{rpzt}|{~uls|wur}}zli{zv~|t|b|ryl|xyz_{t|~y}aw|pqxo}~}|x}wz}zvt|~|||~~x}zyz{ztyw{u~|~xwx~xwz}y~~|{|}{y~zry~{}~v}z|v~|~}|~|~x}{|~}{~zxwuy}}z}~{}ry{zz~~y|~}v~|{}~{x}xw{wyu}~y~~x}~y{y}uw{}||{}zz~w}yu~}|~ss{{{}||||}|~zx}~}{|}||zzy~~w~{{qy}vz~rz|y||~~vy}}~|x{~{{z{~|~t~|tyzz{}|zz|{~~}}wxzv{~yyz~xzq}}wzz|{}}{|}}|{}~~}yz}{v~}x{|y|}z}ryz|~{{}mszx|}||}}|~z{}}yz}~|zx|rzvy~z}~yvu{~{{{v|~y}y}||y~|{|~}}{{w{wz|~w}}{~zy{|}uz|}}}xy{{szzyszk}{yyz{}|ys~}}~uyx{|}}~~~zzvxx{|y~z|z~sv~|z}ym|||z~~v~yw~~||{|zz{}qzqx|}}yxvz{y|xxt||}{ywzx|~}~~yw}x{~pz}~xz|}vs~|{~}~{}~|}{zzz}~~}uz{}t~w}}|{|}zz{~|}{xy{|xw}|}vzxw}w{u|||x|ov~|~~|z|j{|}yx~~wxyyy|v||}|v|uy~~z|}v}v}u{wy|||}}z~w}xz~~}y~zz~~qz|w|~{~oz}{~tpx~}}{|}zuz}g|}|x|zz|zsx{|x~~~wxz}|xt~|y~ty}|}}~{z~}{{}xyz|z|w|}}{y|wz|zy~y}}~||{u~o|vs|x~~uz~z}~|}~}y}ymu|}un}~}{}yzqzzwo~||}n|{}}xuywfzzz~~yzy~y}mv|~yw}|~~{wu}{p|uus{||svv~{~|}~x{~wyvyxvq}s||ux}|{}zyy{v~|z{||ox}vyzz}~zyztto~~|s~}z}|~|~zrzp|~}~w{tx{}~|nu|{|x{{zzv}tz|{{}y{w{{}yy|}}{|yx{q}|~ytow{w|~zz}}{}y|{y}u}u~y|w|zr{|~kv~|u~}|x|zv{rm}tyuy~~uywu|wyz|vl|wxw~~}||{z}x{{y~}|{yy|m{}uz{}zz}x{||x}q~{|~~}|wxu}yysz~{||tz~tt~~{zv{{|}vvrxwv~~s|x~~|t{y~xtxyzvu|z~|}}{wyzf{~w~|zzvyx~qv}||~{x}}vx|}}}y{{}{~v~yyyxy}x}}y}u|}~~w|}}|}qzy~qqrszv||~{{z}sy}~{t{{zr}~~|~{xx}{{}||}{r~{~{vzzvyyv|{q}}z{|z}zvx}~xv{~yv~zy{zx}}||{|sy}x}~yx{~rxw}z{}|~yvwt{z}}o}x}|x{}||~y~~zxsyv~}~}uz}~{yvz~zyz~z}yz~}|}|y~uzz{}z{x||yyw~zxx{~x}~u|}x}{}zw}|~{w{}}w{y}u~xz}{v}}|}|~~z~v}x}|s|yy}zzy~~ry~}zzvzy{w~|pzws}y}~z}wmr{yyl|}z}uyy{}zw|p}s}y~|~wvy~~wzxp}w|yvx}w|z~}{|uy~x~}}z|}w}zuz}|{yslpxw{wsm}}n}||tzzx|{xx~uy}}~v~l{t}{zxm|{w}}|u}ypt}{}y||yw{}|qzyywz}~~~wvuuvtyvxww}|}||vz~~rxvs}~}{}{oz}w|ux~q|znz|}||y||ytxxm~~sx|}vv{yq~|{|v|s~~|yl{rxxtzw}}z|}vx~|}vx{u~zy{}xxv|wlvv~~{p|zwouz}}xuw|ur|r~|u}~{}~|qz{y~zt}y||}y{ttz|zwv~{|{||~uv~w}yxwu}r{z|}zr|}~~|vx|~y{r}~|yt}~}|~yy{sv}z|~~w|y{x{x~}v}||~z{~ry||~zy{|z{~}~|~|zq}{||zvw{r|~y}xu|uzz~y~x|x~}v|y}~{z{}~}x{}}{v{v}}xv{}{z|zzt||wy}{zusw}xx|{~~v{|s|}}{}~zt~~yty~{||v}}y}{}~y~}~vz~wyuw~~wz||{tz|s{zzt{{{}w~{|y~{|zxz~{}~x||}zzv|zyx~yzx|zwx|{|x{~~{qy~}ry{~z~x}|z|y~}y~}}xt~vyyt|s}x~yzv}~~wszwvwz|y~|y}so|ptv}wzt|yz}s}ztz|yw}z|ww}wzj{~{u~r}vu}z|v~wxw|qz}{~vz~|}}sj{}z{y~qw~tt|v~y~{yyv{||u~{~~yx{yz~u~~~y~~{y}~t~}{yp|y{r}y~{{|rwwu|}~z}z~x}{}||y{j~}}z}{ztv~|~zxw|xvzxzzzzx|y|{}}xyz|s}y|}~y{e{{{skuz|t~z{y{vs|zvxx}swy~{}{~~||{y}y{}}wz}q{~vy}r~~~~|}|wkyw}{^~}|~y|q}|||tz~~oqz}urwv|zvuyz|{v}y}q{v|yuy|u~y~~{~}uzoy{ovzzzx|s}}~a{xy{z~z|~n{z~|u~xzy~w|p{u|{zp~trj|zxv{{~w{}|u|}x~~~y}||{~~|w~~z~{|{tjz~xw{u|{z}tzx{|}|ys}~nixxt}yr|~y{{wv}}}{yy|{~z{yznv{{y}}s|{uq{~wu}}xu~qyxxz}{z|{{s~w|{v{{zz{}{~~}|wst}{y}}}}y{xz|}z|}q{~t{||}zyz{|}x~||x}v~t}{v~{z{u}zzzu}{y{y{{wzwz~|yz|}zz|x|x{}{~|~}~}w}yz~|~wz{~ux}~{}ozy~nt||yr}~|~zswzw{u|}{xyz|x{v~~y}}{{{y}s}z{{x~}t|~yww|l||~|xywx~u|{{|rw}|w~z{xz}vu}l{~z}{ywvyxz~{y|x}x}}}|{{uz~os}v}|{tu{swxqyzy}z{vy~zvn}ywr~{jyqzvyywwyyu|z{}|xyw|z~xz|~}zz~wt~w{}|y|u{u~z}r}{t{~{{{vz{|rzz{{|q{vzt~|z}}y}}}}~zxy~}|tx~x~zwzx~qx|ys}zx~pv|szk~z~~v~}|su~|s}t|zt|}z|p~{s}zvu}twyyzx~}tzw~{||}zyyqvz|xzy~{wxw~z~zfwuqz~sy}{{|{xz~~p|~}us}~|xst~}sz~zl|y{k}y}xxoyvxx{}y}{wv~}~yzz~|t~ynzi||{~w~n|xz}~r|}}t}w}|}y|~|w~syt{{~~}y~{zrz}}{~z~|}~{z}{~|}~{}{}z|w~wqyuyy||y||s~{~{{}}|{~{xzyy|y|psz}{~{{}~{u|x}}x{yy{w||~}x}~|~zz~zw~~{y|ytx~}|}||}zwy~}|u{z~|~|{zw}w~zxz{{}|wzvu}~y||z}u~{rx{vzu|tx||{~~}||{~~|}~{xy}wz{~}|yy|}~~y~~{wux}}u}||}~z}z|{}|}us}zwy}|}~y{}~|~~~z|rs{vvty{z~wx{|~~|z|~|}uy{~z|ytz~x~}y~~w{|~}{||yz{~y}}w~}}s~}|w}z~t{}}|||xuj||}xr|{{~du{|{z~x}~o~}|~q~z|x}yy{y{}xxzxwq|n{}|}~yhw||{zx}{}||}{}}tvpuvr|z~xz~z{}|{}w}z}}|~~|u}w|psz{}||rp}~wt|{zz}~yz~uyx~|}|u~|~{|~zv|t~~~|~~xx|twz}yvzyw{vt~{y{x{yqxw}}v~~}z~u{l}}}x}zytv||}{|w}w~|}|~mu|t~}x|z{~~}w|x~yxz{}z}}zz}|~}zz}~pqu|w|s|}r|~z{z{wz}z|rr~u|w|y||~|y}}zp~||xz}x|{rxw|{y|}~v}|~z|y}~vqwo~{~{{y{}xp}z{|y}|{{{z{|s}wrux{}w}{~{{xt~v{|zyv{~z|x{|zlty}xyr}x{x|{}|||wz{y}wzv}r|v{|{y|uz{x{xvxxx{}wyvtywuzxx}s}{~w{vx|z|{}|~y}xyz}z|syw|u~}wzz|z}||x}v}~~{uyzy|}u|xyyxwzv|{}yz~zv{xz|~zwzty}{zpzp}{~k}|}|u{~}yw{sw{|z}wvuw}w}z}||{s}~{xxy~yxiy{x~}y}z~{~~x{|z~~~y|z|~~}}y}}uvyn}{{s|}|te~zt{{|}|x}}{}~z~|}z}wx||{~x}zc~|y}wz}rywuwy~xx~|}{{~|zzx~}yz~u~{tow}|~~xs{|zt|yxzv|xx}{v~~}}}~}{~{{{|{v~zz}}xwtx~}z{rtq{z}x}~wu|{|w}v{||}~|y~y~{~~ru|t{~z~~tx{z~yxz{zy~y|z|~{w|{zz||||wt}yqt~x~vyxtx~~z{~xzvx|zzzx|zp}uz|~|~zzzxvwy~~|}t}zx~{||qzys~}zz}|}{~|q}|~~~{~{~~{~yzu~{|x{t}~u{|zr{~~|x|p|x~~u{z}|~||~|t~~|w~~{xv|w|}r~zy|}xyx~}|r|}|zz}}vuxz|}u}}{}~~|xx~}y}w~{txy{{z{||xsz|yz}|{{{|~ztz|zzzzj|~wyz}xyx|~y~o~}y~~r~y{{~zz~}y|~}~uv{y}ywxzy{x}~}{||w}~zyz{}{|w}y}|vw~}{|}||t}|{~}oz}~zq}|zxu{~{u}}yx}{|}yz~y|zz~}{z{v|wwzwsv}w{x{{{}z}y~yuz}}{{tt|}~|z{v}|}s{~zv|}}w~~~}vy}}}vv{wyz{{}{{yry|}{zv}yv|zzz}x~ur{yv{|w}yt}~{{{~zx{~~z|~~~y~yvy|ux~{{z~zzww|oluyzwx~}~}|w{xuv~y~|}|xz|}{~y~wt}ux}~t|~{{y~||wyzrzwz}wz}~~uvtzxzw~w|z}~~|{}t|~{xuzt~{{|}x|v|~{y{xyuy|{{|}|x|zyzz{kzo{z{|urwq}{{|{yxy}~{yz}{|v}y{u~}~wy{~}}z~x~yq|~vzwzyzz~q}}}sx~~||}~~|z|~vvrwvz~~}z}l{{y~t|rv|{}yzx{|y~n|x}|xy}z}|~{|~zyn|z{x|xwv~pz}}{~}yx~xyzvpw{|{~w|tz~~|r}}y|vwyxz~w|}{~~~zs{wqvt}qzx}~~|}v|o|su~{y~w|yn|}v}|wqrty|zy~|~y~|y}}|{{{}{y}~y{|{~||x}~y~ov~}z{ytpx}u~~w|}bo}zuz|}zy}~|~|||x}|{xx{}|zw|}{|s|~||w||uwy~{z~ty}}~ww|w|z}{}|y|zzvy||nx~|zor~~~{s{yu~~}~ur|c~}}`u{{~}zzu|||u{~~{~x{x~|zpw{iw||v}szy|w~rk|ez|zz{|}zuo}}p~i}}}w}~}{w{{ux}|wx~w{x}}y}~~y{}s~z}|ywis~z{ql{}y|~~v{}s|t{~z}z}u|~w}y{|xz~v~{~sx{~|}~zu{}z~|iz}}}y~vz}}{}{~zwzty}xxx~|~}vx~wv{xz|x}v|||z|}v~}w|z~z}y{yxzzy{t|~zxr~t{|zdw|~|z}z|{w{w|}z~t}z{y||{yv{}~yy{zp||{~zviiy~}}yw|vs|||zw{z~|}v|ztvw{xvrxovu}{{|x{{sy|~|znyyt{zxy{{|w|}nzm}|}s}}y{}zs{x|~n|u{yvxz}y}}{|}|{|z~~uz{xxzz}|xyzyznz}w}y{|{v|sz|{|~}}x{}v~uw~|}{|}~u}su}rvx}}t}y{{{z~}uxw{zz}}z~~|z{xq||{xv~~~|wv}}t}|{{y||{{yzv{}~|}{|}}z}|}}wn}y}}|r~|{{{}zy|y|v}||z}w{p}sfxzy}y{n{~xq{{v{{~~~}v{xy}}~w{y|}~}|y~|y~wzv}{{~~v~}y|{{~uzu}k}|}zy}|{x|zx~w||{}u~|w}{}}wyv~{~~~|{x~v|y~vz|yu}~z|utuxv|yvx|~szzw~||x~yw~e}x}u~|z{{|~v~}|z||s~xsr}o}|||~xt}~wu~~xzi}}w||~|}v|~~uw||g}~zw~y|wxs}h{|z||}{|y|v}tz~y~~y{x~x{y~~z|s~||zz}~}{}l{z|zl~z}}{||}q}~rv|xtx{y{~uxy}wzr}yz}{~yu}w}|v{vy~~uz{}|y~~{|x~|{{~xx|u|~|{tz|}w{zz}{~}}}}|yx|~y{}{~|wx{wv~}z}~iwxzz~x~yy~y{zoy}{{|w}}}}~|{{x}{}x{t{t{u}u}y|ry{u}~{~~xxsrk}qy|tz|~}~{{}{zw~ozz{}~|}not~q}~t~rz{}xw}~~}~y{}u~{}~vgw}y}|qzzy}y||}syvv|rw|}}s|{{{}z~|y~yp|}w~{zt}w|yty~x~{{|x{}xu~|{y~}}~{w|n~z|{~{}wq}}~z~v{}}{t|{x|}{w}y~|u}~{yw}}|~~z}}z}~}}~|z{t{{gww}|~w~||y|{y{zk|z|wyvyx}}yy~{|o~|{~|~ty}~~~h~|~|p||w|{|y{~mx{}{|~{v||~}~wvz}y~zy{|zu{yu|}}||}}}}}~y~~~tws|x|k|~x|}ew~{oyyyuy~zy||{{~~{z|t|{w~w~m}u~}}z}}{{}y|xw{}~~|||~uy}|}}||~}v{x|v{w|v{{|}}v{wwz~y|}{zy{~{|~y}qz}{v~zz|t~{|}~x|~}toyv{w{z{|{|zy~sz{v}{z|xo{|{y}|~y~{~}}~|}|~{z|}y{||~{l}x}wx{~|w}u}s||}~||q}~szsyz~y{zzv||}y|zuy|wqx|z{~xmyx{{~x~v|~}|vx|~}~syzzz~yuz|w{}w}th|}xx}n~{~~oxy{y}~vv|z{||n|z}r|u}w|~r|{~}~~}k{xv}yx~}z~x{zz~}u}~v|}r|~}wz}z||x}{xr~z~yz~zm|}z~}|~{}~}|zv{{z{{}{}}x{{~x}xwyyv~z}r}{svxzzy~zux|r}|z{ux|y{|~|~s{vy}~yy}}}xz{~{~|y{yy~}t}y{vwxx||y}~{|v}s}t}xzz{~uy}s~x|yw~y~~u{|s{{yv|x~{v|{}z}~|~x}||{wz~yz|}uxz|}m{}{}wz|y|{uxu~yzxu{|~~|q|ow}w|x{{w|}{{|{uyzwx{{}}~w{r|z{xy{|~{||}yxzx}z~z|~|z}{~~vrxz|}z}v|}{}{r}w~y~}t||q}|v}}}u||~}}x~yzz|y}z~pvw}~{|w}xynmy|y{~{s|ry~x{}~~}|{|yv~||t|{vywx}~|xz}{t}|r{tw{~w|{{|x|yrwy~~}}yv|yxm}{vz{x{xz}{|y||xqz|}y~xyzvzy}wz{y|y}xz{z{{mw|||}w}|y~{xy{~}{|w|~||vzy|~~}z|oz|{w~x}~}}}|~yt{~|y}vzxo|vq{|~{uyx~yzxvx}u}yv~{}~{zyy}{}wx|z}|uyz~}~||q{}zvxx}yzzsqy}qt}}}~}|yusz}{~|{{y{z~{|~}wx{zzzu{}yv|x}||~zwjzzq}y~|{y|~x~~}~w}q~y}|~{w}{~{{y||{}|x~zx|z|z}zw~~{|~~}zry}z~w~{|{{{}||{y{xz|~uw~~z~}|y~u~tyzq|yyy|{w~~zxxt|~k|{|}|~y{}tw|x~w{zxz{{z}z~}|~vy}tztyz~wn}{}~x{{}~z}}}wyzuv~|zz|uv}w}}wt~p~}{z{~x|{}zq{}z}y~j{|}|otyt|y|y~{|}}vu{|q}w{w{{z|~}{wyuz}uy}~zzl~|~~x}w}z~|{{~{swzosxz~}zx{{zzu{~|zyy{y{t{|{}}z}}s||qzzz|{zw|ryu~{{}u~x|v|yy|zvvvy}z}yvu|wsz}yv|u~uz~}}{wv{}s~|{}xzv{}{v{}{|vz}|}n{zv|~xy|x~t}~}~{~~vt~ww~~wyxy{f}xyzw|y{z}}~}uz~s{yyzwtzt|wy~zwvvy{z~~zu~yxq|~}}zus}p}u~vxtys|}|z|zyzz~vvs|}o~y}xzz}w~w|x{y}x{{{z|~{}z~t~{x~v}}|wtzyz~}x~}x{}zwz}~zv||zqs~||w}w}{zywphx}~wt{w}y}zu{|y}~v}}}}{u{wdxv|{|z~zvz}|zzowo~z~~|y}|z{x|}u~|zt{x}}x{v}~|{vwz}vt~z}}~s{}v}v~|x~w~o}{||}}}~|}z}wzv|h}k|z{s{||}yx}{||tm|x{z~~}}~o|{z}y~z|||~{~{}y~zrv{~qy~y{|y{{}|z}|ytzx{y}n|~y{ys}qy{}q{x~yuzzys~}zz|xo|}x|~q}xx}z{|t~|k~ywu~z}}z|~sypx{~|ux|{pyr{}|sz~|}}|ruvopxgxy}}{zy}u~r_}yy|w{w}vzi}|}}u|~w}rtvwpy{|uzozx{}~qw~~sz}~|~y}}zyt}z{tyy||t{{}~~}z|wz~xp{{yzxz}z}w{zy~x{z~nzx|~|vzq|{wx}v}}w|~y~|{szry|xu~~x{~x{~|o}}||{}z|{upqqvy}~~l{~y{vt~tvy{{~z}x|{|~q}z{~wvtu~}}}yy|{}zx}~z{{zzt{rtx|y}}|x~}{{x~~y~~~z|}|{|rzyz|p|}krz}~~|z~}}w||vyrx}y}~uyxw{~}zyyzx~}~~xp{x|z{ly}ztvzzz{{}y{~xz}vwy~lxy|}}~~~z}}yr~yu{{qt~uyxz{}zw{mv{|{}u~~w}u{}s|~|px}x{nxu{z|r}{{xy{r~zw}z~s~~{~{{|yown~z|x{|}{}gzp~xv}zpzqu}x}x{n~|n|~vw{yv}w~u|x~t|w|x||xj~wux~}{zs~{}|n|vq~~z|{}|p}{x|~v}}{}t}}v}w}}~v{y{}wy~yxm~~u|~w{rwqszzs}vgz|}q{|uyw|ums|w~~}v{{u~xtizu|ywu~{ovu}xv{~~qzq{p~|y~~szzwy}zvxsvz|||{|r}z|~|}}||rxuvzzpv~}wzd{t{txutuv{y{wy}{}rtpkxv~~~w}{}}|~y~~tz~{|yu~~tuywsy~vu|wzzr~}|z}ruwtz|r~{~~}|w~~z}|yyx|q}y~|vsy|yw{y{y}}~~|~x~~y}{w|~~z~~ssx{rzs~v{z|~zy~~xyyv~~vw~{w`w|v}zzv~z{w{{z}sz|u{u}{yz{|{wy~|~|~}}z}x{x}z}t{|}{~|z|{{st{w|{y~}}vz{p||z}u{zwyv|}|~yzz~}x|{xu{rzy|}{~}~{qx{}v~x|qz}~y~}~zy}{}ww{y{x~xuw~{~|z~y|{|~y{yw}|z~||y{|p~||{v{ruv~sx~z~tzy{}t{}zuq{y~|{|}}yy|{~xyzzz{}}w||~vps}}zyr}{~{{y}}}{wyygyz~m~r|||wzt}z{yy~||wyxzyxz}x~oz}~{}{{u}|wp~~~e}~}w}|y~}y{l|z~~y{~{{v~~}~yzws}wv{mty|s|ru~{x{~|y|s}|x}{|s~|}}wzz~|~}y}p{~}wzz~}w|~y}|{y~~~|}}}}v|~}z~wxyz{~}{t}||z}jsw{{}z{~u{~{x|zy|yz~{x{z{lz~yw|u|~us}{~w{~~|rx|zzw~t|~~{ss{zx|}u~{}|{|{{}y{z}}}pyz{|~{~{|dww~yxy|x|w}zm{wsysw}qq|{r~uzwzys|z|}~|xsy|~w~yzo~w~|ty{~z}~~||zlx}xx~t}}|}xms}y}~tyxp|d{{v{v|~}~~zvy{{xx}y|o|tyszv~zzz|}~|}{zy{w{x|qzzy~xzyw}yx{w|x}ty}z|tzys}z{z~v}~|{~|}}zx|~~|ywvzz}~rv~}}yyty~n{~|x~|x|zv}~ux}s}~||v|z|{y~z{~|}~w{wvztxz}pz}}~wx{}xt|~v||}~xw~z|}{x~|{x}vxz{y~y{zw}y||wt|y}}}xo~vsv}x|yv}y{~z|wzy{}zyz{w{}wt~x|~xrv}{}}z|}|n|{z~}rzyxv|}m}yzy{y}qyx~uyyz|tsvy~s}|}|}~}x{|zzx|z~n}}z{x~|{|uz{p|}z~{~||y|}yyt|q}~{~vztxyy{xo{xwt}wxzx|~y~{~~z}|suyuy{u||}y}}yx|}wy|}vxv}|}v|{zyx}{tx}{x}|}ul}|z|o}z~~~{w}u{}{~y}{|}yy~zvv{zztv}||x{{~x}~s~z|wx~wu~}}z}{|~}}z}||{yyyy{~~~zw}|wz{|~~{x}~|{}{qy}{x{|wxtu}yu}|v~}x|x}}~~vv{zzu}{}y{|mz}xz}{{xv}yz~|~{ut{xzys~xwyxp{||{z}x|w}x{}|v}|}{v~||}}{{{wzn|x||x}{|{ux~uv{twzx{|~v|}~z|{|~{}{~u{{xzov{}zyz|{{~}yzzy}mw{~w}z|zrx{|}{ws~}|zpw{yy{u}}r||wzv}~xy|v}|}y~~q{~x}}}zyz}w}~x|{zyzz~wx{{|zyxq{~~~vyz|y|wzk|xx}}|z{vw~|z|ykv|zyz|t}x~{y|w|zu}}|~}x}}{~~u{|r|z{x{}z{|w}~y~|{|w~q~|{yvy}{{qu{}~{~c~}|tz}}v|}y||{}y}z~yu{~|wws|b|v}v~x||xx{qwxtu}|}~|xy|}||{{y}z~{t{}{y}}zyuyzzmz}||x||{z~uy||{tx~~}{~~z}}}x||z|r|tx|{zy~~yx}|xxzz}~v~qzzx}ujz~vs|}|tv}wvz{|zyv{v}x{{xzzpv{{f}n|w{z~xyx~z|x|~vz~}~x}~{pwp~}v~{|{y}xxpuyyz}|z|{|u|q}{v}yt|yuv}|zvzy{|z}||l{xwyz|}|g|t}~~|yy|u~nu}{vy|ix{|zyvtyx~~yvzxzyxw~t{{{xy~~{hw~}w~|xp{}xp}~xy|pty}y{wqiv||yy~~r|nuz~{wkuxvwr|v|{x|y|}yv~|}nzxty{{yny{~{~||x}x{|~nyzzw}|w{}u~~wy|swx|}wybpxz~c~t|zsv~|w||{z~{v||xav}zy{|trvw|wszu}~}~}z~twru~zp{}}ytp{o}vv}z|xym~szwy~{y|zuyw{}yxszxyzyy{zv{}t||y}}}~yx{~||{~y|wx~|z|y}uyw|r~y|{|{~urzx{zw~|{yzx}~t~~y~{{~|yvv~y{~y|}w}zxxu~~rv~~|x}uw}}w{y~vy|~}|}yv|~xz|}~vwzw~}u{}~w{~s{{yz}xt~{nt|{p}[}}~|~x|~~zxr}y}rz|qzz{~|{zsyww}}{zv}yyxzuu|||u~{yz}{}~||y~|t~|}x||~t{||{{xj}~zw}y{v{tt{~}v}w|zq}sxz|}{|z|syz}z|zy{}~{{~y|xy{xz|{~{zwt~{x|z{~v~}|}|}y{wxx{{}}w{z}{~|{|yuq{|~|xw~}}~xpyywxzywx||{yy~v{}|y}z{y}~xs{}}{~~t{vzy~vxy|zvx|~r|{}z}~wy}|j|{~|{~x}}{x{zyz~|nuz}zy{|{~w{x|t}z~x}w~|xy{|ry~}~u{||~{~|~xxz|yvwz|}{vz|y}}x{z{{}|{|yx~{{zyxy{~{u~|{|~~|~}t~}sz}v}w{~vv~sw|zzxz|~yx{}|z|yo~vz}}q}}~z}{~rnv|~pxwzsq}y~}t~|{z{z}~{sz{wsuiy~~w~}}{{qu}~uxqzzt{|~{~}zlv}{}{v~x}|||}}}~x|{y|k{z}kz|s|{u~ky|gvnv~|wmy|wt~su|s~{{}suv{}|x|~{t||{}}y~pw}wwuz{u~{j}}ww|m{{x~~|q{szz~u{ywz||ztx~|~}}{vsxzs}{v|uz|||n|zl|wwv}{t}nzwy~~yz~vwyz}{|~mo}~z|zw~~}w~xyx|||yxtmy{t}yqyxx}yr{}||zyz~vuw~}wz|}|}u}wow|uq{z}z{}t~wy{uw|}syuxr|~z|ux~r{||}}~p~s~y}swy}~v{|}~{t|rx{}~n||w{y|v|{x}~x}z}z}x~~|z~x{~{xxuww~~zt|v}x|zrzxpuuz}y}yw~}svyrysyx}w{~{}sz}~v~~x~x}~{j}x{z{tzpw~v~js}|z}tv}~}^q|xxvp|rys~y}jyyv{|{{x~}~x|~w}t|x~t|un]yz~x}x}wyrzuv}k{\{pz}y|ss|uz|{x|lt|}w~~|}t{{r~w{yx|}ts}^ww{}|~~wy|zxv}wk~{r}x~{~}|h{|y}|{mzyvzr~iv~~tzb}zw}rw~|v}vy~{o|}{{~|xtx{ytz{yz{tzy}pzzy}xvz~~w|||}wnxkz[}~}y{v}gxz~py|||{}}}v|y}w|}}{{y}zzx{|wr}q}{yy~z|q}~z~z~}|xv|z}|x~z}}|}z}y{xw}{{|{|}~y~|v~wt~}}w}~wyzy}{|}~|}|{}}{x}~}|}|z~zzv|||{~||w~s|{y|ywr|z}~vzr{z~}~~u|~|z~{}x|}|w|w}~vws~}z{}y~~~x{{{|r}oytvt|~y}~y{}|y{|z{|v|||~x{|yzx}|xw}y|~vx~txw}zp{|~zrr}}zyvwu~xyw~{}w|~x}|~v|{}~u~wzz}{}q}|{}||u}{yu~rw{{~}vy~vw|gyuz|uqw|m~x{wp|tmzvywx}}qtyvz|xzy|~~~k~wv{}T}u}rzzpz{x~tzxxw|zwszxxxxzx|u~z}wzxtz}r{xwxtvw~}}tws~xr}t}zzy~pyvyz{}ows~zz}yx}}wyvmzx}~u{}{vz{zxxuyqyx{}~w~xu|{~zwyzx~~}lws~~|z{|z{xw}~uzw{prz{|~~wszz}|}|}|{rjzzxs~|v}~w}u}w}sszr|z~pv{ivww{zx}|wwwx{|n}}uss|z}~}wwutxzlz{|}mp{{m||nyvu{ry|}wx{u}|y{|~y}uzz~~}wzs}~{|{{}|}y{{ztz~q~xy~{}v~|vzyv~z}z~{{|{y{z{||gsw~~j{}|~~}z|}}m~y}}nz{}|x{u~z~}{~}~~x||}}x~|||y|u{zx|}}~z~}}z~~~~p}}y}~z|}{}{|yz~wys|||}}}~|yz}|szwx~xy}y~vu~zp{tw{v}}~~}|}s|z|{~x|{vxwz}}t~||}yy~{ysyz~~~x|{u|yu~s|~}|u}s}|{~}||z~}}{w~{~}u}}|~~}{yn~u{y|zyvx|~{yuu~}|s}r}~x|yy}z~}||qz||z{uw~}|vynyp{}|~{}}pyzu|g~~wnz||y}}y{x|q~su~v|y|yzuzxo~|~uqy|}w|vxzvzkx|mtsuqxvw}}}x}}~z~zt~}~{lpw~}wz|~zwytyyrxjvyys{v~}s~|zyzv}ysqyz{tz~}x~s{|z{u|xy~}|yz}~xr~zy}x~~uv|xw}gzuq}|x|}ky|v~w}}{{}yqy}xpwzyzv|rxsgyx{w|qw}{hyyt{}ry|{z{syws}wt|{|{r|sopv||wz|tu{x|xzy{wxzzyxzwyz{}w}wjz}r{~uxv{{y}tz|y~wrr}{}t|tuxx{pl{qt|oo}s{ny{{wjz|z~pttuoxyqwrywe|skz|{{w~}}~|zu|~x}{}|y|~{xsz}vwa~x~y{|fx|}wwvy_wx}yy}v{y|vwyuwr~xx}zry~oxxuzw{z{}y}xq{wm~nyq~~ryy~~qpyot}~~x|yvuzz{vq}zw}~vw~ywz{|wyx{||{ktvx~lgnwyzyzy{hvww}ywwru|vyzryqrtt{~y~{ty}z~~|{||yqywx~l}vyr~t}vzt}{x}wzvy}ytywZ}rw~uzw~`{z{{zxvx{{~~~w{zzxmzzx}~}wzjz{}k{d{w||m~zugs~|x|{|x{}}~}v~ujyy{yr~xzxy~ks|y|}xxz}xv{xt||v}rx~zz{{yzy{z}|b|~~|xz{qpq|{{|xuvz|~}rvvxxzp{y}{~{iuss|{tuyy|||x~u~x~}~qlw{{{|x~t|}}~{~nz{vgc}|p~~u}{zxz}|u~~xzzvp|{}r~xz|pzuy}zqvv~~yxx}|x}yzx~r|oyxy}||{}w}~jw}|{{xxy|}t{{y{}~w{z{~~{}|t{w{txx~y~w{{z}{v|uv~||u|uzu}yoyx|rxyy{{z~|}z{y~{k|v}x{wz{|yvxyq{r}w{}{r~uvzx{xz||}xuh|K~zz~m}vzX|uz}xz|~|r|rozpxwy{y}p{}xt~{|~sy}zv~}xru|||~vs~y~s~zqrw}}urx~vx|wx}~{{~ku{~zmw~s|}}{y~}{{w{r~u|{ql~{yxz|qzs?|~}|~|ruzz|x{{{rx~w{{y|~|\yx}sx||wwz|rzx~~xz~s~|uzx|sw|_n|u|e{{yn}}p{~}||q{{z~{y}{{vz{{xrn}w~z|v{yqw{x|~}{}czzxxzzv~wzz}x|~|yxw|{xx}l{~{|ge~yw{qv||zzxyq{x}{n{~~x{~}z~xy}q}w|uys}n|wz}|y|t~vyy}r|xn{wx}|z}x{s~|~|{}|~z}xz|zy}ry~kx~|x|xyw~|Zu{~t~w{~}}{~|ny|~y|{m{zr}h~{~ytyznuy{t|w|}m{|yyyW~v|i{|uy}zzvt{}|~|oz{{~vtw|{}|~tzw|n~}x{{~}s|ux}{}}vxwrz~|t}}tzv|yyx}y}umvtywytzx~m{|~||}u{{~{zqs}|x{~x{w|xr{{zv|}o{|~{y|wz|||}q~t}z}|xww}s}~{~~vx~~{}{||~zz~{xv{|~|}zz|{u~~{uqv{~~y{~{yuxz}wv|~x}|{~t{{ysy||pvxy~x}`{^~y}q|{|{|}p|y|v{xtt}~y}~~{txz|y~~xx}~}|xut|}ryx{}zx~{r{q{~u{z{~}x{}rw|y}|{xtsp~|~{x{~zw~{~}i~rz|z{q}}~wyfzwy}~y}w}z~|z}wn|vzz|{{w|}|}}rw}~x~t~|~y|vx~|{yv|~vy}xx}~{||}|y}v~|{x}j}z{}u}u{y|r~ty{x~xyzyw|v}||uyzqywyyvsyx}yw}{{|zv}~k~}}~z}us{}ywu{zw{~y|zuvw|{yzz{wz||kuy}w~x|||{}}v{y}u{}|}vz}sxuuz{y}}~{xss{}}xxzq}{||wu~tv{pzy{ux~~yxhn{z~}v~|w||}}~y}~oypw|n}~x}u~||v|{}}}u|{y~z{sy{~}z~ew}u{{{~tz}y~uz|z}}~x{xp{zy|}{n|tx{x|~}|||~{~|rq{}trtvzztqvzx{yy~t~}}~twxy|q~~~}~|wx}|nzz|z~{}|}yw~v{vz~{}}y{xyw}{}{q||}x~|~{y}wu~z~}zvz{z}}uy}|ju}}}z}}~rsx~|xz~{|}}~yy~|}xz{~y|p~~z|y}}y}zz}x~}}}{}}~~||vzwx~}}~wvz{z}xv~{}}|u|r|}|z~}z~y|{t~~v{wy~z|~~~y{|}|}x~t~}yzzr{z~{||}xy{{s}xwyz~{t}{|w|yq}yy}|~z{|zqw||}y}|~~||{w~}{{||{v||~}~}}|~}z|xw~{~}wyt~vdxv}xx}vz{}~wy}{}~}~||}v}wqxy|s|~wz}}|z~|~|{x}}{~u~{{{|{x|x}{uw|}|t|{{~qzyszz}p{~z|}~y|~|w}x{~z|w~|x~{|r{|vyxxz~|tr~|~~|w|yywr}}~~q{x~{{y}{z}t~}||}x~{}z~}qhzkxy~|}~wu|m|{}vy~~tz||x~|}y~yynt|y}z|q~|v~w|zt}}}~|}yvtwz{|x~}uwt{z~}~~}{}z}}{n||x|}~}~{}x|}|yuy|y}q{{|{|{}{zv|t}zr}}~~~{~zxxy~{}vszwu}~|}uv}~|~{}{xv{y|||v{~}}|x{z{}zu|v{x{|s~|y~~{z|uw|r~|||tn||}z~y{yvrxzvz~}}t}y|{t|}wzt{~u|{yxxztw|v{~}zz~{z|w|vz}|o{zyvz}|zwy|~|{}}uvs{w{r{v|}w}z|{}||v||u~t~|yz|}{vvy|~}p{~xz||}uzs||}{zz|yu|{w}ymz}}}|xy}}r{y|{zyzn}|ov}|~|yr|yyxy}}z~|~}y|uu}rw~~zzzw~vy{~~~|xy}yzzytz}vyu{}~y|}}p~z|||}x}v~|x}z}xwz~t}w{}~~}~}x|||s~{}s~uwnz|||swtv|yx}z|~|{{|{|}|~~nw|p|uxzvqv|s{}tx}y~uw|~{{~|}vt~xus{xz{||z{}|{~~ly|}ry|{}~{~{~{|{||}{~|z}w~}~xy{~y}z~|vuz|z|u{{|}|~}{ypv|o~u{vw|}}{yz}yv}~x{w~yz~|}}|~w|}|yw{w{~~{~u~zy|s}zz|{|qy{{y||s{wz~~{s}zpw|{}{x~yxxwz}{t|zyyy{|~{|{|}xxxxz}y|}}||~z~tv|zv|{`uw}{~~|v{vzvr|z|||}}}{t~|u{yvw~{z|uy}}vzw{y|t{zv~}~~{|xh|~xxvvz|u}{z{~|{{z|{v|q}{yz}t}{}{||z|n}v}~yrzss~}q}{~y}~s|||q|z{t|}}y~||~tu|xz|wxz~~txyyyw||zxx|t~{tyx~q{{|}}z}yz}x{|rz{z~or~|{}v~y}}vw{{y~~}zzp}|zsxp}}}pz|xw|qxk~uu|}{yz~~sz|}yzz{js~{y|z{u}vzqxxzz{v}k~zz{zz}|{{yzu}zt}z|}yy{y}v~x{zu~x|z{~z||yy~~~}|xw|x~|~y}mw~{|t~}s~zx|y{~|z{|zx}uyx~}|~ul}uy}z{yy~~y|z}|yuzz{v{su}{i{}||w}sy~zv~vxw~{y~|u~{r|}{~oty}yyw}}x{|{~}uuxxx{{zy}~}||z|z}|~}x|o~~{vtz|}rym{{z|yvutuy~yz{{{et~~o||xwrwzzp}y{yxx|~{}|}zqsyy~}xu{zqv{y~v~}}s~yv{z}t~}w}{ntv}|yy}~{yyy|}{x~y||t{{|{{{||~{qmwsr}w}z|uyt|{zy|}~}t{wx}}}z}w|vt}~w{|z}{tu|~z|vyv~|{}}|zyx}v~}{~z||w~}}vrvu|{|y~yzzz}}}}nv~|z|||x~tuu}~{{y~zvy|~~|xs{~{|}}}~uu{~}q|z~|{~}{|z~y~xv{wwzy{t~|~vy~}~{}}ywv~{~~zwx{w}rt~p~s|~t|xu~{w{~yw|y{x}}w}|~~yy{w|suuw~|{xzy}||q}|}y}}}uxxs|yvz|}ys}xxw}tszz|y}r}yxy}~|ot~wzwx}~twzy{~u~|vux~p}x|yx}t{~~|}|zzxv~w{~~||qx}t~|vyxt~w{}yw~p}xwxy~yu{zy{}xpxv~}|~q~|yz~||w}|z~x}x|y{||wuuj~zz|w}x{|yxz{yz~~}{~{xzq~{}|y|||{{ux}~}|{}t}twz{w}z{|z}~tv|~~}}y||~wuuy|}|t|y~zq{z|{{ux{}z{z|x|zzy}x{xzx|~xrrzx|wt}wt}zy||}~tu{r~v}|}}{zy{yzx}yw{yox}~{|ws|zxx}{yswu{vw||s}uvrwzzz}|zpy}z~{|zzywo~{|z|~}|{}m~|{{{z}r}}}|zqyd}u{{~zs~xy{v}~sy~z|~w{~yrxzuypyztu{}{}v}|}{z}xys~ys|zv}}|vy|zuzx}tx}y|{~}ry|}}tx}z}~{ty~y|x{}|{}~zr{v~y~z|}x~}s{z|wzx}~wx{}wx}~z|zy|{{}}xzzz{u|wx|u|z}s{z~{}|~{}|}~ux}t~z||wx{y~}z|}wzw}yvzzrt~{}y}wz~yu{wzp|{yq|w}}xyy}uxz}zwy}yzz~z|}~t|~}{{z}xyrzux~}ux}|zx}zxz~w{}}~{x}}{}y}u}}|z{|{x{w|~}~~}yz~v~z|~~w|zx{}z}{utz{{|{||{}z|~{~|~}o{|vvyz|vzywq{w~||uyuz}{v{{{zv{~|z}~}~zw{s}x|z|tx{x|z{}x}~zw~~~~ywwu}}yy||}p|~|~u{xx{ytl{|tw||}~tzozv~|yz|}tz~v}t{z|x{n~~{|v||y~x|}~z~~{|~}~yy}~vvuzz{{{zzyw{yi~z}x{yt|~}}~|~~x{}||zz|{p}w}v}xzwv||||{{s}ztx{y}vuyw~~p~uvwww||}w{xz}~|zzv}}xx}{z{sz~x|w~{{{uv}y}t}{~~~zyz}~}vzyumxx}}tytwv~{t}s~|~~~s}zwpzwz}~~~}~}u~u|~||~szzuv{vzyxx|y}{{|~|ucyxtpx||v}p{xq~{wx}{~{~z}{xvpu~v~}~}y}{uiywx|{~{o{y{}z{x}}x||u|t{{wvxz{yyo}zsyu{~xyw}~z}u}}{zy{zt|vy_rxwz{|sw|}vyyxtzy}trn{y{}zz}|sqxr~~y|v||{u~u{zjrwwt}zyz}yz{wzwwp~}z}|txw|zvz{}pzwx|x~{q~~xyxvpy}zz~ug}u|{|~zw|}r~sy~S{~tyu{zlxyv~{|{|{vzyvvy|[xwyw|xzyt}z||x}}{{}xv|xwyvysr|wz~{~v~y}uxz}u{}qtzxy}}~oy}|}xwz|z}|yy|wszz{|}}}|x|zuzwt}wx~tu~{vz~z{t~|~m}}~woztzz}vuz|}pu~xt|z{j||~{s}{yur|v}my|xpyuw~}~}|~zw~a}z|tyx{yuqqK~}|}}|zyz}tx~{yz}~xt{|~~ysy}~}~|{z~||wnw}~s}z}z|~{}z~{p}~~~~w}~|~~~v}w|nuy}zz|yv|uyzv|{yt~zsyz}zyp}w}u~o||xp}r{w~}}u|{~|wvrztv||{|{{~w|xyq||o~~~xz|~}}k{v|~ym}}}{ywz~}||~~{xw|xv|{}|}zxy|{tz|xs~o~}u~~~~yp~{|z}u~}i||t~~|}|{{}sz~|~xz{}~{}{y{|v|}}{s{zuys}}yx~|||zxz}|vv|}iyxyo||{~}xv{~v{~{zy|xxuxx~~t}|{x~}v~~w~y||~}}|z~||z}x~~zx}vl|~|x|tw|}w}xvr{ssuzyw~w}z~~}{n~~w||w}}ty|y}q{{~u|i{|~{t~}{xzz{}q{t}{z{x|~||wx}}zy|yq}||zsy~x|~yr|vyws|{ww|rty}|y}~~~|z{}~~y}{~~}~y}vz}yzq|}{{||~}~~|t||ws}r~v{t}}px|zv}~}x}{yxzwzu}zszoz|~{}utwz{jtt|yyxso~}y|t|}{y|z|y~|wwquz}y}|~|w}w|{wyutzyv|~v}}z|wu{z~~y~}|{zs{t{{{|vz{vx||vx}~~}}y|zxz|}{z|y~|z{{}z}{{{|{~xxzw|yw{uz|}{uw}~yy}s{}~|~uz|~}~vzs{y{{{{zv~~vz~~wywpzs}}|}{~}y{n~yw{u{z{|w|ruz||wz}vyz~vxxw{{}t{p|~|y}{}z{y}{w{|y|ry{~t~|}|}~{yzzv~{xx||xu~w|z}}tuywyps|||}{zt}~vzv{}{x}yuy~yz~x||{{vy{yx|{{|}{y~{||xx}z~xp|tx~~~t}}ox~w}zu}}|vz~y}|}{yzw|~~yqy|}z~|}xz}|yzz{~z~~z|szuyz~}{k~v|w~||wx|y}k}}yz|{v|wwvr}|z{|~~w}|y}{uyv{y|~|}z|}p~szzw{z~}ezx~t}~uol~{yzty}{|{xyw{vy{zx}|}tyv|~~}zz{|x|{r~|~|z{x{y}v||xul{w|{{{z}xyowx{{}{y{||w|~l~v~~{v~u{w{lyw}x}xw|x{}xu|zx{~~st}{xk~{s}ryu}xozur}v}u~}z|{v{y{}v~}xv{}z}zwzp|usy~s}{zlzvzx}wy{{}wr|||y}{}}w~|~}x~}{z|xz~~{~|}z{sw}p}{vo{yvi{~rz{|xt{}{xyz}vss}{w{zxy{}sq}v~w{|{}|vwy|z{{zc|zu{~{ytvxutz~y}v|qx~u|u|}|z{}{zryoy~zycyx}uu~~~|xs~l~~w{y|{|vuwwz~z~{sz}{v}yr{x||}zvtwkvv||w|zz{zh}zxxz|ty~zxwt{y{{~|{zyn|zry|vx}z~{y|{s}x{{y~yyhux|uxyzyz{~z{w|~}u{~}~}v~{~x}{q||~}w{mxu~}}z}~||z}}{~z{wx||x}~~tu{ut~{}}u~~~}wu{~k|v}xtz|{z||~xz}zz~|{|z{pyzy|w}{t|y}xu|||x}}~z}|y~xvy||~vmu~}yw}ryvtz}~y{|}}v}~yyztu|~|xyt|{vx|yx|z{||t~u}xy}}w~x}}xt}|wjxxvz|{}{~|zz||}}x}ezut||t~wwnu~l}}}xyvy{rtizxz~u}~z{~yvl}{z{|{}|z~{||zz}|||x|y}zz~w{~x~{x|~y~}zu||~z}{y}zx}}u}~yx|u|x}v{~xzzz||z{~v~|}{~|}~}z}~{y{z~oz|{u~|{y~zy|{{}|yzxyxrz||}x|}}|}{}{uoyz|{p|v~zy|znz{zz~yxw~||~mzv~|y{~y|}{y||}v~y}{ty~t~t}{x{z}}}}{}~qyyx|}{zz}}xovy{~}uq~{}}}|{v|xv|}}~~o}~{z~z|vx{~p{~sy~{{v}yx~zwsz{uyy|}||zz}uwy}y|x|zy}yxy|yuz{y}w}y|ww{}prw{v|v~zu|{}~{rz}~z{vq{|{}{~txy~|~|zzz|{z~u|yyx{{|y|||w{y{{|{|zp|r~xox~{|u||}|~~q|{tx|}|{}zxv|r~w~xvmw|v~|||~z{{ru}x|~tvy~z{v||}}~{|s~}yy{|~~z{}~u|}wz|sx}{|{ux{z{y~t~yu|[{||xt~}}}~}~~uy~}~|z}t{{{~~{}zu~~|zyx{{{}~}zrw|y~p|}uq|}x}~}qn{wy|zwnyxuyywnw~}~{~y}|~ryz{{yzvxyry{~}|w~yu|}|}z}|y~~z|}|{zv~z{~~}}|l}q|}{{~|z{xz{v}}z~{||{|vzwzy}wy~tzwyx}|y}{t||{}{}~vys}x{}w|{y}}vzw}o~zyzn|w||q~y}|~z{}}{|zw~z~~{~{w|v~svy{|{y|{xx~z~~tw|}}tv}~}~{~{x}w}~p||}|ns|tsx}~~|}}w}pq~~szytr|~u~~|{{~||y|~oe}v{}y|t{|zzq}{o{xz||~xz}~~w}~}wyzwy}y|y}~~}|xv|~s~w}v}uxwyy|||y}}}{}yt}~|~}xuy~y{}|z|{}{n|}|}v}qv~}ytv~zuu{~~zwy|~{y{{}|}~|s~}zw{ryzz|z~yx|z}x~r|||z|zy}l}|{y}zz|{y{ww}uy~w|q}}x{yy~ky}{wztqzw~y|wvz~htrz}~}{v}{|}smx}~{{~ve}z{}v||~v|{{|yv~{u}|{y~ux|{sz|{|~t|~}{|u~yuz|v}yv}y}z~{y}w~~{||wyyy}|t||y|sz}u}~~}zw|}uxzz|zYws|~y}~y}{wy~yvxsx}{x|yz|~i}{}u~|z~zs|z~uy|~ytz}rx~vusv|zz~rx}q{}ֆx}zw||{}|~}zs{|twv|~n}yxyz|~|wxy{}z}|}~xywz|{|v}~~}}|}}y}{svyx{w{~x{|xuz~~t||zw}|pQt{{yv~~yvvyy||zx}vy|w~{wxy}tzv~w~}txxy~~E~{~zwx{yyytuy}}{zx|yzx{|yz{}}r{xs~x~~{z}|x{|x~sz|~}x{w{{|~{x}|v}|yy|{}twxtw{|lx{w|ywtpl~v}w|vyzzzxz~~{r}s{y}x|~{qw~sw{q}{|yu}~z}~u}~~~|}zy{q~x~~y}s}yzu|x~zy~wv{wk{~uywx{ky~y}|{xy{v{zx|x|y}zz|vzv}wt}|zuz{zs||wq}zz{}}rs|v~wz{zxxxuy~{{|z}|~~t~}{~yx}x}{xzv|x}{}{yxv}z|w|{x~{~|~yy{yzww~y|}zv|w{|~z~wz}{}|z~}{xyz|{||z}m{w{~}{yztsw}~yzw|z{toxy{u}w}|~~{|v{zz{wypy~|t|kxvx|pz~{{~{}|zx|{}vmy{|ziw~zqzv~z{~{~}{}~wyv~zz~xyxy}yt~~x{yswys}z}{}~~}}yx{~ww}|x~u|}}{||{}y~t{zt}~w}y~v|}zqyn|z}gx{{yz|x||v~z|z}{y||~uvyy|vuy}s}|}woz|yu~y|k|wsfvw}y}ud~xwwywxz}wy{yzykxyr{t||zu}x~}}}xrwyz}w~||utz}xv~zq||zx|z{y|{vmru|yww~rwx}xzz||z{|yxn|{~ut~{q{mox{}|~~qi|eppu{wzzxz~zwzyqrx{|p~}~uzyz|oyu{}oryqzz{|zusrt|{uqt~}t{z}~|{|wv}~p~yvz{zo}p}ztm{z~|||wx}{xwkyv|}yw}w{yyyU~~|w||unq}q~}~vx|zqvozwx~~}sp~|ywn|{}~{}vhrxzr~~{zw{b|w|vsv|tzyy}xxtu}t{}vtutu{t||gu|||t||kzxzow{r{}|pyuvv~svt~}~w{vsuwvt|~zeyrxy~wYtuw|~{w~my~xl~}{|x{qw{{}vzy~~z}vz~z}z|v}{ty}v~|}tz|}lt{zx}v|y~~}zoxz|z}||{zz{|z|}}}zw}d|~~|u~oxvwovt~v|wyy}m~||tzy~|vv}|}ttxxr|}~z~zzz}y~||||y|{t||{~}|zs{]z}~{{twu}{u{z{or}~{z|~}}ut{lyzyt}s}}~hz|{t}x|w~x|z~xx{ty{w}tpv|}ry{y{~~{yx~p{x~zu|p||}}z}~vzjv}|}|xxs||wrtpqyy{~rzzyxzs}x{{tz~yz~}wy}z~}wwcrt|wxv}~q{|n}r|~{{}}p}~}z}}|}{z~~z}|u}v~|w{{y}}w{}z}}w|zsy|{{}~y~|ty{n{~{|{|~~|}v}|lp|z~}{||x||srq~}x{js|x{r}{~|zmu|}}}{zuxy{}{x{~}|}}~{||{{ww|y|~}}|||}||{yy|{vs}v||{|~uv}|q{xus}r{}w~~xv{zu|v{}}~i}}z}}~~zy}}}}y}||}~|}}xzvu~u}xy}}pt~~}}x{||{r||}lxw{z}}tnv~~|}xyw|~|q{zz}y{|~~r{xxs~x{xzx|w~zz{{vuz{||}syzyt|zx{}u{s~n~|x|vyxv|z}}{}||{}syv|yuqz~~wz~uz|yy|~}{~{}t|u~|y||~~~x~x|}}|{{{tw||~z|zw}|y~xwx{x{|yxsx~{sz~u~|}p|~}~{}tx}{|{{x~}{~v}zw|z~zn~}{}|yvxy{}{yy{zz~w}xzj}s{u}xy{zzyzztut}w{~zp}wx~x}}{}|z}~{z{{|~pt|zz~~}{|~z}z~wz|||~~{~~{tz|w~}}|}}w||u||oz|p|zyw}{~~zywyyzx|}t|{{w}|x~u~y~|{~y|z{{~vw{wq|y~{r{~w{~{}{|t~{|x|~}{z|~zpzz}{}{uzyz~~ny|xwyw|~{||zy{|{|}s}x~|~{~rwx|}|z{osyuw~xxxq|z|z}|~{~tzyvw||~{{vp|}~~|xxx|}||{v~r{hp~~|y||{~{|xzyg~}{x}{}mw|~ywu~}~vwz{yz~{~{~~y}|~wj~yx}{|x{|}|yty~r|}~~}{~w}z|q~ssp{~z~yx~||||w{{w~~{~}zzqw~yx|}~|r{}xy~tv}y}x}ztv|lxz{yy{|}|~~zx}tx~{w|}}y}w|~y~zvuw|}~l}z~v~y||{q{y|~||iy|||zw|}|zu~qsx}|}|yz}{}x{|~}yxw}{v{{~zj}|j~s|}y~ys{}y{|uxrz}}}xw{qtut{z|{|}|{z|~~{~z|zvz||us|~{~wzm~}{~rv|~}towjs|s|tx~yuw{}|}|yruwz{{v~}r{}swt}}ro}zt||t|p{y|{|y||zm~zwyr~{}u~|}n~{z|}~|~}xwuox|~||vz~~z{wzzz{}wwt~|sxu}}hz|u|v}u}uz}|q}}x~{zxo}{|mx~|vt|y}uyx}|wxqvw{{x~v~y~~`~}{}|w~sx{}z~~x}|{~z~{~~vy{wz}z}y~{}truvv{y~||xq~~||yy~~{s~xvvyuw~x}}~|~vvz{{~~}y~x~oxxlz|}z|}|x{}~{{|z}z~yv|pui{~}zzxm~u{xm}~w}u{|v}~x~z{xvx~k~~v{xz{v}|up}{y}~z{~v{|u~wzvwoz~}|t|~l||{|~}{||x|w|}vzz{ww}x~~}}~~||}zytz~zv{sw}~v~|s{}}~|{u}|~~}}{~vwu{|~{|zyz~}z|t~}x|x}~zy}w~}s~}{t}|~||}zw~{|{r|j{uy~~z}}~z~z{}}~|z}|{p~yr}xyxw{|~xsux|u}|}{|}z||pm{yy}ywtt}{zt{v|y{{zw}s}|{~~|v|{zr|n~{z|}xv|~vh~|~~|z|}{w|}y~zzp~w{}}uy{}o}~wyo{|vx||~~qz}|v||z}yvz{}}~yxo|yy}sz{}{~}ti}w|zwvxz~yytw}{x~xz~|}|~y{{yx}z}~~wrv|tx}|w|w}~{y|}y}||~}|}~~}z{z~s}x|{qxz{|~r~vy|zy{~vy|xyy}s|uz{~~}~vzz{}{~}||yov|l|y|zv}y}}y}zyx}xz~}|y|{|}xy~s~u}xz|~}wx~}{~{vyy}z}{~y~|w{x}{|t~uw|z}|~}vvyyx{~{~|p}{~|yyz~}s~y~xx{}}zx|}x~{zyy|z}}}|~{}|{wsu|{zxvzj{|}|}~{v~x{w{}}}zyyyx|yy~wy}|||ryt{|~yx}|{|~|{|}~{{{xm|x{~~|}}~yv}}~}{t}|~}}|||z}~|y~~||v~s~yy~}~~|z{{~y~|{{|vyv{|~||w}}}zyzwx|z|~z|x}v~{z~wzuo~y~{~z{wv}|~y|~yx}}}}zzv~z|x}uu||}xy|lxuz|xzxv~vv~}vy|y}}||~||~~ywwtx|xv|k~{wszz~x~}|{t{{}w~~~|{xwxxr~y}kw|{}{{|{y~z{zwzw||tyz|{r|~x{o~}}xux}|r|usztr|{w}}}zx||t}zz~~x}|{uv|}zwjyo}}t{{~w~}zo|x}vx|wouy}{{~v~waz|||vryfs~z{|}x}o}vuy~x}|xy}{xr|zwrt||}v~wx{{~twu`t~ztx}|~|y{}|u|x~xxz~||~y~}}z|||~|uor{q{xv}vy{zzswtnyy}yv|zry~q{u~z{z~}~{n}vr~}|w~~{~~}m|t~s|x|{~z{|fx|}~z~zuzux}|{{{u|yn}}|v}~u~}t|u{z{|kxp~{}{zy~{{~|y}}{|zzuws~}||}}{~}xwouz|z|}|{{||x|}vywx|||~||}x}uv}|zyvw|}zw}|sy}v|~x|{x~|}|~||{|xz|~y~~~|z{x}{vy{y}}{{~{v{{~}xr}{|{j|~~}x|||u}}y}}{~u|}|yy{e|xu{v{x{~z|}|x|}|~z{}|}|p|~rw}v{~zzy~zt}x}v|}~w}{x{s|}~zu}z}{|z}}}}}{z~xzxz|{zz|~|}|x|}uxw|w|xyz{~{}{yw}}|wm}s~}yyz|sw~{{~zny}|y|xxzv|{~y{|}z}|{~{}{{{zz{q}}{z}}t|wz|~yi{}zz|v|u{~|xzrv}~x~x~vu|x~~xw|}vz~~vtv{}wzo|||xy{l|twv}~}uwxv}zw~~|}}}}~uszu{wz~}vzz~qx~u|o~{||}vxt}x~zmww{vx{yxzyvyzy{y{~z{}|{~~|y|{vsvt|s{~z}}~y}~uxv|z{|{t|uyz||z~{|s~yz|z~w~zzoz|xz}y|z~{}|v{}}yp}{}zwrw|svu|}o|x{~|}}zyxw~z}yu{{s}w|z|vz{zyrzztsy}pt~||~w|vu{{}|e|w}x~{xt|zw~y|zuts||yxspx}x~|~qt}zy{w}xvwx}w|{|w{q|o|uy~v|xlj~~urv~{x{|}}zs{~twq~z}{wy|wv}y}}~wuv}|ty{}q~{}{t|ovz{zx~yvzs~wxxw{|x}xz~|~{yv{u|r}}zw}yzx{yw~t}q}~~w|qxlvzzz}||~vuy~v|~}}{{|{zsv{us}r|yg||}sysr|{}~}{}|ynw|t}|~v{a|~v{vxoxyt}||w~~q~v|z|~zxv{tup{{zmzv]zywy~z}zvuwt{{}z}}x~wu}ixvtz|{t}u{|wu}{v~{qx}~zqx{w{p~x~~|z{|sz~zzq~zy|}~u|}n|yx{{}|s~z~x|yxz~w{wrzyt~{swv~ywx{x{tyy}o|}}|y}}y}~{p~ztxww}v}{u{xxu|t~|nstx~t{|{s}v}}uy{{{_zs||{|||}g{}~y}sq{}}~{xzsn~}r|w}}{|~~~|}|t~{{xtz}||~||uzx{||zq{~p|zx|xz{wwswx~}zx~|kj{}z}|ykwv|~z}ttv}wz}uy~~w|~y|x}wry}zul}{}|}vwtuywxy~{y}}~vyzzywuyyx{wx|x|q|}w|rwysoiq|zzzz|yyxx|zz{|}yvw|r||{}zsx}v}o~xxx|}|z}vvvy}w}}~yv}{~}}|yxqx~}y~xy{||xyx{xtwzw}|{y|pr}}xs{pr~wxt~ww}{{{~v~r{s{nzuswy}}yz~|y}zlzz|}oxruyV~~~uwxzwr}|xp}s~zyuu}sz}}{~}y}~~q}z~ysv}v}~}{{|~vz{z{kn}~x}}~|}~vs{rvz}||{|x{x}|o|gtmy|~yvxt}|{x~||d|v{|||~}}qpsq|{|o~~z~|xv|utz}y~ny~}wy|z|~~~{y~|t~||}}}{}l}}}~}|~{{z~y{z{ys~~u~~zvy}xwz{z}|~o||{|wp}zt{~}~|xz|~{}{}vnz|v}|~~{w|zwz~{wnmw{|}{z}||x|{}p{z|{}|~}{}vyw{~|~y|x}zy~y|q}~|||}y|~}~|}|~oyzyx|~v}{|||syw}|tz~yuz|ky|{|{}{y{tz}}|~~z}||q}ux{~x~wv~ymtz~{}Yup|o|y~}}h{wx{|{x~}{|{{p~zwuwxz|}{x||mxpyyrw|^{w|p~wwz{yuu}wztw~}s{ywz}{xMr{~~~|qxqw}y{a{~zz{st~~t}|{yxx}sq}}o~yywywx~z~|ux~v~y{}x}{w~{~urxptz~~{~z}{{v}y{j~}{v|}w}z~rymwxw{|nq{y{}t|vwzzi~j}|||jw}{}qx~~|y|v{wx{}t~wyz~p}}|z|z|xt}|u}y{|y{zj~xxxywvxzz||wxyywzj{z{}~yu~}~~yx}}jfryulqxr}t}|{{x}s}v|{{u|r|x{~w~|}~y}{}~|lv}zl}u}~xx~|~{zzp|}}|tjy{z|yyv~|}v~uskty|m|w{~{|r~sxx~}|~zpyvx~t{wlzpzzpz}ix{zx{{|~{|x||xwvutxw{vz~rpsthyw{}xy~}zq~{zs}y}nyx~vyx}t|~{yz~ztw}ynz\wul{z~||uw}|yvxy~y||}t}}uvpvxm|vvyxqqszt|wux~f~r|{g~~zvs~x}~tup{x[}|iyt{||y|rzw{lx}z{}uwr}{|tx||yptzoxu\~xy{|g}u}~vyy~~jbxq{wx}_|x~~x~}qxvuyk~zq}{t}}zvzyxy~{vdzv~|rzqnxtpy|v{txv|~z~ozvxuzw}~u}||rw}z{|{x|{vo}|{yuoz{gl{{u}~}{v{{w~t|}u}p{{}}{|||u~mw~|z}}~}}|{}~~e{z||v~}{{z~w|}sf|x{{v}{|}}~|u{~y~}}v}u}|~zvz~k~xop}y}~}|r{zm~ux{{{~~y|t|pww~y}~}z}|u}uz~|}txxwv}{}~~zvwyyy|x~}w}{{}~u||~}z{u|r~}|}xt~|v~y|}|~}{p{|{uzv~uzpx{}~~uz~{{y{y{~}|itt}}w|u|x{p|qyvx|zy~~||}}h{vy~yt|}yu}}~r}zyz~nnw~wy}{}~zwo~}}yum|}x{}{}z}}~r}}}{|~}v}~y{~s|y~~}v||~~|z}|t|||yz{y{}pw{}v{v{zxs{sw}|z~~zys|zvztt|s~|yq|x~~ztszz}vr~hyx{{xy}u}|~|uz~~sy~{{u|}vxzwxy|m|v|zvyw}szzvtw{|{}z{|w}}||}|{yywz}}y}zw{{zz|y~}~|}wx{y{~z}{{z{{|zs|p~yw|u}||}s{u{w|wxww~~~~|y|pxz~w{z|zxxo{y{z|zx{u~~xt}rv|yx|zzzp|wwzz|}uzy}s{xx|xy|py~y}|xw}~}|}}{x}{}{|~u}}wy}{~z}}~~z}}}z|xy{}|y~y~z{|w~{x|~{~{yw}ww}xvzvtxx~w{x|}}xq}{|~z}~{{}|r~zst{sux{p~yz{{yys}{yw}y~}}|}}}x{wzv{ozsvvyuu}}yz\~y}y||v}xz}~r}|J|wzyl}}jysvytywzfz}{vquqti{{~|zpzsx}ry{~xyt~y~x{w}}zzy~x}wrzw{~{}xr~~}zy}zuszvzy}x~wyy|x~w~x|}}s~~zwy|t~gxw}zvz|y}z{{sx{y{yxrvwy~~~{q~{}|y{~Rrrx}zvz~{~v}xz}uyyy{~~vYjy~xy||~zwvzwxrx}u}x{vuy}{~|zxq}|}{q~x~}|}{}nxxxy}n}zvq{vs}zur}{~t~|}~|~{~v~}}~w{}{~~z}wx~|z~:}{w|}u}y~z}x||z{xu|}u~fyviwzuyuzq{~}~zyzy{{tz}ypw}pzy|m}{{rz|~}~\z{tr~xzz{~y|wv|~ow{|y|}|}yzr{}zy~|uz|x}~|qy}vx||z}~wz|~~}xwyx~~}{rw}w~{}|~~|r|}{{sy}yt}zyx}}}~{~~{n~z{|wy|{|}~y|u{|~y}}|~~sz~y~~z|}t{~vwx~}zzxt|u|h{|~{|{z|}w}|pyzys{ys{z{wwyu~wyyyu}~|u}||||}yx{{{rv|y}}}}y}z}v|}|}}|{{}z|}{}}ys|~}~||xtx~~~py|wyzqmyxyyv|zt|||~tl}zzzx~|{|zr{|{{ut|st{||~z~~}wyy~uy{|{|{z{}z|rx}}ww~|~zoxr|{y}|}x||y}~zq~utw~v~||yy~~|}y|}w}}t~~}~~{|x~~}{w{}~r|~{}y}zz{o|y}~{}y|lw}}z{n}||||~z~z}~w~txztx~{~~~}}{v~y|x~nz|t~v~z|x||vy|{{y}~~~z{yzz~|~|~z{yz|x{|}|}|~yzxxx}v}|~~}t|x|t|x~}}o}}zz||yy|~{|}z~{}}wx~w{t~}y}x}~yy|~z~|yszvz~t~|z}{x{}|y{l}}}{||~u}zz|wx}~|w{w~~{{~zy{{|xot}{x|~w|}snu{vy|y~y}yyx|||}yy~}|||t}z|wz}zix{~z}y}}z{||y}xr||{}{|{tw|y{}p|zz|r~|{x{{{{yvyz}{wy|{|xw{zz{yu}{|z}y~}|w{}w~yp}wuw{|}yvw}tq}|v}{z|hzz{v}|}|ww|}~zz|}}{}|~wxy}{}~y|{}z~{uoy}~u~yyz|{|q|~qwswz|}}x{z|y}}{|zxxy|sy}zw}}ryz~yywz{|y|wxv~ww|tv|w~xt|{~u|}}z~zt}xq}z~uvzu}|{}x|yw{{wxy~zw}zvx|x~t|~yyx|u~yu~|~|ywxzy~zwu|{~|{yzy{~wq|}vqw{~{|z{zzzxz}z}r}~}}v}}~}~p~y{{{wt}sz~{}ww{~{yv}}y{{zx~{zzx}yyvs}{x{{~|}vyy}y{}rruzx~~z}|ty~uzxy~y~xKd=|hpfs~o,|XiV\l|p`wfpo1o`qzD_c]meK~KxvdxwBnuÇ[vht_^vKLlOfg{gm|byZpUngzn|b~t|s~zrhkujleiIiǩV|XsUSØ^mvtsLlg~ˏ}4yqYHWES~ImdrbkvoQUmExqysy`Ca^Tcx6#]ypf=|G~Fy\^Z+%og}{bd.vffɞiu{|`lmRboU]tqkvkvu_oV!dxrk|Y[I}`:wyyg1<]1uepca~f\gKIùqtj|]Û}s}xzxz}}zs|}|{}~|y~{wsyxzx}w}{|qt{}x||zy}v}{}uv{{{|z~{{z~~}~|x|wl|yx||k~p{~hvprqktowv~}yy{u|l~xsxu~~|y{xrz~x|}w|x}|~~uy~yrvmryyw}zptw~|t~wwy{}cy{qwzr}w{szuqzikoiu~s{s|g~{΀t}~z{yvtd{jwtxHmu~|{||{||y{xtuvy|_z|{hvrx{~||z~{y~~{||~}y|~{|kmzzw{{x|ws|t{ykbz~xrzh~|ym}wyu~wc}yezo|~t|}~n||qpz||~~pwlywxpwfp{~mvw}pj|sv{~{iyzvu{~wyzzzsyu}~ky~~t}s~{~|u|vt~}xz{l~q~({u~xxyvxu~wz~~}r|zruq{~syl|{||z{~~|z|y{s~}{~~{z}||{y~{uu~d{n~iyyq|xm}y{kku{}z{vz~{}}}w~|zjvx}|{|xo~fza}}Ut}~{yNyh|}r{~}|zz~{|{r|wv{vw}FtD}}zy|w~~}y{~~ww}z|{|~y{pw~{qnuy|ry{|w~s|}~r{z}|~tx}wv{}zm~~u|}}}z}}~{w}w~uz|{|l|}z|rzs{~xy~vtvy}wt{{|z{~xxx~yqy~v~}}|~~|{~wzy~|w}r{fu|~q}~|}{~}rsy}}{~ly}]||w~vrytq~zugqz~|jv}|~V_~wt~~sx{t~{|sL}{z{}~~|zyw}~}v~n}|x}o}ro}nwz~r|{z|z}|y|~r|zw}{|}|w~z{mztyj~v~{tq{{x{{|~|~|r~~}ws~w|z{|y{|z{{~{~}|{v}{r~}}|s~~o{yvz}t}~xpzz}}y}ulv}u}z~w}z~}}u}y~yz}~z|{r}{t~}e|{}{x}y|}m~q`~}xq~yjs}~~vxq|q~{tqp}{||zxIwat|}qx|||~tTvs{}xy~q|P{}oa{}wV{x}{~zw{rfu~|||grz~~u|{p}|x}p~~zxqzr{~|x||~~or}}y{~drx}|~t}}{{x}}|~||vgqqyjbik`Za{njkc_Xc\nx^jb^hfoviunmy}i}iLjnq|bk`fbci]nnpe\elhl_cdcciala^yx]aizoppqpgqaijotq^|`_\ema{I{p]z}sn|cifg~}s~~|~}xv~sz}~|tyxr~}z|tu}~f|zqrt}}}{z{}}t}}|}uz}yx|}|}~}|~{y}z|}{r}~w~|||zx~zy|z|{}}~~|{nv|{{y{swu|~~}~w}xw|{~jo~~|}zzmx}{|v{~{~|x~ws~}z}}z||{v{|w~x~sqn~~{y}}z}u~v~{~x~ws|}nglgvy~|~}}z~n~}yxv}}nr~tq|shzx{~{vow{~y~u|^|{~z~xzyy}~~z|~w{w|z}zj~yhf}~}~ory}|xqyysz~~}}x~yo~g|t~~|~ql{}~sk{t|~ja~zzm{}]o|~u~wvwZ}~}x{}yp|ro}x~~x}~^hnzu{~y|}~~}z|z~t~xyt{~xksntmy{u}yzs}xz}z|y|uvw~q{{p{xb{{c{|h`qvt|aoktzy{~|s}zkruUmiyxwzx{shzlyio~~~ffy~y{tt}[io|z}zz~uks|~m|~nvt~~~}~~{swy||sq||opoxrx{~lulmy}|}[}u|z|{{z}{}tzqz~||~yh{u}}{y|yy{hx|lv|~xy{sre{pz|jpk{~s^~xm~}|ly}zz|~zj}r}w~~~tzpzs|pY}xf{rv|~ywzz}|{~y~vsq~~}~xqyz~~}~yxzzvx{|u|}xwzz{j}~|ux~~xz}{}oq~yu|{zvry~zzz~wr{typ{}uw}tt|s|z{~qqxxxk~uztzli~m|ukluuwx~}t~|y|zq~~v~~j}{~|z}~u|{sw{w{|s{~{t}}yqz~|tpj~qZ~}sirz~{ykuzzv~tz}tx\}~]}\ivgzq~QozsZL:gz<{{~qqxx}oezUw~||o}~}{~vvrq|wx|na~x|y}{ix|{u}z|y~{xv}~~xwxy{|ty|z}x|uzy{x}|Xsgw{ey{{}ti\|mMvor}}p~~w{}}rO|wu~}w~ysvw}|zy}{w|}v~y}{zw~y}~}|gx~py{xv~}|~w~}~}x~||st||}gu~z{ixy{qz}|zxv|q}z|}|zn~xs}p~t~y}||{q|zs{o}ss~}}}zyszzx~~zowu~~ypvlvxzkY}yvxp~}t|g}{~o|a|}|lqnotou}jmqup~|t{ypzvn|tpxvxvyswvwpm{zmu{p{|yytsyqqo~~u~|||~mvh~xs}z}|w|nw~|{|uz||xz~~~}|z}~z~}|~~|~~{}~{y|{zyz~wz{}z{}y|~~y~~{s|{~}~~ovm^|}}n~qs{}x}xy}{t~~~~}~}z{z{{~t{|x|w}~{{~}x~zw|{z|uitt~smywtx|~}j}r{un~yxn}o_Qfbolz=j}p}|t}{`~xt~|y}~xblp|{n|mc|x{zw|{k|s|y~u}{~vz~ud|~}|~}gwy|~z{|{~vk~|z}n{}~}~}u~l{y|zt{nwy{{voz{xx|{cmj|~}v~vyzsyo{~wrw{~||zs}wy~s~}yf~}vuvm{}zyvz}|w~frp||}}u|}u}t~~}||}g{}}z}yz~~|uov|{{{mqrv}gwh|~}|~x~yv|}{~~||{~x{{~zuy}yzo{|yw}~|y~~p~gyu{|w~w`p{qvfzp|xx~z|~y\|qt|~z}vvy}v}}}~x}zvyy}~}sozzy|~x}{|pz~~iwp~~}t}x~x~~j}xuzzzroz^vscpowu}}}zi~^}{~tsyvqvyv}}~s}y}nny|{{xztz{ukq|~|xu{}|}{~}~~y{u{uq|t~n}n|w{w~o~v{ry}}l~w|z}}~||py{ss{}z~ux|~k|{yy~|~}s~}rx|y|n||y|}~zqt}rd}r}hvm{]|{zx~{w{xzoyw{~w~s}tx~~~ur{zzz~~w~li}}~tt~zTs}||{[tkwx{dz}xr~p}{}s}vX~y{t|~ov~|~z}us~}~q}x}|l}}}tutv~dm|}|xq}u|}}~u}~|~}|x|w}~wyw~xoy}~yw}x{}{s~~x|yd}y{~|yu}t~|}~uv}~{}~astynsw~}aysm}}z|||~|y{~w}wq|rv}}|w{v{{~zr}|rysx|stf}n|ymk{~yovz~cz||{r|yz~}x~~u~ynu}~yx{`vq~}qz{~~~zrzzr|}|wt}u~~}w}{m~o|~v__}{|t}k}t|w}yyx|{~t{xzi|q|}|tye{xzxt|zvpyzz}z{p{ya|muO|j}{~|zn_id|k{z|zQJU|~wo}}|zx|yv}}zuz||x{nx{||zzy}|w{|{vz}yz}r}~yw|zvy{z|x|z{|x}vu~{|xyw||y{rt}z|yzotwyxyxx_w~}wu~uU}cr|}~Ur{zx{tqtFqw|xoxpk~=`}u_t{owsyzz}wwo~[w`}|}~yn{{bz{~dozx|zvf}u{~zzwxyzzx}f}~suz|zurfw}u}^anW[zsay|vrjSyNyy_kwm\p|{xqȄt{]~h|v~lz_v~ywp{ve}}|x|y|}xz|}w}}|z|z~z}|}~~~u~yzq}xz|{{]sw}l|u{}}{|x~{}ggy~|u|rprxx~ss|{r~~z{~y}uz}~u~}~gn|~~y~sx{}~}zux|p|vvz|}r|{qfw~sqfge}rqy}zyv~}|tx{nk|~}~|~|}}z}}z~zzz~}{|}x{y}|{xz~||{vvw|zyxy~}uy~s{ux}Xtz}|}}~uw{y{hxx~zz||z|y|z~x}yx~{|~vx~~}{wyvt~}xmzwxw{ysuxwu{z|u{{v}~|}|x|y|}x}v}xy|}Ww~wx~x~yvxyz~~}}{y{}~yxz}{{z{|~z{~{xY}}~yxyyyxx|y~|z{{vzz{zzw||}}}|z}u~{~zw|{yy}yz~{s{z~shc}zv|i}~~{{wyywlbx|~~sZ|~|t~y}}|~w|vm~r~`x|tzv}~r}}k|q}{g~~~~zo{~~~~yuy}wy}u5~|vzv~}zy{}{{}}{}~|{{xs~}}~~{}~x|~~|y|}{zyK~sm{xss}~k}~~|}{~yp~[x}n~w~mn}~{}s}jvz}~|^{yrowzyxns~uz}<}~gi}{|{{s|}cz}|z}w|}kx}f~x~~|ssw~q{{~w~~t~x}n|tuw~z{u|t}}|km{r|{|y~}n|}z{~wk~~|Zvz{~brxQr|~Vurjv^e}y|||xyw{~~|~z{w{}|v~n}|txuwuuy}~zk~~~}t~y|k|{xxz|~yyzzx{|u|}~~w~~|xz~mpQyz|~qL|sz~T|v~wzrp|dxoo^{z~lmb~vspv{|vfw}xw}{rz}zw~~{z}yznxzc|vsyzi~j}wku{tyz{p{rvw{{qgzjx~kq}|}|}|r}~bqv}}vyms}eixgrm`~k~~t{|{uy~}n}di}~zz{}~}z~q|{~~|{~w~~}upt}y|}|~~t~~x~x~}v~z{}{~}~{msp}~~s{}|tu~~~}yz|~rw~\y|wl{~~|xj~|x{~}{{y}|~u}}~yz|y}}s|{{s{~{w{~t}stxih}~j{}}~{w}~k}{q~y}|mtx~~}z~f~ko}}}|{|vu~}z}~~qv~~y~vxw}u|wyzr}|y}|t{~}}y}w[~r^{|t{o|r[|~stuq|u|}xzh}tx@~zxm{]t}wmv~aryz}n}x`xzwy~|ti~t~{ry|~velpw{z~~{y~y~z}z}pvz{{~z~{~|p~}}ql}x|{||~vq{|s|~tu~r{uz|tyx|q{~v}z{yy|z}yl}c}ylwu}|zvz}~w}z{yx}|rsxu}ox{~z|kru{}}{sy{v{~{w}}vzz}|g~wtz}l~xyvwxrwxvmch{v}ovbutsy}s}}ryn|rtMq{|}rln}vj}qzzsq|lq~u|qwx||~}{z|}~v|~w|~turzl|u|yv~yq]}sy|to~~yz}wysz|x{w{z~|yw}}ve~~x~xzzzz}xy||y|{}k|~~~wy|zyt}y}{|w|{|{m~}|y~}vx}~~{z}|n}|t~z{gxdr|~~uu~~}}^|oxko~|||q~s~~~n~}x|~~w~~sz|r|{|xy{|~xs}|w~uz|z}y}v}yz~hy||zr~x~e~u~~y}oxz~}r|x{yr}{x~\hs~sQf|}}{k|zzy~{xrz}o}pwly|}{{~x{}|z}{zzku||z}m|zm{zz||{ow~ud~^|{{usfXg{u5rWvu~|uymh|r{s~}}n~t}~}z{nsj{|}ry~s}u{iwzzm||~|||xw~}~f}b~{~}}}~|~y}xv~txy{}~z~v|v~qvsvj|}kz{oz}~tx~jyw~|I{~w|~ly|{yi~|~{}{zo{j~twxwj|uz|x\m[~yut~zX~~yooow}~~fx}nw}~p}vzzy}z}}~^nr{yk||{|x{{}y~xyww}v~}{txp|z}{x~{~s{z{}{zy|s}}y|qkqx|}i{wt{yv||b|nxgfy{}K|w~x{|~}vi~ji~~zk~s{}yzt~}~v}luwo}|`ux}sjopqstvqv~zyz}w~|{{yyp|~z|{cx{w||||g|~]w|v|z~xyq}}yytu|~~{y}~~sx|t{o|w}u|vy~ut{}z}~}~t{z|r~zvx}y~~}z{x}u|{~yz~|}m}~{v{~{}|y}{~y~y}zys~|~vu{w}y{|^zvpoztwoytyk{yvuz~}}}~k|~kffru~{zv{^ky|x`xs{Lyy|}ysy~ńzv}mřn{|w~rsy}[y}u~ovX~}~x{{}y~{t~|}i~t{|}gxxtz~~ol~kzz~uc{}qp|~hut~|u|~|~uy|o|~~~~s{~~}|ys~}~fr{~~w~}o~xxv}}{}m~{}vy}~~|~{wryzx}z~t{xh~~~vyxio~|omyz}~{yzy~yztgz~s|}}}~{~}{vk{zh~}}yy~x{{}~|{t{}t|rv~|z~t}u{ssnveyz}v}{y|~w|yxtz~n{xoqzs}rzqyt{|Ȉ|{nr~~}{{uv}~~~t~zylwy|~zv~v}jm{{ztw}r~zy}|v}q}s~~{~}z}ytm{t~jap`|~tzhbujR~w}otr}\\]b}-aw~y~y}w~yzx}z|lzxwtz{s}|v~{|s{~}kUy}{{y}{yk}{{{}z~{~z}|ys}oz|w|z}ox}}t~w{y{xut|r}}y|{{zvx{y|~|~{|z}|wxwzntzx~~{y{uy}xxwz{{l~~{v~||u}|^ty|u{t}w~~~|}{zsyw}}t~}}yz|w}x{vy~m}~q~y~z|vs~{mu}s|~}vv}va}v{~a}phx~}vz}h|z~zvrr{~~~vy{z}y}}vzyw}|q}{}yo~}x|}zt{~}}~{~~|v~{{z~~l~syu~x|~y}~}~y}}}}}{x|zvy~}ytyyzqvw}o|xuxos{rs}uz}v~wu|oz}|xkw}Ņwvpxpok|rw{{yqvx_`k{typzkqJ}d|~|{z}vz~}|il|}uix~x~~q}sw|mzw|}vs~~{~zwvztzzy~|u{twtx~|~y~tx}v}~z}i|z~~{wzw}jy|y~}m~t`xur|{iw|}|~|zq}~{~z}~t{|y|~zu~{z{~}}w|~}~y}w}}yutzssnyrspwvrwxq|~xzvujurx{ywso~}{{}|}~z|Umw{|z{|{~o}v}xzqrsrutgfv|nqhwywz||{{x~y~{ox}wzyyrs~r}}~~{p|{s{x~hi}~wt{}w}{zq~kuw{k}og{v}yq|yvY~z}z~z|{|~{}}xw~u}}~~~{}vhr}hrxzqx|}u~wy~|y}wz||~|{~yw~z|r|zwt||~{si|}s|}wq{{ux~s~s}~ywy}yrrvxx}zz{~vnw|~ssi|}~{{|xw{~~z|u~wy~x{||u{zuyxh}{vu{vx{{|{yy|wr~|}u}w|y|xc~vuk}{z}||{}r|}vty{y}zp~v~u~~s{~|{|tzzy}s}{x~jx~|{}zr|{|z~z{}lw|v}}}zyx}|~z}y|}}z~~}zj~Uw~||y~~tys|~s{~ndj|tyj~;}x~Y|x}mh~qt|sjz{zjz|jxwxfpsms||y{s~swvz|ls~t}sp~xvwzhytnxr|}ytltlyv}uus~o|l{|qxn|t~wtxz~|yxzvvqWwr{r{~|g|}yxyzruq|~pt|tqpnv{vqyp}~tu~{wy~{yw|wxxrjznxx}itp~{{u|}{}~{u}z~}{|l|ms}}w{{~y{|x}|~z{}~w}{pp|uq}tdt~~~z|~}|{zZi|r{~tzs{s}{an|y{u{{l~w}|~z}}|dm}}z|yzg}~{}y~og~{~`~yvi}|}x}p~zxw}zvqwy}{w}}w~~}|p{}{y~e~x{{g~}}~{|}r}}~{|}r}{z}vx|{k}u}p~|{}~~|t{}~w}|~~}|~{m|}~}{u~~ys{x~x|{~x~{}z}t}yv|uqx}w}~tul~yytw~}|z|xm|z~}u~ux{{u}z~t~}}mw|o|u|y~x|zx}xx|u|syx|z|}~}y{~|jz|{|nw{~~xwtws}wyzy}{~v}q}|~|{xx{|t}}t~y{x|oq~zcx}m~ht|sn}wywy|hy|{cl|{wuw}]t~~YX|naysxfo`qpxpfpo}~|~u}}xx}hww}~~~~}t{qq~l{u}sv}}x~~~x}ytz|zzyo~x|x}||~rz~q}~~~~ztx|xx|uy~}}~}z{|y~}|~{~}}|~~|}nv~|p~ryw}|zw{sx}zxy~yw}oux|{x}zy{p|{z{~zz~v|zssv}u|}p~ws{^zrlmoxy}|yx}sv|y}{uuwy{w}~z}n~rw}~~vi|~{b[|yz~x|}fy}x}{}}hs~kdtvJ_w[}yZey|yxsiz}{{pz~}}nx||fzlr~|ti~z{xxw}tsvzu}{{ztvo~|{y}}zt}~t|z||{wwywc}{pyWsz^vz~bbOTy~rkz|belz|ynzuvz{~|qt}{w{|{{|}|u}z~vy||tu|w~xw|zw~v}}Yn||{y|~qhz~ucuy||z~q||~~}}}}}zq}}{~uzwt|z~zq^~vr~||yy|}u~x|q}}}~}z|t~}uyv~zzpx~zw|vy}w|yy{z{|~~|uz{v|ww|}{|||xz~zux{u||~}|}|}zyv{ut}}~xzq{{{uz{}|{uttp|}wqytx}szv{}{tyuw|vs{w}pzt|||}uyto{pn}wy~sz|oy{r|z~qr}lw~|~}|yss}|w~z}}~}}z~y~w~z}yzrw~Y||{quy~m{}tz{}}}zshy|ot|z~qzxt{{}v}~v{zvt}q{|wjc}}iutm}c~{gWiMoStNunw~czv~z|p}}t|p}s|nlw~qqw}z|}~sx~~{m~X9{~}~j||rgeyxwwxzu{u{||t~{z|v|}{\q}h{ys}tx}uzytzz}Qr~xxysv{nzywzqYzyz~{|nv{~ywr~Qz}|rpa}xe~wdl}|z}r}wlzqh}Yk~y}}|p{it_}z}}mm^T~y|Os}t~ve~xn}xL~~lo~yl|t}}nw~yzyonc{O~^|usVntx|}}{z{{{}R~|v}n{yz~~~~~z|xv}uz~yy{n}c}}||~u~vy{}z~v}}~}|~{~~ho|~~}zywu|otzwqxz~}|}~~{x}w~~pra}zuuv}~|y|sa}~hvzns{{qzuxzwf{~{uuyuEpwyt{sqQupxz~\r|{}{wy|z~|xyqgxwzyH{d{{~s~^k|~_}}cv~z~y~xrpyy}j}xu{|}yzy{}}zyw{|wi|mUvqza~}}{t{}_sxmws~S}y~Jpyoqs}|sgm|~uuro`BrZmvk@fd|~q}}|{~y{|a~rx||c~x~zu}z}j}wyyv}|~xrxi{ywwzZvB~uy~}kw|zsychz}u~znrzf~{~}{nzzt}t|vq~zz}uc}{}qmt|u}~~}}u~yz~~v}lgtz{zyuz|}}~~t}jy}~|}mz{{w}k}yzqwz~}y~y~t}nwr{_|~mox{w}vs^z~u~wjp}{w|WzKxsx|~p}z{{x~tp~|~uuxv}|x\fs~uw~qZ{lz|vysv~~u~q|s~zt{u{|rwxxzzuuo|{~~v{~hxq{vt{|z~n{{{x}{~w|{s~{|{z~}{y~t~}yxv|~}yqz}u~r{y}~{uv{}}z{}s|{|}zvuz~~}}{|{v~r|~|~{f~{{w|{z|{~swz}xnw~xq|}sr|z}|{n~x|xu}x~z~zxy{~wtjux}pgzvxyys~y|y|pw|}~}}yr|~s~vzxzy}~{sy|q}|}mvxiqpwz~mrz|k~hx}}zuz}}utt~{}x~~~v~}ns}{p~yv|~o~{~~}~~|zt~{~~uzyzv}~{p~z~}w~~k~|zvp}y|yxdyt||rwqosjizv~{}}|uzs|sz{}z}|}zz{|xpz{}~~xx}||{~z|~}yxmy|z}|~}y~}}{vu|yy{u|u|p}e|{}}|ytaz}ykyU|~}x~|w}zx~~ne{q{eVvz~}}t~uzy~|~`xs}{|~}~ph~`~j{}z}hzyvwr{f{}v}nl~}}zf{yu}|a~{y~|o_p}Qk{{mtu|}~ofz}g|zyyfzwiw{yzRl}y|{~{vWv|ysq|y|{{{ys~``o}|xRertu_d|i~y]s`McR~{{}z|}~{lz}iuixxv}{{{~[{~qwwr{~xw}i}{~yqzz}}{~yz}vr|n~~x}xv}}kz}|z~}{zvy|{{y}}~W{}x~w|y|{{}pyzi|~}~nx~ts~}ssqstwy{|rzzum{k|sz}xrj~ez}p{yy~w~x}xq~s}{}fpz||}~uv}}{tq}pwo|xx~zkxw~}~q]c~|sQ{wu{~hX|~rzyzw}vt|zt}ys}}y~~e}~zvo~uxz~|}}}u{|xu}w}~s~r~gx|v}twic|w|w}|u~owj~~mx~y|k}oyz{woj}yzvy~}ys|}_|~}{zxzyf{vx~dd~w}~zy~jhl||}|}y~~|z|tyjs}~ss|u{q{~rv^^v}yrdqzv~||}~us|{xxy}{s~||p~|~zyq}y{uir~u}~zyxq|~{z}~x~~z}{s}x}w{{{yzu{tznwn}sy{~~y~rvkuu}oww~~|xrxzzsj~yk|{x~z~}~su{}v|zwzr~zxv~~zxrycxv}u}du}ywu|ux|v~l|~|ws|{lr|}yt{x}{~}}t~{{~|zyz|~}y}|s}~|~tt|vyz}}{z{yztz|v}yz|~psx||xx~v~|xzpwu|}zt~yux~xh|~~}d{{wS}w|y~u}{{|}p}||z}vz}z~z}zzyvwx|y}{}~{p|xz|}|uy}o~{}~t|xzw~v}vzw~y{|x}|{luz}~|w}y|w~~yz|qyw}|wy}vv|xzuy~xyu|}{}}~uou}{~zu~zt|{y_{~z~^xg^}|}}}~|{bzy|~{~ywz~uzuzdl~zlzeZW\x{f~t|~xttTzw}y`}tyipem~{|{}|w}t|w}~{{|p~vyut|vj~{~z|x~wwq||jvx~{t~l}~}yz}~}vzzxw{xz}r}}~r||u|~~x}}~z{{w~||{~zz~|klz{}z|wt}z|yy}|~w}{}v|w~x{ytx}|y{x{x~x|~~xy~||cx~~x{tdm|xm|P~rpv~wuu{~q{z|qgauxf{xocnxc|{rqy{{x}xh}v~{}}{~|y|s~}tw}no{|uyoz}lswwx|~z~v~~y}x}io~z~}y}{}~k||ptvq|wq|}r{j}yw{~}uo}o~z|v||vmft|ku~ny}|gx}y}{y||~}}xz}~z{~|s}vtz|uq~p~xz~}}ywfy{uy|o~w~}vv~woqz~pz}{vyy}}|~m~{e}}~}|}~s|tx~yy{}z}}v~{vuzz~}~xv~|z}|}}r~w~yyzt|~v|}zy|{}v{x|t{}}}{ywxrmp\~mk|_x[~{|ysf{k~|~}~z}|~~tmx{v~{|n|{}~y}}wu}||}||yz{}z}~}{y{|}zyxytw|zy{z|}|v}y}|vy{w{z~~yzwt~~~u~{}~}~|~}}~~z}~y~~~|~t~}}}~zw~w{}{{{}t{x||{s}t}w}wqq{~~}}}ws}}}~t{|z}z|w~w~~||}}}~~x~}{whep~m||ow~o~r{dzs|z~vx}~flzxp}yvzy~usywopyx~{||qbzw{yn~vupz}y}||~~tyl{}zv~v{~zxz|{}}~~}~t~~}yv}~uu|bow{y~rnix~|u}}ryuf}|h~o}}~xyq}k^{zxys{~vxv|ux~{xv|e{qon}~upyr~x|x~}|~ss}o||~z~ytvkzs{~rry|y|{|k|xwu{vmcxzw}~fZh|yyx~|~]uovzpq|{}m|}|d}}}}v{{t~yv\}}rp~~|uov}|{{}|v|{x~{zr}|vvuzuz~ynlxu~}|{{~~|y~xyx|~x{~{}~z|~z|}~v{~xk~w{va|||{eyyuy|t|~}h~|}~}vtq}x~jysqs}y|~~`~z|x{q}}~||y||}ox}y~rsb{|~^~nmw~ywr~}~yzyhqtxykqzru|~zwiy{||||y||x{sxzpys|w~w}y{{uJ~{~{y}tt{h~xtz{~zkw~x|mn}|wh~tb~}R~s|}hƀ~s{xx{ł~|{k~}v~|]s|wwvuizxzlga?vRz}wUh~z}w~~}xxpt~~x~w}}ux|~~z{n|~~p{zyx~z|~{~z}~~|}y~~ww}~||~~~q}pq`n}e}v{^xv~wwzwm|dxv|woxmx|fs||sZj~|~}zxzb~xcz}}rzx~}t|~vzmv~q}y|h~{oum{xy}|vx}~~wzbs|p|w|uh~zyz|{{{}u~|}{|{~wzvy|r`|vzdqlq{}||~|~w}~|yu}|~se}}{~{~h|z|s_q~~j}m}s}wy{f~zvxf{x}}lvxxxx~y|pztto{o}ct{y|tzz]uquk^{}x~bw|zpvz~zt~|}x{|~y|wzu}y|x|z~|}yn|yqwp~}}yk~v}x{tqso~wvmz||~w~{m~ztxt~}|{z}lIzzzpu{wpu~u`Qz}~~{o~~zpouw}lt~{r}xyzorlq~qtn~~|zio}u}{||xu|ud|}qyz}}q{}q}}yry~{~uzzuxwzlx}|z|sa|~xwy~v}w~}m}ۈvr|{~t|xzwy~_}}|s{z{|~u~kbx~{~g{MXyil||px|r}a~{x~t}utej~Z_p^~{~{WwG|ʇ~qyr}~y|yz{ut~{}ym{~qx{y~w}~~z{q~~xjwly}yp~|}w}x|k~q|v}{~yxur}t~}z{|~{x{{~s|z}uW~ky~i}p}y|}|tx{ygwx~}}}wy{zlx{|}~z}}|yyz}}yvu}zx}}~{vtc|}~|wmz{|zyuqy|dzyvsm{ztvw~}z}{r{{m}w{~}~|zsv~{rz~w~}y|yzw{z|{`~|}ws{~}y}{y{o}jwx~{{~|~w}}|~x~xv}tu{u|~|i~~~~~}optzy~}w|u~}n~zy|}p|wzzx~{uw|xuvrwxrv|s~~z{p|xz}ty}ziyxw{x|zvv~xvw~~}}~yws~y}wguyzmvu}vZ}{~xx|~~wjqru~}w}}{yxzit{~{xwpsz}h|t}|~{}xxjg||t||||{~{~}}x{z}ow{~~zwix~urw~r|tvq~vsw||~~ywzxz|x}|~wz}dvzs}~}|tx|}~x}|{{zz{y|y}|{xfx`~|unzl}~~wv~wz~s~uvh{w}~z~ui{{|{tyz{s}}vvoy|u{zy~}r~hjx}x|lz|~{u{~vu~yoc|zty}~w~}{q|ne~}|ye`s|yow}}zz{w|zvy~|`swx|z{~~o~xw{~|}z}|tt}z||s|vs~yw|l~z}v{~y}~{~{}|}||x}yw}wou~{|{}{qs{xl|mT}{x{Lo{m}tf|ujqu{k|xqi_}o}Mhzu}}w~~jv}xly|qtz|y}s~wxhw~quv}|~y~~~~v}x~k|xtzxwnvtqw~{xk~{{z}}xud}oz~nuwypqy{hmz|trz{y|wwept}ho{z|zxt}onqoaosedo|osv]bfXzUgkqu\oniXhj{mttmsjkSomqtnreokrnpfsqgnnwl_|Qcklcpogsujf^q}xtqfpnpwbnapeuavoufscjsav\oneenorXgqln}w~}zwu_\rwwoxo{~}q}sx|p}mug}}}yxyk}n_k~nR~^}~wqQvgszYhO}~z}yp{yzz~zu~tuz}vu|~~z}~~}z^vzxvtrz{m}x|uy}wwyvt~sxuxx{}q{txy|~}vxvszy|xzx{~wzit{y|r{}}tt~rvuzxdy|ew}{~i}{v~{f~wr|zr~x{{z~vrp|l}x~tst{wt{o~zv}{xu{u}x~u|}cvswzoYzbqr|z~jVw|wsv~|X}~g}r~}~~m|`krp}r|yd}}}gy{sjpa|ojw{|w}lr~vw|zo{pystw}v~~bvr{w~~xl{tyc}~}z{wrqy}uwwe|z~yx|sw|bo{}y~}~}oumyqy}lshvyrm|xayh|{~ui{tys|~y|t{|muxp{~v||zrk}|||y}zvy~{~v}v~z~zyw~zzoz{x}z~~}nzzN~yk|~}yvxqxtqg~umR}~h|l}|}~}~vx~}~u{}}}~zr|}|ru}l\azv|q~sy}}t]mrxxvx\|}t{wUr}wz}{}|}~}{wt|~u|qz~{zr~sl~~y}~y~~~{|z{|z~~n}y}|mz~zx|qy{}lnz~}}ln}|y~z}x|}|}r{|~w||uxyuu{nxsnwuy|{||tmrsy{}vq|~~sy{uj|~}yzttyumivs~yxsxp{~}zv}}~}~|~|wzxz{uvz}z|~}}wz|~tt{voz|yz~uz~ozruswcpz~zu|}r~{{~yy{||{{}~}q|~|w~u~~~{~~|w~~~~pz}}{o{{w}zyq}yv~~p{}}}{|zzic^}||qz}a}yz|kz|~}~s~x|jub~~~zp{{{s}ftyz|f~sx}xy~{s}s~lk|}qxe~x|}z}zs||z}zu{|zpy{xo_tzypk}~w{{}|z}{}x~v{~{}x~|~c~{}}~~{ou|{ow{zq|fty~|}n{~z|xwspzx{usb{}~jrqwwmg}vzyly^ryytr{v.~ztwt||rtupN~~}uq}\wx|{a`Uwyywu~iu}q}z~~l~zt{|~ou{{k|z}}{}zb|~}~e{w|y~X}vu{|uVhp\{n\|i`{j@]lyVf}v~y|rywzx}~~mzw}zvjxyx^nrstnuueyx}}xtun{{x}}zy|~s{}v{t~{yz}vwqr{w|z|vwz}|}z||sx~ztx{}{o|y}~rvix~yxxmqy|wUvw|xyu}~~tvy~~uyvyq{yysjv{y~{x{~~yzuy~w}}~}wx~{[}pteqq~{_s{~|~uuyc}y~}ovmz~wvqi~|z]}n}zu}ruyr{q~^zxy}y~}}syx|~~}||x|z~y||xt{{z~}{}|}y~|vuh~tx}~~xsyzz|}~{}|~~}{{~y~x~|}zz|{|wzs|yhvx}hps~||xwnmxzyq}ywu|wC{uqqkr}p||tw~z||u{~v}zx~ezxr||u{~|svx{~zrodz|ywzxwy{z|xq~{~xLxqwz}v{|}~n|nyys~~x{~~}s|vqwxOvq}y~zx{rz~zy{|go|w{vw{vt{~~|Ylzt||zt~vwx{tt}|on{xu}xsx~w~}uvx~{h~you}}|ux{~w~}z~n~~xz|~z~jum{~z~}}g|u~z{iu{m{{}{}x{vtzz{wqt|}s||x}{s}{zzxx|~y{xy}}z~}{{s{tzx{y}}tt{|{y~y~p~~|yx~rpR~z}stw~~~~~~y~w{o~}~v~~{~{~v|~{w|{{zz~~x|~~vhxy~sx{l{vvz~}|w~{yx{|||}~v}u}yz{{ts{ur{u|~{|c|}owx|yyuu~k{}j}y~vpzy|e{~z|xw~d~|yx|w{r|}txys~~z}uz}xxub{y{~vw}|y~}zl~~||||}k~x|{|t|yz}tlu~|otxz{}||~yn|r}r~|x}}{~wgt}x}}zp|{|~io~{}v{wx~w|vmo}{hs}}~utc~szsq{uzyy|e|m|qzcypz}|uwuvxk}}|{xe:xsyswyoyztx~~ps~q{n|z}u~BrzIeirhwzvǁ}~y}izxs||uzl}|}zz~~{}~~u~{~w{yz}{vz|}m~|}x}v{ys~v}wz}{y|~o|x~|}yz}t~xv{}y{x{zc~ww}|jvvvz{fzowd}hskwjmkqqnogzjWesrvnero_[mRvnpljmttaodkmlphussqlolknr}uppijud^contnowlTlZoi]kpm{ccqqopm`zVlropglqspeipk~chmpl|relouqkori}qpo{ipoammo{hninTnmmmulsoimkvoinolkwsickok`FopoUnYgz{l^jasiqtnjQklrp[Zs{uvuesirkgglWktmprv|rxkssxmkcrwiUkz{rkQjzlkqZlxonrnptZhvmbsaimp`nhtitnlfmoRZllnhojte{l|zk}mymaspnin|kxorlrfnopyifpqgj{\nmkmxpkjn_miooopoophokqwslqihlzdirqa]ndp{pqgsiiqssfvqyokXenpzxuxjiynmyle_srrc`n}qh\pnintmsvqo`r}m_ppolpnrlpql{jfqnjpmonigospGq^kppkmskwkoon`k{qgo~d|lnh_umyik\iihmqjyigRkilmjd_qmmsmq}mllmeanpnkblenmrhyh_bgrnrslqhqHvsmpththplvmsl^ihNkoj~tur`nfnsmkn`pgkqSunqntrmmq~npZersioYntpmgski\wlwimoopkvkmzygdh|rophqphnkmg\{[undtnhvhjlkYofX^noplgoi[YjqqsluhYyboijldj~_rppVppmzijnloSkinj^ng`lko[mer]sjxbxdtZumopYniQnutsh`fKjlq|elinwmholkpenio`o^hQWttmoZjersoqnjqVY`xkktcmgeosyagrvsquTlqopqkcgirdkgc^nlitidnXtQpfnigrr`coucyvlfs]hdhjuslmwkybQshef\jjip|pdxh|ojkYnginzwrlap^gifinl]p\rvddubnknrjqghjvuusjrnVxmwvpnpruqjpik\ykXogsmWlq`rnhnpog_~wfoukgqnq`llbl]lwrxdner]zmnrjTswjjbrqngpHuodkfdoogwqolkiqsntsnPt{omZ_nhvnhloqgoiijjrapji|utr_ypnUnopf|}nlirawVkvWhtipoollllRem]njenuopvpcd`oim{_mUj^ivhsblmmsozmuredfkjnnnqnntalkldmmpqq[rotnolnomqppmo|\mursqkbpsvcpnmn}l^roWrsnokpnlimxqklmrvvpJolrqqLqrmbzmoqmspjkqlsofvrrznkeom|pFaqtimzinhjoSQmnUl^npkrwlimlutklnnmrmeru]irnoswp\lo}onsoQimc5bnqrmmmqnkolhlmivpinqtjmZoaovnnmoqukmne[fqsgjppedlmc{w`obmqhfokxmpcg~tmon[oyhhkjaqeqpQkfpqh~n_yeoyznlcmasjedca{i`mfpplxoq_gl]\nntcv[vttoqlpsfqmqcegyS_aXmovp\iwszkrhrwnjmirsncjHsk|qjnw\sgthnipmngipmjmZgoq^{ppnumqlW_tmeogtdjs^qftirgpps}jlng\gljciiodnbrpgxxrlxc{alws[ik_tqbm|npqg{phektkfgjshsiosiurkno\kqTpkomiplmojriphlxmnphulmndQsenjmkmnkhnrlrmllqNKkdrVmxlnlDqnRsfqmnhrozon|kz{qnmYrgqnoon\l^mejkphfcmmeokool{ilkghqkq{jdlmmnynTmkklmq[lnxjplRlibnomj}oihnn{nmnqnl^pgnNollvqnhp|RqsP{lqlmmyenqojmbp^Onniknk\jcolnmjgoeoinYlCkvqsokxvTlimMqth|mcnnhod\oqp`orkilor\lqonupnvyi?nqmiplrsnoYn~ykwpist{l`q~qomtmnOvbluknpqrmpmp~qw[qjnokphnJf`iophlTl{poqsm|irmlokkp[j`olfjmlomrnrwgxpo~k{qnoainniurjqquNnpjnrnSe_oUqpIks\pu^popnpDkEjnpoQposmjluiUyI}tr}pjxrhlSnpqlwqkkkpoyxmoynclokfEppud_q~nlnpyxpmvqdouct^r|kWnywiiotrcmgpfnjmv{tnQos^sertfim]ajhqql{sfpvtwojnwguVyokllp}mqUlzykmainotkihwoTtaz\czptirkqoanj{pnfymjbnyokwhvouqpyvlo`s}jTwdqnh_rlgdpnZRumq_aj`shoiqtred^qksd|zjxlrddZfe{Yi^txqknZmedu^mj|uzucmpg~gj^lrj]tZ~~p~Zntqnqukitflpoixhmqlumbuh{uqxsqloknlkqoklnqjk_hjanwivjnmlfklsfllkmixllepmpg`psgkbmozro|gjvnljgao|k\slgip}mgqjnmw|cmWtwciousoeqwzrhiqzjzipkuplaxfrhfenkhqei_brt[_klxmfsmjX\vhtjlnpvqmlqppqqnoroplmgfxi{tgntthj]tIhhvrmojfhnyteg^hvhnidckndmmiojjr~syrwjmohq|nkhkvjkpiohoksomlsocmmivssivoirWdpoomonpujjqpiunlrvVzbqqwuOexjoYodhqdpZkjlejjvpipvyu9ugmqnikkpifgrkgg}bnlsfiWnj_ghnYtbvlm}pybljconiqNfls]jhmvkqopgjtlukv~zbhmjcntrlwb~o\oqgnUotlsjmmjtf_dc}XnvjilodrjkoV_ut|ikpmjplro_oqqkqelyjok}hwo\trfujlV^ogeortxdcrjeuhqdlnsuhglgowgeplkPqkVtprdlptge~pnsxchanovot`ixltkyjahjPgujlpqi~jzqvlpupdXvkitmpsqmzpzos^mxnblfx`n\CTxnT_vexffnoeosnvqbjqwqsl[hj}qxornxqv{wloV>glsogqykimovcgU`ijkznntqmtqmn`sghzxp`vpoefrxlqsaZxpn{ohlf\qbcihrpdjtmfMimzvXydmkjt~jbkf{mlkZtom`wctlgji_xletmpc}bvsmfvlrp_ht{fmvxomnipnnhitqm|upbnhjthnsk~\|lnlswlsobsqmrkqrlfflvenvocysstinig_qytpcwqj`t_thslitdpugpa}tmqkvmnerynpYif`t\hounkwlmknrkokfmo]mgsog[kgevbjibtfs]sorqcmh^inyMlfrpssqmh~~rhohlUhrvmvpfplpsjuekjsnhtsjpwoivkcoozpytwjeqkklrleqsp2lmgYlhrfXil{osjn~wuhkqrpxZprmyhlmujronuqeOsl|VhfdhmjgrvYitYppqorrn`pVszkpqmlZDxuluyzYxirmqz|vkoirqUkhytwqkjnrUe|mmqgnmjkhmnrngnnfurpluqkprbfmkiqfjniipquqrkkl||nxlkptqnrp|ehv^7jbsppenooliismfkzjwmaoukhrGsnqr`pikronqfppqnnQsvrxfopolY{npj\isnQklpvknonrckoobpilqnjmplqnnkoOpick`QnZphr~nunqnRqZmnllnnqq|nI?sndO`mjnmmprjynjmnsouhtknnpovttqmhy_mmgncenjl|llnukosvhnmrNnQpnmolonolqhtmNkpsosoZpimik\nUxbmavpnqQnqfk_ooktmlmtlkqtsim]ogplqrm\osmkmqqimnonvtjfwjRkl~qhmoowsonrIuWrgij[vqmrXmmkrovqplomkrrloxo^jmppkheonrogkoXt{:tyaoZoImlmpunsnmqlvmppmmg`i^p.hujkosop\jbhjWqpknenqikmfnuvtfkKjaksk]k[sqhqvl_njjukhBGmnjnpll}plmnenlurfPNpmnkmllgwmelxm~@qvolqotpZ]onkVorekomvjQ_Xgvpwmhilmwjlmmsnhmtlpk{Xykkdmn.Zxqky{}htmosrorqsux{v`jrmolk{hyjMcsmboifpshtpxlqpjspxnTlq{hc}wwav`dsppsnknqnsnm[Uekya|putgjanpsgn_|F{trfrcm^jCn_mpggnie^oojfysfznr}cuqt~rfxomegkocwcivh_uhpnsn||xkpjouJmk}v~toMhv|oVnyw{apfhhnglZ}stlXuXdgogk}z`bbjyhvq]|`h~rwkeZgrHnwUetmvqeblicnTOvimu[gdapqeuocrrnhnacjjmpwwj|_poocUlhoclp|sp\ettXxrtu|drtz~ypIkIshmnvYlpOsmyvkk_\qrslejg|tzqdthYsbqilvg_jnrk`oiu|oiZ_vodxYhid^evYcglD~cutresgkVtfcYzTr~Rhngmpnlodrogu^mqhumo`nVsrhjWpohgmbjtwrqkmwtosodeZm_ltfomitKTnPk`jasbaLtDjpqZqNnghZZkknJmqyThrxixq|puqxvof=}hmxhfYOqhoyoaC_ftsobpisyhmrftijb_sdr|ejn_gqsgfu\nk^fhqlrfs}hg`rju]neg|njldrtSspnvaQhYpaqinqgkprwrYnwnRhninmZnrnZhnlpqowrmpopokomPkHmrmqimnmnk;_njon|kousmmmmmonxop_gimhmjlro@qVlpcq,hjohqlkjl_nFOlrcopjmfmoqsohlrdhhlllmlkUlml}moo1zqqprozqMqqopmmqilqgmpTUporinopeul\gmlxskkntkrgnfBhllmzQmntomymho}{dPkmconvnmlamlptrnkumnp|lvmsosmmtnmektodfnkoioeuupAropX~upntnwpJipmrqqsot`sfwmliqidjujolihpkmcqlfjWokbrsjSirptwfp~jl]pmpnHnxkckakfmnvolen|usgnqfsmehaidhk`ftfqlkjpejmpqqqhlzqoohmm]rsgzmixk|kmlobzreumkdsh_qgphqdpmdogkpvttbooAkljsssv`rljukiqnkikhtsthemydjpfjlVhompm]rhh}driiznwqmoenzomkz|ichhr`hkbjlkihkzW_vjmmnpj_o}jwlsgfoei`m{kronbjhbdm`vioekeonveyqpm]hkih_kt{timr\uogvnr`krlht^}koqy[y[lgsqjjifmrmkhrhmukoll|monbok`tqxlQrmdp[lbtihk]fujhuiklmrkljofmigwjgngptjXyjkfejptunklpzxeyjehlfqkXlhcnvdovmyiu_opehqqjhvhj]nogimpkojhjp}ranpupnelhmVtq{mttZs}[pojeurzs||}jnj{urzytwez`vp{suvplmvo||yyzfqtmgotmossrpg|z~vvW{naz_kzzym{xyz{vquWj~qx}{tnrudwq}tjzxslvwYyo`wwpz|wsfjrppkv~zckt|wryiuz|tozpzvj|efqyywi^ruceolq}fomzjzgnmyi|eosWaxqkor~vwnn}eswv`hngu~rokanlqeknztprvlptonbllgrkzrbXvuweqGoqlmrvukitcqmjnen}fntisnbt[ocngynesiXljX]gmpkkTvgg[rhotvjs`rp_f^scqrwgtrAleQoqkmjotpqasl`nf`olmp{FqwpvncyppnqyzqqxelmusogBYgukolgrs_kkmhoe^w|rl|qsmxiforldwxOonjuppxqujXtuwffb~s{pjnxTqtlnjSrply~to{ptxmmutwullmpnknnkwqmpfqupofk}xlpinqmpsslokoni^EmSumqmTupDglpxqmjgcn.y[nokproToo:tkeohKkpholnm}qZ{mqkt~otonlrutvhjowvqkRlM]mherqUqmlpmsYlumkhq~rqqnnswogtll@qinloqSwKl@om~n\_nkipnuvIqcFlpvqR\nmlllqrxoci]kfsopmko^oGlorgvpmymlno^mtnosokrlpnavndjjohkqqppm\[mhpulpipwpzmmqmUno@bfbnjnjonblnvLvnpp}mgqrenjSktoziTqnn}gklopr_qmrbq@`{hoksupmnuKnqlnkTjlliibqOhtrlhjloemqSmkivljitpjrnsamoigmYjh}knp}wmtqpp7pqogmjUqnkUxsmw}]hqmnkhlr\rrf`gkqPxnph_wPtkOboHilxpkpYnnimpirSlooq|qh_nzumgrqqe~lpNoLnombhqoamrkgmolubkfmbthfjqmmRmn_hvnqngclpjvoxpqmfpqnvklhktpojfmdgkeagqptkkgnmpkflackuoikvniiYwapq^w}p[nutqtskcg~jipsqolonjwriydpirkop|niicidk{Visnszokjhs7mhmekjiiql[onmkhmhkpyiknp_gmnsngklri]opwmhhrkkbshtwth^loljkkonkvtfphdwolksvhcnzvljkihlqn|nyximfl\lw\|pqemipg}vVunmrnhqjTstk{dlohoYsnunprnqjkmofgrm_rxooqo^rainpwmmkolsesmemjrXoohbmhm{sour{l\t^XtospkkwktkgQgqiqnlevi_rLWrh|hoimysmjo~]nkufqjlommf^t{vl|Sqvp5djgoaillapbl]5niqpffs}unnjodnf{YlmswtqtqkI^geot`gs\vksm[rbTtmiry~qhositntslssoqglr|\mmpo6ovimkmnpykinjrmxootlnyo`nimrrwtnkncoXnoanmOds=i^mnxq_toqjfonnoqsnhaqskwbfTm_npilkrqmg~umokkpopokupsljkyxqlrm`nqlHn}mmbnmjKhnnpvosummndlkndpmm|ooskrmjqoXuihmG~Qmlopnjwn_oqjBmnLmnip~dngY\uroqgnnglullrimnmppolWywlYlworrn;mnnb{ejysTim`iwsmntwmfdqpp\eqkjwxn^llktlpuiqs_qbrgtloWovihetskojkgrwnihsgl|gjpfwjxniqoprkphoquxfeqngercwogrbmkooYpnvlrqpowldoqihBhsohnkxzphjdlqopRjmwkMYmng}\vq`}k9mjjq\kpukgvqsjpl_namq]mgav`rnpmzn~rcnhs7m{ztlbsrl_vfovqhj]ikrwsdglkrz^[oh}aeelnlqsrajzqpjuohhptmkiior_o~khohnqmms]nqtt|Xqqoro{grxssqkpjj[xgoumpl\nmzisqqpsisirmQtkMoqvsilbqhvkgkr{uooewpegaoqqsoowpqhhkfZnnmksvrZm\fp`\wcotlptlouro_uftjq]qmytdswleihxtppogdq_mesokqjgklwvpf{jntpbavuSdiejrqjnnqodtm]reywv`rfp~luj`i_lwlw\obrsjnjuoihpwljqoqexelclngwhofm~ovzoqWkxkjs^uoftqXfpmlevso]xjje]ngttaronth}qobpqsnfqnOh^jnkunhpnzmop]ronxcconmmdXmtpomqBplw|sYlrqxvnrpkeZmqs{bqph`s|axoqgcXvmimttjcnewsjprqinJ`qlZdfqpjlfbg{nvijqlLmkhmosjyfveoi}wstoZfjebk,qhztqowjiz}rkqbr\ljmvljaltqsQslhy^isj`lvstnkujfbm~wvmwqnwqutqrbfqwnjmwkovgXfWzgeuneuqqw`dqcsh{osgiwfolmqnokoplmmkpj|rja~opoimh`koajd_jmniXgxlpby\ljd`efdmroWgqrkommsvsuhuntpsgndlnidbmomfzduljZvaplgo|herskclltjhhpqllmvpn`llqhl{}jsptgkf`\sqgocplstjpqVlllzhmrdmpqmk^kqgqfjhrcwsbrjmsytfrsfqhshp]bbtmot^[uoW|dngoecrienVdSi}[oh]meopcztqzvxvjszomifl}sxliphksSsvSejlcprjtptyVidrmmkunbT{pi_jptj^TpfsljpdzXyxVVnfgjliopnvjcblosqfklvjmlptugldumUf^xpfMxiufmypetZbdVlinliWqc`jfppoywiukpfaZdovimhhnTydbvxrbgsohxhmYxsZehmuldgrl\q|qfwptgfc_osackhj}dpsavsvrYyfusopcdqmfgf`qsjuqshm~dlnbjmjjqolignrhjp`~i~jqkwvOnUnhl`plv^oliotmSofts|tj\~mocilmkore~fh}mrkfkn]bljrodlconOc}-mzf^jlpafmojxrmqq^{xnloookqwllzmvcpggTkhi]lhveomtduSs7]RmnqqtsiVt|YUnonspnk>koflwa[cizqjwsnhjVrphowgkwhlo@bqafqwSoo]dnn^jolnxnZjgmlopzpkq~mlrmynsjsjkrf\fljjafupk[uIm=isjn[hlbsqfknynTknn`lx^jQgejqqpfjl}ko[tmtgnph^up`pso^qzn|WHomxXi_atscYeqnkrp`nNjlbljtrmmnnoz\okkrrmqmlqpspvVyekui{mwpujjoqeklmpmn[kysolslikwojnjwofceSlnWffiQKp|qsoprlkpllDoenC`nukoznLzonrrdokvlkqqs`us|eolkmzoc}lnpb{hyivjghg{jesopopfial_o_~psmprrwquockp~|zgV{ktsvp{plksfNrkiiuoka`mmtkzNspowjpstvaon\lzwxh\nler`lylzooklljmj~ps]vrirakl\go`kygkzsqsohwpvcmtjs{ytt{mdu{kuklyngntstjicpboikkommjsjtvjHuZsehwncq~asukdxtjllbngscdgedp\mjnnvqfgcfsmi]shfcmrpaYdiqdn]uwdwaiskibSm|^heqXpqmtSKxlpdi\jfj]gf]aDvsfgqmtSgflfp~gre^dj[pbr|snozgklovg]pmilmlib\c|ngmW^gbtzrnNykpViXorbjtf^mjjUfm|`lujoegfLp\cip^k^opdmispZw^shzhWfpmfoq{lpo}gww]fgmuk^rOncqwqphvjmhqrsdhgnqeRa`vghcfl~|zLYapdrsmpkwjWrniokonlrmd\qjmxt\glgduixUqHhnqpmCpjnNkknWreo^rnjqdoonllgmrtqjnoonnxnobnmrakOqolqlyilo{s_kppipovogelinu_uakmmpoipi]j\egnpw^jlmmmun}vqorr`pnaorqqprmonkfp\ionxjrojomjiuyomllmhlrroojtl]osntxjnTHqunljmXdg|spnhlbkqurltmjiSp]\ktroijojulmnriom^pmq2}pxocklnmuNlno\Znl|itgpoeojksmlhoqftvnglqY|z'ulkpllpdygpoxblsptkr\Ypmrsooa}rmsmpspiqlqsdspelgmdbtIkorrtoqfmjpilovttfsmjwfSn>nm`vqjxsrYmm=sopkliomqinep9qpvJhlvpjhmhs_stgX`soq^nljsskRz}v\opksnrcrmoljgnqmu^iouwsjqihojbtiiRXijoqnpbq%kOiomymlirotq`mgruexmqqiintnvnwpgsmrugrkSnnphdiptpjoo_ilxxg\r]mgKrkhloqkdglmhgefjjlrr`aohotukmhp\k{nqsogpkpkqoTklqa|{Xrqk^onmnkkvjivmvdsikqvswpbsc4jpqum|tr`rohekakocppsasynlR[hiookqq$j\k_mlernoamqhwmpfiMgcoxppcm~qgmqswknkYvkmlumtebnlqqPrZulqhpkqujsrhhmafnsjk{2momktc]lpSljhpgohc\ol`slnplrqhrho_ztmql^eljoko|mgp`btzmphrkpcnbXhvxl_clorjkRljeluum\jqepmj~oimjwrec|Zuii_hndqnwlonu_lpt{n_pSv|kojjtxmg\yqfae{{gs^tlitsnpidnyqgjinoypiokklmgtovulho`Snpkgyekomhxnc|qxpmlodhmpkrbpppb[ivoYtossqlpjtpjmramnqgnqgsmhb_Xkhhfjnrqhgr^jstyqan}npqloqcrlmyowqhmhYvmnn]oinSsntVkkomsmqrbpmfixnmlkmmjono^qjVjppnaflwUk?pyopmmmo_telrmrnq\ow@pVjphetcltnlrossyqom{ksnotmt`vejLnknjrp]vkkjonflnmoqm6c{lpgnmpyhmhopregkptompmnnnsRnkKmqmeDollpqoW}dMmomo]]nnujljlakaa|0frbnhlmojmnnookqljppsn_spglol>kkw~Zn\pLeOymrkz~oiscqppisnopvouevnnVnj`jojmsnumnlW~m}btjpQpeiJjrptpkozfnkmqnoqkiagk_dt^cXproliorjqlfdZisqfscxliueo:fqmp_wdhzl{klpj}hu]klpiqafqo`tgmhktxmmo\dtfjmmhrrordimtdrojgnqprXupoumjjZN}smsygqmiipgvqpz~]v~dueyqkgkisriomjVolnmjpPikrgtgWsrxjgOmv_yidnqlmoicsgtyaUw~psV}~stumrllfe\~erehoerjXkuUkdkq[nqhtpc\rwpckntithpjmhoir:pqZojlNpyWtzgtWfo`x^jOmivNeapgysn{up|osZQfYplukmosj?urkVfwmiwfnsnlc_ycmQdalqjYqgiqdhfs|ijoqmsepl}ikcsrh3rxvko}[llfYlnfozlZgvqjjmmkmirylLjsojpekixbvilvk_hnDrqcmjpVlimlpmo@lmzlfokYlekbsoietl{ldgiilKrkp]yqgr`kxhkhijtmxn~nlpwnw\dj{ioXon}kLqPslrxhipt_rvlgBngsziphfqrk^patnnejqubgur{ryRrqqlR\tn}cripodsq}zmSsrpftmvmmlhpsralbtsormhqgtwpmsdjcZ[[lOym{nrw]ulfiszWu?lqp[vhvJrjrrjbg{|fvnokotmwbqkrkkrmalkqcekmhtqolrpgtftfo|~sujmmqiko;eswqjinjrkklzkM^np@Nl|mplmrosqmmyqgposkjkw`lm4nrmHmo{hnopkoijloawl_b|{imokkpoZpoZmlnok;nvqpqsraznn_mrapgmoxkrlknxrphpopRLpoq~nlvor}mhrikutlkquGqkppip{hpWdmwoWKmQnmllZstnkqpq|jmnurltmak=tto_pemmtlpwramnpolommolk~cypmn{jn@]Pngv{bpal\glsog\zlkpPnfpJsyqknsfoi_wn]ou`lyipxt^pprysf{wva_^Lpdk[tpsdo_kn~{rzusmi_j]fiRsii`nirpkpq}sYj`{iFqnm|Pnmfisgji}mgydzYujprtVmjqgnmemYmlpioaonfhuwmh_xfwj~hdtoZ`tjxtpj~ZfoVqnhkwqqunnhmzulXoqf|\njbru}r_dmj{nrluifpnnqjjkdqvaklrglvusfnk}wkpdogzno|ikxgdqukmlrk[kkqoqoenqumvXknVwiUokmpmjsnnl\Rmvnmsslfodnop?owpfooOnklmpnmOjrfnpegspmnmnngmypOgnrlb[kknkmpnwWpnitsmpUlpmli_oeflronjoZpenlnmq'qp~qomdrlknmpsanokmgoZ~SmcaknwblnnioktqIjkslxulm~gpknrqc|trssmpmmfm^prnqmlkzpllRVrilo]ojTWUmjebKqipAunmnjekawdrmjnklnnqi{hphhgNoekjqf]omsfvm}stRsqmqMUgkonbeonXomlpkrmoTpsopfnf^kUfgplnltsorywLvumlqvsqikqqqJ~jon?fqfminmdllogan]hujmqqikppadtrkieniqtmkavislzllohnn[TjfoEntfpqoqnrph]nadqlpmpxpnCmmtmkn~hd}kwhqtjno}qtnfongmknV\]mjcfXlstZjlrin[k_slqqnnH[lpmTknjkqhnommnlqpWsmqqonsjqqonosmduokpHevqmkml_nswobUlrlqnmQnbl~Sni[xjowlgnno}dpluZgnknvjnmlvr}nporlphmk{kVojnqpNppaqluS{nodm@oXqpxpkl|pmmjkqLwmmpmpng^mknqlSoxvXgnpvbm~eqkqnmoppkwnTkx|qodmplmqkmunlptkpnaponzuftsqmlmMVFnnpobTlumlkimqnntjdkkm`pkmblkgmg]lnT\rInspqklzsnvvlolgjvhCimQpimrnsnhjlgkqimklqRkdanOhivnnpnlhll\htjmmnxmktnroovtopoinottjgwmslumbsowppnUW:so{rtnmrdroonhnwmmnGpllipkprnXxmPlism}inpltmoqGpiowpkonlrqv3Sv}mqshmmgmmomokmlonnp_ril{mchqZCml{r_Ut_njirniostlnqQlotLmnpcokwkzqnoR~nzmnnnplppomR=khlrtFhalhqvlumcnntrlpnhijpImrPswdsXoxjgppinhGjwp]xnolrplkqmtnrfxlkWpjqpooo|pmooTnq}qor]xtplokzo{mmlpnnchmoromlnpomo^umGepwm_falUrmodjFsonmrjodMmnenkroipTM~OnVrokljxnlnlopnpm~plpBuWnmqnoj^Q|nmo{m|kfnglo`nlsgjxognia|jdpvdfjmsmmmqslmg}Z[laghjqZ]pdrnf_fqjnlqghynq\dyqjvldpWgvThjcwieepg]pp`X_o{n{vfvqdp_elvmv`mlhao^x\tqubdfjnamzxmndk_foltovo{ixpkZmvhhfhvhdjnein{ee_imljrlmuekisolZlerui{`wggik_u]qtqdqnuo{d_rXZfsZ_jwklfmdctSlpgo^nildwlglVlpgfole}jNdgpnl}ihriqojyotoknpnpjpqnbvotnkmmqqnomogOqdvktnnsqMlenEpkk`pZxWkklmpi~m(rqko]oekynkpokbohrukupsmmiorrofipXqcojlvmHxjmmVienionnplfontqotstpXojl|qoffmmylolkqpWoownTmpnlnnkkkn^nlrz~lmkmrnqRV~xnkhwliqmilqojnlnmm_qjmI}ssorpPonLorqkfVQbomou|mgtwqgiqflm_Znp|r`qit`ieuJkm~jhtywtZu`dqtltommesppvnyfgqlmQwmlQij`hnr_slxpidqiuljTc`roqpizhob|gMP\wpkojasqmlhor~kqkv}rnk?mnzrnf}vkslUng}flinyrmwjhknpfz~stnapjwgvkpm`kmbFgiqkpmu_tkhdTvx7pqpunlm[ujSumml[rCTatznjrmcnhZpolaphefljh{{hojnlhtkdigpskoehqxmelCoOtdtrrqnZpm{m`logghkkNgrXv``nbopbqjpmdippjtJpolu]mlqklpgqpntpausslqzbo|duxqmgb}OrsosY\mqwftnqYkpWdsemlaloqvrg`pY|ahlromtksqyvp`[xyhYu^qmk{pdijnrpqhq_kpzsnSopj^_spbug`\grpvqguqBalionqsqZklawX_qotUpuoip`rwYVpdot\myrfkrxocrzpidn|ruvlqqq^unvmjomrhomnckptnvTpmUdk~nknlgmoqntmhlUojep7tPunn>l}mScnpjmlpoqokomqYzihokmhmo_mhzrmonfkkipntmuXuqn]slYqopoQemtjsq]hmkhome~fndo{lupqqnlnltshorjZnmpporZmngq0n~RlZrpkjNkmDrmpq\Mllshkmo|nPF)tonounk_nklongolklnoVP\xldjpk|sttrkjtnsqpknnnvdok`rqgsrzZbnuoshlodgZvspmueyerbkrtofy_bulooswrlsbpproXopfqmowgmrt]urawnonsmkyjathm^vmuihteg{Fpvqofru^ztnjru\ptf|nthpTlonllWotfohqpgottsgs{woasv{jkm]fhqjpmcfppwpomkoqlhlkjihWpgxpoodq}nqsrvk~jjyxnrnismnYzgxpf{km|pfmntsVpjkte[ssjhvjnrlpnslvjmnmbommmzxmmrpnmlSlukmso~q}Rnlnqblnlpuosglst{njuqmtpeovjkqmorlli^qrppjnbmbnyDszw]gstptlno]tyjoalojhWqppqmopm\sonwmm~lnjmJsnookmknncqnnT_oqnnnwml}jqnpppeqql\loronm~Wm\rqonpiZmtkmroXrq\`qomolnrmnkl\n^qnyq`nmxnjllpmmqnpj~moojgllnllqOipncxg\k{t[m\nsml~dlapqoikkmjlwkypmrmmpmnokkfooq|njcqsLgrqpy\mvj^nnimtmxsjmnkvkkxnyqm`okxbnloonmovkZmpllmtuimqnprml`lqrGet[pjwnycqjqJmTgn{rqm`BkmooiwoOjmgsmktngmrjjupjnniprhXkt}opk|\oqmjnmmn_neErqonpqmmrkmtirinmSmalkiolklunhmnmpkpm{oknbptlxltmlyyPpqrdQuYn^pnfinqZtkm]rpxcpioWkhzpgynnZunamnpufnjmmpmjpqkoikFfrbqlqsmfkbiluykgmlppdqgqMvpmpYVg8mfjhvnRw{jmjktnshujprlgcokrUn{vrevrjosmldpxmsYlmiMAtkliorwntmdnwnbrmng{nsnkms_rl_ontZUsnnoks~lx}mspfykrmknlng__PzpasoijkvjxnmoiusoYplmp~Z|njidpkjV{qlhvzjwsqsohxponquvoiopemurqmuYkmogmoknptqrzqqceniqjmps]qknkfobqgslppiiSisotklr\mhmmlkqpq\}nlruptokbhrsaponklZwQhsfmiknmbmgn^ur^mopxhmsmlsxdqlrpskjpqiqYsxturyqop||mkOpievopkiqjdtlighcorkbmmgmsrspwkmllkjaSjmkunqzqpr[nFpmtnrnowgjcnlsmsmmsulqsvg\ligjnbsqkplepjqkioqwn[npo~^iziTiejp^Rqiagiuhkq{gnmlulomobiopflkonlmmroion_onjpmmokolpr-ioot|mtiqcon_nhkn_pOpolsrnzmDkZVp\ogeuNqlmqqapuj}klkpintsployXlonjqsqkqnw}pulqQrolknipkpTjhjwlprmlolnqnook}=ospoou]zm^mlqsJ~roPpmlpaseeiopqoxmoojfmphFjYoo`qmkimnbnrpnhlq~omnlbkqirkeoqfTooohioVsfkbqnmmrcptqXppkynilrifshtnotkPpoophmrplpvYrftooZxjtOpynxlvmsmwlpnmmnqwnuoPhoidjglloomsi{o[llfq{pljqlpnXTxpknmArq^lcWlfoXoPqnFhloGsodnpkoonzmjmixlmqpkpmmlqm_n}mrXldok}cm^mmlqcpoglmjWGkpvmmoo|cuUgim]mnoqn~plpkjqhmo^nmoUoLqYmgnj}gnmokw]qk`j}niunofhtcajsn{lklaZqdclxqokngt^n]ypp`e\kQhuQmn_tto^qhrsilps\m|mnppfmn^|fthmmmm\doon[vgYjhu|usmjqNxPh}Rwmaodlni[nk[olYRlupileOpjlSylbmanmgvibrbhx^yu^gtjcejeLklslo"Y]tsr\fkxmgmuncslwvmnmpnhlgneoscrwxobgekihmomeWhrvrPfk]qvlo^ncpbigtt_oSojmpqlQ{nnqspopwitvgmkwptvisjktjqplifkLenrzlygopmjfukokiZofsnvRgGYz|p{pQjm{pYVtmrmsqj{noho~_JtifgxosqlxInlkso`hmpii~jsBUk_ljTdmhar~urrgluhvgtox{t_lolbhvlsvqigpVhlpjklXp{mvyp`Jaonplyeclwrnvnria6chtltkeqUkbtrnW|uhQomtir_vqcrknnoxx|o^lsk`_ebujsjykmfR_hjuorneikproiyogyilssgoc`jlovojnptq|qpmujkqposhrniWqvls_nknpjjiupofgqatolfjmfgeplrgqnrmjsUl^pWozhqqbhqeoorjprsiutfdwqlsU{krijg{jppelpmezhnrnopngmvmhguJnoljk[yqheslwhldmtngqixnktlcelkftnitrhucnlqnfgiqmm|[tpmlkmrgvtm~eaoobkgkrmylgjjnne{ifitomskgnojfjkkemgkpomlxlkr`nph}lcnDmntngqotOonkslfqjpnqumVtqXnpf{qt\mpm{wmfsUrllhvrpcqppp_4prowlmrElB|ymnqo]konnpuqopsinma]rrli|oolpnZlk5jqk_TNmnhjo\okXopklsnsopj^Xphkqrv^qlkmZldi`rBnqpllZjnnnggysjk\rpmpqg:lq|vmsmpownlpomijofnunzjukjeknqohgto}o]UpeoYp`srlnnrjspQnmeTklozukmqonmdgmlqlilrnmmqvmjpnchtxhtlqpwqgmn_qLipllpmYk{dkgnbP]m[jrsrrfHqgQllmikqgksfoasnmKlrclnknh~kkgzmenoUnlpP_topnynsfk[opojtqsuqk6oqmnloiQFanplnm[lnknmpKaluqnq`xkqrlninonlwUtzqloonokcploopilmlmomx}cldqldoobwenku{uq{q~mk{iinyku`nqmttoalSuspiwgpqeyax{|tbjqktlblborglx_neqpqpauvkwXiwgbaqcio]vqzeiqqmoqahw\njessgifoopuowdrsqwjo^onTmlxpikdmo\neWogkt_ltinuppo|lv[ritcn]rjioisi^{WrpogomanRzongsncnpkavkkRz{qsa}jy]t`k]tlnkr]nin}dvom{rzvndpfpqTlttrimorttnpprlutsqqpnpcftti^qhxibrhtou\lwxp_kwdykligkyhzvtcsnk^kn[Xjrdv]grkjxvppqqppUrYtqrhpuufzjileovy_{raedi{u\sszqwl^lmkp_lxjm]m\sggpemcbydfZkenLnljdrjteYYmbjpxrvuk{]ynohX`upvpufyooesjmlqibgaolaolk_bnqprlpwvppnn~xo^`mlQ_otewXelkdngkj[mzyzmtbJnr|^iqxibSiehidrlrincryrthmpocljjslqmnjmumdpdo^lzkGvkltlzoilltnw]q{oq\igrmmikeoevrxn~iforhudooWklpkqmrmWsrmbksem}nostzQ7cog{ork{njmngovlrvvylivnrnxdwoqjjmkrojpkyofrpfzvpkmimnrnvpgylnliig_p]skqYogivmfmnmol6qporkkpxRtZnrokmeqv^xr\pij^~lpslmh|nn_onmoiid|{mupltqlqimvprhdooqj^gpiiPohehjcnkqgqom{phlqkul`pojolrnnppmikqkorlnipgknoqvnjZnq\jsfgjnoonjqqmeknimujoegsjpoxhkmgppmmlurilnhlrjhokcmcotlnpolqnnmmqqhlqdmjlnnmelhhkkn`khk`mpnbijlsuleojodnorpepnrokpzknlklqlmfemmpld|ocmmhrarrlhnpocpgjpumvlzjqhrrppqym^ikfpjikpgiqmpkmkpilogjtkkmnqlpioomlSmlkm`emno_vuopmosqrrnslniaqowfEtvwHkoTppm[kn`p|minsilrmnhtcn|v`lsnrihoKjnxkonlzrknqriphflmt^gwflylplnp}nmhcrrpvpcnslBmspqppigo{jxlglrrpqlwvfiWyrpodlZkginnnhgnoolnmvoomropoih`lcdlhtsmrno]nqnmspojk}pnn[sgjeo_kwfXcki_lUrodsMo=npomlppzllkiokpinnkrqlmonojoknkkvlhrmri]mtvkhnQmc}mlm_lmcqmgs~ipmkpnmtHigrsg}~arzkmkoqRokirnikqinlkmmnotpmhkpjim{gomk_lvhnMnlmknEkVoKjhjljoqsn}jpq]cngsmnkalninkjnyjnojnjlovokqmn5jniqgyl~jlvwsooGpmionpo_kmnpnmnojlnZkntmXoQpoh8npmpwj\nhlhhntlhxjnrOqqlpUmqohnooo|spjqh,kqfrkmojmnXxkwmnsmlmin\o[kYni|lqoaxnnsqo`qmokmriHhlCamlYq\mXkmmjoktkppnkhtnpllmmrmjkeffrio{rnwl}qroruioholmjrfipYpmdmozx{ykhqdrvqkskXelrmknnn`sropsljmQvpm`do`noijkoikmio_o_opel]tork`mbopmxrp}tUkolwkhmuly_nouomcnlrunzmfpyomrqiulmnwp[rqjlvmX6jlxoi`nlpq}fjnqpSzbkpgjtjPkjZrknlmxskmkbknmspmm^opkJr^oddtOwopmgbsg|clptPlnOoo{m}fxMolnYlovmnthymlksozv~nnkvkuthvgkspzdqiepdEkqlQomn[jqsljjho~qrhziiVpnstskonsoTpfhudhaixnl\k^xndlskvmhoZkSt`sefo}opvsdhiin`imauqlolnZhkkkhnhihg_t]hb|CardfshspcTokzaoNnnpbbnsh`zswkknpplkrpofsmmpdejelkn]lmnrxihVpgnokcmlknjwyl\ijqDgpijikpSnoknHk|{Mzjmigpujyw[lsnlccunqnqpnsxlsjslmnshpetlphY}qinselniglYfnmopuvqmrslOqtN~pnr_ookumntlr}opfdmojwdWeVjzdld`oxxqmxulpgowglp`tcldqujhrkpdjhpl^kTszpfbjj^~Nc}novlmknrunjvmyaZokneclpmvvrrhjnkptjjwmo]tfgahzklimXbbnpd{uefinhtgmplwtifpligSXrpqqgiknksjsirhiitknmqyxSulhYjtkqwmYqmrrjmu`coplcqp|nlmpsu_rsrposhfjmltspcehfmjinoeyfkowc\umpokjpwnusmlutkrmnkmxltiptrhipqlfnwovnxopjmrvvibepdpiofqcpjuorooyy{wrvophnfkrzujwmfo`{pmjtsyjiqiptjlmgonornsvhbyfqvrlhrrsmlqnxfyqufqtollkluvw\ktmkilntlxlnomklhmnihipve|olnsihkprgciqrentjkrouviyqjuo^okssrjmoqqmjsgrto{tbtrhlsp`jt{vqltvhiod`dZvxohq{iisaydm_uaspmkokjnlfTkpatfWkUxjnRdwrqsmc_umghmxlmzhlwj^kilovvhailkshqkxpf`]jmt_kqxqiimijkrf__s}qbitlpUjllmogmqptor]agvdoqkdollmmzrqeaxpnrmhkgeO|Xr{frkiwzciNqllwcakp|oqqrlhop~or{tpt|ldnpipoynhljnkufkicjtjnVk{mcnoeswjosovztlikcooqqjolioqbqownrZD{iovssmYeKo|dobRpkRgkslnvyoj\onpqk}lalgxmwvvml_mktSthchkuglfjzqnhijrqmVuhispck[u[jeqhq_i\fyrhyljoZuZkusrdrwspvxpupVq^ximnkxxiiwacqfakomaqoplqgqcpmdQUrq{bbglkbu]j]urmtvnjqpzctml^krqrbyy]qmilll{potuqspanjimZkmasZmbmfhTn`Jkcnplhsgbqk]plpjv[mmflfkposlsJqciutyaqZpmbqmfyshoj]WjtheQmT|iqurbtskpjhqumhm`wsllwaae[sspjuxnd%lpmo_mtoWjrQykzjjin^cnkjkmmbspposeiytlmXophj^jxl|mnlessvptktaoreRflqOmhoEqtvlktipsiWHs[WrUiwoqq{i^hopvnpWtulxmx}n\ntljkl]ylkghhoyqtcjuqwlpqSsuzhphsw`Tl|OSgkfiqeq`t@j{m]hgnmfoMomppfkiv]nunmGivmjxsmraVzlssopl=ikjnL_rqpycpthu{lnsqpvkdjrmumgdiemgnmojfFsgufmqop:i|dzIrkPd}fqs}lYr[MmwppjFpk|foenopyhrgmilhhbkiylouoysgkXpmnNglolp~hsrfijijnrildg|tRe|nzqtmijpqoyndpqgplpfpqkownrn~ebiqsfljssVfmtm\lhgpi_tuvkkrqzXxwn^qyhlrrfoix_kvyUiqhijyqtmsojjWm_moslkqhqjzu`rjZqnfkhghnhoh_llzoxqqnaqetlupuuoimZypiltoouwbqqssumsOfg_rhrrqsrfgZf~lmfvboimoojjTrsqxoPnyqrlcroieiosqfm~jnhsmkjlNlnqanoljjpo|krvllannWoTojmjloqmnqk{kbqqqKBoYnTo\oapztmw~pkisplejfqzWkULlhenplknjjmZ~rqhnonpqomr^ztmkobppkmolohj~mompoqbonuqwogkpLgnnilkmtjmwnmlksq`ylvmMnnOniqonky|q~GzmolXpoojfmlt^flap`oq\pmvpl[kdpqpwloixopmkswltpll7SenspwPnm]r[qnb`iionShlq_j{{hopukRdqtfs`kphnmg)^hwc_pyfpYcQgrkor]emdnhrnrfiqcs\{|jlogehnluusqjph]prhj`eoIupoTmh_{|iVfa~amurrgsknnopocnlghbrmqluoOwroorgmn"nkn_kjluzTlg]zrrjj/whnwipko`skontqvtqnmihomdip|j^aovhnzrlFfkgq]pjp`rrqoposn[gslisljinhrpstcnish~fMxyhdOnipelsqe^kqqo|ookpmj{nhnbillklppoQsmlqplijpooqyquojpoXildnn{oqofloBnrlmmomtkY4oN]ll=Xigkromn@oSoaWnnplmmjminkh]rpnm]qpplpdnpjounomilolGmmnocolnljpmmuoglmlos`piqlmnc{qo_oboZg|punonqgpkpejlm|qln`onhnxsv`lam`orimnongmnorlolfnlnd{kynjrYhalpwrsolWppupljwss_ieqpdpuZrhyrcmhpjohmhroxrqjcdpn]cnnxd_fpo]`eqooyllm`qorfpwnpxsn`nyldklbnhgith^{lqkgo]cdlqektjcqld\ssjmevrdplxqxqjiniwkyojprsmympelssjkbilq{jqjziqgqjhpntikneohqeflgtfetppllsiyroyihqmurkwy{znnkhsxkbrtqhjndkvnvgpcirmhk|rjmbp_nrtonnrpdhbgglofkmopxnnxwnjdhmegvmkwi_jnoiuqzokqkinpjoouNs\ttWlx.u`rtnHndivnokfimnuipVlWp~sP|>ppkpoirTrgyfhtqf:gjpqktsy]otom9jj[kupquiTmurnVpnmj7tonnGnvon\npiprsxloposnqosvom]ikRohndmror[fqmlmikkjpjopkblxzs`nulnmnnmqnopxmnllonL\jlkxmkjkmktWkqguxcnmk|pmlkmliqjcqlscxmo\nujrr{kZpsnocpnnrpksktr~iosir`qllmjmmnz_novy|njiyissmltomVqpXrpovk~wp^vVljrmonqisVkoxzrkqnoovpq`jfhfmksp^oqnessjygn|fu_uhssroitcongn~mj`uspeoosungkvvtkjnleonss^rpppjhoephqjogmpvoeqyhinxknpylzcpgplsloggamkrvqnr|rllYnunajq[qpniolegmupqqk]mo}ugm|kpikrapmofpknpj^olu_wmlTtrpcEkul]oopm[khgtdjaplSsztpfrkgpaituioVk`lqxgrfusimseg_kv^diqn`nFZvq{qzjc`cmq}Ofj{7g[|uinnn\knWnpUks_]nlutOqmpugpoptmqstnz\qleiSbYhg\gjnodkmhUjqun_t^vmpho~pgqQtnlvfdLmhpnSug_fenfigmzjig|o_jjclyxg[tryvp|mtilhqmiXnjYjokhoOnrgnrjcnkmhazdrlnntAkgpgmSnmkbkbksqm_ju]lAplTlqYnhSrmpkgrbkp}tim]rfljgrqu]hmlo]uirnomnpoiol^ikgq{npjyio~[qfwVhenhmmhsbpvopafsgnlqn{keomipnckrqhonhqksgvpiXsvyxkdrbqhfxsktvfrqojolnftslUrnhTgnqbnmefwmopajmwYvodkqstldlqi\jZkgkitzmdmhpcdsqYorkink[vxjrlnosvkanrkkk{pqiltmerj]tkrlonn{wnkooqolowjkvissp}pekojlx`lumren_bqctgl^pYlmrljnrrxgqwnmgfj[tnovcrlmwg{qmmzofjnsokmbi^^htnmmnkioosiiwmksumplpeylamtfmlsil`pqhsrqqnkhomsoqnhbsmigloijkkgphpeuulytnyhlengmrtgjoninszpmn`ktgqm^pwfftnkogcnhmrlimornglxaosljonnlxjjjrjjkmryrkibhlpjbjmqqg{h`gots\bsplpdoqppXmxoxudlkqqdtinrdoqirfcrtqlrjzlotewouyuperkjompr_tmnjfiidWr\qerom{kmjkvufqiyoexwhsewgjridiumnapmmoi\sorjaarqhnotlgozpgcuksajVboqgo{vtdVhqoqelhsrxqrvrijfmujnvoojmpkrsjvrhgqc^xquntjped\etteolbxihlnnk^lqkwmnsqpnljrs`jrvknjnwsmkljnnienqj^oljgpoaomjorxspXowpmnrooilpo~^jZkxTjlcvremxjokuVkoplknpdorkoLolrJnppoyo~mmmrrqitrjnojqjmjpkudlT_epzGmoSip]pr~orqSonjyrooNgsonOohponmzvuonne|qqnkgppQuk]ilgoGc^qomlo}wlo[yppwdJkmmlxkznpe@|tkpqxfsmloqpjtnqmlkmdbktjnwotTiqqhgdpjnoimsjgpnfalhmooimpnYiovlcolnQXmmojomilklkxxp{qonnhiorqPnommsmm|qhjeorolikeTnvkoO_qblkqnk\miiqpogmqhjkplnqqoh|nkkLm[mpm]numpmq'}opTq|penmyqhliopomlhTQnhkmqfymjjffnum{eldonprXnoxH`njgplmmnomkfrasBsh|kk{qmvlqqrgpnnlOmkprl;mlpo~fo&w|mmof!ovylqki`iwm]fju|glu_jUs_ngpwobdlmWoqUnkWeroojnk_pXhugmognptnTlfnfnwunoq^u^}poljlstsnzlqmmuqvhesptuidj~ntbirkouohtsmkcJn~lnjop_okkboovsYru|n[owrfpr~srsvwc`ozsmkwZglnj{woebhnnphr]qtjptfnlmqoojjso`^r_lmn[qgd^Vhnlpqkqggkfr[_nfnd]}srowlec_jqop_ijqmrqoftntusupntsrplyvqpUmnpjihtorxniqqqfmnr\p[enwed;Ygeojersbkjlsvqfeqlknpypkhorscjvau`kfppimripslxmosmkoqp`jSsgddroomlnuperoor|kmljnifnIkH|nooh*jjnlftonjgrm1nznkOocnokkq~hmqmjo\[ajoXlnqGko]okmlnmqpnovBmjooqtwmkknn`wuRpoj{lOqqewoqmudlnYmnxuirOWYkp_oogpnvnonsmlinlmkqm}tfcoSoLkngtnntwPlkirrhlqq4jukmtsqrZmjnxinnrkhlpUnksorqsurmlimlmsrJo}ZqWrunwsplko_qgpiqrk`{jcPs`Tjmblkjkqxvosjpnrimnpgilr|uwql}xVWphblkNpslklqjpgomi}GYmljmSsXzsxnjogil~cokUnkpupupn|znwsfnppmkgSnunsmjo`]jnroimqo~ncpPrstilujpkiomoio[llonPYmnodmkS~mlwtWgplmjhmomnmcpon}isjcjukdnnnplunnrllnnqnnnilrmjhvlirnnl`onsoo]lunorcrocn|jmpnmounanm|]jhlsznnnnpnkjmamlmnqohonpptjohusnndot`lmwkmpopmmknrnilomkyhqo]kpnontoonlonmmhqaxqmnmrmgetooes[nvy|molnom{jhmzlmpoicomfpppnql}m^kkncknkjnuncnppppkonpmpVzbjmklkolp~lpltqndnnrvlo`cnlqjirmnibmrgnehg{lmplfojmlnmmmvogyelqkmifqdprovmpaepltgqsnhomiipporgjidiljlkvpqspflilkprlnnqgprfnkmselpxovlsjlsgasmkprptqopjqdomqrlqmlmlnnlomzpwrklirlrrnqoklkrojoqagkoqjpolVrmigglknpqrnpphminklsslkqZptvnumskbmklrgiiolniksckksngkohlnkkqonllitvomopnbpsnvroqpopxtrmllgrioonsfqqkt]qonjotninkknrlnmhmjttognxopfamrtenilnookiknpuqplcojpnhbqyvoytmkmlmnir]oqmmlltpspqtpmnhmmh\jvtmq_o}{pkpbjphkmopnerisngmnoynoknjonqnnnsrhjpqlotlulrqtmqmn{kisspsoyudrnwopqmpqsrpntlg|ms~jjoqmmqkoodllpnmnooqqormsqoxolootfwmvtogkniltnji]YhupjxpqkinhplpmeP=nmkmown{ntoalwvxkokqgkmhgromtkjUmbhiqqoenkofnkmyepptollpssojxmWnqkfmg`pfq^q`itscpwHokjkmwvnulpfymlqvhohojplakhnsjnnpkjktTlt^pivlbj]jujppkeXrkodnmwmmnsopdrtuik^nmswuin]uVrkosminokhlrillqppupo|ynsapdovnqrhstsxlnlnvoqjdnkbxlgpnhqslvosjpoqmxopplbrsisenthueojllqkkfvkahbbwlvopppbhagmhmphkpqxfpgjNkhnigmnkniprel_lmlfmjncmygfixnioljifjxnjvnzwpxrlnlidmcos|okvopnlhrtqnfmowjotlnkr\kcb\bmfmomhnuupovhkjimylpjhnlit|~oflqpm]wkmkrokm{wothcfrnzjrWmhjeodqapu\nphprsjursjji_{qskhhomotj^rno_ffmmgfmnkpunqsjgyopp_qilkrm^horemwnlmiqkxmrvookamugtlqjqjkjkXm]nhoeosojpnovkgpqnkgnsosnojIn}hbjfjhjxlqihdjdlt|Uuispls|uiprikqndinfrmrnaqmwnoimqooo}nlokukhiftpekndenjmidll]impkgjbxqfdkxmksefokhnnapkdnkscmnm}dlwnmhlhjmmllvii{noxpqnjlh|mmkmnjoglnbnqoeqtltlkn{nilioknw|onprmmojnmpjjqmoocmnsolwolnnpopsmmrfmqpphlhlrvdmlpnsnionckjknlnojpnkmoslljzmpp\oltosZmqshmnnqkplklotroyjsnhpppglozl\fopnzormlwomo|`cln_mgqosnzmlmlnopjgo~plmntobgnmwntykeiqoymoll_hihYioqmo{pnropvnin|ls{otkqqomnblgohoomotspoq{jgonommnnvhrqpetlfknm}npj_r~qnqnrpwjxcatpjpeyjlmpkgkzqxcuhiokhrlhnhndpgqizpigppqkmmrnqmlbip`epgkptelgqoqmnkpplwg{ivrnaso_ojjmgknvtgqiqsmninmwlljwujklsnxoplimofjnmlnolpjpnolpmeuqqopvrsprelpljmlplojhnnnglkuop|iisknhjrffhilimnpnqnmrmyhkmrrojgmklodoqznjnkppbmmzqksrmktevmkltlimpjlnhmirlplmkkukqfRojoprmlnvqlmk^qhpomolpkinlcsnznp{ob\hyml\onommXlm]tlloomlmmpspqjxohh{gklmlmmncjnlgimnlnhoppopqnxulkhhqqvmqtocklpntm]lmmulryinotkrofnlmmqnptqihnm|{ooonnp~viofqZlqx|lponlkxcoocppooy|nqrnmslminrfbsmnmkofqhphnitjmkmml_l[thlpmmmyk_mkobywqqmxnlppomfbppndpmnflsjhjopnpnmsqpVpomlqorrnl~hoqtswmznrrlmijtpknnnm\qfpqnnonplyvnunmtlofo{qpqmmjqXpgjnlko_ostnjmlujqkqyojrp_mizmonqoolmtonrujompvlsmwnkcpmooonklosa|qoopmndkjpdplboujoneonkkqZivaoqro{colzomtmqieu]zpptomsrktmammpmponkqlptryootkfknnnUojsiluntokqgwgllkpl{fluijjvpnjwiqlsmfnlndnxilkhzskpnngqruvfkfko^cmqlgomrvlpgoqiq_lmxks}oluppoproqntkkqotnmirkrkwqgnezonfvlhsqtziysnkkqmcrikosslmtprkrognzgjqrneggjoridqnuuubimjnislnzhlujnmonpmkmqrljk_nqhponklkpmnlmpipnnm~nnlungptrlmmmuvi|rkslkrskoolrjqmkjk|rpqlfWtkjsshkfjdqlwgthjnmocmikinhkjnjuufstllmlmqqznrgjlcoqwpmslbnmnqsnnh^uhwlpqolrjpmkrj_}kgxp}hnqkpw}]nnquYrhphqjvdumnmn~sljgr^lhppkkpqpkskmnnmplnrkmpmkmilktubsnfqopoxknsnmlktlrqkeolmvpofqrhmcpdtmotiakQmhosqhotdmljwippwqpnmsoblj{qivquopukymrnslqonkfrpohxmionmilngqeholpnvpjpssnjeooqqomouqnmretlrspnbmj|pl{ogkhsqqmejqjnkrapliikprnnvmrt|Ytqjsonkmlnilhrxpjnjumpnnpubnwdknmaqphoktqqlolhnmrim`nknjjetlsjunromxprnqxsnlki|llioirojtkptindr~lkpkjolpokgizhnwopzmocrllqhfuuq~qlegtiqnokZoeplkjonmqpyrfnntkgqolpenmlojwlrhrmmlwnmekqqqhvqj|nnlx`isqdvooapwpoponqfronhtknp{wknnznishkrqohyndd}mpqsjnunukukhcoedoisfgxmnsluqoqgipprmpknrrs[_elkdgpckmnsrhtkvqijmjpoojfdirqrmqlqhjrqjnb_nspmimyrropyw^geogrypolflplnvfmkifveropumnippsss]fpqj~nnmkhhedotohknwokbsllois]wimionttypnnkxlsmngloxfsjhozpjihokokrkmb[kotnnpko|jbfjjoxpei_sqgmlv`oioslkqsmogpgprjslgvjtkqmsmpvmsm^qnqustlqhjpueiqohnepjk{`vUijmUptmjoPqv|gomvonrgoqlhgpatulvkrlnar\nkbjflnfkpoohfqkl[s``ongndpooburrigmoiqkjjsmntq^ioqminivPpqtnhmjourirutmllbi`kseqgjfqumkquoonoonhfkkskdllopxjylylcrjmswrlkthjqmqlsjwlnqckjmnjbmnhltsoqgrokcctmtkhtmq^lrnkngnfnsiorjiv{ojvhomlnvnknmxotsoogjqhvnqlvdunqfjcwjjajop]rplhiattskolqltimijfrgmrnelkpkfyhdukxigplnlrqhkijmitpfknlnylnlmusmvunupsipqhjqdmgqkpkkplinjntmgsitsusfjodifhswmjifuyrnpdhlnjtnkhouojhjinsosxiprmofrptnhkjlhponqgjjrminmmemnqtqhmktqnopxo^plgof`wvqnjl}mrkwunbmfhonnkitolon`Zhobgdkqkrkmljnmsplknjplslspmquprmqunsbnmkrihonlsnpmoqlnsvjnkl]nYjmeolnnnlotmp}`olnmpnbmlmtnpbodokonnool]ljjkiqnntnlnkppqiokwlubplonrmleqpnmmmmimsnnl{oqlokdhnzkinprsqzqop`ncpsol\ooqmdkmn{rqkoklfnpqjlyrvktqosnrijmrneomimwbrscmeh]mllwmmwkkooqrpnpzpsdjsgpMhnhqqppldnfkkdnrrqiomospploqpgnakenppimkqomnuldkltmpni^Zpmoksmrpyppnsgpmspib]qoppoltlsotkoootc{mwnnnivlhxeornexpmumnrmomghahqohnkuontpznkmrqll{omnkpfxkzlgonMbzqktpwsrnnnspmojnlsknmrlorjlltfjpmWjllkqtkzronkknrpnvoj{tenuvnfrttkmocjqymncrhmnqknpldbftnpqqorhkxpsopkgssfohepvjv{zkxndVcn_gpbgpmqitmongn~qkvrotdkkooroopmmneifpfXikkllsomoiosnnF]mRrjesttqwqpomwngq]lrroqtsgimnmhrrtnnstpqqopleilkswjo[pmgo{mcmtgqrnc}jjzXVfmhssolpyepnkorsmjpkoqejlkmlnfomhnmltosfikheoikbpnmsbisrmnhnfhqmqrrkomkk`mqgls|jqpepqmnxllnlmrdmppfkwrpngs`ojcshnhgvqmhim\kiqsdbrzthosrplpxcnrmovmhnnlmnihqjqllo^ktsjiosrihiolopjolnnwijomrxoskjiohbqsjmldrnspsmzjomnvkqynjjqfkbomnhnjmvlopkpbkhnkjmljnikhjtlmnngjmsqospprevogmvigcVthUlkmZtjvgnmndiSss|htnyikotjmeuyyrtmreodom{olmhpiintmkjpknmsdtm{nqitkkppnktmskhrpsprmlpoiqhgmrmdjqqcxygowrrnplql]fiisewqcrnlrrktmjoqnbcilhqatxoal\mgrprjXnnrkonlnmkfnlhoxkf]pnrqjplrqoopxmnraqoglrtnriojcsoenhrqoiesnfonngncntmobpfrrkoolnoolkmgntijoomfmorajlpLqqkqmolmtnmor`oYoomnnrprniXcqoqkxporqnpoqoommtvplipnmmnkopnUzpborlmQjqrnmompppiq^\mnjjxlpnnoloxvpnooknno{oqonnlhnxslzonoVwqonnoplemtqomllnkqnnj_fqkplmmqgnmblnwpql|mwlnjjsong[llnosfmqvnmolhlwsl`mjkpkusryokomormmnrnnmvupsqpoooo~txmjjiroshnnqttudzmr[xoqijnnglmj_olifojmkobkmvo{ntqcwqojajptqjoosinmjpnojkmhoohhgjZrlsnrrnppsnpmkknmlrtoukdfewpqlvylrxejunhfnlsupslmfjmzvqnj{nrm{plrhqqiljqpxkxnhqhpxlirqno~ggkonmpjksjjihkpkgphpqpvpmommujgjtihmhgwgoeapoxltmmjqkhqcwknmiollo{ljnmrnohniqnmrorsonkooolr^omkuljhepipsbmjznsrsxpvqqooglgl]rfmtkie^_mdmhzg{vnojhomnvryzrlnlhmp~oumijzitnkjggpsrphqsl\t~tvcipeukkirrriogYxontgjximnkijfpjm`rvnqntomolpcsleolhnmpjfrg{ktmnqb[totf|jki}qloqbjsgholr}qmnqikhjujlkimidmnqairncfkmfoqhtvz\jposnxmqjqijjkplhipamdmjkfhhogeholpgtnudfkrkprX^pinplu~spuyttonvksqzoeysuutonsqoouruwonkjpivpomlnrqvlm|mnuoobpgorphqjwrnqqyl|svswoooemnms|rlpnkusnorupsvenr}hknkjvkukepwlxrumqqosnvjlpmhlohvwsyonytxwjvxoqmlungkynulewrqttplmmhqiytnlvkjaqrahkknkphkqvxtilvmrojzg]pju|rrmlvijtrojgmu_nkggklfozioepqopg`dlgunpu{qndq`itnumomnjghrzenonopo\iiemsgqmgmtoulspnmkrkxfeiermtlneksznonmrndm~kkpmmmtkpkuwnq_rfoppmpms]l]nspnl]mmvkipkmfkmlizkrlr_nymmrtgpmtmdj{pu}omqusihq\rpmmlnvpmnqmolljsvlprsviosanprkkl{homwlpkyqumrjgexnpjcrrthkjnkequxnoln~punsokuaprtjomrkjykqkoroprjtnkrvorjuonuntykmvzkpqknmkqslmopdo_npnmi|rlbihnomqommmMpqnoqmpkdoqUlrhpl_t~mwunpkkslooiupmrptppourkpsrutors~llfq[ilonpoeomqnmnwpnrmwpnkxrpwomokpnlmnjZwnpqlmkepanXphvokbsiklkxq\lkVqmro`bominjmookhhfbloslkimmgrXomomnmmnmoophnpmxntnnqmlmknvflnjqjmlkmnpkipjoslrmujqmpplmlvemoahmmspoommgmlm`mnzqrskjkqjxpdmpmvn_jlsprlnonjocpznojumXdrslpnpnkqqotrWmnjqhapnpqnknbiprpmovyoqkonbmnltoklllknkqovjmvkkminl|jlnpsnrmhlTxolnnoqltklpaspoutkpwpnkwmtjt|mntllhmrjtmmrembtnegpfllkonxpdqrnmtjn_lmpvmqnmdltpmkxqojwwpr^rfpmldUmomceknjrhkxomnqu|rnphqkperkdknjtghnmqnrkfqninsfkjcqlmjllriomaqqoerkqofskqpmiooljxperlspqpnvipjw\omiq`en~iflnxojjkkqlsniiigjjqmnmmmpnhjnnotunzqhnlhgmsqjpqvsklqrhkxjiniqcoqhlhtj_nsjhpolroijkepirnbmercnmrsqnrmqrll`tnrktkzpjipkkjsorgnjpojrnlpubbmrmpofklptpgijmjjcyjrdikqlohmbaggusrkentmp|pdmaymhtknjllsikqqhqdcp_fqn[ramhmhurpfckrmmnlpplhnpu^pfcpfhmeotnrtiltrqlukxonsthrkmhosdoplrlvsonbkbhrnlmomonlerehsblsgntnjofphlhpqrhsaksnVkljvmmnolrhnhdlqlrehmsmjrrjwmqgqknnnqprwh]ficuonfoqttgmhpj_ippulkolrsikqoornpkpuls{alonpWnmookommqpnmkqmnpjomlnpeplopopoonn~hk^sojmm[oqFlgr~ouocppojjmnoqpq}nlkmqujmkdavisrpqqvomptoowmwkioonloxmnpnonirmn}mugmpl_mumljnml{\~fpoormpkvnrnlpkmonmqonpqipmmrpfoljn[vdkomjkkrnj~xponyXoldmpomxkjhd[tqtnirolplspolloomqpnocuuyngmqnmrmYnknitelvqcqkduvohpzegppikpmfboxxqpdlrncjm`tistjujlwzquwifostpthn|pgryonunfqwkwjqvlnrmnoo{voqrnquploluoterimmrnqcquvsoesrmqsaprxlm[lrlldgnrfjplpwroloijtugmzljlsj]ojmpplmmfwnUvnomognssqitnopookpsptkimxcrnttwlonwrqkqgkoo^jktdtgmulmsnojploduntwsarnmrnmhnlpeimnkaodoWj}juopnutwja`glegpjnXklrljqrpkr{citRmucjjlwgnn}qnovhnijvarpogpkoomiktrsohvhjserohlpnsZpweKj_isljrioc|jongninmpplyut_opfknormnjilcn\emle_hpofoovpdkysklSpmmdjmiqohrnoodeuqpnokqsyverivojkpmvtqm_mowtwjkqtomemgmmlsrno[jvwenoWqjomjli`lnkznoljtmokqmemnmrnfnokbqvutmjrp]rdhtrqkjjhnkkjtlolfjyns\hi`olmllqttk\qewpkzohkmpnkrhrqmmnmumg]afmseqpkovnqpogsbkpgjluiknmhilmifpbumpcjnlemalqojlvsnsynqlllgnmklpqkojonf\jirkqkpdlinmvqkn_grh{nomonplwhnljncqrnn{jnhkpsX{boosorqtlqpYhhipj]olm[rqlkkphqqmrepmulerugmmnpojtpoofjjkmpqojmvmyfpkqmpkhmlzkqhprnfliopmlsinvm^horkkunhjmyhjgpniimdlrqqlllmlqoulthruroonnnjpvqomjknwldhoquqkjrlmgpjusvvnxneopdyhygpntmljoqvgplljhoksirpljlkoqbggsmnjrqqrjipiuriijmplvmeqlnkhrkktnhnmwmnrjtgrknunnlowprhpmeqklirlo~llnnqpvneqjplpoknmmpmfrnphulmigdsswjpmjmhzqeqlxdrrsrmfepnkympwqiiwmulegllcnlnvnsznkxpulrknoowflksnrslootgqnbmnkqtnngkkpklnuakhpskxoxlhshe_dlqvjurjksfhpkhunlqqdlrrhsqqpjggnsmbnjiotqvjoqkrirplt`pkllppqfqrjerfhj`hiemmho]dqoixjprkmvpleiimnsmiooleqpmpqqgnplhsmipunskomnnitmkkonwtoononnrronmimdknmfgqpncnhtolthnojwkpqcrumnqpmoohmophm{nolpohpnkjjgq_qkxgwrpwrndqjpjrjpnzqdilonomcmljirqovjoorisloqknlupjvhkrhlpdopqoruikmikttYhlzqgplngnompivnqlrisrn{nonrnoznjnptkqiolgalhnernriqnnfo\mWfforlortlfkzfikhnsjqk`qnxrrlyhmextrovjohl`olmkmlotmko[snpjmoennflxrgfkw{sqlvnkqnYqojllkjofvlpqpktnuhqjfiojjriofldbjorlnjk}foqpb[n^qjwnkpvisyitnwl`dmjnmrqtjvmqnjd`antpmsbiis^^phova`muulpqslmooqxljkndtikzlYlkwr|mnulomjmpnpdonvnvpdib`pnnj{tfvjqpljdmjopylozqhejnoimkotqlnotrlno^tofuqlip^mlpr_mnh{\wanwolmzhurrmp|onsgpjrldqlnsmrmnq|pqxwnut]sortklkohnqlphkpmhnilhirpowijkhsnoielpou}oskqgnlklsnhjsqpieqnkitsmjjluuqi`tmjcsough[jxnmoxypkcuk_ktnsmorohuiimgeupenmwlonhzmllogonivqmlobsjromqrnfrrrkiortzpmyyqqoqhowig`mfumjqybrvnrqftyxmitnYfunrnsftqnljjpjaokcpgstosxnrptnceejiuqklmmknjokdkhkqpfqomspvmlop[entuprhrmp|{wumohjhnsfceoetqqknqiqqufjkkidplmpuzjmomrunmkqsmslhiqqhmcmk{hkkk^jUlljejxhnmrisqinnodnnlnrlnpypuhqdponkqhvkiqn]kmhephqionoqwlmjoojpfmlqqoiinhospsyuokrkonmgmqsfjomwppmhniabeonhoirtnymmklppsltloYlqompr^mmhlmqnswswpkqnnfkjhunljklqloonlwbkmoqm[ojo^lmnbnnnhqlsqcjnnnohplolpnkmomJmojjqwjjzmlfoqoimtltnoolgmookkpsoksll}snglck|oorpmog_nhjlnrpekloloimptrrlupnjknisxpnnnqlminkkiijnmnokmnlmnlmpmmropmsokmooq}qmntpltoli[npponmdmkshmmsojrnntslnnjl]ompmoumnipotnuniplonofponQuozqglflpr\mmphfmqwjnlonenldmojplsumnmjilcsoTlmmolnsknilvktikn[lnnnp`mpqwrnflmjsqntkmnqujwqogepjjirfllhvknsfoenumynhonnopkhlnbvj`pnnuks`Zk]skqskruojxynsnZoqmerhoirmkmnkryflgrlgoomsjjwkbovlognlnwoksnqlljlokrhokpnwlplnqqpjuleavqgnpomlJh`opufqllohksmmklqsnpfmuplunmqplpjliktirnbjroxgpmnlomqnabtmlmmncpfmkqnnbplolbrstdloirlnommgkqvormonqomrlolmmqpmq[vonmrvnrhkqtskwogpRjSozkyqjkmBsnki~`xioeprloqnprlkptprzifkdnwgjljnflolpm^nhnr_hppsZouoxcckljhslj|hjoqloflusnuzoonxgmqdqfwk_rkokbhiqisnglopxnvnnmqojnjkopflknqmiqtldoklonstomniqtkntlipolturpqillwntqjkpqkpXl}nmpmjbsvppvtvtzvmntnplp}vpgqnsogjreqinammqphmo|nkinpovpimYjquorlfv|gxpZiplvhnrnrkfms\ghtrueut`oqaukqssujlpjn}hn}fmisrgqrztonzpiptkdmlh{lmunuulrftqooentormpr]mgqqomnpjrfiphksrzgrhkmdprqmknqdnUqmnjztaksskpnruhqvl~jsipinqtq\{jlvnshs~gqphpl}lnnhkmsiopi~tonmninn|hlvnpmiomiroqjqnampopkmordkUopnqjolmmjllonlpqfol`lfvsjpybijqplmrmpmormntmokqnnoj~pkmaljsmrrmanllhpnkoorjoo\mqmnjonkoplkjqpkjorkmjulnmjml|emn`msvpwm_oiqooqcxh]mljupalnnlkpmlktegxQjqmlmhnqnljnqmjvknooppk~zllhk}nnuY}mmrtjro`o^g_siqioymtrfplkqrojzifqqtrin\rkcwimnpmjkncawj}rsmq^jml^klesoooplnflhroqnjcmrkszj\ldrglunjmmumlf^lihlpknmskylI|lph|ghpklrnqimpfxjomnlpom~ikendojtimixjjpfgnnsomrptuomilktfmwktqospmYspmeklsbijqqnqiqsinoujpxys}[sqmtmkoqllymjpgmmoaplge}opmiltlqk]}llsjm_sukpijqh_npmlehskrzlhu{oxiotvolppmlnmtvulkptthgqwlvejcmrgofroissooklmmjieopmiogwgrnjpvombljrbguwnikgtkcqk^qtmoy`apkrpm|jo~pnnllviopkimsmtlmshsheqpkmspxjiiltloijmjq{ioitnkivmdgpojkdnnmipqmkprcpovony\bekoililn}nlmisoin`hoqektxhzinodll[rdpln|lfpojozmdpjvgjnnqdoomjrlhqogppifmknloqxmisgulapompnspndjpkmnjjhqoupfrzookwiklom{lgtmnmXsflkoqmjzrlbqrqnXhhkuknpqplqlorgxkhlkxnlgmvptr]rkkjibkzourrmhlqrrwtl\mpiojpxmklmgwlqkkjnjnsiojgpnlirpioigem_spqo{~orhwnpmrw~joYgklhslllirsulfbvsxkkoljtiqfp`mnkko~kfqjornmwqooznmwrlvgrjjuttsmlkokonRiqom}klllmrktnppnelomY_mupmnmornlmnrylfsmlpnujramzoXmpo\mnsjssqnrnmxlwonkoqefiomqpmgooeotmkkoqnlUlqoqqqpBkrpvgkqvqpgmm|lnpgmrptiqnojgspowp{oollqnmnrnlpjmpjXppltlhvjnhgmpmc}^l_mmpnwgpsiilpnvinmsjnqtfkXpokljlsoklmqqdmpnormopqnoojzvskmtknVk_pmtsvjmlijjwsrqierpdl^fpo[omklsimpjnjoiolooqjuuktvmsrvmvsqhkicpi~rjdvsingkmsnqkrrlqmplcsrfqndfnqlqlktnhjsrqdimkan^jotlotkismknmkmijqjlcpjoolsinbrlrzknknpriirljitksqlsojqljesqnmlgxcgmarqjkr{oorjmvmrojdfqtmdxqutmscpilppor{mtrmsprknzilpmhqrcplkn|piqqhlrlktkpjnnxolwjmmkhppntvoplkoknznqnfnjsmokkmmql`punqoosrnij`nrrlurpnrfqj~m[opoymnvjblnpnnntoy`onhiuucinnqrqlpnkqnVpnpmjinpppqpqrdqjorkvpmr`pwmlkmepllpsqpnrfrlppnokQrntnplmrmqnmoyoljomimfudmfhnumxoeq{mmjnxnmrcnpnmupmpkjmpknidyq~rqjnoomomqbojmoqnksplox`_tnmohqmeheojih}^lwsxm[mplpkitflmmmhslrh~imnnxtnmnoqfmkkqmphnmphplsvw]qlqo^mkhfqnkpvemessmonnimgoqrjnkghjdgirqoqoptpmi_volvmooqprionarotu]njkqmqnkljmmil`opiknlgxgqoikll|lkmknmjklfmlonkpjnlorf{fmkj]nlkkklolptmfjinlmulwkom`ommpntpyjsqrsoksmoynrnpomwomjnpo`ealjilfkmrfsqlpknkkhp~dtpknl_fkno]mljpqllnphlksynngpppolqpnprmnirpnlqp~loVmspn{koogoqqntjgopnopl`mzfmvfjpcjmiwoknnmpkklknlmmnzoqkpqopvrrrplpjklyl_|mokqmdqndokobx|mmjoZo_qoroloporojnlYtklooimpienopm{ncnwp`loqpj}ltgrmllvwkjnnmpo^ilvwuponnmqppjnsponpnnnbpnnntonnqlxlnZdgoopne`jnprlvlipptkprljnokbsrnjnomplhlmbgq^ljqliolnnkqhkjkqrqc]rnophqqnsohknhixlknqqpbojemeltu}zkmoqplpslfprloopm}pmlpojpxtpql~krpooorpinoovocpmqjrlafZlowmpmxllkomnmkotmjp^xkmnmlpkvmjrq^nhr}pomonophlpVsomlnymksponmqoSepzrjpkklhmoumpmqqnojmopknjoplfkp{cfpnrnmcneukmqohnnonklpbjoocnukdopqnnsnnZsnunvmpnoonomcUorspwmp^keninqnnnitnnhljmoikmXpp\nvfohosqmlqmropZnqqgsmpunxmonqlnmjdskr_nmxrqoouzmhloobomsqrneqvknpmulvknqqslpljqlkn}vnlorkpfqyo`jmolmmimcmmolpbmqwmponi]nmnnnronn`_ydxn_oknmmpmklrnmpoltopo_ufnlplrmmdduqjnsiooknsrozk{ipktj{mkrfkkvmj{fhmklrmlkdvxjosl]hrkqwllkkzkrqmnkwsk]ojnglrolfkhosuuiqkplhkouwjgl`qieiekgpvkuqpfgntiteootmoxrrnodnnufkkoqlnptrhomjlmeqinlisbmsunjhkfmfp_irjlredjpfiillkkstwxjknoqn]rirmkhxnbuirobodooaogehi|stjimsmlj`lntngsolhokgoiibqmkmoignofbksmnhgskapjpml|wqnnojplnpsmjoklngpnneqnyppntmorjlljfpirmmgo|npcphp^pmjknhqelosnrmwm|Poormjdnqwnjmpmhmhpujdqmqolpsioyyfltapl|lkvl^pkqrkmjnlmlmqmxjpoppslospdpjppnmllmntunnqmmoawvn~ooxpzbkmnmnmjvphpjmrouopm|rlqniaertnn`rmylqkmqkjpokonfpjoUxommlm_nn[ohsig_`jppokrk|l~sjibooicmoeemmpyjlsnijhkpkryporhtkto|qmtqsojzosjjdpwlcu`qojfhiigmpssolhijoknoujot^molqcprvopOukq}qtpojznlodlnnjgxpqnwgyiqkk]ptolmnllqkqlpqakisymnsoo|isehsykurhlkpjmpzgrsnojoxlrslghrrgr~hjjqkrwmlqrimilekcofjmhsoponsiurljmqlmjdmmrnjmsklpeompmgppoomoi}rhkhnvvjqlnlskpor|lnmmfpmngr^mkn{qprokmpvm{nhulfdpcmjqfpznfqjdjoetgnklwnkrjkuljko}pa{XxkljomsoqSvrmexSwzqgkpojnmoktnsujoqnrmrlinimrpjnlhmhpkmps]qnhZlaokhwmopfqstgjilmooyhmipstnkshdmtknop_m^llnkpa_luikjishjjikqnhkqerzjpxojrlysmnmqnpqlqpgop{fhfljdrekwumhro_qnplopmqnhnlflntmnbnnkmpynonsqoqpnkgjp^tpcrsXreoowqZospbnnrpnlmkmokpppxjkrqushnkpkmorkqqrmlhnrvmjotspnwjqoodmofgirqdililrocjhoqmmhp{knjqyhknqqojnknnoelji~pqoqsplvopftpTm{crjnqoqeokq_lmrrhgnmmpkqoujbudPpnvprrinhomooonsklxtmncefookkppyo|ommpfbjslkoruvjqspigeprpllprqosnapopqmlm|qkfpx~nwlomkoorFckcokomlnlpnslrpfloettlqemnkpmropkrophgihormlktomloir\qitpzfnnnmptn^mjklqujhnntlmploeoqkpyjplhoo|jpoqxmorrfjzgx~lkkiomljjlonnmrnnoiknijvsltlmlpikhsnlmjtimrvmsuqorkooupatopmqqpto]mmnensgclfnnqntkpkprfoopojorpomgollnpknkopmboqinmnumlakn}mscojnqpkolmpluojuloonlllsmonkqsnrofoopproinvgprTixrfkollqqokjqsmjjooxjcpjnponmvfpgkomlznppmZqlmnrlohndqpofu_nowqnltnm|konimjmslm{_pnnnmlu`wncnolpzqenmpnoqfrkeasqomm{omzlmnpaigpumsgnlzqpvnklloorpsxlnpszk{mknpmmv]ponhsijowpclenqhmskrlpkqj}mlhsirnnvsmnntmlnmpoijqnkznoltm_llrrtakqmfopnqonulkqmopmmnmsmjf}noplaononroklnihrnmpqhknqnnsllwconkXppmnnrkugonr^mbsjrqpll[kpnmorpaorhpnn|mlmlij{pmoomqnpn`lkvnhongqjqnmrrqltgUmmpnltqqopooomlkjbndlljmkoqqponsnpgpooqlnaqqoxktnoj{_oquk]siphqnqlnoerionqqoorjmgkmmmeqmmesnrqgltnmllmmslksqnjm]ltskrlrkomohkm~ornkpiplwnxfm`omorfflZooulq|obmsookqnkqklmrlpngnrpgmrvnispomlnskqqnlfknjk[sonjovc|qosmkounljkillwnlqkrsa}tlqijrnghalxmnpmujouxpnrpiolnoonkmqsygkaltitmgmnppnmkkioomjknnmpcnoolmlokhxrmmqnwmorrmo}omknqrhkkfrifporoqoyptmfnsnvqfqppl|vslqpllsnuphmkzpodkjlpolm`lokqrqvtqgjsnmkqsuorltxnjqnropvopuojmjcpauzjvopgpjpljnkissrklkjykpvntllqhrqkmolmxrbogjnsplenjowrxnleepmmhnppmpliprlijjmslpuoqqkkiosbknoppkwhnpZwiqvr[nuqvwxovplyrlupinfvqnsokqopmvkiogfcppnpjmwkvhlmko_konoijoplitkmllkohinoYmihokmllmjmndijk~tocqevl_]pxmonqppqoilynqorkmmnitoaopcsojkjqipomoxo^cqhlihmhmoiqmeklplrqpjqmckyalmn_qmnnnqpm|vfqornmockrdmhnomkxkjquirnmpkjp|pniqqcmZneuelnnfhkl`~jhkkfbpq^jntqrw^ebexq|rlmpmpmtkrqnrlnpooofwchljmpnoytgomrrvvfdqljkwpepnmkkkmniksnstlhsrrmkhkqnypnipsnmrqnzookn\mnhnoillnopvnnioslnhomlolppimntvsoppmonnlhzrikqui|imiumjmwmzovflinnnditmnmpqhiopjqoprvooj~rnmifmsqpkkqplknloqnkruclpubnljkpjkmyktoipiifmnrfqmropukpifllopphljomotlonpin_r_ynnpflprqjolngrrnqkdqmtosokqnihnplmjj{llhimwiffzkdpljohoknrvjtioplwrorniojtlsgqbppnweqhogjfjqxounrmtj`mmmqmriylmfoltnmh~qmjminlpqrjiljpoomhtgevsijjnkipicjfkd\omniqelprssainnjlnkllslntipoqoro~nvvrueprlrqlflgnkk{uulcqrowhxnedkomlmgpjtmjnmlfmtrkjjkcpcqiqjjorjnn{qifmin|mpmljgjqksnosjhyYllqlZjjmcsuf\qlokkjfpipjfpbsminluvjimsrksRp}rm~}l_tnroowmrfnlrftpskjqmpoklvmqqjmgmnmlcupvooqk]qrmkoltbxjsihr_iot\rmjolmjk[pnnmtinnlljasorkghugz`fpkvtmoeoqori\tXlpqbojnqapgfbgonRrntmnqrqqgtlcyoe`tmkvtgjionzkm^hnhkqjrkxrZmY~mkom|gppjnp^trlsmgqeojjmqlkfntlreilf_pnumorrlnyjpk^lqjpokqovnnnk}mupmopnnnqnijemmstKm[brmlnwjhnqpelnzkimprnrlpnsom{qrYpdrhuqlvoq\l\j|qlmmnSnlsotnqletvthsrsllppsdolpqpjomronn_`anmynsodpiyonlirqqhps{^ppnmoouw{mtmlmUlqshiorwkmjsinqtnqopmgropnpmkh`Vnm\mnnmopmommmoplmcpomsoppnun~lnspjojkmqooxoapprowbqponknnrkokiollqbolnkljdqpnkknoompqm\op\nisejoqospoonlljmnmikoplvofch^cowl{omomjnnrxnhlzplrqolmnjqokpkwrmpIlrullgregmln`oznnwmpnk|qxoxnplgnphommknoljjnnxkmokmpfjwpcujsorkinmomstphlqmmnpnnonormpmgmpoohoqnpnsmllnooomlroompnny_[xnhlqonghempooTyommziqpnnk{qlrhllqxokj{pqpmyjlmmcjhsnjnpurmonh~k`msdnwyigkcqtpkn}knemymmnpmqfmlpj[gpzlviqnoomorqsVmllnosmanqomhrq^sfostlsXpmqpggmkmkpcmommpnkjiponqtjponmlnmqqlmpplYmmomgsiahmfmqhpsqdrdpmor}nrmunoom|nlmqooonrwopdfpqolilpinmomqoonpmkplk_c~mhmxkpzq{pqojromlqklitonlxqmqqbnnpzqomhskolreqnhmompmmqmqoonntrl]lodmqwrqogozmqlxumwoglqmtlidp_`lzioslaekqkmrnsdkwnZvolkttpmmqlroyjlpkmnllojrsudpookk\rononm_g|lolnnlqnjqlloolnsrmnpmlkpongq}em{lqVnofslpnlnacjbvumkp_llmQknlmgn`tsgzkxqounkkm{okoppklkmmqXtnrgnmnngbnnqotpqrjmhhnmqkotgqpnshlmxmllgklkmwjnnjnvqnlmkjmoolo}jxpnylrolrprrmjpjnuno}nulmlinljjl|knreoq[innnmmongmkn\jmjhibnlloknp`_pkofdnsjlqifnrlip_imnpnljlziofmipvop}llpqkopmlkejnqnnnolhqpZnhhoZl|pvnnmkmxqfqmpqnqmownmoktrjjkkmohpolmmgnlmkolktpfpmnoekundmllpshamnekzvouoqmuqpmmmrnnklkmkmjplomlnroknog{r~onpnqkjnkrnSkimmunn}qzooipnfnkunji`kmpqomon\ji_ohmokoamlsoronopwrjllswlnpnpnpwfqppsko|kknovunlqunanlkkqlkmo`nlnrnonomnomlnomoz_oonnqmgvmhmnqn`vno`nomjjqjgoljnoysnnrplpmooXjjonohpmrilwjfnqnrionvrlphlrqkwmfnqiu^ppmnvjmcpgolmhnookpjl_nooxmmlqkrrmvolnx{pfmqokpppjlxobpirr}ndnmlonpjxopqtpnqi~opmponopuum_moijrukilppmmjlhtdmoqpyplpnnmpqesmp{lnWoqbpd`mqq[peoo^mmm}n`onhmlhgnnxmnmfqnsjpmx}nppqqokhxpncjomkvjqjkmpovikognptmd^mmronqpwjr^hp}liolgmmynnnqmlnmoiplo`n]tsjoinnuinqmisauriqxipxYionqkldqmkpl[ssmdm\zlmtlhtfsasicffylyjhwlojprkrrfpmohiu]nhon}mupnmbhophsclngpllkjr{qdppj^pregjistlsYbcmdfioumhbqmsnltqloXslUcovjwglncokhkWhlhslqhqnhnkhZnjycmJienpiagnidsnnmojoqdlmxiupxoqklnqri`qhtrhnokiklwnlhrlzjokmfhsurpqolpkkprprmbehlsokosretlhnstomtvollioklnphapcipmripkluqijqnomrdqonlopinan^`qspkofinmkfgnlmnpolsporistje|{qnvmgymtrjpofnmdutjnrmlniom[hnkolfchlhyxzlpnnnrpiswrmunognqlhkjpmnmnmyglinmepcjhoptijjbnxndpxffkxqmfnnvrpZlhjmvqmhinoppjjrpnnpplmqlrpikklkmrrxllpnojakllxmzqkuxtlpkh{xbjmwplhuojvjmjomnjnpklmqolimmkloqjlmpqqpirjmomqoloulspkieqjonmkmpmihombqlpisqpnomtnpmnosunlpqnnqsrqnvhjmofnohsjootqkqmkqeknnnmlmpqmsmroomnjimqsmpfmqjmogknloknsksqusponqmopqnskmnirkolodrminlmnnuhlennmpqpnmmioqoplkopooorqpsoonnmnjngojlomnnmjkqmojrpnonnpnlmjptiliotlmomvqnpjdnmpxpqnZglmpgroongsmrnmnlnplqq~q_lo`jk|p~pl{ninonzwmnoellokpoxnlynptnsh\ouopolrai^qupnirngnjmplnozmojktohppwpjtmnohqklnUmomegallun{obpmgnjnsqkoknhjZnmrmnocwpnltojmiibr[kohgjjnqilpolromo`mprpqnZgwpvnpornqmntpspoljqermpzkvncfkqpojwmmnvrfcpordojsnonenkpq]nlfblqltrlinvmmmknouphnkonqlnlvmmpnsmzpuonlknwkgmodq\mokqklfmwfnlvldcxkjfpqook|m_ucenkij|lppnomm|bsokZlo`lpooisonjtlkmm`llt`hqknvmqmolmemmnjonvrnoYopqnokm[Zilnmqoaonwmmlm]inrswlqmcroprmlooqiinf~slnqkxrodpronpqjnmmnokozimntnfkodlarmsssmqtrzmlZcckrlrtfpmhjrvouowd|mongogqsnjlfeqli`i^rmlmbpthnqinhepiktkipfntkontkecmgdmmesoWhhpldmop}mclsk`ronlrWqlnc\fohsoluklonjhbsdokjginglcqrmjpnkqsnliplmowlr`rcqhnlnqbknroqplentpnlnhnqosbrnkgrnkjvgqwlwprlolhsfpporjkorwonn_gnqlrkxomgluin_nulrjkpopksmsqesnqrrhmql]nrnnhkormo{khllkchunjfnqkqksmrpoyotrlj{mt]nvfqmjioesqdntfnjookhnirkimpkontkokikfkvtotfkzfmqnbntpxiqkgnkllqwcnhlikjtlkrqjnhujuopklt_ljpihntgeglgrskqqzjqjnpmj_ggqvlqimjlcurklujiirvajoqfomkgrokslinhrutmuupdmoknqZkfwknorqwiqmoonhnppoonnaonogjzolgf`koinhsuphiilmvZirqlmpsq}lopkjmhYjlprhpmqkoWmuv]shk]torugmrelnqmhepilokfkyppoveolqbjo^lormlnvkopplVhwptqslegsm\|]ql]Wovvqk]}k{hrt_plmlorlnJpjinkjcmtrqposrfmr~okPwMnlmslllmmztlhljnloloonTuosRmjlixpnoqglzjsmvsjmp\kmsmqrstnjrkPVmpgitbsldoglkTXpemkaoiqnwunkb{rtnppnmknmjklojldppblTdoiqnkiqqmpvoonnmmoqjihjmpprplpknmyqmkjmphklniopmmnikWfrjkpnplkmmjhjmnmprhladquuhjhqosmrmnimgorlpmijmomwjnrnuosopkkhnqvkjhmkqknohmqtklhopjpmmejqqnjmniwothhpqprqpjnjnvooqenqpphyjomiihnkphmklrknjqhjpgjojlcinlmmkeolpopmjkngiiiiggpgpkhnmmpqmheypoqkjmtlqnmopnmn_kknmdmqonhllosmoonnqmkltncpppl\puvdnwplpmqarmgnmjjmnokyomklrenxsz{nnmlppojkZknmmgkoomlpliooghorggou~nlrmmxpkruqqlkdkos}wtqpionm]ikoomolopwhirwhohlolnzogm`trlmkjcsdioqolikjrhmhmkpmojrmioephu~cnqploumngnllrmplnlujnnvbooohjennkednpklcqpdq\papqnoq|pmmwjopmormfpkkmpnjllmoopmmnkmhlnpomlmll{ju^sirmmngorojqnkqvqolklj|mrcmhkqfqylqxmkroqhlsptsniml~ksqnppqpvmnksplmjhrqlnlndpmonbpknrxjnZk`maloinknruntnonokllpmnmgnqonllrowuslxmnklmopslnrni\lmrmmsoujjsuhqi`oqqnlnoepppppkmonom^qimmlo^mmgqXnllk[iolmqpmdvkspkjhqhb]vkckxn{b]rmkumnp`n|sa~pfnr{oecmkZmppsdkaqmYfhhon`lhhtbsiigimksp[nq`koqmamopqjqrojenlflkkZwdkfnpmmsjmpc\omkkkgqjrjkqof]tdpsklngn}lN}lmfgngqekxgfvadcethpmolkehkfkjwplrm_lhejp^vX~qlqkin_alijmjmgoxjf}scgqmQjkqkeqdwmlops^qYgbjqgmvlxokquk`nOks{cjklipljtgkjesqvkulqgnnokitloyzndpiqsupl`st`dqhnlhbnovmijbmkdqutelkepnvmpsmo\jkjmummnjknss_cpzpqkefrziXhkminl{fyjmssrwlfrnkqvpjfmvsofgnsokpfrmscepzixiofronqqkjowsockmsppkjemniikueojfklmtcjnlokkk^jefsphollfvjndjl}hngyymjjkyphklwognhplqilb{omnhimktppmobsovrrtivfqjqqnjwmrqpncpnlmemmhpnulengojkpxlr|mw]nfvdlfsz|lsqhnkphphdok`hqyqgptporbtprvi~iZjnaginnlppqno}lexojntbljucnmfulprgeujhpjoknlrpogqngnmimcrghpumukmpntownitqrmogjcfjjfmojrjxpniojglelnmfxqpmzsharyimrjrnmnlcbldokolinnoonnnguoi`qmcjlhrnflikqdqornmplwqjiprnlunpl^tisqqpmleqiotpnmqkomokuogprboeSla`qahpn`mfpmypwnroumocmwylvrthvq|emqmrlpLhuoxrokmrfoppsplsgocphvooqlsjruqmpmmm_roqnolsmoo[hgmfqhilooaqmonknhooqonlnhzdldnamnhmtmlnoitvduvqqumkimnplnjogom}xVjqmlomijukjmqlonikomnnjiwioykqpl^kmolslelmcpZhqdrkk{oqmfqonrglaqcrqhjqdm^rildsqgfonprtgrmh`jmsknup}kjwfimooqlqkktiihpyrtjilnnyskkn{nioenj^nifoiwrsmoe^svpuogmfjrlirtxritmkvpyidgljgjyommkojoqnoiti|gnk`ioimiiijmulwsispurdnmhqufniprqmpsmlcdfrjkjxjemrpsrhnpolyhqeeommkphlgqphoirvqmqimnrokjnpnxhlihqntinhmpietomqykglogkqolmjg[mmqiooqrrfdidjbu|jhtcrraornrzlqnk}fgpopinqy}whfqlmilovyqqr|ilmntkpal_omknegqlqmtqne_uqmdlkhqifolzyoVojqmfpvlghnsyoijlklonldqgboiplbkoxflgpkogfXlfppi^nongocpodmvkecqqjnpnavjoq{uqnaqmsmirtoWnbmllijlolzpjnmmrqgtirnkjkjmimonmifimpmlqtqnppilm{{mqjvsnnzimjZjlqouukmveoeponnnwomnrdwm`puml|roqoqpltnqobsmvomlpnpopnpvgoVtmamsmkkppplqkp{ow_nquldpmltokoltrnp}iiOmsylrimrmopalmppporlsknhlbpbpqtnmnpsjosnkisornmrpwUmmYcppfr`qblnmlqirmtmmrlmppzmkonxinjjcirvhoommuounloqqjmhlmozmxppn_pnztmlhutvorpvloolpimnjlqlmioobqpkpmmln\vnoekljknmimpruogncmfnhon{tookneropmjuonoujonpolmujotqfnnlxvhnnimnlxsomrnjjkvonrqjuoetqgnqkd[plmqinnllzmxglroloewdmnkmoramo`njosjoooimdlnnopjkfkqm\zkhmziks]snrdkppktrlonu`mqmpnrrxiqq^ulqbmoqqlnmoloopftrtpontrqrivhmkpuomsqiof[jol_pmqldoirmyglqsovhsinrmhnkoqminmpkmmjkhuvlimepjxkihkfmvhwjnmojoplqeurmpjvnkqpogogi{lkherqkoljjnhntijjsb}llikmisqbopklndmnqrmojqujknqjjapmqpwsoknoikiuovnkpqgnmnpninislmkomppgkkmbolmyjqgumqnqnngifd`mprmkovt^ooglijhoprnsxlhsonjvshdpglpstllnjqsresnnkjoqpnnnakto{hfnouhheqwktitmpssjhtynkotpqksheuonjnkyormiwbmgrmoqpjczijemmntkmilnjgcnkbrujnsvgrnhjlmlomwmngbchimkmjihjpt[aoxqonpnkxqduhltmmjuylyqp}lgkymfoolloms{nsju|h^kil_hqmmkfjyjxofjqojeoqmglyroowhmxgjkdoucijljiukqhtinnnmjiiqv}jnpovmplozslinusksdrqprjjojftlgjnjqkgshjxhllljlvlmtjmtdkpovzdullxmioilgnmjpmtorornpulkqsnelckqnjkpuslpnofrqsdmjmuhoqknyjkrfilqwmntoovzmkusausqlsqpnnlpqnorojwkyllpkpzkqstjsluiqfnnmnlknpnmjmmzngmnqrmskkrmqmrmoopjipjjonfrxjlopknpsjtkqrgklpqddorpjhmmikqpompnhlssmslqkmlqqxposlqnkqhsjnosqekpndjqhsvougonsstpoidmeseqmm~k[ovomnttctoloqkrsnsgrpczvjocifr\inkplqngcokimkppwmooknvjkmlvrqmhnuphkhrokbvekqosniqzrsoklnqt{mhroopowqboikvmijolrmilghiqdtpsmlwwhhmnssmhjkflrempfabtgnwjkjtusppbmmqokjjrnknrlphmoljoommsyjrgwqnpzvlknyopoovjmmoonomltkzlnplsmminpurvkspoenjylolotxjonlmnrqhl[tntnnjntngmwipivqetqhkpqu`qkkksaot]oontonsyjnnpkntajnsirljnmtdpgoklbhnwreknutl^hofeqckqniouhvtkjq_moznoibjmlkXcpolknnkktlhl~md\knmfjrokooopjstq^lurqrmmnohkvj\oonqtmmfnosr}qlrpu]si{dptjnorhrm__tml`ml\ep{odpougvdslfoYvhljpq`soorl|obmtmglsnfpkhnkt^fpvlpqyutdgoljln\ourtqvqaXlnphvnMnopk_ktpo}oligleirryppoimflZzmiokavpmsgvckVk[sxnrqqgqgetd{{mhjgoosudgllc~qusrnkhilo_ptkmxkqkrmdoblbplkqotsuumh\nfbpqrchitilmpstkjmnrmnknymrjjuulxxnkqqZxi^iqoptuojZnfcVv_hffgmmllpemprhn^qmupcqbqxunfpvros{rtnnpkwslqnspsjpglkpajkvhlmjssnolfknl]jtrrmgipexlphhiolntmqlooirmo^nlmslpqdldlimsgjodqqnoomlmmjmkgpkqqnjjikngkegrjkmmkfk`pixosimmkronsqjjmbjohpqwhwdqeqvgqmjpanjnZ`oqphgus`jkpnnkmmpolknrjdlismpmockkqmmqdnssQppkkjpul_qs^tkuiopkpkonoooodqrtlomo}rlpwinioqjllxsqlbncvnormpohjbnqkjin^ksrmspgo|soeYpO_o{m\rnqns^jemqoplmsbtmrpfmluwlkonqslklktunrkpouv_nkapibqfmummkgk\kkeVxkp}krheRlcnuvdjnmqmtajirjmmno\jqpobhroergnlj^vapkm{q\poxykq]eplmtqnzjqwhmmjokWnpnrpjwicnkrqqnnarkckoqgkZkthjKmp`pkrsnlnannXmfmqlpqdmqjkqlqrkkjoeqmpkooinpmj{kj^zrpinqj`psklmomtnenjmgvulmjlpomeikypovphvjsrrqzo{npxjpjvk_hlviqyjpujmqklofsoltpmhoqiroourolkYf{gqloodptjunhppnmgonqnqqohlqlnjkonmqpmnKro{k\hwpVooomoimr|qneomhozoovpmdvnlo\oqoksve}mppkoqflYnhgoklorihjq~}kjofnfijzndntyrmkpwrsrjvlhopjgliqkvrhnfilkjmu\qmofkklkloqqjmqoqepniqeqpnpmoqlnnmulfrs}oS[ny[lbofofrromkwkknmlliphwpu`nzc[onlnppnjjmNodwoiok{jstppmnhvrkpmlpplomxknkrktmpnlnnuqesmqnrmvpkalnmkmjsojrxvomqonqiuvnxrrYnpezqhpnnknwmsXunqkbimlafipkdhiltdsrcpmponcpkmonnomnqroomvvsnlmwnnWcipmorbpndp`mrngcmnmrpnnqgro|jiosploqklnnzmlkkevitld~omslbjssoulnnnuohmppmjqoosqlnwjoklolopnjnoqfnkkfkml[o}udlrfxrndoknxnprossttmpvrphjnpdflkqkmlwmsnqkjoqOjoq|jmllqjhqimymirkQvktoolkmkkolsnwmtqolbilmdnjo_pomnnqqhqvnonqnpjnjrjlioool`nqiisonioklspoljqhltnmqqml_mjnemhljdnpqnKzpumyonmpkoolojgoiponckqrormlhjmonnHrlrlnynnemptkykuopnfimbiymoookmqpg\pajtulT_kmnlsmnXhbpkdonqnnrqkfmpgdppnvndnmonoqeomk{m{oltpnnoc`lmonimhohnnmmrmkqpjnofoopppoqkpnudkpphjoosoolmltprzomoqtfopiimskokrh|iilhoqploqnkmmnqplomomoj~}vormnnbjkokrmnlzlbrivxlq~vqtmggiknc]mopdennqpncntsz~sljdihovkjdwpnbkkjeefqg_pipdqylxd}equpohdntofoq_yffias|apmgpklagilipprjsv}cj`anv|qhg~fkksnopsjoqmwfwrflhjlommimpvlpfpenz`pduisktqnqpxmjqcp}vmmndwknoooltso{sngopzqtlmzpjweprolm~ktusnilovkpcnqsiWrqhmjrlnnglakssorkolju~kjketgshnfwqootipljkkntmjuohilm{qssnkllnnonnkr^lhpq]msPpfqlroZpiosnn}ymolktnmelg{lunu`vXokolnmpcmjmtojjnnMjljoomrpveoi~oqQmnfpvkoqhbotifdpjnqyZnolp]lnmrfmnnjopnjllvolomoqxllqjkp_m{sxnykmotvhiswokrok~ln}omppgkrtrqgkkjntnpynkmompfontpmm`bmtmylqppTxphhb`mmipuu~lponZronpyhoouonpfppnocxmmunkhnpnsoqnlphnqpennurjyntnnkvmsqZlndnlmsptnoqqfonblmYk^tcponmrlgbphonmphppfmonklgwuliiqoeorekrsmkkpqolqvmooornimusgoofmrmnpoupnoowqnokmnhchqlsmpl|entxmmqmryqqrgroolvpnnmlspinlsh[htboqnmqjnhmomplknlnlpirpjdlqpnaxtmnnvhnxjgomdn_uqneojjmumsnstngukvlj{mkpdmvjnufipamllnrn]noofipluvmmljponhtkgljcedeljkqplsljmlmlfmevxmlgXpjlfnpgmkrk`gipqppplgfysozlkyphslnvsjytmkwvunhpmksnimlwijtfZqymmjshfelfjhplpmrqdpwomnfiqjnjitrgnhgrlnlhoiqppop~kkjteqpmnoqjqqmx}nnhkjogqjmnnimqrnkqrlkjjknlmmlokasevyloiplmplsokrtfngzmgnxkiptncblvvxjem`jl|j{{mkpxiqd}ovktnrvsqonoqqjddrtipriou[uoplel[lhdluqirimp\wmdqdbfprqrsv[nnqqxmsnnsrospmplmkgipgpktoohqlri|prfqhnmkiugkjqnjnhpojqjblfppojurmpiampmpltw^xnrkjeofttnZnstsqkqnhonmglqolnlmqno_epoqrlgkgsrltigtklodpsqnkeoVomkcbnmmnrnethq]kwkrrhjhoimtgmnlohplmdikphvkdkillhlneihocqinhrrdoln[gqchjjmqUfmplhqz`xqqoaggaxolhgjzpubojroeuogkkkp^pimkcinqrm`otoecjnpyrnpptnlyom^ksnhfeijngnofiplhqkpjjmsolkkfiomcvmlnidjwmljrrlriozahzlhhtitohmvqlm`nnalpopfmlelsmjliqan_piqo^lrtjuukfkeqelYqhi_\hukpntU`lpZgicjpdr_popv[juV^WWlWroishcwjswxtcooulurdvlppuxhrajhou]tkopp@unshqnkOdimyoih{fiWuio[jqYisr_oxurnt]VsgdnidsqankpqimQfstrlwgnmslrunSsuupjtjmhnolnsqmxtpdjwrjyrp`skggmomkteelcqsnqh{k`pflqmnlpcnqiMRklgjmNvgcqltfL`rpvhgpnsairqjarprtjlkqWjhlihpqu\mouilwdkmvkjolkgplrmrllmQvnxgauoppYZkkpmnuhbqznpppnptocvumsfqjrenlnrmlnrnpopljkmjr]suphkklutxfumqzlnnoopiimmgiraqjhifpglgpokmwmlnqkoElio^simojelm\pjjghRqcynmrjoemhmpqmn|olkosmfdoutbissqjtvj|gpljtdmpo]pbn[qjrmln^piknrkobjnqqnqmtosobwlwfjrnriour_pv_lmjhinqlltgudqpnmgunkmopgnnmuknyhyqbloppioutrloelqkjngrlpcqpqseleppqnhngnnlophgmepemse^lcjhsrlkmn``okjf{Xllwokp}sypljmhiqmmlhnklrilpoikkoloozkjrqushZp`odkiivnjngiphemkmnqmnpntqlroimlrrkkomjs_nlnsitjimllfqnpkttnkk_rqjhnqlplfnkmjhjlonfpqmmmjiloavomqkhowp]oojmphflnliopnznmnijinquqmnx^mvmfmmqroqllomohsnaqnhqkolsp{pmrblmpovnlnlpoon^tlmdomrj{rsonrokpsxqplnhnlnnnrmollffksn_onbpljntsnjjboqrltlmn`ixpnxmei|mqyplnurrohqkqnnlnjlp`txmhlnfobrgqxonjuplnnZokijl^omwnlrsumhm|Xslhrqppomjxnpnlrnqmlpoaaowotpyopfjjookhgpgvooovlpmonhppoymnhrplbjjrnijlmbbm~mklpmlrnlhqsqqskolfcoqwp^lypmomklqqkmlprmmnmmgnosrp{`jrkkklnoioipunpimovolkjtpotoppmznuiol^mqgnknfnzmpvnon~UurpbnqklqlpojmmokoqnkbZlkpqllrmmmhnismzupnionkkemjwUpnnmupnorkojkmlzhl\qopkotmonlnpomonoo^mkmjlYsqpnumnTpponmkMrnzpplis{pppbqjvqlnn^qwkrp]tirolcovpwpq_t~uorprihvkoyptesgtm`khoio[mrqepnedhdnrkditrfnroptlrrFfunnysxoufrqorxvkotltikmomqqnooozojmqmwmpltollmopmlwnnsreojlonljeirouktvp_mnqojjPwtnrmnphkmvnqirebnulpknqitrWqrlprqimlhrmnvmmljguulfmtrotonilxmkriueqlnovloljhppq~vgqxmtknnmqgjpohkmyk}mjpjofpdqYimetf^bhupnnrhdbknprppbpmiom|tglqluojsovgkcpjnporipntqmhkokmpl]qekpwxrfog^vro`mplilponYlmipkgklplotnoqnmkkqriqzrmn3pjplmlkhp]sfsflgse}moqlpmjlmgnnkmmmljmnpjmlm_oqsolhllpqmvtestiureoornosxkqemgmqmnpkorqgljomplfqm]sp_rpnnfp`ivkfnqjdloo~`snqjhovlvjjneldnkjmbtz|{xbowjrjwhismmmyjgnqilnmzk}nigrovizpmormqoiqloovqeopysuqlikwfommoksthisgqisostalupllnjyuhqfxqqixompnxkejonqtngns`knspdpjnmiillkfmndhomdopf|qiqjmxkmoyxmnjorkrilpjlsojnunoskroskkqsjwvrnmjljpnqllpmrrllotojgivrmphufppvpsnholeppgqmsrqpdknomohjtjmspcdoornrjlkljqqpwkkvpncqtqjmmnozukojqonjsnwgoirrpmjkmoqmwqh|uxbumjotnpmnfudgmoiqfntmpnqoetkohglnnmnxusoomosmooimjnntcqkoyojj[lhwnkpmkpjgmoosmnnqppihnnsgphlrsmkcqpmnomlltkllfgmoqrfmne{rmsjljponrmn{mfqpmpnmqmomnljromaqpng_trkqtpllqjvogxemrnoqoodjtquknnahmlqlvpornwkkplosrvlcjujfssperllsgjrxtmsfjunqlvrmrlhjqsovnqna{l|qwqreuoldjkdelrtgnmsh[_kothqdobutrdksurioosnhdnmmonysilpslwjergunkkjnsteifsnomsxokouupkighpomtxojlenlo^sq|gojtojp{qh{ii\rsnsprmhoeqsppdlepoodhslrmlwpxslorlrp~wqvqpqrnlhqpns|kphbjngovlqnjmn^jpirmtkpnmmKc|on{m_mreridkqpximftpnrfpymfonpnrrmk]mpphmnppmmpnmcnldoilrnjpppsoihvgi[m\qrlqfkMhpllznjhojqxjmlllnoig^mmsqgjzjmpvrpi]sUknoelmyirjs_hrppqpnsqpmko}ppmUprrpvslqrRmlthqho\flmoqoqmcopohwrfprrxmdonkq^nqlrrorqmmmsnlnlksnncl^laqxdvkmnepqqcnhngownonvhroflinlplmmqZtqlrdkhhhqsntljqmmljiohmmlqnrmlpoguplnxklrkmphqolqpsfblhoj{kimsccpnlptqinrnfpolpnpsipnlmrjrgsmqopblWmopflk{polnqno[m]nnhvwnrfr\omnldoolmpponomjnrmnpeoltnhdofilvqejbjssoyorngpmlhopkqqlkngomnqqmjqmoxkmnoonpqqopfmrpoplrsmplmgfojssgnpkhknqprn}npqqjlmumjrkskqouquohmnuiyopmpg`kpsqqoum\o_npbhwkpwtmllnmkrowmljmojkwidniphonkmsTsrwktg[smkkmmjnomgfjllonoltmlnsrokqsjlnhlqyoqoZnlkmqsplrqlooqnqg`qlnmorrmmmlorsnqmtlllojppcakqlnpkpbpnqmnnlrnmmmf|smqmutotnmosktmpqnmqojpnqlkplxollk\lsncvpgomezohkqnkk\nqlmomnmpqhpwnlcoqmlnllomkr|nxrohmkfo_|lnk{osn`roaiqmopqonflzXjoYnyskqrxnjpmjlj[neumnpjTootntqqooktqXnuxjmZqximnqirukorsjlkngknjipkeqiblmpppkqkkmtalqpnop~w}orimrofqxnfmngvn`iljokplsmmnmlkorjqdafqrjonofpplooqknpmpnplporhko`k^jnrjroptsgvonm~npiorp]nopmrssmilmnsklqniklos]notpplpmmonpun~momqy^mvgo`mmnmmqqo|pgnnpllnuncflgemqcotkgpmnmnriq}nnjtoeolopwoqrqpnoplefjkeqn]lpljprqjorknn^ennlpdldlnrnpnmmlrhlohlmqpnuseqsnposn{}iylonpbpopkpmolglnqqmlpooopkrjqcqrjnonjonmomqmo`nomxdaakslimnzerplrqarppkxltoloonjlipqnmpjmplmspqlfmmmumknqkpkjminojlvmpprpkgqksgnnmtnqlejnbpqkokonqomckovcrlgktjlrrkopmnmpqsqlimfposptkmgqoomerrdnprllunmkfomlicljkltqincoulnomllnwjnjqqroslnjlnnkionjlsfpojooqonspsuol|onlodnolllplklpunldnrboopmppiqonoponnjpplZmckmfljmovshmnqmuglmlklogysfxisthngtmcyohioiarutpmeopmmkikuopzgehtshnbpnrproj]snolqzsnjvspuvpgZqefgpdtlvwmplkrpenlel{njmumiqdznpsrfxhrnkkrnoslnuqjmposksgmrhofpqmooynnlpfquoqkgqZqlrlrbjkksorkaqtpoiogliltogkojd{ujdsmkbyxotstxpnkkpiqlrvlcolhiqmomkooopaipoofhkqohpjmnqohsrgjsmprtqmlnqjoopososmqokoolkntpjpmrjqnnoqxprookgmoksknnysonqrzie_nplenemvmmekqmpkoqkkospmhijnqlummtmnnrnngmonngoxslqtsquiiblnj\qrmkjhtvmnlocnkqhnprlfoipnon_jtnpjkjomgkihpk`omkkmkpefqlsqosmqrmr}qmfrrxof}ojmn|mlnfuqonngzkwjotqmtqnjmrmmmnoqn`mmnqmsnsuolpmnorlrqssjlonvmmvYmnmoz^ujo{mmgmkjevrlhnwrfnkrhuxlhenenrnhizviisnlgkwnfqoimpnegjzamkmomrlplasjqniqjo`plhbkhhfnow\pxlgdtii`mprvhskl~ulsnskmonxhpejzh{irloijtslrTRvtvl~lhoiqomgvhbihpljlfgoenlzqqonno}nrmrmdklbhjroosjkgqlgtrlmtfqxrpupznknmrgl}oxoqwphxpnkrmvhnmlemhkmompfn|}bqgiazkhhqtjrxkfm|rbolhlgmojnemhhijfpdpjjglZmtphipi{jlnmojpllhlhmpbmcngsrgqpq~kkcnjsjmjnhoknstrmlWcqkwchlpowllmqlrsnqsqpjmydkoqkwWokplkklonkolrgiuolnppkophmolktnpnlekpnlmnpojimcimrqqmmiodplRlpnosftrxpqwgnmilbplnmijghlrxihpk]nkmvnlevkmmjkqfet|gnoinrr_knjtrsrqnwltnbenrgmojlozmlmpnmoapinjbj`dbjtpjonsgfqb\jtjlbmkmamgnmpkvkrldmpiim_nitqpqrwtngcpidhdmthnibdrj_envkmjonl~jjmlslqipningkpknnntmqkslsonomvtplopeqzlfuhpnpiulpicypuoklltojujmimlofmmklslt]prkpsklgadlvqkmkmnemhbjplntujneninwblkmgblrioqqpouplnjgnjlhnmsmplmxzopmponopoplinpelmdrnzspynpoopqsmml|emlqnnpimnl^nmpvmroipn]lslrpqkpvmkyoxhrnxntr`lnoom`nkkhqmmonwqpqipnnenknpnmnlpmppVfmoo{rynlxompfcmnhnkjmmqjlmpinmknpmymoojmojqnmutruoerwlvlmjoalnnShipliylqlrnjnkq}pizsolkkkllkmqooompqokmnm{kemqgnkpokqmoqpmtlohjrwmmph~pow`rnqegfrqlq{xeqijmbjqoijvhhocnncnqkm[nfgkugljwopihphqllpaiocgk`moogoqttqsmqpxpahwquugjlmoompqnjfVtnljpptcpitulimxokkczlol^nrmmensnmpikstqiroli}mhosionguhclokrnlijmgntukejxqnjnmmprpka[ppmfnrjqnu|mokvktdpwekjnjhpnlh}jZpdgronr}ofuphiplivchkpm`okhdgonqnkppgnwkllZpimlrmpmmomoigmhqjmnnqmmnoqjmromjndkpv_nmmuokkglneofplnmmlvmgqlyrpmsiljpnlpmbrjrqonpplhonnppmokxmloorlwlklpmsolljphmnoolqvnzknrnkoYmmionmprknpqnvjoppmno{qeoyhhbpxwspronksraomXpnsjsulouiltoqgmjwmkhzopponmmjnlklmlmjnpnjjcpmpmplnjpfnkokqymlptmeumkprgmjqimonjmqomolpmnoononj`oomloomnnpjdnppl`iuioornhlqomrnmogoomolonpjrtwqyqspqpilvjmqpoipjkajpjtqgnnnlhmognkpnskl|prlmnsokmnpokorkpmuhpknqmpmlnjlnrmslqlokohvoolpor_oinaom^omjumkpnqkjcnk_vmljxplnvppooqmctcopihmmmnmtlonmolqonnpomgjppsyqjnnmoppojkfrmpqsnjrosntlvhlnqlkmpopooohqnnpkolnehgmqikmjfmhhmvkj}mrgogrnpkijmjmlphq~hujmmqmlqeknvgtpnvtgj]oispfgkrmewjlknafoqijqnlpfuolwunbvkfwqntpn\oflrlorglourcogkjpholikmqtnomkkqkcojopgkuutrjpmljqm_xlgnowko]kqlpookrhqlyoisoom{qnxsjqiorrvgmslnnsiqojiikljplrqrklkjmkodomliglokp{orkhjlekupniqsmjjkmdgirmelqoyitprvnnq|palwmisemdjplsjpjpkgnpnmlximfynnnaqnsptoujoqlkftmrpri~kpol^vmjwkpmmpqmooqktvqogiknrvdnpuontonkonlitillwrlnrmruomgrvkpqukrrqoqobkmdkq`rmjikofmjoqikoljglkkiqloooyqpl~inrgjkhgqkoif{oprhmlpsjrqoopqpwi|ibnogimppn|mfqklknprmgqqjorqmmwumr^lnnujmjloomnpmllos|rlpoirong]xompmgpovldrrnnrpklunjymptoTvphoknrlnolnsmopomk{kolrongmhjjmrkoiqrmtkukmmcplrri`nosgmhklnmpmtmqplorpopfmtmtpoppfqixoaloqnll}{nlmmmpnmjusysqmrk|oodmnpmemvijprsrwnmnlrpmmklkkrknhmqoosfnqrjrlojcqmxrynjkngjrjoqrlmodquphnueuoqwo^mcsjoqrkontnjgfmhnkkmkyjolkrsfetklqjemhekWfmohmpjiprljifji^qhwnvzjrkcqbujfupfzplngqutqmr_eponoflmkpsmmnqphvln\qplmkkh^nlnkiucroklldjjogrommpenjlqkn_kxrrxsixmnkqqdzolmnsbkdipqnhYqmtjrnkjbrgvppnrqnjfmqklnssbdjonhjublmmhmjtpuolljoplnmjeprsjmnoenhoudjhdnokmldqnmojolsnxpsc`fdqnhnfonXwnppoqduoiokpliqmlpjkkfcvzuksq{otuknfmkojnfllqjrbjiqqY]tppjmxjlsnjl{pvnoqodoltkjnqqzZjrkpglsaqlmotrmkslvm]nsn|mjmemecsictmokiqxjikrgkqlmrfphyntomLpomxnehqXnjnpsinijjlsjljokpxmnsiclhjpqrmnoksliljlkomjkqiqngovrsstpqjilmoiosojqllqtqnloklqmmnninglhlonfqmmlcqasiqxleonpnonoqjnnllqhqemllokinppttrnobqmooolnjolrmqpwotqtkjonsknmqmtrrpinktsphpkpljripinlnmmumonlsspkkkrm|mhhlnpphikkhnwpqsopnmlkjoogkqmmmkrvntnkiioflmbjpmpqqmlpqoqfoofilkjpn|lmhllpjopjlmnomopqjhilkmkpnkmormlsomlloujpnjhjlhrnmpnknipinohmpmlprolqmonqjxlblkgsajpx_nnismnnsumhljnmoqlovourlhYnnocmmzpnnmpqmrkvknnmoknjkmmpoomnnpknqkoklqmlnpqooskijnqpsvnimppakpoknommrlnkorozcqlkpljprjorolipenktfonkolaqpupnjmntnlfkotmnlpoxllsjmrqnkmpommqmljropomtxmknodmm`rmlkplwunno^nfplpmkpokoehlpomoppnmulnqjosrmiliqlpkpooj{yrhlnjpmTtpbokrdnmqmfosneqommhmsoueqtdnmr\njrpqlkjhqjopfopjopqnmlqmknxqnjZpgsnmglgqlqnlqkokvmonbilpmpqvikntmnlyqnnnopclnlimoohlrmpmkkpobwmqpnooyptkmfmimiumnwgppllk_ohsmjspnhnrpmnnpnmnjetonmorcwkzookkjlkplnqyonnkzkojntnhwqmlrltkjrvnoipnginoommiqnmmnlmutmkllppigrlnugtqnsijnsnspnujslonqjmimioqqispnwtqpnkonhkgejkpklilzpukkons~kqop{nqwmfqtlqkjsoqmoerpoowprlnrmonjrnpkhl`tkynmiifkqtooi{hrnbmioqvjq{mjnokreesrmllmymmnvhnlmplplpnfllllzhrnnlmomnjmciginlrrjroqklkphnrmkiipvqnrjootjlumwjns{dnoijijgw`foovlnnepklfkkjk`ikuikelkgrwnko]wnmidmhkskgbqjlliorcirnhmowmqwptxmeekmidzgmbobnjokhjijonelqtffghlpmhioljclpqlSrkoqppvkoolpmsfkpooojmrflmqqsu`ka`nnkpgloyxsairsonmapmkqphshRoqnrhjmq]drwniirklmmqdkqcoshngiunqopktm}orihipjjvbpsmnpnr^qjwkgiqwkn{knsmuovqolkl|oljkmmqjoj}pubtmsqkumuop{rqilrk[hokltjsn{ofojjpmkkqspkqqfmqknoqkjgtjksngiqnklkirqnqlgkmmnjqoivrmiloolnkogtkopdtroieirjqnmonjpfolsknaoqprikslrpouhxtklnfs~mmklnvqkoeXpvlnquevmonmofgqvqkchlmcoeoupbokntsnolrtolloponmknomsjqpskklnrmkmppjrpfkonojkhoknloYnpnppolmlsnneim\nsqmommlnmgkmomnpmotosltonloopjoopmlnopnqqqjtldhtip^kninnooouleqgimnoqymoolpmoejookrnlrlqsnqonmohrskltonja|pqmkmrrlppmorpvinmfnrkknmplmnmhqodkrtlsmxopmnqmphps`mlolvgmllrpolnsoojgqpfoqojnnnkmppmppoulonvpfpjdpmlpmqmmknmuuoommllndmsnmdhqmrwihorosdngqoknnmmmnnksoqklmsvqnlonkpjllvnlljpjmlogkoplkho`qnqoslluomjmlhlnqolpqtnkotymnntkillpnmnppknrhetmokmqtiomomlmmqvmsnnslpfnmkotsqejmrmwltpprqslolpmktnllpuqnomlli{llordjpmqmimjkkmphmsmypknmsjrmkllkvlpnqomjmksljmospkqkponknknoqhqtolnjmnkolnquqmlj_jkjkmnngspmipdqkmomjdolpquuprpfoionhmrpoqsknhgpkomplhs{pk|movapsnonolhptgsmmkknohkpnihmwkmrp]rrtl{kfiknmmkgpkiehlqrhnloopllhcqjmmllkqmmjltorjpfjamoluploklnoiqxpqmookrmnmgplmnnhirjirjnoqnhmkkon{kjherqkjijpZsrskmnlsomqfibomfhmqjlikonpkbllnniprrrnrvowskontscrwemmwpsttXjumrmwmronzsnilrtgdns^qZquptlwetmh~gmur{fooqlpursqlgmttrqnomrtlpiguovugptjlrjl^prnrirkqouon~rxqtl~qpomoosooryRrpvokttiphnrzqxokofpfnyjpujisqwfjkomrimpyqjhwqqqgojlnfssrjgPqkrmrm_rvlmrtintu|irotdrqnjrvpiqmewfdmuyqsggrufqlrqxepspmzp`sqol^ntjrqrlsqnhinipmeuflnlnpophqnekoonnnmhormnmrossxwppotrmkpqkknlflnlokglsmkronijglkkorholnfosooqorophlikrjnpnsronuqgmpqmnopopkrprsskjfmslkriprmmnlpqoqqmhqkpofookqisyjjgpppimrskikpjnkoszpohqurpgqnppqkrrekmnqjroplmngukkjxqntnpomrlpoqwuoyukppmquunmdmoojklqts}oqlnthmmnurlqvpnkroqknspppizlvmknmlmoomoj]qjpqelgqhr]lnotnnjrkn`memrjlloflr`kkosj`qzoumlpnmrpvnvmrmimmplqknnmjmmso~mqgno_jchmkjhoiqiipjq}aiimomqmzlmwnnoponktpiZjnrknpoct]oblnnozdglpjmmrweonnsnknggnlojoiqnsjrmjrprnopmpmoennoooqolnlojfnlo|olkmkupkjpnonkqjumtklmmickuplonovnpnlmmmk{fpm[kofpmqnoommopelpwolrmnlzlkqgnmnrjmhnuppplnomssowjonqsdgrwljmlpolplkxeqnmjnelmjndhmnppnppivuqilmlhmkplotikrmrovkrnnrljojlnkmnnpsoopolZqqirhmkbnplqcreqsxdjzqmosptit|lnpohmmoppkrmnrchkbqn`kpqppplnmpmnmnmilqoqnpnkgkxopchorkkqugsdm_mppfdjhkenorhojpjlhnrjskorhljqcutznptoigncommmrtpnnoimmiliqqoiqtmtjpjogxkpnfsjpqutmpnlmnulshkpxnfwunppjrpmvulqirnnsqoollhjrpnjmjnofkoolnlqjkplornqqkpupolmqqqmtrkogoolgmpolnohpdnkjqslnlnnmpmrpjhdm|mtoyoijemmmjptsojssltr^kttnlpqnmkonoirbmqnmiqoltnrqkmpnrilplnniidlomnmnm]kjpnnnmnllkonppeknnoqsipollknkrujhumitjxlnpkrmjh^roprmmpplqelfhfjljrgqmlqsrjmpkomalmionoptondmguvojmoooheqhpqlpqqpjikkufllmtokomjml`olmsdlimninplsloohuelirfjkmlenagoqhotsrmmmvjsnmrnjjrllmnrnjopjoirjtykgoqpjqllnhmponcsinnnpnqmmojlmimqjpsrgqso|qoomnknanpkmljnnsonljpnhppmoounmlkjppslllnymmjtnmoolhmbkoluorqnjosmloookoppnldlrtlsnggnlkojknrptkknoqolmjonnpqmlplnlikuplqylqhomraouoinnkl|nulokpolwolspknqmrninlljpnlompohnlqolnetmkwmopropkk}ppmoy`qq^jknnnnwrjyrlwqnqnqlqppmokjokolkngsslnfnomkpoepplmfglsmnhofenrmmnfnpkjhlklnqnjurunomilgjpjronsmnpofsmopstklrppoqmsmmpqmhpospqqozkolploonnrmsopqnnkqqjplnrtknovrmhknnskpqlnqsk\nghestkojliiqsnqnvlkknkemmronnqqnmnorpmrpkqnpjurkqrlqooqmkiopjkopompmmsgljmowkpplsltjwqrmrirqnmlpllqpmpikbnpqkkqrtmntpkgolnlllivljniqnknpsehutrjplnsnknmkplorqql[_mnnntmuhlnkikkjrojnnjoxfgqpookmpotvinilgmmel~lkosrrpok]pnnooppdkjpoppnmwgmhno`gjjl`djkkrmjqimhmkrrlkoliuwowksdlcdphkkslhmnpjldltqkpphimlqnumgnvhkqrmlulrmkmoqojnlqjnpoqkm_joqlolrkapi}rfjiqji`mrvqqncqintlllnrponononminmqghjhjhkxrsnnlurnbkhhosbplsnnnnoqklu^iqmlpooioltidkji`kgrnjnfYgenkpmqroofiksn~ilspknohdqiogpjkritnktpjkizjdnflavjpgffmkjgkmk^inppm}piqtnrlknnsmtkwVpiopjnnmkolnaneeiqnmmqqgjpopldinmnhljmjjsnfreutklipgosfulhh`Xkmkljoppfoprojmyqlqppwroolqlkkqemijlmngmqzphqmnnjqe\rrjjltqintnmncpfpgrqnqrsqhtnkiitnommlimmnkjoksljnnfkjoswoimlhultpqnmoooinmloksnhhlgkqpmsnlqnoomgnmopolhlmmhkkiqiuomkklukdnresikrvjgkskoioisupjjpnqntooiljkmdjknikmlqompkmjsjkmfrssnrmnkoocnikqslrqljlpgjpjjjllimomommhsilnjsfglmnqomllmnzmejmhqppnnnmjnnolppqovslkojiciomwmnynrskikkolfqqnomncpjdwmpl`gklohlljininftnimkmyimudmfymjoolcnkkrbnloiqqoklmkmnkqnowlilnkjjirrsoivlj^lxlkjolqpkvnmqojlmrklpmklgifprjYljoilmklqqokwpmpgoflkmqi^plplnulesjlkplih{jkjksdwlmponglqmlg[voppnitscnqtrqtpoxnnklnmvjpnwkmhlkkrmnmnogfmijkmlqofunsomsnjofshtoplepvorhjpjnrlkonnkrislteqynqkgjlsnnhrenelkdosfjpuio^mlkipmwohpimqikeqllkzov}j}mvjnmkniijpioloiylsmpflqmnlrlrfklxVmkvseqpommomjexlokn`onotntfrlktojpjmnqhomkimfrpipvrknlnlatWehlqnnkolemjjcmikwmmoSojfnujtsinojqmlosjphfolmjrmktkqp\mtjstm\qklk~lsoowxonmfgwlwsnlmogookzpkwkmjgrbimmlmgmhmoolnmminpgklphigqpphnslmrmkmphqrnnqnnlirqpvmriqmk{jnhplqjqqodnksjomlinpnprldsispnorlnrrfroqspnlirpmnodqkrflrnnonlmgthpmjrniqpnjhpmsmprtnmlmppkowwphqommtpfephkminokrijrlgliupleonlnphkommnkkmipmlmtl^rlqrdimjmltimlmtnxnoomjbqgptnkqqpglghhuglgkmsqwtmpplmsotkhhlwrpnnktpmnuqnopnqokimfommxmmqjonkbmnjkmmsnmmomopmcqkjtnkmxtosloqqprpzuojgnnwllprmqvlklqntnoqhlrionmelfpqmjhkdpipmtrnpjpjmgiqkxrmpqonmnnnnkppllrnm|lhoiqnoonppljlnklntmnqbmvmpngrpkr{omqljmmjnnvnkumikiomqlotimmvnknijpnilomnnll`pl{emqoldonw^jgfmoqqQhnkrodolnotrjcgknqiqlig^[aenlrplwriddgat`iliqlmdomuetderqkjmnlsgdomirldhmvineaptoj_`empgoqtmpfk_xzopfmq`keqroJsqwpreiitfgmvphbmjymlplolnmqucbktjjglkpqyhpl`mepnqkrtvqrbjfGkkmtgoprcmoxkojm}lirnnkphbsjlorm`perrknlqjtkiqjfkmdkcikopn[pudksmnqbpklionmljhqkknmjmronzjqioqpkjomomqRvjukomjnueh]rolxoqjurnuihloolmmnmhppn~jtitkjyknrjnqplomhmnnqjmjnmkroutpnotqquntqoumnlpzmsmnqqlnvhnnwmumiommoloqnmmlppkkkrlnlnppcmqqriorc_mwlnoodmnrprmeqimnmnnmnmhsgolhkrpinsqnskwomnpmrngklo`wmflkompmojlrljelmmlrqtkrkicmiopjtjkhqjmneos`goslllqspnlvjloqocrkmlgcskrogldqqafslpspkqlfjrkomroiloqoklomsopqrjsgvgxihkoklddwirsrlhmssqgjl{mhmipqkpijnsjnpiqmdlnymtoljpspxmlnjknllkindsnhtqttsstmquqolhqlnmlonlcoqwqnsgk{isonrfqlitrjooknoliipskrlrmkkmnngmpinkkmknnvtronimoimlifqnemkmewlmqoooltknjjrmqniqrpkompkqhnoonjljqmkmmiplpotmqpopjkkrmnpootppijolnkqkohlnpslnpoolrmipnovqulqstnqmmqpojnqnqpnplntmnsnomqnqmmnkhqqsnsqqqootlqoiorshilkpvmlpmqinijpqlslomsqnpvnjmlqrioktkpnmsestmqknmomiqktqqonqrmokximipmormnqpmlnqiinntnospsoppmqnoomqnmonqkrpriilhnu_spjlmrnfnokoqloqjnmqolmbqmiqghmsqpooegkionqsrplqoomnmgnpnprqmnnppnljmnsoopmpoplmmkmntllnlloomlsmignnkmtlqfl[qijtmjrknluknghlnknhurspngongrokqoknkoqlskklqksmrkurpqmrsprmnmmlnrlllklilvlnjkikokhjoomkpojnoqjhnlmoqmqomgoilmlokllllnmqlrkmlpmmspqooreologltplmpvoqmdonokkpqompmnmhlmnkomqmklgimmlislnplqienjogmblmmqjpknsljlmkrpniomWpftogirlkgoppnprdzmxhqojkpqioknnjr|ppndrpcrmfokqlkpqrsnjqmmmY_olnnmnlwnnrknmsqkponkt~oljroodqnekmoki\kojnqlntnlvmmnmgfopnopgnlvidplsmkmoimkjqmmxmninlhompcxwummowknlfsrlnpexmnkhrmjmrnjlonppkkmgnjmsvoknkqnnglsgnoolllpmnnntjwmijnklgnjnsmjmhnvqmspnojqkpnknhgpuwpkpavnknnmlopptpkpnprlsmjplppjlpnmqork|jmooupnkllsroknopnojidnmqiqnpmrpnomhgoonqvbnkokqlelfovqpzposjlcpoofkosk_elqnprommomommxyesklsoqsoqqjqlokmnlpgemnpj|qjojqxlmndonlkiedoulxqjtsgrjpsklUzhnupiljmcqmqqlilxnn\ktqnnki`sood|us~oeopdpihssqqphlenntunjnmlokOjrguniubrtqkiyowonjqli[ktfigrhphjnn~sklpjm_plenhfirmokm]hsljm{miksk~gnsphutknkgrkfopuofkokpmrtlpnjpmqukrjoqjqolsoW~nlpkfjmphquhnmtqnqriaolrkonfjn[ldqdnjkngvjmmllxftmyhrpmtfqhpkrpnqksmnmepmkkrnqnmkjhl^qonotlrnskllmorortqlfhmjlwmmcsnooskirovleumomprlprshhhlms`soooooplmlqhnjjqlkskrljkntoprdpopjlevoktnnqjoskronielllipmiojmrhunnnnrmrohmrmiumnlrjkqmchjbslimwurskpomkqlylqekmliukmljntoiknnp`onqnnnqrpjepnhkupmoqroqlrsqlmrnmormtlpoiuqopjnurlpn\jnspxnqqvqrmtmoqmahqnX]qzlmmnmpqqmonzopmnokhxntiluoYolj^mntoumjnkqk|lfrnhqfpouxpmonrnihmtmbnmkqlPommkpnobiqqqiinfllmmwvommkntsrgqnoddmjnmnunslmsollmlnpnrkqZmlpolnsrinoionnm|alaomkkxinjafommskmnpmmmolrbiqmqokpmqmlskjmmnmrpkiqknqd~lsmpilpsignqprpkinoljuskkmjupntgmgojhpjlivmolkoneqomlnlnlknlnjkqlkrmcsh_sksqgpnilojinjjrmjqnemjqkgnjqpkkhilnrlooofejmeopkwggongnnlkhvomqzotvmmrpkekjmmqnpjninnrgqdmmqmokjminpn{mkllssmknkmpjqslhnloooowmoophpjhpxqlelhjhkqmnpgqljnmyqvlplrnm|nljqtnpnpjpsinnpitohnplmkldrmjnqlrsmkfnjqllrnisolidmkmomplsmomqlimnepngolnimutpnoekjlnmnngislulymelqnznmzshrmonnmulr`pwjnozeklrkpopipkrlepnooknmmnjojoliimomntzopqq{knmkrkkpmmolnghoonqlooXpqtlnnllpoolqplppprmpgrgodijkoupkmponmpwpmieuosqqeormnkgpmootnxskulmnlminpngpmuoinmlmxehjlomfjmvfklmmix^osmolkvphoteqoopnplmnpkkmmgmrtlnlokipkkmrlmnmnronnnnnhtmoflilnookiuknqlaoilolmtonsqjtnriamtqokpounmpjvnoksmpmrlorklprnonipseskopeollulpmljplpndwnhmpkrkynilmnlumhjrnoojlkplnoejgmzlm\pqclgqnmkojimpshlojopllcimtmnmslepjmjjmnpmnphlrloppopopmlikykkjilkplwploohpornvnsojin_cloqkmknpkmnmnoqosynnctkoqnojonlonmytlnlmklrYknhkmovlkonjouifoolqllomunnsgfgbokkrnmpnssnmkljlqpjtpkmoppkksopnfpiwokokbtnnmtollqjkmocrnknjkaosonjmnloklmppnelpmmpnkwgiopnlwncotrennkmovnkosklktvoltppkqboqrptrloplpqlpmrpknqlmlfmonptnrkroujmdidoqsojjkpmqmtnjppwpmsolmpmmkoqplmondhlnhcnboqpmlpsronjgmskmlindlnfokmomqpmdojlsnmllmlmodhn_mmrrsjslltpnwjppkoopkrsnjmlvlmkrpsm}mlnmlrnnsmkllroqhmokmijVimtmmptsnnmkoshpqjkkdionrloposmjuikomt{ptmnmoqmnmmpnopq|nmzrnooorWmvzkoylpnmqjlloqkpkommjmoexphnqonjmpebomlkhckfkmqsooloqmqnpdmrqgolnimoroupnn_sppklollmmrlmibnunlplmcielllvmsnmonujrqnjsmoinkhksomckuvmilqqnn[kpfiknpumxpnomjonuhoknookntnpmtrnlpsojsirklodxjlmlmvntooopomvoinlqm{kmnnrjplhqoajnqpiokpdolmlhjrjlhlljchnmlpnominfmibtrbonkqntltnjopmqkoolo`icnopotlk`bplooqmqknoumotfoolmokooitnlqsskplqnnjlnjkrmmovpkkmuoitnqvtljuljoodkkmvqppldociskiunjmsqnglhphvsfknokztmlpniqkniwrnolruimoontqpnmeppirtmohokpkrqhiumpeqkplokjpezqolmwoglmrjokuyonlkspgqjplqthoppgsoplvsljkouqopkqlmplmglnodgqroogjtmplnlhrlsogqninosnkrhxjmllhminx}opoihlguoogmnknypkqontrippnorhqhkltqoioljpqnkljnnnhv`nekmkmmurqfqho^ljjzqnormoklpklootMmktsrengvwkkloiojjs|lnkiqqpqmlvkononoiimqhnikocrppl`mjodjnonknnqnoosnqlninlnvmnnlomsynlomrn`vvmwnumpfrolmnmmsqpjkkfnvqnkoroknuiiozljlqommlongmnnnkonnjojobqnnspkgonsuxknpr\mtmijlrdumrunkjnroskiiuqkgslirlnoeolqijnghnrsmmnhfljdpihpqpjpoknnmolpkwiionmjcoimplqnuhnphkjghouklpmrliqmisdrjrimolrsgpkworqniusomoompljpphoqnjjfimpjmlrtpnrpnleqtoomolnlslunlfnonqkojjiijilpnvkojomslkinpnmqgnmjrsnoqpkpknhngomjmkolomkmgneqnlvlhkppskksrflpitqornirjtwcuqjpfbokpyqgpsuowkljrnjmrknsmsnlmmkpnqoonj_shmpnjjx\odqpkfkkkscnmlhjgvhlmmmtmqikpimqnlpjnqtogplnnoorntixnmownepkglgmqnrqmimhqnojmprmhtnspnglqaipmmmqlnvowu`poqtooryhjrlhy~omcqpeqnnjvkmwlnlionopjrjijmiqskqqlpzmot\tnkpfjbqmmnorjqlpsmsllnnkmtsqamlukjnkqltsnnompqonknrlsiopmnonnmtiomdnlkqnqpmmqpmqknkmhmglw]f[jrykdoplctmwospmpqikkmqynfrxxhnr{oljqohlrjrlojqnznmpmtjnphoqnnlocomtpellhpoqjubqoonhwvnnontmlnmqoinnqmllpkhynnsomlnvnlqup]ps`}mfmokjctnnTqnnoj^lkmmojntlgu^Lor{kppmpkmqplnilojlnmmj]dkqkoyomzlsppqntmnxnrkn\_frpprejkqpimnipsmmkqlljnlminqiousunjjpslnokfrlslrmolnnsomooiqnstlpqhbvgklunuphlojingqnknwmxsgponscnostzqnrqlrplqoismfnrqooqoeokjhtpyqprptnpkkkohnplnkompnulkqpqqmpmshmnpmq]ornkrmgsmsqqnqmrlnoxopkrksnxjrnntjopmnkndmesiyncqlrmmpmmhomlnmjnnnnipollokqonnossxqnomsrmoltmqjbiqlkqlpprhmn}nhkmnmmlnsnoqvklevkjnovonclkoinjqmolignjnpmpip}ektemtmijlronooljkkrponnircqqnqmnmllrsoomoynmmlbjnsojnsolnpmme{ronqnjmvlnnnpnmmpmpqrvcmnkonmuqypbqmnrwhiosnnmkiwpqmlnlmmnnm|jpmmjitpuemmljolnllqkowmmppnxlpneritnmnnolphprlpohiorjljkpokovdmhoupqjtjknpjkojsqqnmnjmmnjnmkknn~imlinrqortqgolknntffjmplsknimkljlkppnxnjmrfllnjnmoomnljmlkfkinhokilkqfqmp\knfnjkmqknindomjioppqr[nnomlonbmkjmkmoolovmmxqrmiqnmkocmmooepnkshmloonndmncnmklsnomyrqpkrrislukomonqqnqnslnmmlnnlool~iumnnknmoooilnpo{jplmjoumqfmvfkropzprunhnilpjmjnpnkkqiojnopnmpnnkonkpfrndlpsfrkmmnkgjuopqxlqmjmork|om]pqpjphpXlhlopskbvxfqmfmqkormool`mtpullpnjptlpotjrpnmiakskqklqnnhnxrxmopmknklpcuotksoplmqjqsqnhfnsmo_gpoiolmiuoluxkoqjtqqwiiqlli{ijkpjthoqposmoolqmvollsnortptlhkolqzpnkqppuvnmfelpmhwliolqnjrllppsrtjrmunookrotnpkoxnzrlrooqhn{pkospisqmncqprlhirporfvlpmorsgiokpnojupqpnqjsohitplmnmnfdhrpnqtloonkimglsoqpoootpoopinlmorpqjmmqqlinqrnnokonvlnnplvsmnxrlooonmgnnnloptkpqopdsrjnusjlkpjlpyoo]kpjjoxmntgqormgnqohooopnsonnpsnqnmsruuwkjopmjqmrixkqupjeoompirmoromojprsnpromdlmooynnqqiomnlnjulngrmmlhappntnooytmkojmiomokumjloVofkqiolnomppt}oxkdhnpugjnvqqoonroojkpspimrfnsejkqhngqnonqruyhknhnltfklinsoosioominhmlpmpn||pmksnbmmqkmjoohjjjni}mqojhhoohmpqnqucqifomtpnqqnjoonmmrsmonpnlrsrpthononqthnklsltmhnmpirjhntnrirqdjlmppxrhrknjioljlrreollompmltqqjo}uojmmnlpjwrpomklnnioolphfoqlmpuonlpmjjnlnqmmgqrreolnplnopormwkmqmnhpmoqknoprjonrnmosmnmjmnfjlimormjnlrlnlmpqljkofnl{jltroskpomjljmnnmotooqqknmpxlnmnokjnijonoslppomkxnxqbrnoptmjmjjnnrhqnmtmqpnnmqnikpmknnkljqjpsilxikkkszks]qfp|mnpfpffhqpnlntqmlmllnomidpopvwvjrochhnppkhmpqpkofqopwwVnpifyrkoqspshsnhdoosqqqnpklh}rnoleleojklmrjokqoouupllokovisjXtqlfunmdlnmnfnulrkawgpmqwqdpmqu}pjgiotkqr{otgnsfjlnojgioklolfksjonnemwmonwkmtlphqdi}hjknutodmZimdppnj[tqqlmpsvprmqnuodkpskntsoonphrfrulmnnnwprumiloojolcjkvmwrnvoorlch{imlppcntolopoppt{kipomlmmsqsoktqlnqlnqlooiorpgmrjbqjnpkiflopjvipwnpkym}mtl|numnnnnposqgmlqqjnkgnploqorkrnwm`pqnulnupkquoqslokoqixiovvoilmoxlmwunmpmqunnmqoirfolnsrhmmllfqznmolum{iluljjrqpnpllptvodooppuplhkoqoYlwholpoiommntjpnamqmrsormqnpnoyjvnnoompqoonnkkomrdomcijcpqjlnnqohnttkmmmipnulqgqxktopqrk{rpnmmlnhkpnoohodmnprnlnslnup]kminnslqkmmsqpooksmmm_mimnoppnnmqpoomnrrnnno~cpkmlnqlnpoqprxrdaukrnlrrihllbrolnhuolnjlonpjejj]sk]tqlnomoroqnmmmhmoqnsrpjppnxmnkzonmqmlmqpopkbsnkprdnqpnonjfmnlllrkjfqmnbnmnlrlkmkloomdnimejqijiZrllpmonrmnfptjmqqgnjojeqbjpnfugnlnmokpsikhlpmmkjmpmlhimnwqnqmXmponpmodkkinforqgznqpn{ninspmnkqjmnnnmsnlmqldpmnommqhvncqnwqfrnlxomnjmns|imjrmrloummoklrnprujjanmvoqrknm{mqoonlnknu_emnfmlloerjimniWtpvh{jmlpomqhipjrrnqvmknupoflzjonljocomlnrksqpnmnmhplsvu|niocnomkkrkniisnomulojouorkhtssuklsnlooruo`lxsnpjjdmjomopmoompntrrapsnkfcrkinmkneuolncdpgnnmuttoqmnoojmrn{nqslmljonjkhrpbmnfnvhjk_mnmjuwoqvonjrrtoqplmjooptonnnkjkppmonkjnnnollpoonnmoiwjjnrnomt{lolnqfoonoqisnnovtnlnikjpkklmmmoqopommfkooonnqoolpnmthocqoopulngoimxnplooorqjoqlsonpmmeotgokpdjkrpmhopepokpgkobgiimsoonpiromp^knojnmmskopmnnppnpopngsypoonmninkpnmlpkorlpkxnmnnoqntqenmjqZnsnnlypmnoqfnpwnlongsol]npnlgphqslnnqopinmrpomqntjmmwqopx^qkmmnjmlollnlnmmlolkjohonpopjmpotnmkwnhmhsthljmomppunnnnlnpqnluqnwqirrptnfiptjglnqzomknxlopmkmtko~onxhmp^iuiqlhkosugi_oklhfgowmoylo`ankvzb{pqknrlmnhjoksflopqqrulmillpvoopnpphkgopordqlknkklpgpnQtlnnnx}msmmmgotpnwfmknospppmkinrqhlroknmpnronoogoonntomakkosnsnkdplloyc^kooluprsljlinknpwlqolqjnkopmmhkomjmqnmmulypqnqponjmkx^lpsmeoqiwpkk}ngksumgjiqmlmopgja{mkdrghhkogknkmjpmnlokopilvslqgproogmlmrmqymonmsrmlkvmdmdppopzuoolpekunpsqknfpomsnmmamqqnmjiomgmorof{vkepnqqgqmpepjostkpqrlkmprket^wmpfkmoqomlloollqkirqlnpminlulkolrr`nnonwnnhnplqpoqojdmrpkokqrooloqloowqnonupgoqqkjonpnoqhmkklskfokqhoplqntpyjmolmkjmpnopopzo`pplgkoflrmoohxnrrqimmmntpjkonnqjfogmvjm\mnipkilnplqhqncjnk{ucjnonqphlhqnknjqnpprp}tpmjplrcnsolkkipsjhmkpmlpxhlmutkomfdlrtimqotmsiqzhshmmjojklhnnoqnnnmmmmhr_qjhlkmmhkqloimeoqompnpxklonna{jkzspkvmsmu}^uolqmprkgmdvhl`jnqajikkmuhnoieqfzdndpiwnmompisihupmpqmolrwulqjlsilmqnosjmlnjWhleckjknginnrdommnnhlqkimimosja^pgkgghkqlrisnmnhjmlm{sgjhxmpmtmdhoilkjmojtkhflnpksoqsmquliqqSokillglvvko~kjmmpooqoioqmjmqeardkmopchoqepkhlrfjirinkspmokqkkmujnntlqpuqqiamnomexaedokounrqpqnmmilpmnnojlqaykrjqaprnmnlliknk_fmmokmkoklsnotqkiszwpsmlgojnmumosmm_g{llhpimmwcjnmhjg^oxlhkwqlpnmur_sqpoprpvnqnhstmlonllkmhssmljhonosihibnnnnjvknemklmmrnplrqVjk[rqerngpkgpmoneilldskhhlnrnnonmnnngrmhphmhorvopnndxtnqqipunpexogk{lnftosnimpqlrfjrmppptnsl`konnnurqiprmkorrqnuncsfbuiymksmlqqdljbjnsoppgnqlorllvrrvxjmksxmxulyohffmkcnfnnhjqhiolhjjon{p`jjlminootphqihtwfpmfnkroykjmhprlnvl^mvpewpikqeolkntiktk}outgnpijjwplfllqjtpsnyrmdmtstosrokivnqpu{gknohboninootophgipqnnsqbugokrsqirisnljqo|wojqnnoploklinlrlvvplubozormphpionolyknmokjxrlt|kwnimlksnnhmmlnmkmphohxnhiswjaynpmqhlpdrmmwkmokmpogonuoovnommkllgnvmmksjuntmpnl`knlhbeinfopmnookmsoomponmjmlopmpmsbnkouqqlnomgr^snnlihmmysmlomqnoaqnikor_qvios~noqnnkprnspllllnpooxlkliqnenkopsnpjlcdllngpimkmqnqqonjooickpmtonkqwokofmjznqpjkmmsokoslpnnbo|~opnrjvnqpkpmlldmkkspprnnmojwla`wdghlntorpnbpkgokpp{nqiljkmtnnnrZpoionknionnrhnlonknrleojjmtmonhkkkommqpmmppockolpopomfonvnrrotolmtknpldhrottmpmknmlrkmnlqogqhkmnnnnlmkkrtopmpmminnonpqnhplomnrrmnmqrmvhnqmomlpgljwlxjnkr|ksrkqmvparppjmqjlnhmjmwqoakgjpqrwrpioklsnjn{wcomjsnpjlsnxnetpjmslqmwmlojrrgmtq_ndohqlnpnplnipestgipkkwjnpyrslkopnsmulknjpkklolmalpqoonuevrgmnoxnozpjqpffnkntqqnnnlhjqfojprmlolmulyqngepsqtjhuiihmqlnqwnbtkqmsplnormmmrklnlpnookoqwpoilpaoknrmnptowdxrlnkjvgslwjpbgpqklrnfqnmlpqeogfljkjicnfcipfmilklkopq{mgrenongkjghiomijrluplorkymqbuhkjhmpmh]otv_rfrjnlgfghmglnnmqffpntmjjfomiomumnUnkkmsgfeljonpthllolmlojlurtsrkluisknpjvjwericugqksqkckplexhSdmgpmrlskipsmcaem~sjpurruninvlfimjtjqqhljoijniljen^rhlnatfogr^nvfhjqgepjdojlfefqshtkultkjovin}jxx|xlnpommlqcpkjlnnhcndqeniobompstpmtsoslqpfnpkkqpvgpyifkYr_uppfomtssqsxpeudqrrsrngmrkgospllxlpnnmdolhuhwqmokyqcsqlhknZklmzhflombojdgnrnkipbpqrlrbjrq_ummilkkivhklpsglgckjwskqppcoths|yjdioLptynokrjiqlpknmdolkrnm^jtpmqklwpyonomtmnnwrffYlgtkngksroqhnmkgmnjtdaildsmpkkthmkpptkqbfrjfjmirhmoZopSdjmmtvjqohlmcmpqrknooj_pfnnylqjrvloimemqnmotklvllmkjsonkkhlripimmnknkqFinnninmijqvjfkiklkxhlm\oliqooljktposvohpolpmqqmnpgpk_lqkfopjikkymisngpkvmmighpjpjjrymjrkmmrrrrrppsihbnnouilrghokjgsinonpjqksqjjjlolbosnnjnnmvijmpjoihjpjoltollnkgp]kpucpvlfmmmehokmnnnpkkmsmivnlmm|xukpgoojochj]lkionlkprrknsomwpqonkusoommtonto{mssffpmktuloloqhYprsliohjorqpr|qmnmopowsmndsrtojibmkjoqtolnnkonlnnqpokonimhuopzhmotrmblnjpmopjkmpjlklo{^vnqkojklgopmnmgngknfg^lommiympmrljnkmmnqrmfookpnmrhrlnmjkoommonjolnqmoqhqjsnnmqnuiormjpolmnopoumf^objmpwpentmqmlpikupioooepvpmmimjmiqpknwlnqqlmrnnknmpkrnalrnz|{no_leo]kmgknnqpompooldnmnlmjuhxmgmqnpy{xpwjononrqnqoolomVomtlmnjnkrfsrpo^oqmnpmkdpnknlomolopjloto`ninoxqYoporZonpmonoghmnvos}orgbqntkok{thnmnlsqnngmqhnmoporgutpdnnrrocjoqnqqqljkQopooldrrsgjpjlknkhtogmok]zkrtncdztpjrmwhjpm^trrhilpeotklvmqmmoknrgmlqzpirmiqltlrloymegqlzonn^pirzqjlloknknikqjrtvokklvphoqmpljqtopjdrimnknj_opnporhtcqpqaiiqppjiorqojkjqtlmjujtokqskiiskkgjomqmmYnz_qrohqpekr`fpmtlolkinnmommoqo|opbrnqluolnppnsgipgrscpkelocm]loruimojpmkotmjik}opltornxlkonfgnhnlqsvwnpovuioruiuurlbqrjwnpljglrklhnpssmotjqqmimjjgimqlvhgkuposlopqjsogfoklpdksenljlimoqoqumhjrmnpmsnmiulptqtkfqmqgwltmfl|ormwqklptlsnmglommnrlskkhkqrlstkjlzmpplospospptktmonlnjwnnvprnmsnjlrnlpnooliucjlqoommnexjqqnemhsyulrrgikphhoepvdkouq}cxrxmkgvqnreyrniolquyplonrsksqqnrbon`nlqqcsmhkcprn`rnsnjtnklnook|iqimkqllkkrortsmjugppitrkomrpocdmmkhohqntumujlgjotnmfjorfvnojr~ioidpllsjkiolniqlfolmplvtqoqkbklapiorqnxvjkmlppipmovpnmlklknmnl]omniutonhdkmnqnrnjqlmlpqnqljmioYveiqmnlnklclmwmnonppmorlkunsqmn{iwgsqnmlkVimmvhnmkjnplotqkmqpijsoosvophkooonlonpmiqomlt}qpnfjlmbnploknglisunoqflnkklm_tkn{moaqebkkhloponummknmjnoepmkmqlnfnolp]tomlmboonkhnsoqflhvmlmprtnmsmtmn[tjoopikoicialppnojpvpxhltlllzmoiortnpjmjmqokmipqyzqjkpmrjnvl{momlnwstpmmlpirmqrsouqqniiisorkoslpwrlopmkrqnupjjhjnmrqmqnmnppvqkfthiolnvotilllppsoqftlnkzwornnmnjrurqjiowolstklttmwvqjkihrnjloswfrrjolmjqmmnqhnsvmnp{slrzjsfqykosptkmfmqnnnmhrigmlqrnrqnpnoliclrvqlnanmsrsqpnljqphnnmluegwoiqmtop_teqeolnnposjkfkoqg\mjimnwmmhghqrpnvqerkkqmqlneriopbmskomuqkqppkkosnponiimgwhrhoinenipivjjoghivmtfjitsmsmopkilnnmaoprhmkofolllikdqonoorrqolnjminkiflwljmgiltnmfpriljpjemorkrniUomrmrpncfkkzimphlimrkqjkmmwquqkorsjmqpjskpnqqmjqeqhginlwpopjkqssopp~srupklopoptm_tksqnnkotkqeolnkmkkklliksnloomugiqjrqorokoglorijlmqkkpdsphn^qqiotnoopmrmhvk|rromnuufnvpkjonpnitfvqkUmjsqqflmpmrmlklino[mmhmfkkkkmoqmrmwpjnjpreqjlmmlrqemmdqmvoklopfqnghkmkqomplkrknvlnlmtnpoevqkkpnwqnnlmnlklommoopmyynlofpeqkfvsmnslvpokqigoqokkrqmjkqnoklojpkimqnctrnfmnjnuorknmjmohimjnkmoumjpwpimskrhmqlqnsnnoppkjlruponkqr{jmppinjptmmjunmmpitlqmnmtmiqoitrtk]rmqmsinrmvmkolpropnomlnhopqqolknmnqpqkqmsqfninopllujmbnlhoonjqfjolglhqojlkkmtiqmanpnnqmxqjqomonnjonqrqotopmqnromoqiqkkjornmmxjjsnluasqkkjnoigsoojqmillmolspiqxxnmfnmngippapgkjnurijmhoiqoknmrotknlljnkpvlkpogpotngrorptgmntlglhoopqiukimslinmrhkuubmfmqioidejnmlmhlulogpjsroieqnwcqlolojilowpoliolxmhrzjqsmonfowrommqponpmmqnomtnudqhmlsmnpjonpgprruiqhthlsrptknWjmjqslmnllqjpkolmknsiqogemqqnomqlafhpyqqrwpvprjrtlpiltmlljbxprhrnjlhnickfdfheoqqokj`hnqmopphqmpojommyqlirjjjkkkrjmmqmwtnlrmojmpplrilosnkpllrsigipgvyrnmmjlqopqmomnlilhqtuhufpomhqlkprjwtnpjlvnmufobqnpzdsppr}jmqopq|gknlkvrnnjghxlqctnhninqpiivkpuslqrmipkqhfghkrslvonhlvopkrnimtqnlllopikqflpmpvnkmppnphqntcwosdtighjomopomkrlmkmfnlgqickmgqjkimhukerpenrrtpfjnrowonofpgkomtssklgpppsolnqqsqsuqndnrmvpq}pjktnsjkntprwncnrfoshoonmlrghnrsm_inpom[mklmmpvrossqlnerlomlakhurlsfmvmtpkilnckfkpnowrslmtlqchmkmlmcispnonrntmocorlpklmmnikqlnhpiuolektotlkqmnoptrlmmlorkodwsuoqqposojglhjitmnkuhnjnlnlnivngohlgkomjkmljlliphrqslsxpfmrpnkmlijtgornpqqfzlhhkynjjmoolopomhho|pjopgrlscoqnqlqltooovnoonopkjolummpgjgrjohfjniimvrjhsmpmxnmllpkqikflkhqgqlnokllmfy`kdqnomklqhmmn^hqglk{omqmsvujkynprnmfkqiroornngpklhnpnbqxoupmkiqmkrrmmkopmiikofqymlogbekkeoskqlivngjqpvnymkmtwqocupqnjvkcllomdmpcrpqmgtpqfmrkksumudobrgopnkrmmjorootxdiqillolnmme\tqjbqsppfmolo|pamljsstgjtbkmpn\Njwmplsnwsgnohslqlmef`mvq|obpnxwkdojmvhkko`clqmndtlqktpilmuifhqlrqsljq}oijgmoosllnkwuocdn`pnxlVoapmqqslgjftlowqqfcmttwmmrmwpikvknpjSll~bpojgipzf`qlnojoeoquqmafgcoionmn[Ukdqqcgt{ohtkmblhknqrZjfnkrkoqkxnorsjqojsqmmonkmmqmfnlXertznl~nfoiknklnktymnmnphelnlvWsxtkkktojnommmqkjusrpprvwupknigelksmpmmqspnlithloqiimqprrnfZpkmowmeifhjuklqisjrmvoinflosrksn[lqjonskjnorgnmoqmkhjnmmimbhnpsovppnhhsiglpkklljnfynrqskmhotoflmsmripiplhjpgqllj]qo|nfkrooihmunnlnmtndqrmnoolhqokommopjopnslzjqejfmlwjyprgrmorjmrknfommsloommrqmylokpqmmplnqtnmlhqrpqndlkledqsjjtlYrniknmgptnqujkpmhoorntdl_kirtlqkojmbrjo\oqmrmqmmnwpkkqnisojxpgmuptqqnkerpjnmnlnsfjqmnunpkarjhyqsomaqlUjqruknpaopnnmslomljfaphpjlpfqkopihotlmlkksmriimkjlkmmiroifsnqjmiljrsmlqntoojgklocfwngpmpnmqf`kbsvrjnkaoamuwfrtmmnrcmqipjprrgksnvoojllpwpmlftckilyf[sprlmtbonpkqnqulsumppgsommoqnlnpnmjinmonlngnqjkknpjPonrWdrmdondomjm\qngoplshurkrqnnojqmnqroemsnmlxqunptryqo_qlrmsoohlymnlomqkkllkkgadn^nqsjrnvkmvsmrnhlmpnolkipnijngmkokonggoqjoguglpwojqiohkomiomoowermpprnvkknmytomigmilonovnlnqimejmsjqsnjmolthprtlkhltmmjkkqnlkji{mlionntnmnoknlmko~lphljkojnnppoohrpnovmrnjozpkmijjolqqllmqlmklijkpsnlnqlrlljpqgmpmopqgkunrhlnrbplqprjnumlmqnqnmpipneumllrlnhlqomk\uojkofne^qvhnfjkomootmnrpmknnlomjmpvdkikgtmmkpklljmTodlqllo|plnlrmk^mkiqshj~omionwmonnlmpioprnmilnhllntkofmlookmknmmymmjknoqbryl{ornntexmlpmokqlsgbononepmltmmllomkmoyoleiljplhlkntlpnoljlnohrtppmrmmmtkjnnrpblmhkmllkofpmouvlqrnmtoppkxowmnokmoqopoiiqtpqvjussvhponipsiqokontmrunwrpnmkmxcpjfnnerrrkpovqkooqhqjqgtrmpgliylpoodnlvprrsujnurkpnomsjkqnthrotpshppgmthtkq{ejommnqmhnjrnpqlqwfmpooikwpqvqlxopovikpijhnlgslmnnqqjxen`mskbniviofkgkhoiqqihlmnhqppotxeliqokqlommioipelhlhhlkonSklsopqmjpmonolojpoqpneqnwpooloilnnjQqksmloooikmkioksnnqnoocoxplnolorleaojgmwt^gmlmroplek`phponrloonknnnkgnsmqng{lpnomlonotmtrfupnmimdinlnmnkmolkolrljlqsonjmilnmnisnltkmknhgrlroolsoennxomllvjpnblnmnppxmumqllkpjmnolrnppnqnonkmmqzwnlooxopqnonnkp~wlymfnsrnnopkpifmkimkqjrc|rjl}ronmnjqllrnmjmsonkmr^fitorkounnntnptnsbksfilnpovipqomtonszkpjpnkpnoqjhglhnholnkpfmdysnusmkrmrppolkkqpkokounslrqskurmjkqlqnnjllosoxfjmlomllkmmkohiomthiijghhuvmnphnasxlillgsqos|kklljtvlnrjeojsimqqbn}npqqlzqnpttspmkllqpnpgmqnnglnmepknlmqnplonnrkgmnninoeihlnnmtnzpvmnhjqmnslajfqknotglkrrpm_mmnvnmxrpnnpkpm]nemowvqnjvXoupplokjlumkvnhwfammnkkoqoqjlvtnp^pomnnsolqgnmtagsnqizbioso]rpkljlpmpmoqmqovvokroopvmtnpprhpnfunyioorqjplopmilpvnl~jliomtsgodjrsqjinoqnkoommrrjvmllccpkk}pslnjlwopnkalkqnnnwjpqnVjmhnmmpppfqmlhqrleulnqmodoopnjrlqopklojjrknmyksrjoplqolfnnljmloppnvpnpowhosgl`mfmpvmntllunjmpsllkpkpnlqlqnooimkilllltsnokmnljoronjzmvimijsmglqjjpntnkokpotqohlurokqnmlpqqm~ilqvsnkpwrrn~oqoihuokqpmioqnkqiblmeqpqlpmlsoonnqnoslqlqftmrdojomou{mklmnhmrmdkpurnomiloskopiivkmjqltsrmnlllqonjppoqlmosontqmqrhifmsrtlpqqmukwnlnsjmpqjisnqrsmiqlnoprlftrqnqsopnlkorrjmmnkqmkumorbptonrlonrmllqqolprmmnmnrkemopokqmkonnoophnkfpjnlqtpqorkrpkljsoqvglgkkoelphmlmr{pkirrnnfqnklvhlnqkojocmkroolqmlqojnrjnrlmnlrolkqlirtompqliqwmmojvdqnkiqlurevohrmjfhZnjlinqnpuorpkgjp}mommmjqqhkpmtpjhqkqjmjjlnpaclnloijskjlgprgorpolkmmqloqvlimplu|fklmnuvkopjpiwoqoinlnlolpjjlbpdrknpimjoqnrjrpprknolk[irnnonjjnnmnpmtqrpnmqleilqmmkolunqrmmloijqipiioh\lrvmqpshnpmmpljpnnmkmttnlojlrlnlqmlopjjrmopsolfrnmlnsozulqtklqpjjtnyomnjtrcndllkhminmimjdgiomthnoploitnb[qmokikimfquomvrpjmorilnmjilosjniqeloteosjdkmpmonelgolemlsrihjimmznerknqkklnxnquhpnhsskkiomokmppqnpowlgoelnjtokqfntzigqkoclozqooutjoorxnpvmmkwvjllrpnmnlgqppimgvirkqaheqlrnroqlocgomugglkkssfnqhlryomkcqhmjlmp_dtjioiepqnmohvrlkjzoilknuklmnprrttp|opimihismdmllprxnqirlfpnmmdpnolsijspnkonoerlknnqlnfprmcnliklqhohoshfqskmjjkhmmpglmspkrjjvlumtnjljsollmolpnoqgimqoslrkrcpojkssojoekomplllmrplulnlmnnogrmhtminmkjnmklspgoqqhmslvmtxtpsgjljtumpnnqomjqjpnqohqtlssvppnimoxqonossobmmsoigriuoqrjriioonpqfkyolgkvwjormpnhqlnqrjpruoliprtjoxmxohvqqqnkxpnjjrakllmnsosqoatnsi]iuvoigeuomnipjummfllhijooucsisoqulqumkojchkprnvonornggjmtdqnqmhlxoorobpqmcfkeprjvsoyrjnptnb|ngtm_xm^rkqljpommjxjggnpnmhrfqmtmnpbmpcrpjmmohkqftlgqrujqkjrrooomjjphcxocormrypowelmnuononykplpogohvosnjnuoyptrxptwxqmtusnqlnprnmfjmojnsnmitmjrsleytqelkskmojrsltrnjznrjqvmmkgggpjqjpozimflkojnokiogwlvqlwmlpoiookkkglzrilhfrlyiin\hqmpmomllinhloilsrmnupzlgqjmspihtnropptompspcqkiojmhsgjjlrdlksrktijypnolrpnplqurivirnkxmgklompmlnbtkeprfjmml^okjsksklnrojpsqox^nlonpjnhnnoqskqiorntn^orhmojnklldpmoflmpllrpmc{mpflolppwkllpmopitqijplrvpinnmkhmvilsrallWrphnpqnolhoonhpomnYpqlmtniozjkpplnlnkpooqrunjonllbkqnpmolojgdiufnlovonmhnmllo\jkmmlmoonl|\qommnmhqpnynumnupoqmkpicomnotlnhosjlrnvpjxkvipjkmphhmmnvnnmzpqmninonnmnn[ermmonnlqnnlioljkusqnnmnndkwmloonmykkpmpnokknlemrynp}hhngpmromlmunqtlosqnkopmnonzmplunponkdqwelqkinvqovoqlVomnlqpnplqnnnlsnjorlpeXrnsjmlsmqlfiinoxomrlppjinljk`jnqk{vmmunnnklmnroYlnsomqqnsmklpopmppjmpmtqarnmlxlm^xqnnlpMnonq~noqoglqmlhnoiwqqkhlnfbpisnflqq{povopqnohkjnknpjpmkqqwow^skqqmtqmkonpomo{duihnohrpksqmllnskkkoqxnoqrjizhtrsrscpkqwnrpltprkqpjjnmnoumpnnoomlnqqumkpulnsxprgnjovlltjrllmnowhqnsptpunjehfojmphmjnprnihsmopoohpngnenpqonepjjctpomnmdtotomppkkltrjqllqnolsn[srrllooxktoqwljtojpgrnonmuqlslyhppnnmlsxsotlnlrjlntojrsvhdnkqqkonmnmpmpnbmotqriqjsmkloonkliekqripnklmxozljlqnmjrjimyocroukphkqkoqcohwnlmunmsmoemqvphpkzmjrqmsbdimoifpsjlmgmoljhnxrmpilmikmltowofmxmnplglnnpqrigmopmkqnsopolfqqntrnamrmmsnurorojrsipnrvslmnrigm]nnlno{ohjvlrwkkolkifmpslqjsneffsntmiiopsjhxosnomqqneuojsorrmmpqmspoppnujwkohqo|kqpjnueotwphevjkqlkhxuznbnpqmjcitoluunnlkpnnqzpqo|mlvjmjooqqyclrfohrqtnkppnnsrqtmqvnpgpvjgfexolmmpqhnlmfnmroylkrkgnm}sdll`zpqnoofpjtsuqtlmvsnqlnnmqrrnvqpbqmkpiqqkkqqmgijxqrpjpkqrmorhpyflrsolynfkjofmukfmummlljgpljljnntolfpjlouxmigmhdnrfiiomhklplkqjwftlmolnpqokirzpmtrv_pjnkslolhlkphnkxjlnlrnssmlvkqnhlqnpsxnqkpmmqpzq`kqlolbqlppoqobmqtpqjkmpkjpnveolnmirghlkohrsmw{qlghpjhqnonpjgdnnhpkviokmnunpntinkxpnlnvomltsqjsponjnmlompgkmpiVhoriwqqjkovrglpnpqnkoinqroqplsvjkpjelmcmqpmupprpjimkpqpplsronfnhsnruonpjhosmsrrjsrmkorllkosipqlionquiuspgqjpnpljtmuyqqsllnmnlnskljwqqqtpsokkmqsnoqrmqprnmknopsqomvnZoqqnhmiumnlkiohtqlnshtkjkqvpjmoonneifmmypotopjtncnmdomntuhqsmmgkp{mjqoqnjmmpmkvfiuippolrrpsjnorrrmsvkmqxronhpxjpnhmipfplaujelqrpmmgwoqkrktlnprmgfkudmtnpfjxgnegooqneloiifokhummkmnnpluiopttkklslnqjkrvkrlrotiillpnsxlqtiomnmp{gmtqr]uupknlontmnpfqqrntlfhnntoloekgfjmcclkefwuplkoqznqjvrpfmqbbjrolqnk^vopqnldlltnpvmq}n_ktjsoonkismmk{ohnwpkokumkmolkloupmglmqjqkhiqjtuoumo]pqqlqimnlmkbjivjnioqonpnonnjosrqrrhkuusmprjsowjmgmmnloumjhlinbqoojqpomkgmqroklmqn|pgnqhynlkkymoiompfposlnpjhnnlkclpipopxrrqpqjrjtgisamnunkmfilqomhmtptplqjkjpplyinrooihrosqnoqqmoissmojeocdnnkllpnmnlugoosjsmnmmrwlmrlorlvopolojmopsoohmmmknjmoomhmqnnrrpvvftspoqkmookokqmpjqurnkqnqqrmprpqomiooqonlrnvnpmnslikqmpnklqqnmemkksrsosqojtpmllnlnjnnmokrlmvfqnpntomkknomkqspnlqipipnnpmikpmhoomosmhoplilklojnojtriltmmlpnjnmlnnqmqqolqlqjphplsqulinoqhnoomrnorooknpgpnqlpnmmirkiskmhgijnnmomnnopoinlmmoorlrrpovqqmrsomoqoniqqmkkleojmsqhl]jnlrspojnrnmmjlmpkjnoniomkmluvpoqqllgrnjworofpmekvlnllnonkgiow^mwrvsnzpmppognhmdqonefbnkkommn_lkqrPlqtnqen|hmmosrtnmpgnogfllpioslhkpomkookmprmkzWplmokorypolhprg~sncplivj^omizmjlqcmmdgmqimm`gkqp`npjmnlnknommonnhnmnrokjldkgmnjmtlknnkummmtqijlmncqnirmnopgkpnonrimmnmothlulmmqopqmnldvmyjionqcmngqrluompmln}nknppmmq{lgrolfxlfpuljnnkmlpm|kthllmfgohmksjpiqnmp{ngrmrllqanmrlqlonhopoqbhsnrpiononlnnoholqmpi`fnppplntvrnpkhns{punnnomoorrpolojjporqkjhoqkqpurlgolqoqnlpnonkpmjkmlowlgknnrmmnmmmmlmojflmjmimrpmnnbpkninm[oso`iormismn{lhmqmmnojvpmim~plpmnqayl|hjbptono`pnimnonqonwm\um|Xqkmzzrllpqmjfrdm{gopmkgknqmorohousndnu_nnvklmkkopmjlngokpgthmnZnrolopipnilsmigkUololonkguofmk^nntsonlsruseq{jppmecnn_qjrpqniauhkgiosto{qfoslppomonsnLudmnfmhknrsoprqldvmlzpmpeimqmjmnfjgpjnor^vyiqmjlmmcnpyowvgq{nlnpmqgjhmhrrgnqirmlqkknynokqsrplnmmrspynmldtlqvntp`qusmqxgismqko{joomigifkmkqrbkopneqlsglmvrqopjjoipp~uknnlxmemsnqpwrgkiijgimllpeqhrlllmornouljlopkj]nnpotgpmjoqusuqkpuorklniphrsuhhnnmrmmghkqtiljmqnnspubnlphsmvkhrjqtqpzprownqrinrlsdnkps_nnmklvponnnowsmonjkspnrf}kveRnoo]nbmlnncpmomotmhamnjokapuruwporjmoomoant}lqpi}qolpkqnlloooalsmshdmvtlloYmqpionkseznwmfq_otoeljmrumktpj[doltppljlrovtiqnzocqnoim|yntvhppoujpmqsjnnrnyqzbojomspmhocopjoomkprmnlrtspnnloijpmovnacskrkmperylqnlfjkkfqrgnimzurnnlrkozgikmvxhvklyrp^oqfmhlogoafsndozp\mqplsqkknc{epqhqrvqmslVpdjflmqgklqrmj_egmma_tvpdzjsolx[fllitoxahYpfunmpcmppknqwo~nx{njbrnr\infteqn}fjogtpnnlknpQqnmkukrejos_sfdghconlxpwl]{nbfponkhpi^]jnxnpvtmupnut_imqrppnnpkbvmhhxmsfmjlkiqn[f|onlrcrmmuojaekpkrf_rqionndoidkpbrfljirpfjyieamlrogpqfkmsomtjn{mpqoeqclnnlmnimiqiqmlsrqkepnr{qckfnlm|g^oupojmplwoasphlmbqmst|lmfjupllklpnmkofpikuitmnnvhlrp_rokkeqyukononl`vlqnlpkrmn`pngnrlsrqolhnnoh`in\keghpbiilytppkmvplemmortofnpmlnjrkuhlnsukfnoi_rfpnrqtoiokWmjkhiprvkhiihvjmoqpm}nulhxzhzol^lsgntfrlhqmolimhmrkypdop~qgk[lsgijppgoljoprttngfzphs{lmspnd|nn_ugfvhnmkdxgqmlqgbklilktjleoYqkshpimt^onlrlmqqrfnpkpihbmpnii{llvqpmlnknvnjekjkmqkidjqfoelpwmknnwnvl[kjpnjvdoqwzk~gnknglquslmoohf`lphryktlmpyjpmopwwotkemfkjnlmyznqrxnon`lmllsqpnk`pnqotmnqolspjnrscounmtpfqnqfmko|mtmdrnbnnlokomnjomkqvino~sps\lmpnnZnrncxmpnpsmmnlolpvisqnupmfoo~p\eopt~qthnzplmbcpmcmfmrkv{mmmumplrnqxopkrop^iro|nqqlWu{kxnmnm`gnlKdponjmlgkkrkeohmwtgmmoiilalgorkpmqlqnmp}e`jpnkdppuhumojthhojmyllpmnsekli|m~r}ipkss}tpuolvpahqvmpryqyfnqnnrqlcilgpqlkjgnznmlptqrlroolijokaqfyoorndqqfpmtm`sgvglvqhjsyidpyykrqxohxtmsptokwrmuzltlqgnnkpfgon}mmljrmrolsjjmzl_wukkqmlmartpxkmkgnlyrymqkjjrl}ncitntjwomknugsasrgynjqwrzfjnkvmloreqofkpimmwynkovqjjgprnpmmljmlk_klmmpondm}mjjFlkmrjnjlsninn_thnmopnppfoklmltplxp`Zqytkcnukmn]nniuhnnoionlnmqpowokj}cqhjrspm]lZqermmmqigjsknqnunkoilnpkovlkinnqtnfmnsojmvizrnuovn^qpnlnntwqllkl{tloqsunwfmjo]mnx|jwlnkpv^muavoolzoqylnqomlmsi\pllnimeofnlmmohhfoimblV{rklollxrbklkcvjqk|pgqomme`qqpimnmbntm^kqspinmxtuPopljtlplnpcovslrpzhpu}o`lpkipvupVsjomnlnpwl~myfowpwis{lkopkhmNqilmnopaqsknuloomttqwkipmargvlrnpnjlpynmlqkonnznrkzmqdljontpmjnpXkponnlfjiommnmltlttcnmlipXl}eplpp}YnqyqhmpokfqT{pmxpmwmmtn`ojomslpknjopqykkyn^ioniXirsnizoumioqrfsmtjnwjkweqjfxghstfujjpqkq|rtuhqsygfoamjqkokjgohflnqmhqkottqnpekkmjlmigjoqomkhqnunejqlvv|lmhmpfnhsrkkmm{nlgkpmggofmftqjonmqmnlmpdflsr|nlijpixsznmxixppqkmjozplnhdlnvoghloirchkvnswinkdniksmikptsikjgjrqrqmlqlnskpmptwfmtoqynnkpejruopdjkhnphmnmmupjjnirwq|sijpqoqklrllgjhfnuiqltnnvjqiofpdunsmmhxulsfumjmmrkulfuotlslznnpjypossnknmnulupnujpqmiqpwotijxjyfpsenrnfqeknubnpkqqszknnjtpdhizmeipnummm~gpsjwojkolnfpqejfkjrpugohmjkZ_wtnjkioylrtjpumkmoljyoeqqqqipurqiioUmpugqplrxrqlimeootkytqnjpkgxnlilsdheotrolkohqpqklnpTkppjljqmzm`ommjntkpoouo\kroejuqqonrknynojyslgqprkmwt^pmwn}odnmrogilljljnkoqoin}q^~lkkinnqjqhpdqqnhkjkejhoonmolfkkhcojijnriwdmoipotrranlkjlbtooopmnhqzkjngjlfhhr}kmspnhkrhekuinpl{puinlnlmfdckqlmpnsiplpo^i~trtnpklilkqmnusknqvovlj}noklyignpvjpqmmimwvpsjngofmogml`qpvpmpnsptrmimjwumhukolupofiptoutlrjnlxlksncvtmv~lnlfrl_tysmmomjvlolhopolchxpysmmoounwop}mogszrtqpt^sbdeks[nl`xmknlhlpopnk}pljooddwtloquvtohuopqlemhhehpjpmqffmej`n~kkprqphlgnlqookisvsoorgtokartgmsncyoauhdonemifjiosinyjqkqmpuhuf{ikppqwxrlkml{slqtcnvmgigtpysmznlmeffluigsouqufmo`btlvmsmhsmrso_rgksq^lwbm}toomoghnbqunzwsnmlmtjlj_rqpnsmmenobrugusqcfwjnnl{mlilhqn_ltjpnrTlpomkzduemmpq`n]rpmsmvTnqkhing^vsejuotirrqt]wopqrmnq_uqqfkbiakjelnrur{nxnlemnmcqtqj{jksmuujd^Vrnqnginmdqisn\hqmjhoqsszfnsiljnoioloymmkvgodnkvsknqgpglShjpqrfqkipjtixsgjsoxsnpjvuqtxninr|jkvitolnsoshntumikpkgjtmtnlsjqloptqwp[qvptkxppqhesrxpoufffhmpnhijkoj{kcootpmnqmohmjksnrmkokmilr`rnhvlbobqfxxmqogiiensmkoemcilksonnmnjdqrmlhptuwntpgdup]_mbnqljmwknfi}lelinjplZnrinzelqqqmqnpwnkqsjjnmlqfoglhinooogrnsodoiqemsnuponpnjmocknmpsnnuknmoioxncqofmh^rvcmqntmpo}mn_p`oonplmslkuj_]onc]mnqkpnlqinnsmnognoqrnpqsl{qpqmpmtfoneognnmsqomkpslmyqnoko[o^joeppnhkotmllZonmonpmulpshn`k_telgompnbjnkcinmprpporpnoqppwrpgtkpnmmlhlxnonlnmqzqon|lqnuk`noomdllmojwoom_qcnpjlbusooeqskpqkmpmpjqonjm|qtkomomkmokmj~ohimfo~XpsmkcoSmkntvmymmkpplnm~ojsjjn`wCdnimprmm]ngqjhqpkqkloopkipntrspdmbppkhpconpqyndjm{snil]XpojmxqnrukklynkjimodboltplnlnrnwkqtlwW~orlmrhukjxfpjl_zprzmojosmf[^hxoopqtiqtqyolomoolzmmojydvn}rinoQhtnnvrtqkqqrtmgitoqpuwprougusitpwtwanpktmoyitlksoppomtonqqeorgiwnwogphoojpmqzpkleppifd^avjixunrwkdpmmgpk{|Znpvpnrojcl`paZXjmtph{kukolqkkqklmntr`lleognsqwksohreimlEfelqwsqpjkqf|zWet`srkfvgsnkompfsocenmngyilkknjnq{lahooulquakm]trmhlqh~mXgipsfkmmqqklMoZatSRmdu~ckovnjiqfmonkqlplnodjqmilmpkpmenboetlkffslnrojmrlrtmqmvmmnmutopngxgrwqciqpillbunkrlovnsknpitminmeuzhohtiom^yhjnqlxogbwptqqlhsjmpmujrnmlgpkohlrllkmhtjmnkqimkkrsstqmixppjdkgpnormluhp}jueqsmlfoqgqtylxhotniwrenblmnjkejhlfulmslgslhpjeqhemquqkomnrpepjusijklxs_ostntmolpgevjiooYqocmqjhqb[tmgohhusi]m\[vnhjqlvmmhaonnltoejnrslo^jknqgljpyrjmjhimktufookn_okdgsjkbpmoukqmi}co_khlkeoiqintnrwlldgoj`gisibknoikcivkmnbmspkhqlbqxfshRpompm`vnxhkpplgnxpnrlirshouxnlkqlpnmfmokjtmlqdqkmenjpjqivejgulcgotognmjqexptnkeosqqujopdcfkqq_mjmbkoplkhoumcproBrqlonprknlnnp`nXnjnommpjooWjnkoqpomopprnppnlkrunpijljomkpxoTpelnfoVijqomolmunhnVdmoklupppnioossnrorlhmn|nrhmolcm{qmtkqnMoslmvppnYlkoopllpmsvjq``lppolrqhroemmzmqlymxnmkknfnf\lomnmanmtnkpojlxvm^igikmtko~qjmknqpmlrklp}~qmntroomurmjhnnxklrphlnupmpomrqp{oolbhqjuotljljpelxxkqmjowyonqonlphgohpjtppqltomoppilnhqwvsmqnmveptsluooniRkumionjjmnnplqhqj`kqocpfmmmijp_pqnrqklrtesono]oqkuvqootqjmpokq`lnrqfjpnpyhqopvnln_hglljrxfkghmyorno~hqrnrrimahooksnwrtozojjusjqnfcuoliijknpjpmjsplqrndkqimyhoonomjnpmkopljhqstkoln{tozdroridjcVmcknmlcpmqrmnl~iuiotnogkzspkonrlsnbifozhonorwkrsnsgmqmcokmhpplqqq}e{tjjdtxrimavpopesYrlmqmyojoplsppojqipofqrirmhcqeuoknmqo^vmronnnmlsj`dslomgot^lfqklnpjpppfkwmlnlbqpemkqnmnkomqgvnofnqqnpkqkkeivsnddltpkmepvpsqpmrrtfmkkminlmmiolfkrnmliryznosmc|sv}fofaedisgvqrrpoupkqt}qvskunrkqlolxh}snnqlhrjjlkqnggplrcwnoomwmvqphnotnihqcowxmrrijlpsrfsuqpbe}lquopmmtjmkhpnvhqunusnropst_kqnr}mo{ojlmup{oornylat}qtislflqillmswmlflrmipihnrytncfghnommhmysnznknwhfqolfrjqnsnrntg~quibqnhqzmks|klh|wtklqllotwbhrhrusrirpXmkmlnhqorjmwkriej`}lihnxohqnehgttlhnkorcf[simknno`tfginnwklqljgilsjhmopcxgiwiko{vwjpdphsdhh~mnnsVoenoSsnplnpeuloewrmgtnmmpzhp}q`fewksol`ueqdmjlkriljbfsmnfsowrhopn`lrppdnvohqs{jennndicotWgkmonmksnpjsxs|sqp}gnokicrsrimenp|sqrrkifrstmpenqg|qqnnpiosnukroznkmtqkim{ukmr}lnonnroojnnnl`mhmohq_pr]knnsnppdnoOmmnoknppeqlMmfcqiXustnormr}ln`oppsrqlpqpjrmtjtrprsumoap^gmsppqbnnkqllxinvnummoymp~lqmhsojplpVymoipnndn_rWklymjbugmnspm]kfZtoqq[fknqrotoqrljklplyoqsjlgq\ononsmrjmomsdlshwmskljp{prmqgntlminoqmpnherlornqltmloriqtowgnnXemlnfnloliknq_rm|rlznfhrhvlhqpmtnchnsqvmjpfpofq~ogivjYbtyrnkosjjozs\qnnll\omnkvoo_jruogmxkoirp`nomwlgltnmnmwmztjzjlq`lkukqotpqrmnkWwknsonpioqp]ntmltfnwpljmn{jvugprijhmpdrpnncmfoobgm_oltln{rnnkmmqko`pnpyknlreossowlrmnktjn\oasrqdfmhlmnjqrvqtqmmioqfmpimopqnimskkhoyllkgoltogloojnnnrqpimpknwnrfokjqlkgqolokrnzrpnnYpimXjloukooqismtkuuujkgoplijppjpgmqerunnhjklnopjiwrknqmmtxrkmqrjmhriilpgonjjhntjmfqolllnqsrmchopimpjnkrorko~`mmnspjk_kmqnlqnklltpeq|seimlwonoopqkuirplsmnrvxjmowkqosliqlnanli]fir_|sodchpnestb{g|iiongklhismqcfdnubnorr}hqtnczlhsrpprjroirsxkmp`thro^kiZoqfoqmgimgvumm}psvzmhm^ng_nospmlbmokrg]ndoiijrnhsRkovFnhjn|qtxjormkijrcwXogem^nyh]elpo^iqjpmxkqdsznhYolnmmbeiookphYgrjqpxrxokngmkwr`lyrkooewm`kgormcsvqmukjvqjnq\ptjmooBm[fopnoVknokkpqnrpmpmpololqomvobqlnnlqmjpnkpcnmiojPloMlepntqbfmiqhmqkmopunognpukxe_]ojqomlmtplmzxmolpqmmrnon{nonooplxos|owdmkpVnplklkki_qmmlyljovmspkonnrnpmrlolosqjvn`omim`xfoojpqpspizqnmwYmm^fnmntjgbd]viujpphkjounmmpqlmpkmnfvqrpcormqsnVknplrmovsdmlnjvpjofmqhuelnckrstsoktopmnm{qnzjxtngklopoqokrfrnomlqwjsjkntlbiphqodoghohulonnptokophimisinlwifpjmmksmnzwkoyneokkdnxoqljkomnprmmnovsmnoyopjzlnqnqou\jhxm_gpok{pqqqxhl~llmnmpnjhklmpqojijooisqmqetmopjrwjuzupvmgmkomnijkrmpzjfxlu_p_nvrlkonmujhpplmoustpngmoqvkXllporsqlkkqgeon}vami~yykmklsplg\uhvyoXnonnhjjiqviogqoppl]knjykmkufhrokmmi_ulgolbjosmvpUrjpZf^tsowjq|qkvssY|kxmujxqmii_jsuopmermbmrvj`csookflqkljkcopaqkkz[pmwhqkrkekX{ooosqa|kbhmmmnollaorqgspqikjqmldvgt]oikupshsl|yRqekmerfqsr\upiattpnqo^pnoregtlokwlmprqbmkwklalngrtjolphzrmsklqnknuipnourxpntojnnj`o{bkkkbvvxqolyk|noosrlcolmhxhutfoqnjmgmrnkynnaylbuv\pqrcmtYgjedm_ckmghqxlfgltpaosnnhkrnrtqpwmksgwpiaje|i`o]rjl{rimlfaWrmkjhjofjknso_lwpt\losirnwnpsiunkUspjidipffmqenlxqimaqiqkl{m}lvkfilqpjpnwmiqsozlmpmhlssqlkoigltvonorjrxpnonrlxhllrnispqnsnj~[kejsimkpxujrpk}prjsjgrnvmnoumrmznnnjgsgnpphwovlikmcrslgnehnqnlqnljrvlmbynhnkff|olpgtfpprlhhlrlrjloyvqfljgsqokmogerxofhlrqvrml~hpsmelkmpmtlwjmjownoupmmph{qontthj}mh`kqjpklfqjpcfefllunourjjo`h{hmsojmhpjmkltokmmpoflodjskoildvcuikynseqhglltjknrgmenfioftkliijlslgyubsmficnrrfcglkqmmks`lmcxofpjih`ipjhnoibndrnojhlm]rwrjjlsfmkqkllizjuculhkropn_`mvmrngslnolommdrjqorlnkjmmya`ldpbqznoohlqlqtxnpfmiwiruekppqhhlqejrpqoupcrmnhfsjsgtvtwlgqcn^ppqjmemukrshmsnhkjmhntpaofrrgjimigkjqi_slXijtmrmmjlqotjhkgfqnwsnorqmkmkikwmfnpmdolmpjijjul|hnustm^rgmj{eom{xbupopqlYmeoiwspuirjjgljonnuhnmfklniqppmlmnjqlijlqcruKnmnitlpkkmuokskpqlappmznmt~popolpnvolkjme`lkrpfqsknslbo[nSb_gmqprokjjs^eljketmk]rpwvznxnhvinvgssqlii`nnglkimutlnZhqfskmbrj`kullcm|siqnxtlhldmmpbrosu~npronnrnyiqgdjmpjnqsic|Xn_jjrj]kpkomflovmaulk_mc}sbjblcrmsoqnkbplcnnskirqeoklpsolsxptWcqrjjpo[xsshefognqqdkimlkuctql~lo|jejmxpmrmoipvnombujmoovqzlsm}edynkoiolnehuqmmvilijjmmrsjhimbmifboovi[qjrulpounpfhPumupPgcmunkspZpmcll|srnpjurmilswim|mslxqpjoo{ibnmovvoltkqngtmrwnllnnkkkrn{pwkpqmjlsqqvoqmrsmptsonpnomnnnk`gnkskqnndrjqqq^lklwomyispgtpkprtuijdugzhowkrqnlgfnigowqkpmpr`jnsrmhjmlmmtrptmkoroqmqrlrritwyopmmvdfilluppoooemdrp{memtgrhxpkZvslinvpfnpsnmulppyov{urnmngpsnujpmrnlhqrcblqhonpnlrntjrdjhlwnkkilolnnnmememgtnijhiojhzkrtopekljgirqhnkpolrjuzssebnrtmlnnmtiswqhkkcqnuritrqlghlluitlgquonnmi|epptmpeyn~ilwsrwih`chwgfkhkfoip\nkkgl`nimbjjmlsvmlrnqmmvolmnmithmltoZ\ltlr`piopuqhotmdllinpkqrhvuplkqbrtpj_cvnlsfqgrcfhgst_n~knnhmtkdmtolgfolqnusqlpdlmjn]osX[rnmov\pep_upocskkhnonpdjnnwpnhnmnlkmopnpCjkllopmnolnkmqplxhsrntlbnqlmnpulpkkosmjsfqvmikqlmmhkdqhnjnjrqronpjsvqjsxpp^lrgpuprhqorksnjktokm|mnkqoommkmuskkqjpnrnqmqmmyplmvomxlxf^oojlniedqu`liqpgrmkunmnmjifonenq}kmrnpyovmjpmkmrikooPspurlnjjmw^lnthmomsiqkkhuysjnfcmnpdnnkrmmjqs}gmombmgosc`f_nvju|ilncti}nqiliiqoahf_jxttsjnlbihkkolqiflotorsllrxclseproilnfrlosnoyqhlykqcolqjd~{nfijoh`pqmunmulhgnmhekqoffbarq~gztgni_hrojihWXiojtnawhjeblrqordxkdmg_pqoiplkjgsaflvjpkjkekmyrlmhsjwnrmiiylqqnpvnpctppoqhztomhblkosnjpnlqon+nshmmsmmmpdg|eXkljal{tmknpllkhqslkrmpmqotskenrkptouryilooukmglirYsrmpnmppmopnnoon_qkrkjnjjjrobrqf@jrqlmihqntgkpmnmelwofq}snamndmpdop4lehf#lmko|mepvvmonscf]ntrppmghssknmrjmmgbohmyjuigk^mppm_nemnpsijmvhtlivgu~mZiktEnpjtl]qpmamlulepjmlsohmlnllboepforoenqqklpq~gnmfrjnzk|rpodnjsxpheswvsilljlw_rqin{nsimykpkoeommwqlrmomhqqmtomkmoqnspnnmqgjopskhi{vtdtasnpotmasrqkhspplmotenpnxnmoiptjowlrhonp|zonyilmlonurllnhiigmkunonobolillmneisglpsjxwmijsokqvVe}mprmqpwnhpkkgstlimmnpmqpnnnwnposqtrqmwihmmnnoplhdsilg^smnogxqtofmooiofo}lqmovhnm}ipxpmmlonmlpj_lo_jmprglmsejSmlmuntmofifnpnmmpaonRibxjdk{cphkorlotlorqols{sklnqqohtplVsesqkrpcnlroonhnnpqnkdlsnljjonopjjnnnkgksuhnrnijlpmjro\eqm{e[rlkpjqdro]pspljafnllmpnlgnmewUkjjqrslmprsoonjthoukoniyuqjslmy\ymowtpttam`oZpqpn}vmlqnjporrpm{mpmsqtombsnfllopmfoipl[shsrqupblkmSpolmnokuomninpnmlkhmnemu{gcd^elsonlnkkq~hnfmmwhqygmnmkqZ{hiorpjkqtxnsoptk|nsvmkmomchwngppkgsl}lpordjhjjpyampjmrnsfoktkjnomsv`ipmfmnmlk|rnmxhqkmplqmkg}{{djqdsqakomqonstlrqrdljmuermlnwgong}hssmk\qsxvqfjkvjcqjpji{lsnjovntjgtrprovhgfmkkqlsivnsesimhwejllsjosofnknjhmpnfnirlouqcnolfjj_okmnmpjjlcqjozqkklpgvnhtkdvsbotkmlfpykrjftmuojmmmkqomtgjnhjnmmoqnqpmugluorinsnfrjrfZbumhpmtoqnouljmqsm_fpwkmgyrmnmppjjqt_nrerqjduygsiviitlimonqkmyjrrpkwlkuomrwqoeqcqksssimxlgwjnjjkmmmggtokwgfmpjloeMploikmmoknvmffmlsnqlpfmlxjkekmyl~k[moinYmZromolkwqocirssWrdsogksnknxaurdhooeqnlzjomo|`rlokm\konoqwvmmukouhobvsmfrgulklkrlomjlkoagvfqdprjmftwukn[fmUuhtlxolqkknqy^y_oqnlukrUomvtslty{ovbrik}eoitvlklmnYvordllkxpqwpoqssrntjeoonqj|nllgoOclqomorxpoluumwn`hooYZqyoqnrosppmopkhiojsm|mx^lzoNoqm[qnoipnpoppmwopukkqkdjo|moomkkndppgkooolOukprksmNitimgpmjlqlno|lotlnqnklllpdavtlpynsorsmomninspollQoqkpnp|yimjhkoof|Tn]pnppzdpkjnnslvlmqqqnuogkWtpnjtlporqoppdmjpnmomroonve}xpnopnnSg^onsrujnhl_wyonjlivshneontlrnpjgmqhigqlftqhlsrpphtpmvrunqrdjkdheg|mkglnnmhrmwswprtvlphdeosckiokkirojgstjflhnq_mrnnZjijkjnlsqhjolujkhmxoeljsjmroohnnnsusknnmmrmnumnequkolhlhennrrpidqcjl[ojpmotkkqnlhpqns^spnje|okhlqolgmslrozl{mpfnssoylpskioiduiqlxrqpqqqkxyxljjqopnjutjlhkosnrzlxo_pnqoipqeqnliognobukapjmomqqpopf^kppmrkofrjqkqVnqmfmn`okjiomyn}Ziqipu{ZemnlrkplcnpqRlrpukhnqsrqkos]npopfynpramlnmmiokqkpolmlhrpmlmhoKmn}qroqmriomqsekkorpr^o]n`immn}uijxinor}qpoaqksltuootkikonokxssiomqslmmmcoqlpqnqtjnlzYZuqkqkpmdbglllmYl{o{nVtrlnlhqrrhnohwpjmjrwoxinngqXlgiopqagmnkzmwqm`npuoV[mgnnfp}lmiuqromgon^mmtpgse]khhqmlrolgxt}gQipofleirjlrloYvkwoRpirmtmqqionldncioqqqli{gpnijrnmmjjomthqfojohqmpinvoiy\ohnYnxoltmtmrolemclrqnkqhouOlnrohq{yndzjvtlspp|rsppllypolkooa`bpmhpelrz`|prtisin_k}pupkmmRfqpk_romnmmnkpmjp~}pngoonnpornmqpmp|omooozklWgqxmxmtn`nimmslbqroqol]nzikvglm\qrsupkmlqsinmfgmojpynkvqgqmrpshkknfqowlb~lqppnZqldpkog~knfmSrcnkpplknmrnkjoOrpllono{kfnslnwq\oqr[mmphkosemopn{znotpmvm[flwutplgnmoqlppnjmopqmbomo{rnuktn{kr[aUjmplb_mnpynznlop{hnkklpooalmngmommnkpni^nYlkprnpjqnp{lnhkm|uoVpshlfppnrnkmmdorplllmp\pskm[jmsvklpnjlt{ojmxtrlkj{rtoplmm{vskqwnhvoqlniqmlopoaqnsmpmb_Rrmzmtl~nqlornvonqnps[~nokpkpisnaql`nmrlpiokmrkoqYplpmspnonfqktM]nxqkpkmmkqsomqmqjqqmnkdppnvm`mppg\nrzmidphrlnwrpknholrq]mmqSmoohhlnmurmnVzlvnpnnrlolmkcOozqksoubofkoprnrkepmsojpmookmZom_kwfqgo|wrmolqmjVjprhpmpnghmloononctrk_plnlmpnq}pjr}pXlrvtkndxoqnkoylzlkrokmhjpnslo}{nfsljmas|ndlkdlijhv_nmooi\ppymoolg[nmprltsno^Zr`~o]poxlmzognsknqlmwqnpQr[srmkslmpertqnoluljlxmjlinqorycpmgjiutmn_sdXhnnllptpokisllzln~jtqlkWlbop^krtlmkjnWrmlqcuqmthkifkgtjipkplgkmscjcjulgmlmuuqofgh|hd{ikhklsxperdpgqsukoknir\yrloqmrpuinropktmijgohijolcmmdq}fnkqqloellfshejjqpfmlmtboouemmqrjlhktqjnlnflUheojiqhxktdppsl]mebomhulvksopoqoqilnpnommdfsknsrnqrlquqpijoqokqokofonm^tjloinmoqpomllbphrfspuwtiakbu\lmmsnblmtloklmkTiqolkfgmxkmrnjhllhnmnvmrpqjqlpzhisZugqqmrm\pmolfljnltllolsgrmwnqkqos]nmnsosglohuujmqqnrhy{r|wl}lxfolonokkzpirkklltvmpqnqq{t\cnxll_moonljprnjmloonhplnQ~qplplZkrWdgisk`Seoqqoujiirqmkjkoqwrssztlnwpwzdmr\llpoj~lwgqWcphnqvpkjtemsroovihiolqu{enil[iqrqqqdumhrkfmrropnevjphqqpwfxkszhmrk{XXqmtmpjjorktnorxltixhrpnZskcfqtpnqqnmliqgbpfsqkmhskolmmnpfe^{ssoqeqekqmsnkfjgspnsnnqtgmlnpeipsfZormsnslylpklbglp\ednmq`n]mpmiiljoskgmykrtonqeiyrqmpmfpfqphe`mkmwgodnWlkmqzknvaukqzmixokffommqeldnrXsiqidspmknjhltmonpgpknfekkpkjrqopmmsopvhqswlvomjypiudqjj|f]fppodcsmgs`jrkhnoq\oqnihnsklmmlvmpsmrqhkdergubrntqkkiqbhvknsingmWmktpp[ihoekmhrqfcofqnvherpRqn\lpqrqvltnjkhmy{_imoiojspk]nioonmrukfymlatpupk~lmo~prjkp[pmpokpplbjklckplot_nmenqxqlnposqnpjkgo`tientSw_gjrQlsp`rpxqdpmlnlnppqjd{s~{gjnolqlmkpovskplovrtntqmpxermmekn_noyr_fnqnqoampmqklizpmgptpfkmojlkqtknqmra}lrmsno^wgnbxnPq{fplsmqleymq\oonpiapnwiloqxi\reFrj|gptikcolnmolnloolnf]istkopnxvkkslafpyltunnsspligyjqqqlp`snvrpupkolnsqknuhx|jtorzfmjugvkopotozpnolmosprmngqopqmqnvkokrwkzgrrkljfrnswztvcholmntivhqdmwhorrvhnqlkpyqqmknkmesnunqqktppjqomztirzvnkst_rfgrzikqithim_mqojqnvllkjknknqjvlnniursulmoflg{toj|qoojjxmwlUv}qfslriNprsgipkdtelpkgvupnmvipspthmpqYoknkoqoqlintkgormhoprls`mm{ingmkklpqpkmpk|moopxqkov]mtoqnkqkmllenoorplknygosXmurfqmnkrimkdspjqkkmqg^ktnooqjdfqrpsmo~mqgr]oknikolpoernrbpaomzsmnsnoylqnqmgjunopbptnjqjpdokjnqmyp`rwomnpgrlgejplokor~niemfp^unvlioiuroyronorqrpnwlmnskzppoqmpw]hoqmsngszldncgntntjplk}pooonmtmmuoxvlnqlmoiplmnokmntsnemlWllqssVmrmhnnlpnntkplnokmmvluroc{kmwz\mklrnolklbnwmnmkpeplnlolmvbljoZonmopoqsgnrnZmbootpplfUhlmol|n\npimpppplhplnumlomllolhmlqipnt]wlwlllgnjke[hppqmtmotpolpmjsi\jjrsnprijtnfnrmsmootrll`tqnvmtmosnToqtm}]ohrmtklmppdnkneuqpwvllatqllinln^qkloqnsoljooromsoqm|nanjtsnpsimiojzo~qpiljnnpwr{lk_rkjpX_oTjpmmjrbnulmposjswpoonjogsmrsmr}qsqtumpspemspqhlmg_Rxrmojlunqslokpsigpnmd{lklompizpn~gjrolc^lynmngruhxxtqpnmonsxqmkpijhn`tmmmorjksvrpgompqugpmomm`tjoogpoheoktirrgropokmniqtmnononojivtpvurbpjqpmqpusmtluspbfpfkspquxthojrsinmioqmmmplnkrljhpntqjljplpssrptrgqtvjqkulotlqoqhpnkhpnhkjinumepiarzrfkpqmwoqmnglnvinjgoplhofronnmylbmpkpldqgrninYxjnpprmsrnmslhltnmrljmnlkttlrtsnbmj_kkvkrmynststjkkqdeonohlmmlmldmjkokormxmhplmpmpklkrnTmsqnn]knpnilmomjmmmkjnoghoo_kjinnnnnhkonnojqpo[nk{m]Vj|jposqtfnguvnsllpmqp`xpVli_ojqnkmlomnivoacrquojkmootsqfelpqxjslnkcodojk_lmnnknonyfpokmrmcsp`phomhr{lhpu^njpmlq{oobwr^n[|cqejnqljep[mmiok`kqcpljlslajdkttjlwjqkkvnumrqpoompqdzfpshmrop|vcotnmsqqcinrpf_\jnmqpopzqdl^dioircwqrr}oklffsoqT|`copgsprjvortldpokwlrvmgnllqepnytqpnu]nqlpppnpmrfurjq|poijjsyaoXpkmie~isn`pnioshhkpqkldTpljmhrhYblnmhoopoqj|frj\ykjaltsjob{nkvaqsr;kq`npurpzlfnpdkqnurgmveokmrwn^Uoltuko|qsq\eyMxmjvgunhkjriOmtqqnmmv|tkiuoifjozlpmpfelo}prjh|uelrdq`ppj|niqgipqrijpivmfjnqjrzrpqd|tknbelncukitrksnwolthremqkjlintprnojifTmn|gewfks|zerwnsilpqlnklilrufvjqqzqinouxhrnlfkixhrtebupetpmhnXtsjoljohq{jcojfrlnlellgnifmljrsonpregerinmwkfiolsmhlllmlnqvpjolrdr{chwuiyjlrmkkwjkqmmsgjmcqinzqlomg`kwkmpscrfone^mtbviplhimqjfopnmogllreptsxb`nwqjmiuhzopjlpkftwsprjo\ptdnfvnkvlmcyqgoqhwmugyoiiexnhylYkvih^ksaikj{nmwni`acompsepomqhmmkpohoov[phloqmrpomojzrc_vjuepoikmqss}rhpptrlmqutunmgtnmdhkaoxqjiuppmgm_mzllivnrjrhlniYmvxpokdokyj`pzbhvkpcejlkdwyuji`rpludhJseZmmnkisopmxjnkZoqnpurpmnqmomnunplkntppohgfoonkSn]_okdopaouq]qmvqprmnlqprmynmqpobnltpunpmnkamaq}rnpjoSpkmlnnndltlscostknkpoelonmmfrmqojr_kbonymvqftiqlomvplppqnxamlmlmq||zoqkpoYdmqiomoikelublloopmmrjqlpnmlfobKre_mnsmpsqipqpnnmk^komqmtnqpokn}nkltnlpvqiwpXojonvbpnnrkolvjloprqsn^moouinclqonnslpmmvlToodvgpdlonpinqnmwnfigmmmkprvmghm]ckuioofnpnmg}phlyqnplojplnjhnnpvvol?rm}mojpbdkrp]nwqr{lmlqyqowmpohnvdlmoonnmnkljnnommlmmyp[ylamhofksllonnpkbbppngonqwqpsp]rkmwcrlhnpjkjrplmtpilopnplpVcsncorqk`ieilvrNrgsmkpnnmunpmkotongpkornxlmoo`sanlmjmtmknpis\jlkvt}jalbsrmkg}kpdnmpmlhlnhnnkhVgi~hhonormmryqMpilomm^sojmipqhrjnrqomSrjpnjdpsqqnhmonokinpiokvmymoopehnletpmvhsdnrnqrqf^eqgkl`ovoYn^lmqm~l|xspqmqmmmmjqqliyox^fkyrpegkfobnhnmmmojmmjri^oipwml|q|hmnptnrovrn]rlnq~untn\ooo{nllhnolnyjpnonsvlqnjoomnmkxqk_jjbj{znjiftzqrlzqn~qepqljnkco_\o{bknt[grqnnpqibk{p[|pmwuhlponlpoyqqvnjqjipknl}eknmin[nnnokqcl}kollfnosnsomnhfpqhlpvnoklojon}bnykrSlmimn{jokh`am^zwmlp`hlqNonumbwckvj~pvjrvpnnk{munmmkkqjntWoisklhooqgeprrumpplldjirpsnqbopmvnlnwhloholmntjlomlonomnionmnn{jvlnorvjp[kznknkoonuprkmolpllns{rpsitlWimlpjnll^lml[tnorq^fkkqjsmo]nmlo]tlpnkgjpqngndnlbllhmkvmmimhjvpnymjkmkojkkn__nnqlpmnhrnSkkgpYnq{lpkigvppiqpnikmngpjrnqmitkrjplmmfmqmmjnoposvo_llmtogypdoojoh^koimvxptrrguqqnnrqpjmlrjnjoqmllpqotfpngnlprrqolpomnCqkoltqvkjfpxngliqmbs[lmmqmnvoVng[sdnpbo]qlrmnjqtquxlqhswklpmnlnvdslksqsnllospnqn{pZqlmqhjqkm_mkpforelmmoooonhpvVpnrrjofyplllhn_zvq_mmnnfnlhfhkol{vlosionpiVq`ligmpnjkskfmflmhonymnojhfyoqkglpgzSmtpons]knreoqjnsjnno^qkn}sgkqknkinlns|m\promnlkvpps[rmpi|pfzrnjnzlnmso{qnupynqnmoqmnrvn\qpfjgxnporupmjvktdmolmyinjlpnmjdspqipVlqlp`\nio\o`rrWqqlyvVmmipnjkmqvmmmovlnomltnljrjrmlznsdmpoqujlemmqjvglihmlnk^_klrlmun{pmfehdblmxlpxkknslqnmodnko[qYqngmiolzjoknisbonimyklxwmnsspcskxorlriaruibwgloklrfoxclgqirqsojijeikfppsmktpsjkojrgimmolflitsnjxkhiqhsllcluopmnuqamoilsdmvohgr|kjrfkqnxkmldfzklxpoiammootmilpgoppnjlodmeloslqninhhqogq_fjdvjmhjirpwngprnhkrpmntmhkuqqfoonfikq|grlqlmrmgqjqldhklnojnqo{nxxgjhknjriqssjqlqgilollpqnlksrpliyrml{vommslonvnlqalqonehflpoki{aokscsxjqorrel`skvowochqppcilqpoukntqvfkvqvS{qnumkmpoulssZrjosxfyrtkgomsbggtqveimrfp{}mriopronolsnnznhojmknmvrorlmrhnpkjmljnprdkknlhkqsunpgnmplk`uxmgX`rrlncnsckl}qjfnnu`rj|lmsktdmepismpxtatlmgdwklowsmqswnomiztmeqoopgnhxnpsmklqlugnolnoijvnooyiromolpnmsmnmrpknrmuphqqmrlnrmmojqoofjjjpjmrjnsorqisqsknimrtjmwnpjqmqlqpoqnlpsipkirkjporrvjsqnmrniroololmjmlrktnmmotnlnpskrmfnum|rntomnjnpkkrnlhnsjmrijnkkmronkmmooqnonnqsmgmfknjoio}pmrrommonoolmqjinmjmollqjnsknqmnosvlnkmmnonmpgyrjmj|okhmhnlnsrkqSqulnoxonvcqpoqrjomqnlum^pofuj{o|ull_mqmumnnudnnroontpjnroqufSoploqknYmTyx|oqescmnpolqknrnmi|mjilpvlloqolloesjSnjobc_jlrkunioidknmpootkktfYomjksicxpnesqcmgcimYjormkhnllmnmmmqmogtnsopk\nwl~comqjlpmxlqllknknpslujppmgnrqmotmomvrcatilbqernnmjjqlm^kmmeosorpnknzllonnmunllmljiklnripnhnknrjumkntnkinbo_mqmkqocmvjkfvhi\yhnglsqonvo]ok]onnm|joolpjmkbvoo[ps^pmjnqxnmpwpkpo]pmohmjonymuorqjclnnlqrrjmkTmlnpsnl\Wlomlon|gklukolk[iksyyllnlxnnwpitipjppcuigmnvjkhkwopqmologjiorvfsmolionaqfmlnuvrsnlwsngmlsnibnqnnckjvummrn[wimsqlnjmymg{nopsrjrklrftodpnmnqoinrkpkrlbmej^nlfhtlfutlwgonqrnytgppkfndmnsmrooorlhiihiqhfivl^frlmnttchfrqyikf{vomnxrlulmjcpfjqlbsfpmrtihjnfc_rimonisdfkiohqohnvjqjsllkjnykoqqlmcnkqigtrnl|mujzujilsmjnmilxlwtqikkirlnksrvsmeulprmejfinhlkikjojjhxnlqoplmprl\ltipnmllkpqkiglqlhdjsigipkqibrokrmjnlfvvmmvimqoaiq|ktjgnffvslyzahapuikkxixsskejilnilhsgwlmfmrlpoibeqlujhsmq^npfljn|haiodmoojtijo_pxlhagelomoisrjjtqouwjoplvgjdqqnf_ipkkrkilpsrknqonzmjsvrlldgxtx\uv|njnclqnmqtummgZrjpivuoslm`fmtrfojnnmlqltsnjmkekitlklaolmo}nllmmmfoyk]igmrql|msjnnlljpkklgmaukvegkpqxnonmtmkuhgphrohjozqmlqfn`usoph{grouosilwhUeofsophiinnqnqntkqxsfofnegn}kwlqnmmonksojyphonmqconpviokdomsllhjnkioleilkjqimz`jofoirk]rkpnlgitaxoorrluismiio|emoihwlnenfnjtnnophsommkwmmwnqqfsimuloqmlpnolajihgVgjfmpjnpplprnpmpkrlohgefrmlglorkpklnqlsmlklknkloemc~nmSiimomqtrsuphoohmhkpkmewspqjoqpocnnksnsjmlhkkkmrloalmsjkgnirukiratlrglrrpihoknclnpvkjmgnhhqokqjmlqplrnmkoomoqrlquhptpmlojiopmgompmrjkchidofmsitrom^reikplkm{hodrrsnriodkknnnkhieiuqkiplilppplmlkmkswqrnphop`slincjpnicoqnjqnlnmonlirl_njupZopo[kyo]mokcjnfoqpknpmlvpeomzcqyxmhjkqnocl[mmsnlrrqglmljlmwiojtcquoiuqqwmlqqn|imhnlm{t|uoolqpPlkkpjnpptspoqvjplprqosvhoatsnpdlXjegplpjfhlklkopp_lrqqjuogkl}ghhqjiooqhmppipnqii{nmmybmnrkn`lp]\ennjp_rodpXlXnppoyqnnvnmkgoonkrlplinlokmlslmnomniknnqfkvoovij^niqkqrhnumfknirwmqlonlntYiiqlkvykqynhpkmbowoomnogr}uqrkqlmjynlklmlojjsvolol`otmmbrljoomWmcqYljfqlltnvwilph`lmmojmjpunojmfpuyzo~qorjnglqnlpmrVjrmpmunwllumrlm^ipplqriioippmnrmtlndhjprcn]mokvWlnohTlrqoqmcs{ipujawnoohrjfxknikzvnkqnetzlkkjjmrhqrpnmkhjcglpmfihlmhdjlhlrnosfpoeYnhquflohg\hvliamtjunrkfklp`khgiujhqdqpjlpqtsojhtsqlhgk\npmmhrohoquwnlolohnpm_gsxfkkwopikmrnnksunhkmpfivjl^kjshjol~theomdgdbqpkmtwukjhekjfltprq}rdoopciuhn}ph}mggl~olmfdkcolmyplgpymgu{huupunioqlesuilfpjupktvlonofoglnlrh`ejuroglnzppavgfokopsqwlmjrymfpspgmunpjvlproqsghjkohqwvm{vk|piaypymhtojmxmpgqolhqkkiuymikkslnjqjhpgurilzksqjncnsksalymngnklkpnglcjhjuhlmlounfqpppwdsrpiek}cffoikoqljkniislwoumlpq{uqkfhhmwqomjhrwkgqp_ndmnckgulxfpupkljgpf}gfxljln`qncuxovkcjipsilmqqphmepkipulqhpurotojrkm_{exrrhlaw]mepyxonuiuknkok_msXfop{cadurmmkoqozno]tehsvrkronlspvqeilmhq^wl{m^lvowklmjpwkjlhnotmpmomhmlkqgm]ojjqvipqkqrysvkuslkpoom[fckbvkjoossscjjrnbqlj_poos~hpgozrfwosbjnnq]mhlplmmoxknmvr^rmpaspbooektppphoolujnpmmwtnkmsulppqknbnqkrrmmogj`lqomrkfonlknnqnn`qiLhdomdosm`gdroxqrsmlnn\oxmyvjcozpmnornkMlqktvrowwarkpnumnevfrqrooopngrytptnqm_npqwkopzoo`nfpemqckpminqknjlc{nnjmjr_mrckdligppionpdsylslpqkkgelkgmmrpblntpHhmpnqoim{opqqllqjupkloqlkn|ntln^ldlptneop]lPlhvkklopse`nuonjq]eigiaxivnplskpymssipospiitmua{e{mmoorphcnkfoclwknqmllfusjgptmsqlnsslutomimqwbs{gihuruipvctkoojkjgqofopvmjqlqlmstrhopxj{krdotjsfqinqsynqcdkcjbjxordia|wppmnrnlnirsdpblqap|pklsmomollmbhkpqnswqtqtylofWilkkqpemkcr|ogtmkryghqkouinrillrjorepzf_rl^smzlteilsbgnlohodomkoljmirotluhlk^vggjwrdjjrkljmfjogpfmjrju\mjom`qqgpmjglq`wp^hhpjerchsiciqsserqksZvjfuehhphsggfsYlih\lqomhnaqekiqqijejsuqfrfnsjrvqo]qoomq}psjorkxsqupuohnqhtmhkq_maljtrnu{pmmulqqlnbopzcjpqmkugzimsfenoemtskplTtsamjmngenypfrrjwqfknprjpeobrrjjnzsimqmmozpml^inmtwsiosemcmmonlonkmj^pmdrnkswprtfmvovnnogoowqtnnnqpolotjpPrp[psrvjmrpnrtr}lofnnpngigmlijmmpntl|niFjl~mlgkkmhn]lmtnnnujrondmaoUmoxksmltmpqmnamknklop\ho\gpphqboclnmqkjoepomqltnq}jkik|hieihmrwnlusouqymvmsrjn`kqn}|mnjrnamqyuimmssvuollsfrsolnlammmgplp_npoqgjmnYvnoeekklorgkjhknpokoinpenzjnhsn`l^nlkrgnwrckmpmpnoolrehsu{lhhmgrmlypolqqnsoyjljnmwm_qojmnocQgjtoonponmzekslkm[u^lnqoulgureolmqiyolpobijqprmkmislVxsio~lfs_oqmikrsgfmmnw`mp[ohrnslwq^mpkblkpmolmynlopoxmqkmmmptrkyqjlnoumpjqm[pqp[ng{hqqqmkokjdguwllth_ggjlkmpllvncgjs{pqprojchfxYpbmkmmjimcpaklkdhmufnihkhnqfmknkukmfgZn`i|ktl]hqengzfcbhYSmpftifqamhmco_kRnlrlkmkb~mveupqhekiyojlbhp}fdboumdwymniijphlknjhktljnjmfnms\eiotjoecjhnkWtoqpqigokk`olf~ytpoptvhjqjmozttdkknrmsilmoromhlklndiZjWlfjPriirwrwlqsdqkpn_ollioonjnqilf`kdqkbfumnojkVerZps[lunqjkkgpnrknmmoklklonknjmapgmeksjnmhpnomgmohxkifxfxrqpcomjqqjrlumgujmh`pommrmlfjnnlpknlltahaflslnnotkqpprnlilpsxjhnkbm{crndkvjnkkzphtlfue{rrpijongimomommgsloihxnjprnpenpupnjuljjgmnmkufpkajkhomhllousp~ojw}jjkd|kfrrmpxxmp{jzolnkmhmrlirgtyw}onpiviiypfnmcjhlpjppn|nspnmknnojjbnrvtofoxrkpjton~dqqmnvxcqnow|wlcuptqmnnqcznjmtkylppktjspooqksmujrpoqlrlnqnnl{nilhsttmknspmjkdoirpnpjnnokposkmspmlfintolfonnqonfoljannopmjkrsoropqopqo{orns~kwuknonlhpqokwlvpklilstmuulriurojlgqkgidjhfipipugohovtnshigifkjkbtekpmfh]qpmhlnmtnrj^Znknforqlsntikugmscjorkungapqirnrksimcnhnmrghouprmnlcokrhbinstalnouigipplokklkinemogytmxmfoqw~mejplqgmsulf_qamw`rslwninfkphlkjnyy`djmnhix{nkgslxurosk^nqkrmpnfmpmpqqnpnojjqnrup~mjikrwsgkntz|olgralfnxqonmrmlpkrkkpqlnvjpmjqosltgbpithmk|mkptoqkrmnmlfiutnpqnamxrjloujlmkhriombimskkms{o[jjolqkpmqqmytqlzbn\ghpppqcnpekmkrjktkxqkkjlziktbkiomllpjnfv^liellor]j]pvjkkmiZfmwlkyolrp\jonponmoXlqrlqnrtnonggltqc|jqlpnomyswhehlmhklxlrjorkinqjchocprqnmuognuqplphlnnlqkonmytqrnpifkmmtorn{|nksllxmcqfrijo^VklcmtkqfprjjponikpXnqimsiqnhpZqqisknfxpeoocnnmk}mhifptkhnnoklmfamntr`\ktfqinYpbjrkgtsroggmrhqdilggqmgkqlihjhsWZjfjocnbonojonlljjc}jknpalfoiksnilslnkrkompwiuwnlkbconn\qlwmrqjwmqnmZ^qqreolp`rikm_koVnrvoopilrri`rolqpxmarhrglqnondkjm`shssrrk{riunoknwn^nnkljpkglqflnrrs{ocljrpkrmnoqinsrnmimpiksihlkqjpooqlloollx}oohptyrknobiiknrrkmkfmndhvokmo[pls_jlpewmlnpllkpmqlvnlrqrprwmqomrzbpngkmfhsjnmnlkimlniwkmowmljjprnrgj`nlsnlmoj`qnfmlnirspelpxcowhlroftkhkqwojjokmopjlplkknnpltoenygxkrtlqmorhX[uosjmpcloujmomcqgtkgXjwWovklzonlz\rrlkbpimogqkrvjpq~sbikleirmjveppnljvurmf}oddmruyqnqrbsyhrc}jpoorrldoztvlptqlonslo}ljpqsmqnabghlpn[gjlypovdqoirnnljefcnnopl`lgciouupgnddlmhdnpqxgqeqrl`\n_lvuomokvejeqityomcjvrsrmnmqoXkktgyglxfyifnkvnnoijrnnnpi`qlWgk^ukroiZmtsdjgqnmmnlspxw^jgmvumiqttljsfgrosnnqucljorrulhjpqkmzuumpttn_mlnmrbtsvojohoj\qgnopytcymjphpsmdprfinjtotrklqulimqoimolqjvwmtiesojhjdineoolxqghknnklopwmwjnhn^jilrpjollcmlqsoudn_micqqpondrijzutkexvjomtlwqtlmsnwpmoinpkprwgjmosqehsoaqnprnq[nppjpnpnmpnoprtoramnmndmlolmrppoquvliiqr\Yqy[mdpXldjnrnlwnolokmjmgtis^l}eXomgnoprmnoBjovpqjrpskppnljxrhm~oipnlrk~kmpvkvnommhlvvdqmrkqntokeklnoqonnemr|mjipnnjn~lyqjTmn`upomnpir}lpVlpsqhrnpdllqo_ltjrqmfYpnwllfsenqonmoptnlnwyysqumjpM`gnokrbqoep\mrjjjqloealk`lkpnmpmflUgokhrhmpnrlqlXsmjihlrnpigljrsfnkqonpnmdnmnllhlnlznkknfnlpnihplofnmijmmryoigdniillmibmeuc{rmjdmklqhohbjljjqnoqogonplmtqwnpjqkpx_nj`mp_qjoipnlkiqrzgluqljqmgopjpoojnjjjkmomnlfltonoydlokp}rmonrkqerd{tknkidahpndqrmplsrjkmrolghrtqoopqmbndmndmlooHupnlxoqntlonimmlporomimjvnnpoolpmonDynrorxkl\orem|pvmloorn`qxknonlopldOodelzhSdlinlnpnSnaohanpkrlmplomlhjropvmbllmmonflommtmnslomff`kllplrhpoqoklsmhrlkms^nlqlqmjvkm|gnankizkqonsofloq{qnpnulnnclplmossg~hjnhrnqlkkolmoopqlrepmnl}yuoonlp[ijllrrpjzn`poxpdkptrokrykjoognnhqunhojowgsqknqknmcjnfinl}ifnjjlhmliwzwnipp`ohfdxiohkmdm{pkqogmrfhnmgbophlgsanonlywnolda~xprcopgrtdlpasuqkrjkjmnihsp^mqmhtnnflmorsondomkwfllpoqtrnxkinoenjognnmkhnmtpllkn~ksrgkmmjiperoxqmivsmrjommeiiwfnrnqnw]kootuntlnjtanjkkarrmorrnaqusqkrndznnrqsonusnnroonqemqprrmqlkqkmpoqmpsSpfkf\mnRqeopzvVmijtnnypjonnrnoell~kuxr^qPrnlrpjmbryn{pjrqqNqvomlmozubpsqoHmnepqslpk\nnnmanknt{Uulqk\pvonbnnktrsqhkos}nkoqkppyqqefnemziymimqxtemouinompmrlppnbqowrrkenknnjn~nklkotkotsjknTirlp|lnkmTxijlh`xoomsomrpnQplqmwkmmvnnokkrnp[ynnxoqbqmlkmqqooqnliarnslgwrznvpsnrmcmmlfmntknppmqjji_plVl_pcmlmporlblcrknlohphnolln]yuoptkm[iobotuqonsmlmkunpmjyrpjoro_oq`oplgrrtirlxrrulmhr`celdrnnk~enoxonpsu{lsycnutgwouqjopomhjrm^jreqpslniojnhomims{lnn}hukn`nrpmjnlpn{brvl^soqienuilxnnyqlxjeqmscjoofmnmpcmdoskuk|mnmpvetoholitquhnphmprq|jthukhpzlppnpnotp}umhttnimkpulTsquqrkpooptxltlrfkoxqlxrodvjjplkkfnrlgmngoqrinknmqmqisrepqdqnljqqohprrklnkgkotqllkkpkwnggggomokhqqtvommmonfvenvomnpdlki|upxkptsoolkklpnxvfgmfbkonrptmtkelisrepphcnklnkxhuotowqiuiwn^fyblolpipkmjtjnloybmcepiykikjooolllatnrjmqqmtqfoupqkllmtpumjqpmo`unmxpgijtoruoaqmllkdqr}lfps|tuhrmvnpjwknn|qspa{qfhorsoflpmq`mturfkn]knmthhmtgiyxcrnmrjqimnipnoiikpnoojnirmfyqjtjtqhgemktlqrnaqehjrtiqkhdrnkilp_kylxpjkmotlmjotfbmlmhjnbihkqjhquknorqfcvp]tuqokDosjcyokxm^`neovxqjcps\o|gniopWobbrzkgpan`kptnuoptelspdcgjo`inpkbiWfsqUonjjnehsjmhhdH{bwpirokmjgkqsklbYpnoomqk|efdirbmmovroxdpsckgguiZhphmfblvvdqmpndmzmmptmhgo^mpoimehWwgntUnqg\zlqonmntqnkmr}wonmfpppxnqsstpiulqomsvpk^lhaonjenPmwmuokpkoljhzjorkntsqpqpqcrnmlooospjuiu}ujll`sugpmmpioscmfrpouookoipiglinflkgkctkkqllpqpp~okhbjom{ggmxhunpisqbbrkppoqboqomlmlwknqiiqdnghlolokindptunqr`tqgbqbr\lmspknnrjjawntiljl^kipmjakqjljonrpoqbo}rmnlhliXso_noqloxstiimloupmywqkj`mqdsqflrjnusgtvnohnsopnsmfnpn^mqmksmiold`smvmkmgwikmonmkkmpmnqxchwcnjqkmnpnvgijnoTuohmiodngonojimymkeqohrhhqfktrvhphhujnjmmwkhhngdjn_fjtgiwrjgiopnrmeqzrtkzhoillpnsighnlomosjypnfumduupmsonlniqqohuimgrngkdmnmmtwnvjxbkmloogrylpmoswyqchhZhmlvlteyobeyptmrfincqkmtbilqkijkksljpfmtnmmkmjvpwqjfjorlekkl`nlhhqnqgt~glmhnhnpopjsg]quhkpmmhov`qlpkijdjlrtnqfojnsipokt]ojskjooqokrpjhuohgftoqpsmbknoeeojm]h~xlrpmflqjlllhmirkghtppqamrtjpjrpipowlqrusjnZocomllfcpnqxt{~cgejmkqommvgpmyplhkqhntpjflsksmurflionhprhkmjmep]tznroogkkql_qpemionhnhqhehmtrhlllrsmq_pkjnlqqieqpmdinnion_nnmloqnnz`lxnjlqmnlkoozekjlhfkpfoqsoyo}qopaonrmsnlklpotlYqqldpnpe|orjojpmotqlilpskanrnlnkogckpl`lsZopcpz{oqocntkowolk_kunlwnaj{no~ommkqioqnntljqkvpmboqmgmhol^eiotlsoxukn]slpqjZlmvnjcmwjkjKploiooqnioqplmmonigopmejrpn|jvmopfomjih\sn|khlrklrkidpjm}pmnzmmndolorckom]`kmlmmlnsrmlnsmpnkdoifopnXj{opppqopxkklronmmmkihmuir}\ijglosmoemlsppnim{jrrmrppqyrnlwnshokZsxgmmnbl|lnynkrMrjl]msqkqkqqnpsslqlnkm]lornmpvjhpijnpoxu`nnloopenquSnkniylllmtnpgnnvmnUrfpknuompkvnhlnppn]pnlgwYntkjwnmTpnoppmEqpynkpan`qooeemomumnJh`p`n{ssrfcvpzkrduqWZpnodmmgrblnekxdmfvncpfnblQsmqrbmccunsompjpnhkolkknsWlncnogkyprw`qqpgXyrqcqRonnoraohkjjnhqqr`ruqePrloenq|rsw~oiPujosnmhklon{jqvgkklqkp`mrrrkepjqabmhdsoh^kqmmpgnohO_mwmqlojujnbiPujsm^i~tyqsxeTfmqqnuklofimopdpoutlpdi{o_lmlqkmeliudgeuorfnlpmgokj_rbxvrux_hnzoqitqxpfqn|lnsmbwnlhi~jpwqrewkpgjnpqsopYppmnkjthwv}nsoyqlnldpunmvjjmjinlmsudpmhlqeilt_`qkpxmkpfqlnrnpnbmnrVsokquabosyivhipdnhqmmkmmo`lslqk`jjijlkfmqsi\nromlmikkjnrkqlnoyqta]lrrqlqnslojekomiqqmbopjqjhjsitolhoplnhmckpjqglfmlmd`exudvrqxk_psmqpqsmijgkx|zsoisjqflsomsokojlfpkwnrplgjmnnwzygnegjjrnjurmlkdwjlqjwdx\vqbgjkzplmqrfjodagrqtwqoggmgfojoltnontunuzk_ignosuilejqhbohqkgfjlpfpgrmuYdrhxpgmmilrtmmomidjbhmxpprhmltekiouofpkevqqk^pwsjneo|mninilosonjrjomlmrr`mnkkmgwsmq^tn^ojllrujnodolmmljmqlqllcinmohhhoijrokkxmlqlk^ng~eyotm{mernoqncnnrhnmlnqnllwaixu{t|[yiolmqldpkseqnqnleqqqoqvowtkkrhmmfronmjokotnplmkjjnj\yllxmroZmowminpsnmnhqlonknmghnhmokbrmlpusnaslqnlnoopnnnlamq}qlblxpoijpinqrqmlkookjrmloxsnqchhmuqn]oofePjqqltsnkqrpnwqjknrqelixiotsemoujoomjuo}mlrosumnuhoqolpzkkfzgpmnmxhorqmpikdstovstitrspqntkkppsoylotqocpimbhxo`kmnfgksucsrqkpsutouqpjrrpnrqrnpdrkgnixokmnrmqmmrxtssklmtyftokqtylqioznnmnersmylpppjiwjmzZow{qqnornsnsrypl_hvthqbommy_gpk`oemokf{timlzqpqvhqqourqgooqmqstrpunhyjpuoq|llX{hmntmkdryrhhqqpptmqbnqi{otniiqlaniolraotsjqeml`nymuneqiqpikfteftmlocjpmZps{reyowmuuconfere{mgirgmoivsofitqolsqijpoj\qgsvrlmoslqmtoq^mrzldmmn|inqpjlqoxklnrtqngupbimjigpskorjmlyrkgoonuu|jisu\pnvmj{muhzxykxfjxtoxpjgi}lijghjsmgibkfezqknhl}mslormjmtkhelpcwmjvnqpsshopmpokntrsskk]xkjowkqrqhpmjkhmppwkmjlinlcrthsqrhpognqgprsszmmjmYmpfle~mvhsnlooyookqrmkjlnqjqglplgroqlnlploknnWkoryjrmqqnjtpmljeptglgkqkt|nhkiolskoporvnvpjcqkkmkppiijrpnjtqgmplrychwhprvojnnuomfhokorqjbmgtjngdpmn}mpplqjpripjermnnmpofngrf`sgnllknpkpsrgpkqifjgprldlmnnxli{m2qnhoogofepnpkonbklegjlmqsnogjknijlll_rootnctnrfrmftkpaicqnnujmcuupum[rzklonbxpyookjrkjjkpspikakl_npioiln|lkl`rtroquoqrrakpxcslZvpnolejoposvocsqlgrknsjhpjtriss[[qjbjmdqpjrlxlrgaoMkcglqulgk`ieenoVnnnnsnLnnohmlnitbnqq^vlsho_}ounqnnqYlnpvwotlpvjmilcnjmnqkgimnoo~smlotqp[mkp~nppWknaomoojponcow^ktOrmuxpptomtinnkUr\qrmtoOwsohonnosmtkPrwuml]nfnqrlqwomvrlka`frnejsqXnlfmomrnmupjqv]mllmnpx}o|foqmgxrudoolkl[isrrnojslmofrmqpisek_hlmprhknujhojmkojmjrmmunfhu^k^nmhnuinptkuosotpmlklnTkhpnnpqr`vmonnqnppfnnt_l}korpnpkpoooyokrnnRjx`fdrvmritmpqcnnomlqxnbghgbniff|vflqplrzkr~wnlilkqmpnilltxtjsqrd\oogomYotoknnvmkrgpmQalnnp_parmvqrnjpovljqbdhjmkmlsnvopprlz}ryklsod|pukpoonhpmllllqmlpwoqzhkjfonknrptnhooknoapmni^ltroeppqbqksunbppop|nknllojemjntonl_mtkionmqnsnosllmoqjnmnspnltunjqnmreoptgqejqnqkdrofm|jmnlnmtngrmxigknuwnqoopnirmem|nnokljlpknpmmgrsomkpqjlmppklmorqnnkogomolnimncpjq~lksknlkotqpoq]wnnloolkkqoojlclltynnmmnptmjmwioonikmommoolkjxmdspqgjoonmqrdolnplknroomZiholgmfoop{{nlpqomlnkuhnjkupollsmonaosnqepkoonoplnpmnlpmkorhuhmbqntkemuimkkmmkqmpkoqq_jtrhnrkonmjmmolmmtonpjbqojimohrnlhnomrdnmhfsvmttllhnrinrnnqopmmfiocljonprjfnnrooomskvjqpjokpgoltppnmokospjmmmlmtk^llprrknhqojkrnlthljopnllocmphopsrnpkngogjqriosmtnkpprfmphrtrnnqulmjsrrkrmmitsmorjstqgurnpwjlqrmmnpkpuntdqomlmnnqpkjkomnlogorrlkkyrri`nrsgmhlsnorqqnopqoienhjpmepkqjxrpjinogliTmykmsksimnmsoplipsigmopmkdlxsmpobkwonpmluipmtokjbnynpbpootpoppml^eomsoomopqppptsn~ifuqpqnvpindtlmnrtonqliqlplrivpkngsmonlrleokjopjmnmnpslmslzkpponhnqqpnapnimmknq`_nrqtjuorfnlkgtqpPLqomoovonq{sphkssmkmindqupkipviom_p^kkmlvroohnkjnppnolqjkormlmnl\izm_ojkhnqokmc|itklsOphxplnxusolilknlqkdtpimufnemqloommqrlYlnkqshmnoxngnojuq`rqplvnmolmmq|rpoenikbrplqplfnqmqvosoglwmnorlnkplllnp|qorpnarkjolssjknrfgkrojnaip^qplimjpliklqobloquklnkuoplilplimhhkjnjnskhnkqlqarklpkfkojjgnuwnforoipnqnwmonlrnnimiqmmnnqlvopnqpjsnnmvseoqnlmnpljqjjgbmnjqpkrrhsmnmonomrqokollmksmoptknpopnfiikrnmmclgo}ofrhjenu|sitmpmqfnrrqpaiqmqdqmlnotkxropnuujmcsqhtimnkkimlpqoomjlojhpmknvloofqlinikllkljnnjkqjiljnsjgjjltijhltmuulkqoebnaomhpnrnvoavjty{nrllinplnilgooppninioinupnlsnivqqlmkmqiltpmxorlramostsqndiqrimj{nijlwqZufrhplhtqoihrqllkngkfsmjnkrntgonipmvmhidbqorefioilutrklifmxhdmqkkmikmcikqlgqgonmvklnijeohoalnmslppjdq`mrqoqmrnhlnikppmjlkvqksodnmoipimmiiemlhqelvnnnnsjnsrosrmoppgnmonpmmopflnypjqnomoonponkpcmspnoskjotinjp}nrikjoijlnnnmnlvmlnrllio~qmqeoonoodowjarkkulnkpoplqoymoiomnpjpn{k`fpkquornnpnppvjhmnblgpnmmlpnnnnsokk~}oomprnjionwiqpo\prixqmkn_jjkXioppkopjinlkhl|dl~slvqpkomlpgolmnlnmpnno}cdiomogppwnpmmnrjmlmjtlktsrsnlrinmuirlrmppsmuqmjjldqirrokqpspenmerjknujnprrjmplvnnmgrkommpnmmwqmlsnqplooknorqqkqlpkpqkhpjmklmlvmqompjmsrloummbjpirtllpkslrolmlpqjogimkynntrwmmmpwp{kjomkpnonnntkoqqnptinoysukrpsjkprnijormlomoujjwomnvphznslpmqwsplqpgsniosjmoskrjonqnqqntqrstprjunilkhhnoontlnnpulmiWipklknrqsqknjdqiomnonnlinmloionkqog_kxzlfonnnkapnetmomqhmmrotnnhqklnohqgnoonrbqglfpmnoplmoqqmknvnilkfmrrkmtmhjmmqsommmppllqpxuolmrpgoqskooosomnnmmomnqupq|sknymqbonmwlnlnlqvekohumoo|rmomkknmjqnqxmkqulnfnrfldomlnskkionmjmcsnfkklnunblmrhxonqluokmmnmnemnpipmngpunglokopxpniopYonnkqnprms{gmpplvivrqqznioonloqpp_jmknpqonumwvnqmovnomnwkkoolql]qnqkopogqsjnojnsnrprknismmepjtmnmrnmmmpknnrpinnvmmmrrmermorqnjmjqinomoplhklqrplkprkskgmnlss]iuhunrowhoouootorpmn`trlrmmlnpojfnkoooormmlnqqnnmsmelnilansnlorosrosqggeqnmllgksimqloppmiljplnnkmplogkgopnpklopjrolrkkignmjnvtnolpmmotsqokolofpjoppotoluolqoleornpmirmorrlpcsnlhnptrnhpoiknmqimoookcmcoomohrniqppmlkomsqtpmqliijljpjnlopqeuhnojnklminqmoqplmpkoomopnqjhoqnwkjpbpmnrqmjrnnfrjjkrptjnppinnmoiswpnnsmprskkonzlnssplpxqoqqiarffopdorikitmlpk~mnmokmboftmflqsutkpwpqrorolologmbilnoouqeno}snqonitismdtmpxommmrnh}pqvrvcjpmprresmqqj}nhoullktukhmtplmhpOeinokilmwhkqmnonrrjwoqrg{rtlcjbtiophmohppniomoo}knlrpkm_nqsnruskolrlnsoshXhjmh{hprcpoikpmrprqpmowjmipjrslloocmmnwpotkqeqovqnp{nmjkknmkrmnrhloljmmjomotqkhlnhiqrnonokosgnoqsihqptoossl`jnnumllqoonomnmmlnomoj|olqlfxopmkpkonmhp_mvjjlrjjkkolntnrmkmjimoflouqpfnnknopokgomqlolnnporjpnoxmpopnklkloumknnnmmfppoyjpqqupltppmronfciykprlovnqlopsofextpwssnonurqmljoeommmmpspluqnlgrliprpkopopmhspqlnrkljindonisqonlunpomkklqmurptqnonlllqjonlmxrprqmklhqojtjnr|qnmmhnissoppsnnulnlmmrnkdprpsigooiqlrmqrlljmrnsmmnhohhkqqfoqbmnpmndnmqnlmprpmkqjhrtoqnsoslpkojnljivlllnqqisgkocpdn|invoojhlkqlppksgjnuhqqmznnhomukoiblp_ynkinnllglspjmkulmhoijpanhkknjnplwtmlpowmiqqmpljkllkq~lophdippmiopepbptkmlljlkjn^{cnhilpwkoldfinrkkjhmntlojrnlnkpmluvogpjmrloomsksnnkngkoombphlhkm`rsjqmq^mlinoktq[qgaannqljmfskominknmopmpnnZoenliplkqngnnkmvmmocpmspllpikojmrphkonilmfniqmnqijnkqlsmhthjrgugmonrmmo^efqsmplmnilanrfjummellspsjeoqnhnklnisnnkomXlrlmnnrivgjiomrl{mimncjlkdslpqikpooqkkonjhnqtkkolseomnnlcnhpmglqknosiqnivptnvlsikpnpiomgplqnklqghqsrojrlkqqoohipliolonomo^jiqqqlpgnkojjcnhmpdljhnmtokpjqqolokjhjjmumhnlkoymllmqlppspyofrooppnonjoltmrplqhklonmqhpjovjpnfkrmljmnlltrnpodtmnnqpiosmjnljmhmqomplnlpmrolmcnmmmjnlprkilgknnflmpnmnnqjslnlquihimnpjhqntqmqunooxhm`nhnlooonsojlmjcjnb_kovrknmqplljjkpmllqqqnrlmoptokkqinbmmjorhmqopqyknqolnsnooomfk`mlennnkknrmom\mlpokpmtnmqnmimbphmooomneqnkjimpnqolmlmoknsoijlskmjlommpmouojqomnnvnjnyryoppldkpomhmmookvnpnhhimnkpgqspljknlumnmqojlotmmmmirknrlnornlkmwzljqlnorinqiokpdmlmrrmtnllnqkmoumykpkhkeoUhqmpoolocpjoiomllogomnrgqpeqnjpjogkonkoljoqmrogklsommicaplnktlxmoslmnlnskpnpncltorrllhqnrllsmnmopqmnjiwropknsmfwmoropjnqrie_jrooootmsvmunlolookwomnfuhtoxqdlmdqvqosppmlnnktoovonppshsimnsjgmwpndnbqnmppppsioognjnnnluo{pncsq}mjwmqgtmelohmsmtjmpkknjmf`gnpmmqtsnjpoimnmlpujohpqnpppnethn^evhnpioslnlpoppjnukqmrlojihrnloqnslmnkfnkWobpmmnknjkqjn}_hokqknrnqmmionhnnrrdo}ooqssslqkllqpmonmpkpnpimqrksspmqslmejnpr{hpvpquropsqosdaimmrimlmplkomkpoirnolklprpirmotokplljlppqltnohlksnfijosjpmqrkiqlooojommplkninvsnnlojoolqmqrnmpklsnknpmmntjohqplpiprjpuunhprnsomhommpnfolllllrqromqomrmmsttmvpnjmnrlrmmkkrkliiprloqmjmroolkmprloompkmpplpjoqooiookpqlspinmlzqotfemnnipplmhhnonklronilrlrilsmohlpppllntllqprinngtjmrugjpoflkjqzhnppnkijkpjlf^ojmkomprsvnpjpvhotnqskloipxopplsnorgrvjolqmoehomrrlijsnoprsomulntbtmokjomlloivnrumxokkmkklfbmgkvuoelcjpqomqkninrwmfgrwpkg\nlilgljinkhoojklxljsnoqnilaromwtipldnnjolssw^vozpjpnnqqnpk`vvtorqukfprlibopfokjmrlopkprlnnspovnqrlnlmnmtimopdonm]onlqqmlnnmjmvfobnknppjsnolellmrnqnmlnqrqlounmnrmnolmolmmknqldtphmkoq^lmopoplmkpjodimonqsmpomqllvtmnmomklnqorjnpmjnoqpslmmenphonpjkamploknmplrsnlehmooporsilmionwojpxlxrmmoonnkcpnmnploqtmmnnpnwoodhmkonrpntqrnnmommommkntwprnpojmmvpqmlmlnqmkoplnmjoqnqrmooxknotkjpzmkinjnnnmnleojmkskklsnoojlkipvjjdomvqmlsnolurqmppprplpkqmnnnnqmokponmqanjkbjjholoohopsmrjkmphpqiouppnklpnalojlrmmlpqsspkljlrnmrhnktpwmmklyfuumrjooklolnmotlnqis}psnkkmljnnjlvkonnhnsnwqouuonqkjpdmjqmqljkuomfofjlmnlmliponqwoportcnopmhmsnmgj}{meoteululpoojrlwkufnmlnloinlnpjjogjolrilp{ipttpxrg|prlnmtnlqqcrxnpuomnuonkiodqqcpjugepnchlqrqkhmkepplgadm{{mkliklqjnnstnlkrplrqznmnotdmfeopjjupvjmoyl~j}rgfkmooopkfpkjkqtisgqdgsqolplnimlpnnjgmrhompqrsonqkjnmnj~gqlpiorkbmmhpslnwqlqhlmngnkkolkjllmjonokmom|bqnom`msyopgqkujjktrrksklojpmlnpqjvpnhqnhsnomglomntrpnlmmqjnnnuiknpnktmttoorjjsrrqnoqpxpqklfinoqoynhooqpjwmmpsfkvrukuqnpnpgnsnvrlgvkkvjospolkswqkksjrj~mbrjlrgtqumsolllmolguhlkwponnrqkuokqfskpokjmid{ih}nhhtfplksvxtojwl|qlojwlqmuqmkirmjrsoqkprmnkjklnqtrokilwtpkkikrgiosoogpnqjjpmsngrlklphqwvnrmnrijrjkmkilmkmljmmmkrnptljklriqitiosooqslmmromqmo}mgqmplqsp}jnshjognulnm[lonopfmphnoqriopoiimtnnoqpnnooinnggormlkflhwmpmgkpnmnqqnierpfmpmlcmqpnoponmiqslcjijhfnnpnqsloppnrlnlvpqnnsmvosijnojqognmmolqtnmrjkqootklnorllriolotmqlnqhnrvlmkmumlmutipyxnppmokksnhlonhphlllphzoofmmownpmfom[hnlnpolljnr`llnln`uyorrmomnvkrqdsmntnojnltkooqksqw{lpnmndsdjnirnodimnrklunqnoummmroksonmhqmsmonXspnmooofmao_kjwnsjaogqmnpoajl^ppqncllnmknolmmfjinqntkqpnpkn]ocnlokknnpkifmqlqnommkoqmlpqkrnljnkkmolntloilqmpptoopilpsopjlnjjpqmmmnpjimnpilizjkoqhoslrlirmnqkhlmkqrnmqlkoipujmnqndfrumpmqmnmop~p\woomlhllnojookloukiosrmmmmrhnlrppjkpokniwfvnnrkknirpuknonpnqqkn`ulmpososqin~fnoonqlooonrsosnl{inqmiknpmnrlohqenslpnklillovpnnmpmrmnhnmliklmqjnnppmjuormnwpmdmkrpfukopjimmpmmsgnppgnslrklnoqmitminmomippmglnkgoiikilksgpspmqmmoomdprqjtntqnmmovomlnpjkskspqlpenkmvlrkunwmhlqhkpkntgfoorpqkoknmdmhoqmiogmlsnplnkmppnnoimprujsqhoiltkkmqljpplqmqnlmfrmmkgmovpnqngokkjqgmlmmjmsnljnlosmlkosekpklmrommrtrmmqnnijsqjsnposgobppnpmhojspqjcnhpniunigjoeblrie[opnjopmqpreqi\lleoiotgjxmnspoipikkcqplknhoopomontnskinihprgnlopapulsomnrkknnoikhtfpbzgprlrphvnmoqkgqspsqatlfpgnoqTdnriymorogjkxhngqkqdneitjlnrq{llmmocknkgrypufosmwjrqmomfvhtqqqlmhmwmrysumpjgsgpildmupognkllgoomkqjqkpltrqtitmk^mqnn_oVjbgmnoncglkmqjoqoommnnomkmnnnwmnknpllnmplpovnmdnonmjZunYmip}nrnennmplnpnspnxkriopskrmh`mlnnnkmsnmo{tmnnlrolmoqomuoopooqmoooxkpjlplamsimmmmm}hyonmnukxonomookqmprnmsoioorniospeoomocrjltomjnljooysplmtcomkjopqpnichcrlqllqnnmmsnnmopnolomolnnnoknplnnibonsjonnsnirkvlpqholspjhheeqfpnnqspoolmpoglmtomlqllnwlprkliinqpsrjnlnomouorotoinlsjlohnlnsomirmlmkkkgmqfnnomqvpgnkniqkknvmnqopmkronppognslepkmoglphoujskpoitmmoqgontpnlkiovhlsrsorijhkoqlprjqrlkzoqmehmjpmiqjnmmjumtninsqupljnlqllnutimshmzlsfnioorpqoofkliqslqnlshpqnonmhmqqv`}npkiypiouolrmroohehopmopmtmtpiqdurmptntlqespnqZqidnmkmm[hjrnqilomhhgqpiufjppklmmlmqjVjyjcntrpnjywsorlspqspmojsllmmpsropopqwkepimgeipofmponqkdepghvjo]jphhmuqqmmsvnlpmhrmq{rrmmnemjlibphrlsgoxoppjwrkkwmq_jpkvpeomonskmmpqhmr|mnnhnlutovtkrkplrona{konjlpekip`votkoinbfuljpmpn{njpophnwnlomorpnvvtpdoqpo\swuljolliotqonmqfnjkoujijmqishulpvkplsjkkktbmypqivhkvmjpjslklnlqrolshfkljolkwjdmckmljslklsootmlnopjnnmnimtkcnap{m{qnjsicesmnokonwmjmpm\kzm}hljknrqqtivnkwg\mroohomigoomgltrkmgtmjlmrloloqniloqplsopolmqotqmnkbltqfmpltioomvlmllkvnsknnjjloipnkryohiqnzittjooqotivoppjnmchlptnrqkumtiolmpommhlqjmrk}jplpsklijnwxmolqnikqskigxjpppojrojeumupsmhpnppjhqowkommrronnmlppaptqrkomhpgiltworpskfihlpkknmqkorqnnjknkgnmkknvlynjunnnjuirnklkmptkmeopokooopyrlpkgnspomloliprmqlolmlskpoomjknhkorumgoioqiptjckcnsjgirrstmflvgnogueljrkkqsol{ebfomakfskijknopcnp~ihrtgffelpmjlrgiijqlp~morolepdcnymtjuimnt^pgntkrtnonlqlpliojvuopncloifqdpoqmppoknqobpemimrjggnkqrdu}tfjljrkqefvplrlmeoamqjrllprrnlqtkkrfnfmiqjlgi_kipzrwqkqjpjrsnnqpjoqqnkxipqnkqjfpekqkjsoaqfokujlxopkqxifrklqknnlonjmjnspgtmpmmoiumolhiknpnqlvqqrloepinkjfqmwliolnornenimmuommkmmnjngjoopppqfqlorqrriqmjsotlnkvmjq_oizmkqmmjqmunhsnmsqoqqovojmsolpolnjonpsikneklpshmmjopjknhmahgnmqnonlllqdnkkkjpmncrppmqo{otwnqskponmikfnoklnlkqrkl`pimnkkjnnnmsmmhljolqmyqtrrapqkgwiopqltm{uhnm{simqolnflidllmjulnjkinmvlrjokqowqrgskynrnphrvmqlejjrmhovonppvlhjhlmnnntokhknkogmnpjglisvokmgouplyjodhlnljmsmpllsxskmvonqqm{nmkoolpgnvmqnqmplnmmkmoojppknoomjmwnkhtkmujnpon_opmqjgnnnpomsnpmmojpotgtnmukymijmpntlnmnsnmoqkmlllmmqqnjmuouthnngrowkljhmqklmsrnpprerropnponkpelypnknoinrqrksjxbujlqkvosrmgmlolvnnnjukspmjplqrjflkhpklwlornuodaqxswcisooopglhoolkqmkihthmokpjegmnupjlrjomorokqijooolhnnjpkgntlohnqjkhqntmnivyilbvjqjdnrklcrqhrojokon_nqjoj{iyorozptomprkqto}sstqpnenmgejlnisktmwunmlommknlrkknrlnormmfgmmrkpgommeqorolonehnkmkmnoomhnshrmnqpqmjgbnrqnmnnompipminnormqmsmtormpsmpkplnhmlolkkefgpmnjponhnvurqnnonqhoilknnqmpnlgponthlpiimghnmkuollmorklpjnilpmfomjkoijmjtjhzopmnkrprlkmqrprrkklmpmojkqsjnrkmzknofpinmjhsomlioqkmmoqmxnsrojfiqfhmnimllgkkojkmwpognlloocojmcooneopliooophlnmxqpcmnmppnnkonTjphqklomqnpmljqnptmnmnmojmnoknqwmrrplsmrkjkjunlnppkmmjlokqqkgpomopkmurpluqpp`mmmmqoplnwoslnpmnlxnqom~kmomnqolnpmploqmqsrnnnookwtumoonyonl`pommohllnqeloonhloiwnolnjiekrpmlvononoqoqomnlnknlnnoXrqrnkmlknueqmrjllnrlokpbplpfqjfqqvhhooqumqvpujqglgoflmvgoukneqkmpskrpyorjjrgnkrdiknjktq`lmmininnmjqjerenoumkndljklo|hqgqltqrjtli|kjmvkrjrkkohjvosomhffpqlmlklipelnoglqptmgsmquqrqrsiiprthvhdafnpoxhfsmhgdlulzlpymfboigtijophkkknujmdnqpqqelwmhrnpcnrdllmqkirpmmkovqwmruotultqqkmqqmpnlmnqljplyloncjlovnqrnvpqlpoolopinnjyhwsplpnpvorqmmlhillnqnpojohmnijkqomtnnoohorqupqnnlokkejinfxwhofuRjlirshbmthknjdrmmsklmlpqu\skplllpornknplnkoqmipwljpnfmmooqkkjqrjmfjmkmnnwonrjuumnniipiwpppl]jononrlpioronmpqlnnkoshqntknuslmnqmkktrplfnkqpqlmmotminoltmjr|pkypomlktmmoeomrnlmspmkkmhloosmpiqptrsnmiuojlllpnjsrnpompppopkhnmjmqprmknkokolpjflkqnjlnmjojlnmrqnljpjmmjoiesrrnnolpjnnohkmmpmhlnloopnlortomknlnnnmsslolpknomgmujpkxompnomjolkumllkmhllmumlijnnooqmqmmrkfojoiqrknoqpnnzoqnpmlmtqjotnilnlonnpqunqormjpnrjkkgnrmjkrsnolsqpojolqomklwsllmrkmnwmkuolmqnloqnjnlkhojiokqtqlm^nhmrltqlifikmonomfoobnhpijkvdnmplooorlk{onjpoxopmshmpmtqkj^shprlomimmnorojlmsjnnfoslmnnrornoqnnnuhstnkom}nomopoviqmkjpyptlfpmlpmqfvmdjmmondmmmmnmnkgogbrVmljposnkqmonjokwimmnoqltromqoulnsfuolrnoqncmdlhlnok~pnuolqniqjoltjlfiuolnfqlkoknnhjqrnhaojnpmuqaktoekikonoinfndoqmmmmlinojnmsbglghoqpmlnkmozoglqknpsskkrppqexnmdqmjjnmoskhmynyjomohlnjsikpniimmkrmzklnjkukhhruhoonqsnumnlpiuoqmmn`koqmkqpkukllltgjnitjqpkgo|llnjrmhkpkmmpinoyqnjkkkmizwnrqgomiwnsolhcoomtjj~okqeqqonoqpqjsqoooqsnmjnmnfnpnmlnjrhmptistkjrbhoubnlgqtpoomgqqefomnlmmtprhlqcu~npgirugnqnloprjpljrmjmjkmgrtplrmlgnlqpmwquqhnclrmkokhnxojmnomtophtlnjntmykkinqdeyhkkfquijqpsmmklouprtonloprspfrlhkjoilspqfukpnps\pwiqnnnmqmsnhmlqnrgqtrmupkrnmqxpqislopomqqoqjrosnlnlnkojiotookipojomm`lnmllquosokjmpllmsnlqfm}jliplihpljmhqgknfjjkompokopkmpqurgqlmllqrnlkqkvp]koifqkpplskvlrejpjdkbinmjoqvmsnpnoijgorlbekumnmkljnjtllokgq^omlnjolmrslndnn`qpklqzsimoovlopzlxcmrnkqoklmrqnljqynwokimoolmproovkkilgqonotnloioqqnstmskonfjirrlykmfoo]fnlmxhmmnloopqnprkjlmhbnxmpmonrlmnlqxmkpomqrsmsckrn[oqp`ponolppmmpoqosjlokmfjmtrnmojmnilymolnotn]pnlnmooZknrnhnmrmupln{mnljlrjopnmligspnvqwljlosnsmopmrqmib]msonlmtsgllhqrofobscsmoqtimlqnnporjollnpmqlkdssrosiqmmpohndoomoommrlpnnpqtojnlno^mjomurpkolmfssnlokrsqmmjotqlompinonjqnmnpoqmqnomllojlnnvqjkljifgmoqpklpnlmhkmukloppqimmojopkpshmplkmngpkrorprnnoqhobptooplntqlkkxmmltknjmlqtlhkkspjpmluomvmmkmjqmlmjlnmlinhlnirnlpmogsigkflrkmnwlmqpnolnvlmdiokjj}njqnmkkqmolntsmwjnnmniormolojplipomltqnlopjmlnpkknpprgeqpoomnqnqxpokoflmppkpkilmopphlnmsphnnnqnotnolncjmrnzjrjqjimylinnntlnuliplmlpnqprdnsnlqv]glprqnkpeoqq_mojqsmojltmlpqeoopxjtlnoepvjnmqhqkimmmnktfpqonnkk[qmpoqmlonpmjmsdlkonop^nfpjlokowtloukmmlxhnqjtnnlnsnmmmmnlmojpp~spqpolokrliosnmommrjnmxjeqljprpmkkjolkpyfqyqtnetnmnujslpmqqouqpowmnmm}tomokpdomjmlsihmtdtjnoicnqwobjmljtlqlsukfiqnonmomfmqlonnlqlrhrlpqnmjypfUnnnqmdlqqpjtnltoqp^okeqkkokhmqmnlcjpplnljqdrnoikntqmohpnslrbqlnjpqpluqslxgnmn_ospiofnopmoenmsjprqrdmodpjlpnruwmtqjrrlkrqvloodnivonkpppefjrmipmllqjonlonrmnfljssnmldkqnicphphniilomkowrkngqqropoponpknnvhkpqlxpm`lnsknjpnholonnqjlojprl_nwelokhncrsounmkmhnlnj]qnkklykloojtmwnrjoloi}kpxlgtmmnnl_nkhlnphuwkmll_pjmssmnnooqpnlq\upmnpnnrifpvroopgrwtblnrjp~qofpnnpqqnmsmqnqakppvmoohkjtopnrqnmnoqopdmmnyxrsnsnwloghbmlpngiojoroskomquinjmonlnbmpnkqnmptjonkfkclrplmnonolumnislumnkrsrpdnmmpnllnbpmomqlnqemriojljsuyxnonpqnpnijsznommmtlrnrlkmvrojwmokpknlmjkllnrngmkklmlgkhonulsnxnnsmpnppoopnqewmmnrmmktnkopaqnnunpjoqqqjmnZwnomqumnqmnpnkq`dlsmxknilnjnlmkpnokmtnpnnxjrkojdmovheqoumjjlhnlglpokoanmlrdnllbnmmimpnpmnmo]zjtoomilnpmnmj`nqvmrpoolg|nnjjnqjdnnrlmlnnmmjanraktjimnztmpqkqokbnupmplnpowkhlrmqlffpjr_noonnopmupkvuocimpllnlvqonnpynsknrmnnnkotlkptvnomrokkptpemqkmjphr`lnookdmmwsnpoh`mooolmmkmebvjvpcpntlkprfnloorlponoo\qgnlmmoloogvqqpmhokklrnotevnnqqdxmfyippmlkbnegnkomtmnpohimijhwlfpipufdjhmquoqmmokpkjqqlonproomigkogmplpxloloilpmwitmjksgmqjtjlkrltkhjhnoomjelhnoolpos{vjprhkmmmopivnlkmn_jlkknnkjlinulnsulhnuulonjnjmgnqjtohompohktlkcpjvomrqnlnlcoofrinopekoqoqkkrqmmmpxmfloqokqqfolpiqjmnnkimntngqiimohoqoroimwiinqmqljqlimimloeqjpmsmnlnnjomuhokpmuntysqjmgmdnlk|pmepmnoqllptmw]nt{lij]mkunjmlfjifqujlsopnormqnn|josbnlrmnlldqonkhmnlkjlnosrjqmqpokrjocqlmoptipkltujonnondrtpyppyn~onpjqnhp{nirzmqpmqsmkupqulyoakpwlqblqomlmjpmnmllmnnokm[woqmok`no`fnlqkfdfmpmqpnpl|puigjkooilpohnirpbnonknmogpsrmtmiqsqknonnknv}on|kitohnqkjnmnlopnnjktnpookgosulnpokpqz]omlrmyooos]rimnonbmnsppkfpmkuilqqmnpekljljennnlokmooopqpmksmhon]rgorpwjlkpjchlrjppgptrmnnqkoqlqkmnlssmkmlorohijrrlprlmqokykomqllongmsopknpolmkpnqsnmmlnpuqtnomoqmhnukejpvlijngsfnmklhflkxsmvmnondp`qkvnimrrhpknomniku|nklbonpojnsmsmmulmgpkpkfqjinhqtpkrotqjshriolkzpmulZgunocawmjsnmuehqpqhtnpmintghmqcnkoqikjldpnjkwsgfjtvnlrgqzevqnlhngmjqnnnmoxfnkhtnlmp|klihonqq|iqspthfeopicjjnpoqlnjmmhhqdmklmlkqmrronwuqlhgionkqnzejkqg\orhntjhnnbsnjornqnimjlglpoophmolrptplmpnppqoirkrisjdkoasfqltqcnnpgloulolpomokqoowklvkswnonxokmmnmn~qoojprhroppplrnwiknthomlnktmeknloroekomooqjwypodswklkojmnolpmnojng~mnnonlntiofpmamyn{qkumnmivjpfmkptkmnolkpmjrijkgVrnrlntlojosmjpqpkosomqnbhjirnsprot|omomdcpqnntqmeipoki~npmddptlnpojpmhnrnmlnnlqsqp{monpproseptloialpiolpnpokkmjpojtopmrsmlqoqnjlnpptknlfsokgkrlqkqmrokhqmxmpooowjpomkqoimonlbtfmnqrpkujmsmonklomkrtlompcnddpsmilpwmqgnkmkmnqupnommmjmojtrktlhkmkrponokjrasnwipnllqlpp|lpmjnoznqqoyjpopmiqkmljkslnrmmlolnnunjrixlnnmhjnjjlmomklmpooknmsjlnuhnfnlnqmpmkkljommrmumklqcpnkmnnqpnprenmoromhmsippcjquhrplknlmkfomonrllonbmnonnnolgpnnlomrolplcnnknkmmnkimpqeqflnwnqntpn{kmopmfnlpoqcmrpntkvgzmrmpmpptjn{mmrrmrok`sllolyopuomppenxhoropqokyppsojnpmmxnlzmqmrsnppmnponybhpqoqmkoslfmhmplommrnmwpmp{qlmnppomqrjntqlpnmolnlonlwrnmtp_mkmjngmspsnomnqmmfrlopqnmlnuspjxpptx^tmnnqmnorojyqjnnmklqopolopepmrbmnyrpmmpdnjrfnhomtopme`hnomlurjpqjppntnmpmlkwvmmorolorknmqompckqpsjlhiljki^kojsqqorrkomnjnnmflpminonllqnnmlnpkomookq_linzltnpvrcpnppvfnjnkqtlkpqugnomhrplxomnhmrnnhljndplpllmmoklknrsrlnkipmjlnpjnkojmlrkrmzmonlnnnquptkrmiijpZhqgmopnntnimlkooomlopkqmmmfnloorqpompnkqnomqjopponmrmm_rqlmovkqnospnmlqjnrolioipnonoowlpwknnoloemrinpgsvksoqmonkmmqrlorqovtltdomrnnoqmqoooqnmolnknnmjlftnlnlpnkhropoonumrjqkoguopriqzdkrepfonoootqpmlhnrolpmhkpnmtioskqplnvqknompsnkrlnmqmomhhimrnrnpzsoemumujqvkslnvqroohodsmlllorlhsnoqopplsifqmkpmjohjlXsloltonknoskhopnqqoomrolsp^jlglqoqwpnqqi{kmoqsnwvomlehleokuonoqliksiojnooihtqnzonjooulorxntrjilzplsqrnlpseomhrrnpunrrkmftomlljpqhlsrknmoniljkrpomnnlpk`kgjoo[nmnmoomkloqoklnkunkhmj|p]^oyounomrinimrnoqknmurftnelmiqkrmonnompxjxhbiqmhqmoljjjtmohsjoujjfnrap{hmsnerkimntpksugooqnqp`qmcmnomhvzokmxcqpnqnkxuopdxkdnalgtmmnqkmfke~hnplkenjirkimohajhqpl{nlqomopuonnrsolmprmrulrpjnqlopqlqpmmsnpelnonptVqnllloot\nnglgq]l{nnlqlknjopdlrmfqibniqrxmrqpohnlpqellopr_lkhonqonoljlhkconkoouq^liiljsumjwnpjjkerdmdmpmysokgdqnnovhlmmjkXkpqo`lmhiiprlgqtqljkmemndoblckro{moathlt`tmrUmlqmutqnzlllfilnrpompgnlpopnbidnqprjoolstViyZrkvlmsjslmmn_prsrrmpqkklpmmmfnopnbl|l_phfjqujmykll_lpgwmproqknklnngrmioolgulnkmmjrnooohqvphfrrppmlkilrxprqnvorlqromsleimiqipkornhoxjrmgoltakmsinpgmknljpqpplmgmonmp_jrkphlmskighfmmprnshlhpgfpqmlmktjkijnknllooqmknqtinnhpgqptprhsknprropmnnkqjwmonooqimpjmhtpnooplrqnoljnhloivnmlommnqqkqmomonjgmonymvuphiscqumapjk`ehmlof{olsmumzovunpuposrzth`kwgqppgvlmqkkkjl}kknnljgrfcqktguoltmrlromljzqvkjnnl`spspceo\ezuiflloomlonhilmopqworlrhmkm^npojlmlslsnhzomimtqgotfsip|nllkgonsppirotononjorgsqhnihqonmqpvgdimfnluqojojkuhwvlmtmn]lixkjrsuiujsnpqkiegqpotbrrtjrhIqaalksmlqokntjnm^nqkqsnlnotmnsznpopkoolminrchonon_pabqm`ovljonlhooqommnooomuppnlirncoirlqpmlnofnfh}tkkklWrqoomqmimsmpenqsjkqmplonnkplkspolqhicnntnsmjoojpmokroslrqwgpnqplntuuoxnln[ijpgonnhnijqlnmqntkoplpopmqljqhVol_qnropopjnimnmioenpmrnulonlsnnwvrnltponopkqpfgmmnrdmipsmnnumnlpppmjcnknpklcqmmnrpmmmrrk]nrhqhxvggmlnonrpppnkhjknpnnoqnjlmgdmrm~monmqnmiwlon{qlmrkjokosojnmtonvSkpwmmhmiklmocopjkosnmozrpoyonmmppokmolnnpnkpq~jmooposloo`uklpgngnmnnqqlongpnqollnqqoqqmdumnoippmklknnomkmopjonomnmnxbgqnjoppngisnntn]skjoroiijolvnqlkwmnn|njlyjopquoinjdqdnqhmmsklnomxmesnkrtzmgjimrnnmtnnbunjmpljohnolocmguhvhrnqoqpmqm_rtunnkmeoqnqimplriqsrlogpmjmicmnpnnejnlnlkooltmnmtkmnphkmlirnmiimvjkoouulcgiolkkmqoo_njknplt{ltpnqopqzpokmmonmirstenjpjncmpkplnlnmpmjimonrhj{omsslpzmxmnpqomnorvnhnsomvqqkq`pnulknlokmkuhonsqonnqklpololnrqmdpmgmwvsnpgmvnng{qnriglpolpljledludlqqdhoronponnmuo^snlqkomrmnjumrmpjtgoiolmopwdlmmkmbnlpmmphcyknlpjlttoolknklprsnmsmnmlnnnmtno}mrUpplqnwlmko`diismrnehmmcnnnmdtbjolsivrprrorlyolojriq}nlnk`pmrlonknohmpnsompnmnfmopomnmjrnkominwmonkjoilnmmn}kn{nmmlpqqflpusimrqymjjkuhkomlnmnsnnnoksonhpognnqrnrgpjblplmnpnobkko[norqjfklkmpnmqeoop{kgmppmrjomqmknhnjeqklmksonimjlrkj|lnlkmsqqmkhhmmksupnlrocjlho]ivotooplkxoitklnlqlqtpkjmsllrmtkplpokmklplonmpmsmnmmnpnkyqiqmlopginnimvtlunslomoooktnlnknnoqollolonnnhmmkwmwqropmkomoto[mkplwqt~nw~pljumjsoqneqcknnmolumczohanojpjocmlqnojokrmpkmhntklnrhrmsmtkotjnzomjkuoloqqodnlnployilodpnknmoeomnpmmtmnoqconlrlmwmuqjknimfmnihnnnljiljoopnqwwopwoqnmrl]jctomgmmmomtphpgopfliuoooioomjqmjmoorcosoo{olbjjmlmoopnnookeqnkyomllmrpjrionuwlionomkoqmmqqdqnpnqijvlkupuksnpnponlkrrnolpovpqloelljliwqplpsoo}pgqikmlqrspnlnnkmigskm~no^oneqhanqpbocinapqmvmcqniptmknrvlmommptqkluspnnqpqjnvmrhjslmpfikmlvmqpjndpmpnaemmymkpntridijxpljowjntpqolnpolmklmndmetnhmkpounnpmnohrojpummksiomolhukrqslxprrjkummgpoiprogjqmqnmyogokmjmkrnqsbrkpqoofmjmjmnqlpkmvmklnmminlrnqofrptkrkpsgmpfiknshwjmqbiloonmlrqhlmvlpnvpkfhpskylsqnsoojomjokkmpoqlolhqnrpmlkijjfojpioiimnmlqqnskmfqenojlmqrkplnksjmrnmprnmjnligsilysnjnomspnkppqvlsskmmmonokoqjelijoplmptlglsnlqixsrotlokjsponqnppnlnmogkllpomotplltgkpsqlloobliontjpnjklrmnmrmnpponlmrmlmmsevqklqkonolvqkmenkkunhmppjhhmojjqmpqlknphouvonotqnmnrnnpossmnlkmmknqnorpvimmmnmmklqqrokuujl|lmvnujfnstomhomnjjinloojpnnjqonljqopnrjooomqphnfnknqkrmlpmonbpplupupponsonmkyuqkvqpmlsnmtmollrulfrummkmosnukmnzmlmllkiqoploopppookprjoqlmlnmlnmjhlnorplnokmrwnjprojljojjlmqqllpqtkrutpsmlmmrqompnlmmnsvononnlmqmmlmllmnpjtmorqmmnnrmlknnpmqnolmntnoknmqiomnjmonkmognuomllmmqlmjmoqppsoqonoqmnppjswiqrqokmotmmmmrnqpolookkpnqjprmqprmoooyomoqiiosnumukpnkmglokhnmrunnm]kkplkpknhjpwrqqmnqnlmkuzofmllpjumulnymdnomtmnklbmloknpwmmxkmqkikchwlopnncl`qttmkmmfjmjnpnmnnllllhkjlsmhtjjmkohpl]mmohhdkmnoxnbjklmmolnlsqlmq^nmnopiashnhrmgkkghi`lnlloiosppkooqrnpcmlqhvteotm|nknuomoosmpllkmllqplvlqpjhmmoompkroupkiokhdnmnponajonmaloponpipmlintlooolqjpmnmlinjnntnk|onnowvpqlnjhltilknekgknokmnimtfoinildrmqlnopplnlfpbinolnvimlrfnmteqmidnnbnnomlqnqlsnmnofonmiollnonqnlmpeolnonnqjml]kmpoqnmhdno}orlozjonrinonfmlqptjkolsmounkrmnojjlxqnknmtnoknqqonoqnlkmnltyhsmmnklmjkdpqqqvoqoltnpelemvmelerolhfvqnlvkxqlnjnqpnllvlprnshogrlqnmoqknwikrsprjsljpsnlposnjqimojtpqpjcnmlljnlnxjnisfqlnmmersqnigdwopoqhqojpmjiqlpmrYmqknsmnqqsklluoonmnokmhijnjpilwopmokumjbsnkrnlptjmqqpknpohlokvqqroktpknfkcjmpnmlookmwoonimlmloo{lpfkmjpmlpkmksonompeppaqnmmqpngjdpjookjujjwskpsliilrkj`hilrmopktqpnqjmmnvjhnnfhlghrrptvoimnjnmjlnkgfmkjokukmpjniklppsjktfmoinlpppmmmjignhsykjlhjnjmjopllmlrprpxpmqjlmpnkqsfjmmilpktooesjnsnlmkkprqokpqqhqlkqnlasnshkomtnihlvjiofqmoksoonzpigprlrlplhwqkfspqljmakmpnkproml^klihrplmkklksmnvosollkskienkoitmkmVoojjoqpdysjoinpoukydnmpduolhwqoqanopnjmlgbqehlogmbnnioinfiimuhoqglnnplqkhmkgrkvrqllpxm`djmvbgmsurhopoplxj`klkimXhmSsipnhialllonlordklzpi_p^oWjtmpsxpmjomkrmrrikwn]qroclnmgmmrmqgjqfpklq{fmqrjpjstnpnrnnjp\gksorapoqpoqa_cqhooxltkon|rokoqnn{odlrsfelnjnrimgrNtninmololhounjntnkmjhielnnmrfljjkpporskholqmninpnnmulXjmjmlnjrppqnohjrqrojegxjtosiqtr`lpmoqjknnipojlwlnvlrqmpnoqoojpolqkmknrseopgipwhksotl{omjqiskklhlkkljllohrpnmmnsrqqokmnhpminlegomnipenlqkcrgevkpmnobmejnpmgmbnkopnpmfnikjkpkjgkrltpqkpnqmmmwlkkm|nnjqurqropiohppmnjiqoinklpnolqloknjlqldomnjcoqodptqinlqhmnkonmljpnlrorqnsesozwonmjpnngnbnmpjkmmtljnonooqjmmrnpt|okunk{ljqlounjjnopprxmopmtsanmnolonsnylkosoomnqopppjniunhnondphonmolihlnlllpngnolmmrkhghs|fnnoinvmnjrkopmskjpsnnnxblmmilhnqgedpopojppcl[nfonqnpvppmxoopknonllhkmglloillwqkmonooknoqqlmkmtmqbmmpnomgoqkfdnokrmqmnnl~prbljplpnxooynjnmpkosqzmkhlkwmlolmnllrnnkomm}nljoqonqkgoqmqjopktrwkn^ngmamojnlnqmtvnhojhnommokmnlmqlnjo}n{pxsokmkljnjnpmnbnmvlnnlxikqgnloalpmknqlknjpnjmpjmknfelpogneonascppmi`pqrkrqhjtjlqmlbqnwwqplqjmrmYmtolngpmpqrknkkjqnnsiknhikjrrmkirnmpkjgsmqknmlqicjjnnjpphpflpimtmrfpplmjrfhjhk{fnzjkrnirsmtmnpllcmnsvlhj~knqmejnljqhsqolqjiusxsournymvgkgppirommqfskrhpcimijhkrimfsmbnkoigrkmsjioirkiujnkmnonolmnncbsqapsmlyqnoriqk~skojkskognqnonqro^pmipp`sniuemnuqgqoprynsoqtroojlipnkpkiflhqmfrqwkl`ohrehloppvmjkxopfywninrlrjmlirvnoihgnokmqrpwypskenvspropthoummfulmloml`nmkpkjmgmjolnoqrumfpmtodpgsqllcmpoyfkfrqipamlnlpthpkmqsocnlsgvopoiqfn}iimijksooklmilmoynwrlpqqqkhlqmp{rtjmhqsnikrifkhlelnpnvikqilnsfmjxhksmmlpbrjouvksokoeqnnnsnjqin`rqknnkmjhjunnhkvlkiqkqwmqrlgqhnjroznlkjloolpkknmfmpn|igjrpkrikqsuo~n]ogjmplktnqmpojlglomorgrrwjinofupolqkuoktptmpmnsvghkljonlmqgixlgsmntmtqjfnomxmnlkhjlgcvmknnsqp\pnloeporfmqlhxnshjcsoskndqnopcldpmhjltqoplmr^oin`soepffkqmsqkrllpgqknnrrqomsqoqqqmlhnmkoxnlnromhnnlpnmllnpeqolnj_sc[nilmjmhnfiermrm~mpqjnmipp}nvlgltpwohponpl\orjtspnpnjnnoslolkpgjkunlypnorqnmlpsoconnnnmovqmofmlljmlekmormuirnpc|ommqnnnymohnhonotkilnnfrtjmujmqnicnlqnopkjqorlYjolonmnrtpqolpnuhlonnpgewkjvoonplqiomsnlhncmZlrznhmonmgjlncykomqgsufqnnknglkrjtnkfhqppllpuninmtojgpqojrllmkqrmi_dqljlnzqppmsnrvrhprjplplljrqpgpqioqkjseehhvmmjok^lrnnqrsjipm\motpsjjgrosrmulpqpnnmjmounnjiggpdmplpmlglvnmmqokkljwmlqbpiilq{mjphejnpmfpfuormsiqoonqli\klnloopoglrsmnqpkjsdlpnisopjorjokoqhmxmjlykgvqnsqnhkkeqippp_nliromlqprjjenopfqrkhoonpiogrjopjphouqmnommnqvoolmochsnogsruznkgklppwtnrumnlnitmsmriitk|ekkkhj_ijmnmnmjmmoqeprltkoindjonlmmjnmmsmlglmbmhpqtrjnojgntrspojonlnmfqjen_qlimjzpmujoiooosgkujjkpnlpmonljlifkjumk~mikmarrhqkmmfifkolioumjkhpokkqnmdprlklzyqglvnpowplmhjqnpsnknwhmdorlqorommresolrrroqmlrsmplunqmgnmnlvnmommpqmrin`unbrqmqjoppmppu{ooilpmigmoponmoirposxnlYmmwnjfmpmfnhollkonpptqnhlfpcrmrjookqntmnmhpklnpqoodjobhmojocmfjmjljkskllsqqqmqxmlfnukmgogkoqjnmmnrqtmkopplkemmovpnopsocppunpmsptqonmqmjljdlljninmogvemrlnlqkkdrmnejqknkrllilmoivolikpontoqjrpjqdopnojmligolmkmqsmj~omggtq{rnmqhkpmqmqpokmtrrnjnqotpgrohdtjfgpjnoorokkxmtmnnmllgyemmflqmfominimwlupmnmijilmsnlsesm^slmptllrfpoomnnvjsmolptemkjrnqkpmlscgkmdmlminlqqmknmisowsjnkvnrnupllnwjprrlpjcmmn_nnwrmrfqkfsnkuq{flnqplhpnknonlovnqoiljsnpjslkikhmfiviqntnvqqlronolqglninmnlqmjfhp{gmkmtlhkmqmpnpfhnln_upiihnpgsrmmh]upnfpiqlmnqjtkkkegpljnhlpkoqplkikroskpoplnospljnojujoijhnemgnpfkqgmmnonlvqpgkahjlnlnptosotoinpbqesnpxoknumjhpoenumvqokmocmhmhtkiviskjpnlfmhqumhqlojgn_tiourskiposs}omnsmloqnlsnhlkknqqmkhgkqxckewnc}egrkksnhmrknnomhihluhnkqjmofhjjguknmocdgtljiqcnxtixnqfqoplktwrnmwunhnomzpqunlqnnmskgmipknlushvowumjpzoujnquslikhyclrkdmZmsshnrnwlywqognletdhkrrke~pninhrpmgnkgjogmititlmmoinsiqsqlvlvojihlqplktklkhjwpzsuofqlookpjknwppomnoj|nnnmmjnirgvlqnohn}nqsummohmtuloullppnrnnlobmmsorkqpqlgunsqqorqjomhmlrbjwloqvlnoqjxmupkooquonrkgrmnnotnnppovrpomerlpsrkpntpnnnwjgiqxzopnwspysmjlsljlplnnlhs{noneqilnnsonklpqkpuopommnnktmkkmsooknmkmmqfiknqnirjkrpmuptthxqlooqmoruspkjmhlntspimtoktrnhtkokmymimimekhpsrmkqrtpoloonoplhhrmfpqmijtmrnsjeokrkgfmkpgnpmmhmpmrollmgprmpfnwienkpjrmionkrmmplqt]nojmlhohmsomnqltplqqsphomromlplnnnfknkmunrjkngp}oeiooolhqunhiqcprekqtppjsdlogfpjlmshsrgnlpjtpjpmlnplhnffllnrqrkmeiopnmkmpqknokrutwommnjntqlmmqpurpshoolhrprlxpnshohonjnlprmmopospjjpmlwrkkzplimpsgoiilqelpfnnnqnppmlislnmnjovvklohklfkronokimokoohhgwwplvkmuhfgnqrlopudptmrgnnsmnmcmkjnsrlmgoushinklmpokgglonioiihplnqlmjnitqquunqvuikrjigjljfnnwkmlqtuoqlmjhlvprwnksfkppqlljjnpikrlroqqpcilkbojrqpnilpppflmokpxnkoglp^zkmnqdrkoufrjktosornnsxlwk{pomiqpng`kqpsmwqrmlloimkogpurmgq`mjslkoqfieqesoeokjmnmoeolgWm`gvpmgrknirkhsyopoknmsiwidlwelsnlonkllklrgmgigsoqpkohjcpenn`ipcoflpnpnksgnrckoqmlhmsmrlonollmkfnhqmqrrhykhqigjjkqoallkpqvrsnalklshitmm`rqprlir^mkionohqrpocnqnsqlpincolkjmnolekjhwgnolqlsqqqlqmpnnjtjplojikooonnglirliqhyrmjoosmpuoqpnkonnnpgphnjmnpopjollomfzlntlpr{qfrmlemsjlgogmoikmzfupkrvmqnkqsoqpnjkmunllmmoplrmpomnnjrofliu}holripkj|ktpmmijegpiomng~ovgmotosfrmokomtjipnrmXqlocvoljnipkpinnjnkplqnloollnrliuloqnpqilkmmmnlvmxmwerjlmqqlnijhvqktmcvlsnljhqhung`hlkeulpts{mc^gvjqvrqgrfkhociyopkjrkrndoklhrrpnepszswodk|ipq|qrsqo{fmqrrcvosimoqskoo}mplprniqunjsnmeumkmokihonhlijmmlp`pknwjpioghnkvpiqnmlppjkmslulnojvkinntlurcllookoKqjeurqnoootjgoupxgomtoooeldoprwoqdpsujrinuexkkkkwmwkypqznnmopnelofonpxkqvdwpnlknnspmdulwruzhjmqplrfqslqrpsjrjlsksvmlloqsknqgoepoionqpmllumnplndksshpypenjtvrkjmm]vjvoj|q}hnkriinqjojmnopmopjmoktmmmmvnkluvoriqfomjltuflitmtjonpkmmoonqtjofmnknjppmnsltwhnnmumVqnljjtoqjnhtngooskgwnoshrnpqvhlnnuoptqhoopomikkpqohmsoatrmookbqmnimkprnlnkqnkloeqnq}njnoomonlmmksqmrsprp`dotXoinbnfpisnzjsmpnoomoonskr`kof`wlmpkmplloWkrpkkkm}ormqrlngvnji{rkvoplkiunklmmtnokjopmhirnsmrnunlknloompnukmstpnmoknlnvmypnanknoqmknpgpskn_rqooimnofhqpqeooivnoldrninnmojnonkrmoonlqqxpoooynp_jmqpkohrpjncnmwpcqiqgtnndthkkoqnhl`pkltlroqrsqqurcjopynojtokqmnopmhoknipkvpxoptknpkslnmophpplpmnmlnjpriomsimmisphuipqpnninrnlr\mukllrqqkpnnphqomortrjoqnjommpnnthlrolknlnlrupkhiplqlonllmpjlphholnjqoqlnqohmpglnmosqkoqtopqpmplljjqwlomlomkkknoxoqqpppnlknkoikppjmmnpmlxmspohnnqlXwnmmwksrknsnqnpkppsnnrlnomooroqokooPmluqpvmkZlyiovnkompnqniktooolnnnmk]liiotl_hmjplnon]mgogmnpikxnnonnpmqlnqpuqggmploolnppwnspoqnmqhkmlnkqhnilnnonmlnlsmklofmnpommnmonrlpomelqqpponqfoloxonlnwmomenkpmomoiwkljirlnqlppininlplljnnnpxvolnn|mlfllonqoonuncnjwuolvprsqplllrmfnntbdqlnqomjqvxpnooqmrljlrgqlkrkjolkjpnbwnmlmbnocuhjnlolgmnulpnaqmonjjvieqsqmrcgmnjkqymnnxbsmgdonsuofumjglsnmwqnmqnmleekmmjnmhhmrnrmprboofahjnmkqoounhlkdppsipqognnoommrpmombsinklmnmtkxkqljuqzmljmkasoqmvobqmsobkrmpnmrqlpthnhijmoqnottrgpmlkoqpgysnnogoompnorqonnjlmnrpqnppolnkqonqjcpjnldptdpksnrpelkkppm}okolpumoimktmsummhobooonmmiincl|ulhnqZprqnqklkqipl}ooZnpdmqronrbnnikgplqxyZmmlodkolnipkolrjjimnkrnlptnpktookgoioumpo}mnjrrdloumpmns|mlrlppnfsuopckhglokppzofonnphlmolim`ilspupmnnhmnmokeyrmqpquknlm^pnmpymoqsnnrlmmnnftnotolhmomolksoomqmlfrpuojwqumnqknprannijlmonnpm|npnoocoq\q_qdnllpoplglmplnqoppmknlkngqqoprlqgosgmpmmnoqpojqsmmmskvppkqrpgmnhonmmoqrnnpkmqomningfemfooplzhntprmknrwmptgrmpjrnpoooookhkpniqphnklnoolbpkmmolprnnnolpqnentnnhutqqooumqslcrohodovnqfllovjmjkmonhoopoxpnoloqjktrfpfmqrismlyihonenhnkfsqqvqtpotqolqicqlqonlnqhqqkqutljrqmnfugkplkilrhlsojoiftkmolspjmpirrikhmnqnpiunkrhlljmprnkqjmonlp|pnmfuhrqkklostpnqklmamprklippjpjpkmpjrkbpnhmpvnqxqmsmllgjthdoxsnpssotpmfppnmojtkmejonppnqnjufmmsmlonkpkvxqgqkpsqrgpsojliojqroerrnmvemmpnmlolglojhkkpemjnmvrixoploosowlommplqtolkkppqnnjlmjslqemylegfrxrjpqmtmdlieommqmmltomskksqtnnr|qpoqpgm|hoiqlilnhnsulpoknngouspphlllkqskirmnplkknrmkmmlmkuhmvefkqlvvmqklbtihmmhtpsomiphnmsjhriqpmlpjkniseknksjnmkfmlmplgkjsnqpgvgmen\osllhsosfvlssjncprnjpjmjmqmohohjijmninsonmgnesthhkiplekohkepokojrjgakqjmkjqr[hspnjowfzpgretlitkltljhlsxfrolmgttfkndpboeomgelvomgpqhdihnsqlknmtiospmfnqjljdomqknthttpjskolhmqinnlmjjnktnlomiinlhmimhoipviktgojhglmlqqjikijlmmlqqtnnimjnlmyoqnektli`mrnmp}oeorsmh\ronhgjtlgprjjnoghhklprpnpdpt_qvopprmgpthlqkqnqygnimmslpqcsonmtkqnlenjthsrlqqxmonnmojl[lxrqjloqipuyrotohrmquljljurqopnskoptfnshr`omikkiknrnriplrngidemftblssxkgiwpbg~vntjglsoloqpblpmolpmmoqnnwxlomojliamlnrkoonmqujlbjlsslnjrljopnekocskmonuiiluoa{mlotqoipiojrdojqoyin^slqiiqnoibfllpmoqnpgmoqitnjnsksilvmjjorfoidrsvqoooinrrplmqtjknlnrospqornoormwqnmmqlmnkqn^glmohdiqjjkoqroiilropgojpsrnqmcnlrpmosmromjojsogommnapnoqldrlkntuusioopinmjoirqqpomntjlopnsjhrmpoyqmslokhjgokmujjlwpjqtolkkkgmlorkllglkfkhogmjpprppqkihoppopmjvlllbtomdtfnhinmnf_rhjqpkovnstqkoslrmlmjkl{erqqgrmkjmeiomoobonqjjnlZnjojpnmrjjmjjpfotmgnjrmhmfookgjniumq[thnlmnvjmovitncprmouormljknmqlmksononlkklmqgigpslimnppsjrvpdjoiqinyqlphqnqkmqkqmflkopjpjsroqeotjpnlimimmpjqmrqkrdnkknqmemkpjilmgomplhmvlofoplipllhklninppdknnmkljpzojlikmolqrnmsfnuoonkhonsnmpjnjpmkjsipnjkvkpnnkfjmvmnnonmnltodnpnkplsmwnqnnlnlijzsplmlrmdknkprtoiglqifnkbpojmqqnonknknpqmnodnnpmnnjjsonymoonnimpqrljlnonojiqmollqimfmflupnsloroplslrojalotlmloshklrcpmsnkzlknopnolptnpnlmmcnpmiqowoopopnonjcpmunmpskqolqmnrnvknmunomiknoqlhmnffnyommrpoqollklnnlommffqo}pantnppoioislpmqpooonommmprlufnmnlpnoqnnksxmmleptlonkmlpjoppmzqtkrnentiornjmqmqnnmn}^qjndqmojnlpoknrqjslonp]mkqqmnrmlokjotnuqiolmmppfjlvaumrjmsoqnonlolixjr`pmooounmmnposlpmnkbplpgvdpnijsnndlrqnpkWpjwinrvzmmrodlum|mpcpmnksasimqlkknozplmjmkpmwsuljkghxpmvog~kjnmmuoomnrjplmdlcppofkrovmnkpposqZhqmqeosmrlvs}huqcttsomytpmkg~qrnpoxaogtgnojloqnqopoinxppqkrxllphp]duponblkgfyjnoslJsoikrprfogcmjfphfrmnomnjk}rUhldlpjtkohmjRqdifkm]qnkrqpfqrrkqzommmvlgpquxmlpmnnwkfrkolopmpxhnnhhogvnqnlnljoknpmvmluqm{xgvm`npmpqqlmpoeonooqoomnpjmmlnplmlnknnmpnmoimmmnikmfjmtrmlojijpmqpwlpjmkqlmowhnjmmmljrmpnZgllntnlkljmqnnnqlooojpllkppmikjostmonnkotlmqrppsnokolokolfnnl{mpnolooonrvhurqolnulpkqpzjglompqntnkfmoknkoqjokqknpnmlnoqolntlymjncpogmkuigoshim|q|mmo~inmqploqtimmrqkyrtcmjmipoknpqnhlmdgslxprkjlnp]ljsmgshqlnrokqpjpsmfjlpflcrmwkhninotlkqnmhshllpljsppfjommmjqqklrgrjomsqmifnmmkmkmndplmmopnmnmoqlwppmnnjnjpghqmmfnpnlonjinlerrpmrplpnmlhmskqcsomipioooqtqokfmnnntknkopkmnnpjmmkqookijjpovnimkvpforomnqlkuempspmilrmlrjkhopimpiomnmqldkopoqoommskxnpnokolpmnjkorjlhppnpnljthnwsprpohqmomnooknhqcmmmkkfqtoqqnpjsipscnnkpopmmmnppqlunnmkpnqdqnopmqmemqqmnpppklpkrnommqsnjfhlomktknunnqhwoknplnkwqmoohlnoxlnlnposlk{qnolkmqmqnslolmonnrrpmdjkklrlbmnpp_npnlnsomlpokilapltollpmjppspkimkdkrjkozpivquppfompojqqptulvcrqwmrjrnqnpeljpknslooomrrpmqoikcnjzropofzomkkfrvkdmlshmmjmjhoqkiohwnsnqgmoqmkfvsollmkrpnookpprprolmqppnotmrzdmfkvkoouqdoomnsijrprkotrujkqpn\kv{jostmjlunlxkimoksnrkllqlprqkjojoqoeqolmnqllrppmipqkwqnnooirrlgoppsmhjpmmgomilkhipk_qrqdqrneshuieglglirpokyighlmiheogjkmfoibqqnqnhlimoikinompkmnmkknpk{nlslitxmglurrqxkmmiqknmof{srnipzrjlnn~lutmirmyhrmpjmoqmnrlp`qulYrowvjhlkfjrkzlrnmpppenmlhqsqolnooqjqirsvjfomil|m[qq^litmonkko\kclljocjiyploqtjqxhwhmqljqlkseunlrpkqyt|shmogpkkimfnfk{xqpkzlloktkvovmsknzywmqoqlqkqa{oinkdnshljpmlrjxkpptrnmqgooopkqtonmsr}omutsrtgohqmhsxlinmwr{kmnjppXkylmnnoqsopznionhlohylmmmgomsponr}hovpppjlutkgmkmjiopkolnumnnmkqoimgpm|mmsllrq|oolppvjjstloskkknphslwmqottrsqllpolptoqgoilrjnpnssmkjpnokmjujmjqktmolq^njknkqrmrkhqdkomqnhkvthmoqorrmqgikqhlmmmmjhmqmnsnnqimymjnjrkokhlnuhbspkxltrmyploqqtjwpfilqpmrpkhmljnmkhnijjqrlgtpjromhnnnkmolnlpnfovonvmmnddprpoimqngnnlnrpmtoolktoknmloqlmrmnnfpnmmovmhncllknpmpojoomgmqmonvonotnllozmrjmkkonppkmiimplurlnmqkjmlkjptqqsmpmofpmproookZoqpppnqpnqjmukjhmlllohkmnnpynumkmnotodpinwoosdgpejoonmmmmcnwcn|_qosrlmonjomkmlesirpmin\nonpoooknmmnYotgmqflynnqroprgrsplnumhroinpkankemnplplvmlqoflponmoyrwo~kopnhfsnkrmrhjfinspopnronmmqqoollgonlqinnllppojpomlqknopmqpnennajhkonktqnqnpqkoowrhmmon\mlpnnmsoljpmonkqojhposcm}olmpomnknjuykzmjkrxajqkljnhnpmsknxpfkmoimnonb`jgfjnklzolpmlotvnkyonkpfnionmiilhunmjlqj`lprlobnmpgqqnjmlnql`ijohphijnjvnnonml{kklj_kknrmmkkto|omomzl{qvkmmtejotmnkmfroqppnmkologjpmplomspomosmonpmikiopo|ihksqnhqprhomotmguoomvkrqlnptiriojmlmikommnpooglonkhpnnklmjpkqpmqmmkmrnpnospanlpulooinnmlymnmpmoumjnktmnonjsmpmqpnjrlrmsunnmnmomnmkpmjpommhppdnkumnoloqnppqopoooknlomhpjpppnmqmhjnlnlmnyonlilqjonppmoemjqvpmmnknuokjrfkqmmplnkopjnprrkkqqphrnjnngptnpoomnmkoonbggjqhllmnnntojnmpmnmkliojjmmnpoqhpnmnlqrimpcinprqmknqsninoqqxmlgjspnvqsihoiondknllnqoblmpojrnnsmfjmrmrnqmhtlpnshkpqjsqmpuokqjsojoodtgjplisogmksonololtgniohgkhkjmrpwnsineqpsrohnfklnjonmmppltkqqmljgmsqnlmslsmojjqknpqmkppmkopwjhsimhtoryknnjkfonprhopnphljismorqslkmopqphoqorsnlknrjolmlsnmoumqnxmqqlqomppooplmmmlmsnoqmqpmonkooopvprgltoph[mlslnkvuponopmoonohikmlnopnlnmsjpomhnhrolqvsonfmoitnnkllpnmtlfnlmlkkntkpushksojomipfonrnmpejvmphkipclljqoqakolnnjkoqmmmtmopxvqnpromirkllnnjnplmnnnnrllqprhspqkmlorlrkpmnrpplmngqjmkgmkjvnpmojolkqqqhonngpklskpnskxzpobrnsmskokrinqonqolqmsnsusmjphipmjmnmhqnUrctnlsqo|oxnrupnjvhnmipnpntmmopporqjpnmknlp^rhlmmkpsfdfrlmenlphqoomqqqorosmmmpohqnimjjqlnnohpjidisstnnsaohphqfntuhrqomjpnopspqupjpuinnumfmp`jopnqnqkfpkausnxssslmrslnmmmzifemoovtquktosngmjnnnmsknkmknoppnq}kkoqljlmoxnrlkirmjptqnipnpmwkmjkjdgjfoysgjggqklnlzoe{kjmlnlmwmghglmidmorrlokorrlmorikmljlmkemnrkqokcmjljmkiqkpimjprnlptmgmnp|sjmgnhkripjjqrmgmnloolksrmhnkozkrqrliktpriooqkkprloopigtqtqmvjkoqpilpromhompjsmninclflflxionokmoomfiwkpnmrnqtoliimomkiqlklolqmmntnumynknksqnamnovonrhpihpomplrnihmejimhmmmprmkgopjrnilmmmopjwkvpliooqmsrkhkqswllmkwpmunqmvnimdhpjkmmfpkmuggqtlofnonjsmaqkpifmnpznsqiprmpjfrlwntlsomrkqkkmppfqrjivmfmo|ofomnmmwnitjippkoplngklpmt`mnknrphljglgrkonlemdrikjrrmpnkneminnjnkklkntnlqnlmnfjnoknkmklokojnlmpnonmprppnkmsikjqlkomznojpqnopsqqomvnnolqkpipnmhnip|morknndgrlrppnq{mjprtlpnwsjqkmqppmhrlljnlmqksprjnnokhnqptksmhonulcholosntooqpnmwnkonjqmmipvmokpkpnnmmpynqnmmsfnklrqpqpkoqhrsmlpfnnmboosrivmoionllmiumnttmpnmgnqnqtmnpmmpoonlnvnknjklenqjkqkmnmlgonmpmvqvpvqjulnpsnsjkqspluwosjmnhnloqnjpnqklkjnqnlhriipjlqemmulknjsoooluologjnhlktjqotqpnqymjmlniiqlfmilm}nqplmgqopgznnqskoekpmsrohimsponkshqrgjmmniomrvnljnnmjqykapnnrnpoqo|knrpnnudkiupqoonioqlnplimnkoonoqsqmktivponopqnpgqjqppnlmpmmspkioppsvknlpoqmqnpqolioqongsnlnqnpomloroppcknonkorpppnokinlpnnmmljnnonklklokmphooxojponnmimmmqlolrnpkomppsrppqq{hnjmoqoqdnhotqppmoimonmopprnpmkkooqjjlnpnlpoonpjonnlmtuqonnmrlmnlmkmoqqnlooqiulppoqlqqhoympfornkpskonruaonenlslzmmqolllmlpnouvorvoomonjmgmrnmomnkpppjngnnslqmojmoomrkoonlnvrouknlhlonqompmnnklonhorponnonnhmoprqpomlkugmqlqllsivosmompnoqqpneqnmmptpnknrmnsnopproprlmopmmniqepmnqrspiolnlqnmknlmtoeooonlolpmloqqkooqspooknkrrrurmoponrmqrnqmhoqnpenkfjhnkpmlprhvkqnllvmjnmbpnjktroptmoqnrmoncoqosrpnnqlmgklponpognmnpnlomplmmnqsholkomsqlsrmpngslpnstjnrqilmprmurnnmrpmonpnprowpqlnlnojslsnrpqqfpmnoqnmoxoyoookposqsiljprsqqomnqpommmgonmqzdmotrdshjsnlonispjjmimplmsqjnlomiimnmkmjskrpogpknlillmnmiqqmokmiqogqnljlinmrqrqmnoipnrnimjnnloklsljmmrqkofmsrmhqmoosompqvomomrqwopjmnpomnkopallngqknopjnmokoqqtqjqwriqlszxjlpniprpkmnywuknkhhloooglto~qxolnlsp}srekxTlqdregppnnulpsnoqqfjumqkrtjkitomrtlqvjppnnglrkseytqprhqkojlqnsrsnrpounqplfflposgkorpprsplnoomcnrlqjttsiglhlilllrtspoqopnrmlgqesjjqiiktjksmssqrkoonpnjgvonclynkpikoronqkmokrmnnoprhqonpkspoqirrnmsoipqjponqjwkjlonoqmrlmloigoqmolopjbklnnknpnpllokmnlnmupnlponolmjmnonumlptxnjpkomqoopmmhxmnsjaxpnllnomkrkmjhjwllomljpmpmrpokmnjmkjcqouotjnnoqmqpiijkskrihlrlqhnolqoopunojgpnwnkmtvikomllropoo}xntmmnnomipq{kmomlslrhnmpoikwmppnptmlvlqkonokqokqqkpmomimjmpolmpoqrqoslrnoqromlqgnolpoiqsprirponmlirocpnnuprnpnnophoonkjrpxoqlmkqnisqmornmrppngukkopqmmjnohomplelktgqqkjifooplptnmololnorifngilrlilkdpprlkiqpmmpstnqgjqcojlnonoesnhlppnkntpoqomprmrmnoejhoxnnrqzromfopiumopqpkmppixmnnoolhlnflohnrmmklpljnnooooqpplrnofimgokmknngskknnrlijoskjjvn_npggvnsrilgbfpsetdotoqoshhksmjoqoqtqutkhkmpmqnnrlmpprolnlkrphsikpejjljnirmsr{kokomkopcogpnownnmpbmqkjntoishoqjrnkipptkhkltatlqpljjjrolkm^ontjopjllrsmgqtkmtupmlrimjgmnlpom{llgrmclgmnpprsohloeplprpepqenpqospjnqlglqjkpppnokwmvotqlqoiolljjplnkjholmngprjphpjtupgmgqkmqjnoonmnkojqklklmngnoronilkoortmpkhlnrqmoovqoikqnnlilkplkjmipponmqlnotonopanmollnsomplsnmonnpujjhopkpmlqjnoihkopnnijmnjprkonpokpnonnplnojsjlnptoiiknulplomhnrlnqnornnkenoknmmljpmsokmqikqmmjgcpzinxmprrmrkpqojmnphnojlhnnklmnrhppkrnqolphnplmnnnqllnmoknjmlpollkpplnnoooqosoklnnqjnqnkmopllnnorpkemnlrngjqhmpmmnmntrmhlplnnmkouojlmkgpnhnopqnmmnonqqqtqlnqkpjomnnopkmnispkrrlrlmmgopnpnqhmkokn{rnqnlnlnglsimopollomsmwfnnnmonnskninpgmjmmnnqnooinopmjmnrslmprosmlmmmssyrpiknomnmopnoopopotqomsltlnnmpnplpgmnqmkskmjkmmnpnpirpolfnlmqlnoolmtopnmninnimimommmponrumjiopjl^oppokommmkusmvphklnjmkmorjpnlqlpggtnlmsntkljnjnomlmkliponqlqsomljokqnmhpmomopvnhomunlphkmlmopmmqmsppnmmprjqnoklnnlqoplqppmmjmlriyqpnooqtsrovlmmhjrnozpmiknnhmbhnnnkpmonrpsmgnllmqvonnkugmorlrlmnpsjnkp{nkhqulnoenlmroilsqjkkjhnqnulsrsmmzsokorjmkpopnenqpkspnopyinrmomhlqnokovjstpnfkrlpfommsnsouksopnnkmmpnoolmogttmmisnrjromrpunmygrqklomilojqjlrpmlwlopnsokljnntopmipimkmljmlnliooviqnvkmpnolsnknnqophdrptqkpulqotnrkpkmtrpnkomqlnnorrhnjnnqnojmmosrpkqnnopqpsjopmpnmnqgsnqkeikkpnxklnuhqonollotllmnnnpqqpimjnttlnoyjtqqirkspnovnlllnnklporojlnpmklknvglmlkktuklknpjlmmlrqkkonhpoqxpltmmpmmiomnnrqqvnenopvspkjkojpnrrqknokmvloirsinkmmntmpnqlqrwujpholnpjnpjlrmmrllkjolntmninnrkoqoiomqgmjkpqglnulqmnpjljmlgmmhmomomfmplnipoqmkkmqqoimmqrvooxeplkmdppukpnomoohjtjqnnljhmospjvmykuoimjntulkiopjloflmlpmijnolkqgmknjmmnlkmhjrlphlumjqxmoiustpmimqjuosniemjkopmoprmlqvnkllo^nrpnnumfmssgmqsqqmlrlfmspmmovjjkmkjqioipkronpmp{lnmmjppimgqmqrpsrkvolnqlgrnbrqjinmjlnpljivrrqopqoptpmkkrqknojgophonmnmmnmolmsoppooimoozinonfmllbkopprpmommjnskkfqlnnoklmonhnioomnmpfonvnrpklojminrrnqmminopmjtlmonoqgmpqoomnloogrcmomoqtpoolonnpqnmnujnirmqnolmpoilnmmqommdquilrmnnhmnhpnmomplsmpfmlqpnpstkmnkplpmjprjspoklonnqgopplpmmnmrljnonnqobmononmmlnmkmknnqnqrklmryrlpmnsjmrqnnonmftposqlklqkomnqhkklinhwonkqhxmorlmlmerohnqmliknnnlqrmmmjnrlovkpnmmpkkqokuqikqkkomlrntnkksmmqrnmnmlmkgqmspnmosijlnlmooompdrqmlunorossqmkqlolqmunnprooplnnmkonmonnumoqsoolmkkokkplonmsohlnjtmskrmflmjkmjjotnoonnqnholnknoolpirkqhmmmnqoqjprmklpqmokmolrkpmlipvlmorklqmmoqpnqmpnqpqpnupnkmnlmmqlcnmomkmljotpnmokumluomrrkmrqpbnhgxqgmpot`ooksqmpnmooniilopksumwqpijomikdrtinkppgugmpljhrimlrilgomohotitolijkswjnonogoimoopljtlqoionjobidmfkkoiqmmosqknkmtmknljlpimlkrqpmloonlmrjojiooopqomzgjmijnofqmjsqvonkolorgklmkmgpnnmnooelsljiokoknoljwqorjmmopukkoqdpknlgqonmlnrkvpkknnhpmmjkgosimfror~qsrnnmnoprfoktknnossrnnopjopkskkngsnmmqkinovsurjstjnpinfuomhpmmqkokhioqnngnmnlpuipgnpprn`ljorntsnoknqwkrmcmsplilqlrjllplknsllnqnrnolulqlnnmkodkmomnppqiqjpvkjqnhhrpnmnpqioinmjoxnomorlmpopmrmsjru{nlokkqpsoprnZmspkrmjommhlpnopkpsvskjnnnkklolpjpunmhmkqimppmmqupkmlspnqljmmnmoqnodlmnompjnhprklopkinomtunqpmooohsnmmmrnmoronspprnoopmklrliommolljomppmmdmrqqmmqnpoonhplpjpplmkpinkopksknnpoqklsnqplptonkrnrommmnqriqqkmkpokmrqkjnlknlkopnqrirmrqnnottqxoqnvmqnnpolmpqnmjlnrtmiqnolonpvgmspnnnprnklvooolrnsnllonpmompigkonkpoixqrdomlonmmnknfpknpnklolksbnnkslhkwpupmlooqrljpqnjqkpmmnpqloilkmr~lsimsklnmplmloukprpjoporjnomonpnolomlppoqppk^doqnpjniofpkjnsolhjnnnonsufllmjorpilmpjlkrloimkllskopklqnjpcpiomnlnjqpmhnjprqmnllknoipnmnqooljlqpljoskomnnnnornmnhonvpvomngjnmnlnrmnpknphmmtmmkmjoonnmoptmrjkimnqtomojnpnorlpnkmhfounkoqnnkqovjkwponkookqoqmlqhroqnnpwppllshmlqoolmnokqmononmoolonnmmkqmmonpmmkdummnlpnmpmnqhhroirkpomnmoomlqykprpmnnqimormglpimiqmgmnrmnrpsmlnnnoqkpnplnjooknmlmglsnnlorkqgmjoltmijmlkshoptqjvojpfilnpqlllqoqpfnkrkttkgposkusllmshnrqnskonjnonlmoktmimolonrmnuomjnmorllnlpspnxlrkknwpqjrtppoqmntotjnnpklmljojupgmitnjlolqonlmprklupkjfonlglkppiikvmmrllnnmmklnnglkklokojpimtlnqspsimlflowlntmpprqmjmkwiqknrmttlnnpqfinluomxnrnokmnilpnpknmpjmoow`rnolopqn\tjooillojmrlnqplppqquslellupkltorucpqphejpqjmrlnkmqposokoqnpmomgipknmlmpklnqqkpslkttkoqkmmncijpmnktlljsplmvlnjkonpksimrcpjraiptrhmonlmimqjnhmilljdjsojmsr~tpnpokiokmptlphtrnkcokrloipkjmionoinuonutkskrfscmlrnksnmgjhsnhirplnfnfkmopfhplpkjmplpjo^jahummninjsmomoqrplnmpmpoopnnvrognoliqkplonrnpiipmpiimkcmkmvnomplomvkklknnonnphomjtopljlonnpmlqponnvonqipnljpoompilsmnnompqsklkooofklnkmlllumvpnppqmvplnnqoklkourqqompmonlwlnompsonmrjovlnjolkksorolmneoliilopkrqnljqrnmoplmmklmomqompmnmnlmrkmlllpnplippnmoppslhqmnkpqlsl~molqdlpgopnkuprmmlljjgnliljtolmrqjsfikohnwcqmkililnlrnnp}kkmojnomrooqqrgtqmnolmehohknkkrrnjmljllrmiiolqpklggrlmrsouqnrlojnpfrmkoqihimnnoinskjqnrvpplerjqkntqogtgmnqvoojqupluqmnionlimonmnlmiqlovllloiniknijmoonsnlipmjntjnpspoqmrjhqnprtnrqtooomnptkooxlm[innnjhplrvpnlmopksiknlnmpipkolmkkljopsknknikqpnpfnpqktnniqnsnplpmmhhnqpnlkopmqloioollrtmlpnmmplqmhhlqsfjumnllpplbooiipmrplomrmmvkooonroonionlonkpemprmqonplrknnmomhonqnrpvmknjlqnpqnm{lommohlkhjkllogsqirnmrkrlrspnkoolqmlmtogpnskispnlilrlphmnllhoknonprlpkip_rooonm_ijtkqmkqqovperlolnoqmqnplotqmtnkqvhomyngkimpnmsvnomqktmnuosllckuoqoplrslnrolhrllglmpnuhljtjjimqcoocqomnnjkzpjqpllpkkmklonlvhlfqpksklllqjknmqooooplppplrilmpkkbymlpipnjlqnoqdjsmtmolunwkoolqniqqftwon{qlkksrmjhtnompwmnnjjpxnsompmttpnptksmprflplohkmpmunkgmnnnpkpktoppjpmipkwnrklmjonljpkmsmhqponnepiqsjpqrlutjurlosrjnnpoonksnnlppgkmojonmqpljmunrslqsonlipkohfpmmgponsowdimjoqmqqkjnmoplwmmrhnhmnnklpnnmlmmmroosmomnsrqnnlqksnlnoknqhojowzospukmnijpkkkpnlllkjmoonmlolmkkmnmpnomqppvolnoolvppniokgnkilmqjooolhgmnloloknwpmlpgqmpuhjbugjrnohqqrllnmflknmnjfljnpqjooemqpijylqvmisoplponqpolnnmskjnqlnkllokwmnqkonmknkjpeqqp\jqkwmnmqhikottjolhlljmhmnmkmnlshptkrllmlolqpsqkmjmkonnjknktnsmojinfrrmnropknnrlpklmrokcpodrmhknmqlipmmipropsqokgnpqosromlinplnpimmmpgjiokojnlttaxlnqmotoopgllmlnkknlpqmspneooppkmnqrnnqmmunpmimkvsmiojmttnljpljsxoljmnlpfrnrmnokrorojlmqnslpskpsolmlipkpmimqklqqqlqrolopoolonnsorgsorljnnluoonnhuhmqmjssmqqropoorponpmrobplinknqpklntpmgjnfmhmioktlkvpnqnhnpnmnqok]lmrlroorhopjqnnponqqkmsnnpnnponmiqmrpomjlomqplnpplpokrnmvjpnmlkkppqpjoppgqmmmkqjoloniiqqvolenmhnjjnojooupnrvlmlpkqnm`pgnpmomnjpkpokpoqnqrnglkjpoodkinwnowhontmptohmlmptkmhqinpnpsllnlllpllqjinmmpljilokpniknqkrpmtolmgmoofprnhfpnipplnxmnjmmolsno|njjpqmouspoppjfntknopjllonqrjlplpmgnnrnpmtqmnlnprnmqmlpsmookrpplkfnnotjnglpqioiklonhjspotjsnjqronmmpjmjnsrokgmolnprkpwrhrillgnpuonompncpooonmnsolgknhmniknhtqotmnpnroglqqquosmpmkqoimonknvnlropnoqfomnqplnnlmqkspnkmnjlltrrphnqwlpkprkllltnoourlnoqoimmjrhncemokklullinrntjpmtmqmojvnynpoktopdprporpvoosonllnrmojslknsqpyqqmmmoqkulnogosjdnvpspnr|fhimlonlttuoqpogkftqjilmmremhjppmixirkojonpptlintupqogojpnrmqrmjnkmpuqnsjjjnt[mljrnfptosammmehnvjrmqlmlqnknjzpgnnkeftltvgikkqqfimmkqomulroqqsnqnngjolhmqrlfkponmwntoppgsslhonqptkonqoijmnunumrklltrsrqljpqghpjowmokqriootlmkvmllrlqnqjrsolinmnomtjjpkinplljqhrkslmhqnknonlmqnoolhpmmjjkgpnn^gpoonermslnppklponjphnjmlglnimlsoqhonsmongolrqjinnjsjqomonnomnkmsjononqprrmqkmonjtmommokrnnnmkr{snpmqolqpoopolnpkpmlpspoohomimnlnonpnklsmiqqmniojonkninopgnomunopikloopsontnmqollponmnokqqmpnmfnomolkmkmopwmonjotprmokjn{qocnhejl}kmhmsqomkhsmmmjhiepwqkopkjnonikssksvsrkcpurpxknlgonqqjmllfqiqmnkkilnlmlnoqpgmfllotrfjnkrvlunotnokpsmofllpliipoqlmijhspmqikjlqorskiiulollppkonplopkfhnqipmegplmmqeotgpilmoomklqmrkomkkylpqplqiprrpqslrljgqoglrnnqqnfopsqspoqrkhllmotnjtklsjxmqlljqombntcpmmlnknonklpolmnjqmmtnoqllgmompsuroinmoplgsrnilopomqnnpmnjmroptlnoosmmmmjpmpqokkklgnnmpkposqnqppojllmrmornoillmpopmllrjjmrommnmnhmptnoljqopnqnqoqsnllpjmkorltnjnplnomnmolrpnmqgoljqnmlqnmlrkjkmsllqpnkoepnmnlnrlsnkqoomnrkoronmmmmmomnrnnkpomnpinorqnnillkuikqjwwokolmiospnoonrlntpommimlmopptlgnwpmlmsnrmhwronmlmhmntmlojlhnhsmplkgmmppnkkptmpnlmqlklkmlnoiotlnqknnpcpqlppspqospmnomqnnokokjrnouklgkqmolljjrsqprtppnlmnmmgounekqmhprqnopookunmijimnohkltmpmsqtnrsnloipsjlmnrrntjlmninnqoqmmltrompponpsonnommorkomimppnnnnkppmupooompvlgtlqonmonpoupniolrkmqkimnnmsjnlpmkhjookmkqommhnjmop{pnohiklknlnolpfokprginkolkmspjro}mooqkpqsokpmnjmwvoqodrngqnjnjrnqmonntnokkp^nrommnpqppokpmmhppoonjjrltpmlo|irohlq|msnmmrgppsjuosoomirggnpmpopgllciplokimpuklpnloplnpmqmolofppopqnqnpjhqnlomhvrmoinlkimowiltlopqonnqorktlomoomkqnonqmmronophknmkmmpshkipiokmlnlruonitqnknhkqjmnlmpspuhfjoqoqmnnlmuoprplhltnqotqonqoonmonlwlrmqonnsopptlpkmnmokomnmqmkjnlsnlorkrlknsminnlllsonolqlt}oopmnmholkkotpklnnoprkodomtmmwoqxpkpgonenljmmnqnkmoojllpszjpqlkpnpmjqknjlhhlqothoriojjhqskmxnmhuojmxormkkljmlrorllsutwolmjnslpoqhkpksckki}ppmknlhiueqnponillrqhpjnmbqhplmglilydhlmkoloonqrnrtmvompoqnkjmunokjlnikmoqljmqsmojkopppgynjojmrrkhjiodlliuleiknimnpmbimvwoqqsjmhpmllsqkuvkgnlwnnsmoimqnovgppkoqopnsnkophorltmppvjqqkompsrolqmsppppsunsnssplqjmeiomlojnpnhnjgojpommlpummmmnnlpnlrmofjkplpjpooooojmknonnjjelopknolqigppokhvtoopsqolnmlspfonnmmumkpqmjlqhnnpdmgipoqjnulnomrpjnhnlnjomgkonmnqlqnqpmolrhqnkojlnptvm}jlmjkpknqurnnjorklmqungnmkrpnnfjnmfkksoywjglmjooooqdnvmgpqlkqomklrmonmlmmwoktoupfljoonoklnolhinmktmoprorpkprmmhmmmgcmynnllnrsonmoymnjprniuutgnrm_npkbtnqpmlmnompomlnokrjolosrinmllpmpmiooopoiaqlkmtpnjmrqjqsmvnqolmrmrlsnmlpjinnihqomtproqomvnmniooornmi^knnmklvriljmorohsflcpnkpqbpnipmooqpnnknojmjnlqwtvmnkmiomnqjomnmpnkqmmokdsslenllqlikqnrlknmhoilvmcknprnkqkoosmlpngqmogqjpnmnonnpnmpqlqopkuojoolmhksmonlmonnjgiotollolrjmiljnniqkhonmkimlslsnnttgrnltoflmmunookqokltmmvnkqolmnongoljrlpknskokmrkoninmslompplpqmmlxnqlpnmpmpnolstkonrspnnkelzslfnjrojpkolkrnopopltmnlzpmrnjjmmnmmkmmqksnmmislmlnklnkklilllsogjpkkoqqnnqqjolgrqooomnrmnlpollmkomlpnmsmkoonkoenkjkqlllomtnslilmntpnvplnnmionnoobptimmrgiknrronnhpjohrpkopsooouwjnojnosnmopononuimmnrmlmlkkmnpjqsnonnnfqmrnqnkorlmlrjpmnmoomfmiocnmimnupnomonpslokppmsmijolhnogplktpjzqmrlnppkmqmmoplonpumpmqmjpmnoollsmilqqrtjmsqtoopbjnsdqrkpqlorlrplmhomrpplsmnkmjmpoqohnnkppmiqpksoskkmpmromqtpnnikmknqqrqmmonnkoullnqmkrnomqornhkmpoljpjjpllnpmmslhpqemponlqnnmmnjomslqjnulpopnspsokkopnsnnipmnjfonphpolrnnlkclklgnsomqvxfkrskkmqoinnknmgmsjkimsknplmlpnqsildnjkooopppijmnnmmkonimlmmkmlloksnplpnolojnpkgnirjlmnmqmpmntpneqntnoomqmoknqttpmhkrmmdnmllonkmomprnjlmllkkpmnmuhntpmmhpohrmjkmmtrtjiomlhnjnjkssomhqoopqnhroosjhwmponngoohkmlkvrnnmlilmlmrmmnqknqmpmenqpnrllpjmmrokqomromdoolglvporqoqlppoprolurdsqiuiopkolnmmrommjomopnjqmnvlplnrlpknhnhnqpohlkmnpqttkporloomlljnmjoorojwnomlmjimfonolqnooolnmnkonjkjjrpmnhprmopnnmjmkomomkphooknimopp{jonoqqnnyourrpninrqmqjrnnmirpnlponhnuonooplnpnkniniqlgodkmsknlrpopmqmkmssookeplqmpjqopmfprbnnksojkooqqpqognrqknynosplukmr_qpukpyolenmjmjopomookolqnlqmoqtpqmnqmjlqrmjlpgpnkormnomoomqdmmojojnhpoolqomnavonnnmllnnoljkhmlmqonjgnkzmjjpmnpolntnmklopjoiorjknnnnpmmnmplpnigqqkhinosivmpnomkjrmnlpisopoopmorokmpmmomnknofxqlmknslppmmmonklpnlomokmmlkmpjmmo\kphnnllpiqnjuijklxnnllmkmqpknglnhonnklniqlpporrnnpnolmnkompdikmmqonmofjrnonolqlnqmjruniqgkomsnpnjpkprikslqnlmlkkjmmqmminkynmollrhljipkvp^sphmnlsosnluqmmomlknqhgrqshlqgvnmnpyphqlitiopoooqlnjpqfntnmuuqmnfkjmmimnsnlrnjmnsnihlmjojojhrnmjoomgoko|mjoppfjfvuplkpgphkoonmspsnvpnomkkomhnmujngtohhngpstkonjrqgkpnmno}lgslnmlpkpqssskknmndomuhklnlnonoqkosqovjmjoomnlrlnlpmpmpnjlnqungpnlqqrlkopwklhonpilhnpkpmmomoptinokpompkmmwnsgmrqnnmgjrvonrpioljtwnknjlsojloqnnkskrofjlppmlphspsljnqloljnlilrknqlnnomjqnmlmmqjjqqr|lqjnnjfqonuppsoqntplpnjpnxfkvppomprnnmsoomnjpqmqllfqltmllmpnnqmnmtnpnmgomvmrnrnqtiqktmqjkopppmoi_hronjsjnqhjlrsoliolrlnnqmmlqnjnmkosrklnkqtnnrkqninoipkopnmofnvinqpoogsnmmkommmknnpmompjkjnorgpnlmjsqtjmkmomqkmlnqmmiopllosqglmklnmjoslhnqnpooiosolpmmolmjngrllinsnkklqnlpomrqmlrpkrlljonjunrkponoplnognsmoxpooorxnnnoopmljorqnjlrlknohukljroqqltoqioplqstmnlmqj_monnhllptkljtvppoldjmkqnrposmjnrnjlxoimllpoqrlmqdnmeqkinonpgnmommpmvlsmnnoomlspnjroolptkmjngbiilkrsolorjpgoqqmemkjonrmktnlkklsqiuongmlmlogmomnhgpnlorntokljmenroomknpornlmpxlomutmllnoqngqpnolkjqqipnijrorvlmsrmrlrpromknniqljmkkoirmimrkrnpnnosrniomsmlpknmnplkpmiroknjoqonmhoiolposjkohknloqmjmpmqnkitqinlhkt_phuiqokmonnnnxllpposonmoh|qlmhrxiprtnnpomjprrprnlwornpnpomlxlmquljshnlrllqmmupmjrlolnmiytmmjnpohrphkloormjqpohwllpnmroqllmqncn|jopkvmkrmrikhlmnmlgnomipjmrhhoo_niwnommqpmtojonqkqtjklnbnpsonmnnmssoomjejpxomsmlWeqmmqykntgbntjqnmnzommonfmrpohltqrsrmlrlrltoplopannjlgmoopp_nkxopsofkrqounlrnhriolpmqihnqloqpqinlgwqnmqqnholqnqpmiotmulnqoonhklkoqpitjnqnlmmlpsjrnjjmowmolgqlsmqqlmjmlkoplmjhqlooxklnixnoiqmuohrplpowslqjpnkrpopsnprslpljrmopnlntoionromjolqopnuololnmhmxlinltrnpolkmimpnnjkkopjlpsomiomukniohmpknoknmqnmqonihoxnqckooknokz|okolommmqninunmpfmprhnrkomfohksnmjsnpmrjllqomomplnmjqrmtpomlhnmpmonlplimlmgpljorpnoqmptpmnonipmolmoonommmoqsmjnojnppmnsnmpumtlsunmpnmonpusmqpkntopgnpmmmknmnljnllornpsonlmnhnqlmtnoshrkmqojmpnlmnqqnmntkoqmuonqrlnmnnopnosonnojnnllnnqomrsrkphoplnmtjfmposnoilsnohsomlqmjgmnmmoormojesomkmokmlhkktolkjooololinrkqlmdkltlkoqngolohonlquqkrofqjmonnnqllmnmlpqiklmmrjmnpponurlmqnqlokltmuknookimngkkprmloorolmnnhkkhpnqtomtopmopoipoloqrqmmulqpqrpqmmnlilqnnylnplmmsfmpqimnmomqmmmljplmoknkkpnjkippimpnponnnvomklhrklnqrkonpmlpnjpmrmmnkmnlqkmnpolnolnhllfnolnkqrqknnooqmrpjnnoqolqmhqmnojmrsnrmnlknmlmmqlopggponnlspskkpnomioooqppnsksmkmnprrmpjommfjjjvpooqqqkqltorlkoprkpounrntkmgjlsrnlpiqqjngnoqkpqmmmunjmmhkporssrhqonqolknppoomqohlyolknvojlliprptoolmkqsesndmsnslslhplmryqkfqufkxpounqoho|klunnrrjmqrpnrosphmqjkympqkqqpgqnnkokcwlselnhmprojsxqjodnppmnnklronmopsgooqpkkpoonkpulwnppllhmnnkqmlssvlondlrmlhtmhgikoqktpondnilsoprimowpk|klqtrioozjpo{msmlqixnhmqonmqoljlntppoqpyppnstomnmmom|jmpmllnpoknroojkomlmoskpnnnmmihnqomsopnonjoosqnlljmocdrolxopppoooqojompnmlqlqmgihmqloomqosnsztsndnolkiqnomplpmmjqmnsqopnnilthmmnmojoopnmnuvglnnopsioqhkkolmnplkrthmropjr~{nmhpljnjolqjkotjodlkpjokmgkooqmknlpkfnlhnoumkmnmmopqqonjlmmnonnqorkpmnpmqmlrgmousoiiknork]otnnnopklonsmmmhlllkoonomhlnmqmlnqkmgimljmuomomdgsmnkhknlnjnneslrllipoljxjmjqistmkhponofjdlqhokjponmphnnntplriiohohqjlurpighmnmqjnfjkfmonnonolnpknomolpsofktnlnlnknntmogmnsesiooqnpmnqqpqkrnrmlmnkjhkmkmpltnssirofpoknmmsn{mirlnqnmpjnnslpqmqoklporjokmmnykkkqkljglpmhmorktoloriljotonnhnolnmjjmmklkjvppvppqpqprqnelstnlmoknrpkolremnlkmpljpnmkqjslmnbssokxinipjsomhpnrhoninlfvhjomssojplmoqrlsoeollqpmipnooqjlnmrrsommtqkjqjhmhsqvnipqklrvopnrknutmowtjpkomnoqqpovqkmkrmkrlnxpinsmosoltoninplkqixqknpqpmolnkpkkrlmqorkkkkpukoxnluplqplooolokontpummjottjklrrchmospxspmmjmgopn}pthoioolmnollllnjqyqkmrsepmifhpnlhoerrnsqcpykollpokllemomqmsnncnmmlqkogpjshnppstnovqnmignnjmxnnonpwlnnmpsktsrmirfsvnmkonoslmtiknkinrnkonjolhqgjpnkhfmnpoupkpqnonjpfkimqknekjqpjqlsognmtgvqnmohpovrllikrkefclobqononnonosmgmnnqompmqnqniupqnnkplnmonsjopiksioohlnfmulnmlnlpnqqnknlmmqkqnlkjhpmnnposnnomsqqhlqpmnlnbppmpohlfjnomipomoohmplmmlnppmrpllkplkpmpmjlpolmonnmlmnnpm{flkokmjpnnonlqsnkjppnrloorfmjpopmnmsmrrmoiooploojqkekmmmnnmplnnljmrlnoppjkrppmmpnipmmlpomrtromwlqomoogkrorqnnijopolspnnmmmmijiphlnnolmnoskohqprlkyojinmowmqookonfllmolnpmonoqklskkrioklqhnjtlooulnqqnqqeqpmmotqjjseonhmomkkjomslpsqiqqpmnqmlnppsnmlmqjpkkppmnolk{nrknppmlsmkmpjn]pokponkohymnlopprlipspkpphlokqsjmmfrmqllonoowqornokqmnnjnlrommppipsnmlhasroopwkmmnn{nnplmnoqnimoqrnlrqoonnfmennpnkmsqookplnnpsqnxpikooskonnoolrnqpmljppmquqosoklogsqopmlllphnnropnpdljmrnmouthopqilbprllkgqtjlojlmsnnnklmsoroopgjpppnoglmlkolvjotlmnpkolmqkpfnmndlklormpqkllmpqropnqerkmppooqvmsnnqkgmlnkomnppolsppoopngmnljjlpuoskrpmphoommnopnlo{trqogqmnqlinniqnppkonpqlronoqpkjmmnhlppnpullhkoxkjlmoonvmovqmlnkpnlqngijnjumnemqomlnopkjjnnkmpmnpnoomqpmpjlnolrlvknopmjmlomnjolnmnnjpqqnmmnpmlsponnpprrskktmnolnmnmpknulmdnpkorslnkrkjpsqkklnkmmmklmnnjcmnqqjnqnsmmpnktomoninosmkpufrppilnmppsjqooikqpmlissokpmnmonmsnkouomllmpmkipon{kpvmmmoqmrhnjwrpqnrstpzqoepvngmpqvqnommpmojmlllltjvujnlllnnrlmjpkooh^qqojpinmptnnkmgmoryqgtmlprlmmtmkmjlmhmgkotrqmpkiktmnqllmikllnnnctnmlqrmnkpmbqnmoiuuqqjotinwpovpnpojrmpjmlkoqukqpikmjpmiomprjnmlqorkjoopssskolnlmmmkjlnpnqpkomnlqllnntqknmprrqojlphnomjrmpmptpurnkmmlktnrpdkimplnrshqznmmwlilnomhmhkmmljnmokqmqfqikslmgqjlnnnolknknnmxujmnnonnrmrkpwnmuroplrmklqtphmlmnlnurlqmlqnmsmtmonofpomllmnmmqmpnlpmpomlpgniqpiknnjsjklpeonoqtsmopnnnjpkgpfjpkhgminlrpmnmommklrnloqnnolqnppmskekoqnvmgggqnnnlnnjkokmjpnopmlpjpqsnskonxtogonpopnrqnoojmnkoqlinmmnlonnnprqinmnkjnmpmnpnqtnljlrgfttmonsojvqilhsmlrotrnonnnpqoopnymngqqjpkgnknppnlogkopumfnnlplmkoqtnlnllrlppktxoromntiotopnojnqopjlimoowmiocmnmrfjmomnnnmrrpnpmkkhnmooonmoomnppnnnqnpmoelnkmknollllnoofrmjmqnlsslnqkmlnluhpkpmpphnhummlnlrlnmhoeknrhompkmokclrolnpksonopnmnjnnjulmohjisnnhnnonnpkkpoinonnqprronmofpsolmmpksomonmkijfnonpmjmqprooqlpqsskpkkmnmmtrnkimrnsrjnkmujpplolnmkjinempmnsnlfljo|tnnimfojrrpmnmklnqostmkjpmjslnilmkstmsmkmpqnvqoopkukommkpsllrkokolpojmgnrlnnotopjonnpenvoogqorhnnnphktrnmmovpmmksirlpqnnniqinnppqmkkomnebqmkllknknnlmoloftslsrpnelpovjrjrmnjlqrpppjlrwkmpmrllfkommuroojmmpgjomrmjppsnnllrqnslnjndlhqoskjkmqqjiosnkmmmpkmunkppvpporklnhjnosqhppilqkpoclhlqskxsjlloophlqnlpqpnlmmljrmpsmmooounhrroqrmnqpminoijpsqbsononjpmoknnpljknljoloopkrqlholrkmnkoskekonmloplqooklnnqkgirqlmmkokxqllvoullolqloopmttlpqkkldlnntrnqmtmluuwrormiqopjlrpnmsttktmpoprforqposquunlqdljkrnpiskqkjkhmumnjplominqslsnilmomokqinrmkmoxsijkipufruqnqnmkmsmnmmloikolorknnhmnmqosrlqlvnhmplkmlnosmnpqmunltpoqmmplloilmxmqoomzjoqnnlmolgmnkssppijwnqnotrmnodnvmqqnspnmlpjllmnnvrmonplinqloonmmeogookpklqlqnkpmrknropokollnrnmhoknrwrholhlonpjellnnplmpntnnohkoppnmmmlnprmoiiolmptgosijnjmnjnnlpnunmonlsmpxonkjsufqrvnntollqoojsnpnolnpomnnkjnnphmmormrqmplkgjnkposiplmmijoplpopomnomlommqnlmmnlnrmjnoopshmmwlorqojntxroxprnpornkrnkkklnnkolpmlnnnrkmfwkpjnoroommfogooolqqomnolqmrjoprcnojnnqnmnnonmnnpmhmomiqkhnnnomkllpmlnoomnkrohinoqmppjlposnrpmmromqlnqojmqoqqnqrqrnminlkmonjlqmlokknmmnkoqmnommmjmlnopsjpomnnmpimkoppmqokmlnknvmrokoktnlksfmnnknqntumkpnjmnrlpksnpjonfqilpprtfpiZpqknlnnlomulnznmkjimqrqimorntlllnqkmouotkgmiqkqig|lpkkm|osomprmnonkvmmtpoooiopngnmdqqpopkqkomplpkovslrnlmcvnjosmnplvmnmolqgonqqjsnmnjkppnijqmpnollsulerjqqpplmnvrmqskmmfnoulmmnpomqlnsjnunmjqosopommjmpnlnpwnronphnkpvpsipjlooldjmlogilmhjnnimimlohohnfpnololouzkjtpoolllulnphmljlvnnqrhsiiogglhsjlmkoqiloowrgjnlqoonmlfkpnglmlfrlinlkhnpmqwkqmlgonmlqkkjmjlkqwkohronpnlpojtqolpnqmocokoqivjmjlquwpqurplhjmpmmoonpopqnejqqpkjkpowooprlnnjnfmmmntqvppnfmogknlmnlpilnlmfrpknrnppOkpkngfrnj|ikjlmnnqjjpltmpnwqpyly{npxoirmpmntmdmpcnl`mgngooqhlmolnojmnolpjpkopylmonpkonjnqmbkgnnnjolthoqpxhfjoojkokmrgqnupkqwgompckljcnmpmlolqq\ljsmlqmpojmktjoomcgnqgpqpnjp_mlsnnnomqfpnlnnnqhzkrtpmhrjpmnemprlnroomqvrokjmhnrzomqmnlrusiolnqnlmmmfmnqmmgrrlmxlkk}tppnpokjRmknmilippriklkninnlslkogopmppmpnohmrqlpxjqljloksllunm`kkjqkqsmqpjnlonrnqqijljrkhlvrpjxqqkkmqomqhlrimnnnikimrqqmfnmmmukpolikpoYmmlhmqkhonmjkojnmovogndpojysmqlnnoloqmknnloplplmoirloeqnmktqhgojjunnpjkrkrekgjlmnpmuqmkolnmkkqtmnoskkmmlolkloqinikvommpmvplknuqqonllmfnoiomkpmljlnnjnllkoqnnpsmjpjlojjqoipqnknqmkomoqrmlmmmkqlqqoohnpqvuqlqnqlohshnolniiolpnopnmniqmlpososrnpnrqoqnqntonillpyrlompmmmcnkrmlmmoospnsommoknmjnpnoeqoknjndmlmnnqninmomppomknqihmlnjnkqzmmkqpmjoinpomplrlmlmomnohjsmjmhnpmkoooppcpkiqfqinmrnnspqoqojokpooqnqjkmlnolnmqojnloplqnkuompmpmorhnlprksoomjlknrktllllmnsoncjilipmllkvonpmqqknmqqlmmmvmtnkrlplroqornn{qpplsnmookomsqlknmnspplgkklajphmpmlmvrplomjmnmokqikqnjopknquursqonmmkohvkojmrdlnklmonvmnlksoigrntmmmmmmonnjoolnomjipqlfninmpjhnooodrrmkmmlgqnmnmojokqgoqosmmjjnijnhmholnnljnntkhnhgoqmgipmqjqhnunnxqlmokpppomlmsqlunpjonndptkmrmfnqmlkojfokjqjcnlldijilomqohrrmimnrmimlikoolmmpmmjpwipnolkxjpoqmnnsllpmlgxoljmoknoonmhojoslijplmnorklmnmpgikplopotjjpmkookerllnmiponprmboqnpmpmnqjkkiqonjmodriuhononrmhmmiojhnngnoiorrcjsmntnpwtlron`lspnemnqjmkniqqrsnjmoozckpjnkonomrsokwplpmtoprmmjrtnkmpmomqnopqrmtvhmlsojpomomniqltsnokypmlnnlonlomoplpkpmnoohqohomooolwplojrxmkjsqnmdnonqppnnqnmsijpmrojdonjkmjpnhileqplplttlnkkmpspjpmrkkzntjpypnsmloolhlmonnoohmnlounhmiplllpmqpsqlkonhmknwlntmqlhrnmm}moolniioollnjonqrnlriokmolgllfueonnmklxtmmmhfopooqqfqokjlsqvhsmojorpoppmzsmjhlojtkunmknkknjrummooutjpdrmmvlnnnnoollipjlmlrtjsookoqndpkhnpqxljmmqnoqmmoilmomihliizmqlptokgomijltmleomlfxpjinpndnlmkpmsqiniponklvmomotvklkqiomaoefpnpsornomtonmkoponvkrmoptlqnjopirrrmnglmqrqlpnqommmirklnromn[ufpjooomkknnmshnoojonniojwlqmhoskrmmtnlpp_klnpmrqmrdoghtokotrjkjsqnxlolnqmnplrqmkpopmnkwupnjknrksnilpljmqmprjlhnqkhkohvlqvkmlohmrlmnpojtqnntjpomnhnmnrptlnlkonipmppoelonllnnmlnnprkookhpsnnmsnokmmmlpksiqgkeqotopmhomnnlrjsmnppnlqgmmkmmloimkhnppllimjolomyi}jojcl{vllolmvlenohnlnomrqlmltrlplijoloqmnmnhknoilijrespokjlttpqplppsonkproluqllooqingnkrkwtouplolismonlnnhliqellpxjsmsoeokippndnlmmvrokmkootlnplqiplnnmokqnjkjgrlqlilnnoonokjosomhoqrqmrrrmqklliqqtlorplprkroqmpkwfnojhm{mqjpgntgopdlollonokqlojtqoknnsnotqrojhmmnsjprqpjnnmqqomgtjmmlfkksnlnmrnbfmpkknnqsomkdywnnoinxqjmoioinkomvqqlpjmmijloomrpnpklmksmlmjbmpqkhpojjommirllpmxononmsqkomnmlmrnmgpgijfnlmntojimoompppmamikonpmoqkllngtmmonqloyphqkmoopomtlihlpknkmpnnnjmpjklgoptplonvqpmoqllnkopniontpoonnpkmenrnlkrmllngnnqrrllsnmpflmoxmpolwoqlinnnkmmmnosoknojtnrpmpkjpkxutgnmmlijgpoonnmpopnqntmm`pinnmjmlkmoololinofoqmomllmkptnnjoionnmmngkolommppfnnklmuphoonlrnpohvnmimonpksnnlolomujnkklnompklpqonpmjnmknnlooossokllnhmoootmmomvrpkoikrnklknmmpolkkpjjjmoonlnhxknmlnilkononnnokurjlloprmktmtojmnoppohmrmmnommmmhjnmqvnqllslpmnjmlopqpqmporllnmrnqoopgnsnldnkhrnpnoonrlqnqolmppljpmtnooktqoklpknmnokmkmremjkllmolmlgmpmmqkokoonpppkqpvomopqnnmjmnnpqjmoounllnnpkmiqpntmnlrorolnnmrnhjmkmlmnjopmnteptnhmnumlqpokmpprfnpoiojilqrokiminprniqphrjpn^plnjukulnnbnqkkhnnqhoenpigmnlhsnjnpmnhrmnkimdopnemtnppkkqnjhsrmgipfrqrnmkqykmrqihppoilqoipqiohmmernkmpmnrqornlnmqkfmljrsjqokxpproklkohgoslorppljgjjnsnipknlmnhvljrmo}oip~oktsnkmpgonmklnepmptlnoooloprlgnplizpmmhjiqlnqqe|inmomjnjxdttmmnnjovfpjfnpnkklgnhpomdogoklklowujllf{lsmonfnlnnlollm{llhpmjiyojriopikgoonmlvirntfp`auyomieiurnookdqqhrnmmnolfoonlpkrlklpgmnonnixkkqqlopnqgludqxsmtmmpunlnnmm|lmmeimmknvtlqdrjnhoqolqokmojmrjqnpsnihsplpipmmmsoplljqqlsprmllknhpnrjluqlqlnqnynhkmkipgmnfnmomopmgomqmlorojonlmlmpmhjlrnpsomjilqqnmpkjnrpxsinniqlj~oshkgpqhoolqnollqmrmppmplpknltmnrmomhnjrijosooomnelrtolljsmjlrkjhkmpnqosqwcmmqroorqpqrkmoslnppsmqkllkiqnpmmoknijrtnrnrplnuoopokmoplomnovnmvkkpompmhmjmmmkqnmklikspkroikjpnrkpopomtpnlqkmnnspqpoupnpromloojhropkqqpqpkpomuojrmnohioinooqnmmonmpmsotkpoklmmonqnornoklqrnlsioqlonknmlpolmmsjsfnulonngkppolnqptiiojnonppnplnkrlokpnntmkrniqrplokjkpukkmlwovmrnmjpoiloolppmtjlnpmokmsjonpomioqrhtppjgoummosnipmqmqpknsnjomfogkpnrljjqmkmpmmfnzjtlnkkklo}gnkjntnnmphmcpoljlpqpsimioimqpvlqqpmolprpnrnlnkltomnspkjqlnqq`nnolkrnnlmink`omqiikrpnlrmooilqnmnnqmkofjjppfkmnestlenrppoqmpqkqmjinspmplrlmolnkiflkqnqlsljnmlvrnnomngoqnhrijhmlkjeqomkpgqlglorpnmjolpohhlvnohnmnpkhoosmnsopmuprjwnuornlqmtporpunfmpkwlnolnuorzokmkrqopmopqeqkrvnlkqgookrnmoljmro|qmmooknmspmkioglimlonplirmnnnmnnosmkmmrooonotmnorklnmvolpnqsmqnmroqinnmoqmlolnontljllronuiojoljojmppnpqnqomlqqlqrnojqrqnlopltpomnpplqinkroonkrmllonmrolmmpkhsqnookcpkknkmmooqmmlrrjmlmsollthotnnpmmkmpnowoolnoopljnnlloosoolpmproqommmmorojiqkljolqjjogfkpjqnzhuspkkjiolqmsojnimtoztpio_cxfsklojqmktmmsrplmwo}qm`jumojkqrmkmplqdmpnlrlirxrjftmjTnmzqpdopsmpstlrrpqlmprnlrjqnjkooynngoojollptipppmlpgmkm}hongmoqmosnholfkkptsmhokvk}priilnhfhomujsljqxgkomnlkhgqllrmtoloktokkkrpkpopppkpjwlkrpinpsmmuqhrslsmvdnpmqtdfqtpjmmmrlcrmprnpmmmjmmlborhmgllooqsikqunmdoljroikljjjpvmpojslgsiiligsqqnlwqrqlnollpxngqnnsslpprkotinjnmludiqurulrlpfqqookresgkskqqpliwqimffqprqononmpklukeonjlumlmkpnlqpokzrmliuqkuoljndpmoqrnyq`xomonnlmhqigpqorurqmrollsnuoqsomminlolvppl_nllgpolxkrpuvrlfjpnhppimpomqqhegnupmnolxrkjquprnkmhqogqqvunvqupfpsxnpoqnzomhjqlnhhlnnpoinrjqqqpduinrmgnipinoilvgpiesm\nnskmvpokonsenooomhnsoknrofqpjnpmjlmqunspjoikhmqmmmvrinsrinwnklrjkxjllrnnthm}rnqoikdqhoplntp_wpoqrmnrtokmsipnpiqpmpkoflrnlolokqlkllmjpqhoksqtjlkmskhtropppgnrojhkmwjjmoomujrhnoftpnoonqmoltnjltrmiprmngvp^nikjlknpqowmpommsonjqmrkmelkhfsqmnmloomlmnepoorrkolqolpmpojiwjkqpplmknmqrompmlqopprkonmpnlloqlolpnronpomlprmkosmplqvosqofmokymokoulnmnkfipnigkjsjmmjnkkmjnsokfppolnonlnqlmnoooooonvmnmlmmnojpsookoflnjppqrollomplwqrmhogpoomomqullqmmmkknqpogsoqqoskmlufrpqomndmigomlcownmvlkjlhmnmppllgijnnugplomnlkogmuivllwhmllmisssonowdwokfphljokmqknnqlxslpmkjlkmrmoukmklmmlrrkovitptjkojmnlilonmwmnqimxlrnnqnljpqrmshokomrniqjngnnkqjmlhophijnqmglllpsqlrpoqrwknmmlmmkonknlooqoimoeonkmiommmhqlmrjpmpnnlqnomnlkkqnkolomrmnl^pooirhmthjriprpnmmnotnlmtomlrommolkmrkpoufnoomlqoobkgshumnokvmlmqqmlohqrlfpgplnmklomlosmmqlnolodfqkmnmmpimlqmoolmpqpqqmenkomplkqnlpprkmkiuqkopmrnknnqpmnlvipoipmlpmntpwitpnmmpnoqpmmokkmmsnipnphsmoomwongkgnlnk~mnmsilmornlqhrkhqgoglpmnlynhiyqnlrkrtiqpjpsolqijmk[frxrqjppiqlmimropfopmgnioqmijqoimqksqlyiwqgwnorgckspmnrnlohaiastlmpmjgnopgpnmorolukkummlspgjonjhnllpuhnipltlsu{ilkkfdjnnkpmlmnnmglnkkeltqlppjogmwhnjiboinpurpemlknqqplljolfpn{p^mompwrjrmspzsmvkikmirmir~nosjgknnzjnntppnomsmiqoonkoopkqgrinonrpoqoilppltnooqfklkhrqteolopmsimllsmmrlplmmopnhmhqgrqsqktbononllelpgnxvqpnjhmsksqlrlpkmlrkpcpoiqlqmmtgnqfkkokqqnfimsmdqsmnlmsnnokkknootlorpkknptmipmimmmopnkomuqhklmnpplswpnzmmlplupfklrjuoliloooimuplmnqpmorjhnqssmnipqkxonqofoqloqqikmnncrppnoqmnsknmokorphnnmoolnplnnkmmonmohnpnsknmsmrvnomjmqpknnnjoonqnnowojnnmlpkgkjrgnllolrpomnmnooktooppnklpnpmsppmlmqoknmlqmloljoonmormlnnpnrknppnnqolnqplmnprpglmlrenrnjospnymqoprmppqvolpnqplkqnppmojnmllonktshnmnnolommknnnornomlonoqmgmummprsqlmopoqnlmqnlpsokioumknoimqmnorowltopmimnlgqnnpnmgmnrjnfhlimssnqerionqmrpmmllnqppphknoqqnlpjplmpnmiokmqonnphhmngnrmkshkpmgtplkeknknkmonooojpomslolorjndlnmmrmomiqnoognllrqspioolhmuelomnnqlliqmopkoomqoinmkjnrnkoqpmtnnmoolnplqjnnorkmnponnqkmirqspjjnrjomnoqknnqqnmoppminpne|bnktniplqgxmmomnomromkfoqmmpnhplinlynhjnhppnklqiokpnsqolkmkmrglnppolnlolnuumqkokqmnmnoqonuqnslkoqfjjqujplphmpmnwolnkjmikplhqmoofomrlfhmnloippsoghppjmhmkpuoiqoqkjpsojqipooriklqpokpnlsnooihvnwjnnmjjsocpronmqllopspkponokmcmnpopnlqokmmrnplolkpnkskpqpniqlojqrzpntjonmmittokimleqkolnnngkkpkolhmlqjnrkmopjfluooifxpomkndllnqerojmlqimmnojlmemopmmhorempllmqplnpfnnsrlmjsqjjqqsponnsknilqmonnoqhmqmntkolonmlptjsllpnoimjlnhxnmklmrqmkolpnoplqxmiifinqllnkoflnjnllsnnlqenpioninslnkm[nklovmgoosqonompjhnkqrmiqodmmolmmhlknogfpmWsmprpmnkoynooqnnyohjpnpolivnkrnkflmomhjpkjhrnlik^nhnkrkpmtowntvmpkqhflsnpnsqmgpnsjtpkqjsqngpfhjoojxnrifg{jkjmnpknmmiltqprplkjorilslnvlmlpjpognhohjprsoxlyplloiiulplplklmnlpmgmmonqoknlnompkqpnqionksinnpqmtkokuqwmpqlqlsmmlwhlrmqnmqmlhlrlpmgipoplslmplkqnrogop^ppipjprjslyljoqfmdkmpqpiplkpwlknpmrovumpnjjmjloXpdnpkronqnooh}liolankkmmkkqnggopnkmjfglonhqprqlllsrhqejvkolim~qgkltuiljromhwlol_pljqmlmkknpkljllioriimrokautjoiipxkmqmkqlhtskzphkponelmmqlotpblormommptomgomqqnkkfo~nnrnrnskqnpvltopljspmmjfkqlhjcrpohjhmjmkljrvjsojgrqgrqnoqmpummpnjpneljnmprjkhpmmislnhohfpxvkmsklvphyiznpirqmnyvlookmrppgmqnkrqhuplvokopmsonkiljofewjgkqpnuslmilmplnnmskrttsmfquhmlnnmnrmpmlorppkswoosqpmkneslkqnnlrjnkkmltpjoxrlqiojskoiirmrlmqmlnjnnmmpnnrn_miitomcljnnpltmmnpnrgmhikjqosokkmomwnmnlnknmpkkmomiminrnolnijioltpmjirnnmpjmlmknnopomolvlqqsqpmimonpmihmrjoqkmnoormftnmliollvnpnopnlpktohkmltpjnroqisqopkmjllnfookkpomponoknlrlnndnomonmemtrmrlonlmmoomkjcmiopjjonpnrlnimflfmrpmqnthjkommnomdnpopqvotlmlwionorlmolnlrnkmqsnmolppklrlnmmqkpoqqppokgonqkrorljknkmjqosmkkrpmljmmqnmllnqgovprnnojmonnkppnjkpikgnq{meplntonjmnookpoppkrmnilqplqrmilmmmlpooooksrkklovlnoommlmrkqjuropqmimnjmqmhnsontmnowapnnononpnkjolnsmopiokoimmoqkmooongmommrohomonkmklrldsmqnqolptmmijlopqmbkmmjmonnmponsnonoqhnlpiphpmimtnmooomrooaqorlxlli`jmjpkoprpkqotlmpoiieoqgmmouonkoqxfptmgoqtugmntmqokdphkpooshnrmrkno{kspmjnlsllviooelpjnmop}kngnlmmnknxqsgvlnmowmpnolnnmjnnkhjmms{kojiolponmlppnitsjmipjojjotjmqjtllnhrqqnppqnnoqpjiqnpmdpqrijlrkknlqkmtmolopsllmoxlnspkhknhrmllioljpihqlmoqstpdsnfnoqjq^mrmtmuxeollotnprdiioglmxqmoignllrjmtqmdpfrpylkkjcinimpkjptkhpmnhjtmkgqpkknnkvolklmiikjmocopjfntocqwlqpngokgrmolistpkujnkmifkmnnpmplkkkmkjuirhqntonomvpodfslozlnmukxomnmelkrmoqnipvunpjgmlsptonwkkqspnknqnlmlmmjqupmpemnmqotdknijoyqmjlqliloshlqtqpmrnmpiqonokpimlopoorllpjimlkkoxsq|qpyonnloqmnonnoxouxugjlinkttmompkphminljuqppnrolelnnokplqkmromqnpminljssjpmoylihsippnkljssinllnnloronnjsposinniipikmogtnndnvprlpnsmqmlnotqljindkmpsmlmmiqktopnfkhrnpnlneionnmqqpprjmoodlmjmpjhrmpsnnuorpkmksjvmrnnpnomnkpioklmlsqplgnmpnwprqpnsiopooptkoqeomopnjnukmwlkmmnikqhnompoplpnltkqmnopluhlrrmcnlnnolnnvmmnonlpngnrjnvtrpokfjlnjmmnmpkmjkmlolmnqqpoqnqslnnqlolnssmllnlponpskolllhenplsopjalouomngqmiomnipknknmnfljopjsinqomnlnnjnplmntvlonmlmoummnpon{ns}pomqmironoontpnpnoronnkspkpnngnllhdhoqpolrmlqtjnvnlmokpmkjjolrlppkohlomonqjonoippsqsgpolrmvpmqrrnxrlponxnjpikorksprpsnqhpnokjooclnnjmnpqknqvgokskojdlnjpofpimkqpvopnnjgupujpqlsqnlukqlllrnloqnktpquimooqnnslmufrptkmpiqnqmsnoqpmmrunnourrhinjomlrqtnsqrnikmrljtostpnpfonoptojpmpqpniporxjfkpjslpkrprpporlnnnolnmmrlnomhnqyfnllpmojlojmrsmmnqsopossgrjluqmimglrmonrnjsmipohsprormkomnsgqimrpkpshqkrtlolqmnqnuoepklniXoowlsyjfimohrnpnrimorpooospol|orljlolpnmppmektqkgodmpprqiknleokrfqrpkinnqolmommko{rklslskmimjrnlgvpknralnkomjsplgrsomkndmnjormqkonjkhskjmmohkrjckpkmkooqmrtQosloonkmqegoqokppmlumnmmfolpmhprkolgnesnoqmzunoknplpnhnmljoxnm}mmmkhposmqqmpkmpmwjxnnkomoljntnjplnutkimhumpkomvgsqplqmonollplllmjomiqilqmlolmpqottklmpkmkmrlsmilqolioomopni`lpmgpnlonkqmlhlsnqrqplqojplokmguohqmmjjkshnllnlnpkpnnnmlljmnpmnmmmnqklrkmqqmonkkuqpKlnqpoqlmrgjflslkooptommoemkonnqjmrumnnsmrjtoqkorqkmonjnolkiunssijomqqoeplnnqqhnkohkoplnktltmrlnokxkkojooknlonmmtlppjnqrlknoggnnpimnttmomniplolojrlolnmqmkmqqpmotqmjopmhmniphkpnoohoomnolikqsmloqmmqnponmonknonumxnolhnnnmiomqnnmkmjplpnmqjnmloltkonrllknnlmnpooilnssonmnsqmaoqmkvmpqqqonvnlgnpmmsnksnjpupvolmpmvpg}otoknlpkhnjkukknikpknolosgmptsporokplnflgomoolpkdppqpplpknonq^uoqpmmppoloopppkmnmoqijornnornmmlhopollkrqnmrammonmqvnrqnnkonjnjnqnnrsmfooitpnnpiknllqllnrgmjtoliokhopmppmtpmrnpkonotsommhminoorimoplqpmmmjnjpkinaoiolmqlppihmmppssmnnntgmqmokjoojknknqougmnnueprhpmopmqlpinrlrknmllnooghlnmoloipljllqontp~mqllnpoipplrnkojsnpoqqljlqommgmnqkqnkjilmsregolmpjnmljlrpmvrpskqpgilnmlmomnpoylogluswnssonsmtnouonopkolmrpomjqronprrlkpnjqntlpmnppqmqjmmmqlitqjmmrtkokllsmjsnmqroonlknnimklqpjnclqldrnfnfnlmsopusnmolkknomlolrlhhkzmo`nknhonkeknnjwonnhnpmlb|k|ajomstnjkopnrgncvippnmssnsmpvim[ktilbpnfpjqllqnklpmjnnijhndsfnnepiqnoqknpnknnjoo`wojqkokrpqovnpdmouqpvnnqmpvnn|pmqohoolkorpqpo{d\sklcnmlnppoformmooljkoo\ghflnpqkoiysootmrfnlflprxiqolkkmonupppqmjtqmussjmlqnhqolomjmeknniuptermsmlnmklojmmmmriokisqjlnqrolmtpnqnjnnoplrrgpqosjltwomkoouoosfnlirnesrpmtkplmmqpljmpmvnkkmnpqmjokqmiunrnnoptolporkllpnjnooopqnqngqpjhhkoonlqoltkxnqwtqmrlgsppmnrqtpnosnmn^pimpoohqjklmjfnmjkqsnkooprkkmqilljjvmuomulhsmopkqnrdktloootopelblnnbrp|nrljjikonpmkmsrnmqpmpgUrsndpihurpjqionlkiobkqlmkppvglkolomhpnnlehkxmoklmoolrkulefminpmormoievknkpjrjinfmillumhognimsjtnnhmkkoilnmkeppnoofohkmlqjrmsmjrvpqkewtqqwkopothmoojnmrknvrvuloxpomqlookpnkltslcrnovllpnrmhlktlwqstkuclnkxpeoltkikmhpnqjlpmpmnk}ponlrnrtrnkkmsjgjvnvkfmhmrlorovklosxlhnlujoukhtqhvinskghmkoomnomemij_qrldhhosopmrkoiqdzmopmnimiokmouoemkkylmkkl|qmkkkojqlpsqptm|lopl_pejoimjulqiqohelqmpmhimtnqmqkndspoqhjrotnlqpolpsgxpjnlqhrrhjhigfmmloxmmqpkpsikkilmrmilnimmlilikkllmkpolk_ipolhepjWkqrrrklpihvjkpnjlklhiqocdspn{mltsknotmkkoriqljponnvqtjlkpsfgnljloepmjorjlrnqyfpmn^pykdkmihjrkqtmgonjjTXopmnnipaoqqdjhhplqlnflldmlosqopjgnnmeollmmfmtrilkghngpiltjnrmnpipinqmkbnmhiqxifoppckfkqni{mjukrrotoenllkvqkgnlmbjljjlmk]cmptuo|iomtlnnnootjkjicjqmnntnkkdlrnwgltkyhinpjnmgohenumwjvoqpornvemgkjakiarflsqjmrljynlhqgbmqhorloih{sunlrptzlnkhfutppe|Vkipijdkjthmc_oojvubk~tqmejplqiqmrusrhsepojoniicqglkelclrrtjjolkdpytkotijoocknoaokowdomvnqsmonvlkmajkSokdoppiolivpyoqoivmvnovkkmflcmgnhtnunplprpqqoofq]mun|fnlomormpp{lopmmkmlohkqleonprqonopmonopnormnronnhjwjnimlpwmnnhnnanmlomtolsnslnnotmteoldnolnqdlptlqppnpulpnlpplwppmryjljpnrpZnpmnynoqorpjqzljqnhmhjoojnrmmhoomqlqtxollqlijlkpqpqznhqqlponpmarmqRkrpkn~kojpnqmnhzphrmlnoopspqmimwpsnoomkpnqrimrloiqmxoujkhlkiolqqumqmjmitrnuloizijnrqqhuqmgqrbkmrdusphwnnlnisqtmnrkmxlkpiljjjknsyrosljrophmnldjmlnjinnmkoqllpjo\qumdkqzrrmimnpqulsn`pnqonpimdwlyninjqmsionjqulfnmnomlrlkpbknoukemvrbqrtlgwprrmomknlvvjqpglpWpuoppksxfnomolquzonevrmqtjmqjsirmnnmgqreowjniiiom|mimjplplkmwontlsnjp\goqpqrmmopokk_pmqrlqkqplomteogpolmtmsmomvgrolpyrhboruoem{mmq\qogomlpnrop{olro{{orn|fnlmpnoldllnblmrlkkqolmnpkpzkkmjmmvoqqkmqormpmanmrmnptbygppnmraiqimonnrgnsno}polnnkluxdnol[mnozhoollosmkqdtnknsjppuqqkirhbs~kitzklrqpinhpknkolrgoooephmmnlmrotlcpkmasompnwqdronoljnsofrhqwkspojnqrlnmnspkgploikqnmlosgnpkqwpznohiolnqmlkqpogijmplnnnwoktjyomlrsjnumnopmqmhkghplnokoolqrknqimlpqmpxofgkkrmkrhomlnlnmnoiqgmuknmnllkolompkrmnqgqnnkqlm]meobojdnmimjhnnpkvdop^pnpozmlmgqlskunaqihnmwomomooogmmpioqrorpnhlqiprnhooqeanmkj^smnomkshlvlrqcloq[drkppgpmnpsmoqnmmesikkighdcmgnipuwnnlowkppohefphlnznqmqpnopzosgpsefjrllpjlmlqztxrqloreiushif{mlnmnqjobomfnokhnnohqllqhscpoitmerplmoksoknslekpoqylvrwqqnookntrppherdyjprmantmigtqmljkinlomrdbjeksozpmtfjomq|jnglknnflhpmhl\jnfbplonvmqtrlppgoqhjriwpmuqllrn[tn~rpo]esjky]olskojpqzrmdhrumoiwkduzsinuyj|jozplqlmkkq`llnqlgvgqtojlpapoljlvcfpaljrf~qntw|{eksfniymskjypknjrlqrqkqqhvnrmmo`iiomlegklcophjrjmlxqtmioghljptlu~qnjgsqquqlipmo]mhulkdntiolunomthppiovforlurds~bbofslnfxnbpunpkto~kzmigqrermcammpmuqvqQsihinrlmonklljpljmommjqllnnqoplnjmkkmmnplmrmjjqrolmnfxmqqoopqjgomfqlkrojmnpdhswvl{ljkqqmpmqplfpvumlkrdojnppplqcojlZrsfojlrvnmrlnmvkmfolmifproqshrmolrnlopmlinkqvhlnklpptolrtlhgpnzloqpmmhpjpsyinqmnpnhisnsmhlypkktkkpjphlmilpmltrlpmpmoikmiqmcppsijpgjjjwqrpktjgkolmoiklffintomopmliqdsqnmrniigkmklnpotqkppsherfisiposm|nprhspepnnnojlrimsghoospdzrnourlminv{juotkZsnsplqdm`^ccikjllpljjpgnooyimknomho_kstokouprjooljod^jmnmriwokhqlingkrlpsomynlnsltcnmkluxpmjnrqgovqfqdmflftnfjrmsomhsqosipsrnd`oorsnhjolnmlnupkmjplomsarijmniqthkpjhmknqiinvbnqglopomno`lrvet{pmvpnvgqjpamrmlmnrzjqoskynpmmyqlommmkitkkj[uqqmilisp{ttmyumnnfjjvull}pkxrp^mlumpxkmmpslekmjq`mjqhrnrkrogkornusmkhm\oclxvxljmkfoomunowmsalmnlklmole`mnjnovmjnmufkkdtpnxpsrmwcqpiishknlknoloompdkkunpdjrsiwk~sefnttlken{k|qnh|pmkqopktqiicilknwqnkkoqjmnoopiigqmhmuqummutkogoqmjlnrkjnkowohjhopkkrjiuhrjhnhniiloomiQr{gnmunrrmsjuonnpqjnlqlbqnolnok[nioqrlqdlgkljkqjiqonpkjlhmrwmllnpqipnmnjsmkgqrpqormgmnjnlkkioidoqfqahqlimqilumwrrklqnnolmmommlrmlkqjmphpsltnhppmmkomooknqkhnqkplqpllojknmo\yojpjpmlfonoqkmhnoknnmkmmolmnhllknor{nbokpsh_inlkspinmnrkngrlsoorjn|oszla]nqmijgujnllpsstoypnnqmvuppooooqophmgopmnpoqhlokqqlwlnnnlouxmmpnandmmnjonqmonoonvcjlmlpqjrmmroh[kasnokmnlg^kniclnmmphljsromsoixq{klflmiklfoulqnjkpsxknnrj|mpmnfqnullkoqmqzlln]mglkjmimopn`nmnhmmnojkdmkployqpsnqonlkpmnmwlmeemjrlYlrvlencnlmkto{oolrmkklznwvoofmmqgtlqmnqnnelhnohnompmtnnorkngtsilfpkhqnqkmsokmunorlvrlnklgnnknmmsnqqikmkjknool`donmqjncmhnnqnmnq]~rnophcxnllvnmnohimnrnnznrjk^hooqzmnnnlpl}lnmnpmtxrnmhogxlzopjnTjvmnsowvpmljprngnmoulntontmjoknojmmq|enmsnnwmllmsqdkmmtipqqqnoqtnqulolgotiqnouksnnplmnolhkgfjioxprhkqmqoiqoksntlmjfswmnpr`plh\mmtnnmnoemornknojwsppmklummlnnotthtwpfloe`knkknsyollqlpvcms^rtqnvhtqqlmhuus]pwwlknoknjxionokspcklhromlrklkonojjiknqptlmlvltlomkojdoqfm^gmuuqoooqlgdollkqrgOhot`ejoi\ztgnmokp`jggopaekzrpgqfssoomjnkhjnmbxqljtdprlrvkprpnnkptcvl]hltmckpvj|kus|gjoidhlejlgpohcZgtrmlr]k~nsoonpmoiorlfmjmjlnnmqogktmvokrhppnx~qvllertmqcktpijofunsfkmq|[nmnnstaeijuibrvrUluprnxn[lqixqjmgsligskknlPoctppsigphlitjtz`kltjmrwmtkftpmpnknmkqxolpgopnsepkmnoqlypprjookrmninskqbepnlpgrlrmurmnnlnppuokplpnmnmpiomnwlmlujkstkjonvpnplltaitpmoxynnjrrpqugojmwmmrnolmlolhpoqvoinlqlkrkktonmmspYknlqgnkqiskqqqsmoknpuslhnquomnjioxxrojojoplqrohpknpdnklempkqlrrmtvqmjlmvqmlhpsmvnglotkontksonkmommmolwnpollrjnrplmppXjonomkmonojnhojfpmlppmomoocfommpvmmzqi{pkmnnirmromqulnmjlsqo`xkpmofk\noilonnrvngmZdopdj~mmmoomnuqkmo{kpomqomwmnkkjosmlprmqUuornjrrmjnmjorofnmsnllfnlomknjqhuodmqtnrmvrpnoqjssipdnolrkhmnonogkmtuokjrpiopqoplmnnfplmpnplookqoilsnopnvrmoihlmkroornmswinpsqqlstomoqskiqfqolnnhmolomlnmqnrpokopkrmmonksrywqokkojjionboqsnompttnnosqdpklq`lkftnpklirlplliplvkrjyequlnninnpmqrmkmmsolnplpogjpmhonjojpmmhgrmnonhmmjksmrqlnqmmtltmmmmmeltjsrooongopitfilpponpftnpqplxnsmrpnjpgmislqnowqjgkpnunlnnkqlmnlkllkjkonnosuqknmniorpohhnpnuqtmkkjosokjhlpljmnmoiilesihojltonqnqbkfertmliqmllokquxposgimhqpmhloqulnptlnrnhnlbflyvitlvqvxpmuokgoiqhokqnlmpipimnlumpeptopnojfmbmrnmlosqnprjymkhiimpnmqepkmiwmqumjhmktpoksnhjhrsmboulkkrpotrpfgjmiplipmllmhnjnmmnekphotilopqflgtkpnlkpktholmhqqmtotqokqksjhlpqgfhnjahnrWrsoslgmkltrn{iqannnnnwumuuvtoiqqrm_vsqsulpsfpmlkfsumbwoklqljllpnoxqqvt~xbpqhpXs`jtmmneowoTnuzmvremuos{ftppkssmlnbpxnjrmprpqwqnhnugdlw|qjqrgdtwpvs{tlwwnf{sqoeosTpnrzcgdwmotejho`psvkmnhnjlexriorsilrjmkqhXicpkktnnpnztmkxaqsunoppqowhmrtkplqroveclillnkolrkqrllnuquknh|cjoimnrispnrlvlnphmrnknetjqojplnncjplsllqlmpipopjjpjnonrjlpmhqmutlopmktlponqurckopkqukoipovjprelmnlkjmntlcnnlsvlmmnnfo|sliipnphrtmsmtsmlsonsflmpkjonumhgpmilrmjslrlompjoirjqfqqpjtzmolpnpdorkjvnyokswkmujhmingmjhnlotmrkrncgllnoirpmqkipznsiqlkhmvwnohvklkipqnljqnllbmelnlpn{ovWnolpnmhpqn]lgrmomnncnpclqjlkbl}owmmonlnmmvitnoolnqkookpojpsjjzpoomlfngnnomingiooonktkummslqrsmnqnkpgskroto`ronrmis^pdkankxmuffnqrmqhtcsmlnonlkjmkjpnpqsjnnjrlnprmlipllZmqnnlnqlllnmpqmnvktqpmuxmlipgmnkmjtjhqjlhplmqjpmmvlunrkjqprcpp_omeopnjnnirpqblowqgymlsrkepgmqmuncnplonlqkmnojn|jkpxkkltoojolqqkumvrffnmnvlpkllpio^uqlilvsvlmimoepopsmqnsqlmnqhwhoroin`lldnmoornjhpp`uomnpilcjuqfprlitahvnlgll{hp|fmsmldkjnrqsmmling\of]nponjmgknlnnokolmqonoxnrimuppuitoqmptipikdpmlzulrlrlkprkqzfhmojkof{klptqgmmijopk|olnqqnqtllrmipqxnrqnnlpmsmrnpikvrnqomjqrrqrynrmbilr`nokphekmmnvrfmopvuwljjolfsoqmvnlpnrkkonlnmqogknjtqjksorplylpvmopmtlcgirjjj{yyjktqllnmbqlhidlimsumltomqjtonhkrnilmjqypjrtmgkegjruqpfqgpnmnsqnonqjllllkpjnliqslpolhomkpoufawospfRhomuooyrmrrvgqeimlnoiidqjnwy}wpnkpqwqmxjiinhikqrpopok`ovkominciboaszdgqunjnkkflahskfufnqpwsmfYjrhyqgumn`}nflzhqjmvoiniqdqwpl~d|gmnlourqqmdTpirjkoprnujnjsrd[dpkpp{imlokljlklonajlpojviligplou]skblkemxthioipw}}ifwnbjtpmzjls|olmielkvsqqosnuoorpmojnfkoqok`unpplornnollpokrqgpnokmkhpopokylkmjqvpqqrnlsgik]nkllnphnoolmkmrnnllxqmilnrjdojinjqknolylknmmkloklmhpplsotjlosopqljnyluholmgoynmhoqowntrmkopk{pnrnmofnmnhlnwkotommouikqhqlrok}gutlnjonlkg}qoor{doqonltmkonmi_kn~kmvlogosomqlkomopnmhiqqkjmopnkqmjjpkpkpmnmmsljpojqqzpfwkfmqklokovnmmlplmnrqfojqmupojvnrkktlnms{rmqpsjqpkpompmmmmnnmpmporomiiqqmprjnpgmiqrpmpjmrellqgklgiqppmdnqoqqtqlnkskvbooojnlnniuqmonipkqhmoopqoimjpnlpppnmqnlioltigppqqoshnqglmnqjirkvpingqnmsijnnkfsmropsopkomqkpdmlsjjknqpoplwsokmpipmmmkiuopqklpjptrtqrmlklsl_mmjvvhkkhzrknpqjpgmlnnkqdpspqpprllkgfprjskwncwkjmlspjjcgoqjmhvlkplqcdrtoskknukvohp^mlpq{sq|sipemhknoatjqoivkoroowhplgl{pk`mqkjnsklgpmmnflsxksqvjksmkkkjlpngnnhstlksilsmoekqsnomuijrro`mnokpoup^t~mlpmmhnjpilhonpmtqslmwgqrmgospekhncljkjskoqkplsjipxmpmohmcnkadqr^klmkjgxipopkqiokorkfeluonsvjwlpkeorrjhlqkkllftlpvijulpifkwljnajroofithippumkderwmnqnypjqnpnqpnnjk_glolqdknborsiorilortqftolggmioklelnippmolmq^lupmmlehelgfmustfrmllsgkooicnsmhigmqmppkkkoqf~lxhttefvinohrfllqmuiqkoggirisjrllokpojdmpnmhggfnqrgmqkonkvjkorjvrnrmqqnksynmkomdlppnpljkomippmjkpskfihhjltpokvlhlftoljtluhqjkfprnpmlnmojujlgnkkiinlhffqlkqrpsmfsjofglflnsmklom`irpqyoolgrqjvmsrkvomrmklkdgomknmunoqhuqljhtgnqnhoyrmgjhquvnoqlilksissntonrinhmpskrumrmnqhlkkelnmronstmmqrlhmkvxojqllmmllsofpmmipnojltkmhdshmi|yg]]zmejhkgi}pnnho`jjpodj`d`jkqvpunlmoqigpbo`kulmmoeprmtjopdknmukplnhmomokxoaoowkddpuptlldmpenrrnm`nmlmpYnlnmpkppnfjpfmlqqvpnfp^hrpklnlnimngglpj_pjlajkmmeihinjpsqnmmkjgzqmtlnqhqtzl_mknemrlhwyq]wkwolpgnllnonkmnqmpklbrmjkinjpil`llssrolpkiznpbggk{lttqgqorklnlvfklmknnqomqtpknn|knrmoonmkklmigpqorlwuororkkqjmmrllmkjnojonmnkmjsnikkrrrmwhpxgnngufmswnqkgdojomoqnhonmlsmmbpslhnnkqnrnonkilnjjpkqnqkloqinhoqoirmtjoqklqknojfxmspbkm]oirljqglrhlloip`omilnqmnmkqmliqnforlmjpaknqrfokmomnnuknn`nmorlojsjzusmqnrjnoptsjpkeqlqhlpqszxjppgjowesqcmfjrojskioficobo[lphiepppopurgsr~jnnktpwqigdlncqvugnncrnkojom~lyfprnmjduwxouerkroujmxikri[mgnksnkVqpkvdonspkn{gdpmjoonloltlspmfpgnlmqjxsmlynsmooilrgpmnulunknqmo_ujnljufvmmqfcggmbfkrlpprmnnnip_lmppcimheomqmesmjokwplksmuspahpkkolfllkoppjulkvlpkgomwpttulloxpnlciqimeopnffkinnkqgyppltpopjmjloonpmsmnk^kmpnxmojhnlpmdhqfpkonxgolqrqvqpupkflsbtjhporrljpgqmqqmnpqlhwcpnyqloklqpkopnkmmsjtntkkoooctmmrphlqmhmpstolppghqnnotjlnsjmmlnf]pqnmnqpsoniloinnkyuppuowgnlqfmpeihplkjhrfyjlnnoirmfmlnwbgiolmrpzjqbmqomhdsk]djepodik[^hlposndjdhqrgenjspmuymmjikikgnmnoanslhnmqkmktjrgepknjgXgimjpkv\lrijhatqqpql_olniqioidpjNXdknencmlmpmgjmjodumq^nukfcnerkilfgfhvlmpgpnsllsiandlhnpzumonmhnoVjsmkBrsrffan^hgkmiglq[zl|tltbjepupjwnjjfjhcolkek^unifqchnrhumonvzgpnilhj|ig`mkroccpkndiiifjjnljmkpgmpoqinnnonolnqjnn[poylnrjwwkkdooopponxkmqolqmppmltpkpks~jnhxnosrpolqmojofoimlillpmpkvnxlpjiwkmsnpmmqprpnzmqhnsminvniovnrlijlljpmopplllqlgllmpqmlpetploynpk_sxmmhgghkykfjnnnqmqjpkhtonflpbglvllkrmpnznmnqlplfkqljjmpnmniqnpgmqpfgjpprpprsrnlykmklozfrqfrtiiofsmopnltpunmfem^punslqpmmqanlkoenqpmlmpnunqokmjnjtnjlepiwrvxoiq\lnmslghgqwvjopzhjplqyserlmnodplpovmhmlllsnqnqhonmljpolmgrqlrdhrqrqkynqljytrhknlejojvuhslvonpoknvsoikrkykkfmntltlpskuiolhoqojeoxalfkoventpqrpuqhliwqmromkniqaqqjemklifnwkjuu{imloquklfprupqqojbrpikhotlsokqkrnowsiplqjmkosnnmjjflotrjpsrsnqrwnloemoohopmtqljnppxoro_hdlfnfovomwwomsuikpunmprrmomiqmlmmnnnqoo}ujqrdkolrmmfkmjpomjjlnmmnsjoqlmkoxocxtpqnnronhmnvollw|nieknpjeemllmmrvqprnsonlomlgomorlanl}kmimvrrrkwlnnpbogororljmlqiupfqgluokmolsfqlmrnqkmqlpoullponsnnlmmslrpghmppokwprjmomolqmolbooomlnollspqnnnuijnqsllnprj{ppjknhlsksukjmpptukvooksssonpplosjojpnoqulnlqrqlhlmomqqnllljnlmmkjlulfnqppppnqpmpumnloumhjnvrvqojljenmrnrrmllptmnpkkomohmonsjnpllhhmmpjnwjpmmmqnkpmhkpioonilwqrhkpkpmsqlopkplllkwmkn`kkp`momoomloklnnxlprnnlnnominjfjnmohrqdgkp^qanmotmpmofmloqnklmilyYhjrhkltluknsrnipo}nwvoopeljrmnnlld|olm]mkhoikmhipmjmprllmrnjbltloqlmoqnnoolmhimocnmm|onksmqycmncflzkupdrwkolgjlmhopmmnjknlvmnlpkqwfnfmgkjlpmnoomonmnklotgmllm}wkkn|omqbvlhxrtupjjdldonrjeqkpmlhmomiqoqsimmjpqpjqpjpiqloprnnteqqnqolqhlouentmdlnqrrojlwmlrlpmjohkntpjxjdpilplslomlrvdmkqrqtmrpojdohwjksupjtoonjwvmqlroqskommojkqngmtnjnmkqknpmnqlnqtlnonhglyrppwpj{qejgleknpkkngmeuunothoopmpspllvnwrkoknpomkinrpokmlkhlnnnrjonompsmokhlosulbipjtnokat{ilnqpienkeoimmmisnpvuqsnplglnho|htfkkhymvyrdnhptoenky}pnooqmmxuqiynhqrmfnkkotmmlulghpkmlflvwkkisd_uhdoojlkeoihapspytpfhsjqzkukjp|lfrhsidginnprhfgpuiqomolgrvjsmishumkfrq~igwpvnogqpngcsnpmtompmipnwrmnmlmiklnjkhrpgqfwu~rqjqxllngpjpp}qzklhqnoqkmudjksjnmohuslgjmpomglodrjomjqkknmnhrlmopmoqpmmhjknoqkqt`ojpmlkjqepvsrnjpopogmhtoijjlkjcmmohojjiqpmrugjmgokmjvoolmqnqnrruotitfqqmgjlrpjojsipplnjonjnjomhmolnpneonkmpmiuqjpkpnknomqmlkmqpqhqvolrqkifmqdnllmnbomkqfqkkmkjopkunqklmmpjxlkxnnnnlomnvmgomppmiikmnuneskhrrsekmvkkwpppmo[iojq{nirylmmtkkfkikko`bnpoumilnjtmpiqkqnnkmjurrpsncmpmfuononkpmonlrmlonkoonnuunlomsogenvp_oommqYooppsjpVosnohqoxllqpjtpnrqmqkopoqlkailntoslollxnnnjpnpnnnfhnkpkir~puppkjompxelgpmpnmpnlomonloklpjmnojlo]onxorfnolnpqllmooqimnuoolrqwnmnmjjnZs\omonkmmfliotglhkcrlplfimoiqiojmokpniomikpdokiksrknnml}pgkfjkfekpvkmkooomlemyixqoilonjmkqhdlsofilugnvqmo`jmwk_prjnelsillhklpjijxptkkmhlskkioomihpiqioyhjjnonsoimkokqmhmnnjpmenlmgmllphjssljflrthjrnpkhq}njfpnqhhnpjdsnmqjlvqpsldprtusnyoomqhmklnqmqnorulojqowptqopnnmsugkmgsjmmlmmrprmcpkmqnipphorowlomnmofnhoprqnjmiiorgvpsrnjplrmtonnmpxqnvqfnlplipnowlpopkqyefnomrlmkisthmklqljpllqlphlthnnrjilvkrkm|klqmrmlrmpokprjmolnnloekmrmqprrpjtlnupmloppkm~hnnmpmnxtpplkmumtfqremslnofomjlmmkloiypxtkrlmjmlpqjmpprpmmslonrsovohojrlmmqnlnnvenlqlkekmkkqlkqnrqkljrplnomqlmusobtmonsokmmrwnrqpojkfddrslk`qoldmmfomookiolnonieiqnnol|wkmvloljrqkjhlucqkkvzojmpnqnlkqoejcnpgmfwqnoomrfmkornnoonulpnsnrlzmjorhoirliipsemnmullkiljmknVlehijulnlngfknkumronmjmilmxoxdupjuljnorsmpombmlonmnqvnlonjjmpjlhoorq{lnrlkmgolulwlnppfknon_qopnrjookmelnrpnenploonqinllnoyxnslm{ip`rtpmsopoolvimsommoophmgnromwmrmfnmmnnjqlsimtpmoknplnjopmnnotlopmupjxlkqk`splmplehrppipbo}vnindlhpmhomommklgnp`qnmnnlpsknorqn~nnovkmnnoji~nqkfnqnrqmpopnnoeksuvpkplkolnlkmsnpolnnmdmoppigompn{np^bijojincmqksipomropmkrsnommtlpnppompklmnjflinmlnqnmrnsurnmmmrttplj`omkxoomjsmripmloonm_kiomfimjrzwkrlpkpmtrqljqnmnixnppklkoxsnljwlkrkoqpormjpimhkmonpobi`loonmoumpsllouknmjoobqnkpnnpkinknrenkqlsmmlknllllkorpowpnhqnolnrZ]juilrmolqlmnrnnmmmonnlomgkqinolbko}mgkrsojgpklnrnimnntookmajnnmnpoeloiltqln[rnkmlnkookjnpjnp{olvksZjkxlpntmomjlmprqjnpinnbnpnkqqmfoxxnooqompanopcrnpnluoposqgmuppjniooloqglsvpmmsmpnopprnfiolookomnllpmrlhmppopivkmkmlmkdvtojllsmnnmjhrlllt[ljngqsnsnojioqplmrjhmkmmepoonnqnhmslmnnklqmn`mdkopommodmoormnpqpnmtqmgrfprnpvjlshqiwvhrfsjpqmnkhqlkrkliorllpsh{sjsojmkplnbjupplolrijth~jolqfkqmimllvfepiu{miognlstwdngpryhqtmqnjglkopnmgkssqupojfmodjlptvltjmwtormmjrnrkponqnlmffpnrkrluifgmhoknrmrnmqpioilmgsnmmkgvkmmofsoljqfcokqrgfspmplqnrqmoopllsl}ojnsloi~kklnjuljqmutnoliiggniolomoqprpjjmkokonrolprljpmnvmpnnopnimsoslipjqomqmnhn[kslpnomwknoljmlovmlmot\iosmmkukhqntqoqlkqt|nnoofqqjppspprulnnvpnjjimm_qnlpfiknkokjnlznimqnqojnopoophonkmpoptmnnklncxnltorzmnfogmkmojrrosjnsjlomnfqnmmonaevmnjmfqlkmlmrmnnlnnqmjllkdnpqonjomenopmleconlsnjqkdgjsrhenr_wljyfdliihxjkuerporrvkrsfgvmpnqvmttqhnjsjftj_jtossiriiiqtpsqqgvrglrerprnzmysurolgfsuvqlogpzstrgvmtkrfdpojqtoqmndpenlp{mnj`{luilnisjmqhqlcnpdodmiqmusjmjedtmpoukmlnmsmpbfniocpkonsjidmmjzgnkc``qrmojrkoppolodiklpnjpgomogcjigqg^msmms|qrygkklmtoosgopp`tomttinohnmmuhjxvvunooomohmugjggnrnmqfuqhnuqenqhjsmrjiknholrhpnmqntnrqillpotolknnspoknxkdpqnsspukipkoyjpjhkoklplmmmmonkkkbjpqnylprkvloqlnlmnutosnmumkmfrfjpmogpliqsprmpwp`kistovlkpbulnfkimm`jmislpmncvmjllnktnkijwjipiprgmidpokrlmjillnpmmqjpmrnrmlkomkpmznnrlpoqljnnhmkkloqhpilqtenofqogoppnllilnqhlnooijnt`mbcrpnionlgrponooqmpkolnx}litoqvdnt}orqpnemzqpisnkkvlmmmkhkdgoknjgodlprkdjnosqmlllmoonut|gognonsqojknnfmqomppnqlsnnjo`xjpmpnSowjjkknpi^uno_qonokgnqlklkmnliw^Tqm}onkqmnlsoqnlqlpmopm_pikmmnuqmvspprpxnluslorsijohlqbqnnphoq]poindilpnomkkloznswowvlkjuixtxfwojyltkjrsmppqenikplmtndtmgnmromdqpqnxoijoplpbpeoolrj}uarkerrnltr|xnnmpjtnkqplsskmodkppjilirpelmhkrrolotxn}ojoeqoqvysvlmlhkspylsoqnpnlpm{nkvogipxtqgnmnsnhoomskqpiphu\rnomyosroonlkrpqkutppihjsqqjjpgmorncmkib{oomotmqtoploojnopnjk~nsknnqjnmnnkpmoqpotmppmizqkwnsdnnqpnkm~hnnkjqmjholfn|bnm\qnovrpolqnprfksnxhomsvboonnpnrciopuenmjomomfsrnqjposntonkbvnmnplnnmmpppsnrlnlmoqrhnsmojprizmbnorkllkpnlnnhhqqhoqmqmmqlqvlqrpjqz^ienlerrfjlsluorlorokvooocnmplmkkonpirlnijkgrroiqlgjqoxhmlkskmmzmqnpmmmpvwmormqmqrpphimmrykposn`hlqlskoopuokohnnomqposommvnrqojvngtpkinlnnkjnlmsoqmpuigmqqmsqisknmganqnhnpkljpmnclfnnkpqpddiimrmnkhmmjmlnknrlnunrlkmmonpngmunmkmq\rjtqnjlnipo_jpqilsoknlokoolflctspooqrsmsmmmsksmlmrjnnwopnolpsonuuknqnpvanhngo{nqllkspuqvtjqmooojjexqkonomqjplgprpvntkrmqsoinelkmnocpilponlkponipmknmmk`luefdjqfttmmckkuqgrlstsqqkqomoilhsmmjlogkbmsojdrmlnqqsjnojtlrmocmpnmlnyjwpltkhljojhppsnxnsqpnsgsiqrpq~lwmcjvlnj`lsgopnmqmoononnngpreteedkpojmslqpnonrnnknsmjmkqdjwllqnrlhrtrkmksrjnpkrkrkloqjsmpprtlmslqumsemnonmsmgnotnnswdlmpoekpqsqplqzknkmpronnszmlmomnjloqjlhxonoqsmjjvioonmknqqhxlorjoinijlomukqmqypkoapyokpmoqnspmkinlnpngoponmhominomvlxqqpsqgqwormmpritjlvptnqnttprmmqrokokcmriqrrqruhmfotnomjnrsgmm^likkqonpllnmoqpnmmnmqojwqrvnleiooyklppjbnupmmgrksojpolmnsohqqooslmmgoojoopoorppmqibqvmlqpjvpdcrrnoopoopmoipmnqmootmfvndruekognlpopnszitscnomoiepqqpnlnpiqhrunlnmscosjnpqlohrolnowy|rlnjnipiggdqsmmnrnpoqjopqphmowwlpfql_lkwmmpnnpmigoj|mpnnjnonqjqomqleojriisnomqplosltlonmpnnqmgoslnnrlnm}xamonputnhgnopdgpghssmlnriflwgtspwafqpntlkdpnh|{hbhammjrtritxzigip`{jonPnqzxmnsjiljiprkpqoqtrmjk_nrllrsj\thmhPmtTkjf~ctuky|udjvh\osnojvrjqbprghuovrpeoksnmwsagkhtjnenYjptr{xionoomqiuppfpkrkjlimshmrpluetvjwlhrfjelkojpaohsuxql|trmrlpnlqsjintrq|njqiolptoqnsro}k^iNqsgnjtmpcqrbminhonmlenwnplrrjbqjkrrljjknmsmqkpojonkjrlfpupoonoyunnjqlohhnnljpnsnsrjhklmp~`vmnsirqskocqttolnjpnorsejqtpsmhrlkmttmkknnoqkgmiqqllolrelqvjnnsdkepgphogpmtnjljnmsjmkknpeqqpdjv_ohjmportvptkjppnrwojtpsovkqojhgnlonpwqfrmpoilkrknrpipmyqvkgoulqlqsnrkqmj[rmmrrVnpRqgesqlopikqorlommcmmmmhnqtoogrelksmwmnnmngjogknmgprltwjnkpmooiojprmpipohlrlu{qgtrlbkpkkmetllilajkonoglnjhnhnngkmmibkomviopvxkvnqnjtrqqebprskjqtntniljlhfhntoqcx`ptqkljrgmnpqqqhmgflhbbqrotolianozsmjnruirym{vonuklpkzkri_ukrisnqjqrumjueptqqkwrmmoqaiphowqrnnomll^kqmiontpkrqnd|ovpklnnhnrolxmlglgZklikllkxqanppipnvormiqlloppportftopklmuoolopoohwqsnnmr]nloqmhmqqphogprlrktnljpmowlopllglmYeluntlnphjpiornpqsmqmowdlnqgmmsxsmontmciloillqkkcineenoojvnmpqomprlgngknh`rniiknopnppokpnijmmgjrmlqo{ons}pnkqkiqpoolnnlmolrbllqfilpvjskgilimjolnbnipnkollilppqwombkjfpnqknoklnoqkktmhmplmnmipmliioijiditlnpornkknqjholnpohelpnmikkirmlqWmlinmimcjmmnhmrfnqqkld{shotlnnhnpspqpuolilnliopprlkbgxpcjnomionjtlmqjp~okorqqnkpnmlmocqhsmhwfvnblojqmpnqmqmjlrmjlqlmifqoilonmnglonqp]xllqzmrppgnyilln{tppxkontpfqoqknoikq`nlnknkiqorvojemonnwzpfpmotollosomrlpplmnkhnvpngkpposskxlmqnkmoWqsgmkspconkmmumqkjlmkurXlivnfdsjompkmmqnlmhnigmmonlpklpomkjnqirolxhlopnnrkjmnkkqilgqdnemmlswumqknplmrmmqmmnrqirmmnnoqhnmnmllimtmnmonroookiltnlqpplxitnlmjsxmomoifmpnoynkjmbnlrvplmojkpmkmnommnoonljjnloppvlrcmohju}tnnlmompoynnlnknnmoondngcpvskrq`hqoqnkjplorpoulntkknmkqmnmvnmonhnlnnsmkvmltrgqkjnkjlninzlmqqpndonpqmmnoonkonuhomktorirlnnokXpomqo{nmnshgrfkmlnklrmpenmplgqivtkmqzlnlpmhopnjmlqoqslonwenlpknoknlgmlrkruiqnhgpmngkoxknlprkqkrrmpkqjfoomlnmmsmmomuimolqopmpomprymmoouphnoosinvinpqssnjulnynqnolp`jormmrmqdmitgvlnjhhpnnlirnvdpjl{nispimnkllqoonklmollnppznnmkhmsjonmmpompmsnpgjjloppiijml]kpkm^owounnplmmojqjplnnjmlroqmpnkhlopiimrokporqcmollmnmpmmnsokpmiojnoxojoljmqyoqpromrlnroplnrgjqmoojmpnlwpmopnhxmvmonnpqtpnnnWmmqqrknzqx{jnnsnmnjsnqrennntnptobpqcfpjmknjqpnnopnolvwljmntoolmnmqkfokimooqmnmottoopzqilqqlon{rmogpmistpikmpqrnpmpmh_mtmtjlhnsdmmkoe{jqgmnmhkjpqnhmposynkslnnqoo_icopmhqohojnnjoioklnpqlpjpjjomqnjpne{]nqllypqhqksljqlmninpojonopnrnokokpslnnoxo`kmnnorrommhkllolyigqurbolokntousommnnnmoontmmoepoiginmrjpnln{ltpsfomjpumplhspnlkoktyqocqjjpgepnjjnikqilrooi]pmjlppkrmkkollsnhjnntwmmplpmfkrlrjpomskkrdnmmh{fmohemqlkhkprknjkrnvbnrlphomknnsqnnqonpnkmpnpmjfppgmkloslinrlqjoiirknpoauonokankfmjjgkjksgdpljlmqnnqtrmkm^kcnlgjkplej}mlmljplbkrlsnkpotdfmohwlkmgtfinmhppkgsmhnpmirkllmpfmzlmngqknprmf_bsnmrcjsfyokqsllodrkhgllnmimjrmnrmjlpessormnqlsdgmmtpnoklrdnsolgftginoh[qnhqptonlosmhvllyhmxqornoluiobonllkmpll`mioskfknonojqnsojrnnkknnkgofnlstilkqnmipmenioneksjkmqckqqjgkpgrjubqnolqwyq~cknhrfoXajtiroclehowjuonnpflmllwetrorytnripwlomiry`nngppgttgglzpjVh^dqufhphhsouqmnuksfutlipnpwflipiiurlsklke`kpkorpqhjlrqotWissrmuloomkgooj\pwliatkoklahmqimq|nrpmlgkivpomngpqxmrjqnyn]flki|lomwnrnmqj}qphdtmlnwkrmchljgnftpgotpxq^rpjkfpsnommkuhsukoneptqmorofkomfp_nshqksnmlujool\knpfnoonpqrjjo{nrwnnjjukmiirr}gjdrjhelklpsqmkonplrnmvkvookvojj{pfglkgspsooklkvxo^unqsvodpwsmjnurnohnqjkqonnekfksmuskjqiijmkononlsohrrvlvofdpvilqpmooturjmfjlkltjoqjqlsllnnrqtrmujonnvkiputnqjjslppgqpnkn`llkaorkoo|mnfdkzmloljujmojfrmekrarmymq}myrimolwrnmnlqononmrnitozplhjf}osmpmnmak\tgroolukqrnnmjnknvml`olflorstnnqoqmhknjnloajjoonotmhmnmmmkktooinlgalqmnqtsvnpnjiknwpglakoqlmdopllnlkoknkopkmqoj`pwwssqlnolmkwlolmklqmknmgslpsnlnnnexdnqzosmpkkhvkqnpnlslnlfpslksooppmppsplmoklzononomqpppqqpxllnmwwrr}nqpsoumhnmhghnmmpnokmohnlyqncygkjpnlqlwsgmhfopjryqnlopiloqnq`mpeqiolermnopokpmhornkmpqnyqlmnnngmmnomrmoro[kmqlonlk^gn}pozlomllulmlm`rpsvlnplhuqmmkornjrmmkrojqqoonljoqopolmooiqnotirpojnmknlpknjotystqnpsouklmvlvsomunpnfkpogbglqkkkukpnn^noofwimnjsiopmmonrwkgqmryqonn{kpbirnqjppkthmglrbomlmjloospzokmrgunnj^mhooqkgnrmmnaulrkqkoonkitkhnmptngllfqlknifoxqtiiloltoqojsrttkqqjskonovrqginmrosllpsojpmpvrg[jkoqksnimuokompnimojqisrrnlkoifmlnljmpjnrgjrprjuqrqjklskjooorhjgclnojolneklrithohfowkjonlpohoclriffhpk]lspoklponcq~iqdqojjpyopfknskinouhze`rohkqlnwlpzupnhjz|btplochmshlbkirmncejllokjlpjvkffsnhoonmjhsbjrnklnpemtlipmipjjnouoqkjijgoonlr~jghkroiinknfZkfokpejmqkopdqnfawmpnnqrlhjsmxonwmemgjppkgokmglpijkjtltruqhhptkpmcouosmnrylpqpfrmfillsomjpi[sinkmokotrufnoogjmpqlenmkoknlpmrrrfoltkqoqriplol|kulmpsmmnlqpmjliotrjjplfmpmouqqikpprkslousnloikplnoqoooplosomlrtsjmuoprpjnbsntrniqnnnjhpmkfmfinsnonhoisprknvqojolllmljoq_vomqpqhrfnnslpmrqoqplrwionloqllsmoouptikmmespmmmskntmpropnkloonpflpomjxnyqXllgnngmfmmpmlonhmpmogjrjqqohlxreqnorjgqvooolohkoonyYvsiclimportipnknsmlsgoimnolkirstmnkunrsgzllpchpgneljixlkmnhimnumponllnmjvmwlklmnilqjoqknpjpnixfnnjfodsqppkkopylupqhjmnuijxhnkfnfpmrmicnippknsfkfqmqhn|millkqmnqjpumnnngotopsmronhhffqtolgtimhmwmjmm{lkloknrmhpkniljppqpomvomqlmniolomnrlfolroiq\wjkfmmqmnqnnjnfqrmorropnlipnmlpi{tpoopqqmpokcjqomnjnoiplnqjmjmliscpnolklpnlml{mpulpmlp~pvrnkpqn`riolmomnunosntrokpionxtilftr{nxmjhgjmrnjqokknlnnkjmfnqnmmfsmvwipkpstoroonqnomnmmnplonpjjgldndprsjgkmknnmmgpgrelknjo}lkopmhkokpnjllhrrnonrrptokooomqqmmlomjnnrkpknmnojmpnqnomoolppllkllylliikmtnmjirnosppnngxwinlnjprtjpomjninslj}skwommmoforsklqkljklomysoimcmglnlmnknnoofonneomopohpmooikoglm{oowlmoikfohnlonmabmmnppuoqnoulxpr_mmmqnjpdnqkolnnpinnupnknhmdrnnzcqooshvmnlhundorxnjnphx\uo_omdmnmwkldldmlntikkerjsqutsukaunonpgplkpxbkhpmdkpxqqglsuumxgrj{d}uljrXnxrplkl^c}rjjqochlnlw^cwdiupnrllemtplorhjeiqqgkokjfimmpktfmpsgqmugqlpmkezoklghj]njcrgjjsqnqmgvtholupgxliouimqlmektoiq^jshinilrdq^_lnjkujrekrlnroljinltnkiiefhrskk_sqnvhhmuhrifmlijn]cgohmjpzr]rkmjnsntnimpmmqmkmpkojqqjowmphklqknnnnkonkbovridopgpglmrhqooloodg{sgpletglmrsoolrb`hqiqkj`\qjprhingmoksnnqgnqnsckckkqonummjnmjp^o_nhnrjnkleemrnhhmmiloerohgqdpnlfhlofmvlf\olphgrcpr~pxqqmnilknqlrrjdimlrrplnojgslspdqmmvoljruksksvk`nfqtlnopkkrndqejtpiklmoqhhqjrpnonkmoqmmoomllnmtossjvruekpcploininpmnukiojomioflj[ksontevnppnulolnlgoktlmjnhlmrpgqltnoflmrr]nmphfookqglrinpmnrhwidnnmqmolmpjomcmjosroqlpsmmomjjnphnbrnkhihtrlmfnkrlkprnoqgnpikllormunofslirkbqposlnnopimiuiplmmrhlrmhvmmmknnuopwlmskjqjmkl|pqsmkjmmwnnlfnhrnkunnogliknmmlmtqmkoirjskdovUokokmmoommjroppsllmlln_jn|iq}knwpskpnvuplXlnwltlqplemqmqpkngqhklqnnsoqkr|pmrqtmjjpmmnohrlmphmjocpqhnmmpplomssmsopkooqhtlomh`molppiqmnnstln_ppmmkommtspknjlnuv_rnzoksojmqhmpnlrmpmjmkrkvmjqluolbvfjjqlnnpcr_plmjmglvqvehpkncplkmnnbqlrnoktolnpkqtrolihfvqljjo{mjbmmilqennkixnumolstfqrijphgsmslhmorrjqfvhfqjutskpcrknpnoprmstmdegkqmtrlknsiioqlnzjnkknsnoukonqmvrnfnducgllqmqnrjtsnnnwionopemmnlpdwklqcpgisixjfjkimsnlntqmjsnmmnoqpjahuutpncsmhmh{ogmlnrhlhwuvmlzbqxuptslmmhtlqckmujjmjofnjjlpppqgbmlmkosoioonortpbmpfpskdohlerhfnclpdorqohdpmnlmnrngkfofpcoshntgjnqnopqmhojrkurfisrkljnbsmopmenpqmeiglriompijpmdllliqjrqupmnojsiolrrnonpnjkrjwnjnmgrjknqjqmclttrnffonkqnkppjgponilheqgmsnpernndfkzrqskqkckknipooycrfmpjxmloorodrppljmecqnkouuojmnvoqrtojpvkrl`lnomlskpmem_pmnpmjqlnofsjjilljpqm^onopohiltpqnomnmilmjoobogrpnilqokllpporiuqi[knppgnlqollnooloppkmSjdtjrmnlqjnkmloinncpplmfkjoksmnploqommkopflmpsrmkocho^prmru_nkrnonqmmuqmnmmvmnplohntjrmnloqpnnsqnnkpmpmrspmgsqntpkhmimhmmktnmnolommfhlhqiiqmpinqopinnmmknkmkemlxkmcgooolmjplipmknonfojinnill{lhmkpqopemvmlpqorlm{nrjrfqqm}npjksmliloautnnpl|qmnlfojmrlmnvogUontmnnopoznumnyjlo`linlomomeqmnnopmroskmomghkriqqjhpodjoioqddlimolsnlsoubmnjxknjononrsjuvijnlepqooqmloovjmtnltomnogqrpppltoumvpiklkdjvpkzlgltpeon]ojpowlgirrrk`tloqnzjaqmlhdcsdpstghhmfpolnehosmrlnpominosjjku_uomnlnnmgmtofklvptualjhckepfkjwvklrpihmppjo\zmomdsul`jorfnrsmnrknqshloforqjslggjrxksotqioljpnmYl_|menmimripqmheqqmimmspnldqumtxmlvprwkmrsjzhnjmntpn_ulmplnknkhusnlkjqkolourljkhxrmktfjvhzjrdonlms{nmgngpnjnmyfnvkojlmjjnsqnqqq_vmhkuqrprpjnk^nhfmfwsnmreotxrrornyljlrluugjontqoqoxneqtpjimnp{dqjhvmkknkonlljknqmhismmksljonmhkjihozmplhfqr}jumhlpnlgqvmosihhmflzflhqilpgrronnosksdnhqjqrkfnvsonrikflmnwlpexurihtktrsjlhmkmjkpjkrnhtjhmrdpljnnoerssojnpdkpqtqjjkkrimxuhoqmknooyunommrmiqndplmjjwofqnuqvmmdqdslrntfnmksj|or]qmthopmqvptpglrkktogmpvstzqlylokpoitjuwlmtemqnmjslzosqrjoklomnumsqkkiqnmkpwmojpphiwlltr|osnrirtjsnljmpfmkmmnrnosskuiumvpjpipmmjhymkohnsgtmngopqlproinugpnossjpgcrrqislqfpnmloknpjlmncmnyitsqq{xorrnxnmulhjmkxhmkgnpuqoommrqovslmnmlllpulgvfjhimitarqlogjomjluojshlnmjmotlntmqklvnnsjmptmljpjotuimmmennsrnfofmmn`skqo{nlqlqhohponjmokosfxijmlqmimreolpkjwshkgipiqlinlthnqpsxhmrlmseiinpmkfrtkpkriplkprgingiptwonrhkrkmenhntonmmipnijikmiiqpmvsmioypnhosqmvkjslqnlhwsmknvthihng_rlrrpgtumqojnqndkoqjh_gnpmtglhmimfjemikptinldl}urhgzlkkbliqppbmldjpftgmnp_qhjinvoqpsfpmxhpckgkvqlT_ptjohrnVkluhpnkkhojjilkermnolnlnopdqjlzomognymdljmpjjppqwnjnoolqnhmknkXklvpllrxonni`qopqokqmffppljmfjnptoqslmnqmocijhjohgjsquimrnnjkpom`lrkkjuqjuopgjiKinofxole_uolnnqlpeokanmgfjqojplubtqiekjlljlrbqpormzqiuobgoljtcunpknpYoqopanlzygjchjmkkr_lktae]lkqko\[ormqsdqlmjtfhonocoijzkvmmmmgjjrowiouroliwpuvqjqljlm{ghpmkjhjgmokpvpfr|`ljomhokk^nkicospfojznjkmmippp|nmonikuspxifpOsdsfotloupsnkykvsrtjvkjm{lwneohppjkpycnjwooujtnqrkqmkpokpkkqqawloonloonoiolmsmvnonqmomkeomlnhnplmqpkbrnlnlqmlooopnnmqpmjofnnpcmiinmoqlnqmj`krqitmjkpinjlqnpkmnosoflslntsqlpmoilpmykqkmvmlinqqkqlnqpkllskprqortmmpjpozojiomqlqphkfognikmfmmipnlpjmkxomyqijoqlomqkqjplmpqpqumstbkqrifmrl\rrllnkmlprnvqlllrnpjoauplomkniupksmojcdmirpiqhlptqo}ollnnimmqnwpltjoljlrmkorvmmosmkpp]pmvfmqnjnroklmgmlkonkdildkmbZolphgnpfkomsnnqmfqnkgjqilkmpmpohjopqpmssvngmpslnnlmmintopoqvnpdpohkompmjgrmvkpwtmpqjvZttoornthnkkhtswgqknkokmqmplmmikomlfvktnrmjlriolooq^rljjqnwtjmmpallh{pqemonzs^mpmtmnosoq|pmplqmmmpnrpnwoflmnloqovillnpjopmoqolvlisqkshpkuipkojlmkgmgpsnqpqknrohlunzjkuqdnjrmqhrkkhoooxlkpohjmrmpigovppynkngplmdsrnsjjziqfpwieotrvpnoqekmfloqqskjktlnpdmmrpoqovrihislqnimpurlpimp}pwrojtkmognqhkgkrggqpkpqmrivfnmhjmsknsmlkrmhcmlofomrqlsnrrnomoommn{rjknnlqnjnnphzmenlqniekthnmpkojmnsolwspjknplm`~jqmsk[\vminpnqmnodshyrlnnysoomtiphvmlptok|hnronnnqnunqnqompo~njkopnjqloqirnmnmlimomluonjlpolonoggekq_uklnmoknmjpaompldiooaonmnlntojnljfmktlngmtkulkontoklliltlnlmuon[kklmiofmqoojnnrlioornjnowgmhnhtmyqwqomoljmkvpojpklhrnjudohampphwsolkmkdqltoqmrnijmlhjkmkqkpplvomimpnronpip_jljoppmofpnlrmjrhnpsqpophrrpjfnkdolotqmooorunklorsookksmunovpvphhlsmlklpfuhmokhqrmnkmqvwonn}mpgpfopmonnpkoxqmhrkpkmpiklnnwqbolnonnnlnsprqmkqmmemnnlskqnsslmjmnqpqvcnnmp_slonymmmmmmmijpmlumqngompkkqpokpmmqQtmtplpnqoojgnpljmontlngtonoomklonfasignrlemmjmpnlp_mhnobmnni{oqnnpmo`folorqmqkorptnqlksmqknxlonkscnnonijnpkknpollgonjpmcjkioplmwnqtikjoolojqnnrohpno}mnomtmnoclninnnrpqooqlpmlnmoojopmoqnjnoopvwsnlqm{omgrhontrvssxnfimoosmpnk}knmojdknmmoprqmikmdnnwqfllkmjqqmkerfflntoi_t_lniurowrbnmlnrljdsndpprfskktononqoqjnqjogsrjkpumeinnujrjbhoposqhurrpinqrkehompepmmlfynqmjkqmzimknqmlolphotphlmjglnfhkk[ni\lskqromnopsbltltr`ntmogrlkzojiolvsllkslkllwsqlknikmksjrnonnwhfqumlininrtkmnqolsvqwhlnwnojrofnldjommpmrqrioostmqkmpmkkilovuhlonnjnojmumqonjnqmpqnsocpnnpijln_mfpsmpjh]jqlpmkpfipximnoobqhpknpoxrhjk{piYkngivtnhhblpmomphopsdsmkldosoojkonrnlumiqotollmnphllobrnnnsasnqfmo`qfqiuirqmppnm[mosrotozuktjmomeqmqmokiktmmorqqmdjomjlnlokdmqmofmdomqpmm{lqlq\ppeoijpqonoqkpprpnvnnpllappnlpoklnrrsmfojvhjvlqksrlosngookoponjmpn{qpmprlpkatfp`kqlmmmlojfhonpqyklmqkpoXrrpropj^pplptrppmoohrnopol}gtnmnmsmihlvmrjpprommlploojmirftenglppltlrnslnstquolyepnkmpoolplilqnqtiilnhmmppmmmunjlmmomqoqptqulohkdonf{voqnoqhssnmilopjojonolputhvkpoqrqijjqmmpmkkmupljtpznmsjmnqkmlmmtpomkohnlkoflrephpmvosqpmmlksugnqrommhesjkorimjoljrorqpkvhpjpnkpkgtuepiqnmkokloonnpdjknonomqokoklukliqtpjpnmnqurrrofwonrktrtqoloioolijgpqil_vjylmtlqypt~dpfoonqlkjpithyrllsfhonmosrhropnnwplnpltmlhmpmqmknmnhlolpmkpqurk{droorrnxqxomnflomjqpflpowlunfjl}mmrmojqhpgjohjqjmlpnmfqgmljijpsmmqiqroonjgojnpmnknqrrppimulqoqopllvnndbtoojpjqmnnpjioojrurfjlpsgrnnookmgqjiniphqlmnrrtpkhohuslkurktsjonuomoonxlqmlrslokmnoounhjjlmhojplmjqgfsmoolpmtlkopolqqkqorgppktnvmnlpnlmijpsmyjhcooqmonhmjepljvnkumkolpfrnqnpanitgyqim\pujoeizkli[jgjrtunofnqjmninlmrlqhkijnofglnsqnkollcglcgpmkoqlinhndjrjwoljullj^poqnnnhckklmpplxiojqrlmqorqumjmrgmdntkrjpjiiikqksgbmmfjnmmmhkormmimvkxnog`hvooipohj||kehmogqllthgulsnllonospmrmpohnfitmpoqm\kgiqpkeqgljinrqoonpmtojmkspqkwmrobdmjlnmnqsnozqnmrhnlgnormujhlnofkktqhplmikykpphnhtjqqrssnphu`nkom^vlroqyomnomonowjmipwdgqmqnmqjtnpssvmxnoqyoqijoppprmgpolmlkpqpogklrnlhnkrijrsilpqmqmlmlrmcnlrlmpiunaplojlrqnlrrqomnglhjnnlqornklkixoolnmmyrjqjojvmonkqmmllrqgihsixjjqljqvpjmzy{okmprjbpmjnftrmxhpqlmlngjmiobnldakulksxjqbsrnjiurlplzqqnjtxolitripporpomqlhfgnjxvqnqspnqvofnmfky|iukvsfjohkrdahmqsmqnsuomogomjwqq`jnjmrknn_mpgmzsotoxnkpgjukkilqdlojrosimojpvpqpenklpnmqnkpmtpsinennisum{plkipfkpn\ifplunxjohliltjltcpnnppnpotmwppnqmkkquotloxivmun{lounlfhrnnfuxwomlliljjqdripvrttckulnoqqkimcjkiklrploohmkjmprjslpnqqlrmr~hkojnnqskrfnijmhknttcuqnougeqjlupukqlmhvmqmnndiqnr|nirmlolokoqspptjlhjxncnhovfoqqjjehfvppnnkltnnqnnxnipnppughhoootmrsphypklmpmjpvrrpmktfgnoqnxrntjvliprlenmqmjlilhmoprpmnozopmnhnioosaonnfnlkroopknlonovpmrbqmnnpmpktppt{mqjpmljnmpwmntmpmqmigormmlkojkptq_mtfhurkwompmrnnqxftupclkpssoqjmljlZnngn`pmmnifjpsohpcnrmpmqqrecpnnkmitsqjqppmvqrnmtkvroqqknnfruqrpmnlmbjjyloopwvpunpjmjtcnlwrnlnuqkn~ejnqjpjppoltlmpkkjllnonhrpnmtojrpnqrqjnmnlirnfjpmqnmhkmplvglovmloojpnonjlnoip~oqopnilrnnppmqokjolkojpnfptnlqoonnpmomollpgnhgmqmgo|cglkppnpgklumkpomjowsonlrpn{umumoppukmgkphmmmjlwppvjpow[nnndkzlqlkojlnrmkmkqoedqjsjonsnpnnprnnsyhiqnmpokumfbemlswlomfonqnlwsingopmsnlpplqonnnmlnmjnmnrp_qlqnwon]smpmmkdimokvkapyjtokuumlrigmrmrosvjsqsonklkflulrrpqmomprtoipinoqdplxljpkmak^mtikpmpkmoqooivmpuonipmrmhmkgnkqppgmpjknmnupgqlilqlzenmprurhmrnhmjnrhinionkpklnronkrkkljrnklkorkmmkqmnputnmoiqolumnqqqrjof~pnmoitllnnkmthokimqnoiksqtotqaijnqhnnsmpnohkjnljppslijgm_qqokqjipjoopgkssxjjiokooilorpjkpmr|qoplpmkjjkukppjmllkkqrqvjinqnnloqodwlk|onon|qpjsohmnuhptlkkorpidokkmkrliuolnorloskmeptkmnmkxpjtmooqmmrnqmlnpmrrmiqpilqinltpnqrjkpwrwnnnihoqjqplirikgqltlrpmpmozoqotvnmjkonpfithmvusrjlllitmjppilmzkrmksq{tnnmvlnqnhxptlonkknelvxplmrlqqqjcg^lpkolp^lqUnpjwpknkfhoqqqqllinjopmcngdlzkimirlqonosuopnlspmfpnqvnhjurnsoigvqkqqnlglrin{nm{kwvjkomlhfmdlegrhoiko^lmpnuppkdthsloqkqnmhksgngi{okntpbopprmqmqqozsonhoqxsncqooXnngenbkiajmqmhlotoktnvgpumottmQnoznmiylfivkbjmqpnogrpnjhmpinkqhmpqolqkonoksmrotmkrmslpnqjemlgpfaejtknitmonogmnphrnjkpopknpmmq{rjflmqojxmjtppltpinepnrmnpmnlmmtiksmtlisouqoqovrlrnodtsokqmjnmnlmqsmmlhajjnqykmpkklpjorlioollpopnqrmmmponrnnjmnoimqoqppkomlrtmmgnorqsrlrvnjcqnpfpgokrskjjlcnnqpofwetoqk{tkfqlrpkmlymmnsnnkklmoigsoknmeokpjVsnlkmrkftkompgoloqrmpnxwopdbnnkwupngpniiommmopotorlsmpnviphqlqhpmllwulnjskoukxlpqroojlprpkvrkomlypphfreqlhqsmjtizpqtpm{irnupxuuulnopopnppsmokrjrjmoimqpklpljkrnnkqmpanlvnirmtnwohunpkolvmnzqwjl{rqmssprmqmvqorrrnkinplnkhmjstqtulmq`mnlqokqokksgqhnmvpsuulnomnuopjtnllpqqoqjqsjlvrupsqkhpqqomoqlsjjpmqelhsifkmmvnflnpmmo}rxnpkfl{dlnknpmssknmukpqppmpnpstoo|tlusxqsspslm`rruiopfkkqguhpjkqom^mnodnfimojmctpmlimnjyvsqohqmlnmruoomrmvnlmjgwltpquprqyprpmnljolnpiknnunmtmkqptnpthrrraloumplnkwpyhnjvpoqoppmkoulvdlqqqwmleknjrp{tpweomnf\nrm`nptkvoqpomi{emogvoniqsqlkmofmhjpunostmgrgqqostnsmiswiqqnvqlkgl|lh_omlhkqljyjtmnkgnolmOlrkppuimimghqpzkcklqqcqmflmshtimomnmlspnkmlpsoilmlsplrullqrvphkrqthnkqrhojpilhol`jsmlohqjqkqimomlokomnfnfmqhrhpprpjqiqhqgqmlpgnmdvulihulowhrpwisrmrlsvooitngjkphpmiinkmdkpntqinjprydmhejqvlknbrskmskoqnjjlxhlurvmmfotgihuoqoopidhpjmonxjlnjgngnoltklfspgplvrmln}nbhjollkoufxhlg~noqhinxmnoqpwlfrjgnhjllmjopnlrqmhnooioukppmlrlpkhrgotnonsdsqyqokkspmorqmtmwwpeunrurpngpsqogkpmllhom|dnclloookkhpjhvljiljxrmnnprlmrjodiqptitquphlpopopnckf|jpmkfvmqnqimqanoksknnlvulnwojlmmijipmqoppzmssmnlsqnginremhn_onfitqlmjlmhjmij{fjjsuyp{oorrklneud}nnrdgltpqnkmnjmio\mnngjn|lkluokriqgklpcbmzninllgionnjlmnhnolkjdmnrjjkrvq{tiing~sifknohthllVljnkoknlfknpsorlggthicnmrnolmhnoolmmoihmolvjfkgmfpnovhlosbroktlsepjol^mlltpmmm_nmmprjnttipnugmsmmoppxlnonjsp|monlxWnphiknxmtoinomkpklrlo~nbqldbhherusfounomtkqrtmlmjptjnpjloqqoimlogjorhnhZpmjpkkpnilppycdonlqcpjlokoplkporolrhjmnknloxszrlmpow}qvhmnkkrnonlnpnmhnljpolpoyqo{|libmllolnqqnjooqmociok}w`jknklrkvkpkrpqofpmmvpmkijolgomkoqlojnqljqnkphqpnrnqopojmmpklnlttpjojimrvrngnmlpnnmktnppynnlimpopgwlufhmjmolkoonmmplmpnponkkvpsoloikerqosirnslmoporlpnppptqknomeqlnmdpfn{nnlppopknnkkklumknhlptlvnppoimfnysopnpprongtplinmrollrsihoorhiopokplnloklkmkmommrqknoekminjmqomhqwoloqqhkmlokuoqqnpooonmmknmppnniwqmlpnmgjlmmmnpupphmspkmmpovnnnsjppoqlllnpkouklnmqklkkjqunpurppprslmlnomgqmmolpqcqrkpqnymmumnqqpknnkrpsooqnjljnhtnpmlnqlonkskrqlonljokomnomjonnkqprmmjopomlnmpjiollomoqqmoppooojpmpnrliprgnulpknrqornnnrppzmmonooskpmoknskmhpnostpjomlonomspsngqpqponojklqtpqnrmroijkonnplnlppmlmjloljnltmlnqptuk^kpnqnnmrtnltnppnpnnkkhmsnkkkloppooonolpogmlkmrqmsolpkqopiliiflmnsnqirvlkommkplploomlnpkminonsopmlpnoiolprnqfmnntjssnomlnqqnynknppomjrlrlxojhmqllmplmomoonlnrrltsphojnommolnppojrnmqqktmnonmnmnrponqoioooqpjue[lloqlkjnylmjorpkjglmllpqlrvtujnijmjopjliokhptlmknkfrbrlolhnoqdmlmmhrsrlnlhopzporqcq|pjkrnhioskortqqmmh|\pnllmgsplomjqqrppojtqlojdonjhpmifmpnriqmonuklerumormmkgdqqspojnlhpvvsqomgspmfepntmsknhrqplnmipolnoonqipppijasmmlmohphqnlrmpmlsshpnpllneprapnnnojkoiqntghompnmlhh|nqqynnrkjmkkloemxlmhqnomlsmaorllnpikqjejihsctmoroelokokopqiommimqllckpomgjpqsjsptoilmjmnohnkmhpkqilnngpnmjxdlwoonqlkqjmnnhomgjmonlmrodmnqpklpnrmlsuqjpmqmqrqojnjjssmjklkmmlommqhmoji_opnkhojnyjlnmqpgrlmxmntlriwmqoopnlkqosiljsnomomliiqqlonjlfkjlinelmoqnodomodrpfnorso^soirnopstrsmvrkwomvjnhjiqphmnhogfmokjmkonmmommoppqpkmromor}tnqqxs}qkijpngdqeilrtmimxvckfklmmllkpknnlnmilknfrjkmommkqokpnlruinh|pppnktulmomrimfllmrnmmqfknkqnlskllpnvqiwlkkovqqonhkmismodmiogrmron^phqgrnpqmpnnqymmkkjefqokoojokkkoljnemnqnimnkmkpqppoomsnnmmoonllqimmrqkonkopspkmmktnpolonqllkpqqlnuoqnljnjnlmmonnlpoikonirmvphsjpplmqlmmmnqonolkplookqnloppnprnspkpndkoolqmoqoqpplqlkrnlmknoplnnoninopqnnstmllknrjmmooqonmmmqnuqnqsdlmm`lmpkmvmornnpikk{lornnotnrpnmlonnnoqnoqnootljnnonmplxltlpjkloomosmmpmkmdootserssokglnjgukokomdqnvomoqusjqmjgpnsmqskpoqigqgemponmjmtvgjomrlnkmiqonldiowoqmqlrkujqtlpcmkrlpqonqfsnqonlfxplllrlqvrjtkrnoqsloonqqmfoimsngmlnpnmkpwjhmordjpnmlmpmmkrovnlvnnmsvooblntmqihlnkmkmsjkjkpcsrheorslmirpnqlljmqnnpplmmksnvplmhkloknrqrrkmjooimjrplnpjolnrponcnonqmkpplpmmuhnnnqlluklonmosnplmsnrhmprlnnppnohmomlknnnollrnntonuiroodlmlorlmkrjhnoonpmlqqphklnmopoljrlsmrjlnlnnlmoifonoopolunnplpkqmpkmrnpplnoompnnmnpmotqjovrrhojptslnmnsslokcrlqtumnlomljlklkttkpmtmmqnljlgnrompmpnlnmjllqolnlmnrldojmjpnlpmwolmkmnsjnqplnmpkorlmlnlomnpoprolmopmlnnonppjprjkriupommmrnlnmnlnntlflplrnoonoqmopnlqtpprjnuopioillmlmmqjnoljmnnoiqiloonmpkmonnmojhpoepqooolkrposkllqpnjpqmnlipkmooqpolonnblmpklopojlplopmrnvfmo_nkkoqommklkmqrkjohlootrnrnmnogmolpmnnkrloomnnjmljnnopmpljjsqmqpnmlllfnlio|fnhapjjnmnpniqqqklnojoqkokdnpqnimisippnookhokqmmkmnmknmmqpkpnjrmqpokomktsmrhkmjstkplmujifqpcsmroopititmpgvgpmkqnmtmiooqolpklqjqkonqtotruoltkkjmmomeroklimpmtklhrnrjnqmoqinppsmpfgmroslrqijpnnpthkgjrvrklriqjml_nnomklnjkrlipionrsoqwnnpnqclpmkoqmogkloqjyfopl{rmkdnjzeoikyksjkijlmmsrf_qt|npnomnkluqoykpcnmlvlnpplworkqhroegpjlnijkh|inllmuixqWoqm`nyohyVrjjuvllinomuxwntglnnnlmjWnuilsfinjrulnkfotnnqnyrcttjfhhndhugsprjvpoohtlvoseqozlZkgoktloqlkmvmhsppegnilqlomop`iqajzjyiqwts^urujl|ipjpkqpitvppsr]spqntompdrgmknlsnmqojljjllmomnpqqnlmiollnonnrkmmnlnvpkkrkkkpmlhmojnpnkqmopkmkoprnpmpe|mluqjqkpimnnpmmlrfmwpjlqqhsknomrpqkmljbptkkqpornnlpnmyjmmnqoogrknuosjinpsnrokpinlllqnjlmknqlonnqlomniqipprmmmldnromksnoinomrnonjgrqornsmjqlpnilkomonoonnqonmjjnlqompojsolnllgsnnpmylkojmpnlnleompwnmjlkllnjrnnwtmhsknlskproikrpprlftjmrlagmiwopkpknko|nrjuppsmjoomnjfkipilmprmnosunrlminkkrqjloiqbmjejnlnmmkpvoennptmoinmklmkqrlnnnqrpommiknnjeqooplypolnmqgnko|lsmlloormnmmhnmohwwiknonokllsmjjkinfitjkrmolmiqqnilmrqohinkkkmimkinmpnozkomnolmkkimmqmmmniglllpynqqolpqlnmkmqokm{rnpmmgooinqoiomsejnltnntlpljlopmoojoooqilhjnqnylnnjoornoooljlso^imxrrppugpvlnbwlqmojimnqinpkgrqovulnngioqnsjjlnnnqplkpnhrkklmvjtliljnhkuwkplkomqshqjmhonpolgkpljnjmjkrulqighskjsmoqnimpmqguloniqmmnumokkslpnoeqmnlklqnqkmsoippkpjkmmglojkotritqmqniopqomipjjiskivnokrooltqnmjgmnmspimmptiphdpronjpnlknllvhpknkjolnkuppkkqnrtnljsrrglook\poulompnsolkjopkkqklqopohornkwmlkiljieelknpmlljoguloomlmocoogbkjmprqpkolrqlopmjumnqymvtnqkmillonrpnnlrmpokojiinkiwtonnjorpmhoqlgqroqtjnjrtnprlnsllooninvkpnknmnjtopqgppmkolmnmjmnknolpomroklnpllpnmuroklqopnhlmjnmkiomowlmgklommhonlonmimfnigklmpmkomlmnylnoqnousqplnjkoqmpkioooqokmnojnoooovmllnhpymplmomhkdllgmnlinqplomvinommlpholmtqlinrtpnqmnliipniglpqolpmlnqohkmmkms|lkhnnsnnnmnpommnonnmlnnnompnokmpmomllplpqtllkmklokqjpmtnhonotolktjnhmnmnnomlrolnpooomornmliooponlpprlmkgpmmppmpmpknmlootmlqokmrkphoprqpmmrjslljjnkiqgmjomhrmpomjljonromplrnmoktooolnnmmamjnnnnnmvokoonmmlnmpoodlnmnlnokhrmeopsmliuoponmlutpmrlmnqjoomfpqmmolkkckpionnqopokuprnommnwomnmqmlnrpnlnblomnprqmnlplouislluuonmjojhqmkjnnmipsklkkpkqmkmmlmmnoktkmsrmlrqtsqumimkrmjqsm{ilmqqmjovmgjoknirspnkmmokjovlnnroolnepoopjgtkjmiohijlwlnmnonmluipnimmpmrmrkkmjntnkqtinqopjinnrmvminmkllvmjonqhknohmmiomloprikxnltpqhmkuhminqltnsononmmppromvnimmnppmomjiklqjokpmqkqnpncfpplnkmlklpypnkmfsigoilfksnmnmnllloqnlmuimiqllonoprgstmhunusjxlneqnonmbnsnrlrppkplopmpsj^optmlljljolkjtjvpojwhkooljmmnlnkkkpkokiokrsmnplikvjjlhniqqldorhqlvpllqinxkwkmljsokhmqoiqhpnkmsummkmhpipshqjxknwkekqknkxqirnmgnmltqonolxkpintnomqlruljllqpmnrllplnjmqtkinniqnqkruqndkmnpquqo^oljeqorpnrrospdkjjrolniohnmrpirpkmpmsnhnmkqqoonoktqhxrmopkjorqtiomprloqpmnjpunjlimxohopngnfhlhqljlomkqmommiknnkqlntopieqmwklononokpmmnoiskhpanikdmmlmollgoomqopqldollnqjnpnuhmqupmnqnmoqnuotrqrpZpjohkknoieqlntqn`nnrnqmnqokpkhkmkisnlpmqsnphmnlvplrlpmnrlnrmhpml`plonrnopknmnihnglknpnpoonlkpojpqjlopiluqijlolkqhnoovlonmlnnmfnpmnlnidmmmomkkntqmpbhpmouonkplqrnnrnloylnvnmomrknlokmtprmnlmhmupornkmlmnjonnmmjqoolhomonmnpvmlniprvompojtonlpoxnmjqnnrmsmpqmmnnnpsrnnpoppolonmjpomnnkonkmmnoplrmrnmmlupnnkmnnjnnqolrominopqhopoblnp^minjzqlplnoljlonmnpoogovjsppplpmmluoutmkqmnoknmmsnlqogkqvlmrjnrhioqqyqketojljiqplnoljmmmoflmkppmmpnolpprolpkonknjjlhipjnqpsploqnrmnokpmnvqsnlqlqnpnnoqtnoolmptqqujkpoqndqkjnplfmqhmjpjtrnjjnpkrmuinmnphnpllikprstomkoknpsrsjlkkonrkmjnqlouqqokmmrghnnnlsuhthqsorrkuhznsnfikplkpljpvpqprfsjsugmnpph{njkphqqpllilmonrjjmqnorlqopjdqpqngoapplilvi{sionmsjsqkaqspvlnigltlljumqslngjmqjkimrhjlllimqpgbglqmhqnnlrpkkemramlifusloprkchngjroqummklqlrhrnlmliqmxpoeljjpkdlgnioWplmnojhohinumgpmqgknqloolrmqhpriiglmp{oupqrentfinorwkmlrqpnqwtqujomostkmiioqlpungmjsyjqjhntjpvksisoquroorhpoqnjoromqonjnknmklaontyjfqrthkkprpjlrlkkrrifpofstpopqni}rnhtmjrmolnpmsipqcloujolsljilovndpikonhpnomnrmsooumiqpkskwqmlqjopzjrmkespnjpkojnkqoolhdpmuvjnvuppwnmpmkmwonlvqsqimonoqpomorfnmmloprnplnpgspptfnlqp^hhcpklr}xqponqkoimjnrpqgmlhojnntommjnhomriwomopluosjrqorpkpponmoloikqkmklojnnphshcpjonpelnoipjhjmpnyrekpomoromonkokmnjknldovnmemknhnntrplqrpppnqlnnmdnrotpqlqmpaovpmqwnsnrnmngoiknommjpmsvkjfmqqplnorklrwqqmhknomvhmsrupruvopvjjolqqjltipnkpwpmnwwgrpopmnlionopsmookonqkoqonnqqkqmmnqqninkjlpnkofqkwrnhpnmpnpmjklgmqpmlnnpkmoioqmpnfoyptnnnomlomoirmqnqpplpnpmliqolowkmkomfolnkmoknlrmqlrksnqnntnjoimkimmnmolqnnohconnimnhqgldnnkmsqjlqonrmrfpkiolmmkqnlloppmkqpohkqqknomnlnofllllnnmooppqntnnsnunmlvrpirngogmmformsknrpokppopoujjohmpnpmjlmlllpplonmqjromlmnrlmomlyttipmlonojijlknrollononnxfmmpopkrmnjmqqmqtntldmlmrorplrlnjmhmomhkuonljnnqkonoqorlojmnmphqkmnoktkprjntnrrklrlnhqoonnmkqnspxlnunpxknokoqnmukmnilunkmmpnqrlllntmoerhhpopoqmknmnomqnkoppojmknnmoqmmpiyrpqqliijnmrolqjlukqymjkkpsmokngnloriomkptqlolpuophlnnqngsmojhmmuknnqrpmtmjnnlkmqoqkmokkloqlntwqqikmlqlfjtskinlpsbpjphnrlillmprpjrynnjhntoqkpnmqkpkmnlpnnkoksnpqmnfgquojofnklkmpoosjompoqmpknlpksngmslpwtmojshmpktsltmslkoqlthrhppngkrooglvrkepqqoikymrnlsjnipqoknjnpjlnpnonnlpimqnk\mjmvkkptmltiiklltkqv{psjlmsumdpommio`onlflfiqpoqnslilekrikrnjkliplnohiptqiqqimkmnkunxi]orljcZpantqinimpqkbohmnpjmqqpnnnjkqmgqlgmnkjlkofslej\iotmnppq{tiqpqomfepknnumm{sjlppjklnqqpjoomjkgotqojsirhqojromommm|nxwpmkwmnitpnvnquhkircpiiupmjrrmpmnlslnhnrlnnoogjplmlqmmspolqpojlipmnppmmppoospmnnlqqokmjimlopoamkmmnlinlnmmnnooqlmqokhpopnmrlkulonoqmtknkqqnnnipolpoonmplnokqqmnnlwqnipomjlsmkkkomqlrmmpkppuklnlpnmmlnonpumnknnllpqnokolmnjrlpmnnhoqhllsrnsnsgmlrlmqmmmhkoirkuooponkluoqmnloqmoonijqqnmnmnopjkpnolrmomniorrllnsklnnjqgmhlmnolqwnkkknmmjonlqimnjsoilnsnmlqsnmonnolminmosnoonkppnqqolooqolojmsqpmojnlniomrulnlnmwpplinoloqpmlkilipomnkhpligonnonlnnomlmknnqpokooopnmcnknnomnkplmlopnqmmqrlkntkjqknomljoompkknlomonpqnipmpktnqnoonlimsrolqoplnmknlnnmqqplotpoptiljmprkkrmnlohh`{ploomlxlhmwkqpkogpiripinglflngcqgoootp~qikhqipdmjirmlnnwihomhrmmismlmoimnllikrplkojp^muqgpxispsudnklorklpbknmgjnolqoogonj|jlnkywnlvtqoqfmrgllrpenvzmwkrlki|ohnmjkdoqoklpopmnsefninbklqfkijidlmmolgjmhmqaoppkpljuljmoklpbnuvnrldqoipk|grrikrlliqxokmlkojnik}iiojjrenmlklmuookoogmmpilmormomnoqdinojouxnimmpnnuopmokfqnnphlqcqljooppthenpnnqmpmqcpkmrmjnnprhmpjobomqmkzotmmqmdkmpqmhoyoslhomkqzjmjotkonillmolgminiooomgnlpkjmjllgnsurrluppqlllftomnmjmrtkjmeknoqmopcmpjmnjighjpsonkmksjmujnlqmmpmkpjqjmmhponmorsjkkgheonfrmppsjvkioomqmnppjloijjljomngrqnpimssmujmppmhpnjponotqjolivmnjqilkgrjonpoholplmlpqnpvqmqoohnnoqkmgomoouljjpnhnoqlllpfoonpnmoknorqomn`hokppmphhnqptislmlrmnsmlijqpwvjrmpogqphlwmlgnjsvhhlmonmhlnqhlrqlknpqnohrppqmlwlprmmnnqmmqlkontnslqnllmprnimqnonopirpmmijhqlniihoorslvlhmhljsepkiujuopqmkkimfvlhlirrnsqkvqqhrkphcqcinjhlprpkns|mrnmhrqfpipmdprnnuimnjskmqkfq~edoqwkspnmnminulpprnnns{priokukmpiljhlkukkptnqtrlkonlsvplmojjnunnilonilumtoppdkmnqmnqtnejoprrqhwxljpohmwmljmrqntksnkfpnostgmqinpmkmotkrsykrplrnstriifsmogmplqmtmonmkmrnjppjiofpklooofjkrlm{pnpnpmoomoqmjimlqqopqpikqrokhjpojphnnrloooqlndojirkmfnrmmlhlmpnrhrmsmpmmoflkmhnirolkqlkwmkiqjqrosjplmpplmmnkolssrmrqnjskloqlnlmnpmmnnpionmmmqmonjinllomljpnmppoonokgljnnolmmknmmmjojljohmhmmpknoenknnmojmnnoblosomokommloopolorkrqtomopmnllnglljqlrypsqoquoqowmtlhhofjmrrfpompjjqxpklpkqllvpiutlqovkqmkilngroojlnnrjgkioqjjmowhusrldlopl|anmpfeujogpoiwsoomqgmxmrgolprk~lonttkqoqpknqtnoimkrpqlumdnpooqqmnjrlmloqokrjonkssllrfplmnemj_qjrldqlm_nosopseqmprlskmqmvaljmromlrnomjnfnropmmpnjononpolkjlkmklqhrpnudsrmoltjjmlrektonomlllkmqmtoklkkkillqpnvno|mokqgirqsjgmtmgmrqqmpcmnsmkkdholpikmlhmtnqqkkguljnktrlnolojoopjmqjxjhkonpnsokothpppgtompnonnlpioponimxokrtlpqlxulkmjqqlnootspmphppfnvjlmqosskoujnlocmthkpjipmmsoqvllrlomkqulrgjmpnppqsjjoininnjndkdilkrnppmpmomhnknlingknrllsqkkxqpmhontmmppgpooqmvplmmmoeltmpo`llhqgvorqnikpoonrjoloomikqkrjppmmlgevuqnidqnjmnjznnkofbntnmimcarqnqrflmmjlgtokjnjnnktmffnfsmyepmqkknplgilnnnkllnmkwunnpwkjqlnqnglposcltrkhccdmosmojgllkptlpsfmpnphwpplonmtnpnonoppnoslmiloknplkmwjhlkjdppqrfoilqpjphnhmmmlpopolomokmlmwkoolmnonlpqomeqpwmpnqp}omqkikinooklnkolmnmmponomtroxinjlomrnntmqeojqmommsrlljmpoqoplnmlxmobolmnppnqmtoojopmmnuomloyooonnoolomjonmlmomlnlltmrlqlpskprnmpdoomonomnoqplllmkunlppmtojriluolprpoonmnoonpnqmomoonpbmlpnmpgnmrmwslqmlhmppllpsqgomjnimoyhopqsrofrooknhkmommqhcmjbnpoolt|mlrmipojpnpkpkmkpmvrmmlnmomnoroksmlnxqnoq_mdlwlhqjrnlhjlgpnpsqukomrornjmpskqinkphbnjolwknjirnrlogprnmimujjtspodkhqlltjjlnjiqwsixmohpnrkrlkmqtqeukggkpqqopswdqyoqkpqnlemjkgqprpinuolirokjssroremqmgmrjmmlinkkjklrknobvolimokjqpppqkfsplmojjaqnjpmhhkiqiqvohpquiqunlgmonwumdklonmbpuogkmmoopeslomqn`jqtn[iknYpqmdm|gwnmxzjinljmnvjllo^njoutolmhplvjllnvuki}yloljnnkpoinim{wmlslpoymopnpnpkolqlfjwlokohankqjtplmqfjjijnlnmsookzsetnnllmprp~msmojnfrnnmpjkpjiiiouqmomohng{nmpjorkepemklklkmophrpzkopriqcjohlnpktpunlkqlliehlfnlooqqngpomlmkmnmqnoqqljlliulhmmohppmoojrmtnhmkguiwpnn_jlnklcokpqkhpniknljnopnggjokpmt~srqronpnmosmpnqnoqkmlkmjqpodmxoronvvkinpktqloqwkoskkklkkjgljmlpofmqonketblcknormpoosoqqzehlmsmtkqmnonkhklonqlonliipqmp[oloqooatsrlsqniqokogmoqqnnrppokjkoonunmnonmonpksnjtmlookgnlnqrnpapkmmgrpmmknlkqlolknndoqoonotoojopnllpozmrrnnrkrnmnnnknlukpqinkgpklplmnpoomlijrjol^hvmmomopnpopmmoolorjnnhxljpktotgrmenl{msthpqlopnlqqmjonrmjmmnqnmjmjqmloknllsopnnlpnmhnkmmmlmpojqospxmulnplomnqpiskinelhjqmmplmkknsilupqmnnolnlnknkrlolknhtnnnnlhsmstprrhlsohmnqsomnmonbmwpmnknlmnqmmtokrlkmnmklommjpykrnqsenpqrmormnovnovrnjlognpqpnpppmqlkjqmlkknmnkoqsinlmmmmlpqrolqrjuslkinppompor|olomoelntmmlllomonosilnhlmomiiwtwlqoktmmonkponnnllmjjoppuwnrnmnpknjikpknqhgjmrqpmjsjjhlrpngshskmolljmvssnimkmmkqqdnpoqkmllxmpupiiogrell|tnpqokpjrlnkujruupflkhtvqnnvenmismgcussjdfnp`ljgptuppmrkcjqrpqktnnsgimftiirppfnhjemmertqfjopqhlq^qhm]kmloirrfnrbkuownq|otmntqsiqgqnmnmmpvmkmnsqfmnpkkrnloohunbpjwszomjonlmnhulrr{rnepllsopqssnlqkqrongposgqkplqgpkkokmjhpilokorqomkmusmmkpmmoqnnkulnmmrmnlmlokkhmnqqjemronmpkumogpmqnsonsknpmolpsimgpppdrnnpknkqdpwrpokqkinnlhporojollmrnjsnkoilj`npmpnnmjlmvksnllmgopkjijnolllknllqkoskeutmljnwjmllvwhlknpijpohmpnmwiokxmslpnnlkqnojkoogmpmnonpnnnlmnopmhshoktlhijuknpknlpmbhpmoqjklpojmqoncnnnmnkhlrqllmolmmnpownjppmounrqinnjknmnhllmmmjpnonnpnmmkqkilmlsmnonlmonpvlmnonplgpmnrklo`pqkljrmtmmnlmvlnnpkqjoonnoocpmnslolnmnrjqmominkkqhhnmpjjoxomnnjnnnlneoinomjnmokomlnqoinpimmqlmjfnoqqphlnmlpkoinpmlkmltkpnopsloionloepkllpnnqlkoippjnnlumlmonllohmlnjlrtjnpnmmkogrlmlnnmlnjnwogonmlhhmoimknomlolmmsluqnljonlmnvmrpoqgrnnlnpmlmhnptnnommjhmsqpzkmmsnkkssnpmkrqkkmqpnnjhjjmknqijlnqmmjknmplnmgpgokoqiwopnmmlrrmnllfflkrskponwkoqkneopoomqnrovopjjpvrptkmsplsmmojwnhkpmopqmnlmpvmpjmlnnipnlsppopkilhknusknqkpkohnnnqpkmnmolmqmkmqmofmilnoskqoqinmkrpomqknpqmrlpommpomojimnnnnnpmogorlkstnjsjppqmmlvknimolqrsllnminlukqmnqmktnkinnllpnnlpnmjnkmloponnnnngonmnmoopklqkqqlkmmpppjolmgpokoplvnnjomopmsofmnmnpmnoqnnknmqmvtrpmnnnroqsrlnpoponmukmpsroqmkrroojqllllooloqpopkjnjpnlomnorppqolnhnopojrmmlpmlnkompmqmmrismgkkinmfmliorknlmlmmnhlsoqnrolllnlmpiqwnssoplnolohqookrnoklmjlmpgrlmnhlmcnnipglppqmonioqeomlsoksltmoonlylnlomoprnmipoggrqohmipmoozlpglkllppqmqnqhjhfppmqpiojmmkinqeqjmunmopprnporjlmpodooopoqsnqihonkqlloqpjnmmnikookpmmpnlonskdnmpbnmlljkljmrmnlsmppooplnnkojnpntlorolhur{mqkhomkqpmqvpokmlmlinjllnnkqhkqnpnnkmnqpntomoljuqptkokmlqnomjkmjsjrqmeppqmkjhjpmjlmmpxknlnhlgjnknonmolqimpdlgjmkkpqpmntoqqmmlqljnnrhjtnmlgnrlugnmgqnlmhonqnwmlknnomllmqmpookmmipokqgpnpnprnoemllpkmmfnlkomunnqnroompmolmnlrnolpnjrknmiiplomomriqqpksnolqkmqnjosgqjktnoojpmrjqlmmsonhminqjomppstpooooplrporppllqtskollmonlonnmomnummnmojnokomjomnlolipgnntllpopnqmnnqmonnrlllmkpopoxnolknqemhjrkmmnmkonrkfomnnotnklpmrloocgnqpkrmmnnokrpnlnllnmlmnoklommopolptlpplrnommkjljjhpmplnmjnilknsknkootmmrqmneuppnmmlmphmnlmnqpponkpqjj{olmsnonlknsomoppnmmjnrlmppmnnsponmnqlnmrommqkolsvplnpthnorqnkirntnnnnmompnmmeoppmqllkrromluooorqmoolopqmlmsrmnnpongqqploolmjjnnkpnkjnfksqnmonlipkionmnmomholongopnknqmolrnoknnqnnqarjomjlnomokrlpnrqtnrlokukjuokqllrmvgnekpjoqnrqmpomfiiplilkormznnqrolknnomvipjjniololpjongokmlrjoiogknkrkkpnswmhqkkpmlsflkokwrtllqnmeplnql`emrsvoolgjlslirtvnlhmpoknkkollnmmfnyxmunlnnijonpomigpsmrnnnnnooilkjmnqinqelfnovoptnlihtgnqllsknomnennolnjlkoprpmrpmpslokyhioqmqtntkvolmmkkhlgqrlonppnjoohmntpomokljkmnonsnqkonlpmpnpnmnokokppppogncmolmopkwkmqonqnoppmkosfqovmnlmqrmmnoolnmeqzrkjksvmmlljrposmlkjmolqlsnhpknojnjgmllojpwqnnppmlnnhlolmiopmokppomopnqmftooynqmpulrolqoqisumoxjlsqmqmooqnokrmilmmiomimmpmnmpllmmommlonmhmkllqpjoleknlolgfmnommpqmpolqkwojkiiktgmltqmoqjolpmknppllkokxnlroqrqqsulhymrpmfqqnijrnqqqmnooonjnqmojpflnuummmkiormrpktpkphaimnpekrpspnnhrrotqiqymnmmkhlmqoojnotljlmnipulolikpmpqjnqopnjorpijhmmnshlvopmqonnnljqmnnmolcipkolhskktrtosjqmmpsohppltplrqwnnnkopmmeunhknnnlsjkxjpnprnoikumkx~mkij|kjmhopnjmlpjnkprnnotpnryopti~rmpjmqngiprpqoftsbonqmoijogmrjnibokonnmpkbrlqnjrgj\qmpulsljrpmovrngtttunmpbqspnpsooopnpnijoZlncitlqhelprohlntmsjowmtigrjoflurjnhsonmnoqommlklpnlnlnhnqriqzonlmkppm}ppomlmjjjmdrmnklreqxnlmnlmkknvpslnlqolsqopolnljndowjrrljkofspoonplomimlljrqkqimlqwooopoooskoollkoqojmklfmkpolkpnlmmcmplknopmonoorslnsjpuknmrqooktnpsrmgmqomumnnkmonginojgpqomhroglolqpqhpnkmlmlrrnngmsoqrjmonohkhonpqmxllnoopkonompnhmvouliloqmhsnm^pjoqoqopqmlmjoplrh`nkxonlllontnilpqmoiompiokppmptpnqornmmnrhkrlpoilsnplmolrmmhZmqgrqoqpnrnuofmsnmmmpnpginnrneoondoqk_lvoiukmnumdosnionpleqjomkqkqnplmq|pnhnoohdllqqirvJnelsolbihqmolqlpiippoooroiikoloqllhmkmlmqkogpsrojtnxnmhlpmpqmhptpojnmoollnqipsnttnjxqrpodnmlpqpqostnourvrropimnmo{nploentmyupmkvqpkcmhikhokknjptjnnkmxpemwunkposknoomnmplnopjmptnpmnmvmqkonmqpnmponsofpkorllomokkjhmpnp|jmokmmljorohopjlmdnpqqqqiqrpmpiqpmnmompokoholmlmmfnqruqjpnnhqinmlkroqsnklnlgmnlnrnoovolpmonqmnkmoknnkknonrmoqnqoqpnpqnptjnommnsnnkonlnqmnjnppkhsrmmtnopppunqooonrnkqplpmmnlnhonoqmllkjmpoloefpqnmojmnlnwnopnpknrromnqqphlstmnnkmqooupnnmnmvmnnoohjkhkrromorppmmmmnjomppqmlpovppmspjpljmnlkolrlnrnrrmnphmnnqpmqljmmllfmoqlnpomnmmmdnhomqnqnhkllnmmrnpojnmnnkmnnhmpxmlmnmlpmnjpnllomkioonmmpnloomihoqlnlnompovlpnppgmspmlnknqlminnlokmlmmnl{ipnmqmrloopbrslopgpjjooropprkpomqpnklvnnmkkqsnmolnsompljopsjmlnprnpnkofmqiprnmllypppnkmqfnmmmvsmqollpjikiqonkgimqnnqpriqomklknjokopmnhoiljhtmwsppprkkrormpnqmjqnonnimhorlpplonqnmlhompipjlnnnkqppkmuoouornhmsnnqknsjkjlknnmpmnmmmpjoolllnqmoqnnnmlovmunnkmkmolppjmslkpnoliltqlmkksmpllmopnjppgsjjonqilsloqot}qopknvmpsohmpgnmmpspjongmpqkpnqlopnnnqouomhmnqmoiolopmorpskljosjjrrrqnroqqxllzfmipuojjponouhmpogoriojmpfqqplrnoqqoqkjlmmnpklntpltrinjisqiiwnsmprjprnmskupmrqljimnpuhnlqjqmjstqppxdjosltpnlnpljmjqmsoogplppsqrniqoklkpmonmlquqomlqookumsmrjmnmkmnmnlknnmppoomrnrjlqmmfrofmknmnpqpmnkdpulnlpiunfkosqxnooknnmjrnnpmtoulmujmmqkiskupnpnmktlwogqrothjsoqpnmonoolsjmpollgnsknootohoorplqxmnknonqmeookmonmlrppnpqerroolotumnjrodllsfnnmmsgiikjqkomnlklmtpkjlrjiomtnnnqonlnnotnllpmomnlnnmsqmlmmpolxsknnqmumqknotkmvpponnhqkpcnqoimqqjcjskrkgmtqsljun|enlwmkhniozjhurnnzmnqnpzp`muqrjoliijhmrpjppwpmspqoiosojjilbmjqff`vUkccq~bqnmepviqmj`pgnrlvtlmmcjnhjnkolpjrnoint{odkliphnmpcqojposomjlmrplhnvnlmcoflyrnrhoovm}hptptzonnikwrknjljogglvjl~nlkrrtolnqlmqknhhqonhnoppplmkspgogodlljgmokoerlilrlqgopnmkmkkrmpjmok`onlnkxojnoonpsplokojqiqhmpminomquknqotmnjponnoolrjommkjtyqyjfonqitkgfhlpmedpnklokjthoovlotoojqmjskjsrnirkkoppmqnnmpjmpsmulmltkkpjonoqoolmeqnkslnkpkmnpqqpoppntpghnlqkpnjhmjkplkqmnqlruhqjnnnjzkholinnrlklovjnqmplojfpjmjcrjorkpmdeltljwotqxkkiwzluj`imlukpokomnlehulto|jlfhlnpgklfmgrnmmojbkijptilkjqjmdongpsnlqmhq~nmpqlushkfi{nnv`qnxljjhqplopjmjigzroummkpfhukyqljvkkplpokgqrmi]onxhpkvmurhuigtpihknieobmzjiqkmomincxqjinbpn_jnqhfpnhjvqyqqshnpgpmjmohmcunrujolsrokknkkkplmgspgmssnopluistfnmpommpjoomlokinmjopurormlusqqnmjpnmrpnrvmndknhnmimmdkqjjomolkltjtnommoooonomronnnrjjtlnolrjsiqrmkkrskrlnommpqplkokopmnkrliimrlnpkknrknpblmqmunnmrponpsnnnmokmtrnolmilsqrnn|mmvmejpohqnnilejmninrqgonppqtmkpommnemojlqgkomlplknpknslmonposlonmwnpusqjkooiorplokklnonpimlokmmnoprmklqtmjnpmfmniomnoollmnjpnnjkngpqpsnfnkitpnokumjtklmompomnhfmmijkjqsnlnqmokmoekqmmoolrpnknpmnmrlmkgroloknrlpkonfptimonnnhqmontnnmhojqnpmlmjljmkq{jknnnojgqnjloplkuqqllorojuolornqklmopgonjmkrphphqpkoklplkrlmhomppokppqrjnqnnmqplurtkoplbsjokmlkkknnsmqmntomnoknlpmstpkonoeklgkonqolmlmmntopkmikstho}omjrmnspomkmpnpnnmmmnppsnulrkonotomollnmcojklomoglronpmorkjmolslgooplkglpnopllnojpplmfnomnpmilmnoqniqkmjllxgknnmimoplonknpmmpgnfknpnorplklqlmluophqklmnikmkoompiljmmppqniokjlmnoonqojsjinnmppmgononmpmnnkloioqpronkocmoozmommponklinmpqlooknipmkonpprkmqnmltrrlzolptnnhtpmknommokomgmhhpnimrnfhmolommnkorrkxnppoqsnilmrnpnloohokmlkjosknnsjnkniqkpkeitrnkkomlmlunpmnqmpslmnjnklqonoolnsoqeqiknrynmnqheonhtonmlkmnepjpnliiqrrlotnnpnllnullmmnpormponlorpnlqnmrknkolopnomnhrnoqionprrphojllpmmjomoppololnsmhlmrlohmkqrkorsvsmtnqynrrgproqmnqollnpromnmnxqnnjominqnnlpnonrinknompnmmhkntpnomqnowqlojnjookmjjomjqmimmmhsroolnmkqjppmlnsknkomihjnlnloolntloprmohlvqmmnmolspkzkppnojopprmpjqlknmqoljrnoompnjoumnmnoqrknnqonmjmmmorjjplkpuolpoonmkmoopomlnnjpojpknkpkpotkmmmtosoplpmhopnpkeqpkovkoxpsvomopmnnkqnkoknkqnpoqmhyomhnlimslmpornmljjnspnmpolokmonlnqlsllmpovknnntrlnroohqnlmqnsnkokmrmtoolmonhmnmoknlnlknqomzksphnokkltjqjlolnnqnmmjklksumpnonpnnvcmkmjminomnmoommlononloolmmjnkmsnhmnlpeltopwnmhjnnkjkoolmmmmjnjnsqpqoopmnjjpnpuoimolmoqmmlnnmnpoopnjmrlpnqmnmnpiumrpolomnopsokpnjlqljqpsplpmmosnglsqnonhsqopmojnlnooquopismhomjnpnklimplkqnsdgpollokmpprlpngnjlnnksrompnpofmuksknqnhpmmhmmnnskllmkmonminmnmonnmrsgllnpjmlompopplropnnmkkoqpljsjmmkrlqmonmsqjmnjqqikkogonpmfrilkookmpmirhpphinjmoskjompokwmghklomsjintkkoolkqnnppplonckprpfifjnnnhmrjpjmlorsumolopglinlxamkcjldqllolcntknuokqsrsokspnlpllrpkjuoholknmmljilrmjorqtmdrcsmopomdpkodnokpqppljlpmdoqqksqkgmksnnmqihnrktptjtqrsktsmlqmmunpiooovqookmqjkonklojmvhqqmkjnplqpqilosmolsikgollgmkqfoqmkrloissopnrmqnonnlvnqknmnhjqflrpgsmjmhelwoqlqnkilnmgukklmrutqjqsookomsmqkfmkqrlkkolirneijjjwmmlmkjsqvnqnnmljnnooorptjnmlnloooqooojhrmlomrojjnosnvmlonqiomjlfginoohktunkprpjpgpnnqnemknlop`qlsnrhqkmllkjmolsoironknqplpotjomcspnjmumqmkhppijqlolmpqrkphhrnmnilqinlpnjjjponopmjsrnotqpomoqlpqprcokplnlojmniempoqilolnlsnmnlsltuoommfonotovapgopklonngupompktidjqwqqsmpkmnnkpspnikosqqhfmmqpnmmukpoommnpknmlnlonnohfoonnoohlpioqkwkmolglqgplqolknqpsltroanjownookpktnkpnnikjmnllnoplspqtnlqrtslqksnmhmpkqouujmmnlmmokmqpmhoppjoonpqpmnliqkqilroqnpnivqlpkrjmmqlmoprojonnskmqdnmpkqopmmjzosoikpmzisnopmlaoaouqmlqlpppiotkmltrprkpnmjmolmnlinpmmrqkloojllsnqmrlfsosolnloloqjpngmomkstksnlnnqnluipqenopnpimplnklprjnorokphpmfnpyqptmjpnikotnknmnlrqkoookpppmpsnodrfkmomkmojljpkkqpmhoqpjhrmnhnnmproomrnnnpklopllnnqqrmjnonvnjnms|qnzmmpwotmjnmngkoonppnpnlpqntmogtinpnoponqkjhklnnkprqmqllmmvoomnjqlcmnqninmllpnkpqkmrolroooomnlorqinnmsmmoonoekmpmnkojilo|pospvljlvlnrlgomlloinrnqmohlnomkpjnjvnmoqoipmnnplkloqmnmpomomlmonnlmlolhllpqrlppnqrmplqnpnnmlmqqfmhmtoqstmsopnumjkjqnkolvpmmnlrqslkpknppmlqoromnmtptkmrloilnorijnjooookopmfniouppornronmcqjoospgponnoulnptlmnmkoqepppmrsmmsmmpmvnmjpmihnmknmvmpkrmrjpnsslqbmppnmoslllumjlmoqikqjnljkinnplpjlolqmrpoqlmlnnlvjtorllnsrkmnksololmjjlknohnnmjmkmrnxnmmjoflmojqnfpillsmiqnsmmlpkmpnponnplnppkmsnkkppnjqnmmqroiplnsmlmosmkjmlpkkspqlkilonhjmloinsomnlmk|ogenlnooqllpomognnikjooonmmyjpmseorkpkoimkxgllmpngnnitlsmoomipmmpoqpkmimninonunhqouinjkqnnmofjjrlnpnhlmjopovjpvjpmtmopjrdqmnbolioslnonropklpuqkooooslljunjunpnillnldnrlpmsolu`nmmoopijnmmpooojqrinmtmsmomnlpilkklorrqjlnnplnnmjnngmpmnfdlsokkoootphooppkhkoonmmkoqmhvbknqjlxglnnlrnkinmknlglklalqfl{smkolplmqmnormrjplhnoeo`jjmnktnoloknujomskrngmrkejiotlnspnlqocumoovsnp{nkipniqimnjihlpoqjpgnmsnpnikkiopkqmonjgqvqnxsoqnwogrdsogknqmnshphItgdlnlnlnompmrilgnnkknqlpmpqhnuknpmpkmmzonntmkjosprpnlijhpkontklpamlqjtiqenlnljmnlfroornolemmqpknpkhmkkolonqqsmhlnmmngqjonpsnXlqinlnjllsql}ogikosipglorikniomqoovqxpmpopqhonlmomknoonnmnjpqjqmaqqllplnkkzpijlopnpgmunvmooiooonkkjnpigkqmmtpsmfhhnkoplrlnplnnmktokononnpqqqnwkmmonmsnokpmmlnlmpqlmftkoenmmqoroklnfmqlonoompmmmonlmfvstnnplsmmmnflpomnsnmllmmpqkilmopkpoymjqpnrlnkknnpmnonovpyhnsnrlcmorljpnnlnomlmpmmninosqlojtlxoxhcufommqknnnpqmkonioopnktokmkxrclnnnnwnppqonpnpoookollpbmnqflklpqkgnnnhjnnhmhrmkmjnmsnintllpkmlllqiopgornqlpnolnkjnorlkutnnikpislomllflnoommmmnlsknorpmulqmkoonmkurnomlpmppqll}nnlnwnplpnmlnoonomnqnqmhorqllmnmoroonnmpqpnonkniojpripinpmsphlmpinorskormqqrompnrnqrtqnprnqomskmrmhhnmtlmolonnmipnmhponpjsnkliloqnnkpkmojpnnllhmlovkmonnkoqnmntmeqbusnoiqjuQommpnfooqwiq\pfocmjlilnlzqseupulisnsknplqqqrclljomornqrijnqvkqoqmop_tjmnankrkiimrlyhfhme|kzkoq_jspjmnqrjobqtofkmkdgiqqhljjhhlkmpiqliomigqoymqnmohgsqfnjihavjfmikmkpnclrsmtoktqgwlolr{jmpkjg|qrhodfrhskhloieffmgjufnnalwkfmrphht}oumov`selqnjglontjtinigrmmk_lnbojljvorlhelnmsonmisqotmklmlmjfmfnppngpqhgfrljxnpjkolofnmonijlkmkokkolqunnpougkospiiimjojetsojnynnlqkmfrosptoflnnlnjpjmkioommjnnnomkmkorojgncnqnrmlinhlnqonlelnoinmkppjnqrmrpihisgnxpmgpknojgngoikmnomrhljkrkmpnjjmmpqmmnqoniomifrhlsioionfkomwoqknkdonjnpenmrrpqnnpojkppqrlfokmrnnpnoolmslrmplmsoqoonlmij`mpisoompnnpsjoqpnnkilikotsgpmtpnknmmooklrqhijmoiopqmmmrrsmfpipromsnnmiskqohpmrmplnrkzjlmpnpnunniknminhojnkufillnlnnmnqkmksnpoffmumgiqmkmlplqqsinmknonksjpjl]pjslkmnktqpprnomlmspnogkspkoogpmdkhjlpjlpfmslhpiloplopmljmmrvmpjimnrmhpnolmjlkflnopsporonpekjgnr`tjbmpmknkmksmtirnnnklnkoowmrpjoovtlnjnopndqlnynokqnjpoljnkojqnljnpm~qglqrnmmoopqiolmmnkqnmnlqinknmkolnqppmnpmenoqpooplokoslllmtqtotplrmtqimcsioojimprmpppmhuspmilkroqpmllmomnnnmoqorrnornnoksopamojmmmkiigndsmqrdjqroenelntennphkrmnimomgqnspqlotsjsljeuomjlmplkkmmlkmjmmnllmkfnnlopfklohlnomlqmqnirpqlnfpqntpslomennllmhslrkoejvrjpnlpnglkelsrolifjplprlqmrrpnomnlllqbpnqjlkrklkmnpjumlmjpipkjstpkilknmpkpmolmhklomiqpkmjnjlompishjhooosonltgponnpqpornjhmpllojqhqipmnpomrposilkpolnqpluiinmjnqpnjplnposommqipmnofqnupqinrmqmpnkjnmrmrmlpkkoiuqlmrsepknonmllkhphllq|sknkphjnprorninnmorpjkikojplpnqgqhqgookooojtkptljknnjpllmmqhljmonlqgnskmhlomgkomqojokooiploonohnnoprohlormnojorhvmklkqgqljpkpunmnlmoiosoqromnkqnojlfqnjnnkvqjjiolpmnomslooisnmqqqnwojntronfkoomnpnnkiqenjmrpsmqnhgqoonmnqxkpmoqpmronljrmqkoqnnklnqnpjomnrlppprimmonqourklgmolllponisnogpnmmrkncokpmrolpolmmqnlinoktppninlnonlnllpprmplnsmspqpnnpnlllemtymrvglhmmpmlvhpqjimooqnomjpopqnqnkoomlsppmonmslmpplnonpmmmkjlomlhlnonprlmqsoliqmlljfnkrlqjoomkpmnoommphnnplnjhponloklmqoomjqlhkjsmlqkotmillmpppqnnkoqonoonnmo}jmkqtnypnoomnmjljjnxkmmprkonjqpoopsqnonpnhpnnrknmrjsnrmmqqonftjlnnnmngooqnmphmpqiolommoomlqjjtohkollqkkpfpnnrhppptmonmpimoltmlmrirwmpnmjqllmkollnqmlilrtqkmkrooomlqomtjqmolopgmqkknmmpjpqokomglslnofsoisrmnllmnlkrhnmikkmipkfqqniosokclpolnmvnqgknoriiorlnkokmlmqmoumqsjkofomnmlnncfnloktlipihinprnnohjloeqpjollpopnqmklnkqmiokomornjkmklomoqoklnklpllpmonlrqklqmrqoqrkkjlpnjnpoprhjkmrrniqpmmti{rnuprmllnqprtmsnunrjlslqprlqmlunoipptodtrtplqikslqovljotjqilklllqiommqsvpljrovnmhpqnnponjljj|pekspimfjgbwmpymlmmilozrlmpmiqmpkpppigsompnmgqqntondgpoloi|ondlggmpsqqbmsltm|imnomiilllmjmlompnojmhmnmworllrq`niklrqutlqopppkonqlncnmuommofllfmfgpqiqknthtmprntllnpuqgokpjl`mmnprlyqqljkprkpnhootmjmqjqhpnjkoroomik^oqiloshndinn{nkqmpmrtylmnkogmqomummiloqpnromkttipposktgmnknnnjrmunnosnrrqgpqpmmjkjkkljjlmgpvrpvchqsqwpoorpimmtgomqvmplpolsjgpmopolrirqwnqkkqnpnoskrjrjroo~onjumpnmprlirqloonnp|opesiplnoljjlqoplqplmgmmkploprrlnnostmnqulnorlnrothnnocqqpmolrhnjmlmltlcmqhikkvgsnkgjllrnqnmnhnwlgoipm]nomjmosmwnrloplutptmmrjlmnnnjjsjfnhnlonknonmopkolmnrpjrnnhpvjqkmrmommnllp}sdwpnmootjjjhpimiqqpoujiptqilrpnqlnkktjnlilllmohemmjmqlolqplmntkqjlofnirqpnllkqpgmhfoonpkknvksgtvmklko^srnkkoopnslimnj^kqkmfpbqknnkoomipwssstrpisvmqnrnniphonolok`hpmlpsqiheoqkkjngnlpmojmmljmreoqmkflpkqsooronknsgoaomanqnmksmndpjpjqpppmlsonjfqsnqamolpnllmqqoqnmodtqpfoglliuphlrnkvokoxouklmrlkmqgolmrmilmjonunrlnijnrsgmjjmqlomminktuoopppplrmmkplnvckmtotbifmlpoorlmmipjttmmlkqrmumkmronnlmimrrhnqoqpqlpqsqoqhssmonsnsooqqn_npphsncgm`inqhsntqpcojnqprpopnhmgkkpnlllrknmoppjlcnepqgiopojlljutnlmmorprpqopnnnsmqslnudmxohgvoermwnroqplojqmrkdmmnolhksmkkonvnlmjosovnktnlontmogpvllqnlnojpojlomippotnmqnfgkroplneoxinjilqlpsjmnnrlqplhhionjslrnmv_opkktnknjslcqlplrkkxoomlmmlolkpnklninnpmo~lhnplshflmfqmrqpplpuqnkonzornnmjokf{olfjqnjlqjmfpppmmjnmnommlnnljllprqntljunlkvlmlncllqnnnnqnclrlmh{mmjpljrpqmodmoonpmkmknkemrklunlkoromlkmmtmqpkrppnrslomkrrlrnqnpojrqqnonslpnnlnhhonkjoopsjktnnppmp`mmll~pnmqnmqhudksoornxrmiollpklpikkrnknrmqnsmhmqujcllremhmorgqpgpqlemplsmjercslmjnjrlqpmrongnkngonmqijotroonsnommniqrhnnlnnkpkqlrmsmmlrulmjofrlspllogornhlmopsnjirtllpioikppojljlnrqk`ooqmiopijppjljmqrpjhouroqnkqjmnmvommmkrjijolptmqpnirpgrlo{knpnmvkjnnjomug]hvmo|nrpkkmknrmsmmijnnkkonklnnpqmmqlporqommtqhnmnnakkmfsqmrmlop]ptncmnplomopkklnommlrmqcnelnenmrukmmgupmsrimnokniqmokkprrphnmnlnrkleqqlxnooqtomltoglisglommrdu`mmjppnmoljpkmjinlkpqliosnrronqlkmornnnnppfpnnklpjmnrrkeqnqllohsrmqqlnlsorjlotonojqollpsomqplmsylleqqfsmrpljknltkpknmikoprnqpqopqoqimphlplqknnlnoqnmpfrorpnonkgplnhqnmtpsokpqnmpmqmuvkponljrpgnmmrupeoqnihomodknroomkoqmyktppmqnnnojspnonphksrjqpopnmkronwnmnovosoppknotpllykmvnpjpqiloslmpoolklqullmotljpnqlpponnnokungmtporjlpsoqoklinlnqqipnpmlkknmnoooemnljrrllmnlplwqpntlklrpmomskkpmosnmpiquoolntnncmrojppmkkomjpofmulknpkrontkhofqnvmljmlpqonnnlpmmjmgjmrrljrqpsqrlkrmnlpjmjpknokkknnosmphmnplnrdmlrnklphmologmmnqkoqnnlqojtslmnpovoposlonmmonytlkpiplomjpuqnnmfkoqnqjnkluppnkpjkupoqrtnonsjomvkqrgnprslminmilipqgorjmomsprrsnsnnrjsqjnlnjopjpomshmoomlrfopqmpljlnnkoolonkqqlgnmimnmp`rqqokhmnkmpllkpojpqjnuqnpoqpnmnkmnm]onqnmnoonqqdmqnlomlnnmmppkmomlnmmlkoljolmllsnmokmpisjrqjnmomtnkolnlmngqkjqllrplmnplnkmtmqlmqmlmdppjonmfokmmlmnmrnnoopoilpollmpnsnnsmqmlnjjmtlonmnrnosolmprjnnknonlqkmqpnmqjpmnlmnjjmlmnlmlnmkonnrmotlvnninjmmnnwqormeljeornrmktflkphgilmkkgilqmpmllnzqrplkjvppemllbknrmojmtdkgmrkrqfklgjukpliknnllwktndzjolksppjfvnlpnpjqni|klgktiqljqrspyllsvphhjknvoinmchkliflmjwmjmnixonnrmmfipiukvngwsmhkqgjflVoq]jonkhnnokxuivtpkmiljkokkuphloWmqqrknpm^kgsnoo]mmkpsuirlqnk}khrtjrjssklypspjqqstoqplpmsmkphllmionppmqkoqkmmqqmonnnlonmpoksnjlptgnojmpioifspklljmpofnpkpmmknekjnojkmnmlrnmrlliqro|jnlpniojjkponnpllkummbrmmpoplkqgoqppookluubnmqooqmqommlogjllkolqnknnpkqkmqlomqnmplqpommngslomlklmnprnlfmmtoooqppholooppmmsnlmsnomntoqknlpppnjmmmpljtqlknpqlqnktvnprmhprnpmoqpmmipksknojqolnlminnnooqomnppkjmllsopjop{pplfnrlglmlmnnlnhomypnoonlpultjwjlolnnmlloplrnnilnqomnommmwmoisoiorknpnmqlkqlnlolnmxlspmmoplhjkqmqnlmspqmnqrknppnrmploqpotlpinqppnrrppmnuooqnpomnnqoiomlnqhpnhlpmqoospemipoinnooppnkppqlnkomltjpoqopnotonpnsrfqpprmtojucfhhokmlysqnpofkiiplinpnjjnqspiixrogsk_hymjtpojhntplqqnrnkmnopmnormnjmnjvmpjtokektjimmnkgrmmkljonrtlqximoriolkpmjmmqnihgnnjomlonmjrponmrmnnrrqpmrkiolfoqmqnlkoiobrqrtpomslmoolhnnhmollkqhvnokkltskjlnmmjhnrmmklnmnrkltosonqtmnknmoposrqmjnkntrnmupofuulmmnduoltkomkjoqkjhknrnwnpgijposmjnljrogjnjolrrfrfpmfnnnltmkolmookpllnmoponnfknppfmjnlkqljpmropjulolmhsnqgnmmmpnooltltotmsmookkeolmsoqlymmjkkjnrlmsltoqpinklmsknqgpsmnqllipnjlpjqqmqonokjulqinljkosnuolprmlnnkllojrvirhjnsnoimtoxtiomljnlmoomskteklmlqkqlqgimeinqnmanmosoirksjttilmqqnnslrlmkmgkjmqvgonmknljrohnelmwkmkiovnnqiqpkmgmnhhfnnqlmpmpomqpslmngolopmrhhlsktrpmpijnouokkcpopimllsllqrumsllolpirmilrtolmkkqm`qmntnnuflngjjpdginjohohnnpnoookkrhqmfksekprnjnorjnmhplonqjepnpglqolimllipkqkpljojhpomknmhnedpqogqzpootpplhpmplvnoqhpjnxonhm]hjollnngliqplgn^jocimplhejompeicpmsfnnnpinrpmjinqtjqpqjgppvknnnaqholkljpkjuopnhplphnjmqkkqqokmohngonnnlouvqltxnlsltnnpmrilmnjfjloidhllnlzprhpnnlwsknkkppvjmkrqselijmtflhlgdimrmodpp\ononjklnpouoxgilmmoalnmmllpnmfhjmnnqpkjipmpwjjnj_sjmhkmlllsnomljnlpnpkkqpruppommooplmmnnoorkmijsollrkrnljqgjlksoorrrpohjpppponkomsolkmonrmkoonkpomsnooqmpnknqtmqomkurnminrnqnqkgpknflplmpqntqjnpmlomrkqroommkrjomkymmppnokpjpnppkqnmfnkjloqqojknslqpjljpsmqpqptknlqtsnmmnqknmlmrrmpqqqkmookjokmnrmlmlnpronqkkploqnmoflhiwllnnnkpszvosmmmooYpnjqomqnmkqoflhwposqvklhqqnmnhoheonllmnmjlnhqponuwmqlqwhlnojlli|moqhnongjspkpmttrnyqokpjgnqqrsnmlnjrnlkkqqprokkmomnojnntqnripmtpohprrkiwqnmwnlcsqkpmoqvplvkokjelsqmrgmpgqynhtlefwpvfipjpqrskltvlekoirneoonmpljklmxl{pkqqlrrlhisnmklvrknrnimlonimqqjoompoopjqmjnornmriqmnkpnnksunmpmilonqhrkxqmpolpmrmmknnojommqnmtobkohmrnlqtpqlnmnqqoxrljmliriokkomolkklonllnnpijprpnqrgoqppnpnrheipnlphmrjjomnmsopmommrhlnoonjmqnoumpmlmhijqsnslsmkqmomonpfnninoumqkplumlkuomspmimmnjnookllsnminplnoompooppmrokhslqlnrqrmrmmkoknrnklvnojkomnnplpmlkouopppnplqmnkoormlfkkslnrqlmmnnkmpnjolnpnrlmpllnlqmmpuimnnmmpnlmonpnmnmmtulrmlqmoonorqsonommlnpmmpojlrpojmppvhninioppnmololpqnmojqmlioknlnoopinrnrsopogokqmmrkmmmejmomnpmrolnpllpojlkunjqltoomqnlkmonnlkqnlgjgoppkoloeoknnljekpqlsmlnwlipmlhnimrnpmdspoipoppmjotmoqmklmqjloiiqrfhonvroliuqlljqqqklndfjkmpnlnpnpppmvlmsmxnin`orr}vcnkqlokootuwwvromoirpqiutnmlpmwnphp_kpoikfonknpuolppnipjnnqmhiounpmtpkqutplptodpnmsllqlkafnjemhgo|mlsnfepticrnvmrglkrjpYmqnmpmlqnroioqkoqprqunsoopjnpoomnmodnnnkppokllhonomkmknrmpsnormrqloglkoonnpnuqgnklrmpuoopqmommlowmmlnplorlspmqqmpjoliqnqlnnjmvpmkjqnpwvlgmlongwmqronlksnnnnlnlrnslmpmoioqkpnpnrlmjmooopolqmqlilmpnmlnqmomgosqorloonmtpqlnjpqrloonkmrloqnmkplnqpnrmlrokmqogqimnlkqrkuxnopnrmpninokorpkkoqpnkpsmlopsmtrsknqiseqllkqroke{ngqrrkpnskrnlmohnmjorkulsnjilglloqnnlrmfnqnqoomljkkwmnnklnmpnprlpsgkiomkmipoilkkppopkmsehoqiokksumlmkjromulmsojpcqqqqfpmiphnbiqmnqrpmislqiihprimrqollqknkjnjlijjppmeomgnlomlnpknmqlinpmlriwnnoomfoipjomhllmmooqllpmylqpoomnoqqklpnolmnfllonnmoqnnqnpjnnjnmlrimmnvnlnsphojnjqngnnhlnommokmnjoqpllkoptsjmtnjinnlsosnmujjomnpntokkqpomronmhpmmplppksqognkqokmminllolrnngnpolsnlugpooronmmnommmrqonmpnmnlrjnomotijkppqnskmpskpfhkmonmjl{mnklpnmkrokononkmlilpwkjojkqrohupjmknvnpnnnmpnuomrpqolgisopomfolkkgosmmqkpmjkqlnlhmrnkioolrqprmknmkrnnkqpimmlpsmlqnlimjltnxqogkqkoounlqmnkfoloqp{qnpikpoknmnmsglkprpooksnirrlfgrkqljinpmsmqnknpv}hppsminmpmljnqnrjmlipmruqoospnjjqphmlpekmqkljormmmpoljsqptosrplkqxnxmlsnnkjgsqloolmqqplirllqklplslponrmmlrllpooookolpiijkqrkpmmpvvnmknnqpjlnnstunmiruekprqsopohojubkrldnoopnpjpiqfxqnfnojlhlioqhemhjpgmnovtolslojjmt~lvlnjpjovoknpammswliolokmjpjjklinykpqmmrkvoqkmbglmmlYqqnnvnnqlonrigmhqrsilnsnenuopmoj{lsoplnmwporrcmrgiqooeqmpyikqiowhklnknmpneh}iltvollmjpjzsjpqqppjplfpknhgmumlnmqtppmkolqdnpnkgljrdojhuqnnlxllmhcnosonnpoklosmknloiuojnkhblpoqqpmiknlrtmkjmrtmmsmonrhnmkoommksgjqnkcpslmmmfk^nsitlqktopo\orompflinmojjumpjmhojonpjlpnikuriqmkpoflnflmuqxmlomnknmlmqnlmtqpkkqjqlnowmonpjloklqqlqgpgpkhnlhqonjnnykjtlonkpqollnjpllrrykliksjnlloiqmojkhjmpqpmmqsrmekoqftrnvomspnloilmolmom~mrlnlinpqjsni{usknsninqorspmlqlxmovqolnplnkknqmmkopdsmjjqlmjkohvlmhgorptvuooknlqspt}npfpsslpdgroqojmpnsnhklojioohupolnolnrljqkofmqorrlmmkmgqotpljiwmmqipinpqrsgkslxslihotntrkmpmlpkpuorzkkqnljrjgtjonmnjtmvqnqptpmmln`pjmmnjosqohjjsnoposdumkmniropnllooiknnjspnmrpjnvtogomnlnqpronmxpqmkomrwriyookpnoqelmghpponnqnnoskpvikrqqpqlnnolkmmlvkpqqmpjoollpnnrjqkjdqpvlnjrnopqpookpokqoqiemmlnokonnllnomppnomkoilponkioumon~qlophlqppnmsmhglndlmninlmngmonjnlmhowjimonoookoklinlpnpmknrmpmnoinklpwmsqnmlqqmoqlplijmndkmrkqonogkmmlkqtojmomohnorimklmmromnqorlojmnampoqjlknkkkqnsonlmlnposmhlkkimonqsrmokrmpuquhponnpqmolkmmkmnnqnmlmmamkmohfmnnonpoimjmnleomohomsjmllkmmnonrsnpnirqlkjuqkpnwpqtnqywpnlopnjrkphklolnjmmrmkninlnmpqpqjroonolounnmoklojlmnshhnnslnqmqnknmonokmljrnrprmpmgpmnlonnmnmnnnponlglnpmplolmnmljtoqjqrlrjhnhtlm_ovmhnpnokoorolqkknqrqlppsojqmopqlornmoiipqjoppkrjmmllpmleonnpepnmlpqmorlomnrnsomqnmmtiionnkovnnlmqnrlpkjmootnllonpqmlnunnknjhlnoonrmksnkwlphmosnmimqqiksvnimmnornlnrrjjnnknomojlonjhnllknqmnqlpsllmojomnhrmnmflnpohqjpulioknnhkjplnominspoulslrnqlkmokpsnkgknimljsphmmrqmoopnnqospkjmnmosjliphpsmrkonqlpmpkwnntjznkqtamiommmpplnnjknpojnnppppgijmlnpmoroprnmoqomlgojnpknlmhpolpnqjmmpnqjoqmmpqllgqmookjooklkroppojmnmmoeommxptlomlqooopnsplqomqlnoqqpnhnstmojrjklqrjorrmprojjqnnmmjqqlmmtjnlommniepmnjuotnomohlpmmrnpktmlonqnokbmtlrnlrplnkponlmlkmokphqkpiplmnkjrjhnnnomnmlllironqomqpodjlhpnontnikptflolknmonipnpumllnnomolmnrokljlnnmpmkhnlikomqenmlllnoqvnimrnlisqrnqmkilljlosloqkpnniqoontmoimnnqqmqjmopmgoklnosoqkmmnlsknqmmnnlkqmpofqirlplnntklupmslkmspllpponlniiornqnnlpoppqiklqsjlkVoiqhirqmvjvlsyklnothnhmllnomifmkpvshnwlnlrikjlplulhkkherrkimkmjsommtnlmjllkigokuukkpisumjmkjsojigqmnokjmatmqjlnjmnphljkkoqnionpvnmommolrmhpuhlkromnpn`lmhqpqhuukqroljqsfkxnmmorntmmonhsoqpmjlrmhynqookvjkjjrehnonipjlibapmhoplgxgrjmmoomhpodpjiekknmnlkijlorpevjqrmlkmqnhanokpmmlpbssngtnnkismformo{_lqljvtslnrmuorojiykqnmjodtlpkpurnqnljjrqlihmhrjmfotolmmpjlmoooonnloclvjsqqkqnopksqlpoqnokrqlkomcphmqpqo\olmnkjklfonnnrnrovkmp_eholonilkqkgejhqqqmsnlqoonnppmknlmslroopijelseqmivmfrmomnsniylpgptnnpmsqgomqhkgniiiikagiqpebshrkpupkkowqomlmngn]wqlvqompwklim}io}\gmmqsbxknu^kknhlcqjjkjl\brgkmpwl_vmuepmsmnlkdtciqmtniltnkmmklumgolqklkrgkqhrpgpikshqtqliqpqkjnoenjrjsmngmquonrmnWtnmmmmqlsrnqolhmlpqsllilkjinqfcnfompiskrnpeqokjrmpzkemlmmoisnkluoppmplmkkmnomnooimslpnnkjokmnoskmpknnklnrjknoqmnonnnonmolpmmmoulqomllqnqmrrlnmjomdoknqmnlpqpoqkqqpnmponoronjnmqndmmnprlpoommlorponnqnmoqnplomnioqljmqnoprpnpniolpnomrnntsnrnnoljponflmolkvnmiomoomlullqrqornonosnnmimommonnmkqmjqqinjmmnprkkllhnmmoomwmofslnrftinoskllslnspnmkmpnplqhjlmfwjjjfinok[ojikonjjlolkmnkrgnlcenhnlemrklnojnornqmupfmkmpidrnmnqlqulpmg^ntmgqqgcplngpgkmqjknosvmlimiolgsomnjppqnnigpdkrnwlilqlemqlqqvppoplqpgorqssmspjblutorof\intkmpmjjpnoplhxnvvmp\plppioonpknmomhqnjltjklkjoonkrooqpunqrmkmpnpmmqqijrprlhmpnprrqnhrommoqokppmlhmnnomhllmnqpijopmkorlolphmn{llqqolrnwnhlpsmktkmkknpqsokhjnmqlonolplnnukklswnmoqkiqmnknnrlrpnptmqqlmnyjlhnomnpfjqmkrnqnnjrnktqmmnrnnlqkmmnkrnjppqjonpomjjqnmmoolknkvonromnnqmnnmljnlnommupunokonslonnnkppnpmnncpoqkllnqjmnmsesqmlkkmlqlrlmpplnqonookhnorlimomnmpnilnrnoopnonqnmplvookonllnlnnllnmnoqonohkktqoewrqnlnmqopnlnmdnokljmmnnmmjniolmmkopvoklompnlojmwsmjkkpololmnmqnlnpnnooqoosjlnpsmpkplkaljodopooohmigppokqhnkgrpnonvnllnnillninqoqjrlonoooploroooomnpomjrlgipmqpmmhjrommppmnlmgrrhpknnjhpn^tltmsppxqlojpqoposknpopikkgljrlnrskpqnsfmxljnklnolppmyhnontznrlmlukiongnehoru^npqnnillknawoimfhnojmnnjsjmoxgsikinrosrqsfglmrjmnmipmkpmopjrnlopnqsuhprnsqpvrbokoomroqplhlqnnomcpmpiopsborrmoqeloqlnsotlpukmmeopknqnflflnepamokmqaslokqjivmjsmprnjlmnpixhjvqjmmupmt~`ljm{xjmfhgijmpdhwumslmonktqklinuUkoosjops`spptdpnvskkgsoqqpqrggvnnpilmtej|rrtwnhmvqcspmsdusoqushqlmohrqnkyqpludjoqkrtlmfkrwlgoqjozfknhmmninivpriklqjmrqkoupipvphjmnpu`qnlmuyqj{k~yidkiSrunwrlpigmxjpprlvmhrqpnkzpli|nvwmqvumk{rprkopmipjipllprkommvjqelhnommornfkpoenmkmomiokslpphqoiglpnrtjhzqokplkolqoqmprmjnklipjsnmoporghlporkmrqlophoompumolmljojpnrokkklklnkkunnmrmpmrmmmrmmqljnspisenqkmqnmonmoomknmomookummokllomfylmpmnlnpnlotjmkmosnlwmlppnlrnppmpkjotompnnnlmlnpnmkomilqfppmgomnmlmmjmnlhrpmkpimsnlnommfhlmnjkpsjogqeonnssliqkkkqhneolnrognkgntdklonjjgnojjmokqloqqqhnpqmnnjlkrmkpdqoqaolnkwosoomgnrpslijomclmgbnkojpmmmljlnmotnljkilohrndopqqmpkkhpnnknqqnnmjvnlopphknjq{omgnqnqromojinnomjjldhomnjsioqmiujmckirsnlhpqrlqnjllmnokknojkohhilppksnrqnnmllontiksyQoqtnmmpndsgojrwgsvZvknupvkltqsqigbkentpmmolhqsotlriojnoknsurrkhqminlvtqjdmmklwmionwjtpWrjtctpkopsYumliihsmiormdoulkpfyrcumpwlprrocjrnhmqlbomlkklpknpknzmorukrjfkrqmpetmqsmszsqpmmmkqnndollphkvWmkppillknmlmomwqoylsn_kommgoeqllkphhhogoochmjfropmmkmnpeopkqilooxzojikomlsnpoppjrsrrolmlkprfmqmloilknpunhpkgphppqsononcjrpfimkmpklhlltmqsmlnnqlrjsoepomhjgpiiniuom{_rpollcrpelomlktnehhmtlohrnmklqjnomrqlsokjmqqoikllvpxpollitmplglgkqmqqltljiqkmqloqkonimuopjl{jlnjiokkpfn~onjoknqojmomprmkbknoosrqpopjpmjjmrmoknlssmmoljnnnftpinlkqokomnnlkkjnniphokkmoqokrqllpllpinluwmjsmhpijkopnqmnnnpnppmnonqjrlponrqkommpnoljqrqhmpqmqlqglompkolmrmooqmknpimpqmsnooppqollrqnnqlnqtunoookllqpllnmolqnomlmmknmpnioljnlpkfpllmrjqnrnomqspnompnqproolompoonqpmmlkngonoptopolnqnrkoonkpkpmolnpcrlpnnkuplnoholnwponmkolfonlmmmokmhlolkmnlnkqnopqkfonookjniamrqgjlqnqnjknlkgnnqplnnoonquprnmqkdjrnpiroonnsokmmijpmqloolmknplponjnpmoonnootykmpsojpmtqplnomjmkolognnrjpmlopnipolvmpnopndkknilpcnjdssomonujntmpknijmionulnsjpqhllrqmshkimlilnmqnplmplpllnlpnmsmsklamnllnljonpqpinljuoktnflnhlioojonhmknqnponnlmqojkookkmqopmlmujnohns{lsmhmogmopstollllkqpmksmiljlurmrspmhmoahqjjpmnhqmojiolomotnqoylpqorlpqnmpqvotkiliknvlpemrlshjkoononqrtqjilnklomqqlwspmtonlpomomqkoooooesrklooohmmnmnompknqpilsqoorppootpjoojkprmnmhjnplolrnoktjonqrlnooorqmmagqqlqcppXejqgqrpq{bvmrppimhptppfgmkgkfrtllebosmr`mlpohgimeoksohomumromoprmmrjwrmqmnput[uaiaiqqrmlb~lmiihvnmvhn_dgfrgditijfqfwnvphbpllljnrlqrqrrotopp`qjjnniiprpovoymarqssisossimlqomsjYlnoqmooYepkmellknmenmixlvkrrPjrpglqjnjjlgnYfrrilcllolxjeoshsmksjjnvoetchmktomkqnn[rnrmmqqjnqnqtlhnbipoplrmmgmosrktpgsnpnonojpjponrnempvnkposmoqipqnikfqnojvmnsvmlltmprgnnerriqvmnqhrslimwpmusdmppnkhlpmnvmioijojkwonplkprrqheokmjklokogopomgpqlqlumiskuormpilrmnmhntupnoqorthotwnlootpiljnriumqquullrqmqppniqpmofglrjonmiqpmnnlpjpiqitnukmuqprohkomjmomkinnlnnlornnkmlopmrqrpqtplmnomnoqpkjknnklmikinoopmpomnqsqqjmnqmqkikqlloopswhqpmonoppwkirmoomfnklmpkojlmnpololojmlnpppnlllpkmkqmpnpnnlrmsmlmnmnormmpnoqjkooqnoooqplmpooqpsjqompnrlpllofolloqpoknknrmmpjolkolmklhooksospjmtnnnoommlnlnllnllrplomptvpmsqqtoormflpiljlivrmkmnkkopnjqpqnpmnkkoonqolmmijrpnrnnmmoqntoopqnpopnmminmpilmpnnlrntmilpowmkljqgojlqoeojcmpnnqpkmjnmnnrljmlonqlmulpotkfmlnkrenmjoqnooooluqkkonmlpqpmpprnpkopnkoolmjkllmmnmpjqolpmrprbpmkpnrunlpoommhhgsorljonqmjnnjjnvqrtpmormlnsonorlphnmnllqpkmidnmxrrkirpqsrmnlmhmjopoorkokkjmpquppolkpzknvmrmonoolnn_mkgoollmrnmoqlmunimmnmjlmpnlkjoospjnppupnonkcposopklullnpumolnppmnnikgjkkojkinjqlnppjppto`nrmqmjmojikpkpopmnmrwokiokpppoptoqomqkqbnqnnpkspjjkgnmpqlflpkvompnnmlpnjnommqnqnpspnmnotjlnhlpmgkgppkkrlholonidiohvjpjnsloylvoprqjppqvnnoqgpghlilpqedkwqmnrrsoghlmiqlruamtqrksqpgjolnnlpgoefmmkVpgnprsmtto^jpu`cjufulp^nrimqgrohqjo}vnnobclkkmcpufonwkrpsrmoUsvlghmfrskotu{vcrokxrqmvueknhmsrpOplsnqlp[tlppkrdjqwn^rokxkrsojTqwomqrdphgpslf`vrpm`vomqrrqusrfnrnmjm{qgov{sqtnunnpqjemhfqiorpspqonpmmqmhjnmunonloqonlrjjmtjujomrolslpqnnjoopqmkornoinnkkpoppwmklqloooucxlplnsnnhroskmmojvqgloortqqkpmonkmsijmqjolnmfksloqrtnpqpmrrmqmpmnpmqroptppplhlmspjtnkmlnirpqjrshmsmlkqqgqlZmofnkqooirpoemokonoqlqpoqrplloooppllqjoolkopnmtkplorpqminnlpnnorjnkogroummknrppnmolqonnqmmoqnlpnqilinpnrgm_omlhmkrpmmniiooookognshmnoopgctpqonhmlmfskqnonqmfmsllqjliljgmplnmmlkimnmgnoomonlmpoplnrnklsnoohipnnokoqkppmdoomrmljjgpooltmmamjsnminpfli}rkkmrrnokhlnlnhrrhkpmlnphmktkenpmnnmkmlmnnrnhlolqnmrtmmmoojmjjkmjmknlkqnpkqrnnl{rronmmlnqonnosohnqonommmpsolompoxnmoohlqnkknpllhofknqroopqppkmkoortgqnlnnqoojohiqnumloowmmmlnnmmuqlkrklnmmoomlniojrpnknpklxopjnmolnjoknqpnporhkpnspnoormmfmromhrpnorinslnmmnhjs{nnlmpknopiormqmrifeqoljnqonmlpmoollmllmomnkomlookpmniqrmnotioiplnjoyllsgimnjpZqmtnmnqkkmmpilpp`nmwipklohnmnoommoskhltpqvjpspnmpcnpplknjpqlsnrpmlqkhgorpngkslflhoqotllluqmnpquvoqmpxlrvorommkninimomkqsmnmnotmnnjmvhpljgjkrpnkpcernlopnklknoqlonklpljjpinlqqmrklonhymljnpnsm}njypoqfplpsomjkqmlmhnoyopmqnnqmqjoiiumpolntrmqrqmnmoiopYzomniqopowokkirjmjppknzmdrxtqqmlgkkmo|lpomdoqlkoWkqpionnmpinojoikphgokrkkphjsknmsqpmirdlligpiqpqimjjflqg{pikkmmikkofmrnltol|qprmlnhlklpqnommptlljiptpmljumsviponkgklgimiunovplgnmsjip_tnjrmoonmkqpmgilnlpnrroqtrnlqlesopnim{lrxqtnttmillnhpipkmlmuiiqlmoutkqokpklnkrnrppmlnqkmjjkmoommnnfsjgolmqnusnokrpjukomonnmkjmmpnlnmsmnhpoomnnknkoofqmloiwortlpmjpmllrlnpommijlmpmlnmkjnlkjmpulnppognmkkoqnkhrporrolnirnrgompmmlimkqklnnjmlpkoqisiojopkopspmokpmpotlnngmjmpmnlkmljmfqovpilpspmnnojqknkpnnommonpjqnqkjnopliprqnonkjslomgjhnjqqnsmloplglnolmfnqqokqnekmlmhpoqwnmmmrpllpsyokujpknkrpoppnumtsqoommjqjqnooklrmomnupmjtonmolojqmokmooppqigmvppiqlnnmqprolrlklmlqkrnptoqhsjmqmirqltqoqnlmjolmlroqirnqrooqllkiinqpmlpolptmphmnslopmmpmswoapofmljsnmlnnuopkmnkmolnlqooroktjvnmqnqmnjnriloootnjmqklornqnnqkim{mrluqmwqdphpmnxpjrknkhjjjmkmnonjogpuklqjscnninojmhnjdnnmmlspmmkmomllrtqonmmmnqpoholtgqlXpqnsglnnormjhrqpksjjlmlmnpmpqmnjmrokmlnqmmlmmmmhmnjogokqsloosljmimlppqlrovinsknsiopuhlidklrnhiknlkngpzmivrmnmqokkp_lnmkiprqihmmlijpnlognlqnonoiljuotnmqlrhimmilolhljqqbejooqtoipkshmjoitkspmqmgctirhonvlahjkllgpjnohoomjphombmnnhdfqooqpmhmhqqkrcjoodmlmgrokqohgmrpqmbprnrjlklrongigonlomgxpqjresmlinkkspjqnmkmgjlimonssbpgqllngpnhnolsumoiphmsmmooiakroiyem]hrupiyknvnl{jpnwhzspo^qmmninkkmmoijfrmmhoepoklmnkompsljolissgsooijnjloimkshqnllnlmmnomknofnjomlmnjiktnnupiokmpkqmvrsnhsklljsnoqnponntlnqpqmpktsriirnqkrrplgjqnmnllvkumjigmnpollrqimprlrisonjoojqqommrnpohijokpmnfrjjntmhnpqplfppkhmorsmmloqmsiorqrrslnspoomnrnpemnpjsqoljnnwmjlsiljrncmpnmhmqnnkokinpqmrqrhqlimlrlswqnljmkmmipo^lipmnkntuccullmolholoqpjnokfsprkiljnhmdqlnqoemojl~nhqonkomknmnqyqoofnkollioioilmsslinrn`nhltnumljo`qjrukllosliqgjllmplhprijldqoopnelhgkmjkcnrnonopjnjgnpjgphikptjnlojgmqmpoosiqkhspoqlniqornbongjimlqdjnkmmqoisikojqniolpljmmmikljmjjsllokmmqnrormiionkmqmquklmpljmolproppomjonnpkrssqqpmthnlnlkkrnmfmiinpspnonplnh~imlonnomnnkqqjmmpoqhqnrnijhmpmqnooqmnqlqjmvjqmnlgnminmlnosolivomknqimrilmjronpimhkpujqgomolmkpjpmpnpnmsipmlrnpmqppsrsqlplhntlnomkooqojmllkldnpopniknfljnhqogtpnnjfqposlomopknlnmongoopkmnnrntqsmmpprlpnpkmpmrloqkppmmnlnkjrnltpspmnqoijonnjomofsgmkkkrnpluonoqprrqiwnqeqomnislmopcljsnnqlmornrphmongmmjsxlnmnosmiqnikjrmpmkfplmpfnxolkrmnnpppojoqlpolnlnlnmpoknqlqnnlpnjpmjqommommpoqouofponmmnprnkkkoomsolkmompnnjonjmnnqnpolnqjoolhqnnpnlqnnlmomjtnqmqoionpiqlqmmknpppqrmqiqnnmphknstponpnqqlhnqnponjngmxlopmmrnoklnmrnjropkqvlmqpmprnlngqomnlmrnqlpplnjlklnmjmnjmphsnkopppotsskpnrqnqkrplsklntmsmnmkntnoooklnpnmnkpdnnqnqlottnirskolpmoltpnqnhnslmkjmjulnqemjlkkqlkvknlpononlljlruppjjpllnmknoojommrolplomtmlmnqqqvpnmropopnolmnnjmmjnirk^aooioikn]eklhqwmfzctoooomolqwqnlibpbp_mpmhbakpjiiltvpagklmkdon`kkqielsqlkmkihltnlpklzvZndcelxmhql^}mrrcaijhnkm^olhpijmmhmjnfwpsjh^pikfnnlpniqmomonksanjmnlduwnjkujypjllnwxowhsgerjsnsh^phmlignPljmrmimjpinprrphlollnVqqmlgponkkjgn`krpni`nmmmuomrsdmnnqplovnhelimninoipjjoonqlnpkplpdnonnlnvlmlnpirknnlmovojrowsngnrqklnmqqpotmgomokplknpnnqtnronklmlsjnmqjpqqjojlmskqmhknormlhkrolsqlumqpnmlonmpirloqsmjpnlqsmjlkknjnjnopmmqmlkpprrllljooomkmnlhovqmqkinlonhkemnqpotloqpjosolxljonnotoromnjnqkplkmomrmoijkokootkpnrngimmjoqrumrsnmmkjimtqpoqonnijeskollcjqpppjnp`rumorqvnfjrnlknpoqmqnlqqjlprollmnqoprliyllkksnnq`keoolnmrronmnnpzkqrnjqlpsvnvgyrqnispuoojlkpooxjijipqmkmjjulggpoohlsjslpgjnmnjomikkktlnzmpfqllrljqksoohmqmeqqlqmpmmiiwomuosqtkgnntiroqmnmmkpgnsonlmprrlrpjoormponpmmnjfoximil{vnfnmnpmopsmmskqpnllspjnnksqogkvnnijojlnfjkjtgplxmhroqlnlttjnprkmnniiokjjomsoqmosqfmpo{lpoirjqjpmvmkmpnwmppjjmqotkljlmkropnmnmmpnnmjmlnmlmnjjmkmuooiqnrniplkllinlmogtlpqonmkmkhpinpmowuvqroognifmontmqnkqpvjlopmjirqokjulmmmomlluoqnmmrqmopjmloonhnonnhminllsrsmvjnoqjoponstlqprlpmmlpqohmnjnnmllnqommnpsrlrjnkijnpmnntllkornnvjmkoklonkqmqnpmqnmlwpoljpfnsnlgpnollllolmuorsqlpqronmruolmlpnilkmrtqnnpqktonnnmkjjqijomoqrnfnhnnpmopnmrlmmrrmjprqlrknlmlnoqknlmmlnrmkjoneosonpliokqrmnmmlpmnmnosmmponpijormlllnnlpomlooqkmqslrnmmmnmpnqnlkokmlnqnloknnomltpnkomnmjmplmlnlkumoupjgolmrpkcnnjppokhlmsornopnpgnrjmkmionlqolkknnkjmjokhpmnniojpjrqplrinllklgomqomnioomiksnlllnpnkplmroqsnmpfoqnklmmioqkrokpjioworunqllorkonmkimnhmnmomqnosgljmjnznklolqlmmpooplnkooknjommnnnpolqnunlnposnmrttpmotkmmktoklmmpnhlkqkqmrppgplnponnkllqmknllnmmqpptpqkkomkuknpnhnnmrunikkomphplkkmlminppkgokopminrpnoqpqmmkotnkmonkppmmmrsonklmlorummmmqqojplopiljjonmlnnoiiokmpolsilpjgqnqnknjnnmwonroqnlollnoklmmoknlrmqrlmkknvmntpmqspxqopqqnnnonqkmkmokompukojnlmnonikekoklnomoookmnvhjjlnujolpkelkkgqjxmrlmmfonwlnklqpkrmnhwooplrlpkjmaslomlnskjmpqitomoimkoikjirinpprmolkbqpjltvolnljkukhkmirnrqnagsnqlimnmkilrmpkolmnkokgmmrlokilqknkiiobnmlahopemqpmilqmkmmkquobklogolr^khlkqlnriqlrplnswlpkkiqmqmpplsokqtkmhoodmpolproqlhnonhnpppstqpnoonjnilolomnqomgrmhklpoonlmonndplolpkqmrnjlppknloomhkknlkrksqnoljqmmkopkkknomokmqonoojljklnllplqljlnkjknpoojrxnnlnoplkiomlnlkkkorkpnllnqnijjgopmloilmloqoqpogqolqmolpoowknkosomkklqtljxlolpihioojmllmvjmklkommuejppkropuoromlonpmolknikjqkmmkomnomnjmoonnlukpjsonnlsroptnppoekmsrsnmosommnpnmnmmonajpqnloomjmmmnpsomnnsjljnpollmmnnmppolpmnonjnkmlgjnlkjtrooonmkjnnmlnqbunmiqmkplqoopjwpikpplrnlnqhooqonooplkmplvohmnnnnmnrhnmkmgpnlhrhmqpoqnolroqqorjgmkqpkhnnlolmnpdomomkulpnljolkmmkpuplnoqmkmtnlmpmollkqnmkumpmmpkhmlioglmnooponmmjljimoqnleplinpsksqlmlkoplmnwpjioomjoplmnmrutojljmgsqqqmjmpmkjnlooetqmolonlqtlmpmomljpinlriniphmshfolkqmomofmkplpojfrnokklonmonlrjrklhokhlqngslproinkhmplmgnnonklqrkmsqlqmnpntsnmnmmipmqnlfkqolkslmkkkmoplmwlqhwppkjnqsqdnrknooekkkmmrkqqpmpiilokskkmnlpmnqminrghnpmknjnlplgqnkmpplpisqqpmnnhnomnknoptkklnnmokorkolykmqmppsmnpojoihpqpnnonimoprmpgotkprqoojplomnoklmpolqomlpohmlqiopnnmpnnkmtklmirmmrkilnrspommnqopmmnplnnmnknknmnpnqmnqolqnnjknfprkjrlmppqnsnmoqolnohprmsnmpkiiopnqpunnknonornpqnqmnonlqqlrnommhmmrqsilomsolnmnjmqsrpkokmqqkknolnpmnpkopmsnjlnjoqnnninnmnolpqglmhlnlqdqoninmkiomkhlnnoqononpllirtuonsmmollplpilpvkonettlnnnrnnlmpmogtomngqoipnlqgnqlklloohpqpnrqrormlpnimnnspfppktnknnnkonpppnsjomhpqnmnhokumqpllnlnqmndjmjotholjjkorpqnllooenrmnlnmrnmqpmkkmkkjpojpkonnlptmqnqqjljonhknxohmrmmnnmmoponjnnorpmmlomlnjmqlmjrprlknqmlomkkikonqppgmnqmlnojjmqonmopjjkjmqoqnoklpikzomkonqopoopmlknokjoliljqmnmnjooqqppjnnonmnliponnlpllkionqlkonqlrmiknmollnzjknnonwmtopplpnlhmnonvkoonoqknilopmmmrolmpplrplompknnkloppnjmomjknoommjomgktlpqoonlwmonskmmnannnrlknlzllltqrrsnqknjipsminnmlpnmoupmpqmknnnhsgkrorlnqnlnnljonnumnongnoihqmlnmqpkrlmormslhnnnnnolqkmmlomljnosmpjklnmppmplmoqmkrpnmnnhoooploqnolnmopnmpkmlhkmompnoqnimlpqhmlpqilopqmpomjuhnkmlxpliokfpoqfliikrkonqnsmnknimklnojmnmlnrkmpoopmrmrolpngprmoqlllmqpmolromnnppiopolnskmoonimomppnllmknnslpptmomkjlplpnrnlnnoopnnpnnmmnqopopslnpoqoprmirnjnmeolmllmmmnrprmmmnq|qnlirnmmknlpklnroqplqmmpmnofnfoippkhjmllonfpnpjnlplmlmkoqilinrnnqnfprlpoorqmlpksooojoqllioojmnmqoknmlhmohpmmlpooonmopllnnkghnnmnmolenkoplpqpqropmslrsotmoopnyklommkjomjjlmlmoqknmsmhsmoumuqpojpnhmkkomjqllmonnojoplrhmpqipvognnomnqpuqpnmnrklpprjjjloilroomrvrqnmrtpplnmmnmuhmmjllknxpkkonnmlimjojopmnnfkopnjnfnhqtmomjkvqqpjnntllinpvlnkovmspnrntsnlmnkkkuqonwrtntgnlolqmqmotpuomnnppukskboiinlplmlqxmpnppronji]lmipmnkpqrmilmshmmomqhnnqonjrpnqmmnplmmnluljjkninmqlqgpnkqmnrponvilmlpmnmmoljjolpiohnprmslpkpiqmukonnpjmlkmojpwknhmpoqgllskmpmjnlnkmhpjommqpjnpmjliplsonpimprqplqrmqroomhqonlplznfflfqmnmlmkojnpkjjljppjooonpelolkopnmngmonrknqpnmnkomknpioioloqsorrmpnmoojknpsopgipoqoqjpmjcinnmmniknokkpngmknnkponnrumjpqqslpnnsmhoqqnllonmnloqmljqnqdpcmgonlqikqilmppkqnjolslkuknkjtqmlnpltoknlpvkqqruoojsmmnqopqolqnmknsgoknmnpkoqqqqlpjnenkjqoslmllpmmpmonpqlmmnnnlkinknnmljjmnnlmoliiiprsonlqpmooimnjkhopononmmjlohlnqnmmlpkupnoljkimupkqnlrjvotmipsknlsjtvoomjghmlroqoonmwopgiivoommxkhnmqoqlopnnnorlomgpkhnhkmjprpnkrojotqsspmqnpplnmorhgqjno\mlqroqoqlknsmtmrmlhjuqolnorsg}rklolomqmnkmolnjemlrqqonmiidjnngkiliqooksnxiqpvsunnlspopwltnkokoqespliknnxooopjshrlhnlmwnjqnimpjjmplijqejmllmoroootlnkneoklhpkmpoosmlnpnnmemnqjoppmrloompmhmupllnmknlhlmrmlolnojfenmkqmokkknrjkpoonlmqoqtomqmozhmomkkmmklkpohmqlhsvmqpmnioqgnjkompppkoqjnomrkommjmmqmrjopnmnppomplojlrnlqfqooomklpkpgwmoqqlbolsnnjjoooiolqjtkfqqlmmlomnokpirifllxknnnrqnmoippqmomkmnhegjnmmpmnvltqmqinmlpnojjn}jqllvwomxm_mnlhgjr}qkpjpfldnobnrnnimmpjni{oemkq^mlnihnnnohwpoomlqoskljorlprpkmmljxsmgtnpjxkvrlqjtkroumpafgnnol|hlkbptooklnqlmhmnqkwplujqkqknmnrqkrolmhpgksrpkoooptrujjglsngmmjtrknjpemqsbnltonukrsjlxi`lnYlpkksmolibothkkpnnolomorjrykjxlorjnmkmnropnimnmrklnmknhporjuoknqmlnpnoltsoontlkpkqnponrsnnuplhlmemoqnrtojnmnjjppnoqsmmlnmpnmtfilitqotqnmkopnroloqslqopneoqrnmomolslqisnjpikoikopqlmrpmqqmohpkknmnqpoopirmnokpijnrnnoookmlrmrnomlumlfnllkmjopmsksrmnoonnopnnjmunsmnllmmortjoknonpmlnojronormnnopomnlokmmmpoliommrksijnpmmjpmnjjnropompmkltronnkommrqllksoptkojlnmtmoqmppliqmnolrnhklmmmnmnlnpmmnrolmnnlopmpoqnknolkolmqsorlnmmluonlkhqsvnkkpoomorgnompolopujlomjmoogmnqploinrnlpmukomlomookelvnrtokjhgpoonpnrmngnnmknpnoqporkkllqnrkmmkqlqqtljnmmqnnnqlpmtipkplljnlqtgoqoqrjjlmfsrhhjomunoqqmilnjlopksbooinnlnomsmnokmprloojpsjgrrhiqmjoniinjkfepnbrnpokinjmqojmonmoqmfgpjjljmnruziongolpmolqjqcooemgqlgilskjmpjnmpkkkpkonltnonhmqppomrmioejkokpqtpoplrqmpmopljrvnqbinqonjoloijhtlfmoomqgnkpmqhpnkgojxpntmlnlporoommomilnqkmjlknlnorrqglpnxpnlmlklrxknvmvhlovoklplmqnpppnkpkyqqqpfolrtjmljmlpnllliiv_osllfioonsroqnphopmknpnpvnrlkqllpwmnlrmjpskkmorgrnjmqpoevirlnxworpgoqipmnjtpmqqkklmnqqwihmqrqirupolmqkkkjjpkiqnmpsmnspnlinjpnmlnqkjniporinsqntrqjnoxlhcljjvqpymhpkqlqtokintrknsqonmpjioxnrpmonunnqipqloskyhqqsormfkmimmqsounmnjqnrmupnnnkqnmsolkmmmnqnmpqkiilifujrolllmnmmpmrmjnpoqonpklqijponiplrknklntrllqilqnkqlloloomqplppntlptmjkqohnnqqlimksnjntormmsrmtimonoimpmpojmprympllknmujmkpremsrkkkmonjillmsnnnkiqmpopnkpnjppnempqmminkqommpmnjmnlmlmnipmqtpoolonlnnjorrmklsqoupoomnvhpnz`nprlroolkkmmonpqqnoifojno`mrnltgpptgmkqjrrmmjqprogovkjjmqdjonoqvinssopqnqohlhphpendoomjtjpcigfiwcknqdooknmsntjpklovpmolmplopnpnngmoqhrirqlnnkojpkj`poimttnpknnpimlmtriqkmenmunqmlqwk{omknvrsqjlnltlitmgoijiwrjyjohrrmnqpwnqhollpoptlrejumkmklpuqfkjrkeblummirkfrkolkqpcwhrmmqprkojogmmohkejmlsllslknkqlpqlnipkorjnoojkkoptinrhmpmqrpuoplllqsgnlojplrknnjnfnnihdnhummghopmmkplnmmmmporoxirjsrhnsgnornqqsmongmjpqoiopnnrnnrucjqmvcnxolkrlriipofiqoitnl\oomompinlvlnomrrqrpsphlpnotmqokgmmjlfpphpflmoppnhtpminomqoprkqmfoqrlrm}tq^kftisnqyuxmqllnyqkimrnklomkmbperkwmjltigmnntizpngpqmkomsgkjsolotkmmofknolhmlo`lqqinfniom]drmnedqnompnjniilomxqmqqollqnkmmsijjjqicoogkmumqumkmqldrzlgolnnnpmmmjkodnllmrlqqpnmkjppikpqlonlllglllvmnmpohjmvkmicnijjqqqmjomdqpnmllkenoqrojmtjmpmllmrokojtmnonrkpnnjmpmlnkmjnptqkqnogoopjllqpmmnnmruonmmlnoolopmpjnnoqnpnkjolnmnoonnpopnlmnoqnmslopoormnoijlkjrjnopmopnmqklolpqimnnononomwpjopoomqdkmommooohmnsoqossnpllqnqlplmolnmmqqlnhnpjpsknlqkojmprqmknisoomnnimpskmovnojqojmnnpnljmjpolnoooqmoonlmrqmoupkkomvokrojnnokjmfjmnqnnmmjjrpknrjnpnmnhpnoqspjlpnjnmqholrmyprtioqsllmnoonqpljopooplnknkgqonohjskkkppimjhpfhpfnoqpplllmmjkssolndqmmlnpmiqnmpiqmmmqoplpopgotmoomlmtqnnhmtpjpmnzoqnqmmhippilkoojqnnqiomnmtnospmkkmmnopmkpntmqjnhopipokomrknnoolpnmsnlonqjnmlnlmoqlnmlmmnjoooqpshjknxjkmnqmfmnpmnslldoqopnioljoommmrnqmivmpjopwmnwjjkmooinoiihprlsmqpmlmqoqokmqqpnppkrpmnloihhnlqojjrkplqoollikngkpnolmjongjmllkprpqnimrmoklnnlulrlpqqmpmmknpmrrknonnqkmospnomgohjkpilnlknnonumomplclppmnnnonnkgpnopsmoonsnlokloplnoplnknmjlhlonqwnwpkqqilmillsjsouoynmmnjkrplinnsjpionopnunmnnnpllhpqoormnommrnqoppnokqhomklwnnonponolopnlmoopnoigmmnnqllppllrplmolponqiosnpjkqoqjnkskqmqmqmojlmnnjnonntptnnnkmnjnlsmrljmlntlmnjklnkmlilonomjdnlspmnonlpormsoinmmqplqgmpmmloqtqpljlmlmkjpmlkmnnopnjlmlidqrlknjmoqmsmrpnlkqoimrkljmpnjolsnjlkomookprmljknmsmnmopoojlnnnlumqnjlmoo|qomonmonokpsornpmmlnjlllrtpnoiokdjrqrkjpkjkmrmnophrloomqvnnslqgnuirrnlnmnmnnrpnjpjoklotzqnopmmloonmqinknknonngtoroqmkfnrohkrpmnmpomlpnikprlimonmmkpololmlmjjnrknqiqplomsnhnlmlnmnqklopntfnlompnmomklqqpoiprmgnoknqrlkqnjgolskkpjnqommmonnklpnpnmnmmkmnmimjllnnpfmq{mqmunmkjkniltonlokotonnqrmmogjpmmklilnmkmsiponhlpnqhnimnohlmlonlplqkmsmmmkronjnomnmqprsoopjorrplolnlqknomlhhlojnlkumlpilomomxsqknommrlnnmijlplpnmuimknokiokimlgpnoqomntoonllmmmlnosjenltpiqllslmppotooqqkmnjpnnkjopnoqmmropomgnioqjnoolqkmpnmnpprnnorkjqnpmjurmopkkdosnmrmhlrjpoolsrmmuonqnwokkrlnopntoorompnjmktnnmookpjqoolvpooqllolonknnomomnnqpmhlknrqnndmnmmongnmmlnpqyommnqqkjpnrnpqoqfmponlnoukqoplkppqknojlnnlostjprijoknoomiphosomrmkmonopeijnkomnmimklmkmilmlonqmhlqommothlminlpqpmgqnsnloneslsmlpileunonomoplmriolsmlmmmpknolknojmronqtkqprnmhnckmsmfmnpknthgnppknospnpmhmnnnokletsjolrjnlmkktktlrsmkuomopmqmpkqpotlrpmmlmopsjrpnkpnpljjpnonkwkpvilnsmpwfojrqbkpjhkimmhomnlkjkrhsopulshlnrpooipnamoigqmkolnlmnrnohsimksointotlopqenoqplkrihekhfjopesjpcjjojkmrqkmkkolilmwpllgnqqrgmdrsqiqllkikoshjlnnliljmnqkqomppsotsopbolihotmsoogkpomhkpqnqfngjrjlojnljmsommpoqqepmplkmpkmmnmmrooomknmmqujnnlpimnouirnlnnsvwpknnomnqqinvrnkiodikgnrmmmjmkpinkmsrqplollqonnmomooonkhpjutolppqmldomqnnjqokpnpiqdftocqowwncgjnjplxloxivornhji|rqphlrzplinpogjjxjkr\ngxoolohjoljm~pnnnslkrsqirgolorjnouknqonqlgcckkatmyrjuonhtiqbgnporxtlojlglkpmstpmskuq`hnmhvsZtnriyn`pkrnmenimvklmljipqhegbkkopmmxmq~photuqmplqsl|jwexntpeglniimxuas_ljiimmejnmvkqnlrgrjmrtpwntlqninqyilm|vnoqtrmpkommqpghmmmmnrorqpnshlmnqnnrnlnnknjmqkpglnkhn}pqlsnqkqqouioollnllsnnnpoflnoonvnpnllolkhoejnmnsmnkokllkplnqljllnlskpqqmqquoohnpoolnmkjmmonpoppronnsooppqpklmmnmqsrkqofqjlnrtqpenmmioinknnmlmomolrmmlmlonpnomornpqqpmmlnklnpnpmlmpspmlqrnppmdnnkrnmlmnkpnmfompnjnptploomjnmnpopnnmronjklroknmmmmlnntpmnnnjopspnooposoqnkmnikhmnmnlomnlnkponhhvonsommloonkmrnoolmooplokmlqonolimqolmoqmsnomiqsopkloostpknskipnnmooooomokspnhhpmmninnilnprpvmjsmntqmmlkqnmnjksnkomqfkmkmojjovhliqmnlnonmonlnnhpmsnnmphnnqmmnokxnnqosqmpokmonkhmhopmpinmlroroinnljnpoplnpngnmonljmkakqjiokuljhjjgpilpoqkokmipunmnpnmrpmmhlqnpinqprvnpmpmdlefnloohkslnnsnknjupqpuuklrpmmhmomjtpilmjqmjlmuv`nkomtqntoqhovksrdjniuqmmstiiqppqqkopllkkrnlnhorgltvilkhkliore{jkjnonlomjhr\joqknqglpsohrljltqtlpnjppkoukoomrsmvngpnogceqnjoaqmffqjisukfvjvkljphicppinjmnpemcmriqfitoqnnjzsnnokpllppi[nspmqjonnkononirlimmjnw`lclhynmenkctssoebjmowpjenliknmmnlkpmhjpuogdmjogliinpjrkkjnoqojldnmvgimmiopjpmnoloorhwjrhfssnoqqkkkfowlo`llpnlpkmfrooimmuizmrocoonkmolnjmmqpfnuevnlhjmgnnorpgskmirnovqckvfspujnlcmjvljfwljjqwlpunqjtshitnqmsm{kqmlywrrpnjok_nnqjnpnknrrixlniospikmspmopqnppnimsmo[s^mgnhqrrnrkggskpqnskmknrknktooizikqndjmgiupmniomlojrlulnwomojufokomhukprojposnnkoqkmsomprppkrnjqoxdlmmijpetloivlldlqkfkbporqoopjqvnkqkrlnquikrppimhkppjpknpkkilnqrsk{lkoqujvgZtngmnkqwroqjnpjihppoliskioepfonhlefqtjnnosoqlpjtwpozqoklnfmpnommmqijoqkomlpgpkiotkonojguspmkgsrlqlnebsjnojnqpoqidkqmqdlmlllmsjLooomknromnmnqljnljnjqpoptnqqhroljkqqlmkklkmgonkhqjlqvkvupmqnlfrojqnjlnrpkmgpnmlqpmnodopmmiokjqhmlpqlnrjktpjmtmoknfgmlolnommsluolkupnohoqsqrqnmnnnnnopnoknknijlpkllgnclipmoqmuoqmqqohoomnmkknpojpqmkmlsmmqrnpjnmkoinmnnnnqnomplltllslplkomrqpkmrionnrnrooojnl{oqanpnnmfmqnmmoomolpqmqnmsmmljptnnkonunspioelnjmqoknkpnlpmmpnpmlmmlpmrrcnmomnpnlnmqnsmqjmqlhnnqgloqmmjoovokrnplssnkqlijkrmnhpkkoqknprkpnmlnjophnoprsuommkljomnjrskllnlknopnrnjolmmoirorjoolkmlnrnjpofninmhjjplopnpnlwljpnmlrmolllkmqrmoooymnnpprpngmlqrnqqjmiloumnnnrqfpnmjpnnkqnvlmijodmmnrmkjliqflmhmltknnnnokmlmonjqmkgiolgnnqnmornlqkpqmpjrogqlmmnnoooqmopqlmoplnjpmnqmmomnirmlmonnctlqhoojkmrnmerygjeomonmgmcmiopljsuprundlqsqiplutevkrprunpmnlvnmmkphkppqeoplkmnlytmjjlepujnkzjiqhiogksorotdlprmmncjrkmljrokrl`lrmprhigsokkjpjmollohmpfomdqljkhkmklnpolpojplnloomipojqikkhljmnsogujqmosmoqnsrlnmntlemkiwpllrpklmtnqnqlmrmjjijosnmojmukompgpkntpbpwixsmmnz`mjjlkkpwqtvopsnqixonsjoosoonhnolnrnqkigoopgolpnnttonnksnnmjopomlokmnpkrlmlkmrpookh]hgki[ijjpenhlpdmnfvlpmsmjoxnij|fmmmpmpgnnjflpnnlomnlkmpnmnnfgwkrrrlpnntpimnluornpnnttipqhjmpnlunnhlmmklskginmmuqjmosoioisoljyogmprnikhpomonjnnorolkojodrqrqsmnknmqelmoookqjjkromilosojnkmonnmnupppmkjmllhlkjvjprnqmhoerslqnmjvjnmppqnmoiktmlkniphqktvkkprjolkmrppmnmnqnrkomhqormnhjjqlemmpljnmlsmqlsnolpnmspcnjnknipljnllonhngqlsrmrnnnlnmrnnllkmrltpfloohpqqowmlhjqlmmnnlnopjnoilkrolq`lqsmsoqnpinmnklomrsqljnknkgnpnopksrmmomcpppsqtnnonujmkqlrnjlpdokpnoploosmmnimojnslgirlmropfnhrmrogmonhunrjknolklqlmkrmlonnouphrnrjkicikqrnnmohtmlmmnkoponllkllnmrfmponjptpujiklokknmnnonikpnqsnoljpoqnolsmlnnoqmpqophnmkodnollonmlkqmnlqqeomnnmrmpnllommntnpiplikkkminqmponqklknkjorkmoonnnlrnppglpqjpjplfxplarllhpqruqlloihnpmqoolppnoohnsqnprlhxolipq{korpqopljtomuffksinlrmuunonqkrmnhpknmsnjqohrkwrisfiqeloojioeppttkgprrmosrrouplxptppkmpkqqoltqlpsovorpoohpnqrvmltopnumprtqjlnojoqojlqmrnlsunpgpsskkmlionsrqffqelkmjoeqrpopmtttlnokliqnpmttykrnjplpqpuioioproqolqyhgtjqrljkplmhojqmoprwnmoolonqglnkqgjhkmmsirltrflkjkkojnrmilmmphppinsrkwfmnnnmnjpijsippoksimlremprplnirpnqpbklnrlqfrsmjlomnlpjognnqijohmmnkmkkpoopkfsknnklykmnkkmolqmjplpptopjltlonponhgpmekqgkbpljmqnmjkvmunjlonnpprpon^oqrnnqilgomdhcnuqqjdhookqnsifojlptnqopmjtpqtoqqntslkmnupmllljlmoonmmnnlolnpqrnqokjiqrpmlltolkcmtmlnktjmnsnmjnmlnnfntnkkqnntrokqomponunnlkemnkmemlmpolnlpmlmljogkjlnokmjnmprlmonnocnslnnlonljomprljrrmkonfopkmqmpkjonmnokmmnnrjrmlomunovolnlnmnltkommojrmlslolkrqqomkomlnkmnnlopnojoqmhoimlpornlmktmsiikuolionpopnprgoppjhonnnhprqmplloopnlpmknompqoknnlmohinpslojpnpnjppqorllnklnonrrlopoptynpiqokomlmmklknmmsmqlqoknnrmmnmjqilmqmlshnnttmnnnrnonklmpnkmplommpqnlimoqhmkjknnmnmmmsononkknomhjonmnmjesoplqnlkqntmqooppgvnpospqnpitnnpnolnnmmipknnjjmjjlppqmeukmqkphjlrtqpevqoopsjnoozhjprlploqmxpkmjornnoklkplqqopmtrnmpmjjdmjklqdmopihgmqkjljmhmnruoopqpdrouigpmnommjrimsjolqnlikgmgsjrjqroosjmqthklngnflopsinlnlovqckmtkkxopmqsqelnlnkqsoeplpioqjfmeosdomrnmonkhmnqpplphllrlphxnjiilkmhsksdopjlnnnpnjmnomotmtpqodmoonqllopvbwnslinplqrorhl{nnskmennploovslvqlskhuojjoqmnokxjrimionpjpjpqqlrnqrmsomrlsrnspokmqpzpwnmppohowmllkknnrqmnrojtohsbmrnqjkkiknqrlrqmlwlsnnnpmomnonsiljqjuqnqnlnhnpiqomkpbqgl{fqxvnpqromllpopppomnmnqqlmplmnhnppnmmolqqulmooqpusmlhhojovonmssmrnnpjkqomonkpjnmkopmrlsjklnkrulomplzgkloinkmpqjpiqmlolnkoppmnjkrjlomkkkrypqnqsjplnlqnnpmmqpjllmnoniumpnqoppunplphnpqrvrsqjpqsrqdfzjlpmoqjlkjmmoqmjnujnqolstlfiolopqokqquqpqoonVmmqmrlihsromylnpujppnnnqkijlqomlokplntjsrmmgiqoopjkmrlrpmowqpsoooksrkoolindjpmonnkojemplillopnymrlqnpqqykpmpkippqonmmrlojpphojqimiimkrkpqpjljoprnomnqmlmijpnproopljsqrylunolgmmlkkokqinmkoqlnnpqntjiwnknioljqoiormtqlplfrrmpnogoohlmjspolujgmkqpljonnoojjpmlsokkmlpnksinllnnmnonnknmnkmkmpnqnjoompqnmklrjrophmssktovekopnrrmsmpmosolqloqkmkpqkpknmmkhpommonoiopmqmpkoqpqtkrmipmjolnwibcpmltfnqgtrnpmnigtdokpmojnlmrhlnipqml_jxpnhmokmrVmqnmfhlligmonZsmrimpmpjkjkvpfopttinmrgkklhouhlqj`somgaikljlnremplkqmkmmlimmtnooigkdlpglruolsmlnprpncormineqypgptktmdwnnroqmnqlsqmnlrmjnllpvrgaqmkrjrohnpqgtojpntmlncosnnqnqmkllojfjtvtqkkoptqoppqnemoonlmrmho`bcrpnpfqmYcoviunlgucopmqrhjkrrinegkkmjanoknecenmqsobsolljlimqqpknonlnhqopjrlmnnnqnqloowcmlqcmsq_ilgsqsrccjjotnmfbqjppgqoplsoempypqkketklnllplnntkznolimhlmlgfrlxmlnsxfommrkrlppqenqmhptelohmqshVcllokqsiquohmkqnnuppt]oorkmrjmlul\nYkrpprgllsnujlnlinjonlenxnht~dnnklm[kllkrkptnnhejjlknlprokmmhblxolfpolgngknipkztolkopontnjrqkjqlgq}iqolkhrnklnapjuqnkngkmkvmmgrip]jkjvknn{qrjnsholuillepqpfuoniorlrlpnkupbjmopjoprmgrgklismlldhijsmppniimoooojmknnmkunrdorrqmilx`ktoj}pshgllqmtjlmptogtogpqinwnkmkshppgvklwtmeonnpjfrrmbprmqloundqoolmpmpqjfpkomnkoqpqonmlomhoinfsonpqlklmslojoljknnqoqnqkkgmlkskmmpompoplosmgnlqsjiqmplltlonlfqhhkymmnpnkcjkplnnotlmmhnvqkpgngponjoomqolmlolsnmonnpqjjmnqmnoormelmnqksimoponplpnrnkkppiokmkpnnqjojnoproltlllstirnmokmpokmppijoooolpmpojmlfmrpknmxmknqnwtrhtmjqpgnknquvqrrmokilumtnnoxqlpqknlrynrtltkmmmejitqopkhomljopoqrmpllkilllkjnklknfllqrkmmqjn`jsklnrmqmglmpqospnsloslpnpmppnhpvknljormqoqjnrrononnslrtpjntmomjopohpmkqlmliqmqnololin{ttntjrmsiksosjlnlmninzoooprptmkqpsdngmqknspihomqmnnmrornljrrrnpmlommqmjpnp{pkmpofeounrohlokpomoqrrsnqonqlpnpoqonoonlnpmignplskjqioprpnmmmqownsppomoqqoipkioplklqpimlijjroknjlmoqqspnomqmrkpjnkkorjiolpopnklmnkllrnlpulijnipjnlppknnnjmpmknnprmnmmppoimo|mnrnmilnmnnpjrkqngnlmjksknhrmtkqugniuppjtoqmnilrnonmooqkmmpourjmkksplprklpmkkornossshwrrqmnmqosdngmnmjvolkmmfmpqmppkqlroowoepirjthlpooqmotqvnlmnmtmrnrplpriphorpooliqkmkinpmynkkrknknonruqqonljrttjplprkokmpspnmmlmommnqomnlrsmonqjqnihjomlhnnmlqknmhnlmmjsinrijlrnmknjflonninrlniiqnkpjkkhutnkqjnoivmomklsjolqknnmmlonrllqmqrrnosmmoinqnlrmiopnklnjqlpnvlopmkkllinonljqopoqpmomqnnpnolqkpmnjppklmmnpnnkojlkmmoqommppnnolnonoommqoomooosnnmpjqmjklrtomokjvlqlkqmnmklnnmonnmjmporoomonlplpqnlpqglnmmnlmnmpnnoumnonqonommmmplqsophmnjmpnnnrloslnbqqqllpmpmmnjolnnplwqlnpmllonmololloolonmnkommpmompoqnnuoopnnlloktnkqnfnvopnmqhnmrorgtlkpkomnmsokruxmslolmxwnotqfpcnormqorjpopnowimmogqpknjzpomqjkojnrinljopoqprklmivgpn`lpoqestloinonp~rnoljmnokkokmnjqlplomcjmklpppkqpkomkmgkjmvjrvkoloostqlno^pqkojnnmlmprrrmrpotqkjmkmsgsroopnlktsromnomnilmplhknlkmlkoqorskqhppnookiiiqmkrlrilgqollqslpuqskhlbjopmjqkpqlopgvkrqlnprnqlnmomkpjnmkqpgslnomnlopopoiknmlkikmkpklnlmlilihnnolfnkkisnmmomomnrjmggppopjjnxnnhnmlosqoknmnjqjnlqkspjkolnilrnqlnmmkmoqnmpnuqppsormlqolumiopbqlpkqkjufrlolkglpqnlenlplkoknpeuprlmnpoonlnqoqmmroknocipiknprplsormqnmjpmlnpoqlmkokksinlmnqlmnnommtnklooihnlmpomlojnmnnljkmmrnmnkoqomommmjpkonsqokloknunjomqsfpoppulmpmoornkkmmqnnqiolomnmqktmnmvqltlnnqoomlmqnkloknlkwonenpmojnnpsmmorknmnpnkeoqoomsnmmnomkknxqojnpmrprpsnmlqpmsjmnommkpotqlmsnpkmmnnnnnrpoopmqnmnnonglmnmmkllpnnoknrllonoqkoltkqvnpsplmlkpqhmmqozqooqlkmlrlnkqqqrrnllmlpqqoklhmprhmjtnmljomononmnnpmoooposmhkilmyomnrqpntqkqomjmeqqkhliomplnknlpjmtkmoqolupoopcmnjopojijlllnqponpwpmormqsrhlomnpnrmkplclwrminqtkmnqvsqjomsmvpljpopsleionpnrplfooisopntlnnmokopkpmmptnxlmnrjnlriplnpiquppoqlsllqdrqpomooshlojolmoolmkpwkrkoqmrklkpnhnnjiojmmmninvngooklolmmlqejnmelpsliknprsmoqllnpmoljkjnsgsmpsklqklumopjqlqpjqoonnsoqnneklfnnqnklkngilomopmhnginkmsjinhonnzklknomrmqqnokpmkmtojrogmmqrmqpliqlnouilnjlovkljqgpmslfnhmnlpnopqokorlpomosnmpqpmstjotnnonlnomnpshqqmorhjlsmpgirplxujnknnokonokpmljgnxmhpjkjrosknjxlmmmopnmmlsllljnkpswsimmkiprjsompjhordkqkvohuqkqhllsmoqvntklnnnmomnnjtknonjlonmleoinjplnrnmlsilhnpkpl`lkmslkrlisplirjinmjnqnnlmnkotmcimjrkslnikmllpkgpiponbopnunmlinkgmnomomsjqkopnrejohonmdnnipshnpohqrnzlojoppnnmornoonqljmnmpkshmmpnrkpmkplnmlnhlprocmmpnnoqyn]hnmqpnnktnrenqiqlvqnnnrolohnqmoqonlllunebppknjfinmkimlpugkqoqshpioompknnqsqok{osmprlnmkmpkpqwliomrkolstspqitklnojsqjonprwolpqlsmlnttmpnojlolmmsjnmrowlqkkpmhlomsp_jlqinlkmirmmqnmmllklzrkpkljpnlolmqqwnimknwkzqrnligpsxkrrunpunkromtonqqokpkknpnmqrimomqorqjhsozdnrmlmqlmnmgitldj~mkolnpikkogwnnrmhiqliieppsnohookl^ligpokolrpijnsxjgnlkkjqhnommplollnnqmronkinqtmfotmukylplojkioprplrjzlkjihnqqnllkmmofprglonmhpqnjphpljiojslioqkpxlmn`olonwlgsrqestpronnspomhokmnj{hmhmkswnlkmksnqtjvmqkilkonknmjmoqwkotqnqlqvnolsirkkklkljtnownolfqjlmepmnqtmptmnrllmqmminblkvvnmrsonhkkkexrrvmkypugkotpwlitmfipnlneoonmvshnmsjonmnmkktmmflmmkghsiphllpmppbptptnnmnrjjnoumpglqnmkwnjpmtkljgogtuzom{npnpnmnjqdninmtlolipskmnhoigqhsmmqlosjnlnqrpojpqlerojjnvlihmhkjpkjlokqljmloqopjpkmmooqnponjtumljiminmpuqrfjonplqonkljnimnipuopnjkipklpmlnimjrkomjroonnnsjmpnhpootrsllhlprnkhmoopkrmnoolljklhkmenmljnvliqojmpoklvqmnpomnpnkjlomvsqomlelpspnqjrnonlpljnonnivlopntlpoumnjslpklppqpmhmmkmkqmmopnlinsnkmmjljmkonlkkunqlkpmonlrloqnlolnkomokqmkrqmnqnnqmlnnnronqqtlnnmnljrpppgrollololontkkoplnnnnorjnnjmlqskltltmonmnwlgnnnnmrpnmlpmpvtkoknnlsnognrmmpoonopmonmnwjqjnppqlwkkjnomrlsknrlklonlnlrkrnnknlmljqnlsmnoqponjmlollpnmpsoolmlqlooqqmmolksknqinmlnpmlolqntlinnnnnnnhrplinmkmmjkmpqj\imokllqrnowklonqieidvnsnllpqsnpuxijunnkrjpjrmlmlqqollppqkrknokepfkohbqojmrkknplqpnpqtkmrim{onnrnpjfjqprvqrppksjqnllphelsnjmglspd{mnkligmlroolrqumgnmflhoqmkngnunhngmmqrpkxorqnhlonkjnolnnslkljvrhojupltvmntoonnmusnoopqosnlpokrpimpmponohipnqlollgeplshnfqvlpjupijkmgomplsmnkqopqrekrrjnjktrnknsnlnmolkppoujqnpmlmhoorknjmqjopjqlpmsilmlmjjkpklrplmokhnpmmogrkkpmppvloklqqmvpnlppplmnnonpllrqknkgnonoqhloqojonrqrkgqjklpjisplpeomnosfpmoocmpkmimmpoppekpplmuppprrqmisltynnmhqoeoiojk|spomnpoklhmmqmomlqqlmmmpnomhgjnnqlimtljlkeijppilkpoXopmipqjkveqoqrotghpotlhjpmkonmlnifjptlicmeoinjkmmnrmnmlnnikmmmkkunnqufosktmmnhnpkjrugnnpkohhpkmcckiljejglpnmmooljmmtropjkmksjiimyommrnpmrpnflmmfjvixpjmvoviiohrlimhfqjqjlomoo]nqhpstmcnomnmkqnjpmuooxupoljnfijooonfqrvmjojinfjdkklrgqkojjfrjlhloontnolbkmjpohoidnkmjjrrisjninnmjpooqloqlppimiopkkklloprin}mlipnqnlmoofokpppknqmlqprmlomollqoniommkogsmmqanoqokjnrnmniilohqyiqoiumnipqpmoemjomjpqmnjrjkipqnngpnmlosmksqqqmqshnmnolnpmpnulokmpqhqdmpqolhnqdomrhltijolnntmtksmarnlorlknnkomkjkommrilnomplkofkomolnolsliltlinqpnjjppsjknpomrrrtnoqlkqqmpolmpumjmvkxouisklrsmlxmloonlkmsmnqqnmorgppmomnlnrkoolxlloroo{pmhjrqnsnrlhpjprkjppvnqri|jsorpmoolqpropktkonpormtnlrmojjnjnvpmnolpnwlplisnpoopqmgslkrrqppmjosimqkmiqmofnlqssklmpriroolqonvmkknwpmnprrsmnkmpnklwmlrnsjoklonlloplinop{arlsnsetj_hokpopnkoblmjkmolnrlnmokimsofpioofqrookenspnompqmnkmikmojnchowmtqtolrkmvqkpdwjltnnplgrnmigjoejczmvmqrqcuepjjomqrqo_rpnktkobqogqpqnjmljkmjrmuionimvlopmmpmikhkjqpkpfpnfurnlnkpmpvoosippplmktfhmkmoynonrkopokknjmrsmmlnqnljmrkmojinnllllikonrjo_igruskmuyjqrhrwpgplpmjnoqqgupoognomljlrqlntnomfnnuqrrojjmpofnpmtnliqsnldnmilmmrtqomomnegqvosnonthmlhlikpslkzmpivuknqsomkwmnrikpoopnmjnvnjcmotjtkombmnjqslnrqmhhsnooonknknomjlrmmpljpsfoimlppjmqnnqskjkn|mmnjjkkenijlqmnpnstlmdmeitmqriijofqsrmttuhikplmmkllnskjplqommjoostplmosnpljloijmolypnpinfqnomfmnknkpnnqnjsuimmpqnlmpljqqkqqnnolknnpkqmmprqmsoojoioesnjpmlpolljqooppknlmnjmlmknmmshpjljimpkonlokjjmnsijnnhgmllnnpmkoqkoqpkmssqoonjkqorkhllknpnnoknnsjngkpjknqnormmpomwllnlpgllnrmonnpfklqpkpklnfplkummnkpmfnoqmnqmrrpnnkonqgmlrmmoompomotjlpkqppnpompnqqnumnpmqmognlloijpnpqknlgqkpsoqnkmmijoojlopokkqkrpjqlmlpkmontrooiookiotchpkoplomllohnjqkjninplmlnoponopmqpmniqmnjprnooqnmloorolntljnlhollnomnlmynnqppjlpl|spkjnsooqjpinoiilhnnhnorlqrljqwgojrmjmpnokmnnjlnljmmqmlrknpnhookqqnnlpinonpfmknjmpolnmrljkjnlmnimqmromnovmrlonnjljlknlkkorooolj`kjmqon~lnmgpnyqkmppposspkqlnnmippnmhlqlokilpjlnnpoknlninllnkmllhxnltlrslojnkjopjrijmoouiminonlnroooqnmuqkkmnpnboqpppnvpppujpmnpztoknnrjnjlmilojlmmomrpmjmkrtprusupooaqmlljognmnmoinnp|ljqlllmponpqjjmpqlpomsf^0Ev!jtz6}uI0Ra~`]giX4<GmHOOit{cK~x]8lCb4q^r?T8 v^sYktAUCla]9kGUG[WVL\XO]^dW[VrX7VOXT@AW_Q^[WX^CUIOTZS[W\STS[TXVVXWSNF]\QPUUPZTXRULYTS[XUVUX[TSUVUUN_ZVXXSWXMRXXZ\NXZZWE\UU]YUWWU[[U\ZYXW_UW[YL`VSFUXVYVWWVPSVTOUQVTWRZ]YXSTY[UUYXX[XSUTZ[OYWZRQ]]XWP\SWX[WSUJPVXWV\UPYBYYVRbS[@UVTZYVUWa_UY]_LYTTVU`XXPZYYVXWYW\UPWVRUVU_UWVXSRUUY\SQ\[VSXP`[VTURX\RRUUUW[\XXXQURT_VZWZN\TX^ZVWSRUUR[UQRS]\ZTcX[YUWXW^QWU\Y`?[ZUV]WWR\][RRYXZZRP_ZWRU`]?bMMqSUR[XYWVYi[ZZ[UPYYLV_W[VWSTY`P[T^Y^V[WYMJO^TTZY_YSIY]\[Y\F\TL]Q`\[]^VYQ[M_S[W]\^b]XO[VW[YX[G[WWXxWT]SVPWRTYTfVVXWX]^_XTYWgVPcSqWVV_\VZVSXLWUWQQcRU\OPZVGZbQRV[WYYLY[VaJcTaY[MXXUVOiU_TVYXDYXbYBWTZUYXXXVHU^RWWU\`Zc\XO<_ZW[SYBZWAZXR]]ocZZT\XQYYR[XJWUZ\YT[>`@]YTRV9RZZqP\WVUc_TVY\TLYToRObkTZ]eVWZW[WX]VbVtZaZKa:RNLSVVW_iX\FRVVNWTdYfVTWVXZYQN]XRXUUQXVVVV[aWVUXPTQY[SX]L[XXW^Z[ZSZVZZWZY\XXW\SXGmZTSVYW[Y\XYYPWMY@OVW\W@]XWPZWTP[[YUYWXGZMWTO_YPRWT]XY]ZRWZa[KWYUXsYVX\VYYWVNXZ\WYZZZYLLVrSXYXXaWPXXZ[]WVVZPXRURUSTPPYXVWYWSX\GWVUQVXWXbVYT`YYUWZWPXUPXXXW\UOXXTWXZRPWPWSTXZW[YXSYM]WYSU[ZYWVXVWWYVVVV^[YSZRXXUWVRYU\VVVXWY\dSYVUVTTPWZ\XYXYXEN`YWQTMXUYWUWPVVMSXSZXZVWVWQXSXSVUaV[XX[Y\RS\URXUXOVOWSZS[`USWWYSZWYY[VW[X[VWZYZTUTUVWXXWQIWZUOFTU^Ti[XS[V[YYNTTYWNWSYGTUYSTgUcVQP_X.TRSTLQQUXRDRUPHdRT`WZKURVUmRTV~bbSYUtFTXrQRWORUR U[SsXh^\fRROJUPOYfnUdJSZURWWyU8SUTRPUTkTgWQJWVSUPTTSSFOUSRR`SEWSb`W`ROU`WUZRQYXUVMVXY_ZS_\dXX]WUPYYLVUUQHXNZVY\XXKTXX[ZZY\[WSVVYMW[WaW[UXYSZX[^WSXXJVWMWZVYYTQ[RZW\\LZVSSf]SMY][KV[UYUZV\SOZTVVVT[[VYXXWXZYX\_VY[XSYYYVXAYXTKLVXWRZZWXWZYYPVY\QSZUh[YV\VYVRYWU^YYXiWeNSPIXWWVV\YZURWQYOXLZVLY]XZWYWYZ\Y[YTZZWYS^\RZX\GYYTYXYiUVVVRhXRYXfSVRWTLVURZISVWWW`V_Xk^Q]ZTW\ZRWWNU=S8CcUKUFQUXQWWYUQ][fVWUIVIWeRkSIRRVQYR_SnSS_XMUV?T|XTWVPTVOS^_bSYVUURSQ_WUcWUTWUTeTV:U\PWVNWYVVXUW[SWSS[_VVVVLVdWN^Q`]PQ^X\Z[HVWVAQZTEZPXUXWWQa^ZUWeURYOWI]jQLOPVZ_WWQ;T`NUQX[XXXXUZZVTXYY@YeWSTXVTYTTMlVRNWZRWVS[XWSUV\WVMVTVXVLYZXZVVITWXTWP\KDCV\W\WTZXSX[`V[UkWmTTSjWUUqUWP\RSQZWWXlU]UQZDWRT\]YWYkWDLWOVPVUMUUY]XZUWU]Y`]YXVTV]VVYX]RWVVSXVTMWX`X\\XWTWXWVZOYd[XU\ZVXVWUPYQQ{RaUW[XOYUXWQXbWURkXVT\UU[NU]TWVTShVTYQW[^[QUZSZUW]SSPUZbXZYYVX`WYWYY]]UZTVEVVWWYYUUU\WVUXXWUXZV^]\`Zg[Q]LSL]^[W^W[^_TDS^\WRb__UZQtXUW_S\`Z^XYV_VRFUYOZcYZY\[OVeSX]_Q]]X[SL`TZVMV]^ZV][P_aP^Q]U\^b^Z_^\^_ZZZ^U\\]^\a`WO[P[Z]X_U\^VXSW^_WWZ_MWWTQ]_VWYY`WWYUZM\]]XYYXaWUQWUWZVXXUL]V]_XLTWWNWcUVWTX\YYY][VSRISVXcZYWVTcYG[YVWWVVOXW[UVY]UVKWLWXTVXZXW[Q]_WR[YWWSXIVXUWT\\ZXZ]WWVVVXUVWXK]VZWa:WTXjaRXTZT`XZXX^XLX`YMWR[MU]WRVdWYXS[MYXXc\`\]V[VPSWOZXPdWYWWXU`YWVW^YUXW]XVY^DT\UUXTQZVMP[XZZVYVVVPVUJRVVSVVUSUUTLXMVVVXWV\XRQaTL]YOPYU\XTQXVUOW[XTdPSUYTQXRSUTX[QWVHUYXVUS[\ZXV^TUXSUP_ZX`WXUXRWPSZWSTQUUQHXVTWWWXTQSR^ZYZPSUZT^R`VWDWXRWZZZeXSXSRYWXYZa[UXXSNW^QLaIVSNYdTRZTLXD[SNP^ScWYV[VMUVVVV4WSX^UQZQiZTTWYUYR\iP_IW[RVW\CXRWXWXZYVTVvUSXUYRTUUTTYWJXXXVfToTVXS^]TZZUYVWRYYVPUXVPXMZTY\cTZXPSOUXcRZU_SWTVPVX[Z^b^VQZRPZWYcVUVZV^ZVTXVZPTYZ[Q_UVTcVWKXPYY[YXTUT[VOTXUYZcVZVb[\P^YYX\YV[RTU`ZZZ\TQYUVVOYbWOSVZWVZYWVWVPWT[U\\YU\ZZWYSQXR[KXXQ\YW\QWVZUXYVYZ]WTVXV]aU\WXXPXYYQTWYX_TSYRWPY\Z[SQPTRU;ZVUQP_QYUVLUVN[VQW[YWV[X^ZTWrZSHVU[SSUQVkQ?UUYR`QTX\ZJUYvKNTSX_VPV]VSWU_UJ]RRXTXVXXLW_TRXTTIVVTFXZR_DZT]\XWQUTdUJSVYWCWROWVTQVTXXU[NJRYVXWQLZT\QTRIOVYTESHYRVUOQWQ\KWUTXUX\TW\[RPUWPXVaUY\V[]ZYY\SUOW[VXTPX]MdTM]SQ^bZZUIY\ZUT_YVXXWS]VXY[ZWSW]Y_XO\WXUMZWYXhRRUUYUF]LUQNVUNGPWXOZ[YWSO]UY\Xea`LV\IZKY^]QPd]\`XWg]Z`eP`dimmg\SVc`XV\XR^T_;WWV\@]YVU]]UUe\ed\RZ=[_TPbH^NFQY^UTW`xQ__]ZT`i_xXT\Wa[XV`][_ZX^f`[WNObjL[[]XN\rXXrWW]WZJXOWXWXW_UYZ[[YYVR_RTB]Hb^^\TZYVUXY_ZY]^WVXXW\V\VaWLXb[TZZZWYGWVNW^JZSSWUXYTmX[VZYZRYPOZ\XU[\ZZZNWVUX[WXWZXYN[VY\WVTZXUOXYZXRYY\WXVVYQRVZTYYTY_ZTM]]\[U\SSWWW^X]\PWV]YYPUTRRdaPZTQ[WWWPYYdXXYU_PVSUTR[XZb^VWWZ`T\W`ZPVVT_\^XWb`^UMTUUZZ]Ri][WY[YQSZY`Z]_UTOUTDPXALY[VU?][WTZYhcZUY[VW>M[c^URWW`TXURNYNUK_qPbfVXTOU[A\YX[RaS\[K[S[kWLXMpVX[VOT\WOYLX^RcmUfU]WUWWTOSHVa\YU^ZSSjJ[LUWV\V\VbSTQKV^X]YUXTUZUUOSVHVUUZM[ZQgXZX[XXZWU[[^[WTTXPT^_W[W[TaV^TRX\TUb]^XXXT[RT_TRUVWaTZYVN[VPXZWWUW\WI]TRXVOUK^cRVVXSZYTWV\X[]YTLYXUYPT\LXU[T[X\MQXZYIV[UU[SRYRX\V[RQZXWXNUY\MVWWWTVYUZMZ`ZUWWUY\WPXKXXUTVXYYVXWSXVVZWUXTWXVVY]YRRTYTWaWHURQVaWVYQURVTZXYWXYZWZNDY\[XXLVYZ\YpVTWVRFUJTUSYk\ZYZ]ISCbQ@BXOLVUW^XW^XO\TY`PZX>OYSSQ\aUN`R`XWVURW^Y_cKWY[XRTUWWTKNXTWaVTYWVU[aXYa[[WVRTLYcWVYXXVX VPWTWSWYXVVdXWYXUTZ[XRVVRTYTZUiUCSXbXSYWXTTWVSWPW\SKTXW_X[LVVMTVTTU]ZZW[XQPSURYR[[YT[UdTS[TNV[YXYQYYXT\XWUUWUNYYVY`ZZXRZTTY\XTRVTYQSN]_T[ZVU^QUSZZSQOVUZV_VRWV\ZZXXXSbRURYYX^YYSXTMOOYT[WZ_^VWTVUOVZYYg\M[WTYVVYXYZRM]XVVYY[XXXRWH[WXL[STTW^WWWYZYNYWZSXYWWQVUHXMZP`SYXVVVXVPSTPZQNV^XUSXZKVWIUQWVYaOXMYUW[UUQRc[TLNTYbZTWPWqPNBT_PXSUXaSXRRYRHW{\L\SVsORW^ZMP[RSWYT[UVRQYP.DNUKYXPUZ\QHYUUTXXSZW\TSQUSWUTQRS`NSSTPSTTKYKLWWWWGPUWWMRW_WXSjRVRObVP^V`S\^XXW`PZ[][VWXVXUGYLZUUZWR\SVXbZN\[_`LWYX]VX`VXU`TXYQVXWTTVUWTSUPZZZWXXYQYUZVQRXTTRWRWNWPY[WZbQ\XRZY\UTW]WXUXQXUVWRXbXWYMcZTRYRXVVWX[VUKVZSTUVYVb]]YQ[WZXPW[VV2\SSXXSUVW[`SVYNUR\WX]V`PVXWLd^ZVZU[VSYMZXXW]W[ULVW[WVRSWWSVTOOJUZV][XbJfN[VUUW]SC\UOWWV[`_VXXJW\ZXRS^YZYPUXYTXYZWRWXQXOU]YNZ^^SIT[V\^\OXWX\WX\SYZ\OXXTYZQV[VXMQU[YTV[WVUYN\][U]ZQY[TTTXTWNZWU[^XYWVUWQWTMT[U[RYUX^YWXRY[SV\ZXT[XYTQQ\KVWZT\P\RYVTEZVZKTWOTR]UXXKU`VNVSZTXVWUbUVV[[\WZQ[U[WUW][UWVRTYS[MXYTT[YWUUTYYYXYTcVS`WFYZSZV_[W[VPTZSZ\\d_aRT_NYR[_\]T[[[]UNRZYYZc[d[TWsPRQ[R]X[X]]]^tRQWTWoe[[N\RT[fTY\^XcXVM[OQN_^QX_\ZO[YFU\W]M]XO^S]YYZ`Z[Vac\OZX\]`^^YZ]RV^Z[_Q`BSZRPe]VZT]VXT[WWW]VXU\YbUXX][OXVVV_YU[RLXP^UQY[[ZWYTaaVWYXZWWXTUZV^YTXYSUWWUXXVSWUUTSVUVXWFWW\Y\WZTXR^WNXRWWVW[\YZ\[YTXWVXVVSYbZWY9YXZXZPUPWXYVWVWSWRKZXXXS`ZbP_]dX[UWQY\ZU[WKZV[kVU[Y[TX\\TWTXYUaZXYmYXYRS`VOPVVWX]\[HY[WVJVW[WZYYWXYXWRVaZPUYXW[\TZ`_cgUV\\VWdXPPUQbOTcTJRYRN[MSRXQdSPUYZd\hRNXaMNhXFORXXZTSQ^YhNU]S\MN^V]LYMPPUSYV4XM^[JMWXUSSYQXAUPcSBRSTYGSfSRXWQVRTW8UVYUSW]SSRSYQNOQ`URYWUUgVTOYUd[OVWXXV4R[WP`XUUROCQbQfZY\[[MWRTXjWeXUdx]YZPYXYdZ\\SY\UQUVZMZHSZkGRJXTZPWQ]\NrVYUaUPKW0XQVSVVT]WHZXVUYXTVVZOTBMYWRVfX`XSNZUXUYKZTYZZY^ZZZW[X^Y[ZV]VPYrXFYNNW`ZYYWSZ^\[dXZKRBSW[EZWUZZUZn[PXSXSOUWXVVZP[U\W[UOOY]]OZYsZJXRXY_[[Y[\RYUYWZ^[YUWWJ]WZMYe[RSW>YYLRTLTaWZU[^LWTVXW^VW^WMQ|Z:TTV_WTeWTUU^VVXcmQTKbdQWSrV_UVVdSSU\Tj\H\VExXO[]UYR]DXICXQQYV]YVUWUVTSUWISXXR[PXU[QYXXROHXZVTQUUR[YWX^YSVXSZQQPPTRXUXYXP]ZZV]RVRY]T^VUW^ZUXU\XW\ZYWYW^XTV]HNZYUW_XVWZUWKX]SFVS_OY\XOVg[]SRZsVXTGWUXTHgUPhSXVU[\V\JV]XaXRFV^XWWYWTVSZaWVXWYUZOTWYVbRVXTYOWUXR^]_XXYS]XNVHSWXXZVSS[VX`VX^WSXUZWVTRVOZSZRbXVTXY\UW[UYWYWXUZWU\YTXWZ[WXWZRXYWZ^S[WWRRX[ZZWXUZKZZ^TPhNYWSZTX]YaZ[YN[VWUZQX[ZYXWW[QVSLUUWTUYSVUS\RUVUUPWUWQNVVi\R\YQ[WMTYTZSWZX_TAUVTCRTVMWVZZTXTRYUSRT[ST7fUM]STSYbb^F`YMTQUPEVGXNWU[UVKMKXLTWW[VRY^\WY\TVVXKSFWUYTWTTWfZRWRU]YjTTW^UNSWXXQ[aRVXXWWUUXRTVVBZYYRWVWTSY[VSRWbTQTZWY[UUOT[VOVZXWc^VPRNWTGjTQSSVVMWQW\TVWWVPTeZWVSWXPZWXZ^ZYZW]WbW[TX]VW[YWMYbWV[X]WWTUXYUTVXQ\UgP6PRYYYT_Y[XYQUVUR]K\QQ^ZWXSSJ\YVXYoTWTUUWWQXOWVN\WWXNSTeCVQVLXX7WqWZV[TWXVUgXXTUTSZTTPiUT]XVUZ\UIZV[ZUSVXYXUWTY_VbUVZScWWW\Ti[YVOZOXXNXWTSZSZVOYK[JVY`F\XXUXXX]XWZ^VYXQX^PTbYW_IZ]YVRdW_[\WWRVUXVYXWVWZXXY[b\SYXXT\QUVdXTVZXVX[WJY[YY_R[YVVXUXIVMY\[Xa[]WYU[V^XMUYS[UZlXRZVsZ[Yd\kY[Vh^ZZYT\Q`ZWYTUWUKYDY[4AXSPX\]XZiW3OZMUi[YIYaWZX\WYZ_ZzPR\WYSZZVUY[MZXXUCVWQSWSLfZQW[WTUUV[QWSSVWRSQSRYOG\KPXR[YQYWSTVSUVSD[UUXZAhVTbSSRUXYSKWVPMUSQY[^W]ZWYJXUTQ]\T[NURSTT`TUTTLTUZTUQP\SSQ_RX]UPZMWUSRYVSY\SXXf[YY[X[Y\[X_ZZ]V]XV\[YO\G^^QIUSW\n\[\Vv]WXDKJU\XN[^YOYVXR]YWNXVZjYSSUGNTHgaVV`WD]_][^Xi[_E\VZV[[YZX`\DX^VZYZW]\Sf_P]\ZYYSZFWOWTZ]XXUZVQ^YS\YVWTRX`XXfU^KWUY]YWWVV^Y_W_UZYRSRW\SYYS^\QY^SWWYS\[TOQXTVUZXUZXXXVXUSZOSYVRZV][RZ\\UXVWVYQURWUW[]WOSVS\VV]_YSWXYZRYOTXYYYHZZVZP\YSZXUQN^[TSSQUUUV^[WXTYTV]PVYY^TZYU_^\IT^WS[[UZUVWcWWaDT\W^SXWUYUL\WZR]SWYRWXYTDUWTRRSVSRU]SZ]Z\NOaN\VTW\MU\^QYYVSaZXNWYWNXQWWQSYR\X[UQWXWSXXZ^`^VVZURWTWW_UYXXWRP\UT]XVYN\S[RVYXVSV]\XW`YS[T[WUYRWXW^__ZYXXYaYRQZVWRWVVXYYUVTRTUUVWXWTYYWTRYZ[]WWXX[UVYaUVZX[WRIZ[VXcVZVWVkVE`XWCWXT]dXMYWiVX[eI|U`RVWWXjXWOZYWWZYSZgWa\aPV[\XTYYWQWU@bXdYTVW`XVZYYZ[ZZ`cW\U^X[V[QSYVTUYZZXYVXZ\Y[bLO]TU_YZ^XU^]a[XEZWY\P6WYUs{Y\LU]RY\\[P\R[+_eeeWM\][C[S\V]SYb]YWMWW\_op\^AS]]ZO8Ydk\T[[[VXWoZ]]]\[YV`[O\YY^WXORUae_]\[\_ZZQWS\_VWQRYUTWO[XQ^VVXYWW][XJTX\U\WYZQT[VWWWOZ_WYYX`PXUMP\b[ZY@Y][RXUV\\Y[YRVUXSYZXXV[YXdZQVTWXHYX[T]W^R]RWkYZS[MZWX[XXWXKQV[WNXVVRUQSZVWPUVSUSZMWWXW\RUZVXZSWODbO[[TW[WYWUKT_WZP_TXRbXTQcTQU\TUTKQ[VHUSWM[NSX^V[RVX`RWLVVTRWWMXXWVVZSYYLSQRSVVUTWRSRZVZXUUNWXTSVSRZWWVRU`X\NX\\WSNVUSRU[X[YOQ`RSR[WXGVZ\XZVSUPW_X[K`RIY]PV`^WVYSS[RQ]PV^SfXTWO\\ZOTXWXXU[ZWSO][XYZYYWXUZ]SYWANT[JOZ\X]_YQT_ZQKXY[U\YZWUZVYPRMS[XSWZWYPWZQTRWWXY]VXYZ[]USU[SXWVYVZOSYTXN]ZNSYX[YYYQRW]XV\VXQTYVQWYTUVY^XTWSZISURYZ[VSRWZ\UZV\YXZQQTRYUNZYRRUSX\XYU0VSgTVWVRUVW\YLUWXPZVUZZZTYeRLQVU[UUgZXVTSXWXDVUYMU]WWVSY^ZUXTUUXVWQW[WQJPWO`[XSWR[V^VWXXVUW`UUXRYXZVV]VZRSPVX\ZXYN\]YdSVXVPTYZTyVXNRYeQ`WXUOSg[VYSYOWW^[(\T8`a^VTY\KQ^WQaX]VHEaTYhr^UM`XVQUS[TxVQZOTb]XH[YK\\U]O`o\bS[VYSRXOU[VUWYSWVYXvWUUVV`Y\S`T]BZVU\VMUgYYPTXWVQ^eVUZY]WTXVTWT]Oe[RMXX_ROT\ZZTT[ZULV\U`[U\\a[]XcOXTSQWZWDUYX[QZWPU\ZTZXZVR]YTOWWTVUY]_UVXQVQWXgaXaSDWaYXLPWS^W`YVW`[WSS\VVbTZ[WWQ][XXXZW_ZYUUFSYXVVVTbc/^[VSWYRX[WYSXYVdSE^QZ\Y\X[T\\XWU[MY\T]VWZTW_ZT^SWYYSXYVTYQWhZOVYaXXXY\[ZRTiXUZXYVV\[]YX^[WWTYQ[\UWTWTaXZL[X\OXTYYUVPXTO\T_[XQX`YMXYZXYWYZU\SUVYZVXSgVbSOS`TXZ\\W]TY[[VXW[TZ[WYTV`TVTW]U\SYVVFPVTYTZYTXTUZQZcTUUScTMXZULWVZMTZRT\SRSROPVS[XYRXTZVVX\VWSW^ZMURcXSY\XWXVTTXZNXXYVSSTYTeXWYP_]OZYV[WZUOX^UW[TXZOOZUXYZTZXNWTOX[XVDVZWWMRT`Y]WXWXYPXPIXV_YWNWYUYXVUZ[VWXTXKTXXS`XVT`SUSPTPXVXWV\QVGMUWoSR]YbYXYVHVYVGNZU\[X[WVhVZH`[WS>SS[bWH__`BUWNZSZSOZWcXWYQWXZAWUVZSWRXU\\?UYZTTUSOSTXZOQTU_VMQ\WY\XYVLXdT^Z[]IUEZVVWl`WVZOgYb_es9ZPR_nZNZVM[H\O^MX_|ZXVu[fda]VV;VXVYV_WTYqWOqT_ZZibV]G\OXSZSYTY^WWWYXZ\]R\XXY`NYa^TbJ_XQ]O]PVZTZVWUZi^TXVUZWRVZWZSTVXWTcSb[POPW[UWW[WWWXWXZccc\TWYRY[ZW[[\WYTGYW\9YOSVj[UbXWZZUTTWGdVa]SYQIXcYUXTWWW]ZAZYTWVXUVTTRYWNZXSWVRZVTWTK\V\Z]WY[[ZT[VRQUYRZ`QOXXUYVT[[YYOTTTZMX\XW[X[YUagWaOM^Y\XSSSSS\VZ[YXWZXX[WJbWXYPYZb]V_ZTYWWTYYUSXTZ[T\K[RZTY\cTVW_ZZZY]TW]VVV TTKVUMUNWWY^]QXWYOZWUVWYETkWbQLZ^UTOXWWVKUNXhRmNLX]RXST]]iZUUPIWTWDYNYKY^XRLRUYS`VVjZZ^V?XVVUpYIYXWWWUVWTSOTV^\RWZPY?}YUQ\[VQVXXYSWWSZYW[ZRVXSJHXWX^]X\WRQWV]_W\XYKWZSOSWPXRW_YXRU_\YTSW_WXbX\Y]S\ZPUVUYWNU[XULXYWf`TYY_ZPTUTW]UNV]VW[]WUX]TVSNVVWYUWZ_VO_XQ[XSsVY@ZWVUNWUUSSZXUUV[RUUUblMb^Y_PQRRRYTTVTYVaTdQXXU\WSSVTXXQSWRQgU[WX[O_]IUWP\QZV\JPbbWVUVVXeRNTTXUWRTTZgPTTWUTPTO\`RJTSWUVcV`X[]XYZ[WKXLXTXWX^VWXXTUXVV\YW[jdYK\YVYm\YVZSXQX_hXVUZ^VVWTW[ZWXWWdVUXnZa`]ROWbW^]XSNMVKeWZURYTLVOXUYXV[ZSWOWSUZWQTUXQZUkYXZWZOVOQLTYN^YUX^STWMYZT[PVUWTTVUHU[^\XWY[WZ[XTT\ZVWWR[ZZVJ[XW]W`RU[[cW^ZZZZ[MSOXVWWZW_VNZTXT\V^YPYS\ZZV\UTOVTPTT[VQYQI\KNL[YbYZXU[URTTZUKUWESY`ZXZ\_RYa]Y[XeTYV\T^XiP?W_WWVWaUUY[JYLY]fZP]Tg[XXY[TUYZV[cVU[UYA[U`pZN]\\\UXeZ^E[UVNWX,YaZVY[UZX_`u]U^VY]ZV[UVUb\^XRZb\_QW/VXKXV^TRVUS_TNRNWYWSUWXdTYcB^e_YRgT]TVWSRVUVReKWSYXURTd[EIQWRSYW_VU]YWVSPVX\T\UWcXYXQXbZQDHUOVUUTRSXUTZSTQUYbZVZROWWVYZTXQSY^YVYEVYUNZVRVWTXUW\[RNMR\T\WWYWXUVTWWRSPYQXYXWVUTUVUWWRXWV[TSVNZT^Z_ZWVRfZ[RV\WXUZWWYVUZRM[aWWZWTYWW`VWV[\WSWQ[VZTR^UW_VZSVWWaUCXTWXNSYZUVTZYXYS[VT][]ZQYYX^VWW[QPRQTSZY[WF^OXKY_`LXZWZVPRZYXUTUU?TOSYUVQMXVRIUOVSTYh^TZZPZUeBKdaV`RSpTVWUSVXSCqVSUXURTVGYGWUVTTUSYWNVNSNL`RZYRYLYn6RPLTTW_RWOTLXKVRWUTZQPZZLSSXWSTW^Y`WUYUU[XT\M_\V`T[TU[WLYZWWUTZV[UTTU\YNS\\UZ[XUR]VUUMT\WR[a\UKT\YRWSWXTZWYY\SXUYXSVUXXWZWQ[WYV^RWXQXYV]VUSUGWXYWUXXWX[TTQLYWUc\XYWXWZX^Z^YWXSUW]XXUVXWWWRX]YWWVQYVYVV]]_PcTaX`T\[XZZW^UWURPEWWX\`VYWVXTUXXUAWUYKVZVW\WXVU[XZXXTS\\UYX\XT[X^ZTWYWUYOW[XVVXWWWXSQWYSSVUVY]W[WWSZZ[WVZUTYVWXXRXY[W[XXYVXRX6WIT\TXUXY[VXYYYXVRZdWUVP\SXOWLUVZXXhUXZ]WXWWbRYRUVYVXTUZ[KWXYMXU^Z^ZUY[UXX\XYYUVWVXXXXRTTQ`XXUYNWF[ZHaSYYS]USZ\YQXWUHUS]ZQRKUSYVXWQYPXZYPZVW[WZW[TSWXBgYY\L[\OXVOWQUZUV[aXNYTRXVWT`iWWUMPZ`VKW[c]^YVVYac]bU[]_NWU[X`TYUUiUUZXV`RWTSYAWYa\V`Z]TUOSZRRUTYTRSVSVjU`Q>VK\nQRIXZRUMRQV_N\WIZXGX\JWgUUV[]PYXVGUdRUkZPIrY[KWUXVSZR\SPUVaX\SPUPUSUPRTUXITUSSTRPWTSVVWSV\UXZSeWRUWXZUXYWWWR[]UXZNVVXZ[F]PPTZFVUI\TUWZRcXXXaIPU^XSYWO\XbORYUTtXU_PXQOZNMXWRVVUTV_ZoYX\XOTYRUKWRXTUWTTZgUQWXX]ZXURVcW^UX^WX[]ZTwYU^XW\XVXYY^Z_YZW]aW\XTUXVJT]R`SURZXZUWXrX\VXVJYYNBYUWHYTQVZUZaUUX[XURWW^YO^TZVVTOZ\VX^WTWWPZOXSWYZUXP[U_V[XZXYXVWUXUSYWUVW\^VWOWU]VUL]QSTO_TTSVQSN]ZVNPSK9a>D^KcXRSS[RT[XTR\qE\HTGOUUDQRScT_WLVVO_TMWY>SX\YPSSN[MZ@LQTRWTQGVJSRXNXUWRSCNXOSTNQL]ZXOJTTTQRQP[Z_fV]VVYZPV[WXRXSWW\PX`R[\T]\\OYYYXPTVUUg]VVZ[_]]\Q]LjG^XMUOZYVXYbYU[OTVWTPSX`VW\[WSYVMQZUYX\_Q^XZTUYYcXVSWXlMQYWJT[UZQVWTT[XZPaS]?SRWX]UV^TZVS]TWVYTK]W]WTVTN]HXWTwORMWX\VVYKZ[\aVSaBXXRW^ao]YRSBSV[QV^WK[]ZM`V[UXXWZVcV]QJUYOT[TKVRPXVWQ\WWQSWV\Y]\YUKZRVVXRXY\]P\]RQ\f[P^U_OTKZeYYZLZb_W]eUbQIYV_ZfR^XZ\W]V\[YPN]O`UdWM^PYScPdWVThQ^Rf]Q_VXN[]YN[K\V_bR`TZ_RYP`]a[_[VTWVf``X^]NOJ[T^SZ_YQ]PU\WY^UTQNZmMbVTT?XA[VUWdHWTXQhUfRwZXPXVYDTVUYRU_ZJ^:Tcf[YPPZULLeVUS[ROVgZLeViXQ_bYSUE\T[VNVVV_UVHS]VVVUYYWAWM\WWRRXY\aSLYURfR[SFQUMDPcLOP_JIK^PDQGLVIKMTJQJLI<@F`NoTHQRRLO\LRRDB4SGOGBPWWOFEZNUM:N[SLQIUa?:MOP[VBUN5LP:FWINUWUN7PDQMNMOJDGM_COOCDKPR^KQIGQVILHNUUaTVZSYOVYUV[^PnVTWXvXWWYSxSiZ`TF[SZWVVRYVKXSVTglN\VOVTXUR]WYXZXsS_UTOX^eXTOfLZXVaLTiaVTTRU\\WKWZUWTVXIY9VVUVTWSQRS]VYZXWUWCUZUV\XWWXV[_XUWY[[V\UVWSWSQYXVYTUXYWYZZTWZ\[UTTXbV^XSE[YZX[ZXXXXYV6WXVZ[V\VSWVUWWWEMWXY[ZWNWXXTZVXU_WPYXQTX]YXXO_S_STZZVWV[]S\ZVTXYRXVTVWS[]SRUQTWUTPZWXUR^^QWQ\Z]RUXVVXXUSVSZ_U[XTTSPeVVZ]`RUZUXXSXSUSUT][YVO]WUQYWTWQ\XY^W[W^W\TSVWY\[UWRNYLJVZX^VU\TWa[ULYWYWUWYW_UW[XYJSYXUSTY7WWT[T\YUTSOWV[WYYWT[TRQ^YUPWPZJ\Q\XMYOYZV\[[bUP[USTZWtYXWQZUPTZX[Pd6_X\TB\]XVOZ\qIeRVQ`KXWW_ZW[]V[^@TSRWVV\[PW^L]\X]bYPVOT]VR^]Z{DRZ\S^aXnBZUYlXS]ZdXUZYZXVcYwWPQY\[VVZbjW_PYVVVOX\ZYUSbMW\U_XZSXZXU[P[XXQTUGWUYYVVWWZUTLYTTZUWYVUYSTWYUPMWP_YTQUWXTVZVUXN\WWVTcVWS^R\WQ^UUOUSXTNXZT[UU[IW`Z>\TUWV[ZCUXUVMTSa_V[V_SQT\P[SXSST\TTRZ\^O]Y]XR\ZYK\RX[WY]XYXXWPQS][PVMX[Z\i\cZW^OPX]U]XQ\OWNX_ZbUZWL\WUKOXZ\]Y\NYOSVUUS`YTQNTTRUWZS\ZYUSTTS^W[U_WYYP\]UVVVSXXTWX_WST\U]TTRXVXSVXUxWQ^[UQQa^QKWZXQ_UYU:I^Yc[GV[TWUTJNV\ShXVWpPKZnHAURbUUTV>[Ug_UPRSSVaVGXTVXVVU\P:OZRRTVQUVT[YZ@SVZUUJQXQh[bUHMYXZZd\UWVVRXTLYYQRSUWY[VV\XV_ZRUZ]TUX`VXZS]X`WVR\]UWUPWQX][\VO[XXYVQWZVVZXXUVWY_YVXWPZTW]]UKXXXU]UIUV`U[WOWYVZYXU^SR[LV\XH]aYUYSZUZZ[PWd\\\S=S[YXYX\QdiIWX[W[H\W^YWZ=[^TUYZRGZYUQZ[]T]^XSWZVV[`YKsh[VQXW\RRw[m_]hX?Y]LXqVW[]W\[X^PUT]Y]\_[WRUXX}^W[ZTYYX\ZV^SXSU\W]YP]SRL[\ZVLaUX][[W\WTOUXVO]P[\fWYVUV\SO`eZTW_KPSWTVX\U[YU\OVZU[]XUUTeYYZYaRU[XaVZZTSSSWTQRO[WHY\T[T^W__XTRMY[VTWRUWSYW^RLTTUZVYWWUXVURU[V[RXWP[PO\TV[XWSYPbKX[]\VWV^^\[Y\[VVPWTYWXNTWYQ]UVYP^ZUTXYUSWZUTTX`[VURWOZVRXVYTXWVSY_VTSZXRRVQXWWXVWUUX`ZVXX[YO\TXUU[XIZZYXWXUQXTUWYNYWNUYTTZZWY]WUV[RVXTQXUYT^]]TZWSWVUZQU\YT]ZUZVYTXTY[VQ_[YUYbSYOWUY]]VOXS[Q]GUOYTWQWaV_R[MVYVZTTTXUTXYV[XQWQFSUOU\Z[YV[hWY\TQZ_Y[ZUXJkNrX]kYYf[[WX[YR[UKj\]^GW[SGYWYVUVXWNZ\XXYWUZ^NZgQVNQXUYW]X|XWYXXb\W[Z\XXXSXcYUZU[VY[U]CZSc)RPWU\ZTXYZYYYQX]^2XX[YX[VYZYUVZU[`WQYHY]WRM[[][SV]VVkYnE[_VL]UlZlXVXZUY[PVSTYXWYYWTXPQXU\ZYTZMXPYYMZVRU[]\WYXXXQbWZVXYXZUXW]W?NXMXUWO[PWMYXWVSX\BL^\S_\XXQVMR`ZWZ]XV[TYYaWULXWVWZ[ZMCVuRZX[YYW]X\XWX]]XVW^d[UXYUTXRUWZY^YZZRZPXVH]QckYWURZSVYZN[VVW[TTQXTX_XSWVSVY_[[SY[UVXYeXMX]STYNTXVX^YURZUWaVVVVYOW]YXVUVUWUZXYY__TUXXVJQWZYW]SVP\U[\VRYVUXUWYUUUMQWWS_VT[[YLVVWRRQ_TVZT_UVV[^Q\QZRV[XYa]XVVQWX[LYYR^]WUSO[RWUUa[WTZT\]WZIUMTSVR[XTWU\ZQYW\QQWUQfZ\XZaV\RVO]VUU[AZVUXX]ZRS[USY`WTbVYa\WNXWUWXXYPNTWVXZWXVTUYWVZYWZWWYRZ[U2DcYWMZWNVOYWLV]ULzcT_QlWUTMVOQVWUY_T^XbTgRSZQTbUTXYUcmX]CXNXMWWRWIXYVXZUWZXeV]QXSWYVW^P[CO[U[UQXSW\U\]XSVVTOY\\F\U\W]VVXWYZT_]abTYOWT\^`Y]Z[VZYZZYcTZS][ZYJW\YU[SUHXVYh[I[UVOZfQYYYVUT[i_XR\WYWZ\~[_Y\W[[ZZe]T]UYWY_\UPXb=XXV\kXRVWZXVUTVYdWUZVTX\Q]WXPVYNP[YWZ[aZ[TZYROSb[Z][ZZZ]VPSQNTV]`YMWTRXWRZUXZPXSXUPVZSRV]S\[U\Z[[VSZSTVVXV[QQYZ]UWWWPWWOVPaZXQWZXVXV[PRSTdXX6fXWU^XR[LXPTTUVZRXXYWSa=aXA]OUUNYXUV=WYXIPdLPYPPWUZcZZSXWS;V\WHYS\NUYVZUWZMSKZZHMUQXX[TTVYWK\TTVUbTNSUR[TXYXUk`TUkWWOQM[dUU@UJ_VUWUWTQSNWKSNU]KUSVSOLUc;[R`[WYTYQ_TSLTUUXRdPOW\QTVVSRZ`QVX]SYTMVYU_\ZS]^UUMUX1RWYUPU^UYPQJUSWTSPVLRPQ[MWURRQWX_QFJRUTT^SXRWSUVk^XN[YYYWUULVTUPMNXSP^TQSDSLN9ORUJMSD]OOQ2NEPQQ;VTORLXPQDKSNLXI_JZlMcOVRTKMNIM_LWULMNHLIOQQQRDJ\GKLPVTXZHYWN`WYS]TWWZPHTTWWQU\WWE\]XSVYZWF]YUXSXWXYY]XRZXYXOTaUVWYQXXX_XTUUXSYZUV]YVWRWXW^]VTWWXY[TY]RWO\QXYWZ^_U\UXVNZSWYOW\SS\\VVZQYWOUPUTMUUZ]XLXZSUZVW[\XZWSMVU_]^ZXXMWYSYX[TXUJOWU`]VZRW\[bY]XYQ_XPZXYZRWQX[XZOYPWXM[UXXVYZLWY[WRUY[OY[X\VXT\WV[]X]WXHXWOW^MYYZ\WW\[WUSYW\\VTYWXbZVZX]SQUZY^YUOYUZXXNXVRQSVUYWY]XZb]YXLVSX_WYUUQWTYWXWRYYYTTVXVWLUSYUXWWW^WOUWSV\VPY`]YUYX_YXY^QLHZYXOXTTZ[MW[XWYUPE\UaYX\TXVUT[MTKWUYRMN`[IXWTQ[ZZWKYW^WTYZWMT\Z\OecXRWWXYZWPVQV^Ya]SZZVTXSVXVY^SVU[]Y[Z[YK]XVXW]XRLYZUWWOWKWWR^WZ_Y^XW_WPSVY_[U^WgUXbYZUXQYUYSX[[`^ROVVXS^YYVYUTYV`V^XR`_VU\VWTPkW[UVT`\[SW^SQ`WWX[_VTT\ZWT]SU\YUZ[bXYXV[]UW[VWU\SeW[UPYWW^^_`aWRXT`XU]TZZZZUVWpWWRYVOUWUUV^[ZVSUX_XWWQT\ZeYXPaWZ]TTXYTWXVUVVNW^QV\YVUSSL[XTYTQTUX0WKSaTSV]UVQVWR[SOSVWUZWUPYZVZUUSVWNTS[TVUVWTSVPKWVVSUUSRS\[O`LS^X]\WU]OPWU[YYUTSQMTdXRR[SZVX`YVQW^VTVWXXQU[XTeVSXWT]VWVXMUMTKWKaWZYZT\VUTRZQYVYMZUbYLX\NZWXUUXWH\WSUWYYRTUOULYZXRYXXUVQXY[WVIVUOUYPSTYWVO][WTUSEXYUVO`Ymb>W[RV[YMXXUVbUTWXZJVVPNXXSXXRPWWQWJVZWTdPVZTUZQ[[RUX\VpVUVT\TSPX[ZWVWWTUZU[WUYTXZXXUbWZ]JWUWVaXhUZQWUUXWeXSXWUQZTQSWRYVUWWTYUKVZEYVb[VZYRVW_TQV_ZNWPUYTXYKTUXYWYTnUYXVWUQUSMTRX[VWV^XQMVU[SJX[^VWVTTVSVXWRXZVUTVWSUVVWU`YTWWVOVVYTHZ]ZQ\OXXWY[uTWX]XXB\YX[ae]^GEaU^[YYZYUZ[M\Q[Q[nOVYT_\U\_KcX`^ZMYN_]XYVZOGY]JTc_T]eWAJX\]ZXaEY\XZXWX][_a_\XcWXWURYPYVTY`XZ[XZbVWZXTOUSbUVWXVQXYXWVWMNTUSTNXSe`GVU`WV@UXVXIV[VWbKWTYZWRW^XYNXUVV_XYUUW\SYaQXc\Z[TV\XSWXVNVJWVZVjVXUYRWWOVTUU[TVRX[]XNT`aUU\U^VcWWJYRNWVXNVWZZbVTWXWVUPZVUUGX]UKPXWTXUYUVWVKXYVcVHWPRPaUXQWSSVY\XVZUYMYaTQaU[[YR[VYUN]RfY[UWYSIXEWPWWUXWQ^Z]SXXWXVSUPZSYVZXWVYXJVNXUT^^U[SXSW^VYYV[TUYMVZTZUY[ZR[PQXT]^YSU]WRW[TZWJWQUKJXWTQXURTWWYYX]O[WTV_ZTPZYZWXSXQYIY]VU[\VQUU[ZVYZYUWRWYVSTXY^XXSYNZUZWSVVVYxVSSXWdZQWVZPWXRYU[X]UVUZFYRhY\XUU[ZMURTVWU^Ve__`WbUUWTVXZZRSX8V]Vk[RWZcJWYUZY[WS_RbXWVYQVU\UWUWWU[TVMWMXVYXQUUZYSQVYIUXYYXUOXPZORWXYOcWUPTN\WXYOZYNSQZYMWkYW[`S\WVbOJXQQOXVQSXR^^HbTN_\\^Ya\NgRZW[NSYVNWV]SINQT[QJcPS[N[XZ_KYTNTFJSYV]_[X_Y[UR=VWYS]d]Y[RTXZWV\XZCYW_PbXXUXQ[[VTSo_YT[[cSK^HP[U]VY_XTXVKXSV?@UTW^=WUSQ[aGT]WUNVR\EVQVUIVYOPQSYUSeZ_VYeWXSW]X[WRWYUZW\XJQZYVWZUWYZNV_TZUVUVXVYRWUUSVRNJPSUTWYXTWTXG^WWZhKUACIdaZNVSSP[T^UcR[VTRY[N\QR=TLQZSWL]PWYGZGU\C:YVMURWRQXOELS^RXT\GSISVURUSS^[_Q\\UQRWKNFUUYIVVYTQXIUU^VVPVYYVVUVVYWWXUWWXUVZXYUQHNR[_UZZUYVVWXVUaSVSRSMVPUTVTX]SUUXUAXWYQTPUWUUVNZSYSWQ[TBTUSXOYV]UbVRWWWTTTYFQRRWYRWSTUZUPRYXRU^U\UWUXVMUW[`^XXX[MTU\UWIKZZY[gZtSR[gT]\UA[XYY]Y^VSPCXSWWVUX^YTSUUr^MWj]fTXH[bcUWYT]ZZWh]NSWPZUW\d[][V[WUVX\SU\LXWZS\WPZ[[U_XWZZRUGYUeZWbWYQU[[Z[NYHcX_UIJSR\Sk[wJDFQ[UY]MTRYYS\P[QMNSRbZTXRW[ZYQdL[XYNZJWSYWbI_^\WX]ZRRWOkYYXKT\=XVX[[a\YhdMQQYYXZY]]S[ZQc[Za_d^9RPUQLMUHT^ZO^KYRZJPW_OZSM[WXLTWVOLRUTRQSFM^XLYCYcSJLX?|QLj]OcUNWLSL\O[^bTWNGNZVTINcXUVVTT_TXN=YQWNVPJPKS^\^UD`OQW|OdZdP`PPS=UY_aWWtQUdP[WZYYXX\[ZXZUXNW[YWV^TS@IcVX\UXZ[ZXR\YZVV@eS]YS[[WTUWSYUWZaXYTZU_RXIbY^QP[UWPNVNUYP\^XR^WUXVYXUVWZV]RNWXYWSVVUVWU[WWSVWUvVWZOBT\_PUWTQLUYWUZMLXVZUZYVXTXSWVWVZV_X]\VTXZ[V\TX_XdIZ]IL\YXeTRYUWXY\YQU^VLZXX`WYWXWRTYW^XSjP\VTOUYSUUX]VWXYSSTR\V\T`YVZUcTTTX[WAWY\]W[`YYZW^XxXUV^TRXYUYZWO\l[T[SU\RXZX[PXPZ`j\S_W^SYZ_TLYWXXYiZYSfX\SQQbZcMTS^ZhaZNZdZc\XPXbW[YWW[ZL]gVZd[WZY\]QLYXZZW\V\Y^XWIVRWYYXS^VUXVXVYUVSRRUYTUS[VKdW[SZVSQVXUUTV[WMaRUV_QVUUSWXM\ZTPOU\XaXBZ`i_UY^ZVTUSRWJfUWUWVYUU\WUUVRYWPULXSUXUTVUXZTXNTTW^TOWmVT7XUIYVQVRYQTaYZVTWXSXUWZWdV@^dPiWYUWSWTUSDVRWRbMZTUNUXUQYJSSUXXTTWX`WVWVGJWK\XVSU`kVTVSWVOYSQVUVTWUUWXZQGXYSWWUWUXUIVQgWWRU]V]U[^^_]WMQSXQ\NRYZXXWS\aJV[NS_ZVTRVYWWYS[Qa[UMXZYWWVe^\XX]S]VWZ[U^[UXY[XTWR[XWZ[YHUNWY]UZZZRXW[U]X]YYVA^VWVVYXe\Y\Y]O[UIXXdYPJRX\\RR[[XUYPYWXW[KYYV[OV\Xd\_XPXXaQRUW[X\TTWVRW^WYPWWX[WV\WOY_bRYZVaQ\X][US]SZWUQ\\U_VW[^YYUZUUSXQJYXVPRXZWW\`MYT\XTa`XXV^XVXVX\W\ZY[bT]]XYZWYRMSUVVTXNXSTZWWZWRVXU[X[VWRZRSVPUPX[[\_RSWWUWWWSSUYYYaXTTUT[VVT]XSWXZUSWUYSSY^ZVXHQUSWXTXZOVUV]STR^XTVO`ZYWTUZTWTO[SZY^Qad\Q]NXU]_TNZPd_bLeU_Z[[F`PUZLYWX]Z[X`]_V`Z^JN`[NT\WWQJc`\Y[VU]XTXL[W_TW`\MhOZYWYP`I[ZT`YX[W^LYSY[Z^YW]NZTVX]W]fcPZUQ^ZUT^UZbXVZWShXXQZRWWUTXLTSVTQPZUSXKUTMYY]SSYXYXSWY`SYVEUZT\`IO\XdX`[`TW[i[QVgV]VP[`TY[WVVVZWV\VY^V^XNdWUWZXXWVW]Y[UURVZYTTRdR]Z_VXX[hSOUTTY_RU[TQUQWX[SXRSJTXUUX]\ZSVVVYUVWYSZLOaWW[WWYTXTEXXXU\SZPZV\Wg[TVGZUWX[V[PY[Q_ZZX[eUZeVQXSWU^TRRSRQVYUVSbSU[TVSJbTV^VTZ[^XWVZWY6VRUWR^S]SXU_XOTTTTZPRWZTnXqBIFYSMWWTSRTVGV\XGeITWXZUUYRWhLXSUS=SYVpVbQXYYVNZWWSTZqVY[WJUW[ZZZARUTUTWXdUJUWPUUWUOVXKVC^XTTUUREXL[`_dXOOY[RYPQV^[XYXWWWYYVW`Y_\WV[[XZYIO\TVRTXTYSUW[cSaVSTUY[YW\ZGWVdeXYVVVWVTVZPUXXYXXR[YYRRYZUUXU\UQS\TWPWWXXTUV[_VFZ\TPVZVWZUY.YT[VTYWWVYO]_VPVVPYSUXQYh_V]`PhVWVWSV`TQUQRVCMU^IZEYU[WUSFUYTYUZUWZWTZUHGSJ\\WUXY_[SXPRWU]S]ZEUQSWWVULSR\VVTVSP[WaG]MXSTaVKRZTTHTX_XS_TVVRR`W:RSST`UUXUWZPYPRNWU`[WTYTTRQTWRO[TQRYELVWSX[NTUSW:SZVEVLQRT^REdSVNSWZU?_TQXPXQOYVVPTWWTUTO>RYMXXWRRVZPWO`TUOSNVcXWRWTbUTNXXTU]UZXMTYVUPTS[WMK[VXXV\VSXWXSSXYWVYWYW[PURRYWWZXSYQUXWSWWU]X_XWQ\]UVLWTWR]WWVZNYU`UYXW^V]T`MTX_XSZXUU^cYXV]VWWSUSWY]PXYR[YVU\]WS_\UYZPYX[XNP_YYXQYTWWZXWVR\TX\UXTXWYUXR]TVYXV^V]SYAV]XXU^ZVURXWWQ[WXWVVU^b]YVYXWZSYWUSTYSTMFX`]WWPPS_UQOXV[U\OSYVYPUWFQUIZTUVZV_YbXUXYT\UYSXWTWQRTW\W[XVXUWLWWXWOV^UVYVcg[W^QZWVVX\V\XTZTVYXUVUXW\WWZOXWSNZXYT]V\VUPVXRSV]PQ[QVXP\XU`\Y_XXVUW^SZXVRWVWJTVNOZRRHVUVbUJ[YWMQ_ZWTR]OGfYYZV`JWtR\XTIYQ\LbKTIaD\TTN[HbU[XQKSZ[EYI`WbOY]TR\ZSVOYG_WbT\R[OULVMWRNWUfYMYPTVTSXLV_RVUQWSVWHXpWYjW[Q[WWXeTVQ_YQUXVT^HWZ[XTZ^S8PYZiURX]ZWTYYY`M@QF\KVT[eWXMSZZXYVV[MU^OZWTTZYXXPVeCWMWKWWVWLYZWVVWSVW]YYZNPZXZXUS]`X[DYTRVUY_UX]WTiVZSLWZVX]XTXZWSOLXVYYO]PT]NVYXVVMTHZTSWXUKZRV`UYHWW`ZSWS\VR]YY]VSX^PTZ\bXXWVVWUS`XYVL^^XXUYWVXSRUVTYS[RXTTWbY`W\XWUXZ^\]^[[Wf\P^UVXKWRTQVXZQVRSYPVVTPVZ^QcP\UZUS[XPZTYVX\[UY[]TNLUVcTYcWW[VWQRWUZVZVSWX^[Y\YUVVY]\YVZYZ^TUXXYWSLWYWR[W\YVVZX[UXVWWVWRZYaRPWZZTNWWcVVXNXQXWXXZIYWQPSPRW]WWYZZ\XXYZRRYQX\V^X^WN^\USXPU]YSZIXTTQW]^XYTT^VXXSW[YXYXY[Wc\ZXVYU]YWXXZFXWW[_?OWJEU[[W[ZVYY\VZUVVVZSWVXaXSVXXVV\[UUZRWYSLPQ^TUQ\ZY\W[VV_U_VUXUSWVKWXT?VVMYXY[WXU[XYSaWYTWWXYWYUZVVQ^QXSVXUPW\WWYVSYZWXYQTZ[M]_SRTUXOSaXXM[XSUPXYXWYY@Y[LTYKWPXY[TWU]ZYXSTZZZ^>Zs8RR`ZUWX\ZdYUOZaVhX[YSdiZXWZ[WcQaWV\ZY[f[a\Zc^Y_IW\SWNJ^wSZPXUYZYZCVTYZXXWXZVZUUZZ\XbV\vXF]XWUZP\KUZVUcTTVYS[Z\QRZ^_PZUVZ[SdVY[UWUSX`WWTTYaP[WRV[UT]U][eSZTJ\^ZXKTXT[\VVXXSW[UO`XRR`UWTKRYW\VY[ZYUWSUNY\VLV`VP[HOV^TXXZYVWY_XabTWXRY)UT^ZUXSZXWRa[WTWVgXSSX_VTHWQbWXRcUOTTVTRU\UfOXTQUVRVQdXMLTXRU:V[TZVAPNF_UAdVTRXHaVAaUNZIXT]VFYPTUZXWHQDUPTVXVXXUVHXGfUYVW]PGTMT\V[VRZXYXad[]YUJdRVZLRS[Z[YZYUYVXVWPXYS\U^XL[XZQbd`UZTX^]YZLVL][X\\SVUV[WWWXS^]WWPQUUKYTX^_Y[WUXXQYYXVZ`YZIP`W]CUZZWZXYXZ\VUYUYK\\YWThYYZZW`\IZ[YPSWX[\UQ\pJ`mZVOZ\=WnVT;WaZ_\FRR`FY]S^]_KYaXYB[[X:UPXG\aVTFRZNTLUbapYHV_WRf]TWTXWXY\f\hXLUWZZd[`ZZZP`W[OSU[=كèΐpᾶž~kuOuُգoiREMlyoB~b͍x£|Ƣ4d֕nQ~})w}mo~Z~zk{hevv]~zqno}jrw~jy~wo~yyy~uco{|vx~ȯQf}gmt{ęřƗsx|kՌ~utuvu~v{dzd}v~xyx{|~z{z|v~vh|yury¢tĊzp~{z\~ژחwz|{uzDž}}l{z}}{t|z~֧|_|]ɗs`qtj{}|k{{}nɘzzwoΚwxm}szm}qy}q˙}syzlzw{{yo|svowvl{xwwŚ{^~}{~}ĜysyvĔznsn}~Ιqyl|{xz|~~}zql}n}{s|w{̚|Þzwz}w{ݖš|{}yygkØ~Qyy|y|{xʔ}{|i~bv|~|~}sz}pth}~}qxq{lyvx~|~uuymzÚy~|~vtskn}ԫtytlyuyw|rwlÔƚxhbvv|wskri}w~x|zw}}~|ow|}tv{yw|z~}g{}yɖ~zlvä~zx~wx~v~xwwysxs~zqs{}}rnv•՘{{{ƒz~|yzn{{}y{jt~t|~}{~{7j`}~mw{o|lVtg|hg|~{{zhuzn}wv^uw~~xve||po|}~t~|{yy}~||~|qvv}|j7kwrvwO~|e|uS}o~z̕Z~||@z}x|bzy|w}~|~|]||yx{}~sx|xvt~|{uJV`xmf N}ȅ~~}{|zx8px{~r|v_o{x{}~~~n[zsy~vTynq~~~}zs|}{~}s~~~v~Uy}~{z~~{qsšl~\XWz~|f||6\||ks}xsgvzsuba#k_ښ{Řz4~|wYA1yKqPǕ]y=E;zzbdm`xP@Hmۉd ,y'qNxŌzOruYg_fmihCdl}woccn'{xs`N oezyWw]]ȃym jZolAi=gWsv[c&z`S8{^^gtpwtpstktujsofqghmss}wjhspqysvlljppuvpqswji{thwmoy}poloqtnvmihqvpnrhnrvtsofunuttuchs~reupol_nrvkxnmujofyssxqrlkwyupqnpsmuktqqtrrsruqyumtvrsuqtmlsktmjukronorrssuoxnonrpzrnonptrtvol~onnsri`rspqmwopyporwpl{ps~fvptkk_woit}wpiuouyt]qjlbltvovjqsso{uzmxhlk_glrknorufmwqVmfremev^srfoqrrmsdvlcnwtnypwZaorpuewl}mnozpqqnhjswejmqtjysofknjostrxjiiexrhktilklpfgsipgoogxt_tfwxddoobnhqrosppqwqrypqpsq[qoqpppqonponrnpnspotqqpnpr|qpqporspqqmpoppupnoobnrtevprg]|fmouqoi_lrw\ffwuwausmtkbsunyXorop}hre^ryqz~fjm^fmeokjkkl{utxoxqrqqnlvqzssqnisuywnwz|otrrqsqnjpomqsf_{zqol{odpptlpxu~tmirjy{sdmjyziq{fwohmpu~aswrowlyn|hil`gnfrqgnnmin|mzpqxtvoxiklqwcz~rplpmvxtsgliv}ltvntsunxqtpx{qpjtmpnqrteq{xveljnkmcyqqjppsTcbgjpwunhnluqsqn|jfjmloomsoqafurvqjnrtes|lyhkuljskp:rsvvrso~cvGpqvdm~low~wt^rc|nusw[dthl{hpoyssycwtwmzcmjl|Ohe{~Otenrl`dpnvY^xk{oz{~mple^urqc`wqd^qosytn~jq|cmshiirybohjnrxlpzcpvkjiuijjklsithqokn|~svocsw|qyuqtotrknoyonmjnutvjjqvvtsruqmomdtmjftghnpormtsgiokrq~oee~{ndkptofmzt'om`mudvkRvrxnptywchumylkvzp}}qur{}gromiwktnkq}v{~oordnvvqlwkhkkopitrnqqy]ovdk}yylskkvnvwsz}ytsnjk@ollyq|olktjthnnn{rswnprtqj~msswwykmjmqfqirhrsmnturpo|sxifkprertpnqynvwwlPqpakprlkJw~rtwfkiusxxohvtl}vqotrnwtbnz}}xlnprnrttmSyrvvwtk|~yWxtmpgqxuwtwrplvrvqqmtcotwuzrznturzw{qj_ssvxvqb{}x}h]qoo`fLqhhtgvl\tjsprvtbmgtq\lpmhjojq~mxnsqjknbxwyzk}Szuujclmgqnurpmktumuukixouussytqkqqj~poquywoxplpwr|cqk|pottssmvqprimsrsonzohyu-txqvpntx|{cmowktlwurp{zuqpoHrsrooown~tyw{xkv{pwXpzshssugrqguktmrYqwpknj]bqmahl]vqwyozrotmjnl~opkgommmchqxrngqx}oqrY|rKeer{prnimqwsd\gn_bwrPdvqnbszevdhg{sprfpprztrZfkyacxqElT}budqld\_x{mall^fpqo{m\spchwkhuslsK||bnrtmruqvp{jxrkznrlptrlsqrqmspsupsjrjopl|rktrqpqtwklsnjvskqrorunoxphpjl|}{jvpvq{swkkqhtw|hr{oukmz|sjxnxysuwohokfmt|p}urv|pegrftbnyrlweYetfsd|{kubxsppijnpvl`mwqiuag~kpuwiiouc}idsoikrd]elrsmcjunreohnjqvgsursuklvnbfmnuqysrhljutnmshd\}nswXo{qsoohipcoqnsow]kvmorqpltemmnshukprhoiunvp{mhisoqrmlofzqwpt`pxcrohuumsrijslnsryessdynnrmswrugu^lmvminolmmqslxipmoisp{rnrnokpr`opjrqp~bwnsrooqrypsrnymmvtipujnoxsomlgpnmqpomprhrportnqrmsompo~usrorovtojhotmmtjrttmmqqwssqpjx_qkywxouvqkssdapmnaopt}oqhxcglooopjrlngetwmpswusvosfrtkkwz`qm{iegrrqpulmtcqsgrkosmtojunlpsxmrttkqqgtrpkujqsnmit}atrcfhbsjfuqYutnu}rjsvnpeq[ut{l~umwlw\Yuk~xhtq`rnxvlss}s[zrronyhmqnlwuupghayxrrlqvznsrocolxmndfvluts|y}|quknqrcspopoppwsrqvpjqonqrpomsrnppooppsopooopppprnpqqtonppmrpumnpxqpnpctqu^plyrduowrwgvupntrqomYqlipkn`hpqVjx^qkfvhgp]arvRgn]wbmtvvdhri}sssesq{cte}qthUnyr}mdr|rpkiqzr}qmixxwgxp}pwsjjv[~sopywWrwwvsYuqhctysgoxvqpjwuxpt\yw{vvo`urwfwstt|fssufdwulfw_rd|tmhrmomomq|djhhxs``aivzfgpfclsskjmhrjfreozfieliifclitonizhw|~Itrl~ot}~tko^wtj~rpkzs{plll`olsqYlof~n~cvqwpcn{ng{eiyrphtomjzlnmg}poikzeqthilkpuhgthuwillgjfwlgmlj|tgkgwphklmahjt{mpnivlwtqwnyruxhxf\ssfvpwtmroyltuqi}ywwvtwtucxnnxoqqsnmsdoauvshPn{pihnnl[nrxY{eewpqykmxysppgjjtoghlwqwlotpi|xmrtsZ}upswqpvp{vsqrlsfptssqnlludxqmmegtolmqxwsipmhnjstmpqetsvzprriptqqqppuomqnprvmqpqpuooqnurrtpqpprrqpsrpiqpqpprvpppsqqpqqpsnqoqtqpqpclqppd{jqm|iksKrpkrxulxshmkqnmotjjlnkohitojcig}pijpyfhnvsmdixui^bcMmriwh`xy^ryydmqhWvqkgdb|ldxldsSjvg}}ubpm^~xS]uemopnrzvsetsDoxjlpy}rlstvwupsmpyuez}s}ql{n{punilrmjrrttktxurqytnsuqprnqmoqpionjlronmuowsvt}qolsqpttnkkqnkeqvqopomnwrwqpoorqoprproswZozvyqvnoryoqpijgtmrrqyoqtquqnkrilo|srrtmmgtlmkksiostkpsoruu[d\x{hqjqmvrerryqnrgniRmos{zpnnsxptmtuoil_mjvdZ`omqpjsVghmjtoomdmootiukZtpnnpvs^ti{wjgjqf{|eotlj{krzn{ttsag}|dijvssrvnbtwsqmsqsuqqtgsp|rqszejuevswiljd|qnnwookqrmbrfwlzp`vyurrnmtnpilnpqlzvqqouumjpuosrsplotdnkqjlttjmupworkvvqsltksmucmqktpvrojspqmynwkjposrunozsigurkqorqnpmnelhoomhontjivtuletrounnrmzwauytnkipxlqonzmtouxnmortwrokklmhxgwwm|yrvsrkonqpxouotnununmonzpsyqlqkyw|nqx{nywu_sugfsXwys{hcphyumqpnvqvowwr{oo[svumrlknmpnyt{pnrvtsrxm|tljnroqpuktk}kxrzjtghgqutr}sv{qmupisdorqptqompmrndrvjkcygjnkop[hbqaqoknijyiKmcjbgor\pmiqoy|micompthtqy][vuly]xjsnnq|nojm[^lpi~npkuwmkn}n}attzq{t{xsdrmr_mrutwk{infb{lqjpqmsmazrmolarqmnq|rsovybxqIp{qisjsojst|tkjjkips[nowkyozuozm|x^ulkzxjjqrovsarrtwaymXxtuuqmkmuurm_nsstustxsuut}ustlu}gswuvtu{}e`srpvtxZJ|cpwfarjgonniqomstSvo}moonvsz^q{civkwifal{njenjesxteqxTscjduitounsryxtsptnvuwkxzuixqv{pqltmoq|hkkpheollqrnziqg^tsdclqhjjq{aaksilcrfcgf[qredntfgt_ftgqeir[ml^ofty}icbfnixmovywntvonnnqlktqusoxp|}wcmjkwhouiqwr`ylkn}oyh\onskujroqnunfmwnrjIqvnTp}q{qtwpmnsrs{goorssq`zlxvrqobqrerhdop~znmk|q||ojuspqzd~rzl~hpt={zyqgpjsyppun}l"v|pyxhOqpomqoqmuik>|lvwrrqqnqsqqqpqnopnqpppqoprrqrqqqppoqsmqposqnsqqooqppoqrsprrprpoprvyuutnb{nt}pvwv!ucvjpius{mqmrjt|wt_wrrjowtrm{nstkmqux`YnwmjqEZx|upw{{UmJvBrmtf|cuuwarqvpMzzjxnywrr}n]}sWsf^}yWpXgnkxrnynqrrjmtpirpolnhqunorwyrvrlkrkjoomuprv}sompqppuqvqqhnlmxslqtngsotseh}skpnvmap\ykonmduploqkyvkappqlrjmutuhgm~vrjomrmotsnssrtufn~zpdpuyniunrqpu|rmolxvn^lutgmjqfmixpprokyejyh~wgg`pqxorZngkiyxozcepgkfoeoqevipjshrfkpYrmwvmxqdtmjhjnm]xjdzbczkw{jipnvhomlrrpqqvtrxlxyijwqvmj|lippnvwitrqiwtlswnmtqiuwsjxpvtqnvrxksplyznpjqgomrouxxqk|rpokpiotsiligvqtvlowjvjjtpomnqprxxlv{vrxnrtvuscuvbjomURtilsytrrevxzk{mtqcpg]qj_oyfqXowyh]qnrbelo~aaal`cnNsdi|rlcsnsirmonutnndnjnnofnzfizwiq^ct}qp[{tl|pk~pqvxzqsepfttlrrrrssppknqqqqqlqotrqtusnuprsplpoosrosopxrruprupsqvqooprrpqorzl|qrnvxtqhuuuyqktjhivl}vwms~twkpy{{_iruw{dzrhqtwpmjz~njqlfnulexZnmpmlljlovmoqopqqf~owgpnonngvfmpfuvnsbknuvkziekmtrovqpt{pslmspms|usrvklqq{tzhuoxngxpmptyyjubrnorrnnsvqvfntdnjtpwosprpqr{ppssropqqpoqqrnqqqqrrqqpnqqppqpqqrppqrqrrqosqosqppppprqpki{wwnosuqrunmqq~yr_rjflcpmuxszfuq`wsfpymmtxkephuywooqyuxwk{vtulukulpqrpjfadrksrr}~t|h||mxl`nsnlqpjktudpewj]wcvx{jn]knnjzttgp\euwumowk7|f~kvqtmsqv|rnpXv~hs{uporsnxgtupvtrrwiqomroirqvdquklowr}qoyqswXhgydio{me{danrroejhcvjuquksmupordzt}qrvjlqnfforsws{osnlpqfpikhldogsqsrvtolplusurswpvnznisxlrivsskkxxmgqosguqpjvivsk{rorpznspmolrwlrkkqsimkqqpsoolkkitmptmupnopnvjlptmopmkytsl_Wrok`fqvp[kskja~rd~|ltkvwnwnnuolm{ghpe|ii{ivzltvstw}vzutsqudhus~cpnslooxojpmrlsqplnxsmovpzrqool{{ovhuqqurqupglozunotreznstbksxicnj{rtu}|npuo]gs|sju~rivfpgnwrjdrvan}vponkppjtsnxzwiplnqj^`ykscxd{rk~iurloti{xpvkpZuioisrdolyhnqtxxjs{fdpfstrsnptpkauosgoolkrlmspnrxognspmloqnqrhmkslrqkplovjniksttjnvvpoidengsotpkwst~quvzhtsrlmclvmbf}nkf{urpj|runyjjpyysh}rwqpyuo~pssnrlopmqupynqsskrlogyyqgusnsdnqksokpmqrsxqposqh|mnhsimrnrpkrpilvskvdgmxoawdok{qulyplipiq}rqgrclrq|sdql~kodsopzxjhywrtf}ojlopmnhq\/fegeof+cpeqnt~UzXegkwzggqpudoe\ovnPznbvw|zpl_r`}t{i{jorultqtqtrwtla}synsmwer_rvrzqkln\rkmlqihqooz}kucnro_nlnv}nxoqrrrpqq{ppqpqqrptqpqotrrroqprprrprpqkqpqrqsrppprqspqrprqqqqsqqqqj|gek\zgIskq{zlvn|i}tsncdvnygryt^j~nqo~j\f_pkz{vwgonvjuKjrwufnrkr~Zjrwyfnzbxj{ksgpwekhkhmekitqoTyjejsltwzpfse|qndlroytpqqqsqurwktezqltfnwtjsgmutiusoxzs~znp{htsohiuyntqmoqmhdgynruxqtrforhxsqksunsom{rzujus|yrnpyrvtwriouwqwtrrvuqhqx}v{vuwfmqlkprpuluqmzs{Yqmszohkwfiewqgpkl|wmuykntqpyymyncusxnqnnv_tjnhnpirjvoXsqfpjqsqtrpyjvbrumunhJkntbinUmmfthfqfn{wDaoRximnv{vyhyeioigo]evZ}qmzwdvsZrtpro\|nsfmmu]vn~vmh}{rvuxgcoysrqlonsuqilpxposrxosrknkxh{qrfr{qqmtiuuugqynrkebhyqwtquovpvp_qjpmptrqxxpmlurusosimsmhlqftknnollinqnmyuplorpstistwpounqriojvqoqn}wqmtkyoinrttq{v{llhxrsolnqtvovnzrosuttpkrmmwpbxjntq]sol|ejisnqjzxzonwmtsvullrzzstrhqq|i|sngpytnahuuutkvyl{]ihhhmvpsojo_pbopqxsjnwsqvoivmqjsntj|xwdnrkrsuhzrqmfqwpkvtimlofskqkrposnmqcsohuwy]fsqgdmevqsmtzpwjn|ks~jokcjuvxjkilwfrmvuhirqxi]bkwuo|mrvptpuls{tfn}peqehtuivpx]qnw}^uj[rwj~{|{skmquyxsw|frpqutjmgpmmqxoqqwldttmnnimnmgkpixqtptqrnpeksmjgnpxmzlmtkpohqipsqppqqprssqotqrprppqpqqsqqqspqqprqppqqpqpqqqroqqpqptpqrorqrqqmqsrrpdropnunklmuuplkxsqsxlrk[lmvg{e}pupqkpnin~uxzlfmkktuws{tntrlnkn|pwohtp`upt={f~m~now|pshwsgjvrzdkwqh]|nri|ve}lp}ow`pswttoommonz{hyvrjethijmloprs`dyttsqtptsypnmhpdrwqy|rvc~lkjmuboqulsS\{uzmlsjnqjlpqrjot|btigVrt`eqcnssfhlxbRqjltgt\m{ohkwynToiedhwqqoqs|npprmqkmpqrztmmeqrivsrl{vuzxqypnhdrkknfmmtxc|tltvsqynprnebmuqpl}rokqvmyjomjmsznm|kolprogoklvNllrklpmlrfhovemniptjmg]owirlhyvowrwromitmkurtqvzt~pnp{pp}txpqygz}ntzpwmurvneymnyrlmxp`gkxtknmNmueuiv{y\vysrfsx`qwnM{phwrluhr|}okxqhw}yxtn{onh+jgsoqzttyurwvwr{sxsqlprovvpeilvzstr?zyowmtvqtvppgspltq|twTutqsqommnusqftuorqptt}bpomywpqnlpmnpjmsucjnoxvsgxpvrimppo~nplsovlgckqyrdw{lnotlutljrsounphoroodssrsurqxq}kqzmjutjmllskttoysfsvsmuezmtmyswnq;ownvx}muwwztpmyqjuweysvtuznxqv[j}e|{gptn~svwesu`hrtll|sfte[osiulpo^lfptudrym~lhodiruqhxjxsrsvp{gevzoGnogznlqmmpqovn}qzoppoqgnxsgl|qywlp}ptgujqtryvumliolthjkwnqm`txhojXmgbcyeklt\b{\~napkufjnnsyuqjjbwhzkqgesq}\Myvb\~fgroruupz{syumxrblonrupuvy[ejlmqyopqsjnb{ilo{ukmxufpduxwlprsetlsdwwjkyfbgskopzfxnqwvsjmovvfuud_ovsn`kkszplqubwvkytjoso}`nylqqrpjstoypm\{lzlssy{ym{mrrjmqtdoznonswpnxkjruknncmi{plerrpidorwtlggztqnll}i{nxk>urwydlflvxqxyfp{om~llXZhl|yipw{som}Zdrquz`p|lmpumrjtgrsxzimjxlkxsxlpcqwqsmuhmurwdrsmknsk|jqmqtqsq|nrnkpvovmrvnwohqqmsnkxp}suqjbnphktpitqpvfnowllqylwkwqotq^t~pyosrnuqw{tU{osjytwsgoujvlfskrqcktltmxkoimskjvplmdnornrcrsonraunrrm|rqophtrtorqrdtotvnsnolltrsgy~~rsenxzmirpqqns}qnmf{iqnqqrwqnqtrzpply}npursntjrrsvrsqrjjoptvyknwqsixsvkhtqxtxlnrxmrqvmprtswqnwlmsjpnqpk}tmvvn|rnnpoprmqwmsyqxgrnvwyv{qltlsunkqomsuzlkrsowns`gwphm{eervqtrqsynvronqorxruqo~nxltqqxntqoiopzpvpkpqnlstnpykrvlokoyoppoynlsnqtlswmqvfmqprvppxqppmoqrmpnronul~uvlg|onjrmnmvtrwwrmqpoi|kg{tgtv`z\|vwmqxqltrsp{uphpttrusepqwhjoslnmurtsgphpyhirqlqrcgllnhiyd~u}llpmkonf{htqehlcf{aviyt^fmlsduuhplfgrrYjrs_fskWhnjqprgivpnkYrnq}o}rmpnpomrpoviooqsqkhfhucjlplkjlrnfrpyhqmosvmpkwkomju}sirm}qkrrzjtsxsbpshnioonowenonrkxgxpordpgniu{`{gtpr_mqilmekn{ppUouqjpnjkkcorskmooincenmupw\pkvptz{ssqtm}nrpeuyrwpufquotvrnsmkripsf|qkpmvzvi\mljup|iurpwmp}jhluoqpnmlqshzckouqppvhptzlpdjmtojqnvjrxrqrosromsoshipopmisqqmtmolnuruqlpkrqulqkeulvnluuovjvTnuorvllphriujonppirpvolqrgbsmhos{jrqwnfsnusop|rqppzonpjmrtisvksryjroivpjlpsrsomwvsnypsvwspqoqssnpqwqptqo{qotprtttlqvtproxwplhuyeruof|gulskuqslnnotjouotqqwzphslbnfvduqpsoqmvnkrsprhrnyrxmprv~yjsvuottxmlrsosxvkqrnrpvjqlvvrosvxlqsfrpurvnamnfzsqoamln{Xymtnx}cpyhdzrysmnuksmooxpkupcuqjwshqm_rsufjbopqplsnh~n|{pm|lv_lthyv^|twsomgsrovnznkyosxr{vzypx{qpell]r{vrp~xwpppqpqqqqqsprsso`ojppnuqpqpoqroppsprqprqoopwrqorpprnrpmpnqrtotppixtmww^gnv^ltq}stjsggqwts}cozsuwBdsqluwoywspsvyzkdkcz{onuxqwlsqtwwnukou{wu}prqutpgieqtsoltooppijbrjtgnnssrxwqirgntfpp{vvnlsmyyosvspnql}rq{psnvpnvzgmorcroowps{atrcqiyqp^_jqocsitzxiqrsnnqmsvjolmnslorwr]twqs^ugzqkwpkmrqrwstmrrttr~nxyqjoomtivrpqlzlsvptpspiouwtqiz|pxoiozwtfscvlucupeylnoinu{vgogrxru~romhqqrkr{krxlpjtupltshpnrprr|vovtpqoeiouqsfomqpxpqsvyvo|srpoktptnnnyosltmoxqjonqxlhjmjqxmuynfrkrvsvsiyjprrrnym{jpqtkorztrpq{^xjtwkt}|gte~_xszbtkpxoxnxtqqnWqucslsq{lxrte}pzwsxom`px{mylmqsiux~qpmstaupyhx~nt}smmhmhksj~iore~jnqunochiypismtjjtopuhmtfktukrjsfnju>lytppgliwtxnpipiqxGrrrrxpSomljmhjoqscntjrotswcyrks_wlvzeiowttuzneefsivul}tnwqzpwxol`vrkyuhtfx|ootkmuzrwzn`XtuWmuzq{\rcsNL{wrzmsyukl}uiwro}wskfqzqyvlvakjvcjicicnfxpypjzgtpznmwohpjujsljhz|usltulskvrtynnirtmkkrkydsqtpkxopjnnvmzqropoprysppsolrpooorprnqpqpporrpqpqrpqpppqrtqprqooqpporqprozopoonissqjt}pomrkoztlnipqhxmoptvuwtuognq^uurymrrtoqqkkpjlsqprsqruilwxlZxmdqysYt~uh~{nh|djqnj||srqguyqlyzznrmmqs}p{gewtmmZpojp`n|mp\rp|tw|tQzrv~yqkgtnqr^uinqjiqrjtypf`sorlvkv}}qnz{qmoqropvloqmkwrqmWp|porkknnuudlmptjphtrmsnqsprirqinxlspidrymdpnpomrj|lbtooyfj~wgsxs|qnworhmwt{f`pvtn|uqqsgajqsj|qgxy|ws|pwuyjvd|vigipnlpdhtwjrcil`r}qxueh|m|iwlqolnuksuzyzp{kgjg`~||v~vwntmtjueqvvkqs|kp{pybfhqrtpynokwgmflrpjoiqupojjnihp{jrvUw{rlqpwnqprxh~skxrodsojspnvvwyruolidnsplywmjkfvruwqqs~omutqnsvutottqtspupmcmrptunjr`knptorqr}otpgwpo{zqsuomtvkkmlsrso_nqrtpopunmoqr`qs}r|omvsubtltjm{crwmnly}lrrojvbjpmvdsxkcmjnzjzevkerjplmsrlklalrpqmqqrewraqfwrlxfs}_n~qvkmgowlufvrrauoczlqph~ono}dvuqrsvoh}vkxvqslsp|srstkvkujtsrpyrmkfpvt{ptvprpr}rtjmksogkoqquypujqspvqozwtx|tcnz}h|`tknfr8qsknaoktuvflqmkoyWprrtum{mqzpxonttkh}pmixtxtmvssiqtrpnqtm\yqktrt~~|yuiqqxlqwufVttkfplomqjww}qlzgtqok{nmwmdlqolmuoppumlstrttskmrjzuxsopkloysnsofsxhpgkmhizsururmuq{lsnnlumnohonnnzwotgsippsttppaqomp|k|qgiwolrwq}dptgjrvtqkyjcmjv~vppq]htlxolnoqoln`ljamljsxktossqvsylxxskxkrlpqqugwvzzflup_cvjvpstuukyqxqxqsk{slzpnw}oojrv{otzttkrqoqikvqumvqqpmmqmtpvsqtoyqrnwkirlrppxptrskoksrpsprrwynobnnvunqwppsnn{ldytwjllrurq{onr{vrmpxqmnamomqnkskqv^uvjvjlgutzrnokglgrjktqtxoyrktpv{ipjxlrpnplfpreqwnr}ms|mjssuptKgvxrwpjnr{crmstkoMOszt}qxwrlsotwusvtqkpjvnrtmwom{kmnIfj^tpYmgljgforsrgmtv}wqsaspOrwquwtensZ}|opss{ekv{tosxsrnyqssuqorrhkbopnjwryblqrwsqrrtvtpusltnntqvrso{smlpmmwmssuunmtullskquy}oewopkmprspvlqxoqptprvpswprqlltjklvwnqoxsmqxsVxxshen:ivqfqHq~tvnzkrnmqijojb|xhiprlpqnnnpnpvurdqkqtq|v~ghrtpqopqurpqrrnrpsorrpnorppppppqoqoqqrqpqqqrrrprsqoqqpqqupqqtqppprstoqqxoqqrnpvpvdps~xwtxtkrpxjkprfswjruxuqslspsdvssnwvszqsjpgmvopsomurujpmsmlrrrimnranttqxvyohltrgvwpx~qtwsornxixqmukmltnkyzy}}~gi}vxowywpvsvzvq|vuwpxp~hgxxmhxmlutur^op{tx|k]tx{hvtuwyqtlznlrrxtzqw~ipnzfwpvqy|rytyrlw_fntjgzwxj}przthltmxnxzmol|k}vqcvseisPwtuqdpqvyxopvzguswsnn|nov{xznnwstizxl~xt~votnosv~nolwrpjnjssxrosoxrxscl_xqkqomewtcmjuoolb]~kyo{vnctknkrtcruipYokTrljliwplugpvjojunsktklbonqinmfqokomkhqimvtmxfumlrpkukoqunxrpqrurlriqxpssz|rsqkvitxowpqp]luvlvtjpsrokslkopotmqsnphjtqpthvpmrorqnpssrsroplrmntzvusksszostoxnwfnysrimrpsrlkywoopuln|~mpmuxpqorrlnsrmmrsplqzn{rpuperppvmngkvziqnkoposryspzr{nq`tosg{uwlpqhsnpprxrtipouvsqhsqtvy|nukqjsttrrthouvjrpnkpstnnwmrtpzkppvr]fpm`yvpt[qsoymmdosmwwpoplegsomaknUqo_ltfq^xWYpklgbipkv{nfsgxxmnwoxruzpynxsqoxsmsettnjsptzwu`tyitos}q{hlmqpsorbmvjptqsslwpX{rmzrnnnlr}fmvlp~jdplvnqtkqopuvnnynpwnomkkuxmomknwnmqrxljos|okmkjgmkvl.hnierZjhS{tlz_qcottjirypixy]}sowd^s~fzupwnqlnp`loztnusorulguqorwp}pgpnqzrjsjhoelknpnnpuzlozjtmppuunmmmlutuvonqqnlqqwqjposmoqnurnoqislnpzusxjrwwbywj~nrsssxnq|pupqumvvnrrlvrqelupzyniytzwpxronprzugwuxoblwnpjlspo^uquolur|syxxummpdrgat}yor{rsjmotjukqmqonuqhou{ppxjrlgxjy~xwcqnqkvasprrk~otiplpk{mkklor|key}pwo{sp]pzyltwyzovitpqxtpzojpoovewstvslvvuzx|rrsvtovGosyuvkrwoaspkllfpuvmjqtsnrsprsuwprnvfWtslnoq\uxsepqnnr{kpRUhdtkwpwrulosn9or{bsst?~mtunplxnovmmrvs}sby|rtpifszojp|rlsbsqxggnvrqhhrugupfzzkx{noq}rspokopyxjtuo[ssmt|tzpaks}ymdussrxzu{qoin^{osh_junqegpugdcufgtmcihnz~peiyxgku|y|Ykhmphuxvnyto{qrmprivprnjrkqpjbrrwzvuyns|rql{ppmvZkwmioywqoikmqdngsttpmrpwhit|kson}kssp|ynnulrmjrshrlurrrkxztuzst}i~qrtszt8ymp{{u|vyzj|vpWwA~p~A~4~zZwvu1{}Vc|ncq}_|~x}|vzsu|k}ydwv||zzt{~zy~u~~~u}~|zvq|jv~CToks}MSno|MjgX]z^MĐz~rtwqwke}zwyptURwk^poB|jw{+~g}^wgnp\{}oܴgyfkVzqrNw|s~~~rqsQ]myÜsuuO|cd]il3yTq[sowew|zZbz{{Xhx}tprYx|[wxi[XiqrbYhs}n}knv}`~y}zhhspyy{Qo~qds{rrqxbpLqpvbudztuYghlwvzgtndPoNjdmLx~pJpmz~snppdt1ZjzDž|rǡcz~^Mi~|pSotrkgmsztos_fLknv}l{b}_buH|ta=Gyx{zgppkyzz~w|f|p}hr|suS}bvuv|m~v|yxzx~y~}|_Jvwfc||WzqJv}eyeyv}xw{xyurztx~wt{t{{y|ts|~^xjx}g}qu|`y^^}u~udmscxhll[q:zjlFRppYgu{za`\hvvsh}RcNUb_j_qDlehX:Œx|ox~jsvedp.dVe__{}S^nTcyei[Yy{xfutfWg|oos{v|N}{ӉViEv{{ov~zduqpeqwvxs~ޘ{qlzkbyt}^{j{pk~w[vŲcv_xuzswYhZlrorpwg8_g\g{~lR]xpvkzogeqj`~vjm{SW|~u~n\Z{s}CF{|L|^Ygzg}kludKyzz\yzsRlNgU~}dǶrv{gr׌ljGLb{ln}Hbsuzpqxxiu{kmmy|ih{}~nvjyzuuzfrmrllyjtlxv|xojwwyp}W~sisaflp~YXEuxckiceu~Imf|tsw]h\No[Yotypąz`ypipye^ye}ykav|wzX^e}_l}qwl}fn}`VteP{e\Tiw]}aufcaum|pmRy|r|ts~zdvvS\_ғxy}{|Zbt[dyat{f`xH{ux:]l^c|tyvJ]WOZ[jiiho}}~__}{kavoqu|qqfg~rNuui|3slXujS_gRymzyztp}rf{sy\ljxfnp|{wskp~ptwKa|~yjЋpy~qxp^vvixw}xlzsd~pxzaytp~~ovt_|~{fvuk||~pHx{uyvtyx||re{~n\k~{`Dxssnzuot~ofpuhux~sju{z}|zhusu}}z}f}|g:gtYxqw}~y{[~~plr1x{hnk{|~}{~~}q}sw}zohegU}veMpl.ilq}%nVcŽo_k{rjhtw\epx}~|xmd~uXBol|{oyz_|q{tl{lwzu~}wvy~}y~~}|ty~}x|oKoGx?vrgr|~\bzchfUơɂWpxEn|}xv|y]pvpu|xtmclsuAltp}qYy_Ϧmsfg|z~{h~vw|uuw{f{tjsvN~tp_k{sj{1|x{rO}pf{w}hwt~z^yv}sOxpziRgty0kq`wÖWkna~]zb~`t}/zE]z~tnoɅi|}]asscfce|~v}MyfazvvqBg\j~ǁsbli{Kmw}l}uLnb`WW^t`ajր~hto6ioxUNu~x||}~zsv}z~z}}}~~z}t~~~~z~{{t}tw|{pwzy{}{yp~~}{xv~vw~{}}}{{zx}}yx~|~xz|ty~y}~|}}~}|~~wpr}nwyx}vw}v|z}l}vx~sm|z~y{{rw~z~|~p~|u{}{zyx}}}xquj~sxvq|{z{{|}}}~}~tuwk{~}x~|v{{m}w~s}zory|{xzqw}sww|~}~|||x|{|~zy~x~ysuw}wot|}u}{|~zru{~~|xy~}}y~~{~}v~vxs~gtr}z{~xs~zp~vw|r~q}zuu~|zuv|~zwv||}l|~xz~wwz|}z~y}uzy~sywy{|z~~}~|~}{~y}}z}uxw~x|k{}}~|x}yv{~}{oz~x}~~w{~w|y|~y|wvv}ztz}zyuw}~zvsvz~}}}|t~|}{}~~~~{~z~{vyysy}{}~|}x{twt{{}~}zz{~|u}}x|z|t~z{{~|{}}}|~|~}zv{{|x~{~{~{|w}~|zw|amy}z}z~~~~uz}u{x~xtwz{~{}}~|}{yyz}~v|yzxz}~z~|~}zywz{|u{~~~xw|wzr~{zvswsy|uu}zyzxq~{xy}|x}~|q~|}z~x~z|vux|{||vw|ysx||~xws~|~~pxz~{izq{{tz}x{~ty{~}~}|||}{zu}|r{vs~q~pyyzv~}zu{~|w{~w}}|}~yx}w{z||wikr}tox{|_x|~j~m{~v{}}~|~~lvv{ye~x}x}z}y{{y}~v}|~~w{ex{v~|}}}}|m}y~z~v}~zwv|zq~|wtv~{v}yw~x~~w}w{{|z~y}{~r{rwxz|~~zsxy}}y~}~{{|yy~}}~o{}~u~}t{~|y~y{}~{zxy||wy~tzxzt|}suz}}wz||przw~t}}}yx}~|~~~||~{|m{z|x}{|y}}{yx}}vvp~{x~zw~t}{z|wt}|twt}w~y}}|{zy~|v}z{rwu|{~zx~|~y|z~|z~zo~{}~{xy~||y|ywwpu}}yz}}k}~|~~w}zzzo|z~}|v|w{{}{|z}|}yvy|{|}z~~v|zvwzyv~wyu|x|~sq}}}}vxt}|x}xn|w}y|{~{xz~~|~x{}zrzz~}{v}~~}xyu{px}~|m~{|z{}{z}zzy~~||w~}q{zz~x~n|ui|zww{{v~rr}|}z{x}zu{{w|{|~wu~r|t|~~~z|u~wnzp~}zsmq}}s|y|}}xyyu}qy{zukuw~}r|}~{~x}{}|p}~~r}~~|r~}~~pwt~}x~o}~t}~~|}~xuyttu~|{w}zp}z}}y~v}|s}}|d~{w{}r~{ztv{t|z~vw~}mw}}||||||{x{{~v{~}v}~|}~{}w}~zx}~zl}zwty{yz~|xr~uz~wy~lsz}~v|x~}t|{~yv{~{}}|x{~y~{y|}wzw}{{wzuw|u}s{~~z~z{~t}}}}{z~|xz{|z|zxx~~|~{}wy|~{z~q|qy|}u|uuytp~{wuw{{}n}||{px~}y~}~}z~|}{{z}|}uy~|w}|}~y~y}}{{~~|~|~zz}~m{xxq|}~y|w}x~|~~qx{zxx~z|}}{y|yv|w{}yoz}y|z||~yyz|syu|{wz{~}px}x{~x~{}|t~vx}|~|z~w||}s~}}}~{vw}~~us~{{t{~y~zx{o}|~zw~yz|{{{u}|t~{~pzyu~x{{s{~{{u}y}xuy{}~y{w{~~~{y~rmy~~zyv}~vwxyx|}zx|}~j|~~~{ozzz{~|uz}~}yyy{}hvzu{}~z}~}~n|m~xr}~{uwx{{z~~vuy}~|x}~|{|}y|~||{|}}wzx}puqv~{z~w~s~}~z{zv~||}fyq|}wty}z~vz~|s|zzq|yx{wxu|zz|z{|~|s}|ywt{{z{zyvsu}k{~}yq~tyvzyxl|{~~uvt{q||}~}~z{}}}uxyx|~ox}~vwz~v}{u}w~vz~qt}xly}yx{}y{}~|zw}|t|zzx|}u~|{{|}xyyt}zz~wxwxz{~o~vwv~|~wz|w|mx}yx~px|{~tr~~ujr{v~a~}~y}}qz{v}~}|yv~~w}{z~~}h|uvwyyy{x}y~z}sz{sz{z{}}}~yx~iy~{zuyx}|}ys}|w~o}uv~ty~z{}|~~~~~}~|}w|v{||}{y~~~v|y|tz{w}y|{yz}{sryy||yts||~}{~w~zp|}~}{x|}ot~x}|~vuu|s{}{znvvwcyowyxr}}{v|vtz{{t}zo|ywx~vryys~xmu{yuzt|~x{{zpyy~zv}y~wy|ozu}~yoyq~|{||tv~~|x{z|y~uzu{r|x|{~s|wx~~~}}z|w~yjq{{z~{{~~{|nph|oz~zv~u}|z~mzxvt}|{~xw}~{}u{yu|{o|{x|z}xrz{zwn}~}~noxw~yxzwkv}||{w||}z}yv|xux|u~lw}~x}~z||mu}~}x~xo~yu~|{v~ttsxlzqvyr~~r{}x||zu}t}|yy||fyzuv}wg|~}wuqpu{u}|vw{tz}^tz~w{|~qxrt~rlhy}z}tz~x}|kxwrw~}q}ypz~~v{~{xi}twvxvbv{}zy}|vz~tsia~xzh|z}}~y|{r{}||yz||~u}xr|zuwz}x}uvwx~j{~~|{~}~|wv{u}zz}v~n}}z~wmy{w{}vx}}uxsvzys~y~owu|}zz~q~~{vxxw~{zxuz{p}xx|}r{ymy}|v~q}w}|w}|w~~}yzy|{|ww{||y}}|}|}}~~x}}}~yz~u~~|}zt|y{tu}mz||~{~~{z|smte~x~~y{{r}}ul}}t}y~r~ylf||}ty}x~|s}~}}u||zyx|w}|zz|}xe~{~}{i{~}~~~}}{x{ztxyqw}zfoqum|}k|v{{{}zv|~zt~zv{~uw{uzk{zo{y}woaqs{}s}~~wy}vsxt}y{kxp{[y{a~qzzwyzg{|s|~}x|w~{z~xwpo~w~vyuytu{s~gvx}e}y{|xntytwzxu{nuvxrq|~|t}avz}y|vzxxr}}y}owvzw|{~~u|}z}w{~p{~y~z{xy}~~}uw{|yt{j}~hxw~zopwvx|{xxyxz}wm~syz{x~}iz}~zlpz~~~}rszvw|bq|tx~{ets}{|wx|{qzz~xr|{{u~}tx|}v~pwv~|x|qzz~zx|~||z|v{|~|z}u|foyvzwx}{{zx|xzzq~}~|l~wz~}}~zyx}{zt{~y|gzy}~}{|{|yyx{}~yu~zoyyq||r{u|~ss{~x~z~~}zz||}wy{~o|{x{z{u~~~y~v~}{{qul|rxtnxy~x{~yz{{xx}y~u{v}{x|~s|y|}}k|xy|tuw{y|}zz~|~|wzwzw~~}zuv{~|{}t}p~x~py|z}z}~zxyu~{y{uy|xy}{xn|vhxu|v}uyyv|v~sr~{|~t}~{|yz~}}~vxyyt}p{|yo{s|z}{zq~zoz}~yz}~~}}~{~o|~{x~s~vt~~~r}uy{{u~ptx|~vzw||vp}{h}{}yo}oy~~ywx}|u~~u{vx|xny~{x~}~~l|~}~w}~~~||}~|||~}}|~}~|yy{zuz|}y~|y|}wyy|x~~}{}~}z~~{|v~~{~|{~}yw}{|{}~{}}~z|}|xy|y}x}}~zx~}z~w~||w~~{{}|~}{y~|x~x~|~~~z}}vuw~{|~~|s|~|~|}}x~}~~}y|z}y}|}{~|||}}~~~~{{{u}~}}z{{z~~w|w~u||txsy~z{zz|}z~~z}|}}}~|{x{|}|~~|}yv{}||t{~~||{}{~~~~{{|z|y~y}wxz|{}~~z{}x~|}|y~}zu}|v|}~{~{~}~~~|s{y}z}~~~|ex|}yy~}z~|y}w~|u~{|~~|{~y}}|}yu}~~}|~~z~x}~|{}}uy|yt~y}y}~x{xyvtyy{}x~|~}~{{~~y}~z~~~}z}~}}~|v|}}}~w{~w{}x~z|{~|}}~}~p~|}~{y}~}~~l~~~y~~}~{yw}z~~zwz|y|y{{~~q{z|{||||}~~|yu}}~}}z|~z}~z|||~|~~~|~}|z~|z~v|~t}~~~|}}}}|||u{{vz}~|}~~~z{|~{~{}}~~~{|{z}~wx}|~}~~~~}}u}~}~|}|w}~}yyx}~{y~~zy{zzw~|w|uy~}zzx}{{{~tx}|~|{s{~|{~~z~}y~|~}~|{z~}}}z~}uxzx{~~~~}t}}}}zy~~~~~~|~~~~v}x~}}~{|y~yz~}}~|}xy{{}}~~{}v}}vx|{~zwxw~|~}wz}}|~}}{}z{{y}~x}x~~u|{~|~||vy|~wz|y~|{z}}}{~}|~~|y~v}y~}}}~~~~}z|z||}~~~v|z}}r}}zy~|zz}}z|}z{z{|~}~}{z}~}}|}}yv}yyx{}}w|x~~|~}}}{~}~}{y~~{{}~x~~t~|w~~xz~m 3aU!{v1UO^Rjo-EP? `qFX_ 5isfeLd_[?`WNXgVToL&_VC!DJ+iQ!;>1I{q5kL*i1bEg~z?I{ln eX=^HJY1 ff=ff=aа= >a >а= Lff=ff=aа=@> Cü >= ffaа=`>; >bh> 33s=ff=33#>a Cа=bh>z^= >bh8> =ff=33C>aPа=bh>=/= >bhX> =ff=33c>ay<а=bh>=/= >bhx> >ff=>a|=а=bh>> >14> <>ff=>az^=а=bh>'> >14> \>ff=>az^=а=bh>G> >14> |>ff=>a=/>а=bh>g> >14> ff>ff=>a=/?>а=bh>˃> >14> ff>ff=>a=/_>а=14?˓> >14> ff>ff=>a=/>а=14?ˣ> >14> ff>ff=>a>а=14?˳> >14> ff>ff=?a>а=14?> >? ff>ff=?a>а=14 ?> >? ff>ff=?a>а=14(?> >? ff>ff=?a>а=140?> >? 33?ff= ?a>а=148?? >&? 33?ff=(?a>а=14@? ? >.? 33?ff=0?a>а=14H?? >6? 33?ff=8?a?а=14P?? >>? 33'?ff=@?a?а=14X?!? >F? 33/?ff=H?a?а=14`?)? >N? 337?ff=P?a?а=14h?1? >V? 33??ff=X?a'?а=14p?9? >^? 33G?ff=`?a/?а=14x?A? >f? 33O?ff=h?a7?а=?I? >n? 33W?ff=p?a??а=?Q? >v? 33_?ff=x?aG?а=?Y? >~? 33g?ff=ff?aO?а=?a? > ? 33o?ff=ff?aW?а=?i? > ?L ff=ff= Cü= >a@>а=LLff=ff= Cü=@> Cü@>=Lff Cü=`>;@>bh>L33s=ff=33#> Cü C=bh>z^=@>bh8>L=ff=33C> CüP=bh>=/=@>bhX>L=ff=33c> Cüy<=bh>=/=@>bhx>L>ff=> Cü|==bh>>@>14>L<>ff=> Cüz^==bh>'>@>14>L\>ff=> Cüz^==bh>G>@>14>L|>ff=> Cü=/>=bh>g>@>14>Lff>ff=> Cü=/?>=bh>˃>@>14>Lff>ff=> Cü=/_>=14?˓>@>14>Lff>ff=> Cü=/>=14?ˣ>@>14>Lff>ff=> Cü>=14?˳>@>14>Lff>ff=? Cü>=14?>@>?Lff>ff=? Cü>=14 ?>@>?Lff>ff=? Cü>=14(?>@>?Lff>ff=? Cü>=140?>@>?L33?ff= ? Cü>=148??@>&?L33?ff=(? Cü>=14@? ?@>.?L33?ff=0? Cü>=14H??@>6?L33?ff=8? Cü?=14P??@>>?L33'?ff=@? Cü?=14X?!?@>F?L33/?ff=H? Cü?=14`?)?@>N?L337?ff=P? Cü?=14h?1?@>V?L33??ff=X? Cü'?=14p?9?@>^?L33G?ff=`? Cü/?=14x?A?@>f?L33O?ff=h? Cü7?=?I?@>n?L33W?ff=p? Cü??=?Q?@>v?L33_?ff=x? CüG?=?Y?@>~?L33g?ff=ff? CüO?=?a?@> ?L33o?ff=ff? CüW?=?i?@> ?ff< 33>ff=;bh> >a`>а=ffff=;bh>@> Cü`>=ff33>;bh>`>;`>bh>ff<33s=33>33#>; Cbh>bh>z^=`>bh8>ff<=33>33C>;Pbh>bh>=/=`>bhX>ff<=33>33c>;ybh>=/=`>bhx>ff<>33>>;|=bh>bh>>`>14>ff<<>33>>;z^=bh>bh>'>`>14>ff<\>33>>;z^=bh>bh>G>`>14>ff<|>33>>;=/>bh>bh>g>`>14>ff33>>;=/?>bh>bh>˃>`>14>ff33>>;=/_>bh>14?˓>`>14>ff33>>;=/>bh>14?ˣ>`>14>ff33>>;>bh>14?˳>`>14>ff33>?;>bh>14?>`>?ff33>?;>bh>14 ?>`>?ff33>?;>bh>14(?>`>?ff33>?;>bh>140?>`>?ff<33?33> ?;>bh>148??`>&?ff<33?33>(?;>bh>14@? ?`>.?ff<33?33>0?;>bh>14H??`>6?ff<33?33>8?;?bh>14P??`>>?ff<33'?33>@?;?bh>14X?!?`>F?ff<33/?33>H?;?bh>14`?)?`>N?ff<337?33>P?;?bh>14h?1?`>V?ff<33??33>X?;'?bh>14p?9?`>^?ff<33G?33>`?;/?bh>14x?A?`>f?ff<33O?33>h?;7?bh>?I?`>n?ff<33W?33>p?;??bh>?Q?`>v?ff<33_?33>x?;G?bh>?Y?`>~?ff<33g?33>ff?;O?bh>?a?`> ?ff<33o?33>ff?;W?bh>?i?`> ?33s= 33#>ff=z^=bh8> > Cabh>а=33s=L33#>ff=z^=bh8>@> C Cübh>=33s=ff<33#>33>z^=bh8>`> C;bh>bh>33s=33s=33#>33#>z^= Cbh8>bh> Cz^=bh>bh8>33s==33#>33C>z^=Pbh8>bh> C=/=bh>bhX>33s==33#>33c>z^=ybh> C=/=bh>bhx>33s=>33#>>z^=|=bh8>bh> C>bh>14>33s=<>33#>>z^=z^=bh8>bh> C'>bh>14>33s=\>33#>>z^=z^=bh8>bh> CG>bh>14>33s=|>33#>>z^==/>bh8>bh> Cg>bh>14>33s=ff>33#>>z^==/?>bh8>bh> C˃>bh>14>33s=ff>33#>>z^==/_>bh8>14? C˓>bh>14>33s=ff>33#>>z^==/>bh8>14? Cˣ>bh>14>33s=ff>33#>>z^=>bh8>14? C˳>bh>14>33s=ff>33#>?z^=>bh8>14? C>bh>?33s=ff>33#>?z^=>bh8>14 ? C>bh>?33s=ff>33#>?z^=>bh8>14(? C>bh>?33s=ff>33#>?z^=>bh8>140? C>bh>?33s=33?33#> ?z^=>bh8>148? C?bh>&?33s=33?33#>(?z^=>bh8>14@? C ?bh>.?33s=33?33#>0?z^=>bh8>14H? C?bh>6?33s=33?33#>8?z^=?bh8>14P? C?bh>>?33s=33'?33#>@?z^=?bh8>14X? C!?bh>F?33s=33/?33#>H?z^=?bh8>14`? C)?bh>N?33s=337?33#>P?z^=?bh8>14h? C1?bh>V?33s=33??33#>X?z^='?bh8>14p? C9?bh>^?33s=33G?33#>`?z^=/?bh8>14x? CA?bh>f?33s=33O?33#>h?z^=7?bh8>? CI?bh>n?33s=33W?33#>p?z^=??bh8>? CQ?bh>v?33s=33_?33#>x?z^=G?bh8>? CY?bh>~?33s=33g?33#>ff?z^=O?bh8>? Ca?bh> ?33s=33o?33#>ff?z^=W?bh8>? Ci?bh> ?= 33C>ff==/=bhX> >Pabh>а==L33C>ff==/=bhX>@>P Cübh>==ff<33C>33>=/=bhX>`>P;bh>bh>=33s=33C>33#>=/= CbhX>bh>Pz^=bh>bh8>==33C>33C>=/=PbhX>bh>P=/=bh>bhX>==33C>33c>=/=ybh>P=/=bh>bhx>=>33C>>=/=|=bhX>bh>P>bh>14>=<>33C>>=/=z^=bhX>bh>P'>bh>14>=\>33C>>=/=z^=bhX>bh>PG>bh>14>=|>33C>>=/==/>bhX>bh>Pg>bh>14>=ff>33C>>=/==/?>bhX>bh>P˃>bh>14>=ff>33C>>=/==/_>bhX>14?P˓>bh>14>=ff>33C>>=/==/>bhX>14?Pˣ>bh>14>=ff>33C>>=/=>bhX>14?P˳>bh>14>=ff>33C>?=/=>bhX>14?P>bh>?=ff>33C>?=/=>bhX>14 ?P>bh>?=ff>33C>?=/=>bhX>14(?P>bh>?=ff>33C>?=/=>bhX>140?P>bh>?=33?33C> ?=/=>bhX>148?P?bh>&?=33?33C>(?=/=>bhX>14@?P ?bh>.?=33?33C>0?=/=>bhX>14H?P?bh>6?=33?33C>8?=/=?bhX>14P?P?bh>>?=33'?33C>@?=/=?bhX>14X?P!?bh>F?=33/?33C>H?=/=?bhX>14`?P)?bh>N?=337?33C>P?=/=?bhX>14h?P1?bh>V?=33??33C>X?=/='?bhX>14p?P9?bh>^?=33G?33C>`?=/=/?bhX>14x?PA?bh>f?=33O?33C>h?=/=7?bhX>?PI?bh>n?=33W?33C>p?=/=??bhX>?PQ?bh>v?=33_?33C>x?=/=G?bhX>?PY?bh>~?=33g?33C>ff?=/=O?bhX>?Pa?bh> ?=33o?33C>ff?=/=W?bhX>?Pi?bh> ?= 33c>ff==/=bhx> >yа==L33c>ff==/=bhx>@>y< Cübh>==ff<33c>33>=/=bhx>`>y<;bh>bh>=33s=33c>33#>=/= Cbhx>bh>ybh8>==33c>33C>=/=Pbhx>bh>y<=/=bh>bhX>==33c>33c>=/=ybh>y<=/=bh>bhx>=>33c>>=/=|=bhx>bh>y<>bh>14>=<>33c>>=/=z^=bhx>bh>y<'>bh>14>=\>33c>>=/=z^=bhx>bh>ybh>14>=|>33c>>=/==/>bhx>bh>ybh>14>=ff>33c>>=/==/?>bhx>bh>y<˃>bh>14>=ff>33c>>=/==/_>bhx>14?y<˓>bh>14>=ff>33c>>=/==/>bhx>14?y<ˣ>bh>14>=ff>33c>>=/=>bhx>14?y<˳>bh>14>=ff>33c>?=/=>bhx>14?y<>bh>?=ff>33c>?=/=>bhx>14 ?y<>bh>?=ff>33c>?=/=>bhx>14(?y<>bh>?=ff>33c>?=/=>bhx>140?y<>bh>?=33?33c> ?=/=>bhx>148?y<?bh>&?=33?33c>(?=/=>bhx>14@?y< ?bh>.?=33?33c>0?=/=>bhx>14H?y<?bh>6?=33?33c>8?=/=?bhx>14P?y<?bh>>?=33'?33c>@?=/=?bhx>14X?yF?=33/?33c>H?=/=?bhx>14`?y<)?bh>N?=337?33c>P?=/=?bhx>14h?y<1?bh>V?=33??33c>X?=/='?bhx>14p?y<9?bh>^?=33G?33c>`?=/=/?bhx>14x?yf?=33O?33c>h?=/=7?bhx>?yn?=33W?33c>p?=/=??bhx>?yv?=33_?33c>x?=/=G?bhx>?y~?=33g?33c>ff?=/=O?bhx>?y ?=33o?33c>ff?=/=W?bhx>?y ?> >ff=>14> >|=abh>а=>L>ff=>14>@>|= Cübh>=>ff<>33>>14>`>|=;bh>bh>>33s=>33#>> C14>bh>|=z^=bh>bh8>>=>33C>>P14>bh>|==/=bh>bhX>>=>33c>>y<14>bh>|==/=bh>bhx>>>>>>|=14>bh>|=>bh>14>><>>>>z^=14>bh>|='>bh>14>>\>>>>z^=14>bh>|=G>bh>14>>|>>>>=/>14>bh>|=g>bh>14>>ff>>>>=/?>14>bh>|=˃>bh>14>>ff>>>>=/_>14>14?|=˓>bh>14>>ff>>>>=/>14>14?|=ˣ>bh>14>>ff>>>>>14>14?|=˳>bh>14>>ff>>?>>14>14?|=>bh>?>ff>>?>>14>14 ?|=>bh>?>ff>>?>>14>14(?|=>bh>?>ff>>?>>14>140?|=>bh>?>33?> ?>>14>148?|=?bh>&?>33?>(?>>14>14@?|= ?bh>.?>33?>0?>>14>14H?|=?bh>6?>33?>8?>?14>14P?|=?bh>>?>33'?>@?>?14>14X?|=!?bh>F?>33/?>H?>?14>14`?|=)?bh>N?>337?>P?>?14>14h?|=1?bh>V?>33??>X?>'?14>14p?|=9?bh>^?>33G?>`?>/?14>14x?|=A?bh>f?>33O?>h?>7?14>?|=I?bh>n?>33W?>p?>??14>?|=Q?bh>v?>33_?>x?>G?14>?|=Y?bh>~?>33g?>ff?>O?14>?|=a?bh> ?>33o?>ff?>W?14>?|=i?bh> ?<> >ff='>14> >z^=abh>а=<>L>ff='>14>@>z^= Cübh>=<>ff<>33>'>14>`>z^=;bh>bh><>33s=>33#>'> C14>bh>z^=z^=bh>bh8><>=>33C>'>P14>bh>z^==/=bh>bhX><>=>33c>'>y<14>bh>z^==/=bh>bhx><>>>>'>|=14>bh>z^=>bh>14><><>>>'>z^=14>bh>z^='>bh>14><>\>>>'>z^=14>bh>z^=G>bh>14><>|>>>'>=/>14>bh>z^=g>bh>14><>ff>>>'>=/?>14>bh>z^=˃>bh>14><>ff>>>'>=/_>14>14?z^=˓>bh>14><>ff>>>'>=/>14>14?z^=ˣ>bh>14><>ff>>>'>>14>14?z^=˳>bh>14><>ff>>?'>>14>14?z^=>bh>?<>ff>>?'>>14>14 ?z^=>bh>?<>ff>>?'>>14>14(?z^=>bh>?<>ff>>?'>>14>140?z^=>bh>?<>33?> ?'>>14>148?z^=?bh>&?<>33?>(?'>>14>14@?z^= ?bh>.?<>33?>0?'>>14>14H?z^=?bh>6?<>33?>8?'>?14>14P?z^=?bh>>?<>33'?>@?'>?14>14X?z^=!?bh>F?<>33/?>H?'>?14>14`?z^=)?bh>N?<>337?>P?'>?14>14h?z^=1?bh>V?<>33??>X?'>'?14>14p?z^=9?bh>^?<>33G?>`?'>/?14>14x?z^=A?bh>f?<>33O?>h?'>7?14>?z^=I?bh>n?<>33W?>p?'>??14>?z^=Q?bh>v?<>33_?>x?'>G?14>?z^=Y?bh>~?<>33g?>ff?'>O?14>?z^=a?bh> ?<>33o?>ff?'>W?14>?z^=i?bh> ?\> >ff=G>14> >z^=abh>а=\>L>ff=G>14>@>z^= Cübh>=\>ff<>33>G>14>`>z^=;bh>bh>\>33s=>33#>G> C14>bh>z^=z^=bh>bh8>\>=>33C>G>P14>bh>z^==/=bh>bhX>\>=>33c>G>y<14>bh>z^==/=bh>bhx>\>>>>G>|=14>bh>z^=>bh>14>\><>>>G>z^=14>bh>z^='>bh>14>\>\>>>G>z^=14>bh>z^=G>bh>14>\>|>>>G>=/>14>bh>z^=g>bh>14>\>ff>>>G>=/?>14>bh>z^=˃>bh>14>\>ff>>>G>=/_>14>14?z^=˓>bh>14>\>ff>>>G>=/>14>14?z^=ˣ>bh>14>\>ff>>>G>>14>14?z^=˳>bh>14>\>ff>>?G>>14>14?z^=>bh>?\>ff>>?G>>14>14 ?z^=>bh>?\>ff>>?G>>14>14(?z^=>bh>?\>ff>>?G>>14>140?z^=>bh>?\>33?> ?G>>14>148?z^=?bh>&?\>33?>(?G>>14>14@?z^= ?bh>.?\>33?>0?G>>14>14H?z^=?bh>6?\>33?>8?G>?14>14P?z^=?bh>>?\>33'?>@?G>?14>14X?z^=!?bh>F?\>33/?>H?G>?14>14`?z^=)?bh>N?\>337?>P?G>?14>14h?z^=1?bh>V?\>33??>X?G>'?14>14p?z^=9?bh>^?\>33G?>`?G>/?14>14x?z^=A?bh>f?\>33O?>h?G>7?14>?z^=I?bh>n?\>33W?>p?G>??14>?z^=Q?bh>v?\>33_?>x?G>G?14>?z^=Y?bh>~?\>33g?>ff?G>O?14>?z^=a?bh> ?\>33o?>ff?G>W?14>?z^=i?bh> ?|> >ff=g>14> >=/>abh>а=|>L>ff=g>14>@>=/> Cübh>=|>ff<>33>g>14>`>=/>;bh>bh>|>33s=>33#>g> C14>bh>=/>z^=bh>bh8>|>=>33C>g>P14>bh>=/>=/=bh>bhX>|>=>33c>g>y<14>bh>=/>=/=bh>bhx>|>>>>g>|=14>bh>=/>>bh>14>|><>>>g>z^=14>bh>=/>'>bh>14>|>\>>>g>z^=14>bh>=/>G>bh>14>|>|>>>g>=/>14>bh>=/>g>bh>14>|>ff>>>g>=/?>14>bh>=/>˃>bh>14>|>ff>>>g>=/_>14>14?=/>˓>bh>14>|>ff>>>g>=/>14>14?=/>ˣ>bh>14>|>ff>>>g>>14>14?=/>˳>bh>14>|>ff>>?g>>14>14?=/>>bh>?|>ff>>?g>>14>14 ?=/>>bh>?|>ff>>?g>>14>14(?=/>>bh>?|>ff>>?g>>14>140?=/>>bh>?|>33?> ?g>>14>148?=/>?bh>&?|>33?>(?g>>14>14@?=/> ?bh>.?|>33?>0?g>>14>14H?=/>?bh>6?|>33?>8?g>?14>14P?=/>?bh>>?|>33'?>@?g>?14>14X?=/>!?bh>F?|>33/?>H?g>?14>14`?=/>)?bh>N?|>337?>P?g>?14>14h?=/>1?bh>V?|>33??>X?g>'?14>14p?=/>9?bh>^?|>33G?>`?g>/?14>14x?=/>A?bh>f?|>33O?>h?g>7?14>?=/>I?bh>n?|>33W?>p?g>??14>?=/>Q?bh>v?|>33_?>x?g>G?14>?=/>Y?bh>~?|>33g?>ff?g>O?14>?=/>a?bh> ?|>33o?>ff?g>W?14>?=/>i?bh> ?ff> >ff=˃>14> >=/?>abh>а=ff>L>ff=˃>14>@>=/?> Cübh>=ff>ff<>33>˃>14>`>=/?>;bh>bh>ff>33s=>33#>˃> C14>bh>=/?>z^=bh>bh8>ff>=>33C>˃>P14>bh>=/?>=/=bh>bhX>ff>=>33c>˃>y<14>bh>=/?>=/=bh>bhx>ff>>>>˃>|=14>bh>=/?>>bh>14>ff><>>>˃>z^=14>bh>=/?>'>bh>14>ff>\>>>˃>z^=14>bh>=/?>G>bh>14>ff>|>>>˃>=/>14>bh>=/?>g>bh>14>ff>ff>>>˃>=/?>14>bh>=/?>˃>bh>14>ff>ff>>>˃>=/_>14>14?=/?>˓>bh>14>ff>ff>>>˃>=/>14>14?=/?>ˣ>bh>14>ff>ff>>>˃>>14>14?=/?>˳>bh>14>ff>ff>>?˃>>14>14?=/?>>bh>?ff>ff>>?˃>>14>14 ?=/?>>bh>?ff>ff>>?˃>>14>14(?=/?>>bh>?ff>ff>>?˃>>14>140?=/?>>bh>?ff>33?> ?˃>>14>148?=/?>?bh>&?ff>33?>(?˃>>14>14@?=/?> ?bh>.?ff>33?>0?˃>>14>14H?=/?>?bh>6?ff>33?>8?˃>?14>14P?=/?>?bh>>?ff>33'?>@?˃>?14>14X?=/?>!?bh>F?ff>33/?>H?˃>?14>14`?=/?>)?bh>N?ff>337?>P?˃>?14>14h?=/?>1?bh>V?ff>33??>X?˃>'?14>14p?=/?>9?bh>^?ff>33G?>`?˃>/?14>14x?=/?>A?bh>f?ff>33O?>h?˃>7?14>?=/?>I?bh>n?ff>33W?>p?˃>??14>?=/?>Q?bh>v?ff>33_?>x?˃>G?14>?=/?>Y?bh>~?ff>33g?>ff?˃>O?14>?=/?>a?bh> ?ff>33o?>ff?˃>W?14>?=/?>i?bh> ?ff> >ff=˓>14> >=/_>a14?а=ff>L>ff=˓>14>@>=/_> Cü14?=ff>ff<>33>˓>14>`>=/_>;14?bh>ff>33s=>33#>˓> C14>bh>=/_>z^=14?bh8>ff>=>33C>˓>P14>bh>=/_>=/=14?bhX>ff>=>33c>˓>y<14>bh>=/_>=/=14?bhx>ff>>>>˓>|=14>bh>=/_>>14?14>ff><>>>˓>z^=14>bh>=/_>'>14?14>ff>\>>>˓>z^=14>bh>=/_>G>14?14>ff>|>>>˓>=/>14>bh>=/_>g>14?14>ff>ff>>>˓>=/?>14>bh>=/_>˃>14?14>ff>ff>>>˓>=/_>14>14?=/_>˓>14?14>ff>ff>>>˓>=/>14>14?=/_>ˣ>14?14>ff>ff>>>˓>>14>14?=/_>˳>14?14>ff>ff>>?˓>>14>14?=/_>>14??ff>ff>>?˓>>14>14 ?=/_>>14??ff>ff>>?˓>>14>14(?=/_>>14??ff>ff>>?˓>>14>140?=/_>>14??ff>33?> ?˓>>14>148?=/_>?14?&?ff>33?>(?˓>>14>14@?=/_> ?14?.?ff>33?>0?˓>>14>14H?=/_>?14?6?ff>33?>8?˓>?14>14P?=/_>?14?>?ff>33'?>@?˓>?14>14X?=/_>!?14?F?ff>33/?>H?˓>?14>14`?=/_>)?14?N?ff>337?>P?˓>?14>14h?=/_>1?14?V?ff>33??>X?˓>'?14>14p?=/_>9?14?^?ff>33G?>`?˓>/?14>14x?=/_>A?14?f?ff>33O?>h?˓>7?14>?=/_>I?14?n?ff>33W?>p?˓>??14>?=/_>Q?14?v?ff>33_?>x?˓>G?14>?=/_>Y?14?~?ff>33g?>ff?˓>O?14>?=/_>a?14? ?ff>33o?>ff?˓>W?14>?=/_>i?14? ?ff> >ff=ˣ>14> >=/>a14?а=ff>L>ff=ˣ>14>@>=/> Cü14?=ff>ff<>33>ˣ>14>`>=/>;14?bh>ff>33s=>33#>ˣ> C14>bh>=/>z^=14?bh8>ff>=>33C>ˣ>P14>bh>=/>=/=14?bhX>ff>=>33c>ˣ>y<14>bh>=/>=/=14?bhx>ff>>>>ˣ>|=14>bh>=/>>14?14>ff><>>>ˣ>z^=14>bh>=/>'>14?14>ff>\>>>ˣ>z^=14>bh>=/>G>14?14>ff>|>>>ˣ>=/>14>bh>=/>g>14?14>ff>ff>>>ˣ>=/?>14>bh>=/>˃>14?14>ff>ff>>>ˣ>=/_>14>14?=/>˓>14?14>ff>ff>>>ˣ>=/>14>14?=/>ˣ>14?14>ff>ff>>>ˣ>>14>14?=/>˳>14?14>ff>ff>>?ˣ>>14>14?=/>>14??ff>ff>>?ˣ>>14>14 ?=/>>14??ff>ff>>?ˣ>>14>14(?=/>>14??ff>ff>>?ˣ>>14>140?=/>>14??ff>33?> ?ˣ>>14>148?=/>?14?&?ff>33?>(?ˣ>>14>14@?=/> ?14?.?ff>33?>0?ˣ>>14>14H?=/>?14?6?ff>33?>8?ˣ>?14>14P?=/>?14?>?ff>33'?>@?ˣ>?14>14X?=/>!?14?F?ff>33/?>H?ˣ>?14>14`?=/>)?14?N?ff>337?>P?ˣ>?14>14h?=/>1?14?V?ff>33??>X?ˣ>'?14>14p?=/>9?14?^?ff>33G?>`?ˣ>/?14>14x?=/>A?14?f?ff>33O?>h?ˣ>7?14>?=/>I?14?n?ff>33W?>p?ˣ>??14>?=/>Q?14?v?ff>33_?>x?ˣ>G?14>?=/>Y?14?~?ff>33g?>ff?ˣ>O?14>?=/>a?14? ?ff>33o?>ff?ˣ>W?14>?=/>i?14? ?ff> >ff=˳>14> >>a14?а=ff>L>ff=˳>14>@>> Cü14?=ff>ff<>33>˳>14>`>>;14?bh>ff>33s=>33#>˳> C14>bh>>z^=14?bh8>ff>=>33C>˳>P14>bh>>=/=14?bhX>ff>=>33c>˳>y<14>bh>>=/=14?bhx>ff>>>>˳>|=14>bh>>>14?14>ff><>>>˳>z^=14>bh>>'>14?14>ff>\>>>˳>z^=14>bh>>G>14?14>ff>|>>>˳>=/>14>bh>>g>14?14>ff>ff>>>˳>=/?>14>bh>>˃>14?14>ff>ff>>>˳>=/_>14>14?>˓>14?14>ff>ff>>>˳>=/>14>14?>ˣ>14?14>ff>ff>>>˳>>14>14?>˳>14?14>ff>ff>>?˳>>14>14?>>14??ff>ff>>?˳>>14>14 ?>>14??ff>ff>>?˳>>14>14(?>>14??ff>ff>>?˳>>14>140?>>14??ff>33?> ?˳>>14>148?>?14?&?ff>33?>(?˳>>14>14@?> ?14?.?ff>33?>0?˳>>14>14H?>?14?6?ff>33?>8?˳>?14>14P?>?14?>?ff>33'?>@?˳>?14>14X?>!?14?F?ff>33/?>H?˳>?14>14`?>)?14?N?ff>337?>P?˳>?14>14h?>1?14?V?ff>33??>X?˳>'?14>14p?>9?14?^?ff>33G?>`?˳>/?14>14x?>A?14?f?ff>33O?>h?˳>7?14>?>I?14?n?ff>33W?>p?˳>??14>?>Q?14?v?ff>33_?>x?˳>G?14>?>Y?14?~?ff>33g?>ff?˳>O?14>?>a?14? ?ff>33o?>ff?˳>W?14>?>i?14? ?ff> ?ff=>? >>a14?а=ff>L?ff=>?@>> Cü14?=ff>ff<?33>>?`>>;14?bh>ff>33s=?33#>> C?bh>>z^=14?bh8>ff>=?33C>>P?bh>>=/=14?bhX>ff>=?33c>>y<?bh>>=/=14?bhx>ff>>?>>|=?bh>>>14?14>ff><>?>>z^=?bh>>'>14?14>ff>\>?>>z^=?bh>>G>14?14>ff>|>?>>=/>?bh>>g>14?14>ff>ff>?>>=/?>?bh>>˃>14?14>ff>ff>?>>=/_>?14?>˓>14?14>ff>ff>?>>=/>?14?>ˣ>14?14>ff>ff>?>>>?14?>˳>14?14>ff>ff>??>>?14?>>14??ff>ff>??>>?14 ?>>14??ff>ff>??>>?14(?>>14??ff>ff>??>>?140?>>14??ff>33?? ?>>?148?>?14?&?ff>33??(?>>?14@?> ?14?.?ff>33??0?>>?14H?>?14?6?ff>33??8?>??14P?>?14?>?ff>33'??@?>??14X?>!?14?F?ff>33/??H?>??14`?>)?14?N?ff>337??P?>??14h?>1?14?V?ff>33???X?>'??14p?>9?14?^?ff>33G??`?>/??14x?>A?14?f?ff>33O??h?>7???>I?14?n?ff>33W??p?>????>Q?14?v?ff>33_??x?>G???>Y?14?~?ff>33g??ff?>O???>a?14? ?ff>33o??ff?>W???>i?14? ?ff> ?ff=>? >>a14 ?а=ff>L?ff=>?@>> Cü14 ?=ff>ff<?33>>?`>>;14 ?bh>ff>33s=?33#>> C?bh>>z^=14 ?bh8>ff>=?33C>>P?bh>>=/=14 ?bhX>ff>=?33c>>y<?bh>>=/=14 ?bhx>ff>>?>>|=?bh>>>14 ?14>ff><>?>>z^=?bh>>'>14 ?14>ff>\>?>>z^=?bh>>G>14 ?14>ff>|>?>>=/>?bh>>g>14 ?14>ff>ff>?>>=/?>?bh>>˃>14 ?14>ff>ff>?>>=/_>?14?>˓>14 ?14>ff>ff>?>>=/>?14?>ˣ>14 ?14>ff>ff>?>>>?14?>˳>14 ?14>ff>ff>??>>?14?>>14 ??ff>ff>??>>?14 ?>>14 ??ff>ff>??>>?14(?>>14 ??ff>ff>??>>?140?>>14 ??ff>33?? ?>>?148?>?14 ?&?ff>33??(?>>?14@?> ?14 ?.?ff>33??0?>>?14H?>?14 ?6?ff>33??8?>??14P?>?14 ?>?ff>33'??@?>??14X?>!?14 ?F?ff>33/??H?>??14`?>)?14 ?N?ff>337??P?>??14h?>1?14 ?V?ff>33???X?>'??14p?>9?14 ?^?ff>33G??`?>/??14x?>A?14 ?f?ff>33O??h?>7???>I?14 ?n?ff>33W??p?>????>Q?14 ?v?ff>33_??x?>G???>Y?14 ?~?ff>33g??ff?>O???>a?14 ? ?ff>33o??ff?>W???>i?14 ? ?ff> ?ff=>? >>a14(?а=ff>L?ff=>?@>> Cü14(?=ff>ff<?33>>?`>>;14(?bh>ff>33s=?33#>> C?bh>>z^=14(?bh8>ff>=?33C>>P?bh>>=/=14(?bhX>ff>=?33c>>y<?bh>>=/=14(?bhx>ff>>?>>|=?bh>>>14(?14>ff><>?>>z^=?bh>>'>14(?14>ff>\>?>>z^=?bh>>G>14(?14>ff>|>?>>=/>?bh>>g>14(?14>ff>ff>?>>=/?>?bh>>˃>14(?14>ff>ff>?>>=/_>?14?>˓>14(?14>ff>ff>?>>=/>?14?>ˣ>14(?14>ff>ff>?>>>?14?>˳>14(?14>ff>ff>??>>?14?>>14(??ff>ff>??>>?14 ?>>14(??ff>ff>??>>?14(?>>14(??ff>ff>??>>?140?>>14(??ff>33?? ?>>?148?>?14(?&?ff>33??(?>>?14@?> ?14(?.?ff>33??0?>>?14H?>?14(?6?ff>33??8?>??14P?>?14(?>?ff>33'??@?>??14X?>!?14(?F?ff>33/??H?>??14`?>)?14(?N?ff>337??P?>??14h?>1?14(?V?ff>33???X?>'??14p?>9?14(?^?ff>33G??`?>/??14x?>A?14(?f?ff>33O??h?>7???>I?14(?n?ff>33W??p?>????>Q?14(?v?ff>33_??x?>G???>Y?14(?~?ff>33g??ff?>O???>a?14(? ?ff>33o??ff?>W???>i?14(? ?ff> ?ff=>? >>a140?а=ff>L?ff=>?@>> Cü140?=ff>ff<?33>>?`>>;140?bh>ff>33s=?33#>> C?bh>>z^=140?bh8>ff>=?33C>>P?bh>>=/=140?bhX>ff>=?33c>>y<?bh>>=/=140?bhx>ff>>?>>|=?bh>>>140?14>ff><>?>>z^=?bh>>'>140?14>ff>\>?>>z^=?bh>>G>140?14>ff>|>?>>=/>?bh>>g>140?14>ff>ff>?>>=/?>?bh>>˃>140?14>ff>ff>?>>=/_>?14?>˓>140?14>ff>ff>?>>=/>?14?>ˣ>140?14>ff>ff>?>>>?14?>˳>140?14>ff>ff>??>>?14?>>140??ff>ff>??>>?14 ?>>140??ff>ff>??>>?14(?>>140??ff>ff>??>>?140?>>140??ff>33?? ?>>?148?>?140?&?ff>33??(?>>?14@?> ?140?.?ff>33??0?>>?14H?>?140?6?ff>33??8?>??14P?>?140?>?ff>33'??@?>??14X?>!?140?F?ff>33/??H?>??14`?>)?140?N?ff>337??P?>??14h?>1?140?V?ff>33???X?>'??14p?>9?140?^?ff>33G??`?>/??14x?>A?140?f?ff>33O??h?>7???>I?140?n?ff>33W??p?>????>Q?140?v?ff>33_??x?>G???>Y?140?~?ff>33g??ff?>O???>a?140? ?ff>33o??ff?>W???>i?140? ?33? ?ff=?&? >>a148?а=33?L ?ff=?&?@>> Cü148?=33?ff< ?33>?&?`>>;148?bh>33?33s= ?33#>? C&?bh>>z^=148?bh8>33?= ?33C>?P&?bh>>=/=148?bhX>33?= ?33c>?y<&?bh>>=/=148?bhx>33?> ?>?|=&?bh>>>148?14>33?<> ?>?z^=&?bh>>'>148?14>33?\> ?>?z^=&?bh>>G>148?14>33?|> ?>?=/>&?bh>>g>148?14>33?ff> ?>?=/?>&?bh>>˃>148?14>33?ff> ?>?=/_>&?14?>˓>148?14>33?ff> ?>?=/>&?14?>ˣ>148?14>33?ff> ?>?>&?14?>˳>148?14>33?ff> ???>&?14?>>148??33?ff> ???>&?14 ?>>148??33?ff> ???>&?14(?>>148??33?ff> ???>&?140?>>148??33?33? ? ??>&?148?>?148?&?33?33? ?(??>&?14@?> ?148?.?33?33? ?0??>&?14H?>?148?6?33?33? ?8???&?14P?>?148?>?33?33'? ?@???&?14X?>!?148?F?33?33/? ?H???&?14`?>)?148?N?33?337? ?P???&?14h?>1?148?V?33?33?? ?X??'?&?14p?>9?148?^?33?33G? ?`??/?&?14x?>A?148?f?33?33O? ?h??7?&??>I?148?n?33?33W? ?p????&??>Q?148?v?33?33_? ?x??G?&??>Y?148?~?33?33g? ?ff??O?&??>a?148? ?33?33o? ?ff??W?&??>i?148? ?33? (?ff= ?.? >>a14@?а=33?L(?ff= ?.?@>> Cü14@?=33?ff<(?33> ?.?`>>;14@?bh>33?33s=(?33#> ? C.?bh>>z^=14@?bh8>33?=(?33C> ?P.?bh>>=/=14@?bhX>33?=(?33c> ?y<.?bh>>=/=14@?bhx>33?>(?> ?|=.?bh>>>14@?14>33?<>(?> ?z^=.?bh>>'>14@?14>33?\>(?> ?z^=.?bh>>G>14@?14>33?|>(?> ?=/>.?bh>>g>14@?14>33?ff>(?> ?=/?>.?bh>>˃>14@?14>33?ff>(?> ?=/_>.?14?>˓>14@?14>33?ff>(?> ?=/>.?14?>ˣ>14@?14>33?ff>(?> ?>.?14?>˳>14@?14>33?ff>(?? ?>.?14?>>14@??33?ff>(?? ?>.?14 ?>>14@??33?ff>(?? ?>.?14(?>>14@??33?ff>(?? ?>.?140?>>14@??33?33?(? ? ?>.?148?>?14@?&?33?33?(?(? ?>.?14@?> ?14@?.?33?33?(?0? ?>.?14H?>?14@?6?33?33?(?8? ??.?14P?>?14@?>?33?33'?(?@? ??.?14X?>!?14@?F?33?33/?(?H? ??.?14`?>)?14@?N?33?337?(?P? ??.?14h?>1?14@?V?33?33??(?X? ?'?.?14p?>9?14@?^?33?33G?(?`? ?/?.?14x?>A?14@?f?33?33O?(?h? ?7?.??>I?14@?n?33?33W?(?p? ???.??>Q?14@?v?33?33_?(?x? ?G?.??>Y?14@?~?33?33g?(?ff? ?O?.??>a?14@? ?33?33o?(?ff? ?W?.??>i?14@? ?33? 0?ff=?6? >>a14H?а=33?L0?ff=?6?@>> Cü14H?=33?ff<0?33>?6?`>>;14H?bh>33?33s=0?33#>? C6?bh>>z^=14H?bh8>33?=0?33C>?P6?bh>>=/=14H?bhX>33?=0?33c>?y<6?bh>>=/=14H?bhx>33?>0?>?|=6?bh>>>14H?14>33?<>0?>?z^=6?bh>>'>14H?14>33?\>0?>?z^=6?bh>>G>14H?14>33?|>0?>?=/>6?bh>>g>14H?14>33?ff>0?>?=/?>6?bh>>˃>14H?14>33?ff>0?>?=/_>6?14?>˓>14H?14>33?ff>0?>?=/>6?14?>ˣ>14H?14>33?ff>0?>?>6?14?>˳>14H?14>33?ff>0???>6?14?>>14H??33?ff>0???>6?14 ?>>14H??33?ff>0???>6?14(?>>14H??33?ff>0???>6?140?>>14H??33?33?0? ??>6?148?>?14H?&?33?33?0?(??>6?14@?> ?14H?.?33?33?0?0??>6?14H?>?14H?6?33?33?0?8???6?14P?>?14H?>?33?33'?0?@???6?14X?>!?14H?F?33?33/?0?H???6?14`?>)?14H?N?33?337?0?P???6?14h?>1?14H?V?33?33??0?X??'?6?14p?>9?14H?^?33?33G?0?`??/?6?14x?>A?14H?f?33?33O?0?h??7?6??>I?14H?n?33?33W?0?p????6??>Q?14H?v?33?33_?0?x??G?6??>Y?14H?~?33?33g?0?ff??O?6??>a?14H? ?33?33o?0?ff??W?6??>i?14H? ?33? 8?ff=?>? >?a14P?а=33?L8?ff=?>?@>? Cü14P?=33?ff<8?33>?>?`>?;14P?bh>33?33s=8?33#>? C>?bh>?z^=14P?bh8>33?=8?33C>?P>?bh>?=/=14P?bhX>33?=8?33c>?y<>?bh>?=/=14P?bhx>33?>8?>?|=>?bh>?>14P?14>33?<>8?>?z^=>?bh>?'>14P?14>33?\>8?>?z^=>?bh>?G>14P?14>33?|>8?>?=/>>?bh>?g>14P?14>33?ff>8?>?=/?>>?bh>?˃>14P?14>33?ff>8?>?=/_>>?14??˓>14P?14>33?ff>8?>?=/>>?14??ˣ>14P?14>33?ff>8?>?>>?14??˳>14P?14>33?ff>8???>>?14??>14P??33?ff>8???>>?14 ??>14P??33?ff>8???>>?14(??>14P??33?ff>8???>>?140??>14P??33?33?8? ??>>?148???14P?&?33?33?8?(??>>?14@?? ?14P?.?33?33?8?0??>>?14H???14P?6?33?33?8?8???>?14P???14P?>?33?33'?8?@???>?14X??!?14P?F?33?33/?8?H???>?14`??)?14P?N?33?337?8?P???>?14h??1?14P?V?33?33??8?X??'?>?14p??9?14P?^?33?33G?8?`??/?>?14x??A?14P?f?33?33O?8?h??7?>???I?14P?n?33?33W?8?p????>???Q?14P?v?33?33_?8?x??G?>???Y?14P?~?33?33g?8?ff??O?>???a?14P? ?33?33o?8?ff??W?>???i?14P? ?33'? @?ff=!?F? >?a14X?а=33'?L@?ff=!?F?@>? Cü14X?=33'?ff<@?33>!?F?`>?;14X?bh>33'?33s=@?33#>!? CF?bh>?z^=14X?bh8>33'?=@?33C>!?PF?bh>?=/=14X?bhX>33'?=@?33c>!?y<F?bh>?=/=14X?bhx>33'?>@?>!?|=F?bh>?>14X?14>33'?<>@?>!?z^=F?bh>?'>14X?14>33'?\>@?>!?z^=F?bh>?G>14X?14>33'?|>@?>!?=/>F?bh>?g>14X?14>33'?ff>@?>!?=/?>F?bh>?˃>14X?14>33'?ff>@?>!?=/_>F?14??˓>14X?14>33'?ff>@?>!?=/>F?14??ˣ>14X?14>33'?ff>@?>!?>F?14??˳>14X?14>33'?ff>@??!?>F?14??>14X??33'?ff>@??!?>F?14 ??>14X??33'?ff>@??!?>F?14(??>14X??33'?ff>@??!?>F?140??>14X??33'?33?@? ?!?>F?148???14X?&?33'?33?@?(?!?>F?14@?? ?14X?.?33'?33?@?0?!?>F?14H???14X?6?33'?33?@?8?!??F?14P???14X?>?33'?33'?@?@?!??F?14X??!?14X?F?33'?33/?@?H?!??F?14`??)?14X?N?33'?337?@?P?!??F?14h??1?14X?V?33'?33??@?X?!?'?F?14p??9?14X?^?33'?33G?@?`?!?/?F?14x??A?14X?f?33'?33O?@?h?!?7?F???I?14X?n?33'?33W?@?p?!???F???Q?14X?v?33'?33_?@?x?!?G?F???Y?14X?~?33'?33g?@?ff?!?O?F???a?14X? ?33'?33o?@?ff?!?W?F???i?14X? ?33/? H?ff=)?N? >?a14`?а=33/?LH?ff=)?N?@>? Cü14`?=33/?ff)?N?`>?;14`?bh>33/?33s=H?33#>)? CN?bh>?z^=14`?bh8>33/?=H?33C>)?PN?bh>?=/=14`?bhX>33/?=H?33c>)?y<N?bh>?=/=14`?bhx>33/?>H?>)?|=N?bh>?>14`?14>33/?<>H?>)?z^=N?bh>?'>14`?14>33/?\>H?>)?z^=N?bh>?G>14`?14>33/?|>H?>)?=/>N?bh>?g>14`?14>33/?ff>H?>)?=/?>N?bh>?˃>14`?14>33/?ff>H?>)?=/_>N?14??˓>14`?14>33/?ff>H?>)?=/>N?14??ˣ>14`?14>33/?ff>H?>)?>N?14??˳>14`?14>33/?ff>H??)?>N?14??>14`??33/?ff>H??)?>N?14 ??>14`??33/?ff>H??)?>N?14(??>14`??33/?ff>H??)?>N?140??>14`??33/?33?H? ?)?>N?148???14`?&?33/?33?H?(?)?>N?14@?? ?14`?.?33/?33?H?0?)?>N?14H???14`?6?33/?33?H?8?)??N?14P???14`?>?33/?33'?H?@?)??N?14X??!?14`?F?33/?33/?H?H?)??N?14`??)?14`?N?33/?337?H?P?)??N?14h??1?14`?V?33/?33??H?X?)?'?N?14p??9?14`?^?33/?33G?H?`?)?/?N?14x??A?14`?f?33/?33O?H?h?)?7?N???I?14`?n?33/?33W?H?p?)???N???Q?14`?v?33/?33_?H?x?)?G?N???Y?14`?~?33/?33g?H?ff?)?O?N???a?14`? ?33/?33o?H?ff?)?W?N???i?14`? ?337? P?ff=1?V? >?a14h?а=337?LP?ff=1?V?@>? Cü14h?=337?ff1?V?`>?;14h?bh>337?33s=P?33#>1? CV?bh>?z^=14h?bh8>337?=P?33C>1?PV?bh>?=/=14h?bhX>337?=P?33c>1?y<V?bh>?=/=14h?bhx>337?>P?>1?|=V?bh>?>14h?14>337?<>P?>1?z^=V?bh>?'>14h?14>337?\>P?>1?z^=V?bh>?G>14h?14>337?|>P?>1?=/>V?bh>?g>14h?14>337?ff>P?>1?=/?>V?bh>?˃>14h?14>337?ff>P?>1?=/_>V?14??˓>14h?14>337?ff>P?>1?=/>V?14??ˣ>14h?14>337?ff>P?>1?>V?14??˳>14h?14>337?ff>P??1?>V?14??>14h??337?ff>P??1?>V?14 ??>14h??337?ff>P??1?>V?14(??>14h??337?ff>P??1?>V?140??>14h??337?33?P? ?1?>V?148???14h?&?337?33?P?(?1?>V?14@?? ?14h?.?337?33?P?0?1?>V?14H???14h?6?337?33?P?8?1??V?14P???14h?>?337?33'?P?@?1??V?14X??!?14h?F?337?33/?P?H?1??V?14`??)?14h?N?337?337?P?P?1??V?14h??1?14h?V?337?33??P?X?1?'?V?14p??9?14h?^?337?33G?P?`?1?/?V?14x??A?14h?f?337?33O?P?h?1?7?V???I?14h?n?337?33W?P?p?1???V???Q?14h?v?337?33_?P?x?1?G?V???Y?14h?~?337?33g?P?ff?1?O?V???a?14h? ?337?33o?P?ff?1?W?V???i?14h? ?33?? X?ff=9?^? >'?a14p?а=33??LX?ff=9?^?@>'? Cü14p?=33??ff9?^?`>'?;14p?bh>33??33s=X?33#>9? C^?bh>'?z^=14p?bh8>33??=X?33C>9?P^?bh>'?=/=14p?bhX>33??=X?33c>9?y<^?bh>'?=/=14p?bhx>33??>X?>9?|=^?bh>'?>14p?14>33??<>X?>9?z^=^?bh>'?'>14p?14>33??\>X?>9?z^=^?bh>'?G>14p?14>33??|>X?>9?=/>^?bh>'?g>14p?14>33??ff>X?>9?=/?>^?bh>'?˃>14p?14>33??ff>X?>9?=/_>^?14?'?˓>14p?14>33??ff>X?>9?=/>^?14?'?ˣ>14p?14>33??ff>X?>9?>^?14?'?˳>14p?14>33??ff>X??9?>^?14?'?>14p??33??ff>X??9?>^?14 ?'?>14p??33??ff>X??9?>^?14(?'?>14p??33??ff>X??9?>^?140?'?>14p??33??33?X? ?9?>^?148?'??14p?&?33??33?X?(?9?>^?14@?'? ?14p?.?33??33?X?0?9?>^?14H?'??14p?6?33??33?X?8?9??^?14P?'??14p?>?33??33'?X?@?9??^?14X?'?!?14p?F?33??33/?X?H?9??^?14`?'?)?14p?N?33??337?X?P?9??^?14h?'?1?14p?V?33??33??X?X?9?'?^?14p?'?9?14p?^?33??33G?X?`?9?/?^?14x?'?A?14p?f?33??33O?X?h?9?7?^??'?I?14p?n?33??33W?X?p?9???^??'?Q?14p?v?33??33_?X?x?9?G?^??'?Y?14p?~?33??33g?X?ff?9?O?^??'?a?14p? ?33??33o?X?ff?9?W?^??'?i?14p? ?33G? `?ff=A?f? >/?a14x?а=33G?L`?ff=A?f?@>/? Cü14x?=33G?ff<`?33>A?f?`>/?;14x?bh>33G?33s=`?33#>A? Cf?bh>/?z^=14x?bh8>33G?=`?33C>A?Pf?bh>/?=/=14x?bhX>33G?=`?33c>A?y<f?bh>/?=/=14x?bhx>33G?>`?>A?|=f?bh>/?>14x?14>33G?<>`?>A?z^=f?bh>/?'>14x?14>33G?\>`?>A?z^=f?bh>/?G>14x?14>33G?|>`?>A?=/>f?bh>/?g>14x?14>33G?ff>`?>A?=/?>f?bh>/?˃>14x?14>33G?ff>`?>A?=/_>f?14?/?˓>14x?14>33G?ff>`?>A?=/>f?14?/?ˣ>14x?14>33G?ff>`?>A?>f?14?/?˳>14x?14>33G?ff>`??A?>f?14?/?>14x??33G?ff>`??A?>f?14 ?/?>14x??33G?ff>`??A?>f?14(?/?>14x??33G?ff>`??A?>f?140?/?>14x??33G?33?`? ?A?>f?148?/??14x?&?33G?33?`?(?A?>f?14@?/? ?14x?.?33G?33?`?0?A?>f?14H?/??14x?6?33G?33?`?8?A??f?14P?/??14x?>?33G?33'?`?@?A??f?14X?/?!?14x?F?33G?33/?`?H?A??f?14`?/?)?14x?N?33G?337?`?P?A??f?14h?/?1?14x?V?33G?33??`?X?A?'?f?14p?/?9?14x?^?33G?33G?`?`?A?/?f?14x?/?A?14x?f?33G?33O?`?h?A?7?f??/?I?14x?n?33G?33W?`?p?A???f??/?Q?14x?v?33G?33_?`?x?A?G?f??/?Y?14x?~?33G?33g?`?ff?A?O?f??/?a?14x? ?33G?33o?`?ff?A?W?f??/?i?14x? ?33O? h?ff=I?n? >7?a?а=33O?Lh?ff=I?n?@>7? Cü?=33O?ffI?n?`>7?;?bh>33O?33s=h?33#>I? Cn?bh>7?z^=?bh8>33O?=h?33C>I?Pn?bh>7?=/=?bhX>33O?=h?33c>I?y<n?bh>7?=/=?bhx>33O?>h?>I?|=n?bh>7?>?14>33O?<>h?>I?z^=n?bh>7?'>?14>33O?\>h?>I?z^=n?bh>7?G>?14>33O?|>h?>I?=/>n?bh>7?g>?14>33O?ff>h?>I?=/?>n?bh>7?˃>?14>33O?ff>h?>I?=/_>n?14?7?˓>?14>33O?ff>h?>I?=/>n?14?7?ˣ>?14>33O?ff>h?>I?>n?14?7?˳>?14>33O?ff>h??I?>n?14?7?>??33O?ff>h??I?>n?14 ?7?>??33O?ff>h??I?>n?14(?7?>??33O?ff>h??I?>n?140?7?>??33O?33?h? ?I?>n?148?7???&?33O?33?h?(?I?>n?14@?7? ??.?33O?33?h?0?I?>n?14H?7???6?33O?33?h?8?I??n?14P?7???>?33O?33'?h?@?I??n?14X?7?!??F?33O?33/?h?H?I??n?14`?7?)??N?33O?337?h?P?I??n?14h?7?1??V?33O?33??h?X?I?'?n?14p?7?9??^?33O?33G?h?`?I?/?n?14x?7?A??f?33O?33O?h?h?I?7?n??7?I??n?33O?33W?h?p?I???n??7?Q??v?33O?33_?h?x?I?G?n??7?Y??~?33O?33g?h?ff?I?O?n??7?a?? ?33O?33o?h?ff?I?W?n??7?i?? ?33W? p?ff=Q?v? >??a?а=33W?Lp?ff=Q?v?@>?? Cü?=33W?ffQ?v?`>??;?bh>33W?33s=p?33#>Q? Cv?bh>??z^=?bh8>33W?=p?33C>Q?Pv?bh>??=/=?bhX>33W?=p?33c>Q?y<v?bh>??=/=?bhx>33W?>p?>Q?|=v?bh>??>?14>33W?<>p?>Q?z^=v?bh>??'>?14>33W?\>p?>Q?z^=v?bh>??G>?14>33W?|>p?>Q?=/>v?bh>??g>?14>33W?ff>p?>Q?=/?>v?bh>??˃>?14>33W?ff>p?>Q?=/_>v?14???˓>?14>33W?ff>p?>Q?=/>v?14???ˣ>?14>33W?ff>p?>Q?>v?14???˳>?14>33W?ff>p??Q?>v?14???>??33W?ff>p??Q?>v?14 ???>??33W?ff>p??Q?>v?14(???>??33W?ff>p??Q?>v?140???>??33W?33?p? ?Q?>v?148?????&?33W?33?p?(?Q?>v?14@??? ??.?33W?33?p?0?Q?>v?14H?????6?33W?33?p?8?Q??v?14P?????>?33W?33'?p?@?Q??v?14X???!??F?33W?33/?p?H?Q??v?14`???)??N?33W?337?p?P?Q??v?14h???1??V?33W?33??p?X?Q?'?v?14p???9??^?33W?33G?p?`?Q?/?v?14x???A??f?33W?33O?p?h?Q?7?v????I??n?33W?33W?p?p?Q???v????Q??v?33W?33_?p?x?Q?G?v????Y??~?33W?33g?p?ff?Q?O?v????a?? ?33W?33o?p?ff?Q?W?v????i?? ?33_? x?ff=Y?~? >G?a?а=33_?Lx?ff=Y?~?@>G? Cü?=33_?ffY?~?`>G?;?bh>33_?33s=x?33#>Y? C~?bh>G?z^=?bh8>33_?=x?33C>Y?P~?bh>G?=/=?bhX>33_?=x?33c>Y?y<~?bh>G?=/=?bhx>33_?>x?>Y?|=~?bh>G?>?14>33_?<>x?>Y?z^=~?bh>G?'>?14>33_?\>x?>Y?z^=~?bh>G?G>?14>33_?|>x?>Y?=/>~?bh>G?g>?14>33_?ff>x?>Y?=/?>~?bh>G?˃>?14>33_?ff>x?>Y?=/_>~?14?G?˓>?14>33_?ff>x?>Y?=/>~?14?G?ˣ>?14>33_?ff>x?>Y?>~?14?G?˳>?14>33_?ff>x??Y?>~?14?G?>??33_?ff>x??Y?>~?14 ?G?>??33_?ff>x??Y?>~?14(?G?>??33_?ff>x??Y?>~?140?G?>??33_?33?x? ?Y?>~?148?G???&?33_?33?x?(?Y?>~?14@?G? ??.?33_?33?x?0?Y?>~?14H?G???6?33_?33?x?8?Y??~?14P?G???>?33_?33'?x?@?Y??~?14X?G?!??F?33_?33/?x?H?Y??~?14`?G?)??N?33_?337?x?P?Y??~?14h?G?1??V?33_?33??x?X?Y?'?~?14p?G?9??^?33_?33G?x?`?Y?/?~?14x?G?A??f?33_?33O?x?h?Y?7?~??G?I??n?33_?33W?x?p?Y???~??G?Q??v?33_?33_?x?x?Y?G?~??G?Y??~?33_?33g?x?ff?Y?O?~??G?a?? ?33_?33o?x?ff?Y?W?~??G?i?? ?33g? ff?ff=a? ? >O?a?а=33g?Lff?ff=a? ?@>O? Cü?=33g?ffa? ?`>O?;?bh>33g?33s=ff?33#>a? C ?bh>O?z^=?bh8>33g?=ff?33C>a?P ?bh>O?=/=?bhX>33g?=ff?33c>a?y< ?bh>O?=/=?bhx>33g?>ff?>a?|= ?bh>O?>?14>33g?<>ff?>a?z^= ?bh>O?'>?14>33g?\>ff?>a?z^= ?bh>O?G>?14>33g?|>ff?>a?=/> ?bh>O?g>?14>33g?ff>ff?>a?=/?> ?bh>O?˃>?14>33g?ff>ff?>a?=/_> ?14?O?˓>?14>33g?ff>ff?>a?=/> ?14?O?ˣ>?14>33g?ff>ff?>a?> ?14?O?˳>?14>33g?ff>ff??a?> ?14?O?>??33g?ff>ff??a?> ?14 ?O?>??33g?ff>ff??a?> ?14(?O?>??33g?ff>ff??a?> ?140?O?>??33g?33?ff? ?a?> ?148?O???&?33g?33?ff?(?a?> ?14@?O? ??.?33g?33?ff?0?a?> ?14H?O???6?33g?33?ff?8?a?? ?14P?O???>?33g?33'?ff?@?a?? ?14X?O?!??F?33g?33/?ff?H?a?? ?14`?O?)??N?33g?337?ff?P?a?? ?14h?O?1??V?33g?33??ff?X?a?'? ?14p?O?9??^?33g?33G?ff?`?a?/? ?14x?O?A??f?33g?33O?ff?h?a?7? ??O?I??n?33g?33W?ff?p?a??? ??O?Q??v?33g?33_?ff?x?a?G? ??O?Y??~?33g?33g?ff?ff?a?O? ??O?a?? ?33g?33o?ff?ff?a?W? ??O?i?? ?33o? ff?ff=i? ? >W?a?а=33o?Lff?ff=i? ?@>W? Cü?=33o?ffi? ?`>W?;?bh>33o?33s=ff?33#>i? C ?bh>W?z^=?bh8>33o?=ff?33C>i?P ?bh>W?=/=?bhX>33o?=ff?33c>i?y< ?bh>W?=/=?bhx>33o?>ff?>i?|= ?bh>W?>?14>33o?<>ff?>i?z^= ?bh>W?'>?14>33o?\>ff?>i?z^= ?bh>W?G>?14>33o?|>ff?>i?=/> ?bh>W?g>?14>33o?ff>ff?>i?=/?> ?bh>W?˃>?14>33o?ff>ff?>i?=/_> ?14?W?˓>?14>33o?ff>ff?>i?=/> ?14?W?ˣ>?14>33o?ff>ff?>i?> ?14?W?˳>?14>33o?ff>ff??i?> ?14?W?>??33o?ff>ff??i?> ?14 ?W?>??33o?ff>ff??i?> ?14(?W?>??33o?ff>ff??i?> ?140?W?>??33o?33?ff? ?i?> ?148?W???&?33o?33?ff?(?i?> ?14@?W? ??.?33o?33?ff?0?i?> ?14H?W???6?33o?33?ff?8?i?? ?14P?W???>?33o?33'?ff?@?i?? ?14X?W?!??F?33o?33/?ff?H?i?? ?14`?W?)??N?33o?337?ff?P?i?? ?14h?W?1??V?33o?33??ff?X?i?'? ?14p?W?9??^?33o?33G?ff?`?i?/? ?14x?W?A??f?33o?33O?ff?h?i?7? ??W?I??n?33o?33W?ff?p?i??? ??W?Q??v?33o?33_?ff?x?i?G? ??W?Y??~?33o?33g?ff?ff?i?O? ??W?a?? ?33o?33o?ff?ff?i?W? ??W?i?? ?432343S>23S>[/6Y/6[/v>Y/v>VmSm]>>Vm]Sm>>쎽1v>1>3x鎽3>t>43df43S>>[/6^[/v>>VmSm>>Vm]L>^>쎽,bVv>1>33>tG>4343S>>[/6dX[/v>>Vmں>>Vm]Z%=>U[>쎽,bv>1>3-b=3>^>43833=43S>>[/6p +<[/v>>Vmj뼫>>Vm]=>U[>쎽XĬv>?3=3>^>43=43S>>[/6N=[/v>>VmJ +=>U[?Vm]VI!>>U[>쎽`v>?3D8>3>^>43,>43S>?[/6 >[/v>֋ ?VmZ%=>U[?Vm]VIa>>U[>쎽Pw&=v>%?3Dx>3>^>43l>43S>?[/6I>[/v>֋?Vm">>U['?Vm]>>?쎽;=v>5?3E>3>/?43gf>43S>$?[/6T>[/v>֋-?Vmb>>U[7?Vm]>>?쎽ԝ)>v>E?3E>3>/?43gf>43S>4?[/6T>[/v>֋=?VmVI>>U[G?Vm]>>'?쎽ԝi>v>U?3E>3>/!?43gf>43S>D?[/6T>[/v>֋M?VmVI>>U[W?Vm]>>7?쎽Δ>v>e?3E>3>/1?43gf>43S>T?[/6T>[/v>֋]?VmVI>>U[g?Vm]VR?>G?쎽δ>v>u?3"?3>/A?4343 ?43S>d?[/6*t?[/v>֋m?VmVI>>U[w?Vm]VR?>W?쎽>v>F̂?3"?3>/Q?4343?43S>t?[/6*t?[/v>֋}?Vm?>?Vm]VR(?>g?쎽>v>F̊?3".?3>/a?4343+?43S>ff?[/6*t"?[/v>ņ?Vm?>?Vm]VR8?>w?쎽ug +?v>F̒?3">?3>/q?4343;?43S>ff?[/6*t2?[/v>Ŏ?Vm(?>?Vm]VRH?>փ?쎽ug?v>F̚?3"N?3>?4343K?43S>ff?[/6*tB?[/v>Ŗ?Vm8?>?Vm]VRX?>֋?쎽ug*?v>F̢?3"^?3>?hf23>23S>^Y/6>Y/v>XSm]^>>VmSm>>1vG>1>&fVx鎽3>t>hfdf>>^콲^콮>>XSm^>>VmL>^>,bVvG>1>&fV3>tG>hf>>^dX>>Xں^>>VmZ%=>U[>,bvG>1>&fV-b=3>^>hf833=>>^p +<>>Xj뼫^>>Vm=>U[>XĬvG>?&fV=3>^>hf=>>^N=>>XJ +=^>U[?VmVI!>>U[>`vG>?&fVD8>3>^>hf,>>?^콧 >>֋ ?XZ%=^>U[?VmVIa>>U[>Pw&=vG>%?&fVDx>3>^>hfl>>?^콧I>>֋?X">^>U['?Vm>>?;=vG>5?&fVE>3>/?hfgf>>$?^T>>֋-?Xb>^>U[7?Vm>>?ԝ)>vG>E?&fVE>3>/?hfgf>>4?^T>>֋=?XVI>^>U[G?Vm>>'?ԝi>vG>U?&fVE>3>/!?hfgf>>D?^T>>֋M?XVI>^>U[W?Vm>>7?Δ>vG>e?&fVE>3>/1?hfgf>>T?^T>>֋]?XVI>^>U[g?VmVR?>G?δ>vG>u?&fV"?3>/A?hf43 ?>d?^*t?>֋m?XVI>^>U[w?VmVR?>W?>vG>F̂?&fV"?3>/Q?hf43?>t?^*t?>֋}?X?^>?VmVR(?>g?>vG>F̊?&fV".?3>/a?hf43+?>ff?^*t"?>ņ?X?^>?VmVR8?>w?ug +?vG>F̒?&fV">?3>/q?hf43;?>ff?^*t2?>Ŏ?X(?^>?VmVRH?>փ?ug?vG>F̚?&fV"N?3>?hf43K?>ff?^*tB?>Ŗ?X8?^>?VmVRX?>֋?ug*?vG>F̢?&fV"^?3>?23>23S>lXY/6>Y/v>T%=Sm]V[>>ںSm>>'b=1>1>&fx鎽3>t>df>>lX^콮>>T%=SmV[>>ںL>^>'b=,bV>1>&f3>tG>>>lXdX>>T%=ںV[>>ںZ%=>U[>'b=,b>1>&f-b=3>^>833=>>lXp +<>>T%=jV[>>ں=>U[>'b=XĬ>?&f=3>^>=>>lXN=>>T%=J +=V[>U[?ںVI!>>U[>'b=`>?&fD8>3>^>,>>?lX >>֋ ?T%=Z%=V[>U[?ںVIa>>U[>'b=Pw&=>%?&fDx>3>^>l>>?lXI>>֋?T%=">V[>U['?ں>>?'b=;=>5?&fE>3>/?gf>>$?lXT>>֋-?T%=b>V[>U[7?ں>>?'b=ԝ)>>E?&fE>3>/?gf>>4?lXT>>֋=?T%=VI>V[>U[G?ں>>'?'b=ԝi>>U?&fE>3>/!?gf>>D?lXT>>֋M?T%=VI>V[>U[W?ں>>7?'b=Δ>>e?&fE>3>/1?gf>>T?lXT>>֋]?T%=VI>V[>U[g?ںVR?>G?'b=δ>>u?&f"?3>/A?43 ?>d?lX*t?>֋m?T%=VI>V[>U[w?ںVR?>W?'b=>>F̂?&f"?3>/Q?43?>t?lX*t?>֋}?T%=?V[>?ںVR(?>g?'b=>>F̊?&f".?3>/a?43+?>ff?lX*t"?>ņ?T%=?V[>?ںVR8?>w?'b=ug +?>F̒?&f">?3>/q?43;?>ff?lX*t2?>Ŏ?T%=(?V[>?ںVRH?>փ?'b=ug?>F̚?&f"N?3>?43K?>ff?lX*tB?>Ŗ?T%=8?V[>?ںVRX?>֋?'b=ug*?>F̢?&f"^?3>?033=23>23S>P +Y/v>=Sm]V[>>jSm>>=1>1>L̬x鎽?t>033=df>>P +<^콮>>=SmV[>>jL>^>=,bV>1>L̬?tG>033=>>P +>=ںV[>>jZ%=>U[>=,b>1>L̬-b=?^>033=833=>>P +

>=jV[>>j뼭=>U[>=XĬ>?L̬=?^>033==>>P +>=J +=V[>U[?jVI!>>U[>=`>?L̬D8>?^>033=,>>?P +< >>֋ ?=Z%=V[>U[?jVIa>>U[>=Pw&=>%?L̬Dx>?^>033=l>>?P +>֋?=">V[>U['?j뼫>>?=;=>5?L̬E>?/?033=gf>>$?P +>֋-?=b>V[>U[7?j뼫>>?=ԝ)>>E?L̬E>?/?033=gf>>4?P +>֋=?=VI>V[>U[G?j뼫>>'?=ԝi>>U?L̬E>?/!?033=gf>>D?P +>֋M?=VI>V[>U[W?j뼫>>7?=Δ>>e?L̬E>?/1?033=gf>>T?P +>֋]?=VI>V[>U[g?jVR?>G?=δ>>u?L̬"??/A?033=43 ?>d?P +<*t?>֋m?=VI>V[>U[w?jVR?>W?=>>F̂?L̬"??/Q?033=43?>t?P +<*t?>֋}?=?V[>?jVR(?>g?=>>F̊?L̬".??/a?033=43+?>ff?P +<*t"?>ņ?=?V[>?jVR8?>w?=ug +?>F̒?L̬">??/q?033=43;?>ff?P +<*t2?>Ŏ?=(?V[>?jVRH?>փ?=ug?>F̚?L̬"N???033=43K?>ff?P +<*tB?>Ŗ?=8?V[>?jVRX?>֋?=ug*?>F̢?L̬"^???=23>23S>J=Y/6>Y/v>UI!>Sm]V[>>J +=SmV[?>8>1>1>01x鎽?t>=df>>J=^콮>>UI!>SmV[>>J +=LV[?^>8>,bV>1>01?tG>=>>J=dX>>UI!>ںV[>>J +=Z%=V[?U[>8>,b>1>01-b=?^>=833=>>J=p +<>>UI!>jV[>>J +==V[?U[>8>XĬ>?01=?^>==>>J=N=>>UI!>J +=V[>U[?J +=VI!>V[?U[>8>`>?01D8>?^>=,>>?J= >>֋ ?UI!>Z%=V[>U[?J +=VIa>V[?U[>8>Pw&=>%?01Dx>?^>=l>>?J=I>>֋?UI!>">V[>U['?J +=>V[??8>;=>5?01E>?/?=gf>>$?J=T>>֋-?UI!>b>V[>U[7?J +=>V[??8>ԝ)>>E?01E>?/?=gf>>4?J=T>>֋=?UI!>VI>V[>U[G?J +=>V[?'?8>ԝi>>U?01E>?/!?=gf>>D?J=T>>֋M?UI!>VI>V[>U[W?J +=>V[?7?8>Δ>>e?01E>?/1?=gf>>T?J=T>>֋]?UI!>VI>V[>U[g?J +=VR?V[?G?8>δ>>u?01"??/A?=43 ?>d?J=*t?>֋m?UI!>VI>V[>U[w?J +=VR?V[?W?8>>>F̂?01"??/Q?=43?>t?J=*t?>֋}?UI!>?V[>?J +=VR(?V[?g?8>>>F̊?01".??/a?=43+?>ff?J=*t"?>ņ?UI!>?V[>?J +=VR8?V[?w?8>ug +?>F̒?01">??/q?=43;?>ff?J=*t2?>Ŏ?UI!>(?V[>?J +=VRH?V[?փ?8>ug?>F̚?01"N???=43K?>ff?J=*tB?>Ŗ?UI!>8?V[>?J +=VRX?V[?֋?8>ug*?>F̢?01"^???,>23?23S> >Y/6׋ ?Y/v>UIa>Sm]V[>>T%=SmV[?>x>1>1>hg&=x鎽%?t>,>df?> >^׋ ?>UIa>SmV[>>T%=LV[?^>x>,bV>1>hg&=%?tG>,>?> >dX׋ ?>UIa>ںV[>>T%=Z%=V[?U[>x>,b>1>hg&=-b=%?^>,>833=?> >p +<׋ ?>UIa>jV[>>T%==V[?U[>x>XĬ>?hg&==%?^>,>=?> >N=׋ ?>UIa>J +=V[>U[?T%=VI!>V[?U[>x>`>?hg&=D8>%?^>,>,>?? > >׋ ?֋ ?UIa>Z%=V[>U[?T%=VIa>V[?U[>x>Pw&=>%?hg&=Dx>%?^>,>l>?? >I>׋ ?֋?UIa>">V[>U['?T%=>V[??x>;=>5?hg&=E>%?/?,>gf>?$? >T>׋ ?֋-?UIa>b>V[>U[7?T%=>V[??x>ԝ)>>E?hg&=E>%?/?,>gf>?4? >T>׋ ?֋=?UIa>VI>V[>U[G?T%=>V[?'?x>ԝi>>U?hg&=E>%?/!?,>gf>?D? >T>׋ ?֋M?UIa>VI>V[>U[W?T%=>V[?7?x>Δ>>e?hg&=E>%?/1?,>gf>?T? >T>׋ ?֋]?UIa>VI>V[>U[g?T%=VR?V[?G?x>δ>>u?hg&="?%?/A?,>43 ??d? >*t?׋ ?֋m?UIa>VI>V[>U[w?T%=VR?V[?W?x>>>F̂?hg&="?%?/Q?,>43??t? >*t?׋ ?֋}?UIa>?V[>?T%=VR(?V[?g?x>>>F̊?hg&=".?%?/a?,>43+??ff? >*t"?׋ ?ņ?UIa>?V[>?T%=VR8?V[?w?x>ug +?>F̒?hg&=">?%?/q?,>43;??ff? >*t2?׋ ?Ŏ?UIa>(?V[>?T%=VRH?V[?փ?x>ug?>F̚?hg&="N?%??,>43K??ff? >*tB?׋ ?Ŗ?UIa>8?V[>?T%=VRX?V[?֋?x>ug*?>F̢?hg&="^?%??l>23?23S>I>Y/6׋?Y/v>>Sm]?>">SmV['?>D>1?1>3=x鎽5?t>l>df?>I>^׋?>>Sm?>">LV['?^>D>,bV?1>3=5?tG>l>?>I>dX׋?>>ں?>">Z%=V['?U[>D>,b?1>3=-b=5?^>l>833=?>I>p +<׋?>>j뼫?>">=V['?U[>D>XĬ??3==5?^>l>=?>I>N=׋?>>J +=?U[?">VI!>V['?U[>D>`??3=D8>5?^>l>,>??I> >׋?֋ ?>Z%=?U[?">VIa>V['?U[>D>Pw&=?%?3=Dx>5?^>l>l>??I>I>׋?֋?>">?U['?">>V['??D>;=?5?3=E>5?/?l>gf>?$?I>T>׋?֋-?>b>?U[7?">>V['??D>ԝ)>?E?3=E>5?/?l>gf>?4?I>T>׋?֋=?>VI>?U[G?">>V['?'?D>ԝi>?U?3=E>5?/!?l>gf>?D?I>T>׋?֋M?>VI>?U[W?">>V['?7?D>Δ>?e?3=E>5?/1?l>gf>?T?I>T>׋?֋]?>VI>?U[g?">VR?V['?G?D>δ>?u?3="?5?/A?l>43 ??d?I>*t?׋?֋m?>VI>?U[w?">VR?V['?W?D>>?F̂?3="?5?/Q?l>43??t?I>*t?׋?֋}?>???">VR(?V['?g?D>>?F̊?3=".?5?/a?l>43+??ff?I>*t"?׋?ņ?>???">VR8?V['?w?D>ug +??F̒?3=">?5?/q?l>43;??ff?I>*t2?׋?Ŏ?>(???">VRH?V['?փ?D>ug??F̚?3="N?5??l>43K??ff?I>*tB?׋?Ŗ?>8???">VRX?V['?֋?D>ug*??F̢?3="^?5??ff>23$?23S>R>Y/6׋-?Y/v>>Sm]?>b>SmV[7?>D>1?1>ڙ)>x鎽E?t>ff>df$?>R>^׋-?>>Sm?>b>LV[7?^>D>,bV?1>ڙ)>E?tG>ff>$?>R>dX׋-?>>ں?>b>Z%=V[7?U[>D>,b?1>ڙ)>-b=E?^>ff>833=$?>R>p +<׋-?>>j뼫?>b>=V[7?U[>D>XĬ??ڙ)>=E?^>ff>=$?>R>N=׋-?>>J +=?U[?b>VI!>V[7?U[>D>`??ڙ)>D8>E?^>ff>,>$??R> >׋-?֋ ?>Z%=?U[?b>VIa>V[7?U[>D>Pw&=?%?ڙ)>Dx>E?^>ff>l>$??R>I>׋-?֋?>">?U['?b>>V[7??D>;=?5?ڙ)>E>E?/?ff>gf>$?$?R>T>׋-?֋-?>b>?U[7?b>>V[7??D>ԝ)>?E?ڙ)>E>E?/?ff>gf>$?4?R>T>׋-?֋=?>VI>?U[G?b>>V[7?'?D>ԝi>?U?ڙ)>E>E?/!?ff>gf>$?D?R>T>׋-?֋M?>VI>?U[W?b>>V[7?7?D>Δ>?e?ڙ)>E>E?/1?ff>gf>$?T?R>T>׋-?֋]?>VI>?U[g?b>VR?V[7?G?D>δ>?u?ڙ)>"?E?/A?ff>43 ?$?d?R>*t?׋-?֋m?>VI>?U[w?b>VR?V[7?W?D>>?F̂?ڙ)>"?E?/Q?ff>43?$?t?R>*t?׋-?֋}?>???b>VR(?V[7?g?D>>?F̊?ڙ)>".?E?/a?ff>43+?$?ff?R>*t"?׋-?ņ?>???b>VR8?V[7?w?D>ug +??F̒?ڙ)>">?E?/q?ff>43;?$?ff?R>*t2?׋-?Ŏ?>(???b>VRH?V[7?փ?D>ug??F̚?ڙ)>"N?E??ff>43K?$?ff?R>*tB?׋-?Ŗ?>8???b>VRX?V[7?֋?D>ug*??F̢?ڙ)>"^?E??ff>234?23S>R>Y/6׋=?Y/v>>Sm]'?>UI>SmV[G?>D>1!?1>ڙi>x鎽U?t>ff>df4?>R>^׋=?>>Sm'?>UI>LV[G?^>D>,bV!?1>ڙi>U?tG>ff>4?>R>dX׋=?>>ں'?>UI>Z%=V[G?U[>D>,b!?1>ڙi>-b=U?^>ff>833=4?>R>p +<׋=?>>j뼫'?>UI>=V[G?U[>D>XĬ!??ڙi>=U?^>ff>=4?>R>N=׋=?>>J +='?U[?UI>VI!>V[G?U[>D>`!??ڙi>D8>U?^>ff>,>4??R> >׋=?֋ ?>Z%='?U[?UI>VIa>V[G?U[>D>Pw&=!?%?ڙi>Dx>U?^>ff>l>4??R>I>׋=?֋?>">'?U['?UI>>V[G??D>;=!?5?ڙi>E>U?/?ff>gf>4?$?R>T>׋=?֋-?>b>'?U[7?UI>>V[G??D>ԝ)>!?E?ڙi>E>U?/?ff>gf>4?4?R>T>׋=?֋=?>VI>'?U[G?UI>>V[G?'?D>ԝi>!?U?ڙi>E>U?/!?ff>gf>4?D?R>T>׋=?֋M?>VI>'?U[W?UI>>V[G?7?D>Δ>!?e?ڙi>E>U?/1?ff>gf>4?T?R>T>׋=?֋]?>VI>'?U[g?UI>VR?V[G?G?D>δ>!?u?ڙi>"?U?/A?ff>43 ?4?d?R>*t?׋=?֋m?>VI>'?U[w?UI>VR?V[G?W?D>>!?F̂?ڙi>"?U?/Q?ff>43?4?t?R>*t?׋=?֋}?>?'??UI>VR(?V[G?g?D>>!?F̊?ڙi>".?U?/a?ff>43+?4?ff?R>*t"?׋=?ņ?>?'??UI>VR8?V[G?w?D>ug +?!?F̒?ڙi>">?U?/q?ff>43;?4?ff?R>*t2?׋=?Ŏ?>(?'??UI>VRH?V[G?փ?D>ug?!?F̚?ڙi>"N?U??ff>43K?4?ff?R>*tB?׋=?Ŗ?>8?'??UI>VRX?V[G?֋?D>ug*?!?F̢?ڙi>"^?U??ff>23D?23S>R>Y/6׋M?Y/v>>Sm]7?>UI>SmV[W?>D>11?1>̔>x鎽e?t>ff>dfD?>R>^׋M?>>Sm7?>UI>LV[W?^>D>,bV1?1>̔>e?tG>ff>D?>R>dX׋M?>>ں7?>UI>Z%=V[W?U[>D>,b1?1>̔>-b=e?^>ff>833=D?>R>p +<׋M?>>j뼫7?>UI>=V[W?U[>D>XĬ1??̔>=e?^>ff>=D?>R>N=׋M?>>J +=7?U[?UI>VI!>V[W?U[>D>`1??̔>D8>e?^>ff>,>D??R> >׋M?֋ ?>Z%=7?U[?UI>VIa>V[W?U[>D>Pw&=1?%?̔>Dx>e?^>ff>l>D??R>I>׋M?֋?>">7?U['?UI>>V[W??D>;=1?5?̔>E>e?/?ff>gf>D?$?R>T>׋M?֋-?>b>7?U[7?UI>>V[W??D>ԝ)>1?E?̔>E>e?/?ff>gf>D?4?R>T>׋M?֋=?>VI>7?U[G?UI>>V[W?'?D>ԝi>1?U?̔>E>e?/!?ff>gf>D?D?R>T>׋M?֋M?>VI>7?U[W?UI>>V[W?7?D>Δ>1?e?̔>E>e?/1?ff>gf>D?T?R>T>׋M?֋]?>VI>7?U[g?UI>VR?V[W?G?D>δ>1?u?̔>"?e?/A?ff>43 ?D?d?R>*t?׋M?֋m?>VI>7?U[w?UI>VR?V[W?W?D>>1?F̂?̔>"?e?/Q?ff>43?D?t?R>*t?׋M?֋}?>?7??UI>VR(?V[W?g?D>>1?F̊?̔>".?e?/a?ff>43+?D?ff?R>*t"?׋M?ņ?>?7??UI>VR8?V[W?w?D>ug +?1?F̒?̔>">?e?/q?ff>43;?D?ff?R>*t2?׋M?Ŏ?>(?7??UI>VRH?V[W?փ?D>ug?1?F̚?̔>"N?e??ff>43K?D?ff?R>*tB?׋M?Ŗ?>8?7??UI>VRX?V[W?֋?D>ug*?1?F̢?̔>"^?e??ff>23T?23S>R>Y/6׋]?Y/v>UR?Sm]G?>UI>SmV[g?>|"?1A?1>̴>x鎽u?t>ff>dfT?>R>^׋]?>UR?SmG?>UI>LV[g?^>|"?,bVA?1>̴>u?tG>ff>T?>R>dX׋]?>UR?ںG?>UI>Z%=V[g?U[>|"?,bA?1>̴>-b=u?^>ff>833=T?>R>p +<׋]?>UR?j뼫G?>UI>=V[g?U[>|"?XĬA??̴>=u?^>ff>=T?>R>N=׋]?>UR?J +=G?U[?UI>VI!>V[g?U[>|"?`A??̴>D8>u?^>ff>,>T??R> >׋]?֋ ?UR?Z%=G?U[?UI>VIa>V[g?U[>|"?Pw&=A?%?̴>Dx>u?^>ff>l>T??R>I>׋]?֋?UR?">G?U['?UI>>V[g??|"?;=A?5?̴>E>u?/?ff>gf>T?$?R>T>׋]?֋-?UR?b>G?U[7?UI>>V[g??|"?ԝ)>A?E?̴>E>u?/?ff>gf>T?4?R>T>׋]?֋=?UR?VI>G?U[G?UI>>V[g?'?|"?ԝi>A?U?̴>E>u?/!?ff>gf>T?D?R>T>׋]?֋M?UR?VI>G?U[W?UI>>V[g?7?|"?Δ>A?e?̴>E>u?/1?ff>gf>T?T?R>T>׋]?֋]?UR?VI>G?U[g?UI>VR?V[g?G?|"?δ>A?u?̴>"?u?/A?ff>43 ?T?d?R>*t?׋]?֋m?UR?VI>G?U[w?UI>VR?V[g?W?|"?>A?F̂?̴>"?u?/Q?ff>43?T?t?R>*t?׋]?֋}?UR??G??UI>VR(?V[g?g?|"?>A?F̊?̴>".?u?/a?ff>43+?T?ff?R>*t"?׋]?ņ?UR??G??UI>VR8?V[g?w?|"?ug +?A?F̒?̴>">?u?/q?ff>43;?T?ff?R>*t2?׋]?Ŏ?UR?(?G??UI>VRH?V[g?փ?|"?ug?A?F̚?̴>"N?u??ff>43K?T?ff?R>*tB?׋]?Ŗ?UR?8?G??UI>VRX?V[g?֋?|"?ug*?A?F̢?̴>"^?u??33 ?23d?23S>)t?Y/6׋m?Y/v>UR?Sm]W?>UI>SmV[w?>|"?1Q?1>>x鎽̂?t>33 ?dfd?>)t?^׋m?>UR?SmW?>UI>LV[w?^>|"?,bVQ?1>>̂?tG>33 ?d?>)t?dX׋m?>UR?ںW?>UI>Z%=V[w?U[>|"?,bQ?1>>-b=̂?^>33 ?833=d?>)t?p +<׋m?>UR?j뼫W?>UI>=V[w?U[>|"?XĬQ??>=̂?^>33 ?=d?>)t?N=׋m?>UR?J +=W?U[?UI>VI!>V[w?U[>|"?`Q??>D8>̂?^>33 ?,>d??)t? >׋m?֋ ?UR?Z%=W?U[?UI>VIa>V[w?U[>|"?Pw&=Q?%?>Dx>̂?^>33 ?l>d??)t?I>׋m?֋?UR?">W?U['?UI>>V[w??|"?;=Q?5?>E>̂?/?33 ?gf>d?$?)t?T>׋m?֋-?UR?b>W?U[7?UI>>V[w??|"?ԝ)>Q?E?>E>̂?/?33 ?gf>d?4?)t?T>׋m?֋=?UR?VI>W?U[G?UI>>V[w?'?|"?ԝi>Q?U?>E>̂?/!?33 ?gf>d?D?)t?T>׋m?֋M?UR?VI>W?U[W?UI>>V[w?7?|"?Δ>Q?e?>E>̂?/1?33 ?gf>d?T?)t?T>׋m?֋]?UR?VI>W?U[g?UI>VR?V[w?G?|"?δ>Q?u?>"?̂?/A?33 ?43 ?d?d?)t?*t?׋m?֋m?UR?VI>W?U[w?UI>VR?V[w?W?|"?>Q?F̂?>"?̂?/Q?33 ?43?d?t?)t?*t?׋m?֋}?UR??W??UI>VR(?V[w?g?|"?>Q?F̊?>".?̂?/a?33 ?43+?d?ff?)t?*t"?׋m?ņ?UR??W??UI>VR8?V[w?w?|"?ug +?Q?F̒?>">?̂?/q?33 ?43;?d?ff?)t?*t2?׋m?Ŏ?UR?(?W??UI>VRH?V[w?փ?|"?ug?Q?F̚?>"N?̂??33 ?43K?d?ff?)t?*tB?׋m?Ŗ?UR?8?W??UI>VRX?V[w?֋?|"?ug*?Q?F̢?>"^?̂??33?23t?23S>)t?Y/6׋}?Y/v>UR(?Sm]g?>?Sm?>|".?1a?1>>x鎽̊?t>33?dft?>)t?^׋}?>UR(?Smg?>?L?^>|".?,bVa?1>>̊?tG>33?t?>)t?dX׋}?>UR(?ںg?>?Z%=?U[>|".?,ba?1>>-b=̊?^>33?833=t?>)t?p +<׋}?>UR(?j뼫g?>?=?U[>|".?XĬa??>=̊?^>33?=t?>)t?N=׋}?>UR(?J +=g?U[??VI!>?U[>|".?`a??>D8>̊?^>33?,>t??)t? >׋}?֋ ?UR(?Z%=g?U[??VIa>?U[>|".?Pw&=a?%?>Dx>̊?^>33?l>t??)t?I>׋}?֋?UR(?">g?U['??>??|".?;=a?5?>E>̊?/?33?gf>t?$?)t?T>׋}?֋-?UR(?b>g?U[7??>??|".?ԝ)>a?E?>E>̊?/?33?gf>t?4?)t?T>׋}?֋=?UR(?VI>g?U[G??>?'?|".?ԝi>a?U?>E>̊?/!?33?gf>t?D?)t?T>׋}?֋M?UR(?VI>g?U[W??>?7?|".?Δ>a?e?>E>̊?/1?33?gf>t?T?)t?T>׋}?֋]?UR(?VI>g?U[g??VR??G?|".?δ>a?u?>"?̊?/A?33?43 ?t?d?)t?*t?׋}?֋m?UR(?VI>g?U[w??VR??W?|".?>a?F̂?>"?̊?/Q?33?43?t?t?)t?*t?׋}?֋}?UR(??g???VR(??g?|".?>a?F̊?>".?̊?/a?33?43+?t?ff?)t?*t"?׋}?ņ?UR(??g???VR8??w?|".?ug +?a?F̒?>">?̊?/q?33?43;?t?ff?)t?*t2?׋}?Ŏ?UR(?(?g???VRH??փ?|".?ug?a?F̚?>"N?̊??33?43K?t?ff?)t?*tB?׋}?Ŗ?UR(?8?g???VRX??֋?|".?ug*?a?F̢?>"^?̊??33+?23ff?23S>)t"?Y/6ņ?Y/v>UR8?Sm]w?>?Sm?>|">?1q?1>vf +?x鎽̒?t>33+?dfff?>)t"?^ņ?>UR8?Smw?>?L?^>|">?,bVq?1>vf +?̒?tG>33+?ff?>)t"?dXņ?>UR8?ںw?>?Z%=?U[>|">?,bq?1>vf +?-b=̒?^>33+?833=ff?>)t"?p +<ņ?>UR8?j뼫w?>?=?U[>|">?XĬq??vf +?=̒?^>33+?=ff?>)t"?N=ņ?>UR8?J +=w?U[??VI!>?U[>|">?`q??vf +?D8>̒?^>33+?,>ff??)t"? >ņ?֋ ?UR8?Z%=w?U[??VIa>?U[>|">?Pw&=q?%?vf +?Dx>̒?^>33+?l>ff??)t"?I>ņ?֋?UR8?">w?U['??>??|">?;=q?5?vf +?E>̒?/?33+?gf>ff?$?)t"?T>ņ?֋-?UR8?b>w?U[7??>??|">?ԝ)>q?E?vf +?E>̒?/?33+?gf>ff?4?)t"?T>ņ?֋=?UR8?VI>w?U[G??>?'?|">?ԝi>q?U?vf +?E>̒?/!?33+?gf>ff?D?)t"?T>ņ?֋M?UR8?VI>w?U[W??>?7?|">?Δ>q?e?vf +?E>̒?/1?33+?gf>ff?T?)t"?T>ņ?֋]?UR8?VI>w?U[g??VR??G?|">?δ>q?u?vf +?"?̒?/A?33+?43 ?ff?d?)t"?*t?ņ?֋m?UR8?VI>w?U[w??VR??W?|">?>q?F̂?vf +?"?̒?/Q?33+?43?ff?t?)t"?*t?ņ?֋}?UR8??w???VR(??g?|">?>q?F̊?vf +?".?̒?/a?33+?43+?ff?ff?)t"?*t"?ņ?ņ?UR8??w???VR8??w?|">?ug +?q?F̒?vf +?">?̒?/q?33+?43;?ff?ff?)t"?*t2?ņ?Ŏ?UR8?(?w???VRH??փ?|">?ug?q?F̚?vf +?"N?̒??33+?43K?ff?ff?)t"?*tB?ņ?Ŗ?UR8?8?w???VRX??֋?|">?ug*?q?F̢?vf +?"^?̒??33;?23ff?23S>)t2?Y/6Ŏ?Y/v>URH?Sm]փ?>(?Sm?>|"N?1?1>vf?x鎽̚?t>33;?dfff?>)t2?^Ŏ?>URH?Smփ?>(?L?^>|"N?,bV?1>vf?̚?tG>33;?ff?>)t2?dXŎ?>URH?ںփ?>(?Z%=?U[>|"N?,b?1>vf?-b=̚?^>33;?833=ff?>)t2?p +<Ŏ?>URH?jփ?>(?=?U[>|"N?XĬ??vf?=̚?^>33;?=ff?>)t2?N=Ŏ?>URH?J +=փ?U[?(?VI!>?U[>|"N?`??vf?D8>̚?^>33;?,>ff??)t2? >Ŏ?֋ ?URH?Z%=փ?U[?(?VIa>?U[>|"N?Pw&=?%?vf?Dx>̚?^>33;?l>ff??)t2?I>Ŏ?֋?URH?">փ?U['?(?>??|"N?;=?5?vf?E>̚?/?33;?gf>ff?$?)t2?T>Ŏ?֋-?URH?b>փ?U[7?(?>??|"N?ԝ)>?E?vf?E>̚?/?33;?gf>ff?4?)t2?T>Ŏ?֋=?URH?VI>փ?U[G?(?>?'?|"N?ԝi>?U?vf?E>̚?/!?33;?gf>ff?D?)t2?T>Ŏ?֋M?URH?VI>փ?U[W?(?>?7?|"N?Δ>?e?vf?E>̚?/1?33;?gf>ff?T?)t2?T>Ŏ?֋]?URH?VI>փ?U[g?(?VR??G?|"N?δ>?u?vf?"?̚?/A?33;?43 ?ff?d?)t2?*t?Ŏ?֋m?URH?VI>փ?U[w?(?VR??W?|"N?>?F̂?vf?"?̚?/Q?33;?43?ff?t?)t2?*t?Ŏ?֋}?URH??փ??(?VR(??g?|"N?>?F̊?vf?".?̚?/a?33;?43+?ff?ff?)t2?*t"?Ŏ?ņ?URH??փ??(?VR8??w?|"N?ug +??F̒?vf?">?̚?/q?33;?43;?ff?ff?)t2?*t2?Ŏ?Ŏ?URH?(?փ??(?VRH??փ?|"N?ug??F̚?vf?"N?̚??33;?43K?ff?ff?)t2?*tB?Ŏ?Ŗ?URH?8?փ??(?VRX??֋?|"N?ug*??F̢?vf?"^?̚??33K?23ff?23S>)tB?Y/6Ŗ?Y/v>URX?Sm]֋?>8?Sm?>|"^?1?1>vf*?x鎽̢?t>33K?dfff?>)tB?^Ŗ?>URX?Sm֋?>8?L?^>|"^?,bV?1>vf*?̢?tG>33K?ff?>)tB?dXŖ?>URX?ں֋?>8?Z%=?U[>|"^?,b?1>vf*?-b=̢?^>33K?833=ff?>)tB?p +<Ŗ?>URX?j֋?>8?=?U[>|"^?XĬ??vf*?=̢?^>33K?=ff?>)tB?N=Ŗ?>URX?J +=֋?U[?8?VI!>?U[>|"^?`??vf*?D8>̢?^>33K?,>ff??)tB? >Ŗ?֋ ?URX?Z%=֋?U[?8?VIa>?U[>|"^?Pw&=?%?vf*?Dx>̢?^>33K?l>ff??)tB?I>Ŗ?֋?URX?">֋?U['?8?>??|"^?;=?5?vf*?E>̢?/?33K?gf>ff?$?)tB?T>Ŗ?֋-?URX?b>֋?U[7?8?>??|"^?ԝ)>?E?vf*?E>̢?/?33K?gf>ff?4?)tB?T>Ŗ?֋=?URX?VI>֋?U[G?8?>?'?|"^?ԝi>?U?vf*?E>̢?/!?33K?gf>ff?D?)tB?T>Ŗ?֋M?URX?VI>֋?U[W?8?>?7?|"^?Δ>?e?vf*?E>̢?/1?33K?gf>ff?T?)tB?T>Ŗ?֋]?URX?VI>֋?U[g?8?VR??G?|"^?δ>?u?vf*?"?̢?/A?33K?43 ?ff?d?)tB?*t?Ŗ?֋m?URX?VI>֋?U[w?8?VR??W?|"^?>?F̂?vf*?"?̢?/Q?33K?43?ff?t?)tB?*t?Ŗ?֋}?URX??֋??8?VR(??g?|"^?>?F̊?vf*?".?̢?/a?33K?43+?ff?ff?)tB?*t"?Ŗ?ņ?URX??֋??8?VR8??w?|"^?ug +??F̒?vf*?">?̢?/q?33K?43;?ff?ff?)tB?*t2?Ŗ?Ŏ?URX?(?֋??8?VRH??փ?|"^?ug??F̚?vf*?"N?̢??33K?43K?ff?ff?)tB?*tB?Ŗ?Ŗ?URX?8?֋??8?VRX??֋?|"^?ug*??F̢?vf*?"^?̢??@?>>ccF>D> u>> >u>t׳:S>׳>>VS>@>>cǽF>D> *u>y +?/<>y>tg{:S>?0=>>@=>?c? 꽐'(u>y*? +>>y>t\:S>>?4,>>>@@>>0?cx>F>8? 8=u>yJ?}>>^?U>>?@>>P?c>F>X? U>u>yj?}>>:S>~?U>>4?@>>p?c>F>x? >u>:S>l?* ?>T?@?>?c^?F>Q|? >u>:S>l?* +?>t?@0?>?c^'?F>Q|? 꽇}?u>?t&?:S>l?* K?>ky??>>ǽcF>D>/<z>> * z +?u>0=׳>׳>\m{W?VS>>>ǽǽF>D>/< *z>y +? */0=g{>?\m{0=W?>=>?ǽ?/<'(z>y*? * +>z +?y>0=\>>?\m{4,>W?>@>>0?ǽx>F>8?/<8=z>yJ? *}>z +?^?\m{U>W??>>P?ǽ>F>X?/<U>z>yj? *}>z +?>~?\m{U>W?4?>>p?ǽ>F>x?/<>z>>l?\m{* ?W?T??>?ǽ^?F>Q|?/<>z>>l?\m{* +?W?t?0?>?ǽ^'?F>Q|?/<}?z>l?\m{* K?W?ky?=??> +>z>>'( z*?u>2,>׳>׳>W>?VS>=?><ǽ?D> +> *z>y +?'(/2,>g{>?0=W>?>==??<<?? +>'(z>y*?'( +>z*?y>2,>\>>?4,>W>?>=@>?0??8? +>8=z>yJ?'(}>z*?@ +;>^?U>W>??=>?P?<>?X? +>U>z>yj?'(}>z*?R>>~?U>W>?4?=>?p?<>?x? +>>z>)L>>l?* ?W>?T?=???<^??Q|? +>>z>)L>>l?* +?W>?t?=0???<^'??Q|? +>}?z>&?>l?* K?W>?ky??>?0?>t>c8?D>}>=A?>0= zJ?u>c>׳N?׳>T;W^?VS>?>0?>t>ǽ8?D>}> *=A?y +?0=/c>g{N??T;0=W^?>?>=0??t><8??}>'(=A?y*?0= +>zJ?y>c>\N?>?T;4,>W^?>?>@>0?0?t>x>8?8?}>8==A?yJ?0=}>zJ?@ +;N?^?T;U>W^???>>0?P?t>>8?X?}>U>=A?yj?0=}>zJ?R>N?~?T;U>W^?4??>>0?p?t>>8?x?}>>=A?)L>N?l?T;* ?W^?T??>?0??t>^?8?Q|?}>>=A?)L>N?l?T;* +?W^?t??>0?0??t>^'?8?Q|?}>}?=A?&?N?l?T;* K?W^?ky?>?P?>>cX?D>}>=A=?>U> zj?u>c>׳N4?׳>>W~?VS>>P?>>ǽX?D>}> *=A=?y +?U>/c>g{N4??>0=W~?>>=P??>'(=A=?y*?U> +>zj?y>c>\N4?>?>4,>W~?>>@>P?0?>x>X?8?}>8==A=?yJ?U>}>zj?@ +;N4?^?>U>W~??>>P?P?>>X?X?}>U>=A=?yj?U>}>zj?R>N4?~?>U>W~?4?>>P?p?>>X?x?}>>=A=?ľ?zj?)L>N4?l?>* ?W~?T?>?P??>^?X?Q|?}>>=A=?ľ"?zj?)L>N4?l?>* +?W~?t?>0?P??>^'?X?Q|?}>}?=A=?ľB?zj??c>&?N4?l?>* K?W~?ky?>?p?>>cx?D>þ?=A]?> > =A?u> ?׳NT?׳>RI>m?VS>>p?>>ǽx?D>þ? *=A]?y +? >/<=A?y> ?g{NT??RI>0=m?>>=p??> +>=A?y> ?\NT?>?RI>4,>m?>>@>p?0?>x>x?8?þ?8==A]?yJ? >}>=A?U>m??>>p?P?>>x?X?þ?U>=A]?yj? >}>=A?NT?~?RI>U>m?4?>>p?p?>>x?x?þ?>=A]?ľ?=A?NT?l?RI>* ?m?T?>?p??>^?x?Q|?þ?>=A]?ľ"?=A?NT?l?RI>* +?m?t?>0?p??>^'?x?Q|?þ?}?=A]?ľB?=A?? ?&?NT?l?RI>* K?m?ky????>]?cR|?D>þ"?=A}?> > =A?u> +?׳Nt?׳>RI>m?VS>??>]?ǽR|?D>þ"? *=A}?y +? >/<=A?y> +?g{Nt??RI>0=m?>?=??]? +>=A?y> +?\Nt?>?RI>4,>m?>?@>?0?]?x>R|?8?þ"?8==A}?yJ? >}>=A?U>m???>?P?]?>R|?X?þ"?U>=A}?yj? >}>=A?Nt?~?RI>U>m?4??>?p?]?>R|?x?þ"?>=A}?ľ?=A?Nt?l?RI>* ?m?T?????]?^?R|?Q|?þ"?>=A}?ľ"?=A?Nt?l?RI>* +?m?t??0???]?^'?R|?Q|?þ"?}?=A}?ľB?=A?? +?&?Nt?l?RI>* K?m?ky?0???>]'?cR|?D>þB??>}? =A?u> K?׳y?׳>$?m?VS>0??>]'?ǽR|?D>þB? *?y +?}?/<=A?y> K?g{y??$?0=m?>0?=??]'?=A?y> K?\y?>?$?4,>m?>0?@>?0?]'?x>R|?8?þB?8=?yJ?}?}>=A?m??0?>?P?]'?>R|?X?þB?U>?yj?}?}>=A?y?~?$?U>m?4?0?>?p?]'?>R|?x?þB?>?y?l?$?* ?m?T?0????]'?^?R|?Q|?þB?>?y?l?$?* +?m?t?0?0???]'?^'?R|?Q|?þB?}??ef>^5qZ5q>>zֽ:S>?=Stֽ?>H62>K0?H:C$0?>LL=gf>233?^5q`l<>VMU?=SƬ>??H,m@2>Kp?H:?>$0?|?L>gf>23s?^5qSe>>VM|?zֽY)>>Ԋ?=ScV>?Z?HPK~=2> ?H:>$0?|P?L ?gf>?^5q?>&?zֽƬ>>Ԫ?=S2+%??gj?Hjɟ>2> ?H:྄/?$0?>?L=L433?ef> lì>:S??LtֽU?>?>6 ?K0?t@C$p?>L=L=433?233? l<`lL?U?LƬ>U???>,m@ ?Kp?t@?>$p?|?L=>433?23s? lXMY)>?Ԋ?LcV>U?Z??>PK~= ? ?t@>$p?|P?L= ?433?? l<?XMƬ>?Ԫ?L2+%?U?gj??>jɟ> ? ?t@/?$p?>?>L43s?ef>Qe>Z5qXM|?>bV>:SZ??Y)>tֽԊ?>>6 P?K0?-~=C?>>L=43s?233?Qe>`lLZ?U?Y)>Ƭ>Ԋ??>,m@ P?Kp?-~=?>?|?>>43s?23s?Qe>Se>XM|?VM|?bV>Y)>Z?Ԋ?Y)>cV>Ԋ?Z?>PK~= P? ?-~=>?|P?> ?43s??Qe>?XM|?&?bV>Ƭ>Z?Ԫ?Y)>2+%?Ԋ?gj?>jɟ> P? ?-~=/??>? ?L?ef>?Z5q&?>1+%?:Shj??ì>tֽԪ?>/?6ྍ?K0?ş>C?> ?L=?233??`l<&?VMƬ>Ԫ??/?,m@?Kp?ş>?>?|? ?>?23s??Se>&?VM|?1+%?Y)>hj?Ԋ?ì>cV>Ԫ?Z?/?PK~=? ?ş>>?|P? ? ?????&?&?1+%?Ƭ>hj?Ԫ?ì>2+%?Ԫ?gj?/?jɟ>? ?ş>/??>?gf&?ff&?Y>Y>|/?z/? bh?P?P?ah?x#\q?⾰;<^q?E<>43>gf&?33?Y> Ӡ>|/?=˗? <>bh?ah?>/>P?04?x#<@5j==>V??^q?"{?23>43?ff&? Ӡ>Y>>˗?z/?14?P?<>bh?ah??X{?\q?j=;23>43>43?33? Ӡ> Ӡ>>˗?=˗?<>14?ah?<>>/>bh?04??@5j={?V?j=?x?"{?</U??/4(>?U?D-g><4F?O?|A0g>_P?3F? \ No newline at end of file diff --git a/src/server/public/models/ssd_mobilenetv1_model-weights_manifest.json b/src/server/public/models/ssd_mobilenetv1_model-weights_manifest.json new file mode 100644 index 000000000..204e0d13c --- /dev/null +++ b/src/server/public/models/ssd_mobilenetv1_model-weights_manifest.json @@ -0,0 +1 @@ +[{"paths":["ssd_mobilenetv1_model-shard1","ssd_mobilenetv1_model-shard2"],"weights":[{"dtype":"float32","shape":[1,1,512,9],"quantization":{"scale":0.0026856216729856004,"min":-0.34107395246917127,"dtype":"uint8"},"name":"Prediction/BoxPredictor_0/ClassPredictor/weights"},{"dtype":"float32","shape":[9],"quantization":{"scale":0.00198518248165355,"min":-0.32159956202787515,"dtype":"uint8"},"name":"Prediction/BoxPredictor_0/ClassPredictor/biases"},{"dtype":"float32","shape":[1,1,1024,18],"quantization":{"scale":0.003060340296988394,"min":-0.489654447518143,"dtype":"uint8"},"name":"Prediction/BoxPredictor_1/ClassPredictor/weights"},{"dtype":"float32","shape":[18],"quantization":{"scale":0.0008040678851744708,"min":-0.12221831854651957,"dtype":"uint8"},"name":"Prediction/BoxPredictor_1/ClassPredictor/biases"},{"dtype":"float32","shape":[1,1,512,18],"quantization":{"scale":0.0012513800578958848,"min":-0.16017664741067325,"dtype":"uint8"},"name":"Prediction/BoxPredictor_2/ClassPredictor/weights"},{"dtype":"float32","shape":[18],"quantization":{"scale":0.000338070518245884,"min":-0.05510549447407909,"dtype":"uint8"},"name":"Prediction/BoxPredictor_2/ClassPredictor/biases"},{"dtype":"float32","shape":[1,1,256,18],"quantization":{"scale":0.0011819932975021064,"min":-0.1453851755927591,"dtype":"uint8"},"name":"Prediction/BoxPredictor_3/ClassPredictor/weights"},{"dtype":"float32","shape":[18],"quantization":{"scale":0.00015985782386041154,"min":-0.026536398760828316,"dtype":"uint8"},"name":"Prediction/BoxPredictor_3/ClassPredictor/biases"},{"dtype":"float32","shape":[1,1,256,18],"quantization":{"scale":0.0007035591438704846,"min":-0.08513065640832863,"dtype":"uint8"},"name":"Prediction/BoxPredictor_4/ClassPredictor/weights"},{"dtype":"float32","shape":[18],"quantization":{"scale":0.00008793946574716008,"min":-0.013190919862074012,"dtype":"uint8"},"name":"Prediction/BoxPredictor_4/ClassPredictor/biases"},{"dtype":"float32","shape":[1,1,128,18],"quantization":{"scale":0.00081320781918133,"min":-0.11059626340866088,"dtype":"uint8"},"name":"Prediction/BoxPredictor_5/ClassPredictor/weights"},{"dtype":"float32","shape":[18],"quantization":{"scale":0.0000980533805547976,"min":-0.014609953702664841,"dtype":"uint8"},"name":"Prediction/BoxPredictor_5/ClassPredictor/biases"},{"dtype":"int32","shape":[],"quantization":{"scale":1,"min":3,"dtype":"uint8"},"name":"Prediction/BoxPredictor_0/stack_1/2"},{"dtype":"int32","shape":[3],"quantization":{"scale":0.00392156862745098,"min":0,"dtype":"uint8"},"name":"Postprocessor/Slice/begin"},{"dtype":"int32","shape":[3],"quantization":{"scale":1,"min":-1,"dtype":"uint8"},"name":"Postprocessor/Slice/size"},{"dtype":"float32","shape":[1,1,512,12],"quantization":{"scale":0.003730384859384275,"min":-0.4327246436885759,"dtype":"uint8"},"name":"Prediction/BoxPredictor_0/BoxEncodingPredictor/weights"},{"dtype":"float32","shape":[12],"quantization":{"scale":0.0018744708568442102,"min":-0.3917644090804399,"dtype":"uint8"},"name":"Prediction/BoxPredictor_0/BoxEncodingPredictor/biases"},{"dtype":"int32","shape":[],"quantization":{"scale":1,"min":3072,"dtype":"uint8"},"name":"Prediction/BoxPredictor_0/stack_1/1"},{"dtype":"float32","shape":[1,1,1024,24],"quantization":{"scale":0.00157488017689948,"min":-0.20000978246623397,"dtype":"uint8"},"name":"Prediction/BoxPredictor_1/BoxEncodingPredictor/weights"},{"dtype":"float32","shape":[24],"quantization":{"scale":0.0002823906713256649,"min":-0.043488163384152394,"dtype":"uint8"},"name":"Prediction/BoxPredictor_1/BoxEncodingPredictor/biases"},{"dtype":"int32","shape":[],"quantization":{"scale":1,"min":1536,"dtype":"uint8"},"name":"Prediction/BoxPredictor_1/stack_1/1"},{"dtype":"float32","shape":[1,1,512,24],"quantization":{"scale":0.0007974451663447361,"min":-0.11004743295557358,"dtype":"uint8"},"name":"Prediction/BoxPredictor_2/BoxEncodingPredictor/weights"},{"dtype":"float32","shape":[24],"quantization":{"scale":0.0001350417988849621,"min":-0.02039131163162928,"dtype":"uint8"},"name":"Prediction/BoxPredictor_2/BoxEncodingPredictor/biases"},{"dtype":"int32","shape":[],"quantization":{"scale":1,"min":384,"dtype":"uint8"},"name":"Prediction/BoxPredictor_2/stack_1/1"},{"dtype":"float32","shape":[1,1,256,24],"quantization":{"scale":0.0007113990246080885,"min":-0.0860792819775787,"dtype":"uint8"},"name":"Prediction/BoxPredictor_3/BoxEncodingPredictor/weights"},{"dtype":"float32","shape":[24],"quantization":{"scale":0.000050115815418608046,"min":-0.007617603943628423,"dtype":"uint8"},"name":"Prediction/BoxPredictor_3/BoxEncodingPredictor/biases"},{"dtype":"int32","shape":[],"quantization":{"scale":1,"min":96,"dtype":"uint8"},"name":"Prediction/BoxPredictor_3/stack_1/1"},{"dtype":"float32","shape":[1,1,256,24],"quantization":{"scale":0.000590049314732645,"min":-0.06903576982371946,"dtype":"uint8"},"name":"Prediction/BoxPredictor_4/BoxEncodingPredictor/weights"},{"dtype":"float32","shape":[24],"quantization":{"scale":0.00003513663861097074,"min":-0.006359731588585704,"dtype":"uint8"},"name":"Prediction/BoxPredictor_4/BoxEncodingPredictor/biases"},{"dtype":"int32","shape":[],"quantization":{"scale":1,"min":24,"dtype":"uint8"},"name":"Prediction/BoxPredictor_4/stack_1/1"},{"dtype":"float32","shape":[1,1,128,24],"quantization":{"scale":0.0005990567744946948,"min":-0.07907549423329971,"dtype":"uint8"},"name":"Prediction/BoxPredictor_5/BoxEncodingPredictor/weights"},{"dtype":"float32","shape":[24],"quantization":{"scale":0.00003392884288640583,"min":-0.006039334033780238,"dtype":"uint8"},"name":"Prediction/BoxPredictor_5/BoxEncodingPredictor/biases"},{"dtype":"float32","shape":[],"quantization":{"scale":1,"min":0.007843137718737125,"dtype":"uint8"},"name":"Preprocessor/mul/x"},{"dtype":"int32","shape":[2],"quantization":{"scale":1,"min":512,"dtype":"uint8"},"name":"Preprocessor/ResizeImage/size"},{"dtype":"float32","shape":[],"quantization":{"scale":1,"min":1,"dtype":"uint8"},"name":"Preprocessor/sub/y"},{"dtype":"float32","shape":[3,3,3,32],"quantization":{"scale":0.03948551065781537,"min":-5.014659853542552,"dtype":"uint8"},"name":"MobilenetV1/Conv2d_0_pointwise/weights"},{"dtype":"float32","shape":[32],"quantization":{"scale":0.0498106133704092,"min":-7.371970778820562,"dtype":"uint8"},"name":"MobilenetV1/Conv2d_0_pointwise/convolution_bn_offset"},{"dtype":"float32","shape":[3,3,32,1],"quantization":{"scale":0.036833542468501075,"min":-4.714693435968138,"dtype":"uint8"},"name":"MobilenetV1/Conv2d_1_depthwise/depthwise_weights"},{"dtype":"float32","shape":[32],"quantization":{"scale":0.012173276705046495,"min":-0.012173276705046495,"dtype":"uint8"},"name":"MobilenetV1/Conv2d_1_depthwise/BatchNorm/gamma"},{"dtype":"float32","shape":[32],"quantization":{"scale":0.032182769214405736,"min":-2.4780732295092416,"dtype":"uint8"},"name":"MobilenetV1/Conv2d_1_depthwise/BatchNorm/beta"},{"dtype":"float32","shape":[32],"quantization":{"scale":0.028287527607936486,"min":-3.366215785344442,"dtype":"uint8"},"name":"MobilenetV1/Conv2d_1_depthwise/BatchNorm/moving_mean"},{"dtype":"float32","shape":[32],"quantization":{"scale":0.04716738532571232,"min":3.9071404665769224e-36,"dtype":"uint8"},"name":"MobilenetV1/Conv2d_1_depthwise/BatchNorm/moving_variance"},{"dtype":"float32","shape":[1,1,32,64],"quantization":{"scale":0.04010109433940812,"min":-4.290817094316669,"dtype":"uint8"},"name":"MobilenetV1/Conv2d_1_pointwise/weights"},{"dtype":"float32","shape":[64],"quantization":{"scale":0.2212210038129021,"min":-34.51047659481273,"dtype":"uint8"},"name":"MobilenetV1/Conv2d_1_pointwise/convolution_bn_offset"},{"dtype":"float32","shape":[3,3,64,1],"quantization":{"scale":0.010024750933927648,"min":-1.343316625146305,"dtype":"uint8"},"name":"MobilenetV1/Conv2d_2_depthwise/depthwise_weights"},{"dtype":"float32","shape":[64],"quantization":{"scale":0.006120916675118839,"min":0.5227176547050476,"dtype":"uint8"},"name":"MobilenetV1/Conv2d_2_depthwise/BatchNorm/gamma"},{"dtype":"float32","shape":[64],"quantization":{"scale":0.02317035385206634,"min":-0.7646216771181892,"dtype":"uint8"},"name":"MobilenetV1/Conv2d_2_depthwise/BatchNorm/beta"},{"dtype":"float32","shape":[64],"quantization":{"scale":0.04980821422502106,"min":-5.8275610643274645,"dtype":"uint8"},"name":"MobilenetV1/Conv2d_2_depthwise/BatchNorm/moving_mean"},{"dtype":"float32","shape":[64],"quantization":{"scale":0.051751047022202436,"min":3.916113799002297e-36,"dtype":"uint8"},"name":"MobilenetV1/Conv2d_2_depthwise/BatchNorm/moving_variance"},{"dtype":"float32","shape":[1,1,64,128],"quantization":{"scale":0.021979344124887504,"min":-2.1319963801140878,"dtype":"uint8"},"name":"MobilenetV1/Conv2d_2_pointwise/weights"},{"dtype":"float32","shape":[128],"quantization":{"scale":0.09958663267247816,"min":-11.054116226645077,"dtype":"uint8"},"name":"MobilenetV1/Conv2d_2_pointwise/convolution_bn_offset"},{"dtype":"float32","shape":[3,3,128,1],"quantization":{"scale":0.01943492702409333,"min":-2.6237151482525993,"dtype":"uint8"},"name":"MobilenetV1/Conv2d_3_depthwise/depthwise_weights"},{"dtype":"float32","shape":[128],"quantization":{"scale":0.017852897737540452,"min":0.40204083919525146,"dtype":"uint8"},"name":"MobilenetV1/Conv2d_3_depthwise/BatchNorm/gamma"},{"dtype":"float32","shape":[128],"quantization":{"scale":0.029888209174661076,"min":-1.972621805527631,"dtype":"uint8"},"name":"MobilenetV1/Conv2d_3_depthwise/BatchNorm/beta"},{"dtype":"float32","shape":[128],"quantization":{"scale":0.029319268581913967,"min":-5.130872001834945,"dtype":"uint8"},"name":"MobilenetV1/Conv2d_3_depthwise/BatchNorm/moving_mean"},{"dtype":"float32","shape":[128],"quantization":{"scale":0.014018708584355373,"min":3.9083178263362604e-36,"dtype":"uint8"},"name":"MobilenetV1/Conv2d_3_depthwise/BatchNorm/moving_variance"},{"dtype":"float32","shape":[1,1,128,128],"quantization":{"scale":0.020776657964669022,"min":-2.5347522716896207,"dtype":"uint8"},"name":"MobilenetV1/Conv2d_3_pointwise/weights"},{"dtype":"float32","shape":[128],"quantization":{"scale":0.14383157094319662,"min":-9.636715253194174,"dtype":"uint8"},"name":"MobilenetV1/Conv2d_3_pointwise/convolution_bn_offset"},{"dtype":"float32","shape":[3,3,128,1],"quantization":{"scale":0.004463558571011412,"min":-0.5981168485155293,"dtype":"uint8"},"name":"MobilenetV1/Conv2d_4_depthwise/depthwise_weights"},{"dtype":"float32","shape":[128],"quantization":{"scale":0.006487431245691636,"min":0.47910428047180176,"dtype":"uint8"},"name":"MobilenetV1/Conv2d_4_depthwise/BatchNorm/gamma"},{"dtype":"float32","shape":[128],"quantization":{"scale":0.026542164297664865,"min":-1.2209395576925839,"dtype":"uint8"},"name":"MobilenetV1/Conv2d_4_depthwise/BatchNorm/beta"},{"dtype":"float32","shape":[128],"quantization":{"scale":0.05119945675719018,"min":-8.60150873520795,"dtype":"uint8"},"name":"MobilenetV1/Conv2d_4_depthwise/BatchNorm/moving_mean"},{"dtype":"float32","shape":[128],"quantization":{"scale":0.03081628388049556,"min":3.911508751095344e-36,"dtype":"uint8"},"name":"MobilenetV1/Conv2d_4_depthwise/BatchNorm/moving_variance"},{"dtype":"float32","shape":[1,1,128,256],"quantization":{"scale":0.010758659886378868,"min":-1.0328313490923713,"dtype":"uint8"},"name":"MobilenetV1/Conv2d_4_pointwise/weights"},{"dtype":"float32","shape":[256],"quantization":{"scale":0.08058219610476026,"min":-9.34753474815219,"dtype":"uint8"},"name":"MobilenetV1/Conv2d_4_pointwise/convolution_bn_offset"},{"dtype":"float32","shape":[3,3,256,1],"quantization":{"scale":0.01145936741548426,"min":-1.3292866201961742,"dtype":"uint8"},"name":"MobilenetV1/Conv2d_5_depthwise/depthwise_weights"},{"dtype":"float32","shape":[256],"quantization":{"scale":0.0083988838336047,"min":0.36280909180641174,"dtype":"uint8"},"name":"MobilenetV1/Conv2d_5_depthwise/BatchNorm/gamma"},{"dtype":"float32","shape":[256],"quantization":{"scale":0.02858148649627087,"min":-3.6584302715226715,"dtype":"uint8"},"name":"MobilenetV1/Conv2d_5_depthwise/BatchNorm/beta"},{"dtype":"float32","shape":[256],"quantization":{"scale":0.03988401375564874,"min":-7.099354448505476,"dtype":"uint8"},"name":"MobilenetV1/Conv2d_5_depthwise/BatchNorm/moving_mean"},{"dtype":"float32","shape":[256],"quantization":{"scale":0.009090481683904049,"min":0.020878996700048447,"dtype":"uint8"},"name":"MobilenetV1/Conv2d_5_depthwise/BatchNorm/moving_variance"},{"dtype":"float32","shape":[1,1,256,256],"quantization":{"scale":0.008951201625898773,"min":-1.1189002032373465,"dtype":"uint8"},"name":"MobilenetV1/Conv2d_5_pointwise/weights"},{"dtype":"float32","shape":[256],"quantization":{"scale":0.051758006974762565,"min":-5.745138774198645,"dtype":"uint8"},"name":"MobilenetV1/Conv2d_5_pointwise/convolution_bn_offset"},{"dtype":"float32","shape":[3,3,256,1],"quantization":{"scale":0.004110433190476661,"min":-0.6042336790000691,"dtype":"uint8"},"name":"MobilenetV1/Conv2d_6_depthwise/depthwise_weights"},{"dtype":"float32","shape":[256],"quantization":{"scale":0.013170199768216002,"min":0.3386639356613159,"dtype":"uint8"},"name":"MobilenetV1/Conv2d_6_depthwise/BatchNorm/gamma"},{"dtype":"float32","shape":[256],"quantization":{"scale":0.03599378548416437,"min":-3.70735990486893,"dtype":"uint8"},"name":"MobilenetV1/Conv2d_6_depthwise/BatchNorm/beta"},{"dtype":"float32","shape":[256],"quantization":{"scale":0.026967673208199296,"min":-3.748506575939702,"dtype":"uint8"},"name":"MobilenetV1/Conv2d_6_depthwise/BatchNorm/moving_mean"},{"dtype":"float32","shape":[256],"quantization":{"scale":0.012615410486857097,"min":3.9111388979838637e-36,"dtype":"uint8"},"name":"MobilenetV1/Conv2d_6_depthwise/BatchNorm/moving_variance"},{"dtype":"float32","shape":[1,1,256,512],"quantization":{"scale":0.00822840648538926,"min":-1.1848905338960536,"dtype":"uint8"},"name":"MobilenetV1/Conv2d_6_pointwise/weights"},{"dtype":"float32","shape":[512],"quantization":{"scale":0.06608965817619772,"min":-7.468131373910342,"dtype":"uint8"},"name":"MobilenetV1/Conv2d_6_pointwise/convolution_bn_offset"},{"dtype":"float32","shape":[3,3,512,1],"quantization":{"scale":0.008801074355256323,"min":-0.9593171047229393,"dtype":"uint8"},"name":"MobilenetV1/Conv2d_7_depthwise/depthwise_weights"},{"dtype":"float32","shape":[512],"quantization":{"scale":0.030577416513480393,"min":0.3285980224609375,"dtype":"uint8"},"name":"MobilenetV1/Conv2d_7_depthwise/BatchNorm/gamma"},{"dtype":"float32","shape":[512],"quantization":{"scale":0.04778536441279393,"min":-8.935863145192464,"dtype":"uint8"},"name":"MobilenetV1/Conv2d_7_depthwise/BatchNorm/beta"},{"dtype":"float32","shape":[512],"quantization":{"scale":0.04331884945140165,"min":-9.660103427662568,"dtype":"uint8"},"name":"MobilenetV1/Conv2d_7_depthwise/BatchNorm/moving_mean"},{"dtype":"float32","shape":[512],"quantization":{"scale":0.04126455444367785,"min":0.000604183878749609,"dtype":"uint8"},"name":"MobilenetV1/Conv2d_7_depthwise/BatchNorm/moving_variance"},{"dtype":"float32","shape":[1,1,512,512],"quantization":{"scale":0.009305818408143287,"min":-1.1446156642016243,"dtype":"uint8"},"name":"MobilenetV1/Conv2d_7_pointwise/weights"},{"dtype":"float32","shape":[512],"quantization":{"scale":0.04640720217835669,"min":-4.733534622192383,"dtype":"uint8"},"name":"MobilenetV1/Conv2d_7_pointwise/convolution_bn_offset"},{"dtype":"float32","shape":[3,3,512,1],"quantization":{"scale":0.008138792655047248,"min":-0.9766551186056698,"dtype":"uint8"},"name":"MobilenetV1/Conv2d_8_depthwise/depthwise_weights"},{"dtype":"float32","shape":[512],"quantization":{"scale":0.027351748358969596,"min":0.34030041098594666,"dtype":"uint8"},"name":"MobilenetV1/Conv2d_8_depthwise/BatchNorm/gamma"},{"dtype":"float32","shape":[512],"quantization":{"scale":0.04415061053107767,"min":-7.019947074441349,"dtype":"uint8"},"name":"MobilenetV1/Conv2d_8_depthwise/BatchNorm/beta"},{"dtype":"float32","shape":[512],"quantization":{"scale":0.02476683784933651,"min":-2.9224868662217083,"dtype":"uint8"},"name":"MobilenetV1/Conv2d_8_depthwise/BatchNorm/moving_mean"},{"dtype":"float32","shape":[512],"quantization":{"scale":0.02547598832684076,"min":0.00026032101595774293,"dtype":"uint8"},"name":"MobilenetV1/Conv2d_8_depthwise/BatchNorm/moving_variance"},{"dtype":"float32","shape":[1,1,512,512],"quantization":{"scale":0.01083052625843123,"min":-1.2563410459780227,"dtype":"uint8"},"name":"MobilenetV1/Conv2d_8_pointwise/weights"},{"dtype":"float32","shape":[512],"quantization":{"scale":0.06360894371481503,"min":-7.951117964351878,"dtype":"uint8"},"name":"MobilenetV1/Conv2d_8_pointwise/convolution_bn_offset"},{"dtype":"float32","shape":[3,3,512,1],"quantization":{"scale":0.006704086883395326,"min":-0.8648272079579971,"dtype":"uint8"},"name":"MobilenetV1/Conv2d_9_depthwise/depthwise_weights"},{"dtype":"float32","shape":[512],"quantization":{"scale":0.015343831567203297,"min":0.2711026668548584,"dtype":"uint8"},"name":"MobilenetV1/Conv2d_9_depthwise/BatchNorm/gamma"},{"dtype":"float32","shape":[512],"quantization":{"scale":0.03378283930759804,"min":-4.797163181678922,"dtype":"uint8"},"name":"MobilenetV1/Conv2d_9_depthwise/BatchNorm/beta"},{"dtype":"float32","shape":[512],"quantization":{"scale":0.021910778213949763,"min":-3.987761634938857,"dtype":"uint8"},"name":"MobilenetV1/Conv2d_9_depthwise/BatchNorm/moving_mean"},{"dtype":"float32","shape":[512],"quantization":{"scale":0.009284070410007296,"min":0.000021581046894425526,"dtype":"uint8"},"name":"MobilenetV1/Conv2d_9_depthwise/BatchNorm/moving_variance"},{"dtype":"float32","shape":[1,1,512,512],"quantization":{"scale":0.012783036979974485,"min":-1.9046725100161983,"dtype":"uint8"},"name":"MobilenetV1/Conv2d_9_pointwise/weights"},{"dtype":"float32","shape":[512],"quantization":{"scale":0.07273082733154297,"min":-9.52773838043213,"dtype":"uint8"},"name":"MobilenetV1/Conv2d_9_pointwise/convolution_bn_offset"},{"dtype":"float32","shape":[3,3,512,1],"quantization":{"scale":0.006126228033327589,"min":-0.7351473639993107,"dtype":"uint8"},"name":"MobilenetV1/Conv2d_10_depthwise/depthwise_weights"},{"dtype":"float32","shape":[512],"quantization":{"scale":0.029703759212119908,"min":0.28687000274658203,"dtype":"uint8"},"name":"MobilenetV1/Conv2d_10_depthwise/BatchNorm/gamma"},{"dtype":"float32","shape":[512],"quantization":{"scale":0.04394429898729511,"min":-6.3279790541704966,"dtype":"uint8"},"name":"MobilenetV1/Conv2d_10_depthwise/BatchNorm/beta"},{"dtype":"float32","shape":[512],"quantization":{"scale":0.016566915605582443,"min":-2.7501079905266854,"dtype":"uint8"},"name":"MobilenetV1/Conv2d_10_depthwise/BatchNorm/moving_mean"},{"dtype":"float32","shape":[512],"quantization":{"scale":0.012152872833551145,"min":3.913338286370366e-36,"dtype":"uint8"},"name":"MobilenetV1/Conv2d_10_depthwise/BatchNorm/moving_variance"},{"dtype":"float32","shape":[1,1,512,512],"quantization":{"scale":0.01354524388032801,"min":-1.7473364605623134,"dtype":"uint8"},"name":"MobilenetV1/Conv2d_10_pointwise/weights"},{"dtype":"float32","shape":[512],"quantization":{"scale":0.08566816367355047,"min":-9.937506986131854,"dtype":"uint8"},"name":"MobilenetV1/Conv2d_10_pointwise/convolution_bn_offset"},{"dtype":"float32","shape":[3,3,512,1],"quantization":{"scale":0.006012305558896532,"min":-0.7876120282154457,"dtype":"uint8"},"name":"MobilenetV1/Conv2d_11_depthwise/depthwise_weights"},{"dtype":"float32","shape":[512],"quantization":{"scale":0.01469323155926723,"min":0.29223933815956116,"dtype":"uint8"},"name":"MobilenetV1/Conv2d_11_depthwise/BatchNorm/gamma"},{"dtype":"float32","shape":[512],"quantization":{"scale":0.030889174517463234,"min":-3.2433633243336395,"dtype":"uint8"},"name":"MobilenetV1/Conv2d_11_depthwise/BatchNorm/beta"},{"dtype":"float32","shape":[512],"quantization":{"scale":0.014836942448335536,"min":-2.047498057870304,"dtype":"uint8"},"name":"MobilenetV1/Conv2d_11_depthwise/BatchNorm/moving_mean"},{"dtype":"float32","shape":[512],"quantization":{"scale":0.007234466105343445,"min":0.00013165915152058005,"dtype":"uint8"},"name":"MobilenetV1/Conv2d_11_depthwise/BatchNorm/moving_variance"},{"dtype":"float32","shape":[1,1,512,512],"quantization":{"scale":0.016261722527298274,"min":-1.4798167499841428,"dtype":"uint8"},"name":"MobilenetV1/Conv2d_11_pointwise/weights"},{"dtype":"float32","shape":[512],"quantization":{"scale":0.091437328563017,"min":-14.172785927267636,"dtype":"uint8"},"name":"MobilenetV1/Conv2d_11_pointwise/convolution_bn_offset"},{"dtype":"float32","shape":[3,3,512,1],"quantization":{"scale":0.004750356487199372,"min":-0.650798838746314,"dtype":"uint8"},"name":"MobilenetV1/Conv2d_12_depthwise/depthwise_weights"},{"dtype":"float32","shape":[512],"quantization":{"scale":0.008174965545242907,"min":0.3120670020580292,"dtype":"uint8"},"name":"MobilenetV1/Conv2d_12_depthwise/BatchNorm/gamma"},{"dtype":"float32","shape":[512],"quantization":{"scale":0.030133422215779623,"min":-2.41067377726237,"dtype":"uint8"},"name":"MobilenetV1/Conv2d_12_depthwise/BatchNorm/beta"},{"dtype":"float32","shape":[512],"quantization":{"scale":0.006088157261119169,"min":-0.7853722866843729,"dtype":"uint8"},"name":"MobilenetV1/Conv2d_12_depthwise/BatchNorm/moving_mean"},{"dtype":"float32","shape":[512],"quantization":{"scale":0.003668997334498985,"min":3.9124486300013356e-36,"dtype":"uint8"},"name":"MobilenetV1/Conv2d_12_depthwise/BatchNorm/moving_variance"},{"dtype":"float32","shape":[1,1,512,1024],"quantization":{"scale":0.010959514449624454,"min":-1.4028178495519301,"dtype":"uint8"},"name":"MobilenetV1/Conv2d_12_pointwise/weights"},{"dtype":"float32","shape":[1024],"quantization":{"scale":0.10896045834410424,"min":-14.818622334798176,"dtype":"uint8"},"name":"MobilenetV1/Conv2d_12_pointwise/convolution_bn_offset"},{"dtype":"float32","shape":[3,3,1024,1],"quantization":{"scale":0.004633033509347953,"min":-0.5652300881404502,"dtype":"uint8"},"name":"MobilenetV1/Conv2d_13_depthwise/depthwise_weights"},{"dtype":"float32","shape":[1024],"quantization":{"scale":0.022285057224479377,"min":0.23505790531635284,"dtype":"uint8"},"name":"MobilenetV1/Conv2d_13_depthwise/BatchNorm/gamma"},{"dtype":"float32","shape":[1024],"quantization":{"scale":0.0324854850769043,"min":-3.9957146644592285,"dtype":"uint8"},"name":"MobilenetV1/Conv2d_13_depthwise/BatchNorm/beta"},{"dtype":"float32","shape":[1024],"quantization":{"scale":0.014760061806323482,"min":-2.125448900110581,"dtype":"uint8"},"name":"MobilenetV1/Conv2d_13_depthwise/BatchNorm/moving_mean"},{"dtype":"float32","shape":[1024],"quantization":{"scale":0.0036057423142825855,"min":3.9067056828997994e-36,"dtype":"uint8"},"name":"MobilenetV1/Conv2d_13_depthwise/BatchNorm/moving_variance"},{"dtype":"float32","shape":[1,1,1024,1024],"quantization":{"scale":0.017311988157384536,"min":-2.094750567043529,"dtype":"uint8"},"name":"MobilenetV1/Conv2d_13_pointwise/weights"},{"dtype":"float32","shape":[1024],"quantization":{"scale":0.16447528764313343,"min":-25.658144872328815,"dtype":"uint8"},"name":"MobilenetV1/Conv2d_13_pointwise/convolution_bn_offset"},{"dtype":"float32","shape":[1,1,1024,256],"quantization":{"scale":0.0026493051472832175,"min":-0.36825341547236723,"dtype":"uint8"},"name":"Prediction/Conv2d_0_pointwise/weights"},{"dtype":"float32","shape":[256],"quantization":{"scale":0.012474596734140433,"min":-2.3078003958159803,"dtype":"uint8"},"name":"Prediction/Conv2d_0_pointwise/convolution_bn_offset"},{"dtype":"float32","shape":[3,3,256,512],"quantization":{"scale":0.014533351449405445,"min":-1.8166689311756807,"dtype":"uint8"},"name":"Prediction/Conv2d_1_pointwise/weights"},{"dtype":"float32","shape":[512],"quantization":{"scale":0.024268776762719248,"min":-2.4754152297973633,"dtype":"uint8"},"name":"Prediction/Conv2d_1_pointwise/convolution_bn_offset"},{"dtype":"float32","shape":[1,1,512,128],"quantization":{"scale":0.002208403746287028,"min":-0.28709248701731366,"dtype":"uint8"},"name":"Prediction/Conv2d_2_pointwise/weights"},{"dtype":"float32","shape":[128],"quantization":{"scale":0.012451349052728392,"min":-1.5937726787492341,"dtype":"uint8"},"name":"Prediction/Conv2d_2_pointwise/convolution_bn_offset"},{"dtype":"float32","shape":[3,3,128,256],"quantization":{"scale":0.026334229637594783,"min":-2.8967652601354263,"dtype":"uint8"},"name":"Prediction/Conv2d_3_pointwise/weights"},{"dtype":"float32","shape":[256],"quantization":{"scale":0.02509917792151956,"min":-1.4055539636050953,"dtype":"uint8"},"name":"Prediction/Conv2d_3_pointwise/convolution_bn_offset"},{"dtype":"float32","shape":[1,1,256,128],"quantization":{"scale":0.004565340046789132,"min":-0.3971845840706545,"dtype":"uint8"},"name":"Prediction/Conv2d_4_pointwise/weights"},{"dtype":"float32","shape":[128],"quantization":{"scale":0.017302456556581983,"min":-2.5953684834872974,"dtype":"uint8"},"name":"Prediction/Conv2d_4_pointwise/convolution_bn_offset"},{"dtype":"float32","shape":[3,3,128,256],"quantization":{"scale":0.025347338470758176,"min":-3.8527954475552426,"dtype":"uint8"},"name":"Prediction/Conv2d_5_pointwise/weights"},{"dtype":"float32","shape":[256],"quantization":{"scale":0.033134659598855414,"min":-2.9158500446992766,"dtype":"uint8"},"name":"Prediction/Conv2d_5_pointwise/convolution_bn_offset"},{"dtype":"float32","shape":[1,1,256,64],"quantization":{"scale":0.002493104397081861,"min":-0.2817207968702503,"dtype":"uint8"},"name":"Prediction/Conv2d_6_pointwise/weights"},{"dtype":"float32","shape":[64],"quantization":{"scale":0.011383360974928912,"min":-1.2749364291920382,"dtype":"uint8"},"name":"Prediction/Conv2d_6_pointwise/convolution_bn_offset"},{"dtype":"float32","shape":[3,3,64,128],"quantization":{"scale":0.020821522731407017,"min":-2.7484410005457263,"dtype":"uint8"},"name":"Prediction/Conv2d_7_pointwise/weights"},{"dtype":"float32","shape":[128],"quantization":{"scale":0.052144218893612135,"min":-3.5979511036592373,"dtype":"uint8"},"name":"Prediction/Conv2d_7_pointwise/convolution_bn_offset"},{"dtype":"int32","shape":[],"quantization":{"scale":1,"min":6,"dtype":"uint8"},"name":"Prediction/BoxPredictor_5/stack_1/1"},{"dtype":"int32","shape":[],"quantization":{"scale":1,"min":1,"dtype":"uint8"},"name":"concat_1/axis"},{"dtype":"int32","shape":[1],"quantization":{"scale":1,"min":0,"dtype":"uint8"},"name":"Prediction/BoxPredictor_0/strided_slice/stack"},{"dtype":"int32","shape":[1],"quantization":{"scale":1,"min":1,"dtype":"uint8"},"name":"Prediction/BoxPredictor_0/strided_slice/stack_1"},{"dtype":"int32","shape":[],"quantization":{"scale":1,"min":5118,"dtype":"uint8"},"name":"Postprocessor/stack/1"},{"dtype":"int32","shape":[],"quantization":{"scale":1,"min":4,"dtype":"uint8"},"name":"Prediction/BoxPredictor_0/stack/3"},{"dtype":"float32","shape":[1, 5118, 4],"name":"Output/extra_dim"}]}] \ No newline at end of file diff --git a/src/server/public/models/tiny_face_detector_model-shard1 b/src/server/public/models/tiny_face_detector_model-shard1 new file mode 100644 index 000000000..a3f113a54 Binary files /dev/null and b/src/server/public/models/tiny_face_detector_model-shard1 differ diff --git a/src/server/public/models/tiny_face_detector_model-weights_manifest.json b/src/server/public/models/tiny_face_detector_model-weights_manifest.json new file mode 100644 index 000000000..7d3b222d0 --- /dev/null +++ b/src/server/public/models/tiny_face_detector_model-weights_manifest.json @@ -0,0 +1 @@ +[{"weights":[{"name":"conv0/filters","shape":[3,3,3,16],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.009007044399485869,"min":-1.2069439495311063}},{"name":"conv0/bias","shape":[16],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.005263455241334205,"min":-0.9211046672334858}},{"name":"conv1/depthwise_filter","shape":[3,3,16,1],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.004001977630690033,"min":-0.5042491814669441}},{"name":"conv1/pointwise_filter","shape":[1,1,16,32],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.013836609615999109,"min":-1.411334180831909}},{"name":"conv1/bias","shape":[32],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.0015159862590771096,"min":-0.30926119685173037}},{"name":"conv2/depthwise_filter","shape":[3,3,32,1],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.002666276225856706,"min":-0.317286870876948}},{"name":"conv2/pointwise_filter","shape":[1,1,32,64],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.015265831292844286,"min":-1.6792414422128714}},{"name":"conv2/bias","shape":[64],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.0020280554598453,"min":-0.37113414915168985}},{"name":"conv3/depthwise_filter","shape":[3,3,64,1],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.006100742489683862,"min":-0.8907084034938438}},{"name":"conv3/pointwise_filter","shape":[1,1,64,128],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.016276211832083907,"min":-2.0508026908425725}},{"name":"conv3/bias","shape":[128],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.003394414279975143,"min":-0.7637432129944072}},{"name":"conv4/depthwise_filter","shape":[3,3,128,1],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.006716050119961009,"min":-0.8059260143953211}},{"name":"conv4/pointwise_filter","shape":[1,1,128,256],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.021875603993733724,"min":-2.8875797271728514}},{"name":"conv4/bias","shape":[256],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.0041141652009066415,"min":-0.8187188749804216}},{"name":"conv5/depthwise_filter","shape":[3,3,256,1],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.008423839597141042,"min":-0.9013508368940915}},{"name":"conv5/pointwise_filter","shape":[1,1,256,512],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.030007277283014035,"min":-3.8709387695088107}},{"name":"conv5/bias","shape":[512],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.008402082966823203,"min":-1.4871686851277068}},{"name":"conv8/filters","shape":[1,1,512,25],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.028336129469030042,"min":-4.675461362389957}},{"name":"conv8/bias","shape":[25],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.002268134028303857,"min":-0.41053225912299807}}],"paths":["tiny_face_detector_model-shard1"]}] \ No newline at end of file -- cgit v1.2.3-70-g09d2 From 9e03f9333641c818ed9c711282f27f7213cbe3c1 Mon Sep 17 00:00:00 2001 From: IEatChili Date: Fri, 2 Aug 2024 14:11:41 -0400 Subject: feat: integrated face recognition code with image documents --- src/client/util/DocumentManager.ts | 6 +- src/client/views/search/FaceRecognitionHandler.tsx | 86 +++++++++++++++------- 2 files changed, 65 insertions(+), 27 deletions(-) (limited to 'src') diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts index 8ad6ddf47..7d4684f41 100644 --- a/src/client/util/DocumentManager.ts +++ b/src/client/util/DocumentManager.ts @@ -6,11 +6,12 @@ import { Id } from '../../fields/FieldSymbols'; import { listSpec } from '../../fields/Schema'; import { Cast, DocCast, NumCast, StrCast } from '../../fields/Types'; import { AudioField } from '../../fields/URLField'; -import { CollectionViewType } from '../documents/DocumentTypes'; +import { CollectionViewType, DocumentType } from '../documents/DocumentTypes'; import { DocumentView, DocumentViewInternal } from '../views/nodes/DocumentView'; import { FocusViewOptions } from '../views/nodes/FocusViewOptions'; import { OpenWhere } from '../views/nodes/OpenWhere'; import { PresBox } from '../views/nodes/trails'; +import { FaceRecognitionHandler } from '../views/search/FaceRecognitionHandler'; type childIterator = { viewSpec: Opt; childDocView: Opt; focused: boolean; contextPath: Doc[] }; export class DocumentManager { @@ -96,6 +97,9 @@ export class DocumentManager { @action public AddView = (view: DocumentView) => { + if (view.Document.type === DocumentType.IMG && view.Document.embedContainer) { + FaceRecognitionHandler.Instance.findMatches(view.Document); + } this.AddDocumentView(view); this.callAddViewFuncs(view); }; diff --git a/src/client/views/search/FaceRecognitionHandler.tsx b/src/client/views/search/FaceRecognitionHandler.tsx index 86619b2d1..fcd38c42f 100644 --- a/src/client/views/search/FaceRecognitionHandler.tsx +++ b/src/client/views/search/FaceRecognitionHandler.tsx @@ -4,51 +4,84 @@ import { Doc, DocListCast, NumListCast } from '../../../fields/Doc'; import { DocData } from '../../../fields/DocSymbols'; import { List } from '../../../fields/List'; import { ObjectField } from '../../../fields/ObjectField'; -import { StrCast } from '../../../fields/Types'; +import { ImageCast, StrCast } from '../../../fields/Types'; +import { DocUtils } from '../../documents/DocUtils'; +import { Deserializable } from '../../util/SerializationHelper'; +import { DocumentView } from '../nodes/DocumentView'; export class FaceRecognitionHandler { static _instance: FaceRecognitionHandler; + private loadedModels: boolean = false; + examinedDocs: Set = new Set(); + processingDocs: Set = new Set(); constructor() { FaceRecognitionHandler._instance = this; this.loadModels(); - if (!Doc.ActiveDashboard![DocData].faceDocuments) { - Doc.ActiveDashboard![DocData].faceDocuments = new List(); - } } async loadModels() { const MODEL_URL = `/models`; - await faceapi.loadTinyFaceDetectorModel(MODEL_URL); - await faceapi.loadFaceLandmarkTinyModel(MODEL_URL); + await faceapi.loadFaceDetectionModel(MODEL_URL); + await faceapi.loadFaceLandmarkModel(MODEL_URL); await faceapi.loadFaceRecognitionModel(MODEL_URL); + this.loadedModels = true; } public static get Instance() { return FaceRecognitionHandler._instance ?? new FaceRecognitionHandler(); } - public async findMatches(doc: Doc, imageURL: string) { - const img = await this.loadImage(imageURL); - - const fullFaceDescriptions = await faceapi.detectAllFaces(img, new TinyFaceDetectorOptions()).withFaceLandmarks(true).withFaceDescriptors(); - - fullFaceDescriptions.forEach(fd => { - const match = this.findMatch(fd.descriptor); - if (match) { - match[DocData].associatedDocs = new List([...DocListCast(match[DocData].associatedDocs), doc]); - match[DocData].faceDescriptors = new List>([...(match[DocData].faceDescriptors as List>), Array.from(fd.descriptor) as List]); - } else { - const newFaceDocument = new Doc(); - const converted_array = Array.from(fd.descriptor); - newFaceDocument[DocData].faceDescriptors = new List>(); - (newFaceDocument[DocData].faceDescriptors as List>).push(converted_array as List); - newFaceDocument[DocData].label = `Person ${DocListCast(Doc.ActiveDashboard![DocData].faceDocuments).length + 1}`; - newFaceDocument[DocData].associatedDocs = new List([doc]); - - Doc.ActiveDashboard![DocData].faceDocuments = new List([...DocListCast(Doc.ActiveDashboard![DocData].faceDocuments), newFaceDocument]); + public async findMatches(doc: Doc) { + if (this.loadedModels) { + if (!Doc.ActiveDashboard![DocData].faceDocuments) { + Doc.ActiveDashboard![DocData].faceDocuments = new List(); } - }); + + if (this.examinedDocs.has(doc) || this.processingDocs.has(doc)) { + return; + } + + this.processingDocs.add(doc); + + try { + const [name, type] = ImageCast(doc[Doc.LayoutFieldKey(doc)]).url.href.split('.'); + const imageURL = `${name}_o.${type}`; + + const img = await this.loadImage(imageURL); + + const fullFaceDescriptions = await faceapi.detectAllFaces(img).withFaceLandmarks().withFaceDescriptors(); + + for (const fd of fullFaceDescriptions) { + const match = this.findMatch(fd.descriptor); + if (match) { + const converted_array = Array.from(fd.descriptor); + const converted_list = new List(converted_array); + match[DocData].associatedDocs = new List([...DocListCast(match[DocData].associatedDocs), doc]); + match[DocData].faceDescriptors = new List>([...(match[DocData].faceDescriptors as List>), converted_list]); + } else { + const newFaceDocument = new Doc(); + const converted_array = Array.from(fd.descriptor); + const converted_list = new List(converted_array); + newFaceDocument[DocData].faceDescriptors = new List>(); + (newFaceDocument[DocData].faceDescriptors as List>).push(converted_list); + newFaceDocument[DocData].label = `Person ${DocListCast(Doc.ActiveDashboard![DocData].faceDocuments).length + 1}`; + newFaceDocument[DocData].associatedDocs = new List([doc]); + + Doc.ActiveDashboard![DocData].faceDocuments = new List([...DocListCast(Doc.ActiveDashboard![DocData].faceDocuments), newFaceDocument]); + } + } + + this.examinedDocs.add(doc); + console.log(this.examinedDocs); + + DocListCast(Doc.ActiveDashboard![DocData].faceDocuments).forEach(doc => console.log(DocListCast(doc[DocData].associatedDocs))); + } catch (error) { + console.error('Error processing document:', error); + } finally { + this.processingDocs.delete(doc); + } + } } private findMatch(cur_descriptor: Float32Array) { @@ -68,6 +101,7 @@ export class FaceRecognitionHandler { } else { for (const doc of DocListCast(Doc.ActiveDashboard![DocData].faceDocuments)) { if (doc[DocData].label === match.label) { + console.log(match.label); return doc; } } -- cgit v1.2.3-70-g09d2 From 4574b7f03ccc85c4bebdbfd9475788456086704f Mon Sep 17 00:00:00 2001 From: bobzel Date: Thu, 8 Aug 2024 12:27:40 -0400 Subject: many changes to add typing in place of 'any's etc --- package-lock.json | 4932 ++++++++++---------- package.json | 3 + src/ClientUtils.ts | 75 +- src/JSZipUtils.js | 10 +- src/client/DocServer.ts | 263 +- src/client/Network.ts | 27 +- src/client/documents/DocUtils.ts | 64 +- src/client/documents/DocumentTypes.ts | 1 - src/client/documents/Documents.ts | 33 +- src/client/util/CalendarManager.tsx | 44 +- src/client/util/CaptureManager.tsx | 10 +- src/client/util/CurrentUserUtils.ts | 80 +- src/client/util/DictationManager.ts | 43 +- src/client/util/DocumentManager.ts | 39 +- src/client/util/DragManager.ts | 103 +- src/client/util/DropConverter.ts | 13 +- src/client/util/GroupManager.tsx | 22 +- src/client/util/GroupMemberView.tsx | 2 - src/client/util/History.ts | 7 +- src/client/util/Import & Export/ImageUtils.ts | 1 + .../util/Import & Export/ImportMetadataEntry.tsx | 2 - src/client/util/InteractionUtils.tsx | 22 +- src/client/util/LinkFollower.ts | 4 +- src/client/util/LinkManager.ts | 43 +- src/client/util/ProsemirrorCopy/prompt.js | 179 - src/client/util/RTFMarkup.tsx | 4 +- src/client/util/ReplayMovements.ts | 15 +- src/client/util/Scripting.ts | 34 +- src/client/util/ScriptingGlobals.ts | 42 +- src/client/util/SearchUtil.ts | 2 + src/client/util/SelectionManager.ts | 2 +- src/client/util/SerializationHelper.ts | 36 +- src/client/util/ServerStats.tsx | 19 +- src/client/util/SettingsManager.tsx | 2 - src/client/util/SharingManager.tsx | 23 +- src/client/util/SnappingManager.ts | 2 +- src/client/util/TrackMovements.ts | 8 +- src/client/util/TypedEvent.ts | 2 +- src/client/util/UndoManager.ts | 34 +- src/client/util/reportManager/ReportManager.tsx | 6 +- .../util/reportManager/ReportManagerComponents.tsx | 11 +- .../util/reportManager/reportManagerSchema.ts | 40 +- .../util/reportManager/reportManagerUtils.ts | 16 +- src/client/util/request-image-size.ts | 36 +- src/client/views/AntimodeMenu.tsx | 2 +- src/client/views/ContextMenu.tsx | 33 +- src/client/views/ContextMenuItem.tsx | 10 +- src/client/views/DashboardView.tsx | 6 +- src/client/views/FilterPanel.tsx | 12 +- src/client/views/GestureOverlay.tsx | 26 +- src/client/views/InkTranscription.tsx | 3 +- src/client/views/InkingStroke.tsx | 22 +- src/client/views/LightboxView.tsx | 22 +- src/client/views/Main.tsx | 18 +- src/client/views/MainView.tsx | 53 +- src/client/views/OverlayView.tsx | 21 +- src/client/views/ScriptingRepl.tsx | 54 +- src/client/views/StyleProvider.tsx | 6 +- src/client/views/ViewBoxInterface.ts | 3 + .../views/collections/CollectionCalendarView.tsx | 4 +- .../views/collections/CollectionCardDeckView.tsx | 13 +- .../views/collections/CollectionCarouselView.tsx | 16 +- .../views/collections/CollectionDockingView.tsx | 68 +- .../collections/CollectionMasonryViewFieldRow.tsx | 20 +- src/client/views/collections/CollectionMenu.tsx | 4 - .../views/collections/CollectionNoteTakingView.tsx | 29 +- .../collections/CollectionNoteTakingViewColumn.tsx | 15 +- .../views/collections/CollectionPileView.tsx | 10 +- .../collections/CollectionStackedTimeline.tsx | 21 +- .../views/collections/CollectionStackingView.tsx | 27 +- src/client/views/collections/CollectionSubView.tsx | 23 +- .../views/collections/CollectionTimeView.tsx | 8 +- .../views/collections/CollectionTreeView.tsx | 43 +- src/client/views/collections/TabDocView.tsx | 28 +- src/client/views/collections/TreeView.tsx | 86 +- .../CollectionFreeFormInfoState.tsx | 12 +- .../CollectionFreeFormPannableContents.tsx | 4 +- .../collectionFreeForm/CollectionFreeFormView.tsx | 65 +- .../collectionLinear/CollectionLinearView.tsx | 10 +- src/client/views/nodes/AudioBox.tsx | 57 +- .../views/nodes/CollectionFreeFormDocumentView.tsx | 24 +- src/client/views/nodes/ComparisonBox.tsx | 7 +- src/client/views/nodes/DataVizBox/DataVizBox.tsx | 8 +- .../views/nodes/DataVizBox/SchemaCSVPopUp.tsx | 2 - .../views/nodes/DataVizBox/components/TableBox.tsx | 56 +- src/client/views/nodes/DocumentContentsView.tsx | 46 +- src/client/views/nodes/DocumentLinksButton.tsx | 4 +- src/client/views/nodes/DocumentView.tsx | 39 +- src/client/views/nodes/EquationBox.tsx | 11 +- src/client/views/nodes/FieldView.tsx | 3 +- .../views/nodes/FontIconBox/ButtonInterface.ts | 12 - src/client/views/nodes/FontIconBox/FontIconBox.tsx | 46 +- src/client/views/nodes/ImageBox.tsx | 9 +- src/client/views/nodes/KeyValueBox.tsx | 14 +- src/client/views/nodes/KeyValuePair.tsx | 9 +- src/client/views/nodes/LinkBox.tsx | 14 +- src/client/views/nodes/LinkDocPreview.tsx | 6 +- src/client/views/nodes/LoadingBox.tsx | 2 +- src/client/views/nodes/MapBox/MapBox.tsx | 8 +- src/client/views/nodes/PDFBox.tsx | 18 +- .../nodes/PhysicsBox/PhysicsSimulationBox.tsx | 15 +- .../views/nodes/RecordingBox/RecordingBox.tsx | 5 +- src/client/views/nodes/ScreenshotBox.tsx | 35 +- src/client/views/nodes/ScriptingBox.tsx | 96 +- src/client/views/nodes/VideoBox.tsx | 18 +- src/client/views/nodes/WebBox.tsx | 47 +- src/client/views/nodes/WebBoxRenderer.js | 18 +- src/client/views/nodes/audio/AudioWaveform.tsx | 2 +- .../nodes/formattedText/DashDocCommentView.tsx | 38 +- .../views/nodes/formattedText/DashDocView.tsx | 29 +- .../views/nodes/formattedText/DashFieldView.tsx | 34 +- .../views/nodes/formattedText/EquationEditor.tsx | 17 +- .../views/nodes/formattedText/EquationView.tsx | 22 +- .../views/nodes/formattedText/FormattedTextBox.tsx | 89 +- .../formattedText/FormattedTextBoxComment.tsx | 4 +- .../views/nodes/formattedText/ParagraphNodeSpec.ts | 36 +- .../views/nodes/formattedText/RichTextMenu.tsx | 42 +- .../views/nodes/formattedText/RichTextRules.ts | 56 +- src/client/views/nodes/formattedText/marks_rts.ts | 40 +- src/client/views/nodes/formattedText/nodes_rts.ts | 91 +- src/client/views/pdf/GPTPopup/GPTPopup.tsx | 7 +- src/client/views/pdf/PDFViewer.tsx | 12 +- src/fields/Doc.ts | 160 +- src/fields/List.ts | 104 +- src/fields/ObjectField.ts | 21 +- src/fields/Proxy.ts | 31 +- src/fields/RefField.ts | 2 +- src/fields/ScriptField.ts | 28 +- src/fields/util.ts | 132 +- src/mobile/ImageUpload.tsx | 3 +- src/mobile/MobileInterface.tsx | 1 - src/pen-gestures/GestureUtils.ts | 5 +- src/server/ApiManagers/GooglePhotosManager.ts | 6 +- src/server/ApiManagers/UploadManager.ts | 14 +- src/server/DashStats.ts | 1 + src/server/DashUploadUtils.ts | 65 +- src/server/SharedMediaTypes.ts | 4 +- src/server/index.ts | 1 - src/server/websocket.ts | 5 +- webpack.config.js | 3 +- 140 files changed, 4387 insertions(+), 4500 deletions(-) delete mode 100644 src/client/util/ProsemirrorCopy/prompt.js delete mode 100644 src/client/views/nodes/FontIconBox/ButtonInterface.ts (limited to 'src') diff --git a/package-lock.json b/package-lock.json index 168c6d087..328110401 100644 --- a/package-lock.json +++ b/package-lock.json @@ -258,6 +258,7 @@ "@types/cookie-parser": "^1.4.6", "@types/cookie-session": "^2.0.48", "@types/d3": "^7.4.3", + "@types/dom-mediacapture-record": "^1.0.19", "@types/exif": "^0.6.5", "@types/express": "^4.17.21", "@types/express-session": "^1.17.10", @@ -285,10 +286,12 @@ "@types/request": "^2.48.12", "@types/request-promise": "^4.1.51", "@types/shelljs": "^0.8.15", + "@types/textarea-caret": "^3.0.3", "@types/textfit": "^2.4.4", "@types/uuid": "^10.0.0", "@types/valid-url": "^1.0.7", "@types/webpack": "^5.28.5", + "@types/webscopeio__react-textarea-autocomplete": "^4.7.5", "@types/youtube": "0.0.50", "chai": "^5.0.0", "cross-env": "^7.0.3", @@ -320,91 +323,91 @@ } }, "node_modules/@adobe/react-spectrum": { - "version": "3.35.1", - "resolved": "https://registry.npmjs.org/@adobe/react-spectrum/-/react-spectrum-3.35.1.tgz", - "integrity": "sha512-QNhsaEHv5S5Vqsk7b8aCV9F7qAnWw8VJ/Nep/SOjeiJ7vK993jEOetEhSsUIQ8VHsMKs6qkTtZr0/DKoV+Z/9w==", + "version": "3.36.1", + "resolved": "https://registry.npmjs.org/@adobe/react-spectrum/-/react-spectrum-3.36.1.tgz", + "integrity": "sha512-ZDxbCjFBYU3S8iEbsrKoJS5fIf91lpM44nWyY1rKwqD7Lu6Lo0cNX8g44x5pXi+PcMr2KxZOPTj4khfCqMOCvg==", "dependencies": { "@internationalized/string": "^3.2.3", - "@react-aria/i18n": "^3.11.1", - "@react-aria/ssr": "^3.9.4", - "@react-aria/utils": "^3.24.1", - "@react-aria/visually-hidden": "^3.8.12", - "@react-spectrum/actionbar": "^3.4.5", - "@react-spectrum/actiongroup": "^3.10.5", - "@react-spectrum/avatar": "^3.0.12", - "@react-spectrum/badge": "^3.1.13", - "@react-spectrum/breadcrumbs": "^3.9.7", - "@react-spectrum/button": "^3.16.4", - "@react-spectrum/buttongroup": "^3.6.13", - "@react-spectrum/calendar": "^3.4.9", - "@react-spectrum/checkbox": "^3.9.6", - "@react-spectrum/combobox": "^3.12.5", - "@react-spectrum/contextualhelp": "^3.6.11", - "@react-spectrum/datepicker": "^3.9.6", - "@react-spectrum/dialog": "^3.8.11", - "@react-spectrum/divider": "^3.5.13", - "@react-spectrum/dnd": "^3.3.10", - "@react-spectrum/dropzone": "^3.0.1", - "@react-spectrum/filetrigger": "^3.0.1", - "@react-spectrum/form": "^3.7.6", - "@react-spectrum/icon": "^3.7.13", - "@react-spectrum/illustratedmessage": "^3.5.1", - "@react-spectrum/image": "^3.5.1", - "@react-spectrum/inlinealert": "^3.2.5", - "@react-spectrum/labeledvalue": "^3.1.14", - "@react-spectrum/layout": "^3.6.5", - "@react-spectrum/link": "^3.6.7", - "@react-spectrum/list": "^3.7.10", - "@react-spectrum/listbox": "^3.12.9", - "@react-spectrum/menu": "^3.19.1", - "@react-spectrum/meter": "^3.5.1", - "@react-spectrum/numberfield": "^3.9.3", - "@react-spectrum/overlays": "^5.6.1", - "@react-spectrum/picker": "^3.14.5", - "@react-spectrum/progress": "^3.7.7", - "@react-spectrum/provider": "^3.9.7", - "@react-spectrum/radio": "^3.7.6", - "@react-spectrum/searchfield": "^3.8.6", - "@react-spectrum/slider": "^3.6.9", - "@react-spectrum/statuslight": "^3.5.13", - "@react-spectrum/switch": "^3.5.5", - "@react-spectrum/table": "^3.12.10", - "@react-spectrum/tabs": "^3.8.10", - "@react-spectrum/tag": "^3.2.6", - "@react-spectrum/text": "^3.5.5", - "@react-spectrum/textfield": "^3.12.1", - "@react-spectrum/theme-dark": "^3.5.10", - "@react-spectrum/theme-default": "^3.5.10", - "@react-spectrum/theme-light": "^3.4.10", - "@react-spectrum/tooltip": "^3.6.7", - "@react-spectrum/view": "^3.6.10", - "@react-spectrum/well": "^3.4.13", - "@react-stately/collections": "^3.10.7", - "@react-stately/data": "^3.11.4", - "@react-types/shared": "^3.23.1", + "@react-aria/i18n": "^3.12.1", + "@react-aria/ssr": "^3.9.5", + "@react-aria/utils": "^3.25.1", + "@react-aria/visually-hidden": "^3.8.14", + "@react-spectrum/actionbar": "^3.5.1", + "@react-spectrum/actiongroup": "^3.10.7", + "@react-spectrum/avatar": "^3.0.14", + "@react-spectrum/badge": "^3.1.15", + "@react-spectrum/breadcrumbs": "^3.9.9", + "@react-spectrum/button": "^3.16.6", + "@react-spectrum/buttongroup": "^3.6.15", + "@react-spectrum/calendar": "^3.4.11", + "@react-spectrum/checkbox": "^3.9.8", + "@react-spectrum/combobox": "^3.13.1", + "@react-spectrum/contextualhelp": "^3.6.13", + "@react-spectrum/datepicker": "^3.10.1", + "@react-spectrum/dialog": "^3.8.13", + "@react-spectrum/divider": "^3.5.15", + "@react-spectrum/dnd": "^3.4.1", + "@react-spectrum/dropzone": "^3.0.3", + "@react-spectrum/filetrigger": "^3.0.3", + "@react-spectrum/form": "^3.7.8", + "@react-spectrum/icon": "^3.7.15", + "@react-spectrum/illustratedmessage": "^3.5.3", + "@react-spectrum/image": "^3.5.3", + "@react-spectrum/inlinealert": "^3.2.7", + "@react-spectrum/labeledvalue": "^3.1.16", + "@react-spectrum/layout": "^3.6.7", + "@react-spectrum/link": "^3.6.9", + "@react-spectrum/list": "^3.8.1", + "@react-spectrum/listbox": "^3.13.1", + "@react-spectrum/menu": "^3.20.1", + "@react-spectrum/meter": "^3.5.3", + "@react-spectrum/numberfield": "^3.9.5", + "@react-spectrum/overlays": "^5.6.3", + "@react-spectrum/picker": "^3.15.1", + "@react-spectrum/progress": "^3.7.9", + "@react-spectrum/provider": "^3.9.9", + "@react-spectrum/radio": "^3.7.8", + "@react-spectrum/searchfield": "^3.8.8", + "@react-spectrum/slider": "^3.6.11", + "@react-spectrum/statuslight": "^3.5.15", + "@react-spectrum/switch": "^3.5.7", + "@react-spectrum/table": "^3.13.1", + "@react-spectrum/tabs": "^3.8.12", + "@react-spectrum/tag": "^3.2.8", + "@react-spectrum/text": "^3.5.7", + "@react-spectrum/textfield": "^3.12.3", + "@react-spectrum/theme-dark": "^3.5.12", + "@react-spectrum/theme-default": "^3.5.12", + "@react-spectrum/theme-light": "^3.4.12", + "@react-spectrum/tooltip": "^3.6.9", + "@react-spectrum/view": "^3.6.12", + "@react-spectrum/well": "^3.4.15", + "@react-stately/collections": "^3.10.9", + "@react-stately/data": "^3.11.6", + "@react-types/shared": "^3.24.1", "client-only": "^0.0.1" }, "peerDependencies": { - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0", - "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0", + "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" } }, "node_modules/@adobe/react-spectrum-ui": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@adobe/react-spectrum-ui/-/react-spectrum-ui-1.2.0.tgz", - "integrity": "sha512-os3EdjfyJbrukLcZ5uYtdFRiDlLB3zq2JoXp19J/IDpZ8btibJeRZYSwjL+LscEiT2pOYaF2McMQdkZTIwnllw==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@adobe/react-spectrum-ui/-/react-spectrum-ui-1.2.1.tgz", + "integrity": "sha512-wcrbEE2O/9WnEn6avBnaVRRx88S5PLFsPLr4wffzlbMfXeQsy+RMQwaJd3cbzrn18/j04Isit7f7Emfn0dhrJA==", "peerDependencies": { - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0", - "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0", + "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" } }, "node_modules/@adobe/react-spectrum-workflow": { - "version": "2.3.4", - "resolved": "https://registry.npmjs.org/@adobe/react-spectrum-workflow/-/react-spectrum-workflow-2.3.4.tgz", - "integrity": "sha512-XPLzIBl58HdLF9WIPB7RDAvVXvCE3SjG+HaWQhW2P9MnxSz1DEA9O7mlTlYblJkMbfk10T/+RFaSupc1yoN+TA==", + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@adobe/react-spectrum-workflow/-/react-spectrum-workflow-2.3.5.tgz", + "integrity": "sha512-b53VIPwPWKb/T5gzE3qs+QlGP5gVrw/LnWV3xMksDU+CRl3rzOKUwxIGiZO8ICyYh1WiyqY4myGlPU/nAynBUg==", "peerDependencies": { - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0", - "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0", + "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" } }, "node_modules/@ampproject/remapping": { @@ -544,9 +547,9 @@ } }, "node_modules/@azure/core-rest-pipeline": { - "version": "1.16.2", - "resolved": "https://registry.npmjs.org/@azure/core-rest-pipeline/-/core-rest-pipeline-1.16.2.tgz", - "integrity": "sha512-Hnhm/PG9/SQ07JJyLDv3l9Qr8V3xgAe1hFoBYzt6LaalMxfL/ZqFaZf/bz5VN3pMcleCPwl8ivlS2Fjxq/iC8Q==", + "version": "1.16.3", + "resolved": "https://registry.npmjs.org/@azure/core-rest-pipeline/-/core-rest-pipeline-1.16.3.tgz", + "integrity": "sha512-VxLk4AHLyqcHsfKe4MZ6IQ+D+ShuByy+RfStKfSjxJoL3WBWq17VNmrz8aT8etKzqc2nAeIyLxScjpzsS4fz8w==", "dependencies": { "@azure/abort-controller": "^2.0.0", "@azure/core-auth": "^1.4.0", @@ -584,9 +587,9 @@ } }, "node_modules/@azure/core-util": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/@azure/core-util/-/core-util-1.9.1.tgz", - "integrity": "sha512-OLsq0etbHO1MA7j6FouXFghuHrAFGk+5C1imcpQ2e+0oZhYF07WLA+NW2Vqs70R7d+zOAWiWM3tbE1sXcDN66g==", + "version": "1.9.2", + "resolved": "https://registry.npmjs.org/@azure/core-util/-/core-util-1.9.2.tgz", + "integrity": "sha512-l1Qrqhi4x1aekkV+OlcqsJa4AnAkj5p0JV8omgwjaV9OAbP41lvrMvs+CptfetKkeEaGRGSzby7sjPZEX7+kkQ==", "dependencies": { "@azure/abort-controller": "^2.0.0", "tslib": "^2.6.2" @@ -607,9 +610,9 @@ } }, "node_modules/@azure/core-xml": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/@azure/core-xml/-/core-xml-1.4.2.tgz", - "integrity": "sha512-CW3MZhApe/S4iikbYKE7s83fjDBPIr2kpidX+hlGRwh7N4o1nIpQ/PfJTeioqhfqdMvRtheEl+ft64fyTaLNaA==", + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/@azure/core-xml/-/core-xml-1.4.3.tgz", + "integrity": "sha512-D6G7FEmDiTctPKuWegX2WTrS1enKZwqYwdKTO6ZN6JMigcCehlT0/CYl+zWpI9vQ9frwwp7GQT3/owaEXgnOsA==", "dependencies": { "fast-xml-parser": "^4.3.2", "tslib": "^2.6.2" @@ -619,9 +622,9 @@ } }, "node_modules/@azure/logger": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/@azure/logger/-/logger-1.1.3.tgz", - "integrity": "sha512-J8/cIKNQB1Fc9fuYqBVnrppiUtW+5WWJPCj/tAokC5LdSTwkWWttN+jsRgw9BLYD7JDBx7PceiqOBxJJ1tQz3Q==", + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@azure/logger/-/logger-1.1.4.tgz", + "integrity": "sha512-4IXXzcCdLdlXuCG+8UKEwLA1T1NHqUfanhXYHiQTn+6sfWCZXduqbtXDGceg3Ce5QxTGo7EqmbV6Bi+aqKuClQ==", "dependencies": { "tslib": "^2.6.2" }, @@ -630,9 +633,9 @@ } }, "node_modules/@azure/storage-blob": { - "version": "12.23.0", - "resolved": "https://registry.npmjs.org/@azure/storage-blob/-/storage-blob-12.23.0.tgz", - "integrity": "sha512-c1KJ5R5hqR/HtvmFtTn/Y1BNMq45NUBp0LZH7yF8WFMET+wmESgEr0FVTu/Z5NonmfUjbgJZG5Nh8xHc5RdWGQ==", + "version": "12.24.0", + "resolved": "https://registry.npmjs.org/@azure/storage-blob/-/storage-blob-12.24.0.tgz", + "integrity": "sha512-l8cmWM4C7RoNCBOImoFMxhTXe1Lr+8uQ/IgnhRNMpfoA9bAFWoLG4XrWm6O5rKXortreVQuD+fc1hbzWklOZbw==", "dependencies": { "@azure/abort-controller": "^1.0.0", "@azure/core-auth": "^1.4.0", @@ -641,7 +644,7 @@ "@azure/core-lro": "^2.2.0", "@azure/core-paging": "^1.1.1", "@azure/core-rest-pipeline": "^1.10.1", - "@azure/core-tracing": "^1.0.0", + "@azure/core-tracing": "^1.1.2", "@azure/core-util": "^1.6.1", "@azure/core-xml": "^1.3.2", "@azure/logger": "^1.0.0", @@ -665,29 +668,29 @@ } }, "node_modules/@babel/compat-data": { - "version": "7.24.9", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.24.9.tgz", - "integrity": "sha512-e701mcfApCJqMMueQI0Fb68Amflj83+dvAvHawoBpAz+GDjCIyGHzNwnefjsWJ3xiYAqqiQFoWbspGYBdb2/ng==", + "version": "7.25.2", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.25.2.tgz", + "integrity": "sha512-bYcppcpKBvX4znYaPEeFau03bp89ShqNMLs+rmdptMw+heSZh9+z84d2YG+K7cYLbWwzdjtDoW/uqZmPjulClQ==", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/core": { - "version": "7.24.9", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.24.9.tgz", - "integrity": "sha512-5e3FI4Q3M3Pbr21+5xJwCv6ZT6KmGkI0vw3Tozy5ODAQFTIWe37iT8Cr7Ice2Ntb+M3iSKCEWMB1MBgKrW3whg==", + "version": "7.25.2", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.25.2.tgz", + "integrity": "sha512-BBt3opiCOxUr9euZ5/ro/Xv8/V7yJ5bjYMqG/C1YAo8MIKAnumZalCN+msbci3Pigy4lIQfPUpfMM27HMGaYEA==", "peer": true, "dependencies": { "@ampproject/remapping": "^2.2.0", "@babel/code-frame": "^7.24.7", - "@babel/generator": "^7.24.9", - "@babel/helper-compilation-targets": "^7.24.8", - "@babel/helper-module-transforms": "^7.24.9", - "@babel/helpers": "^7.24.8", - "@babel/parser": "^7.24.8", - "@babel/template": "^7.24.7", - "@babel/traverse": "^7.24.8", - "@babel/types": "^7.24.9", + "@babel/generator": "^7.25.0", + "@babel/helper-compilation-targets": "^7.25.2", + "@babel/helper-module-transforms": "^7.25.2", + "@babel/helpers": "^7.25.0", + "@babel/parser": "^7.25.0", + "@babel/template": "^7.25.0", + "@babel/traverse": "^7.25.2", + "@babel/types": "^7.25.2", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", @@ -703,11 +706,11 @@ } }, "node_modules/@babel/generator": { - "version": "7.24.10", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.24.10.tgz", - "integrity": "sha512-o9HBZL1G2129luEUlG1hB4N/nlYNWHnpwlND9eOMclRqqu1YDy2sSYVCFUZwl8I1Gxh+QSRrP2vD7EpUmFVXxg==", + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.25.0.tgz", + "integrity": "sha512-3LEEcj3PVW8pW2R1SR1M89g/qrYk/m/mB/tLqn7dn4sbBUQyTqnlod+II2U4dqiGtUmkcnAmkMDralTFZttRiw==", "dependencies": { - "@babel/types": "^7.24.9", + "@babel/types": "^7.25.0", "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.25", "jsesc": "^2.5.1" @@ -740,11 +743,11 @@ } }, "node_modules/@babel/helper-compilation-targets": { - "version": "7.24.8", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.24.8.tgz", - "integrity": "sha512-oU+UoqCHdp+nWVDkpldqIQL/i/bvAv53tRqLG/s+cOXxe66zOYLU7ar/Xs3LdmBihrUMEUhwu6dMZwbNOYDwvw==", + "version": "7.25.2", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.25.2.tgz", + "integrity": "sha512-U2U5LsSaZ7TAt3cfaymQ8WHh0pxvdHoEk6HVpaexxixjyEquMh0L0YNJNM6CTGKMXV1iksi0iZkGw4AcFkPaaw==", "dependencies": { - "@babel/compat-data": "^7.24.8", + "@babel/compat-data": "^7.25.2", "@babel/helper-validator-option": "^7.24.8", "browserslist": "^4.23.1", "lru-cache": "^5.1.1", @@ -755,18 +758,16 @@ } }, "node_modules/@babel/helper-create-class-features-plugin": { - "version": "7.24.8", - "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.24.8.tgz", - "integrity": "sha512-4f6Oqnmyp2PP3olgUMmOwC3akxSm5aBYraQ6YDdKy7NcAMkDECHWG0DEnV6M2UAkERgIBhYt8S27rURPg7SxWA==", + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.25.0.tgz", + "integrity": "sha512-GYM6BxeQsETc9mnct+nIIpf63SAyzvyYN7UB/IlTyd+MBg06afFGp0mIeUqGyWgS2mxad6vqbMrHVlaL3m70sQ==", "dependencies": { "@babel/helper-annotate-as-pure": "^7.24.7", - "@babel/helper-environment-visitor": "^7.24.7", - "@babel/helper-function-name": "^7.24.7", "@babel/helper-member-expression-to-functions": "^7.24.8", "@babel/helper-optimise-call-expression": "^7.24.7", - "@babel/helper-replace-supers": "^7.24.7", + "@babel/helper-replace-supers": "^7.25.0", "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7", - "@babel/helper-split-export-declaration": "^7.24.7", + "@babel/traverse": "^7.25.0", "semver": "^6.3.1" }, "engines": { @@ -777,9 +778,9 @@ } }, "node_modules/@babel/helper-create-regexp-features-plugin": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.24.7.tgz", - "integrity": "sha512-03TCmXy2FtXJEZfbXDTSqq1fRJArk7lX9DOFC/47VthYcxyIOx+eXQmdo6DOQvrbpIix+KfXwvuXdFDZHxt+rA==", + "version": "7.25.2", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.25.2.tgz", + "integrity": "sha512-+wqVGP+DFmqwFD3EH6TMTfUNeqDehV3E/dl+Sd54eaXqm17tEUNbEIn4sVivVowbvUpOtIGxdo3GoXyDH9N/9g==", "dependencies": { "@babel/helper-annotate-as-pure": "^7.24.7", "regexpu-core": "^5.3.1", @@ -807,40 +808,6 @@ "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, - "node_modules/@babel/helper-environment-visitor": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.24.7.tgz", - "integrity": "sha512-DoiN84+4Gnd0ncbBOM9AZENV4a5ZiL39HYMyZJGZ/AZEykHYdJw0wW3kdcsh9/Kn+BRXHLkkklZ51ecPKmI1CQ==", - "dependencies": { - "@babel/types": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-function-name": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.24.7.tgz", - "integrity": "sha512-FyoJTsj/PEUWu1/TYRiXTIHc8lbw+TDYkZuoE43opPS5TrI7MyONBE1oNvfguEXAD9yhQRrVBnXdXzSLQl9XnA==", - "dependencies": { - "@babel/template": "^7.24.7", - "@babel/types": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-hoist-variables": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.24.7.tgz", - "integrity": "sha512-MJJwhkoGy5c4ehfoRyrJ/owKeMl19U54h27YYftT0o2teQ3FJ3nQUf/I3LlJsX4l3qlw7WRXUmiyajvHXoTubQ==", - "dependencies": { - "@babel/types": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, "node_modules/@babel/helper-member-expression-to-functions": { "version": "7.24.8", "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.24.8.tgz", @@ -866,15 +833,14 @@ } }, "node_modules/@babel/helper-module-transforms": { - "version": "7.24.9", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.24.9.tgz", - "integrity": "sha512-oYbh+rtFKj/HwBQkFlUzvcybzklmVdVV3UU+mN7n2t/q3yGHbuVdNxyFvSBO1tfvjyArpHNcWMAzsSPdyI46hw==", + "version": "7.25.2", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.25.2.tgz", + "integrity": "sha512-BjyRAbix6j/wv83ftcVJmBt72QtHI56C7JXZoG2xATiLpmoC7dpd8WnkikExHDVPpi/3qCmO6WY1EaXOluiecQ==", "dependencies": { - "@babel/helper-environment-visitor": "^7.24.7", "@babel/helper-module-imports": "^7.24.7", "@babel/helper-simple-access": "^7.24.7", - "@babel/helper-split-export-declaration": "^7.24.7", - "@babel/helper-validator-identifier": "^7.24.7" + "@babel/helper-validator-identifier": "^7.24.7", + "@babel/traverse": "^7.25.2" }, "engines": { "node": ">=6.9.0" @@ -903,13 +869,13 @@ } }, "node_modules/@babel/helper-remap-async-to-generator": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.24.7.tgz", - "integrity": "sha512-9pKLcTlZ92hNZMQfGCHImUpDOlAgkkpqalWEeftW5FBya75k8Li2ilerxkM/uBEj01iBZXcCIB/bwvDYgWyibA==", + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.25.0.tgz", + "integrity": "sha512-NhavI2eWEIz/H9dbrG0TuOicDhNexze43i5z7lEqwYm0WEZVTwnPpA0EafUTP7+6/W79HWIP2cTe3Z5NiSTVpw==", "dependencies": { "@babel/helper-annotate-as-pure": "^7.24.7", - "@babel/helper-environment-visitor": "^7.24.7", - "@babel/helper-wrap-function": "^7.24.7" + "@babel/helper-wrap-function": "^7.25.0", + "@babel/traverse": "^7.25.0" }, "engines": { "node": ">=6.9.0" @@ -919,13 +885,13 @@ } }, "node_modules/@babel/helper-replace-supers": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.24.7.tgz", - "integrity": "sha512-qTAxxBM81VEyoAY0TtLrx1oAEJc09ZK67Q9ljQToqCnA+55eNwCORaxlKyu+rNfX86o8OXRUSNUnrtsAZXM9sg==", + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.25.0.tgz", + "integrity": "sha512-q688zIvQVYtZu+i2PsdIu/uWGRpfxzr5WESsfpShfZECkO+d2o+WROWezCi/Q6kJ0tfPa5+pUGUlfx2HhrA3Bg==", "dependencies": { - "@babel/helper-environment-visitor": "^7.24.7", - "@babel/helper-member-expression-to-functions": "^7.24.7", - "@babel/helper-optimise-call-expression": "^7.24.7" + "@babel/helper-member-expression-to-functions": "^7.24.8", + "@babel/helper-optimise-call-expression": "^7.24.7", + "@babel/traverse": "^7.25.0" }, "engines": { "node": ">=6.9.0" @@ -958,17 +924,6 @@ "node": ">=6.9.0" } }, - "node_modules/@babel/helper-split-export-declaration": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.24.7.tgz", - "integrity": "sha512-oy5V7pD+UvfkEATUKvIjvIAH/xCzfsFVw7ygW2SI6NClZzquT+mwdTfgfdbUiceh6iQO0CHtCPsyze/MZ2YbAA==", - "dependencies": { - "@babel/types": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, "node_modules/@babel/helper-string-parser": { "version": "7.24.8", "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.8.tgz", @@ -994,27 +949,26 @@ } }, "node_modules/@babel/helper-wrap-function": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.24.7.tgz", - "integrity": "sha512-N9JIYk3TD+1vq/wn77YnJOqMtfWhNewNE+DJV4puD2X7Ew9J4JvrzrFDfTfyv5EgEXVy9/Wt8QiOErzEmv5Ifw==", + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.25.0.tgz", + "integrity": "sha512-s6Q1ebqutSiZnEjaofc/UKDyC4SbzV5n5SrA2Gq8UawLycr3i04f1dX4OzoQVnexm6aOCh37SQNYlJ/8Ku+PMQ==", "dependencies": { - "@babel/helper-function-name": "^7.24.7", - "@babel/template": "^7.24.7", - "@babel/traverse": "^7.24.7", - "@babel/types": "^7.24.7" + "@babel/template": "^7.25.0", + "@babel/traverse": "^7.25.0", + "@babel/types": "^7.25.0" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helpers": { - "version": "7.24.8", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.24.8.tgz", - "integrity": "sha512-gV2265Nkcz7weJJfvDoAEVzC1e2OTDpkGbEsebse8koXUJUXPsCMi7sRo/+SPMuMZ9MtUPnGwITTnQnU5YjyaQ==", + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.25.0.tgz", + "integrity": "sha512-MjgLZ42aCm0oGjJj8CtSM3DB8NOOf8h2l7DCTePJs29u+v7yO/RBX9nShlKMgFnRks/Q4tBAe7Hxnov9VkGwLw==", "peer": true, "dependencies": { - "@babel/template": "^7.24.7", - "@babel/types": "^7.24.8" + "@babel/template": "^7.25.0", + "@babel/types": "^7.25.0" }, "engines": { "node": ">=6.9.0" @@ -1035,9 +989,12 @@ } }, "node_modules/@babel/parser": { - "version": "7.24.8", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.8.tgz", - "integrity": "sha512-WzfbgXOkGzZiXXCqk43kKwZjzwx4oulxZi3nq2TYL9mOjQv6kYwul9mz6ID36njuL7Xkp6nJEfok848Zj10j/w==", + "version": "7.25.3", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.25.3.tgz", + "integrity": "sha512-iLTJKDbJ4hMvFPgQwwsVoxtHyWpKKPBrxkANrSYewDPaPpT5py5yeVkgPIJ7XYXhndxJpaA3PyALSXQ7u8e/Dw==", + "dependencies": { + "@babel/types": "^7.25.2" + }, "bin": { "parser": "bin/babel-parser.js" }, @@ -1046,12 +1003,26 @@ } }, "node_modules/@babel/plugin-bugfix-firefox-class-in-computed-class-key": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.24.7.tgz", - "integrity": "sha512-TiT1ss81W80eQsN+722OaeQMY/G4yTb4G9JrqeiDADs3N8lbPMGldWi9x8tyqCW5NLx1Jh2AvkE6r6QvEltMMQ==", + "version": "7.25.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.25.3.tgz", + "integrity": "sha512-wUrcsxZg6rqBXG05HG1FPYgsP6EvwF4WpBbxIpWIIYnH8wG0gzx3yZY3dtEHas4sTAOGkbTsc9EGPxwff8lRoA==", "dependencies": { - "@babel/helper-environment-visitor": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.24.8", + "@babel/traverse": "^7.25.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-safari-class-field-initializer-scope": { + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-class-field-initializer-scope/-/plugin-bugfix-safari-class-field-initializer-scope-7.25.0.tgz", + "integrity": "sha512-Bm4bH2qsX880b/3ziJ8KD711LT7z4u8CFudmjqle65AZj/HNUFhEf90dqYv6O86buWvSBmeQDjv0Tn2aF/bIBA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.8" }, "engines": { "node": ">=6.9.0" @@ -1061,11 +1032,11 @@ } }, "node_modules/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.24.7.tgz", - "integrity": "sha512-unaQgZ/iRu/By6tsjMZzpeBZjChYfLYry6HrEXPoz3KmfF0sVBQ1l8zKMQ4xRGLWVsjuvB8nQfjNP/DcfEOCsg==", + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.25.0.tgz", + "integrity": "sha512-lXwdNZtTmeVOOFtwM/WDe7yg1PL8sYhRk/XH0FzbR2HDQ0xC+EnQ/JHeoMYSavtU115tnUk0q9CDyq8si+LMAA==", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.24.8" }, "engines": { "node": ">=6.9.0" @@ -1091,12 +1062,12 @@ } }, "node_modules/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.24.7.tgz", - "integrity": "sha512-utA4HuR6F4Vvcr+o4DnjL8fCOlgRFGbeeBEGNg3ZTrLFw6VWG5XmUrvcQ0FjIYMU2ST4XcR2Wsp7t9qOAPnxMg==", + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.25.0.tgz", + "integrity": "sha512-tggFrk1AIShG/RUQbEwt2Tr/E+ObkfwrPjR6BjbRvsx24+PSjK8zrq0GWPNCjo8qpRx4DuJzlcvWJqlm+0h3kw==", "dependencies": { - "@babel/helper-environment-visitor": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.24.8", + "@babel/traverse": "^7.25.0" }, "engines": { "node": ">=6.9.0" @@ -1362,14 +1333,14 @@ } }, "node_modules/@babel/plugin-transform-async-generator-functions": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.24.7.tgz", - "integrity": "sha512-o+iF77e3u7ZS4AoAuJvapz9Fm001PuD2V3Lp6OSE4FYQke+cSewYtnek+THqGRWyQloRCyvWL1OkyfNEl9vr/g==", + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.25.0.tgz", + "integrity": "sha512-uaIi2FdqzjpAMvVqvB51S42oC2JEVgh0LDsGfZVDysWE8LrJtQC2jvKmOqEYThKyB7bDEb7BP1GYWDm7tABA0Q==", "dependencies": { - "@babel/helper-environment-visitor": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/helper-remap-async-to-generator": "^7.24.7", - "@babel/plugin-syntax-async-generators": "^7.8.4" + "@babel/helper-plugin-utils": "^7.24.8", + "@babel/helper-remap-async-to-generator": "^7.25.0", + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/traverse": "^7.25.0" }, "engines": { "node": ">=6.9.0" @@ -1409,11 +1380,11 @@ } }, "node_modules/@babel/plugin-transform-block-scoping": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.24.7.tgz", - "integrity": "sha512-Nd5CvgMbWc+oWzBsuaMcbwjJWAcp5qzrbg69SZdHSP7AMY0AbWFqFO0WTFCA1jxhMCwodRwvRec8k0QUbZk7RQ==", + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.25.0.tgz", + "integrity": "sha512-yBQjYoOjXlFv9nlXb3f1casSHOZkWr29NX+zChVanLg5Nc157CrbEX9D7hxxtTpuFy7Q0YzmmWfJxzvps4kXrQ==", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.24.8" }, "engines": { "node": ">=6.9.0" @@ -1454,17 +1425,15 @@ } }, "node_modules/@babel/plugin-transform-classes": { - "version": "7.24.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.24.8.tgz", - "integrity": "sha512-VXy91c47uujj758ud9wx+OMgheXm4qJfyhj1P18YvlrQkNOSrwsteHk+EFS3OMGfhMhpZa0A+81eE7G4QC+3CA==", + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.25.0.tgz", + "integrity": "sha512-xyi6qjr/fYU304fiRwFbekzkqVJZ6A7hOjWZd+89FVcBqPV3S9Wuozz82xdpLspckeaafntbzglaW4pqpzvtSw==", "dependencies": { "@babel/helper-annotate-as-pure": "^7.24.7", "@babel/helper-compilation-targets": "^7.24.8", - "@babel/helper-environment-visitor": "^7.24.7", - "@babel/helper-function-name": "^7.24.7", "@babel/helper-plugin-utils": "^7.24.8", - "@babel/helper-replace-supers": "^7.24.7", - "@babel/helper-split-export-declaration": "^7.24.7", + "@babel/helper-replace-supers": "^7.25.0", + "@babel/traverse": "^7.25.0", "globals": "^11.1.0" }, "engines": { @@ -1540,6 +1509,21 @@ "@babel/core": "^7.0.0-0" } }, + "node_modules/@babel/plugin-transform-duplicate-named-capturing-groups-regex": { + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-named-capturing-groups-regex/-/plugin-transform-duplicate-named-capturing-groups-regex-7.25.0.tgz", + "integrity": "sha512-YLpb4LlYSc3sCUa35un84poXoraOiQucUTTu8X1j18JV+gNa8E0nyUf/CjZ171IRGr4jEguF+vzJU66QZhn29g==", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.25.0", + "@babel/helper-plugin-utils": "^7.24.8" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, "node_modules/@babel/plugin-transform-dynamic-import": { "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.24.7.tgz", @@ -1601,13 +1585,13 @@ } }, "node_modules/@babel/plugin-transform-function-name": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.24.7.tgz", - "integrity": "sha512-U9FcnA821YoILngSmYkW6FjyQe2TyZD5pHt4EVIhmcTkrJw/3KqcrRSxuOo5tFZJi7TE19iDyI1u+weTI7bn2w==", + "version": "7.25.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.25.1.tgz", + "integrity": "sha512-TVVJVdW9RKMNgJJlLtHsKDTydjZAbwIsn6ySBPQaEAUU5+gVvlJt/9nRmqVbsV/IBanRjzWoaAQKLoamWVOUuA==", "dependencies": { - "@babel/helper-compilation-targets": "^7.24.7", - "@babel/helper-function-name": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-compilation-targets": "^7.24.8", + "@babel/helper-plugin-utils": "^7.24.8", + "@babel/traverse": "^7.25.1" }, "engines": { "node": ">=6.9.0" @@ -1632,11 +1616,11 @@ } }, "node_modules/@babel/plugin-transform-literals": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.24.7.tgz", - "integrity": "sha512-vcwCbb4HDH+hWi8Pqenwnjy+UiklO4Kt1vfspcQYFhJdpthSnW8XvWGyDZWKNVrVbVViI/S7K9PDJZiUmP2fYQ==", + "version": "7.25.2", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.25.2.tgz", + "integrity": "sha512-HQI+HcTbm9ur3Z2DkO+jgESMAMcYLuN/A7NRw9juzxAezN9AvqvUTnpKP/9kkYANz6u7dFlAyOu44ejuGySlfw==", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.24.8" }, "engines": { "node": ">=6.9.0" @@ -1706,14 +1690,14 @@ } }, "node_modules/@babel/plugin-transform-modules-systemjs": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.24.7.tgz", - "integrity": "sha512-GYQE0tW7YoaN13qFh3O1NCY4MPkUiAH3fiF7UcV/I3ajmDKEdG3l+UOcbAm4zUE3gnvUU+Eni7XrVKo9eO9auw==", + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.25.0.tgz", + "integrity": "sha512-YPJfjQPDXxyQWg/0+jHKj1llnY5f/R6a0p/vP4lPymxLu7Lvl4k2WMitqi08yxwQcCVUUdG9LCUj4TNEgAp3Jw==", "dependencies": { - "@babel/helper-hoist-variables": "^7.24.7", - "@babel/helper-module-transforms": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/helper-validator-identifier": "^7.24.7" + "@babel/helper-module-transforms": "^7.25.0", + "@babel/helper-plugin-utils": "^7.24.8", + "@babel/helper-validator-identifier": "^7.24.7", + "@babel/traverse": "^7.25.0" }, "engines": { "node": ">=6.9.0" @@ -1934,15 +1918,15 @@ } }, "node_modules/@babel/plugin-transform-react-jsx": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.24.7.tgz", - "integrity": "sha512-+Dj06GDZEFRYvclU6k4bme55GKBEWUmByM/eoKuqg4zTNQHiApWRhQph5fxQB2wAEFvRzL1tOEj1RJ19wJrhoA==", + "version": "7.25.2", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.25.2.tgz", + "integrity": "sha512-KQsqEAVBpU82NM/B/N9j9WOdphom1SZH3R+2V7INrQUH+V9EBFwZsEJl8eBIVeQE62FxJCc70jzEZwqU7RcVqA==", "dependencies": { "@babel/helper-annotate-as-pure": "^7.24.7", "@babel/helper-module-imports": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.8", "@babel/plugin-syntax-jsx": "^7.24.7", - "@babel/types": "^7.24.7" + "@babel/types": "^7.25.2" }, "engines": { "node": ">=6.9.0" @@ -2140,18 +2124,19 @@ } }, "node_modules/@babel/preset-env": { - "version": "7.24.8", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.24.8.tgz", - "integrity": "sha512-vObvMZB6hNWuDxhSaEPTKCwcqkAIuDtE+bQGn4XMXne1DSLzFVY8Vmj1bm+mUQXYNN8NmaQEO+r8MMbzPr1jBQ==", + "version": "7.25.3", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.25.3.tgz", + "integrity": "sha512-QsYW7UeAaXvLPX9tdVliMJE7MD7M6MLYVTovRTIwhoYQVFHR1rM4wO8wqAezYi3/BpSD+NzVCZ69R6smWiIi8g==", "dependencies": { - "@babel/compat-data": "^7.24.8", - "@babel/helper-compilation-targets": "^7.24.8", + "@babel/compat-data": "^7.25.2", + "@babel/helper-compilation-targets": "^7.25.2", "@babel/helper-plugin-utils": "^7.24.8", "@babel/helper-validator-option": "^7.24.8", - "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "^7.24.7", - "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.24.7", + "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "^7.25.3", + "@babel/plugin-bugfix-safari-class-field-initializer-scope": "^7.25.0", + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.25.0", "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.24.7", - "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.24.7", + "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.25.0", "@babel/plugin-proposal-private-property-in-object": "7.21.0-placeholder-for-preset-env.2", "@babel/plugin-syntax-async-generators": "^7.8.4", "@babel/plugin-syntax-class-properties": "^7.12.13", @@ -2172,29 +2157,30 @@ "@babel/plugin-syntax-top-level-await": "^7.14.5", "@babel/plugin-syntax-unicode-sets-regex": "^7.18.6", "@babel/plugin-transform-arrow-functions": "^7.24.7", - "@babel/plugin-transform-async-generator-functions": "^7.24.7", + "@babel/plugin-transform-async-generator-functions": "^7.25.0", "@babel/plugin-transform-async-to-generator": "^7.24.7", "@babel/plugin-transform-block-scoped-functions": "^7.24.7", - "@babel/plugin-transform-block-scoping": "^7.24.7", + "@babel/plugin-transform-block-scoping": "^7.25.0", "@babel/plugin-transform-class-properties": "^7.24.7", "@babel/plugin-transform-class-static-block": "^7.24.7", - "@babel/plugin-transform-classes": "^7.24.8", + "@babel/plugin-transform-classes": "^7.25.0", "@babel/plugin-transform-computed-properties": "^7.24.7", "@babel/plugin-transform-destructuring": "^7.24.8", "@babel/plugin-transform-dotall-regex": "^7.24.7", "@babel/plugin-transform-duplicate-keys": "^7.24.7", + "@babel/plugin-transform-duplicate-named-capturing-groups-regex": "^7.25.0", "@babel/plugin-transform-dynamic-import": "^7.24.7", "@babel/plugin-transform-exponentiation-operator": "^7.24.7", "@babel/plugin-transform-export-namespace-from": "^7.24.7", "@babel/plugin-transform-for-of": "^7.24.7", - "@babel/plugin-transform-function-name": "^7.24.7", + "@babel/plugin-transform-function-name": "^7.25.1", "@babel/plugin-transform-json-strings": "^7.24.7", - "@babel/plugin-transform-literals": "^7.24.7", + "@babel/plugin-transform-literals": "^7.25.2", "@babel/plugin-transform-logical-assignment-operators": "^7.24.7", "@babel/plugin-transform-member-expression-literals": "^7.24.7", "@babel/plugin-transform-modules-amd": "^7.24.7", "@babel/plugin-transform-modules-commonjs": "^7.24.8", - "@babel/plugin-transform-modules-systemjs": "^7.24.7", + "@babel/plugin-transform-modules-systemjs": "^7.25.0", "@babel/plugin-transform-modules-umd": "^7.24.7", "@babel/plugin-transform-named-capturing-groups-regex": "^7.24.7", "@babel/plugin-transform-new-target": "^7.24.7", @@ -2271,9 +2257,9 @@ "integrity": "sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA==" }, "node_modules/@babel/runtime": { - "version": "7.24.8", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.8.tgz", - "integrity": "sha512-5F7SDGs1T72ZczbRwbGO9lQi0NLjQxzl6i4lJxLxfW9U5UluCSyEJeniWvnhl3/euNiqQVbo8zruhsDfid0esA==", + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.25.0.tgz", + "integrity": "sha512-7dRy4DwXwtzBrPbZflqxnvfxLF8kdZXPkhymtDeFoFqE6ldzjQFgYTtYIFARcLEYDrqfBfYcZt1WqFxRoyC9Rw==", "dependencies": { "regenerator-runtime": "^0.14.0" }, @@ -2282,9 +2268,9 @@ } }, "node_modules/@babel/runtime-corejs3": { - "version": "7.24.8", - "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.24.8.tgz", - "integrity": "sha512-DXG/BhegtMHhnN7YPIvxWd303/9aXvYFD1TjNL3CD6tUrhI2LVsg3Lck0aql5TRH29n4sj3emcROypkZVUfSuA==", + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.25.0.tgz", + "integrity": "sha512-BOehWE7MgQ8W8Qn0CQnMtg2tHPHPulcS/5AVpFvs2KCK1ET+0WqZqPvnpRpFN81gYoFopdIEJX9Sgjw3ZBccPg==", "dependencies": { "core-js-pure": "^3.30.2", "regenerator-runtime": "^0.14.0" @@ -2294,31 +2280,28 @@ } }, "node_modules/@babel/template": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.24.7.tgz", - "integrity": "sha512-jYqfPrU9JTF0PmPy1tLYHW4Mp4KlgxJD9l2nP9fD6yT/ICi554DmrWBAEYpIelzjHf1msDP3PxJIRt/nFNfBig==", + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.25.0.tgz", + "integrity": "sha512-aOOgh1/5XzKvg1jvVz7AVrx2piJ2XBi227DHmbY6y+bM9H2FlN+IfecYu4Xl0cNiiVejlsCri89LUsbj8vJD9Q==", "dependencies": { "@babel/code-frame": "^7.24.7", - "@babel/parser": "^7.24.7", - "@babel/types": "^7.24.7" + "@babel/parser": "^7.25.0", + "@babel/types": "^7.25.0" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/traverse": { - "version": "7.24.8", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.24.8.tgz", - "integrity": "sha512-t0P1xxAPzEDcEPmjprAQq19NWum4K0EQPjMwZQZbHt+GiZqvjCHjj755Weq1YRPVzBI+3zSfvScfpnuIecVFJQ==", + "version": "7.25.3", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.25.3.tgz", + "integrity": "sha512-HefgyP1x754oGCsKmV5reSmtV7IXj/kpaE1XYY+D9G5PvKKoFfSbiS4M77MdjuwlZKDIKFCffq9rPU+H/s3ZdQ==", "dependencies": { "@babel/code-frame": "^7.24.7", - "@babel/generator": "^7.24.8", - "@babel/helper-environment-visitor": "^7.24.7", - "@babel/helper-function-name": "^7.24.7", - "@babel/helper-hoist-variables": "^7.24.7", - "@babel/helper-split-export-declaration": "^7.24.7", - "@babel/parser": "^7.24.8", - "@babel/types": "^7.24.8", + "@babel/generator": "^7.25.0", + "@babel/parser": "^7.25.3", + "@babel/template": "^7.25.0", + "@babel/types": "^7.25.2", "debug": "^4.3.1", "globals": "^11.1.0" }, @@ -2335,9 +2318,9 @@ } }, "node_modules/@babel/types": { - "version": "7.24.9", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.24.9.tgz", - "integrity": "sha512-xm8XrMKz0IlUdocVbYJe0Z9xEgidU7msskG8BbhnTPK/HZ2z/7FP7ykqPgrUH+C+r414mNfNWam1f2vqOjqjYQ==", + "version": "7.25.2", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.25.2.tgz", + "integrity": "sha512-YTnYtra7W9e6/oAZEHj0bJehPRUlLH9/fbpT5LfB0NhQXyALCRkRs3zH9v07IYhkgpqX6Z78FnuccZr/l4Fs4Q==", "dependencies": { "@babel/helper-string-parser": "^7.24.8", "@babel/helper-validator-identifier": "^7.24.7", @@ -2411,9 +2394,9 @@ "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==" }, "node_modules/@emotion/cache": { - "version": "11.13.0", - "resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-11.13.0.tgz", - "integrity": "sha512-hPV345J/tH0Cwk2wnU/3PBzORQ9HeX+kQSbwI+jslzpRCHE6fSGTohswksA/Ensr8znPzwfzKZCmAM9Lmlhp7g==", + "version": "11.13.1", + "resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-11.13.1.tgz", + "integrity": "sha512-iqouYkuEblRcXmylXIwwOodiEK5Ifl7JcX7o6V4jI3iW4mLXX3dmt5xwBtIkJiQEXFAI+pC8X0i67yiPkH9Ucw==", "dependencies": { "@emotion/memoize": "^0.9.0", "@emotion/sheet": "^1.4.0", @@ -2637,9 +2620,9 @@ } }, "node_modules/@eslint/js": { - "version": "9.7.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.7.0.tgz", - "integrity": "sha512-ChuWDQenef8OSFnvuxv0TCVxEwmu3+hPNKvM9B34qpM0rDRbjL8t5QkQeHHeAfsKQjuH9wS82WeCi1J/owatng==", + "version": "9.8.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.8.0.tgz", + "integrity": "sha512-MfluB7EUfxXtv3i/++oh89uzAr4PDI4nn201hsp+qaXqsjAWzinlZEHEfPgAX4doIlKvPG/i0A9dpKxOLII8yA==", "dev": true, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -2673,29 +2656,29 @@ } }, "node_modules/@floating-ui/core": { - "version": "1.6.5", - "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.6.5.tgz", - "integrity": "sha512-8GrTWmoFhm5BsMZOTHeGD2/0FLKLQQHvO/ZmQga4tKempYRLz8aqJGqXVuQgisnMObq2YZ2SgkwctN1LOOxcqA==", + "version": "1.6.7", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.6.7.tgz", + "integrity": "sha512-yDzVT/Lm101nQ5TCVeK65LtdN7Tj4Qpr9RTXJ2vPFLqtLxwOrpoxAHAJI8J3yYWUc40J0BDBheaitK5SJmno2g==", "dependencies": { - "@floating-ui/utils": "^0.2.5" + "@floating-ui/utils": "^0.2.7" } }, "node_modules/@floating-ui/dom": { - "version": "1.6.8", - "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.6.8.tgz", - "integrity": "sha512-kx62rP19VZ767Q653wsP1XZCGIirkE09E0QUGNYTM/ttbbQHqcGPdSfWFxUyyNLc/W6aoJRBajOSXhP6GXjC0Q==", + "version": "1.6.10", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.6.10.tgz", + "integrity": "sha512-fskgCFv8J8OamCmyun8MfjB1Olfn+uZKjOKZ0vhYF3gRmEUXcGOjxWL8bBr7i4kIuPZ2KD2S3EUIOxnjC8kl2A==", "dependencies": { "@floating-ui/core": "^1.6.0", - "@floating-ui/utils": "^0.2.5" + "@floating-ui/utils": "^0.2.7" } }, "node_modules/@floating-ui/react": { - "version": "0.26.20", - "resolved": "https://registry.npmjs.org/@floating-ui/react/-/react-0.26.20.tgz", - "integrity": "sha512-RixKJJG92fcIsVoqrFr4Onpzh7hlOx4U7NV4aLhMLmtvjZ5oTB/WzXaANYUZATKqXvvW7t9sCxtzejip26N5Ag==", + "version": "0.26.22", + "resolved": "https://registry.npmjs.org/@floating-ui/react/-/react-0.26.22.tgz", + "integrity": "sha512-LNv4azPt8SpT4WW7Kku5JNVjLk2GcS0bGGjFTAgqOONRFo9r/aaGHHPpdiIuQbB1t8shmWyWqTTUDmZ9fcNshg==", "dependencies": { "@floating-ui/react-dom": "^2.1.1", - "@floating-ui/utils": "^0.2.5", + "@floating-ui/utils": "^0.2.7", "tabbable": "^6.0.0" }, "peerDependencies": { @@ -2716,9 +2699,9 @@ } }, "node_modules/@floating-ui/utils": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.5.tgz", - "integrity": "sha512-sTcG+QZ6fdEUObICavU+aB3Mp8HY4n14wYHdxK4fXjPmv3PXZZeY5RaguJmGyeH/CJQhX3fqKUtS4qc1LoHwhQ==" + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.7.tgz", + "integrity": "sha512-X8R8Oj771YRl/w+c1HqAC1szL8zWQRwFvgDwT129k9ACdBoud/+/rX9V0qiMl6LWUdP9voC2nDVZYPMQQsb6eA==" }, "node_modules/@formatjs/ecma402-abstract": { "version": "2.0.0", @@ -2933,9 +2916,9 @@ } }, "node_modules/@internationalized/date": { - "version": "3.5.4", - "resolved": "https://registry.npmjs.org/@internationalized/date/-/date-3.5.4.tgz", - "integrity": "sha512-qoVJVro+O0rBaw+8HPjUB1iH8Ihf8oziEnqMnvhJUSuVIrHOuZ6eNLHNvzXJKUvAtaDiqMnRlg8Z2mgh09BlUw==", + "version": "3.5.5", + "resolved": "https://registry.npmjs.org/@internationalized/date/-/date-3.5.5.tgz", + "integrity": "sha512-H+CfYvOZ0LTJeeLOqm19E3uj/4YjrmOFtBufDHPfvtI80hFAMqtrp7oCACpe4Cil5l8S0Qu/9dYfZc/5lY8WQQ==", "dependencies": { "@swc/helpers": "^0.5.0" } @@ -3558,9 +3541,9 @@ } }, "node_modules/@jsonjoy.com/json-pack": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@jsonjoy.com/json-pack/-/json-pack-1.0.4.tgz", - "integrity": "sha512-aOcSN4MeAtFROysrbqG137b7gaDDSmVrl5mpo6sT/w+kcXpWnzhMjmY/Fh/sDx26NBxyIE7MB1seqLeCAzy9Sg==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/json-pack/-/json-pack-1.1.0.tgz", + "integrity": "sha512-zlQONA+msXPPwHWZMKFVS78ewFczIll5lXiVPwFPCZUsrOKdxc2AvxU1HoNBmMRhqDZUR9HkC3UOm+6pME6Xsg==", "dependencies": { "@jsonjoy.com/base64": "^1.1.1", "@jsonjoy.com/util": "^1.1.2", @@ -3579,9 +3562,9 @@ } }, "node_modules/@jsonjoy.com/util": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@jsonjoy.com/util/-/util-1.2.0.tgz", - "integrity": "sha512-4B8B+3vFsY4eo33DMKyJPlQ3sBMpPFUZK2dr3O3rXrOGKKbYG44J0XSFkDo1VOQiri5HFEhIeVvItjR2xcazmg==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/util/-/util-1.3.0.tgz", + "integrity": "sha512-Cebt4Vk7k1xHy87kHY7KSPLT77A7Ev7IfOblyLZhtYEhrdQ6fX4EoLq3xOQ3O/DRMEh2ok5nyC180E+ABS8Wmw==", "engines": { "node": ">=10.0" }, @@ -3783,18 +3766,18 @@ } }, "node_modules/@mui/core-downloads-tracker": { - "version": "5.16.4", - "resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-5.16.4.tgz", - "integrity": "sha512-rNdHXhclwjEZnK+//3SR43YRx0VtjdHnUFhMSGYmAMJve+KiwEja/41EYh8V3pZKqF2geKyfcFUenTfDTYUR4w==", + "version": "5.16.6", + "resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-5.16.6.tgz", + "integrity": "sha512-kytg6LheUG42V8H/o/Ptz3olSO5kUXW9zF0ox18VnblX6bO2yif1FPItgc3ey1t5ansb1+gbe7SatntqusQupg==", "funding": { "type": "opencollective", "url": "https://opencollective.com/mui-org" } }, "node_modules/@mui/icons-material": { - "version": "5.16.4", - "resolved": "https://registry.npmjs.org/@mui/icons-material/-/icons-material-5.16.4.tgz", - "integrity": "sha512-j9/CWctv6TH6Dou2uR2EH7UOgu79CW/YcozxCYVLJ7l03pCsiOlJ5sBArnWJxJ+nGkFwyL/1d1k8JEPMDR125A==", + "version": "5.16.6", + "resolved": "https://registry.npmjs.org/@mui/icons-material/-/icons-material-5.16.6.tgz", + "integrity": "sha512-ceNGjoXheH9wbIFa1JHmSc9QVjJUvh18KvHrR4/FkJCSi9HXJ+9ee1kUhCOEFfuxNF8UB6WWVrIUOUgRd70t0A==", "dependencies": { "@babel/runtime": "^7.23.9" }, @@ -3817,15 +3800,15 @@ } }, "node_modules/@mui/material": { - "version": "5.16.4", - "resolved": "https://registry.npmjs.org/@mui/material/-/material-5.16.4.tgz", - "integrity": "sha512-dBnh3/zRYgEVIS3OE4oTbujse3gifA0qLMmuUk13ywsDCbngJsdgwW5LuYeiT5pfA8PGPGSqM7mxNytYXgiMCw==", + "version": "5.16.6", + "resolved": "https://registry.npmjs.org/@mui/material/-/material-5.16.6.tgz", + "integrity": "sha512-0LUIKBOIjiFfzzFNxXZBRAyr9UQfmTAFzbt6ziOU2FDXhorNN2o3N9/32mNJbCA8zJo2FqFU6d3dtoqUDyIEfA==", "dependencies": { "@babel/runtime": "^7.23.9", - "@mui/core-downloads-tracker": "^5.16.4", - "@mui/system": "^5.16.4", + "@mui/core-downloads-tracker": "^5.16.6", + "@mui/system": "^5.16.6", "@mui/types": "^7.2.15", - "@mui/utils": "^5.16.4", + "@mui/utils": "^5.16.6", "@popperjs/core": "^2.11.8", "@types/react-transition-group": "^4.4.10", "clsx": "^2.1.0", @@ -3861,12 +3844,12 @@ } }, "node_modules/@mui/private-theming": { - "version": "5.16.4", - "resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-5.16.4.tgz", - "integrity": "sha512-ZsAm8cq31SJ37SVWLRlu02v9SRthxnfQofaiv14L5Bht51B0dz6yQEoVU/V8UduZDCCIrWkBHuReVfKhE/UuXA==", + "version": "5.16.6", + "resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-5.16.6.tgz", + "integrity": "sha512-rAk+Rh8Clg7Cd7shZhyt2HGTTE5wYKNSJ5sspf28Fqm/PZ69Er9o6KX25g03/FG2dfpg5GCwZh/xOojiTfm3hw==", "dependencies": { "@babel/runtime": "^7.23.9", - "@mui/utils": "^5.16.4", + "@mui/utils": "^5.16.6", "prop-types": "^15.8.1" }, "engines": { @@ -3887,9 +3870,9 @@ } }, "node_modules/@mui/styled-engine": { - "version": "5.16.4", - "resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-5.16.4.tgz", - "integrity": "sha512-0+mnkf+UiAmTVB8PZFqOhqf729Yh0Cxq29/5cA3VAyDVTRIUUQ8FXQhiAhUIbijFmM72rY80ahFPXIm4WDbzcA==", + "version": "5.16.6", + "resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-5.16.6.tgz", + "integrity": "sha512-zaThmS67ZmtHSWToTiHslbI8jwrmITcN93LQaR2lKArbvS7Z3iLkwRoiikNWutx9MBs8Q6okKvbZq1RQYB3v7g==", "dependencies": { "@babel/runtime": "^7.23.9", "@emotion/cache": "^11.11.0", @@ -3918,15 +3901,15 @@ } }, "node_modules/@mui/system": { - "version": "5.16.4", - "resolved": "https://registry.npmjs.org/@mui/system/-/system-5.16.4.tgz", - "integrity": "sha512-ET1Ujl2/8hbsD611/mqUuNArMCGv/fIWO/f8B3ZqF5iyPHM2aS74vhTNyjytncc4i6dYwGxNk+tLa7GwjNS0/w==", + "version": "5.16.6", + "resolved": "https://registry.npmjs.org/@mui/system/-/system-5.16.6.tgz", + "integrity": "sha512-5xgyJjBIMPw8HIaZpfbGAaFYPwImQn7Nyh+wwKWhvkoIeDosQ1ZMVrbTclefi7G8hNmqhip04duYwYpbBFnBgw==", "dependencies": { "@babel/runtime": "^7.23.9", - "@mui/private-theming": "^5.16.4", - "@mui/styled-engine": "^5.16.4", + "@mui/private-theming": "^5.16.6", + "@mui/styled-engine": "^5.16.6", "@mui/types": "^7.2.15", - "@mui/utils": "^5.16.4", + "@mui/utils": "^5.16.6", "clsx": "^2.1.0", "csstype": "^3.1.3", "prop-types": "^15.8.1" @@ -3970,11 +3953,12 @@ } }, "node_modules/@mui/utils": { - "version": "5.16.4", - "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-5.16.4.tgz", - "integrity": "sha512-nlppYwq10TBIFqp7qxY0SvbACOXeOjeVL3pOcDsK0FT8XjrEXh9/+lkg8AEIzD16z7YfiJDQjaJG2OLkE7BxNg==", + "version": "5.16.6", + "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-5.16.6.tgz", + "integrity": "sha512-tWiQqlhxAt3KENNiSRL+DIn9H5xNVK6Jjf70x3PnfQPz1MPBdh7yyIcAyVBT9xiw7hP3SomRhPR7hzBMBCjqEA==", "dependencies": { "@babel/runtime": "^7.23.9", + "@mui/types": "^7.2.15", "@types/prop-types": "^15.7.12", "clsx": "^2.1.1", "prop-types": "^15.8.1", @@ -4148,372 +4132,387 @@ } }, "node_modules/@react-aria/actiongroup": { - "version": "3.7.5", - "resolved": "https://registry.npmjs.org/@react-aria/actiongroup/-/actiongroup-3.7.5.tgz", - "integrity": "sha512-asJk6WN6MhtwqWzVx7zkakhTbrpk1XhJbxF2piGlk2pTCh8zUCnMjvFAmMdQN+voj5lEW4/CZNfrblNDwzCimQ==", - "dependencies": { - "@react-aria/focus": "^3.17.1", - "@react-aria/i18n": "^3.11.1", - "@react-aria/interactions": "^3.21.3", - "@react-aria/utils": "^3.24.1", - "@react-stately/list": "^3.10.5", - "@react-types/actiongroup": "^3.4.9", - "@react-types/shared": "^3.23.1", + "version": "3.7.7", + "resolved": "https://registry.npmjs.org/@react-aria/actiongroup/-/actiongroup-3.7.7.tgz", + "integrity": "sha512-qkbCnMYt32ZWN8X7ycup/kbdaQLENJ+uzy3gRI5VY06RwN+btdvT8seZl1xR0n7qfdDCZxmd5WaKbXA0gl3bBA==", + "dependencies": { + "@react-aria/focus": "^3.18.1", + "@react-aria/i18n": "^3.12.1", + "@react-aria/interactions": "^3.22.1", + "@react-aria/utils": "^3.25.1", + "@react-stately/list": "^3.10.7", + "@react-types/actiongroup": "^3.4.11", + "@react-types/shared": "^3.24.1", "@swc/helpers": "^0.5.0" }, "peerDependencies": { - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0", - "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0", + "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" } }, "node_modules/@react-aria/breadcrumbs": { - "version": "3.5.13", - "resolved": "https://registry.npmjs.org/@react-aria/breadcrumbs/-/breadcrumbs-3.5.13.tgz", - "integrity": "sha512-G1Gqf/P6kVdfs94ovwP18fTWuIxadIQgHsXS08JEVcFVYMjb9YjqnEBaohUxD1tq2WldMbYw53ahQblT4NTG+g==", - "dependencies": { - "@react-aria/i18n": "^3.11.1", - "@react-aria/link": "^3.7.1", - "@react-aria/utils": "^3.24.1", - "@react-types/breadcrumbs": "^3.7.5", - "@react-types/shared": "^3.23.1", + "version": "3.5.15", + "resolved": "https://registry.npmjs.org/@react-aria/breadcrumbs/-/breadcrumbs-3.5.15.tgz", + "integrity": "sha512-KJ7678hwKbacz6dyY4aOJlgtV91PtuSnlWGR+AsK88WwHhpjjTjLLTSRepjbQ35GuQuoYokM4mmfaS/I0nblhw==", + "dependencies": { + "@react-aria/i18n": "^3.12.1", + "@react-aria/link": "^3.7.3", + "@react-aria/utils": "^3.25.1", + "@react-types/breadcrumbs": "^3.7.7", + "@react-types/shared": "^3.24.1", "@swc/helpers": "^0.5.0" }, "peerDependencies": { - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" } }, "node_modules/@react-aria/button": { - "version": "3.9.5", - "resolved": "https://registry.npmjs.org/@react-aria/button/-/button-3.9.5.tgz", - "integrity": "sha512-dgcYR6j8WDOMLKuVrtxzx4jIC05cVKDzc+HnPO8lNkBAOfjcuN5tkGRtIjLtqjMvpZHhQT5aDbgFpIaZzxgFIg==", - "dependencies": { - "@react-aria/focus": "^3.17.1", - "@react-aria/interactions": "^3.21.3", - "@react-aria/utils": "^3.24.1", - "@react-stately/toggle": "^3.7.4", - "@react-types/button": "^3.9.4", - "@react-types/shared": "^3.23.1", + "version": "3.9.7", + "resolved": "https://registry.npmjs.org/@react-aria/button/-/button-3.9.7.tgz", + "integrity": "sha512-xwE6uatbbn3KbNSc0dyDnOo539HJM2cqCPfjiQGt8O9cFbpQSmx76Fj4WotU3BwT7ZVbcAC8D206CgF1C2cDcQ==", + "dependencies": { + "@react-aria/focus": "^3.18.1", + "@react-aria/interactions": "^3.22.1", + "@react-aria/utils": "^3.25.1", + "@react-stately/toggle": "^3.7.6", + "@react-types/button": "^3.9.6", + "@react-types/shared": "^3.24.1", "@swc/helpers": "^0.5.0" }, "peerDependencies": { - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" } }, "node_modules/@react-aria/calendar": { - "version": "3.5.8", - "resolved": "https://registry.npmjs.org/@react-aria/calendar/-/calendar-3.5.8.tgz", - "integrity": "sha512-Whlp4CeAA5/ZkzrAHUv73kgIRYjw088eYGSc+cvSOCxfrc/2XkBm9rNrnSBv0DvhJ8AG0Fjz3vYakTmF3BgZBw==", + "version": "3.5.10", + "resolved": "https://registry.npmjs.org/@react-aria/calendar/-/calendar-3.5.10.tgz", + "integrity": "sha512-5PokdIHAH+CAd6vMHFW9mg77I5tC0FQglYsCEI9ikhCnL5xlt3FmJjLtOs3UJQaWgrd4cdVd0oINpPafJ9ydhA==", "dependencies": { - "@internationalized/date": "^3.5.4", - "@react-aria/i18n": "^3.11.1", - "@react-aria/interactions": "^3.21.3", + "@internationalized/date": "^3.5.5", + "@react-aria/i18n": "^3.12.1", + "@react-aria/interactions": "^3.22.1", "@react-aria/live-announcer": "^3.3.4", - "@react-aria/utils": "^3.24.1", - "@react-stately/calendar": "^3.5.1", - "@react-types/button": "^3.9.4", - "@react-types/calendar": "^3.4.6", - "@react-types/shared": "^3.23.1", + "@react-aria/utils": "^3.25.1", + "@react-stately/calendar": "^3.5.3", + "@react-types/button": "^3.9.6", + "@react-types/calendar": "^3.4.8", + "@react-types/shared": "^3.24.1", "@swc/helpers": "^0.5.0" }, "peerDependencies": { - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0", - "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0", + "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" } }, "node_modules/@react-aria/checkbox": { - "version": "3.14.3", - "resolved": "https://registry.npmjs.org/@react-aria/checkbox/-/checkbox-3.14.3.tgz", - "integrity": "sha512-EtBJL6iu0gvrw3A4R7UeVLR6diaVk/mh4kFBc7c8hQjpEJweRr4hmJT3hrNg3MBcTWLxFiMEXPGgWEwXDBygtA==", - "dependencies": { - "@react-aria/form": "^3.0.5", - "@react-aria/interactions": "^3.21.3", - "@react-aria/label": "^3.7.8", - "@react-aria/toggle": "^3.10.4", - "@react-aria/utils": "^3.24.1", - "@react-stately/checkbox": "^3.6.5", - "@react-stately/form": "^3.0.3", - "@react-stately/toggle": "^3.7.4", - "@react-types/checkbox": "^3.8.1", - "@react-types/shared": "^3.23.1", + "version": "3.14.5", + "resolved": "https://registry.npmjs.org/@react-aria/checkbox/-/checkbox-3.14.5.tgz", + "integrity": "sha512-On8m66CNi1LvbDeDo355au0K66ayIjo0nDe4oe85aNsR/owyzz8hXNPAFuh98owQVMsKt4596FZICAVSMzzhJg==", + "dependencies": { + "@react-aria/form": "^3.0.7", + "@react-aria/interactions": "^3.22.1", + "@react-aria/label": "^3.7.10", + "@react-aria/toggle": "^3.10.6", + "@react-aria/utils": "^3.25.1", + "@react-stately/checkbox": "^3.6.7", + "@react-stately/form": "^3.0.5", + "@react-stately/toggle": "^3.7.6", + "@react-types/checkbox": "^3.8.3", + "@react-types/shared": "^3.24.1", "@swc/helpers": "^0.5.0" }, "peerDependencies": { - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/@react-aria/collections": { + "version": "3.0.0-alpha.3", + "resolved": "https://registry.npmjs.org/@react-aria/collections/-/collections-3.0.0-alpha.3.tgz", + "integrity": "sha512-SKsoQrCuz4zIVMwKGz0WcFoRbIP0H8+eRU2XzjmWX9KlRdrfeqIBOxuiU8XO3or0aHdbBI/bC/YtCjVzix5Lrg==", + "dependencies": { + "@react-aria/ssr": "^3.9.5", + "@react-aria/utils": "^3.25.1", + "@react-types/shared": "^3.24.1", + "@swc/helpers": "^0.5.0", + "use-sync-external-store": "^1.2.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0", + "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" } }, "node_modules/@react-aria/color": { - "version": "3.0.0-beta.33", - "resolved": "https://registry.npmjs.org/@react-aria/color/-/color-3.0.0-beta.33.tgz", - "integrity": "sha512-nhqnIHYm5p6MbuF3cC6lnqzG7MjwBsBd0DtpO+ByFYO+zxpMMbeC5R+1SFxvapR4uqmAzTotbtiUCGsG+SUaIg==", - "dependencies": { - "@react-aria/i18n": "^3.11.1", - "@react-aria/interactions": "^3.21.3", - "@react-aria/numberfield": "^3.11.3", - "@react-aria/slider": "^3.7.8", - "@react-aria/spinbutton": "^3.6.5", - "@react-aria/textfield": "^3.14.5", - "@react-aria/utils": "^3.24.1", - "@react-aria/visually-hidden": "^3.8.12", - "@react-stately/color": "^3.6.1", - "@react-stately/form": "^3.0.3", - "@react-types/color": "3.0.0-beta.25", - "@react-types/shared": "^3.23.1", + "version": "3.0.0-rc.1", + "resolved": "https://registry.npmjs.org/@react-aria/color/-/color-3.0.0-rc.1.tgz", + "integrity": "sha512-oP9PE0Xpo9uQ/TtH1x8iWhsjtk4OTIoTFdQZyoDsj8d84sqRv6Og9ajBZ/VTaneNK1n4NrPSx+qWfXu+SrWlDg==", + "dependencies": { + "@react-aria/i18n": "^3.12.1", + "@react-aria/interactions": "^3.22.1", + "@react-aria/numberfield": "^3.11.5", + "@react-aria/slider": "^3.7.10", + "@react-aria/spinbutton": "^3.6.7", + "@react-aria/textfield": "^3.14.7", + "@react-aria/utils": "^3.25.1", + "@react-aria/visually-hidden": "^3.8.14", + "@react-stately/color": "^3.7.1", + "@react-stately/form": "^3.0.5", + "@react-types/color": "3.0.0-rc.1", + "@react-types/shared": "^3.24.1", "@swc/helpers": "^0.5.0" }, "peerDependencies": { - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0", - "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0", + "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" } }, "node_modules/@react-aria/combobox": { - "version": "3.9.1", - "resolved": "https://registry.npmjs.org/@react-aria/combobox/-/combobox-3.9.1.tgz", - "integrity": "sha512-SpK92dCmT8qn8aEcUAihRQrBb5LZUhwIbDExFII8PvUvEFy/PoQHXIo3j1V29WkutDBDpMvBv/6XRCHGXPqrhQ==", + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/@react-aria/combobox/-/combobox-3.10.1.tgz", + "integrity": "sha512-B0zjX66HEqjPFnunYR0quAqwVJ6U0ez1eqBp25/611Dtzh3JHUovQmTE0xGGTjRe6N6qJg0VHVr2eRO/D0A+Lw==", "dependencies": { - "@react-aria/i18n": "^3.11.1", - "@react-aria/listbox": "^3.12.1", + "@react-aria/i18n": "^3.12.1", + "@react-aria/listbox": "^3.13.1", "@react-aria/live-announcer": "^3.3.4", - "@react-aria/menu": "^3.14.1", - "@react-aria/overlays": "^3.22.1", - "@react-aria/selection": "^3.18.1", - "@react-aria/textfield": "^3.14.5", - "@react-aria/utils": "^3.24.1", - "@react-stately/collections": "^3.10.7", - "@react-stately/combobox": "^3.8.4", - "@react-stately/form": "^3.0.3", - "@react-types/button": "^3.9.4", - "@react-types/combobox": "^3.11.1", - "@react-types/shared": "^3.23.1", + "@react-aria/menu": "^3.15.1", + "@react-aria/overlays": "^3.23.1", + "@react-aria/selection": "^3.19.1", + "@react-aria/textfield": "^3.14.7", + "@react-aria/utils": "^3.25.1", + "@react-stately/collections": "^3.10.9", + "@react-stately/combobox": "^3.9.1", + "@react-stately/form": "^3.0.5", + "@react-types/button": "^3.9.6", + "@react-types/combobox": "^3.12.1", + "@react-types/shared": "^3.24.1", "@swc/helpers": "^0.5.0" }, "peerDependencies": { - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0", - "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0", + "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" } }, "node_modules/@react-aria/datepicker": { - "version": "3.10.1", - "resolved": "https://registry.npmjs.org/@react-aria/datepicker/-/datepicker-3.10.1.tgz", - "integrity": "sha512-4HZL593nrNMa1GjBmWEN/OTvNS6d3/16G1YJWlqiUlv11ADulSbqBIjMmkgwrJVFcjrgqtXFy+yyrTA/oq94Zw==", + "version": "3.11.1", + "resolved": "https://registry.npmjs.org/@react-aria/datepicker/-/datepicker-3.11.1.tgz", + "integrity": "sha512-yEEuDt/ynt7bTfd/9RD1EiLPysWhbgSYSpn5PHVz7I2XORvNPpyamyAgz3+oFiLFLC/zy0qrG7e6V1rvI1NBzw==", "dependencies": { - "@internationalized/date": "^3.5.4", + "@internationalized/date": "^3.5.5", "@internationalized/number": "^3.5.3", "@internationalized/string": "^3.2.3", - "@react-aria/focus": "^3.17.1", - "@react-aria/form": "^3.0.5", - "@react-aria/i18n": "^3.11.1", - "@react-aria/interactions": "^3.21.3", - "@react-aria/label": "^3.7.8", - "@react-aria/spinbutton": "^3.6.5", - "@react-aria/utils": "^3.24.1", - "@react-stately/datepicker": "^3.9.4", - "@react-stately/form": "^3.0.3", - "@react-types/button": "^3.9.4", - "@react-types/calendar": "^3.4.6", - "@react-types/datepicker": "^3.7.4", - "@react-types/dialog": "^3.5.10", - "@react-types/shared": "^3.23.1", + "@react-aria/focus": "^3.18.1", + "@react-aria/form": "^3.0.7", + "@react-aria/i18n": "^3.12.1", + "@react-aria/interactions": "^3.22.1", + "@react-aria/label": "^3.7.10", + "@react-aria/spinbutton": "^3.6.7", + "@react-aria/utils": "^3.25.1", + "@react-stately/datepicker": "^3.10.1", + "@react-stately/form": "^3.0.5", + "@react-types/button": "^3.9.6", + "@react-types/calendar": "^3.4.8", + "@react-types/datepicker": "^3.8.1", + "@react-types/dialog": "^3.5.12", + "@react-types/shared": "^3.24.1", "@swc/helpers": "^0.5.0" }, "peerDependencies": { - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0", - "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0", + "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" } }, "node_modules/@react-aria/dialog": { - "version": "3.5.14", - "resolved": "https://registry.npmjs.org/@react-aria/dialog/-/dialog-3.5.14.tgz", - "integrity": "sha512-oqDCjQ8hxe3GStf48XWBf2CliEnxlR9GgSYPHJPUc69WBj68D9rVcCW3kogJnLAnwIyf3FnzbX4wSjvUa88sAQ==", - "dependencies": { - "@react-aria/focus": "^3.17.1", - "@react-aria/overlays": "^3.22.1", - "@react-aria/utils": "^3.24.1", - "@react-types/dialog": "^3.5.10", - "@react-types/shared": "^3.23.1", + "version": "3.5.16", + "resolved": "https://registry.npmjs.org/@react-aria/dialog/-/dialog-3.5.16.tgz", + "integrity": "sha512-2clBSQQaoqCjAUkHnMA/noZ1ZnFbEVU67fL9M1QfokezAyLAlyCyD9XSed6+Td/Ncj80N3/Lax65XAlvWCyOlg==", + "dependencies": { + "@react-aria/focus": "^3.18.1", + "@react-aria/overlays": "^3.23.1", + "@react-aria/utils": "^3.25.1", + "@react-types/dialog": "^3.5.12", + "@react-types/shared": "^3.24.1", "@swc/helpers": "^0.5.0" }, "peerDependencies": { - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0", - "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0", + "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" } }, "node_modules/@react-aria/dnd": { - "version": "3.6.1", - "resolved": "https://registry.npmjs.org/@react-aria/dnd/-/dnd-3.6.1.tgz", - "integrity": "sha512-6WnujUTD+cIYZVF/B+uXdHyJ+WSpbYa8jH282epvY4FUAq1qLmen12/HHcoj/5dswKQe8X6EM3OhkQM89d9vFw==", + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/@react-aria/dnd/-/dnd-3.7.1.tgz", + "integrity": "sha512-p3/pc8p2fGd4s+Qj4SfRPJjZFStuuXqRNyDQxd9AAFYUWcCQxwDOqtiTZmfvs7Hvl0PUuysHW6Q5v7ABRjVr7w==", "dependencies": { "@internationalized/string": "^3.2.3", - "@react-aria/i18n": "^3.11.1", - "@react-aria/interactions": "^3.21.3", + "@react-aria/i18n": "^3.12.1", + "@react-aria/interactions": "^3.22.1", "@react-aria/live-announcer": "^3.3.4", - "@react-aria/overlays": "^3.22.1", - "@react-aria/utils": "^3.24.1", - "@react-stately/dnd": "^3.3.1", - "@react-types/button": "^3.9.4", - "@react-types/shared": "^3.23.1", + "@react-aria/overlays": "^3.23.1", + "@react-aria/utils": "^3.25.1", + "@react-stately/dnd": "^3.4.1", + "@react-types/button": "^3.9.6", + "@react-types/shared": "^3.24.1", "@swc/helpers": "^0.5.0" }, "peerDependencies": { - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0", - "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0", + "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" } }, "node_modules/@react-aria/focus": { - "version": "3.17.1", - "resolved": "https://registry.npmjs.org/@react-aria/focus/-/focus-3.17.1.tgz", - "integrity": "sha512-FLTySoSNqX++u0nWZJPPN5etXY0WBxaIe/YuL/GTEeuqUIuC/2bJSaw5hlsM6T2yjy6Y/VAxBcKSdAFUlU6njQ==", + "version": "3.18.1", + "resolved": "https://registry.npmjs.org/@react-aria/focus/-/focus-3.18.1.tgz", + "integrity": "sha512-N0Cy61WCIv+57mbqC7hiZAsB+3rF5n4JKabxUmg/2RTJL6lq7hJ5N4gx75ymKxkN8GnVDwt4pKZah48Wopa5jw==", "dependencies": { - "@react-aria/interactions": "^3.21.3", - "@react-aria/utils": "^3.24.1", - "@react-types/shared": "^3.23.1", + "@react-aria/interactions": "^3.22.1", + "@react-aria/utils": "^3.25.1", + "@react-types/shared": "^3.24.1", "@swc/helpers": "^0.5.0", "clsx": "^2.0.0" }, "peerDependencies": { - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" } }, "node_modules/@react-aria/form": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/@react-aria/form/-/form-3.0.5.tgz", - "integrity": "sha512-n290jRwrrRXO3fS82MyWR+OKN7yznVesy5Q10IclSTVYHHI3VI53xtAPr/WzNjJR1um8aLhOcDNFKwnNIUUCsQ==", + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@react-aria/form/-/form-3.0.7.tgz", + "integrity": "sha512-VIsKP/KytJPOLRQl0NxWWS1bQELPBuW3vRjmmhBrtgPFmp0uCLhjPBkP6A4uIVj1E/JtAocyHN3DNq4+IJGQCg==", "dependencies": { - "@react-aria/interactions": "^3.21.3", - "@react-aria/utils": "^3.24.1", - "@react-stately/form": "^3.0.3", - "@react-types/shared": "^3.23.1", + "@react-aria/interactions": "^3.22.1", + "@react-aria/utils": "^3.25.1", + "@react-stately/form": "^3.0.5", + "@react-types/shared": "^3.24.1", "@swc/helpers": "^0.5.0" }, "peerDependencies": { - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" } }, "node_modules/@react-aria/grid": { - "version": "3.9.1", - "resolved": "https://registry.npmjs.org/@react-aria/grid/-/grid-3.9.1.tgz", - "integrity": "sha512-fGEZqAEaS8mqzV/II3N4ndoNWegIcbh+L3PmKbXdpKKUP8VgMs/WY5rYl5WAF0f5RoFwXqx3ibDLeR9tKj/bOg==", + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/@react-aria/grid/-/grid-3.10.1.tgz", + "integrity": "sha512-7dSgiYVQapBtPV4SIit+9fJ1qoEjtp+PXffJkWAPtGbg/jJ4b0jcVzykH7ARD4w/6jAJN/oVSfrKZqFPoLAd9w==", "dependencies": { - "@react-aria/focus": "^3.17.1", - "@react-aria/i18n": "^3.11.1", - "@react-aria/interactions": "^3.21.3", + "@react-aria/focus": "^3.18.1", + "@react-aria/i18n": "^3.12.1", + "@react-aria/interactions": "^3.22.1", "@react-aria/live-announcer": "^3.3.4", - "@react-aria/selection": "^3.18.1", - "@react-aria/utils": "^3.24.1", - "@react-stately/collections": "^3.10.7", - "@react-stately/grid": "^3.8.7", - "@react-stately/selection": "^3.15.1", - "@react-stately/virtualizer": "^3.7.1", - "@react-types/checkbox": "^3.8.1", - "@react-types/grid": "^3.2.6", - "@react-types/shared": "^3.23.1", + "@react-aria/selection": "^3.19.1", + "@react-aria/utils": "^3.25.1", + "@react-stately/collections": "^3.10.9", + "@react-stately/grid": "^3.9.1", + "@react-stately/selection": "^3.16.1", + "@react-types/checkbox": "^3.8.3", + "@react-types/grid": "^3.2.8", + "@react-types/shared": "^3.24.1", "@swc/helpers": "^0.5.0" }, "peerDependencies": { - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0", - "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0", + "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" } }, "node_modules/@react-aria/gridlist": { - "version": "3.8.1", - "resolved": "https://registry.npmjs.org/@react-aria/gridlist/-/gridlist-3.8.1.tgz", - "integrity": "sha512-vVPkkA+Ct0NDcpnNm/tnYaBumg0fP9pXxsPLqL1rxvsTyj1PaIpFTZ4corabPTbTDExZwUSTS3LG1n+o1OvBtQ==", - "dependencies": { - "@react-aria/focus": "^3.17.1", - "@react-aria/grid": "^3.9.1", - "@react-aria/i18n": "^3.11.1", - "@react-aria/interactions": "^3.21.3", - "@react-aria/selection": "^3.18.1", - "@react-aria/utils": "^3.24.1", - "@react-stately/collections": "^3.10.7", - "@react-stately/list": "^3.10.5", - "@react-stately/tree": "^3.8.1", - "@react-types/shared": "^3.23.1", + "version": "3.9.1", + "resolved": "https://registry.npmjs.org/@react-aria/gridlist/-/gridlist-3.9.1.tgz", + "integrity": "sha512-cue2KCI4WyVmL3j9tZx7xG7gUJ7UyRbawzRTcocJukOmpeoyRaw/robrIYK2Pd//GhRbIMAoo4iOyZk5j7vEww==", + "dependencies": { + "@react-aria/focus": "^3.18.1", + "@react-aria/grid": "^3.10.1", + "@react-aria/i18n": "^3.12.1", + "@react-aria/interactions": "^3.22.1", + "@react-aria/selection": "^3.19.1", + "@react-aria/utils": "^3.25.1", + "@react-stately/collections": "^3.10.9", + "@react-stately/list": "^3.10.7", + "@react-stately/tree": "^3.8.3", + "@react-types/shared": "^3.24.1", "@swc/helpers": "^0.5.0" }, "peerDependencies": { - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0", - "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0", + "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" } }, "node_modules/@react-aria/i18n": { - "version": "3.11.1", - "resolved": "https://registry.npmjs.org/@react-aria/i18n/-/i18n-3.11.1.tgz", - "integrity": "sha512-vuiBHw1kZruNMYeKkTGGnmPyMnM5T+gT8bz97H1FqIq1hQ6OPzmtBZ6W6l6OIMjeHI5oJo4utTwfZl495GALFQ==", + "version": "3.12.1", + "resolved": "https://registry.npmjs.org/@react-aria/i18n/-/i18n-3.12.1.tgz", + "integrity": "sha512-0q3gyogF9Ekah+9LOo6tcfshxsk2Ope+KdbtFHJVhznedMxn6RpHGcVur5ImbQ1dYafA5CmjBUGJW70b56+BGA==", "dependencies": { - "@internationalized/date": "^3.5.4", + "@internationalized/date": "^3.5.5", "@internationalized/message": "^3.1.4", "@internationalized/number": "^3.5.3", "@internationalized/string": "^3.2.3", - "@react-aria/ssr": "^3.9.4", - "@react-aria/utils": "^3.24.1", - "@react-types/shared": "^3.23.1", + "@react-aria/ssr": "^3.9.5", + "@react-aria/utils": "^3.25.1", + "@react-types/shared": "^3.24.1", "@swc/helpers": "^0.5.0" }, "peerDependencies": { - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" } }, "node_modules/@react-aria/interactions": { - "version": "3.21.3", - "resolved": "https://registry.npmjs.org/@react-aria/interactions/-/interactions-3.21.3.tgz", - "integrity": "sha512-BWIuf4qCs5FreDJ9AguawLVS0lV9UU+sK4CCnbCNNmYqOWY+1+gRXCsnOM32K+oMESBxilAjdHW5n1hsMqYMpA==", + "version": "3.22.1", + "resolved": "https://registry.npmjs.org/@react-aria/interactions/-/interactions-3.22.1.tgz", + "integrity": "sha512-5TLzQaDAQQ5C70yG8GInbO4wIylKY67RfTIIwQPGR/4n5OIjbUD8BOj3NuSsuZ/frUPaBXo1VEBBmSO23fxkjw==", "dependencies": { - "@react-aria/ssr": "^3.9.4", - "@react-aria/utils": "^3.24.1", - "@react-types/shared": "^3.23.1", + "@react-aria/ssr": "^3.9.5", + "@react-aria/utils": "^3.25.1", + "@react-types/shared": "^3.24.1", "@swc/helpers": "^0.5.0" }, "peerDependencies": { - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" } }, "node_modules/@react-aria/label": { - "version": "3.7.8", - "resolved": "https://registry.npmjs.org/@react-aria/label/-/label-3.7.8.tgz", - "integrity": "sha512-MzgTm5+suPA3KX7Ug6ZBK2NX9cin/RFLsv1BdafJ6CZpmUSpWnGE/yQfYUB7csN7j31OsZrD3/P56eShYWAQfg==", + "version": "3.7.10", + "resolved": "https://registry.npmjs.org/@react-aria/label/-/label-3.7.10.tgz", + "integrity": "sha512-e5XVHA+OUK0aIwr4nHcnIj0z1kUryGaJWYYD2OGkkIltyUCKmwpRqdx8LQYbO4HGsJhvC3hJgidFdGcQwHHPYw==", "dependencies": { - "@react-aria/utils": "^3.24.1", - "@react-types/shared": "^3.23.1", + "@react-aria/utils": "^3.25.1", + "@react-types/shared": "^3.24.1", "@swc/helpers": "^0.5.0" }, "peerDependencies": { - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" } }, "node_modules/@react-aria/link": { - "version": "3.7.1", - "resolved": "https://registry.npmjs.org/@react-aria/link/-/link-3.7.1.tgz", - "integrity": "sha512-a4IaV50P3fXc7DQvEIPYkJJv26JknFbRzFT5MJOMgtzuhyJoQdILEUK6XHYjcSSNCA7uLgzpojArVk5Hz3lCpw==", - "dependencies": { - "@react-aria/focus": "^3.17.1", - "@react-aria/interactions": "^3.21.3", - "@react-aria/utils": "^3.24.1", - "@react-types/link": "^3.5.5", - "@react-types/shared": "^3.23.1", + "version": "3.7.3", + "resolved": "https://registry.npmjs.org/@react-aria/link/-/link-3.7.3.tgz", + "integrity": "sha512-dOwzxzo7LF4djBfRC8GcIhuTpDkNUIMT6ykQRV1a3749kgrr10YLascsO/l66k60i2k0T2oClkzfefYEK6WZeA==", + "dependencies": { + "@react-aria/focus": "^3.18.1", + "@react-aria/interactions": "^3.22.1", + "@react-aria/utils": "^3.25.1", + "@react-types/link": "^3.5.7", + "@react-types/shared": "^3.24.1", "@swc/helpers": "^0.5.0" }, "peerDependencies": { - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" } }, "node_modules/@react-aria/listbox": { - "version": "3.12.1", - "resolved": "https://registry.npmjs.org/@react-aria/listbox/-/listbox-3.12.1.tgz", - "integrity": "sha512-7JiUp0NGykbv/HgSpmTY1wqhuf/RmjFxs1HZcNaTv8A+DlzgJYc7yQqFjP3ZA/z5RvJFuuIxggIYmgIFjaRYdA==", - "dependencies": { - "@react-aria/interactions": "^3.21.3", - "@react-aria/label": "^3.7.8", - "@react-aria/selection": "^3.18.1", - "@react-aria/utils": "^3.24.1", - "@react-stately/collections": "^3.10.7", - "@react-stately/list": "^3.10.5", - "@react-types/listbox": "^3.4.9", - "@react-types/shared": "^3.23.1", + "version": "3.13.1", + "resolved": "https://registry.npmjs.org/@react-aria/listbox/-/listbox-3.13.1.tgz", + "integrity": "sha512-b5Nu+5d5shJbxpy4s6OXvMlMzm+PVbs3L6CtoHlsKe8cAlSWD340vPHCOGYLwZApIBewepOBvRWgeAF8IDI04w==", + "dependencies": { + "@react-aria/interactions": "^3.22.1", + "@react-aria/label": "^3.7.10", + "@react-aria/selection": "^3.19.1", + "@react-aria/utils": "^3.25.1", + "@react-stately/collections": "^3.10.9", + "@react-stately/list": "^3.10.7", + "@react-types/listbox": "^3.5.1", + "@react-types/shared": "^3.24.1", "@swc/helpers": "^0.5.0" }, "peerDependencies": { - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0", - "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0", + "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" } }, "node_modules/@react-aria/live-announcer": { @@ -4525,237 +4524,237 @@ } }, "node_modules/@react-aria/menu": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/@react-aria/menu/-/menu-3.14.1.tgz", - "integrity": "sha512-BYliRb38uAzq05UOFcD5XkjA5foQoXRbcH3ZufBsc4kvh79BcP1PMW6KsXKGJ7dC/PJWUwCui6QL1kUg8PqMHA==", - "dependencies": { - "@react-aria/focus": "^3.17.1", - "@react-aria/i18n": "^3.11.1", - "@react-aria/interactions": "^3.21.3", - "@react-aria/overlays": "^3.22.1", - "@react-aria/selection": "^3.18.1", - "@react-aria/utils": "^3.24.1", - "@react-stately/collections": "^3.10.7", - "@react-stately/menu": "^3.7.1", - "@react-stately/tree": "^3.8.1", - "@react-types/button": "^3.9.4", - "@react-types/menu": "^3.9.9", - "@react-types/shared": "^3.23.1", + "version": "3.15.1", + "resolved": "https://registry.npmjs.org/@react-aria/menu/-/menu-3.15.1.tgz", + "integrity": "sha512-ZBTMZiJ17j6t7epcsjd0joAzsMKO31KLJHPtWAEfk1JkBxrMoirISPN8O1CeK/uBX++VaWSrDZfFe1EjrOwKuA==", + "dependencies": { + "@react-aria/focus": "^3.18.1", + "@react-aria/i18n": "^3.12.1", + "@react-aria/interactions": "^3.22.1", + "@react-aria/overlays": "^3.23.1", + "@react-aria/selection": "^3.19.1", + "@react-aria/utils": "^3.25.1", + "@react-stately/collections": "^3.10.9", + "@react-stately/menu": "^3.8.1", + "@react-stately/tree": "^3.8.3", + "@react-types/button": "^3.9.6", + "@react-types/menu": "^3.9.11", + "@react-types/shared": "^3.24.1", "@swc/helpers": "^0.5.0" }, "peerDependencies": { - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0", - "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0", + "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" } }, "node_modules/@react-aria/meter": { - "version": "3.4.13", - "resolved": "https://registry.npmjs.org/@react-aria/meter/-/meter-3.4.13.tgz", - "integrity": "sha512-oG6KvHQM3ri93XkYQkgEaMKSMO9KNDVpcW1MUqFfqyUXHFBRZRrJB4BTXMZ4nyjheFVQjVboU51fRwoLjOzThg==", + "version": "3.4.15", + "resolved": "https://registry.npmjs.org/@react-aria/meter/-/meter-3.4.15.tgz", + "integrity": "sha512-OUAzgmfiyEvBF+h9NlG7s8jvrGNTqj/zAWyUWEh5FMEjKFrDfni6awwFoRs164QqmUvRBNC0/eKv3Ghd2GIkRA==", "dependencies": { - "@react-aria/progress": "^3.4.13", - "@react-types/meter": "^3.4.1", - "@react-types/shared": "^3.23.1", + "@react-aria/progress": "^3.4.15", + "@react-types/meter": "^3.4.3", + "@react-types/shared": "^3.24.1", "@swc/helpers": "^0.5.0" }, "peerDependencies": { - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" } }, "node_modules/@react-aria/numberfield": { - "version": "3.11.3", - "resolved": "https://registry.npmjs.org/@react-aria/numberfield/-/numberfield-3.11.3.tgz", - "integrity": "sha512-QQ9ZTzBbRI8d9ksaBWm6YVXbgv+5zzUsdxVxwzJVXLznvivoORB8rpdFJzUEWVCo25lzoBxluCEPYtLOxP1B0w==", - "dependencies": { - "@react-aria/i18n": "^3.11.1", - "@react-aria/interactions": "^3.21.3", - "@react-aria/spinbutton": "^3.6.5", - "@react-aria/textfield": "^3.14.5", - "@react-aria/utils": "^3.24.1", - "@react-stately/form": "^3.0.3", - "@react-stately/numberfield": "^3.9.3", - "@react-types/button": "^3.9.4", - "@react-types/numberfield": "^3.8.3", - "@react-types/shared": "^3.23.1", + "version": "3.11.5", + "resolved": "https://registry.npmjs.org/@react-aria/numberfield/-/numberfield-3.11.5.tgz", + "integrity": "sha512-cfJzU7SWsksKiLjfubSj5lR18ebQ7IbYaMQZbxdpZSPOANHIiktaxjPK4Nz7cqZ+HZ/6tQEirpY0iqpLx35CSw==", + "dependencies": { + "@react-aria/i18n": "^3.12.1", + "@react-aria/interactions": "^3.22.1", + "@react-aria/spinbutton": "^3.6.7", + "@react-aria/textfield": "^3.14.7", + "@react-aria/utils": "^3.25.1", + "@react-stately/form": "^3.0.5", + "@react-stately/numberfield": "^3.9.5", + "@react-types/button": "^3.9.6", + "@react-types/numberfield": "^3.8.5", + "@react-types/shared": "^3.24.1", "@swc/helpers": "^0.5.0" }, "peerDependencies": { - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0", - "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0", + "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" } }, "node_modules/@react-aria/overlays": { - "version": "3.22.1", - "resolved": "https://registry.npmjs.org/@react-aria/overlays/-/overlays-3.22.1.tgz", - "integrity": "sha512-GHiFMWO4EQ6+j6b5QCnNoOYiyx1Gk8ZiwLzzglCI4q1NY5AG2EAmfU4Z1+Gtrf2S5Y0zHbumC7rs9GnPoGLUYg==", - "dependencies": { - "@react-aria/focus": "^3.17.1", - "@react-aria/i18n": "^3.11.1", - "@react-aria/interactions": "^3.21.3", - "@react-aria/ssr": "^3.9.4", - "@react-aria/utils": "^3.24.1", - "@react-aria/visually-hidden": "^3.8.12", - "@react-stately/overlays": "^3.6.7", - "@react-types/button": "^3.9.4", - "@react-types/overlays": "^3.8.7", - "@react-types/shared": "^3.23.1", + "version": "3.23.1", + "resolved": "https://registry.npmjs.org/@react-aria/overlays/-/overlays-3.23.1.tgz", + "integrity": "sha512-qNV3pGThvRXjhdHCfqN9Eg4uD+nFm2DoK6d5e9LFd1+xCkKbT88afDBIcLmeG7fgfmukb1sNmzCJQJt8Svk54g==", + "dependencies": { + "@react-aria/focus": "^3.18.1", + "@react-aria/i18n": "^3.12.1", + "@react-aria/interactions": "^3.22.1", + "@react-aria/ssr": "^3.9.5", + "@react-aria/utils": "^3.25.1", + "@react-aria/visually-hidden": "^3.8.14", + "@react-stately/overlays": "^3.6.9", + "@react-types/button": "^3.9.6", + "@react-types/overlays": "^3.8.9", + "@react-types/shared": "^3.24.1", "@swc/helpers": "^0.5.0" }, "peerDependencies": { - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0", - "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0", + "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" } }, "node_modules/@react-aria/progress": { - "version": "3.4.13", - "resolved": "https://registry.npmjs.org/@react-aria/progress/-/progress-3.4.13.tgz", - "integrity": "sha512-YBV9bOO5JzKvG8QCI0IAA00o6FczMgIDiK8Q9p5gKorFMatFUdRayxlbIPoYHMi+PguLil0jHgC7eOyaUcrZ0g==", - "dependencies": { - "@react-aria/i18n": "^3.11.1", - "@react-aria/label": "^3.7.8", - "@react-aria/utils": "^3.24.1", - "@react-types/progress": "^3.5.4", - "@react-types/shared": "^3.23.1", + "version": "3.4.15", + "resolved": "https://registry.npmjs.org/@react-aria/progress/-/progress-3.4.15.tgz", + "integrity": "sha512-wlx8pgEet3mlq5Skjy7yV1DfQiEg79tZtojpb5YGN2dIAH8sxClrKOSJRVce0fy9IXVCKrQxjQNXPNUIojK5Rg==", + "dependencies": { + "@react-aria/i18n": "^3.12.1", + "@react-aria/label": "^3.7.10", + "@react-aria/utils": "^3.25.1", + "@react-types/progress": "^3.5.6", + "@react-types/shared": "^3.24.1", "@swc/helpers": "^0.5.0" }, "peerDependencies": { - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" } }, "node_modules/@react-aria/radio": { - "version": "3.10.4", - "resolved": "https://registry.npmjs.org/@react-aria/radio/-/radio-3.10.4.tgz", - "integrity": "sha512-3fmoMcQtCpgjTwJReFjnvIE/C7zOZeCeWUn4JKDqz9s1ILYsC3Rk5zZ4q66tFn6v+IQnecrKT52wH6+hlVLwTA==", - "dependencies": { - "@react-aria/focus": "^3.17.1", - "@react-aria/form": "^3.0.5", - "@react-aria/i18n": "^3.11.1", - "@react-aria/interactions": "^3.21.3", - "@react-aria/label": "^3.7.8", - "@react-aria/utils": "^3.24.1", - "@react-stately/radio": "^3.10.4", - "@react-types/radio": "^3.8.1", - "@react-types/shared": "^3.23.1", + "version": "3.10.6", + "resolved": "https://registry.npmjs.org/@react-aria/radio/-/radio-3.10.6.tgz", + "integrity": "sha512-Cr7kiTUWw+HOEdFHztqrFlSXvwuzOCTMbwNkziTyc9fualIX6UDilykND2ctfBgkM4qH7SgQt+SxAIwTdevsKg==", + "dependencies": { + "@react-aria/focus": "^3.18.1", + "@react-aria/form": "^3.0.7", + "@react-aria/i18n": "^3.12.1", + "@react-aria/interactions": "^3.22.1", + "@react-aria/label": "^3.7.10", + "@react-aria/utils": "^3.25.1", + "@react-stately/radio": "^3.10.6", + "@react-types/radio": "^3.8.3", + "@react-types/shared": "^3.24.1", "@swc/helpers": "^0.5.0" }, "peerDependencies": { - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" } }, "node_modules/@react-aria/searchfield": { - "version": "3.7.5", - "resolved": "https://registry.npmjs.org/@react-aria/searchfield/-/searchfield-3.7.5.tgz", - "integrity": "sha512-h1sMUOWjhevaKKUHab/luHbM6yiyeN57L4RxZU0IIc9Ww0h5Rp2GUuKZA3pcdPiExHje0aijcImL3wBHEbKAzw==", - "dependencies": { - "@react-aria/i18n": "^3.11.1", - "@react-aria/textfield": "^3.14.5", - "@react-aria/utils": "^3.24.1", - "@react-stately/searchfield": "^3.5.3", - "@react-types/button": "^3.9.4", - "@react-types/searchfield": "^3.5.5", - "@react-types/shared": "^3.23.1", + "version": "3.7.7", + "resolved": "https://registry.npmjs.org/@react-aria/searchfield/-/searchfield-3.7.7.tgz", + "integrity": "sha512-2f087PCR8X5LYyLnvjCIOV27xjjTCkDFPnQaC7XSPCfzDYGM8utCR56JfZMqHnjcMnVNoiEg7EjSBBrh7I2bnQ==", + "dependencies": { + "@react-aria/i18n": "^3.12.1", + "@react-aria/textfield": "^3.14.7", + "@react-aria/utils": "^3.25.1", + "@react-stately/searchfield": "^3.5.5", + "@react-types/button": "^3.9.6", + "@react-types/searchfield": "^3.5.7", + "@react-types/shared": "^3.24.1", "@swc/helpers": "^0.5.0" }, "peerDependencies": { - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" } }, "node_modules/@react-aria/select": { - "version": "3.14.5", - "resolved": "https://registry.npmjs.org/@react-aria/select/-/select-3.14.5.tgz", - "integrity": "sha512-s8jixBuTUNdKWRHe2tIJqp55ORHeUObGMw1s7PQRRVrrHPdNSYseAOI9B2W7qpl3hKhvjJg40UW+45mcb1WKbw==", - "dependencies": { - "@react-aria/form": "^3.0.5", - "@react-aria/i18n": "^3.11.1", - "@react-aria/interactions": "^3.21.3", - "@react-aria/label": "^3.7.8", - "@react-aria/listbox": "^3.12.1", - "@react-aria/menu": "^3.14.1", - "@react-aria/selection": "^3.18.1", - "@react-aria/utils": "^3.24.1", - "@react-aria/visually-hidden": "^3.8.12", - "@react-stately/select": "^3.6.4", - "@react-types/button": "^3.9.4", - "@react-types/select": "^3.9.4", - "@react-types/shared": "^3.23.1", + "version": "3.14.7", + "resolved": "https://registry.npmjs.org/@react-aria/select/-/select-3.14.7.tgz", + "integrity": "sha512-qZy5oX6P8SGrdv4bHb8iVMIVv+vLuo7UwOJtsQ1FUORIsZmBEz0RyfgYdzlueMcZNoQ9JgLYtrK2e0h6AmJOlg==", + "dependencies": { + "@react-aria/form": "^3.0.7", + "@react-aria/i18n": "^3.12.1", + "@react-aria/interactions": "^3.22.1", + "@react-aria/label": "^3.7.10", + "@react-aria/listbox": "^3.13.1", + "@react-aria/menu": "^3.15.1", + "@react-aria/selection": "^3.19.1", + "@react-aria/utils": "^3.25.1", + "@react-aria/visually-hidden": "^3.8.14", + "@react-stately/select": "^3.6.6", + "@react-types/button": "^3.9.6", + "@react-types/select": "^3.9.6", + "@react-types/shared": "^3.24.1", "@swc/helpers": "^0.5.0" }, "peerDependencies": { - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0", - "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0", + "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" } }, "node_modules/@react-aria/selection": { - "version": "3.18.1", - "resolved": "https://registry.npmjs.org/@react-aria/selection/-/selection-3.18.1.tgz", - "integrity": "sha512-GSqN2jX6lh7v+ldqhVjAXDcrWS3N4IsKXxO6L6Ygsye86Q9q9Mq9twWDWWu5IjHD6LoVZLUBCMO+ENGbOkyqeQ==", - "dependencies": { - "@react-aria/focus": "^3.17.1", - "@react-aria/i18n": "^3.11.1", - "@react-aria/interactions": "^3.21.3", - "@react-aria/utils": "^3.24.1", - "@react-stately/selection": "^3.15.1", - "@react-types/shared": "^3.23.1", + "version": "3.19.1", + "resolved": "https://registry.npmjs.org/@react-aria/selection/-/selection-3.19.1.tgz", + "integrity": "sha512-mbExvq2Omi60sTWFGjwcNz1ja2P8VDsxWAqSypHRTyqXhtgqbv8V/v8Gp+7BmVPH1YHcbhztl6rvUZTDOSszzw==", + "dependencies": { + "@react-aria/focus": "^3.18.1", + "@react-aria/i18n": "^3.12.1", + "@react-aria/interactions": "^3.22.1", + "@react-aria/utils": "^3.25.1", + "@react-stately/selection": "^3.16.1", + "@react-types/shared": "^3.24.1", "@swc/helpers": "^0.5.0" }, "peerDependencies": { - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0", - "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0", + "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" } }, "node_modules/@react-aria/separator": { - "version": "3.3.13", - "resolved": "https://registry.npmjs.org/@react-aria/separator/-/separator-3.3.13.tgz", - "integrity": "sha512-hofA6JCPnAOqSE9vxnq7Dkazr7Kb2A0I5sR16fOG7ddjYRc/YEY5Nv7MWfKUGU0kNFHkgNjsDAILERtLechzeA==", + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/@react-aria/separator/-/separator-3.4.1.tgz", + "integrity": "sha512-bZ+GQ936Y+WXAtsQjJdEMgYeqmqjhU90+wOlRGjmGdwf+/ht2yzBpeRuHEYUbE6F0iis/YoVc+b8ppAtPna/kA==", "dependencies": { - "@react-aria/utils": "^3.24.1", - "@react-types/shared": "^3.23.1", + "@react-aria/utils": "^3.25.1", + "@react-types/shared": "^3.24.1", "@swc/helpers": "^0.5.0" }, "peerDependencies": { - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" } }, "node_modules/@react-aria/slider": { - "version": "3.7.8", - "resolved": "https://registry.npmjs.org/@react-aria/slider/-/slider-3.7.8.tgz", - "integrity": "sha512-MYvPcM0K8jxEJJicUK2+WxUkBIM/mquBxOTOSSIL3CszA80nXIGVnLlCUnQV3LOUzpWtabbWaZokSPtGgOgQOw==", - "dependencies": { - "@react-aria/focus": "^3.17.1", - "@react-aria/i18n": "^3.11.1", - "@react-aria/interactions": "^3.21.3", - "@react-aria/label": "^3.7.8", - "@react-aria/utils": "^3.24.1", - "@react-stately/slider": "^3.5.4", - "@react-types/shared": "^3.23.1", - "@react-types/slider": "^3.7.3", + "version": "3.7.10", + "resolved": "https://registry.npmjs.org/@react-aria/slider/-/slider-3.7.10.tgz", + "integrity": "sha512-QmBn87sDkncS/uhcrH0MxUN7bcEo8cHYcWk+gk7mibdIpyxyVDPKh7v7ZsosmAJLzjS0yb2ec1/Q5Oldfg1k/A==", + "dependencies": { + "@react-aria/focus": "^3.18.1", + "@react-aria/i18n": "^3.12.1", + "@react-aria/interactions": "^3.22.1", + "@react-aria/label": "^3.7.10", + "@react-aria/utils": "^3.25.1", + "@react-stately/slider": "^3.5.6", + "@react-types/shared": "^3.24.1", + "@react-types/slider": "^3.7.5", "@swc/helpers": "^0.5.0" }, "peerDependencies": { - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" } }, "node_modules/@react-aria/spinbutton": { - "version": "3.6.5", - "resolved": "https://registry.npmjs.org/@react-aria/spinbutton/-/spinbutton-3.6.5.tgz", - "integrity": "sha512-0aACBarF/Xr/7ixzjVBTQ0NBwwwsoGkf5v6AVFVMTC0uYMXHTALvRs+ULHjHMa5e/cX/aPlEvaVT7jfSs+Xy9Q==", + "version": "3.6.7", + "resolved": "https://registry.npmjs.org/@react-aria/spinbutton/-/spinbutton-3.6.7.tgz", + "integrity": "sha512-OCimp4yXoFIgh6WAMOls5DDDRDRO75ZFic3YA6wLWTRNHxo1Lj8S90i1A6pakY6bi4hdBCKmj4DnFSNKAw1iWg==", "dependencies": { - "@react-aria/i18n": "^3.11.1", + "@react-aria/i18n": "^3.12.1", "@react-aria/live-announcer": "^3.3.4", - "@react-aria/utils": "^3.24.1", - "@react-types/button": "^3.9.4", - "@react-types/shared": "^3.23.1", + "@react-aria/utils": "^3.25.1", + "@react-types/button": "^3.9.6", + "@react-types/shared": "^3.24.1", "@swc/helpers": "^0.5.0" }, "peerDependencies": { - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0", - "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0", + "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" } }, "node_modules/@react-aria/ssr": { - "version": "3.9.4", - "resolved": "https://registry.npmjs.org/@react-aria/ssr/-/ssr-3.9.4.tgz", - "integrity": "sha512-4jmAigVq409qcJvQyuorsmBR4+9r3+JEC60wC+Y0MZV0HCtTmm8D9guYXlJMdx0SSkgj0hHAyFm/HvPNFofCoQ==", + "version": "3.9.5", + "resolved": "https://registry.npmjs.org/@react-aria/ssr/-/ssr-3.9.5.tgz", + "integrity": "sha512-xEwGKoysu+oXulibNUSkXf8itW0npHHTa6c4AyYeZIJyRoegeteYuFpZUBPtIDE8RfHdNsSmE1ssOkxRnwbkuQ==", "dependencies": { "@swc/helpers": "^0.5.0" }, @@ -4763,220 +4762,221 @@ "node": ">= 12" }, "peerDependencies": { - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" } }, "node_modules/@react-aria/switch": { - "version": "3.6.4", - "resolved": "https://registry.npmjs.org/@react-aria/switch/-/switch-3.6.4.tgz", - "integrity": "sha512-2nVqz4ZuJyof47IpGSt3oZRmp+EdS8wzeDYgf42WHQXrx4uEOk1mdLJ20+NnsYhj/2NHZsvXVrjBeKMjlMs+0w==", + "version": "3.6.6", + "resolved": "https://registry.npmjs.org/@react-aria/switch/-/switch-3.6.6.tgz", + "integrity": "sha512-+dZOX1utODlx5dC90DtwnXd9nvln9HxMffBj/gmMT1/cD/RmXfjvymfjTsTMwvHhqCew9yfpvod0ZWwj3BkLGw==", "dependencies": { - "@react-aria/toggle": "^3.10.4", - "@react-stately/toggle": "^3.7.4", - "@react-types/switch": "^3.5.3", + "@react-aria/toggle": "^3.10.6", + "@react-stately/toggle": "^3.7.6", + "@react-types/shared": "^3.24.1", + "@react-types/switch": "^3.5.5", "@swc/helpers": "^0.5.0" }, "peerDependencies": { - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" } }, "node_modules/@react-aria/table": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/@react-aria/table/-/table-3.14.1.tgz", - "integrity": "sha512-WaPgQe4zQF5OaluO5rm+Y2nEoFR63vsLd4BT4yjK1uaFhKhDY2Zk+1SCVQvBLLKS4WK9dhP05nrNzT0vp/ZPOw==", + "version": "3.15.1", + "resolved": "https://registry.npmjs.org/@react-aria/table/-/table-3.15.1.tgz", + "integrity": "sha512-jVDLxp6Y/9M6y45c1I6u6msJ9dBg2I7Cu/FlSaK6HthTpN23UXuGw1oWuAjbfqi31nVXHWBwjCZkGKTdMjLf5A==", "dependencies": { - "@react-aria/focus": "^3.17.1", - "@react-aria/grid": "^3.9.1", - "@react-aria/i18n": "^3.11.1", - "@react-aria/interactions": "^3.21.3", + "@react-aria/focus": "^3.18.1", + "@react-aria/grid": "^3.10.1", + "@react-aria/i18n": "^3.12.1", + "@react-aria/interactions": "^3.22.1", "@react-aria/live-announcer": "^3.3.4", - "@react-aria/utils": "^3.24.1", - "@react-aria/visually-hidden": "^3.8.12", - "@react-stately/collections": "^3.10.7", + "@react-aria/utils": "^3.25.1", + "@react-aria/visually-hidden": "^3.8.14", + "@react-stately/collections": "^3.10.9", "@react-stately/flags": "^3.0.3", - "@react-stately/table": "^3.11.8", - "@react-stately/virtualizer": "^3.7.1", - "@react-types/checkbox": "^3.8.1", - "@react-types/grid": "^3.2.6", - "@react-types/shared": "^3.23.1", - "@react-types/table": "^3.9.5", + "@react-stately/table": "^3.12.1", + "@react-types/checkbox": "^3.8.3", + "@react-types/grid": "^3.2.8", + "@react-types/shared": "^3.24.1", + "@react-types/table": "^3.10.1", "@swc/helpers": "^0.5.0" }, "peerDependencies": { - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0", - "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0", + "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" } }, "node_modules/@react-aria/tabs": { - "version": "3.9.1", - "resolved": "https://registry.npmjs.org/@react-aria/tabs/-/tabs-3.9.1.tgz", - "integrity": "sha512-S5v/0sRcOaSXaJYZuuy1ZVzYc7JD4sDyseG1133GjyuNjJOFHgoWMb+b4uxNIJbZxnLgynn/ZDBZSO+qU+fIxw==", - "dependencies": { - "@react-aria/focus": "^3.17.1", - "@react-aria/i18n": "^3.11.1", - "@react-aria/selection": "^3.18.1", - "@react-aria/utils": "^3.24.1", - "@react-stately/tabs": "^3.6.6", - "@react-types/shared": "^3.23.1", - "@react-types/tabs": "^3.3.7", + "version": "3.9.3", + "resolved": "https://registry.npmjs.org/@react-aria/tabs/-/tabs-3.9.3.tgz", + "integrity": "sha512-J1KOCdx4eSyMMeNCvO8BIz8E8xez12B+cYbM4BbJzWlcfMboGYUnM0lvI8QSpFPa/H9LkAhp7BJnl9IZeIBzoA==", + "dependencies": { + "@react-aria/focus": "^3.18.1", + "@react-aria/i18n": "^3.12.1", + "@react-aria/selection": "^3.19.1", + "@react-aria/utils": "^3.25.1", + "@react-stately/tabs": "^3.6.8", + "@react-types/shared": "^3.24.1", + "@react-types/tabs": "^3.3.9", "@swc/helpers": "^0.5.0" }, "peerDependencies": { - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0", - "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0", + "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" } }, "node_modules/@react-aria/tag": { - "version": "3.4.1", - "resolved": "https://registry.npmjs.org/@react-aria/tag/-/tag-3.4.1.tgz", - "integrity": "sha512-gcIGPYZ2OBwMT4IHnlczEezKlxr0KRPL/mSfm2Q91GE027ZGOJnqusH9az6DX1qxrQx8x3vRdqYT2KmuefkrBQ==", - "dependencies": { - "@react-aria/gridlist": "^3.8.1", - "@react-aria/i18n": "^3.11.1", - "@react-aria/interactions": "^3.21.3", - "@react-aria/label": "^3.7.8", - "@react-aria/selection": "^3.18.1", - "@react-aria/utils": "^3.24.1", - "@react-stately/list": "^3.10.5", - "@react-types/button": "^3.9.4", - "@react-types/shared": "^3.23.1", + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/@react-aria/tag/-/tag-3.4.3.tgz", + "integrity": "sha512-BqXKazX9YHvt6+qzGTu770V0FqGVefzz03hmnV2IVb+zYchXBv3WYbWVy46s/D5zTePOAXdpitQHxqy5rh+hgw==", + "dependencies": { + "@react-aria/gridlist": "^3.9.1", + "@react-aria/i18n": "^3.12.1", + "@react-aria/interactions": "^3.22.1", + "@react-aria/label": "^3.7.10", + "@react-aria/selection": "^3.19.1", + "@react-aria/utils": "^3.25.1", + "@react-stately/list": "^3.10.7", + "@react-types/button": "^3.9.6", + "@react-types/shared": "^3.24.1", "@swc/helpers": "^0.5.0" }, "peerDependencies": { - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0", - "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0", + "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" } }, "node_modules/@react-aria/textfield": { - "version": "3.14.5", - "resolved": "https://registry.npmjs.org/@react-aria/textfield/-/textfield-3.14.5.tgz", - "integrity": "sha512-hj7H+66BjB1iTKKaFXwSZBZg88YT+wZboEXZ0DNdQB2ytzoz/g045wBItUuNi4ZjXI3P+0AOZznVMYadWBAmiA==", - "dependencies": { - "@react-aria/focus": "^3.17.1", - "@react-aria/form": "^3.0.5", - "@react-aria/label": "^3.7.8", - "@react-aria/utils": "^3.24.1", - "@react-stately/form": "^3.0.3", - "@react-stately/utils": "^3.10.1", - "@react-types/shared": "^3.23.1", - "@react-types/textfield": "^3.9.3", + "version": "3.14.7", + "resolved": "https://registry.npmjs.org/@react-aria/textfield/-/textfield-3.14.7.tgz", + "integrity": "sha512-1cWCG6vkjlwJuRTXKbKl9P0Q/0Li5pnMafZqDDWfDOlkS5dFGxYG6QFfoaYp7N6XMoNkXiculnCssfrQ+8hWgA==", + "dependencies": { + "@react-aria/focus": "^3.18.1", + "@react-aria/form": "^3.0.7", + "@react-aria/label": "^3.7.10", + "@react-aria/utils": "^3.25.1", + "@react-stately/form": "^3.0.5", + "@react-stately/utils": "^3.10.2", + "@react-types/shared": "^3.24.1", + "@react-types/textfield": "^3.9.5", "@swc/helpers": "^0.5.0" }, "peerDependencies": { - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" } }, "node_modules/@react-aria/toggle": { - "version": "3.10.4", - "resolved": "https://registry.npmjs.org/@react-aria/toggle/-/toggle-3.10.4.tgz", - "integrity": "sha512-bRk+CdB8QzrSyGNjENXiTWxfzYKRw753iwQXsEAU7agPCUdB8cZJyrhbaUoD0rwczzTp2zDbZ9rRbUPdsBE2YQ==", - "dependencies": { - "@react-aria/focus": "^3.17.1", - "@react-aria/interactions": "^3.21.3", - "@react-aria/utils": "^3.24.1", - "@react-stately/toggle": "^3.7.4", - "@react-types/checkbox": "^3.8.1", + "version": "3.10.6", + "resolved": "https://registry.npmjs.org/@react-aria/toggle/-/toggle-3.10.6.tgz", + "integrity": "sha512-AGlbtB1b8grrtjbiW5Au0LKYzxR83RHbHhaUkFwajyYRGyuEzr3Y03OiveoPB+DayA8Gz3H1ZVmW++8JZQOWHw==", + "dependencies": { + "@react-aria/focus": "^3.18.1", + "@react-aria/interactions": "^3.22.1", + "@react-aria/utils": "^3.25.1", + "@react-stately/toggle": "^3.7.6", + "@react-types/checkbox": "^3.8.3", + "@react-types/shared": "^3.24.1", "@swc/helpers": "^0.5.0" }, "peerDependencies": { - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" } }, "node_modules/@react-aria/toolbar": { - "version": "3.0.0-beta.5", - "resolved": "https://registry.npmjs.org/@react-aria/toolbar/-/toolbar-3.0.0-beta.5.tgz", - "integrity": "sha512-c8spY7aeLI6L+ygdXvEbAzaT41vExsxZ1Ld0t7BB+6iEF3nyBNJHshjkgdR7nv8FLgNk0no4tj0GTq4Jj4UqHQ==", - "dependencies": { - "@react-aria/focus": "^3.17.1", - "@react-aria/i18n": "^3.11.1", - "@react-aria/utils": "^3.24.1", - "@react-types/shared": "^3.23.1", + "version": "3.0.0-beta.7", + "resolved": "https://registry.npmjs.org/@react-aria/toolbar/-/toolbar-3.0.0-beta.7.tgz", + "integrity": "sha512-PKaXD2qiWcVOn/bX07ipamTc6OlqypqcQRGG7WUL0ZXWfV6AfL7GFPS1B2Jh7Etetq68Ynyuo6R4jT4Jypsjdg==", + "dependencies": { + "@react-aria/focus": "^3.18.1", + "@react-aria/i18n": "^3.12.1", + "@react-aria/utils": "^3.25.1", + "@react-types/shared": "^3.24.1", "@swc/helpers": "^0.5.0" }, "peerDependencies": { - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" } }, "node_modules/@react-aria/tooltip": { - "version": "3.7.4", - "resolved": "https://registry.npmjs.org/@react-aria/tooltip/-/tooltip-3.7.4.tgz", - "integrity": "sha512-+XRx4HlLYqWY3fB8Z60bQi/rbWDIGlFUtXYbtoa1J+EyRWfhpvsYImP8qeeNO/vgjUtDy1j9oKa8p6App9mBMQ==", - "dependencies": { - "@react-aria/focus": "^3.17.1", - "@react-aria/interactions": "^3.21.3", - "@react-aria/utils": "^3.24.1", - "@react-stately/tooltip": "^3.4.9", - "@react-types/shared": "^3.23.1", - "@react-types/tooltip": "^3.4.9", + "version": "3.7.6", + "resolved": "https://registry.npmjs.org/@react-aria/tooltip/-/tooltip-3.7.6.tgz", + "integrity": "sha512-JvRAMTcMju/KBOtISjVKKtIDzG3J1r6xK+mZTvu6ArM7DdeMBM5A8Lwk0bJ8dhr+YybiM9rR3hoZv3/E7IIYVw==", + "dependencies": { + "@react-aria/focus": "^3.18.1", + "@react-aria/interactions": "^3.22.1", + "@react-aria/utils": "^3.25.1", + "@react-stately/tooltip": "^3.4.11", + "@react-types/shared": "^3.24.1", + "@react-types/tooltip": "^3.4.11", "@swc/helpers": "^0.5.0" }, "peerDependencies": { - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" } }, "node_modules/@react-aria/tree": { - "version": "3.0.0-alpha.1", - "resolved": "https://registry.npmjs.org/@react-aria/tree/-/tree-3.0.0-alpha.1.tgz", - "integrity": "sha512-CucyeJ4VeAvWO5UJHt/l9JO65CVtsOVUctMOVNCQS77Isqp3olX9pvfD3LXt8fD5Ph2g0Q/b7siVpX5ieVB32g==", - "dependencies": { - "@react-aria/gridlist": "^3.8.1", - "@react-aria/i18n": "^3.11.1", - "@react-aria/selection": "^3.18.1", - "@react-aria/utils": "^3.24.1", - "@react-stately/tree": "^3.8.1", - "@react-types/button": "^3.9.4", - "@react-types/shared": "^3.23.1", + "version": "3.0.0-alpha.3", + "resolved": "https://registry.npmjs.org/@react-aria/tree/-/tree-3.0.0-alpha.3.tgz", + "integrity": "sha512-o/9B+PVSUYxDM1KxQ/Pl1CytPtIagyidmasd10266hWfwzvPA0ZyakBwIEFj+ROnr9buAdP+A4sOTRo+a6g+YQ==", + "dependencies": { + "@react-aria/gridlist": "^3.9.1", + "@react-aria/i18n": "^3.12.1", + "@react-aria/selection": "^3.19.1", + "@react-aria/utils": "^3.25.1", + "@react-stately/tree": "^3.8.3", + "@react-types/button": "^3.9.6", + "@react-types/shared": "^3.24.1", "@swc/helpers": "^0.5.0" }, "peerDependencies": { - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0", - "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0", + "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" } }, "node_modules/@react-aria/utils": { - "version": "3.24.1", - "resolved": "https://registry.npmjs.org/@react-aria/utils/-/utils-3.24.1.tgz", - "integrity": "sha512-O3s9qhPMd6n42x9sKeJ3lhu5V1Tlnzhu6Yk8QOvDuXf7UGuUjXf9mzfHJt1dYzID4l9Fwm8toczBzPM9t0jc8Q==", + "version": "3.25.1", + "resolved": "https://registry.npmjs.org/@react-aria/utils/-/utils-3.25.1.tgz", + "integrity": "sha512-5Uj864e7T5+yj78ZfLnfHqmypLiqW2mN+nsdslog2z5ssunTqjolVeM15ootXskjISlZ7MojLpq97kIC4nlnAw==", "dependencies": { - "@react-aria/ssr": "^3.9.4", - "@react-stately/utils": "^3.10.1", - "@react-types/shared": "^3.23.1", + "@react-aria/ssr": "^3.9.5", + "@react-stately/utils": "^3.10.2", + "@react-types/shared": "^3.24.1", "@swc/helpers": "^0.5.0", "clsx": "^2.0.0" }, "peerDependencies": { - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" } }, "node_modules/@react-aria/virtualizer": { - "version": "3.10.1", - "resolved": "https://registry.npmjs.org/@react-aria/virtualizer/-/virtualizer-3.10.1.tgz", - "integrity": "sha512-y34w+n/B3nwwj18QHIZlkNj5Fn2rt5CbQE4BBWAM8jYZ5ypwF77i2toxhGTuk1Oo1/hgTX7JYIgDIAQbNraBcg==", - "dependencies": { - "@react-aria/i18n": "^3.11.1", - "@react-aria/interactions": "^3.21.3", - "@react-aria/utils": "^3.24.1", - "@react-stately/virtualizer": "^3.7.1", - "@react-types/shared": "^3.23.1", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@react-aria/virtualizer/-/virtualizer-4.0.1.tgz", + "integrity": "sha512-JZ6X0l38ZwBU/JgeLwkDA8mknRxqO1nYSVaPZHgOg8fd9BzMRWBjse7VW+Uf09P0uAEFElwlB+RY8UDx+W/Fmg==", + "dependencies": { + "@react-aria/i18n": "^3.12.1", + "@react-aria/interactions": "^3.22.1", + "@react-aria/utils": "^3.25.1", + "@react-stately/virtualizer": "^4.0.1", + "@react-types/shared": "^3.24.1", "@swc/helpers": "^0.5.0" }, "peerDependencies": { - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0", - "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0", + "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" } }, "node_modules/@react-aria/visually-hidden": { - "version": "3.8.12", - "resolved": "https://registry.npmjs.org/@react-aria/visually-hidden/-/visually-hidden-3.8.12.tgz", - "integrity": "sha512-Bawm+2Cmw3Xrlr7ARzl2RLtKh0lNUdJ0eNqzWcyx4c0VHUAWtThmH5l+HRqFUGzzutFZVo89SAy40BAbd0gjVw==", + "version": "3.8.14", + "resolved": "https://registry.npmjs.org/@react-aria/visually-hidden/-/visually-hidden-3.8.14.tgz", + "integrity": "sha512-DV3yagbAgO4ywQTq6D/AxcIaTC8c77r/SxlIMhQBMQ6vScJWTCh6zFG55wmLe3NKqvRrowv1OstlmYfZQ4v/XA==", "dependencies": { - "@react-aria/interactions": "^3.21.3", - "@react-aria/utils": "^3.24.1", - "@react-types/shared": "^3.23.1", + "@react-aria/interactions": "^3.22.1", + "@react-aria/utils": "^3.25.1", + "@react-types/shared": "^3.24.1", "@swc/helpers": "^0.5.0" }, "peerDependencies": { - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" } }, "node_modules/@react-google-maps/api": { @@ -5007,1114 +5007,1118 @@ "integrity": "sha512-x9ibmsP0ZVqzyCo1Pitbw+4b6iEXRw/r1TCy3vOUR3eKrzWLnHYZMR325BkZW2r8fnuWE/V3Fp4QZOP9qYORCw==" }, "node_modules/@react-spectrum/actionbar": { - "version": "3.4.5", - "resolved": "https://registry.npmjs.org/@react-spectrum/actionbar/-/actionbar-3.4.5.tgz", - "integrity": "sha512-9+b3B5he/zwyk+1pHc5l8/q6mBy+zKkphha2kBScbj/2XRHTwwlcamBJMANMYfVirQT9UP5FHGhHV6OiRgZLrA==", + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/@react-spectrum/actionbar/-/actionbar-3.5.1.tgz", + "integrity": "sha512-yPqUjIbRaUPZtips+FXYNCNv5Yyqcd5MjN238C6kUXoEOMNRfXiO3QLO7JRMywwi4EWPz4GjH+329/VoV+iXsw==", "dependencies": { - "@react-aria/focus": "^3.17.1", - "@react-aria/i18n": "^3.11.1", - "@react-aria/interactions": "^3.21.3", + "@react-aria/focus": "^3.18.1", + "@react-aria/i18n": "^3.12.1", + "@react-aria/interactions": "^3.22.1", "@react-aria/live-announcer": "^3.3.4", - "@react-aria/utils": "^3.24.1", - "@react-spectrum/actiongroup": "^3.10.5", - "@react-spectrum/button": "^3.16.4", - "@react-spectrum/overlays": "^5.6.1", - "@react-spectrum/text": "^3.5.5", - "@react-spectrum/utils": "^3.11.7", - "@react-stately/collections": "^3.10.7", - "@react-types/actionbar": "^3.1.7", - "@react-types/shared": "^3.23.1", - "@spectrum-icons/ui": "^3.6.7", + "@react-aria/utils": "^3.25.1", + "@react-spectrum/actiongroup": "^3.10.7", + "@react-spectrum/button": "^3.16.6", + "@react-spectrum/overlays": "^5.6.3", + "@react-spectrum/text": "^3.5.7", + "@react-spectrum/utils": "^3.11.9", + "@react-stately/collections": "^3.10.9", + "@react-types/actionbar": "^3.1.9", + "@react-types/shared": "^3.24.1", + "@spectrum-icons/ui": "^3.6.9", "@swc/helpers": "^0.5.0" }, "peerDependencies": { "@react-spectrum/provider": "^3.0.0", - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0", - "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0", + "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" } }, "node_modules/@react-spectrum/actiongroup": { - "version": "3.10.5", - "resolved": "https://registry.npmjs.org/@react-spectrum/actiongroup/-/actiongroup-3.10.5.tgz", - "integrity": "sha512-KHSuZvCD5XyOA4wz2iu85JQem2Y01pniWTfhzGLPfJG+1OdOCt+C0mO/jU0DL4NM6UwzdLy4JfvUij/xBsLrRw==", - "dependencies": { - "@react-aria/actiongroup": "^3.7.5", - "@react-aria/focus": "^3.17.1", - "@react-aria/interactions": "^3.21.3", - "@react-aria/utils": "^3.24.1", - "@react-spectrum/button": "^3.16.4", - "@react-spectrum/menu": "^3.19.1", - "@react-spectrum/text": "^3.5.5", - "@react-spectrum/tooltip": "^3.6.7", - "@react-spectrum/utils": "^3.11.7", - "@react-stately/collections": "^3.10.7", - "@react-stately/list": "^3.10.5", - "@react-types/actiongroup": "^3.4.9", - "@react-types/shared": "^3.23.1", - "@spectrum-icons/ui": "^3.6.7", - "@spectrum-icons/workflow": "^4.2.12", + "version": "3.10.7", + "resolved": "https://registry.npmjs.org/@react-spectrum/actiongroup/-/actiongroup-3.10.7.tgz", + "integrity": "sha512-IJqr+TOEZRPWJ+9OSGZvZBPQZG/mp++2awKIVPJzOCWOWu81oIu8fMRgnuQev+RoAJWKBXR1sh5EPMmLJHSzqA==", + "dependencies": { + "@react-aria/actiongroup": "^3.7.7", + "@react-aria/focus": "^3.18.1", + "@react-aria/interactions": "^3.22.1", + "@react-aria/utils": "^3.25.1", + "@react-spectrum/button": "^3.16.6", + "@react-spectrum/menu": "^3.20.1", + "@react-spectrum/text": "^3.5.7", + "@react-spectrum/tooltip": "^3.6.9", + "@react-spectrum/utils": "^3.11.9", + "@react-stately/collections": "^3.10.9", + "@react-stately/list": "^3.10.7", + "@react-types/actiongroup": "^3.4.11", + "@react-types/shared": "^3.24.1", + "@spectrum-icons/ui": "^3.6.9", + "@spectrum-icons/workflow": "^4.2.14", "@swc/helpers": "^0.5.0" }, "peerDependencies": { "@react-spectrum/provider": "^3.2.0", - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0", - "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0", + "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" } }, "node_modules/@react-spectrum/avatar": { - "version": "3.0.12", - "resolved": "https://registry.npmjs.org/@react-spectrum/avatar/-/avatar-3.0.12.tgz", - "integrity": "sha512-H5dZG+mPiSHlST2TBMfMR7mOf+g5C0i9Q2+aMMQ8khphXLFL4fj5GqxgEE7Mi5efS+raofwXJ/dM+AedsSl6WQ==", - "dependencies": { - "@react-aria/utils": "^3.24.1", - "@react-spectrum/utils": "^3.11.7", - "@react-types/avatar": "^3.0.7", - "@react-types/shared": "^3.23.1", + "version": "3.0.14", + "resolved": "https://registry.npmjs.org/@react-spectrum/avatar/-/avatar-3.0.14.tgz", + "integrity": "sha512-QQRRQEO4mHdW9UtXomEJw9gAfOliqhMaYMJYWlwytCAipErrllae7U9VK0AaECokfNBib3Klhp8b/4VtLKr+dw==", + "dependencies": { + "@react-aria/utils": "^3.25.1", + "@react-spectrum/utils": "^3.11.9", + "@react-types/avatar": "^3.0.9", + "@react-types/shared": "^3.24.1", "@swc/helpers": "^0.5.0" }, "peerDependencies": { "@react-spectrum/provider": "^3.2.1", - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" } }, "node_modules/@react-spectrum/badge": { - "version": "3.1.13", - "resolved": "https://registry.npmjs.org/@react-spectrum/badge/-/badge-3.1.13.tgz", - "integrity": "sha512-zfsmbw3hxYWxuySQZTMNkxI5vD1XktHNIBqDUYNaDu8A+GVaORI9pcrua4T2YXyQrw1hYXbqVAmeISJYURajjA==", - "dependencies": { - "@react-aria/utils": "^3.24.1", - "@react-spectrum/text": "^3.5.5", - "@react-spectrum/utils": "^3.11.7", - "@react-types/badge": "^3.1.9", - "@react-types/shared": "^3.23.1", + "version": "3.1.15", + "resolved": "https://registry.npmjs.org/@react-spectrum/badge/-/badge-3.1.15.tgz", + "integrity": "sha512-fCjEXw5ej0GzXTk7g3PkhPKj0sS1mQ6XtrhGIwM1g78AYdv0+no7Zsew1ojRQJpOhWDqJPj2QNRJplouGTI3uA==", + "dependencies": { + "@react-aria/utils": "^3.25.1", + "@react-spectrum/text": "^3.5.7", + "@react-spectrum/utils": "^3.11.9", + "@react-types/badge": "^3.1.11", + "@react-types/shared": "^3.24.1", "@swc/helpers": "^0.5.0" }, "peerDependencies": { "@react-spectrum/provider": "^3.0.0", - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" } }, "node_modules/@react-spectrum/breadcrumbs": { - "version": "3.9.7", - "resolved": "https://registry.npmjs.org/@react-spectrum/breadcrumbs/-/breadcrumbs-3.9.7.tgz", - "integrity": "sha512-1wA9cgSugaplYmT4z/WiUAZsOcXPWN+8sx43Wc5foS3qUSOLpW4+43sjDTVmzVlbXYuZ4byxf1nrXZNEqCWZXA==", - "dependencies": { - "@react-aria/breadcrumbs": "^3.5.13", - "@react-aria/focus": "^3.17.1", - "@react-aria/i18n": "^3.11.1", - "@react-aria/interactions": "^3.21.3", - "@react-aria/utils": "^3.24.1", - "@react-spectrum/button": "^3.16.4", - "@react-spectrum/menu": "^3.19.1", - "@react-spectrum/utils": "^3.11.7", - "@react-stately/collections": "^3.10.7", - "@react-types/breadcrumbs": "^3.7.5", - "@react-types/shared": "^3.23.1", - "@spectrum-icons/ui": "^3.6.7", + "version": "3.9.9", + "resolved": "https://registry.npmjs.org/@react-spectrum/breadcrumbs/-/breadcrumbs-3.9.9.tgz", + "integrity": "sha512-JQ9OGQJTV68ZxCc7cNNa1ob5G+AAXYD3BjAd81ZfUwxjzEnHPXu/FJWHC7H8zaCGno6Pqq8nhgBHNR1TBiQqGw==", + "dependencies": { + "@react-aria/breadcrumbs": "^3.5.15", + "@react-aria/focus": "^3.18.1", + "@react-aria/i18n": "^3.12.1", + "@react-aria/interactions": "^3.22.1", + "@react-aria/utils": "^3.25.1", + "@react-spectrum/button": "^3.16.6", + "@react-spectrum/menu": "^3.20.1", + "@react-spectrum/utils": "^3.11.9", + "@react-stately/collections": "^3.10.9", + "@react-types/breadcrumbs": "^3.7.7", + "@react-types/shared": "^3.24.1", + "@spectrum-icons/ui": "^3.6.9", "@swc/helpers": "^0.5.0" }, "peerDependencies": { "@react-spectrum/provider": "^3.0.0", - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0", - "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0", + "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" } }, "node_modules/@react-spectrum/button": { - "version": "3.16.4", - "resolved": "https://registry.npmjs.org/@react-spectrum/button/-/button-3.16.4.tgz", - "integrity": "sha512-ksPZkmhkz8fJuu+cC9GM5e1pJ0d2sWmkU9sqKn5SNfWh9ngemgvShtkqkuQoz6ThH+MI3n/n4JhFd+UhJ/lILA==", - "dependencies": { - "@react-aria/button": "^3.9.5", - "@react-aria/focus": "^3.17.1", - "@react-aria/i18n": "^3.11.1", - "@react-aria/interactions": "^3.21.3", - "@react-aria/utils": "^3.24.1", - "@react-spectrum/progress": "^3.7.7", - "@react-spectrum/text": "^3.5.5", - "@react-spectrum/utils": "^3.11.7", - "@react-stately/toggle": "^3.7.4", - "@react-types/button": "^3.9.4", - "@react-types/shared": "^3.23.1", - "@spectrum-icons/ui": "^3.6.7", + "version": "3.16.6", + "resolved": "https://registry.npmjs.org/@react-spectrum/button/-/button-3.16.6.tgz", + "integrity": "sha512-dNJldfq9xQ1pN29km0+vTmhlmRpx8ZXF5K/1edvdLpPtpI3a6iJIBxGh8v4uQFNaAN3Er7mdHdvguHkPsnTD3w==", + "dependencies": { + "@react-aria/button": "^3.9.7", + "@react-aria/focus": "^3.18.1", + "@react-aria/i18n": "^3.12.1", + "@react-aria/interactions": "^3.22.1", + "@react-aria/utils": "^3.25.1", + "@react-spectrum/progress": "^3.7.9", + "@react-spectrum/text": "^3.5.7", + "@react-spectrum/utils": "^3.11.9", + "@react-stately/toggle": "^3.7.6", + "@react-types/button": "^3.9.6", + "@react-types/shared": "^3.24.1", + "@spectrum-icons/ui": "^3.6.9", "@swc/helpers": "^0.5.0" }, "peerDependencies": { "@react-spectrum/provider": "^3.0.0", - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" } }, "node_modules/@react-spectrum/buttongroup": { - "version": "3.6.13", - "resolved": "https://registry.npmjs.org/@react-spectrum/buttongroup/-/buttongroup-3.6.13.tgz", - "integrity": "sha512-QUNTtDMiY/ydrpUYq8fO0kkssdnTEJsIxlfhbQa3ZEpEObjgt9XbAehNKPelWATwLNQ/gY8o21m9GT1m7J/8zg==", - "dependencies": { - "@react-aria/utils": "^3.24.1", - "@react-spectrum/utils": "^3.11.7", - "@react-types/buttongroup": "^3.3.9", - "@react-types/shared": "^3.23.1", + "version": "3.6.15", + "resolved": "https://registry.npmjs.org/@react-spectrum/buttongroup/-/buttongroup-3.6.15.tgz", + "integrity": "sha512-QelfmkrH1bWDGTJyVRQxOVSJsn1dv3aNGlgd3u9HvBDQyZItRl+qiflOCZnrtPgX7SBUBVxGooW+3/AunIBkrw==", + "dependencies": { + "@react-aria/utils": "^3.25.1", + "@react-spectrum/utils": "^3.11.9", + "@react-types/buttongroup": "^3.3.11", + "@react-types/shared": "^3.24.1", "@swc/helpers": "^0.5.0" }, "peerDependencies": { "@react-spectrum/provider": "^3.0.0", - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" } }, "node_modules/@react-spectrum/calendar": { - "version": "3.4.9", - "resolved": "https://registry.npmjs.org/@react-spectrum/calendar/-/calendar-3.4.9.tgz", - "integrity": "sha512-5546bmMQ/v3dscTDFx0llEQ3jA23vkcjbiY7hIad5a9bpXHPQSuIeREelFPtsVUzsD3f3v2BL2nDAt6SPLVqCA==", - "dependencies": { - "@internationalized/date": "^3.5.4", - "@react-aria/calendar": "^3.5.8", - "@react-aria/focus": "^3.17.1", - "@react-aria/i18n": "^3.11.1", - "@react-aria/interactions": "^3.21.3", - "@react-aria/utils": "^3.24.1", - "@react-aria/visually-hidden": "^3.8.12", - "@react-spectrum/button": "^3.16.4", - "@react-spectrum/label": "^3.16.6", - "@react-spectrum/utils": "^3.11.7", - "@react-stately/calendar": "^3.5.1", - "@react-types/button": "^3.9.4", - "@react-types/calendar": "^3.4.6", - "@react-types/shared": "^3.23.1", - "@spectrum-icons/ui": "^3.6.7", + "version": "3.4.11", + "resolved": "https://registry.npmjs.org/@react-spectrum/calendar/-/calendar-3.4.11.tgz", + "integrity": "sha512-NZZvdWDOhkNphUa4if1gM4x+tUDZb7fiMoTjp0/RSN2VaBl8Z5tt6R5hP9IAWvjfyPH8rv2zI40yO6ts/QCgcg==", + "dependencies": { + "@internationalized/date": "^3.5.5", + "@react-aria/calendar": "^3.5.10", + "@react-aria/focus": "^3.18.1", + "@react-aria/i18n": "^3.12.1", + "@react-aria/interactions": "^3.22.1", + "@react-aria/utils": "^3.25.1", + "@react-aria/visually-hidden": "^3.8.14", + "@react-spectrum/button": "^3.16.6", + "@react-spectrum/label": "^3.16.8", + "@react-spectrum/utils": "^3.11.9", + "@react-stately/calendar": "^3.5.3", + "@react-types/button": "^3.9.6", + "@react-types/calendar": "^3.4.8", + "@react-types/shared": "^3.24.1", + "@spectrum-icons/ui": "^3.6.9", "@swc/helpers": "^0.5.0" }, "peerDependencies": { "@react-spectrum/provider": "^3.0.0", - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0", - "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0", + "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" } }, "node_modules/@react-spectrum/checkbox": { - "version": "3.9.6", - "resolved": "https://registry.npmjs.org/@react-spectrum/checkbox/-/checkbox-3.9.6.tgz", - "integrity": "sha512-aU4bDFwaiC2hpqOFv9vbUw20V6VlMO7pn1P8Q/qUfNxWVzPY03rJC0Gqcq8NQy2zofmm4tDBJKKOF1F4amGTyw==", - "dependencies": { - "@react-aria/checkbox": "^3.14.3", - "@react-aria/focus": "^3.17.1", - "@react-aria/interactions": "^3.21.3", - "@react-spectrum/form": "^3.7.6", - "@react-spectrum/label": "^3.16.6", - "@react-spectrum/utils": "^3.11.7", - "@react-stately/checkbox": "^3.6.5", - "@react-stately/toggle": "^3.7.4", - "@react-types/checkbox": "^3.8.1", - "@react-types/shared": "^3.23.1", - "@spectrum-icons/ui": "^3.6.7", + "version": "3.9.8", + "resolved": "https://registry.npmjs.org/@react-spectrum/checkbox/-/checkbox-3.9.8.tgz", + "integrity": "sha512-qOwzemGpa+Qj9ZmwDhFtCd0OkqCY+c6yw8iggCfA0A+jrreSexkOAtUo6JIGg6Vsh44oqM44PKKMgvbpW1LXJw==", + "dependencies": { + "@react-aria/checkbox": "^3.14.5", + "@react-aria/focus": "^3.18.1", + "@react-aria/interactions": "^3.22.1", + "@react-spectrum/form": "^3.7.8", + "@react-spectrum/label": "^3.16.8", + "@react-spectrum/utils": "^3.11.9", + "@react-stately/checkbox": "^3.6.7", + "@react-stately/toggle": "^3.7.6", + "@react-types/checkbox": "^3.8.3", + "@react-types/shared": "^3.24.1", + "@spectrum-icons/ui": "^3.6.9", "@swc/helpers": "^0.5.0", - "react-aria-components": "^1.2.1" + "react-aria-components": "^1.3.1" }, "peerDependencies": { "@react-spectrum/provider": "^3.0.0", - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" } }, "node_modules/@react-spectrum/combobox": { - "version": "3.12.5", - "resolved": "https://registry.npmjs.org/@react-spectrum/combobox/-/combobox-3.12.5.tgz", - "integrity": "sha512-S6TA8FrPm0ibLkeulki2S0DsUqy/hEcTVTvvic7qIRyURN/J+DQMQDWmy+Zzz9mxJr8qdJAoWSArBVWtxKhMKg==", - "dependencies": { - "@react-aria/button": "^3.9.5", - "@react-aria/combobox": "^3.9.1", - "@react-aria/dialog": "^3.5.14", - "@react-aria/focus": "^3.17.1", - "@react-aria/form": "^3.0.5", - "@react-aria/i18n": "^3.11.1", - "@react-aria/interactions": "^3.21.3", - "@react-aria/label": "^3.7.8", - "@react-aria/overlays": "^3.22.1", - "@react-aria/utils": "^3.24.1", - "@react-spectrum/button": "^3.16.4", - "@react-spectrum/form": "^3.7.6", - "@react-spectrum/label": "^3.16.6", - "@react-spectrum/listbox": "^3.12.9", - "@react-spectrum/overlays": "^5.6.1", - "@react-spectrum/progress": "^3.7.7", - "@react-spectrum/textfield": "^3.12.1", - "@react-spectrum/utils": "^3.11.7", - "@react-stately/collections": "^3.10.7", - "@react-stately/combobox": "^3.8.4", - "@react-types/button": "^3.9.4", - "@react-types/combobox": "^3.11.1", - "@react-types/shared": "^3.23.1", - "@spectrum-icons/ui": "^3.6.7", + "version": "3.13.1", + "resolved": "https://registry.npmjs.org/@react-spectrum/combobox/-/combobox-3.13.1.tgz", + "integrity": "sha512-p6Wt8TCvaE/ljDpRZQEuGjxvFkXiIwElz3Fq/qoV6qhdeXbm8GxEwkfzpcBk2SgvjVAAWgQYcmUJVav+R5J0/g==", + "dependencies": { + "@react-aria/button": "^3.9.7", + "@react-aria/combobox": "^3.10.1", + "@react-aria/dialog": "^3.5.16", + "@react-aria/focus": "^3.18.1", + "@react-aria/form": "^3.0.7", + "@react-aria/i18n": "^3.12.1", + "@react-aria/interactions": "^3.22.1", + "@react-aria/label": "^3.7.10", + "@react-aria/overlays": "^3.23.1", + "@react-aria/utils": "^3.25.1", + "@react-spectrum/button": "^3.16.6", + "@react-spectrum/form": "^3.7.8", + "@react-spectrum/label": "^3.16.8", + "@react-spectrum/listbox": "^3.13.1", + "@react-spectrum/overlays": "^5.6.3", + "@react-spectrum/progress": "^3.7.9", + "@react-spectrum/textfield": "^3.12.3", + "@react-spectrum/utils": "^3.11.9", + "@react-stately/collections": "^3.10.9", + "@react-stately/combobox": "^3.9.1", + "@react-types/button": "^3.9.6", + "@react-types/combobox": "^3.12.1", + "@react-types/shared": "^3.24.1", + "@spectrum-icons/ui": "^3.6.9", "@swc/helpers": "^0.5.0" }, "peerDependencies": { "@react-spectrum/provider": "^3.0.0", - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0", - "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0", + "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" } }, "node_modules/@react-spectrum/contextualhelp": { - "version": "3.6.11", - "resolved": "https://registry.npmjs.org/@react-spectrum/contextualhelp/-/contextualhelp-3.6.11.tgz", - "integrity": "sha512-mQimyXdwXyZWFWO/7BdHZ46YzCQThjnHGGMmlv2y+YfqaOqoP3UTQb4D6noSbV1M6zKJgMq5timhVo81Sujk9Q==", - "dependencies": { - "@react-aria/i18n": "^3.11.1", - "@react-aria/utils": "^3.24.1", - "@react-spectrum/button": "^3.16.4", - "@react-spectrum/dialog": "^3.8.11", - "@react-spectrum/utils": "^3.11.7", - "@react-types/contextualhelp": "^3.2.10", - "@react-types/shared": "^3.23.1", - "@spectrum-icons/workflow": "^4.2.12", + "version": "3.6.13", + "resolved": "https://registry.npmjs.org/@react-spectrum/contextualhelp/-/contextualhelp-3.6.13.tgz", + "integrity": "sha512-tSY2l9v+kTvMfL6Alu8AoDSqXLCX0lqi8wuQxOVOHvbKEYf9BnRdlHQ5ILLHpt9eFxriVnsQcIbR6sGdoOi2pw==", + "dependencies": { + "@react-aria/i18n": "^3.12.1", + "@react-aria/utils": "^3.25.1", + "@react-spectrum/button": "^3.16.6", + "@react-spectrum/dialog": "^3.8.13", + "@react-spectrum/utils": "^3.11.9", + "@react-types/contextualhelp": "^3.2.12", + "@react-types/shared": "^3.24.1", + "@spectrum-icons/workflow": "^4.2.14", "@swc/helpers": "^0.5.0" }, "peerDependencies": { "@react-spectrum/provider": "^3.0.0", - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0", - "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0", + "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" } }, "node_modules/@react-spectrum/datepicker": { - "version": "3.9.6", - "resolved": "https://registry.npmjs.org/@react-spectrum/datepicker/-/datepicker-3.9.6.tgz", - "integrity": "sha512-MeLle/V2t3dBe7wq/qkc39hJyV6NTZncCZnBfPHnTcLXeZl8sfTf4rt11JS3Y4JOOtM3jiuw1oMpZ7wv+h6hOA==", - "dependencies": { - "@internationalized/date": "^3.5.4", - "@react-aria/datepicker": "^3.10.1", - "@react-aria/focus": "^3.17.1", - "@react-aria/i18n": "^3.11.1", - "@react-aria/interactions": "^3.21.3", - "@react-aria/utils": "^3.24.1", - "@react-spectrum/button": "^3.16.4", - "@react-spectrum/calendar": "^3.4.9", - "@react-spectrum/dialog": "^3.8.11", - "@react-spectrum/form": "^3.7.6", - "@react-spectrum/label": "^3.16.6", - "@react-spectrum/layout": "^3.6.5", - "@react-spectrum/utils": "^3.11.7", - "@react-spectrum/view": "^3.6.10", - "@react-stately/datepicker": "^3.9.4", - "@react-types/datepicker": "^3.7.4", - "@react-types/shared": "^3.23.1", - "@spectrum-icons/ui": "^3.6.7", - "@spectrum-icons/workflow": "^4.2.12", + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/@react-spectrum/datepicker/-/datepicker-3.10.1.tgz", + "integrity": "sha512-+cmnSGSMrMiO94q1KOM3rCIUeFQouwJ8SbECxMQQDAGINHbhQxlceW4sKl0SldpXzS2yVINKj17rjFAbOvxEHw==", + "dependencies": { + "@internationalized/date": "^3.5.5", + "@react-aria/datepicker": "^3.11.1", + "@react-aria/focus": "^3.18.1", + "@react-aria/i18n": "^3.12.1", + "@react-aria/interactions": "^3.22.1", + "@react-aria/utils": "^3.25.1", + "@react-spectrum/button": "^3.16.6", + "@react-spectrum/calendar": "^3.4.11", + "@react-spectrum/dialog": "^3.8.13", + "@react-spectrum/form": "^3.7.8", + "@react-spectrum/label": "^3.16.8", + "@react-spectrum/layout": "^3.6.7", + "@react-spectrum/utils": "^3.11.9", + "@react-spectrum/view": "^3.6.12", + "@react-stately/datepicker": "^3.10.1", + "@react-types/datepicker": "^3.8.1", + "@react-types/shared": "^3.24.1", + "@spectrum-icons/ui": "^3.6.9", + "@spectrum-icons/workflow": "^4.2.14", "@swc/helpers": "^0.5.0" }, "peerDependencies": { "@react-spectrum/provider": "^3.0.0", - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0", - "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0", + "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" } }, "node_modules/@react-spectrum/dialog": { - "version": "3.8.11", - "resolved": "https://registry.npmjs.org/@react-spectrum/dialog/-/dialog-3.8.11.tgz", - "integrity": "sha512-/ng49paipA3MHC5nVbfDlZL6QXFJWCrSDgQ4fXon5q6gB+94d2DvkZ+CvnLZ5oo0Bpkws/vT3jxcG0hsBz1f6g==", - "dependencies": { - "@react-aria/dialog": "^3.5.14", - "@react-aria/i18n": "^3.11.1", - "@react-aria/interactions": "^3.21.3", - "@react-aria/overlays": "^3.22.1", - "@react-aria/utils": "^3.24.1", - "@react-spectrum/button": "^3.16.4", - "@react-spectrum/buttongroup": "^3.6.13", - "@react-spectrum/divider": "^3.5.13", - "@react-spectrum/layout": "^3.6.5", - "@react-spectrum/overlays": "^5.6.1", - "@react-spectrum/text": "^3.5.5", - "@react-spectrum/utils": "^3.11.7", - "@react-spectrum/view": "^3.6.10", - "@react-stately/overlays": "^3.6.7", - "@react-types/button": "^3.9.4", - "@react-types/dialog": "^3.5.10", - "@react-types/shared": "^3.23.1", - "@spectrum-icons/ui": "^3.6.7", + "version": "3.8.13", + "resolved": "https://registry.npmjs.org/@react-spectrum/dialog/-/dialog-3.8.13.tgz", + "integrity": "sha512-BbmBKRVcSOZhV01xCl/MJTG2D+dctDMs/8/SOpM//BXzvlDIGXHRVJiYcPKCGe4Egt+6mNCjY/xvvfqxOXRNhw==", + "dependencies": { + "@react-aria/dialog": "^3.5.16", + "@react-aria/i18n": "^3.12.1", + "@react-aria/interactions": "^3.22.1", + "@react-aria/overlays": "^3.23.1", + "@react-aria/utils": "^3.25.1", + "@react-spectrum/button": "^3.16.6", + "@react-spectrum/buttongroup": "^3.6.15", + "@react-spectrum/divider": "^3.5.15", + "@react-spectrum/layout": "^3.6.7", + "@react-spectrum/overlays": "^5.6.3", + "@react-spectrum/text": "^3.5.7", + "@react-spectrum/utils": "^3.11.9", + "@react-spectrum/view": "^3.6.12", + "@react-stately/overlays": "^3.6.9", + "@react-types/button": "^3.9.6", + "@react-types/dialog": "^3.5.12", + "@react-types/shared": "^3.24.1", + "@spectrum-icons/ui": "^3.6.9", "@swc/helpers": "^0.5.0" }, "peerDependencies": { "@react-spectrum/provider": "^3.0.0", - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0", - "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0", + "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" } }, "node_modules/@react-spectrum/divider": { - "version": "3.5.13", - "resolved": "https://registry.npmjs.org/@react-spectrum/divider/-/divider-3.5.13.tgz", - "integrity": "sha512-7LoOTj+qs3yTBZiWudgU5TpzLREApMt0rwzalyq9ORRQrE8C0YXUxlSLPizyUmQeP4Rj8p3lCdUNWAe1cAn1tQ==", - "dependencies": { - "@react-aria/separator": "^3.3.13", - "@react-spectrum/utils": "^3.11.7", - "@react-types/divider": "^3.3.9", - "@react-types/shared": "^3.23.1", + "version": "3.5.15", + "resolved": "https://registry.npmjs.org/@react-spectrum/divider/-/divider-3.5.15.tgz", + "integrity": "sha512-bL0pwPup9VL7W4faxvHonChx8eEbBUhX67/V47wR21q4PmnuP3bOVZ6U3qqCbhA+R246zsyxlBouX3mL6QuKvg==", + "dependencies": { + "@react-aria/separator": "^3.4.1", + "@react-spectrum/utils": "^3.11.9", + "@react-types/divider": "^3.3.11", + "@react-types/shared": "^3.24.1", "@swc/helpers": "^0.5.0" }, "peerDependencies": { - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" } }, "node_modules/@react-spectrum/dnd": { - "version": "3.3.10", - "resolved": "https://registry.npmjs.org/@react-spectrum/dnd/-/dnd-3.3.10.tgz", - "integrity": "sha512-Qp+Fp6BnMgrp5G18IAcbEUetf2YWelRugYJr8TH8h236n8lariyUpri1Mj604DV/UqNoK6f6k6ocY8JBmvOd9Q==", + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/@react-spectrum/dnd/-/dnd-3.4.1.tgz", + "integrity": "sha512-sg99ExYMmm5sb8EWsTJRUK6efb41t+s7Ih19M/iamfhwSaypAZaMbfP1zjtFbUqC9GtEALteZpt5OqVRkiKlvQ==", "dependencies": { - "@react-aria/dnd": "^3.6.1", - "@react-stately/dnd": "^3.3.1", - "@react-types/shared": "^3.23.1", + "@react-aria/dnd": "^3.7.1", + "@react-stately/dnd": "^3.4.1", + "@react-types/shared": "^3.24.1", "@swc/helpers": "^0.5.0" }, "peerDependencies": { "@react-spectrum/provider": "^3.0.0", - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0", - "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0", + "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" } }, "node_modules/@react-spectrum/dropzone": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@react-spectrum/dropzone/-/dropzone-3.0.1.tgz", - "integrity": "sha512-8hEu6mF1ExJMc+Pv5lk3YHz3yZcRy4FkjKgBMXWWn8kxT2DEIK5hONspECBmlsNtUHuk1QQFFSISMGgsMZFQVw==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@react-spectrum/dropzone/-/dropzone-3.0.3.tgz", + "integrity": "sha512-YtX4W9RtAaQwk2RbLmW/GjJ9DimqwGUSYaWAb9+LaoMBiUvEtJsy7m22frtph8wp62crQR1S/u16sTnqq8tlzQ==", "dependencies": { - "@react-aria/i18n": "^3.11.1", - "@react-aria/utils": "^3.24.1", - "@react-spectrum/utils": "^3.11.7", - "@react-types/shared": "^3.23.1", + "@react-aria/i18n": "^3.12.1", + "@react-aria/utils": "^3.25.1", + "@react-spectrum/utils": "^3.11.9", + "@react-types/shared": "^3.24.1", "@swc/helpers": "^0.5.0", - "react-aria-components": "^1.2.1" + "react-aria-components": "^1.3.1" }, "peerDependencies": { "@react-spectrum/provider": "^3.0.0", - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" } }, "node_modules/@react-spectrum/filetrigger": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@react-spectrum/filetrigger/-/filetrigger-3.0.1.tgz", - "integrity": "sha512-9PfhjeGdHjyumlzdvrFNumKnGeaK41kYragnDMSD3KNH0XWu2kVUTB7eUbA9d6FLL/+g8tyPx+wDo0ZJW79Fpg==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@react-spectrum/filetrigger/-/filetrigger-3.0.3.tgz", + "integrity": "sha512-6bWa7ENBaj/oM0JkXd2Q7fzZg/gL23fitK1nVyRfFw9BHfgqCSZwMM2exBJjtX+Az6II4LjhY9cSbL28i9EsGw==", "dependencies": { "@swc/helpers": "^0.5.0", - "react-aria-components": "^1.2.1" + "react-aria-components": "^1.3.1" }, "peerDependencies": { "@react-spectrum/provider": "^3.0.0", - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" } }, "node_modules/@react-spectrum/form": { - "version": "3.7.6", - "resolved": "https://registry.npmjs.org/@react-spectrum/form/-/form-3.7.6.tgz", - "integrity": "sha512-uh/r3d3haWGjdxh++HCCbezWRiw7PGDStvOHEVLCVz/cN0lrUb77dwx5E4jMvY+oLkaBv05R3UtdMxNdXV1DZQ==", - "dependencies": { - "@react-aria/utils": "^3.24.1", - "@react-spectrum/utils": "^3.11.7", - "@react-stately/form": "^3.0.3", - "@react-types/form": "^3.7.4", - "@react-types/shared": "^3.23.1", + "version": "3.7.8", + "resolved": "https://registry.npmjs.org/@react-spectrum/form/-/form-3.7.8.tgz", + "integrity": "sha512-FAsSOhltgBCnqLXsdTeYaDUQo7TU9GT/byCgKs0+FK9RKPQMtwYRCHDmoEOoWVhIlH6jiOTT6UXxRP+uGJiSAg==", + "dependencies": { + "@react-aria/utils": "^3.25.1", + "@react-spectrum/utils": "^3.11.9", + "@react-stately/form": "^3.0.5", + "@react-types/form": "^3.7.6", + "@react-types/shared": "^3.24.1", "@swc/helpers": "^0.5.0" }, "peerDependencies": { "@react-spectrum/provider": "^3.0.0", - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" } }, "node_modules/@react-spectrum/icon": { - "version": "3.7.13", - "resolved": "https://registry.npmjs.org/@react-spectrum/icon/-/icon-3.7.13.tgz", - "integrity": "sha512-hbd1OZ2UOOZ807zkU/ay8TWQOSnB56cj9HHm3FzUBjpTwpt849Pvk4TBO5K2SAmuQi4gslmvFGmd8BoOEoEcjg==", + "version": "3.7.15", + "resolved": "https://registry.npmjs.org/@react-spectrum/icon/-/icon-3.7.15.tgz", + "integrity": "sha512-b8VouL33orbT6wUxsgvmaPrNOXftagVE4BNLbOFhBik98ycy8H+KajCII5ZnTM8O4+9f9lDyO8D0R8n5VeOaiA==", "dependencies": { - "@react-aria/utils": "^3.24.1", - "@react-spectrum/utils": "^3.11.7", - "@react-types/shared": "^3.23.1", + "@react-aria/utils": "^3.25.1", + "@react-spectrum/utils": "^3.11.9", + "@react-types/shared": "^3.24.1", "@swc/helpers": "^0.5.0" }, "peerDependencies": { "@react-spectrum/provider": "^3.0.0", - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" } }, "node_modules/@react-spectrum/illustratedmessage": { - "version": "3.5.1", - "resolved": "https://registry.npmjs.org/@react-spectrum/illustratedmessage/-/illustratedmessage-3.5.1.tgz", - "integrity": "sha512-HpTueLW3duV1TE3sYw5WeBaGECqS0RVEXr2UaXDXSLteY238Oc7prli2qPk2xaGeRKgh97jsfySDBOvedCuZJQ==", - "dependencies": { - "@react-aria/utils": "^3.24.1", - "@react-spectrum/layout": "^3.6.5", - "@react-spectrum/utils": "^3.11.7", - "@react-types/illustratedmessage": "^3.3.9", - "@react-types/shared": "^3.23.1", + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/@react-spectrum/illustratedmessage/-/illustratedmessage-3.5.3.tgz", + "integrity": "sha512-2f5P9s8TWLRWDOdk84aqWkyNhgT8PZfAdbMLpzrzra0QM5FYwABbMDcjtVaprFq55KqPk9iLwGSb0Avk3T+aDA==", + "dependencies": { + "@react-aria/utils": "^3.25.1", + "@react-spectrum/layout": "^3.6.7", + "@react-spectrum/utils": "^3.11.9", + "@react-types/illustratedmessage": "^3.3.11", + "@react-types/shared": "^3.24.1", "@swc/helpers": "^0.5.0" }, "peerDependencies": { "@react-spectrum/provider": "^3.0.0", - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" } }, "node_modules/@react-spectrum/image": { - "version": "3.5.1", - "resolved": "https://registry.npmjs.org/@react-spectrum/image/-/image-3.5.1.tgz", - "integrity": "sha512-MFl2WkMT224L4v1M9n4ZGkkXhBqecQ6uWZfxHBURrTXFMgPq5sxWY7qw42pc3mAX339kNiLZXTCTA5mKyiqxnQ==", + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/@react-spectrum/image/-/image-3.5.3.tgz", + "integrity": "sha512-8ZUkWXH9tnR+ZnxEeMEflo/nMRNFn60VpXOt9hfJlXbhwUKD4eO3TFA14QQXr407XSZwt9d7CGkT4urw4lxtmA==", "dependencies": { - "@react-aria/utils": "^3.24.1", - "@react-spectrum/utils": "^3.11.7", - "@react-types/image": "^3.4.1", - "@react-types/shared": "^3.23.1", + "@react-aria/utils": "^3.25.1", + "@react-spectrum/utils": "^3.11.9", + "@react-types/image": "^3.4.3", + "@react-types/shared": "^3.24.1", "@swc/helpers": "^0.5.0" }, "peerDependencies": { "@react-spectrum/provider": "^3.0.0", - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" } }, "node_modules/@react-spectrum/inlinealert": { - "version": "3.2.5", - "resolved": "https://registry.npmjs.org/@react-spectrum/inlinealert/-/inlinealert-3.2.5.tgz", - "integrity": "sha512-D9EF8pIQME6GHpvk7HR8/Qr3g79l78EsvczL0wGOzdcMt+LoV9F6RNJSobrI+dgzX0RcbqRyWsdCixboFrfefg==", - "dependencies": { - "@react-aria/focus": "^3.17.1", - "@react-aria/i18n": "^3.11.1", - "@react-aria/utils": "^3.24.1", - "@react-spectrum/layout": "^3.6.5", - "@react-spectrum/utils": "^3.11.7", - "@react-types/shared": "^3.23.1", - "@spectrum-icons/ui": "^3.6.7", + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/@react-spectrum/inlinealert/-/inlinealert-3.2.7.tgz", + "integrity": "sha512-jWO7gNx3rulFA0lkvcv/czNdGZRmG77Jo8aAe2ku/96WvJc9h4ZNyTVu7F+8W5iR+I1Ige1D6UHB9dJCTZlfHQ==", + "dependencies": { + "@react-aria/focus": "^3.18.1", + "@react-aria/i18n": "^3.12.1", + "@react-aria/utils": "^3.25.1", + "@react-spectrum/layout": "^3.6.7", + "@react-spectrum/utils": "^3.11.9", + "@react-types/shared": "^3.24.1", + "@spectrum-icons/ui": "^3.6.9", "@swc/helpers": "^0.5.0" }, "peerDependencies": { "@react-spectrum/provider": "^3.0.0", - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" } }, "node_modules/@react-spectrum/label": { - "version": "3.16.6", - "resolved": "https://registry.npmjs.org/@react-spectrum/label/-/label-3.16.6.tgz", - "integrity": "sha512-RF1YqQOKpDYqnSxM+TK/4gZGBsoKjfaZYsOvjya90LvUO8/2Va8Ux0bwHlqtOxu46yjxPLflpt0u9rl9ce+Ubg==", - "dependencies": { - "@react-aria/i18n": "^3.11.1", - "@react-aria/utils": "^3.24.1", - "@react-spectrum/form": "^3.7.6", - "@react-spectrum/layout": "^3.6.5", - "@react-spectrum/utils": "^3.11.7", - "@react-types/label": "^3.9.3", - "@react-types/shared": "^3.23.1", - "@spectrum-icons/ui": "^3.6.7", + "version": "3.16.8", + "resolved": "https://registry.npmjs.org/@react-spectrum/label/-/label-3.16.8.tgz", + "integrity": "sha512-2qIju/PZNzwTviR1OiiT8SR+aZdkBCI+S0GfT/FABjkmxJvm+lWxIhc+okr9CRGgEzCYnq9b3S5PfPIupLh8ew==", + "dependencies": { + "@react-aria/i18n": "^3.12.1", + "@react-aria/utils": "^3.25.1", + "@react-spectrum/form": "^3.7.8", + "@react-spectrum/layout": "^3.6.7", + "@react-spectrum/utils": "^3.11.9", + "@react-types/label": "^3.9.5", + "@react-types/shared": "^3.24.1", + "@spectrum-icons/ui": "^3.6.9", "@swc/helpers": "^0.5.0" }, "peerDependencies": { "@react-spectrum/provider": "^3.0.0", - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" } }, "node_modules/@react-spectrum/labeledvalue": { - "version": "3.1.14", - "resolved": "https://registry.npmjs.org/@react-spectrum/labeledvalue/-/labeledvalue-3.1.14.tgz", - "integrity": "sha512-JeZHCRRmSPShgOozHs31+e0NnN4S3+SP0NpPGFUo0itPHvOcJSV9aoRCefdMTdXbUupIi5h1EM5Ty0owdy8y0w==", - "dependencies": { - "@internationalized/date": "^3.5.4", - "@react-aria/i18n": "^3.11.1", - "@react-aria/utils": "^3.24.1", - "@react-spectrum/label": "^3.16.6", - "@react-spectrum/utils": "^3.11.7", - "@react-types/shared": "^3.23.1", + "version": "3.1.16", + "resolved": "https://registry.npmjs.org/@react-spectrum/labeledvalue/-/labeledvalue-3.1.16.tgz", + "integrity": "sha512-ZzrGErsGvnndVpL9MMdanYpmL4I97enWU7tQ6w17TUvmb6pG4VIKUVepPMpw9sn9VcEc44dY56nDqH9m+uR35g==", + "dependencies": { + "@internationalized/date": "^3.5.5", + "@react-aria/i18n": "^3.12.1", + "@react-aria/utils": "^3.25.1", + "@react-spectrum/label": "^3.16.8", + "@react-spectrum/utils": "^3.11.9", + "@react-types/shared": "^3.24.1", "@swc/helpers": "^0.5.0" }, "peerDependencies": { "@react-spectrum/provider": "^3.0.0", - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" } }, "node_modules/@react-spectrum/layout": { - "version": "3.6.5", - "resolved": "https://registry.npmjs.org/@react-spectrum/layout/-/layout-3.6.5.tgz", - "integrity": "sha512-kl/vZue7ZQZtkypPeOPZ3WENk4Mn9aYsjSBFZP+3GVRGPi0GBlhVOSicraio7UD3oGz1Xkhy5WZg01s3zQC0zg==", - "dependencies": { - "@react-aria/utils": "^3.24.1", - "@react-spectrum/utils": "^3.11.7", - "@react-types/layout": "^3.3.15", - "@react-types/shared": "^3.23.1", + "version": "3.6.7", + "resolved": "https://registry.npmjs.org/@react-spectrum/layout/-/layout-3.6.7.tgz", + "integrity": "sha512-EheC/J99qt2GpVq05UqPk9iH9PImH9SHXmikNqf/pckKH2Xh/EUY9t5ab+oOYq0N9JbdLp9a38AvuL9KyTJAFQ==", + "dependencies": { + "@react-aria/utils": "^3.25.1", + "@react-spectrum/utils": "^3.11.9", + "@react-types/layout": "^3.3.17", + "@react-types/shared": "^3.24.1", "@swc/helpers": "^0.5.0" }, "peerDependencies": { "@react-spectrum/provider": "^3.0.0", - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" } }, "node_modules/@react-spectrum/link": { - "version": "3.6.7", - "resolved": "https://registry.npmjs.org/@react-spectrum/link/-/link-3.6.7.tgz", - "integrity": "sha512-g9yWHXO8OdoOnUH0xAIek5wDHDi0gYmEL3hqqKwzfMvkmQQCQjVS+D/9IlkxKT5LaumUiHdHDiA2PL1voPUh0g==", - "dependencies": { - "@react-aria/focus": "^3.17.1", - "@react-aria/interactions": "^3.21.3", - "@react-aria/link": "^3.7.1", - "@react-aria/utils": "^3.24.1", - "@react-spectrum/utils": "^3.11.7", - "@react-types/link": "^3.5.5", + "version": "3.6.9", + "resolved": "https://registry.npmjs.org/@react-spectrum/link/-/link-3.6.9.tgz", + "integrity": "sha512-eZDGvH8R1GKQVnlk5h1T6utKO/i3xFEhqC8cI/B5Pwh3WwVB9fSwUljzf9Cb3dqfSMTFXH3GrPmF1XVfRIliFg==", + "dependencies": { + "@react-aria/focus": "^3.18.1", + "@react-aria/interactions": "^3.22.1", + "@react-aria/link": "^3.7.3", + "@react-aria/utils": "^3.25.1", + "@react-spectrum/utils": "^3.11.9", + "@react-types/link": "^3.5.7", + "@react-types/shared": "^3.24.1", "@swc/helpers": "^0.5.0" }, "peerDependencies": { "@react-spectrum/provider": "^3.0.0", - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" } }, "node_modules/@react-spectrum/list": { - "version": "3.7.10", - "resolved": "https://registry.npmjs.org/@react-spectrum/list/-/list-3.7.10.tgz", - "integrity": "sha512-UxS+pXgJGaTeLP+KQdq7IQsaJN1tq6tpqFXFKXdrXGnLZPd9GtBT3zYP2Rnb9r/6Vm67D+pewF6tVKLzctE1sw==", - "dependencies": { - "@react-aria/button": "^3.9.5", - "@react-aria/focus": "^3.17.1", - "@react-aria/gridlist": "^3.8.1", - "@react-aria/i18n": "^3.11.1", - "@react-aria/interactions": "^3.21.3", - "@react-aria/utils": "^3.24.1", - "@react-aria/virtualizer": "^3.10.1", - "@react-aria/visually-hidden": "^3.8.12", - "@react-spectrum/checkbox": "^3.9.6", - "@react-spectrum/dnd": "^3.3.10", - "@react-spectrum/layout": "^3.6.5", - "@react-spectrum/progress": "^3.7.7", - "@react-spectrum/text": "^3.5.5", - "@react-spectrum/utils": "^3.11.7", - "@react-stately/collections": "^3.10.7", - "@react-stately/layout": "^3.13.9", - "@react-stately/list": "^3.10.5", - "@react-types/grid": "^3.2.6", - "@react-types/shared": "^3.23.1", - "@spectrum-icons/ui": "^3.6.7", + "version": "3.8.1", + "resolved": "https://registry.npmjs.org/@react-spectrum/list/-/list-3.8.1.tgz", + "integrity": "sha512-8gSq7cMtVwrPA7DMCg2b9PEYcT8IAmpsKREtAWGOZtzT0xgm8xdEwMUAbhbiDmE1Nbuupe+0vDl2XkUjlrdmXw==", + "dependencies": { + "@react-aria/button": "^3.9.7", + "@react-aria/focus": "^3.18.1", + "@react-aria/gridlist": "^3.9.1", + "@react-aria/i18n": "^3.12.1", + "@react-aria/interactions": "^3.22.1", + "@react-aria/selection": "^3.19.1", + "@react-aria/utils": "^3.25.1", + "@react-aria/virtualizer": "^4.0.1", + "@react-aria/visually-hidden": "^3.8.14", + "@react-spectrum/checkbox": "^3.9.8", + "@react-spectrum/dnd": "^3.4.1", + "@react-spectrum/layout": "^3.6.7", + "@react-spectrum/progress": "^3.7.9", + "@react-spectrum/text": "^3.5.7", + "@react-spectrum/utils": "^3.11.9", + "@react-stately/collections": "^3.10.9", + "@react-stately/layout": "^4.0.1", + "@react-stately/list": "^3.10.7", + "@react-stately/virtualizer": "^4.0.1", + "@react-types/grid": "^3.2.8", + "@react-types/shared": "^3.24.1", + "@spectrum-icons/ui": "^3.6.9", "@swc/helpers": "^0.5.0", "react-transition-group": "^4.4.5" }, "peerDependencies": { "@react-spectrum/provider": "^3.2.0", - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0", - "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0", + "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" } }, "node_modules/@react-spectrum/listbox": { - "version": "3.12.9", - "resolved": "https://registry.npmjs.org/@react-spectrum/listbox/-/listbox-3.12.9.tgz", - "integrity": "sha512-9adZJtEtAVwNtJEU70edZOlx+LfBOeVpWCOXoAJ+5iU+rNrQER7bEpFj15GlJOL+vcwFuCPoIsDBKSxygJANLw==", - "dependencies": { - "@react-aria/focus": "^3.17.1", - "@react-aria/i18n": "^3.11.1", - "@react-aria/interactions": "^3.21.3", - "@react-aria/listbox": "^3.12.1", - "@react-aria/utils": "^3.24.1", - "@react-aria/virtualizer": "^3.10.1", - "@react-spectrum/layout": "^3.6.5", - "@react-spectrum/progress": "^3.7.7", - "@react-spectrum/text": "^3.5.5", - "@react-spectrum/utils": "^3.11.7", - "@react-stately/collections": "^3.10.7", - "@react-stately/layout": "^3.13.9", - "@react-stately/list": "^3.10.5", - "@react-stately/virtualizer": "^3.7.1", - "@react-types/listbox": "^3.4.9", - "@react-types/shared": "^3.23.1", - "@spectrum-icons/ui": "^3.6.7", + "version": "3.13.1", + "resolved": "https://registry.npmjs.org/@react-spectrum/listbox/-/listbox-3.13.1.tgz", + "integrity": "sha512-VaLxXVMMDltrQclfWUZJcpq/0u4Ijm2vr1S1L4ype2VF2S8X2gKiwnfsMfzjhxmfSvjKr1vH+kxRC45sDuFdWA==", + "dependencies": { + "@react-aria/focus": "^3.18.1", + "@react-aria/i18n": "^3.12.1", + "@react-aria/interactions": "^3.22.1", + "@react-aria/listbox": "^3.13.1", + "@react-aria/utils": "^3.25.1", + "@react-aria/virtualizer": "^4.0.1", + "@react-spectrum/layout": "^3.6.7", + "@react-spectrum/progress": "^3.7.9", + "@react-spectrum/text": "^3.5.7", + "@react-spectrum/utils": "^3.11.9", + "@react-stately/collections": "^3.10.9", + "@react-stately/layout": "^4.0.1", + "@react-stately/list": "^3.10.7", + "@react-stately/virtualizer": "^4.0.1", + "@react-types/listbox": "^3.5.1", + "@react-types/shared": "^3.24.1", + "@spectrum-icons/ui": "^3.6.9", "@swc/helpers": "^0.5.0" }, "peerDependencies": { "@react-spectrum/provider": "^3.2.0", - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0", - "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0", + "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" } }, "node_modules/@react-spectrum/menu": { - "version": "3.19.1", - "resolved": "https://registry.npmjs.org/@react-spectrum/menu/-/menu-3.19.1.tgz", - "integrity": "sha512-/bpqSPef1UvoaIwd5GVrqMt8LiByi5rV9yh0K+SSzZ5uY/w4zRQN9y14XnLf4P53R67DpSqAqk3JoWOLFj0Zcg==", - "dependencies": { - "@react-aria/focus": "^3.17.1", - "@react-aria/i18n": "^3.11.1", - "@react-aria/interactions": "^3.21.3", - "@react-aria/menu": "^3.14.1", - "@react-aria/overlays": "^3.22.1", - "@react-aria/separator": "^3.3.13", - "@react-aria/utils": "^3.24.1", - "@react-spectrum/button": "^3.16.4", - "@react-spectrum/layout": "^3.6.5", - "@react-spectrum/overlays": "^5.6.1", - "@react-spectrum/text": "^3.5.5", - "@react-spectrum/utils": "^3.11.7", - "@react-stately/collections": "^3.10.7", - "@react-stately/menu": "^3.7.1", - "@react-stately/overlays": "^3.6.7", - "@react-stately/tree": "^3.8.1", - "@react-types/menu": "^3.9.9", - "@react-types/overlays": "^3.8.7", - "@react-types/shared": "^3.23.1", - "@spectrum-icons/ui": "^3.6.7", - "@spectrum-icons/workflow": "^4.2.12", + "version": "3.20.1", + "resolved": "https://registry.npmjs.org/@react-spectrum/menu/-/menu-3.20.1.tgz", + "integrity": "sha512-lIkL14tJaZh3Ago2x8EMcLlyGBMRquDz0OsqgMHeHwQOtUOnIY31JdrWNBdSYWgASZDytrKJSU4e5gXRMCYNEw==", + "dependencies": { + "@react-aria/focus": "^3.18.1", + "@react-aria/i18n": "^3.12.1", + "@react-aria/interactions": "^3.22.1", + "@react-aria/menu": "^3.15.1", + "@react-aria/overlays": "^3.23.1", + "@react-aria/separator": "^3.4.1", + "@react-aria/utils": "^3.25.1", + "@react-spectrum/button": "^3.16.6", + "@react-spectrum/layout": "^3.6.7", + "@react-spectrum/overlays": "^5.6.3", + "@react-spectrum/text": "^3.5.7", + "@react-spectrum/utils": "^3.11.9", + "@react-stately/collections": "^3.10.9", + "@react-stately/menu": "^3.8.1", + "@react-stately/overlays": "^3.6.9", + "@react-stately/tree": "^3.8.3", + "@react-types/menu": "^3.9.11", + "@react-types/overlays": "^3.8.9", + "@react-types/shared": "^3.24.1", + "@spectrum-icons/ui": "^3.6.9", + "@spectrum-icons/workflow": "^4.2.14", "@swc/helpers": "^0.5.0" }, "peerDependencies": { "@react-spectrum/provider": "^3.0.0", - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0", - "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0", + "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" } }, "node_modules/@react-spectrum/meter": { - "version": "3.5.1", - "resolved": "https://registry.npmjs.org/@react-spectrum/meter/-/meter-3.5.1.tgz", - "integrity": "sha512-xmQwPDmT8hfkEuyUrijpe2xXyzWlFErrnKpQIf49Lql/GudeGHIvtekx3Qj2kvhwLpHKeOOECk35PufCJmwF2A==", - "dependencies": { - "@react-aria/meter": "^3.4.13", - "@react-spectrum/progress": "^3.7.7", - "@react-spectrum/utils": "^3.11.7", - "@react-types/meter": "^3.4.1", - "@react-types/shared": "^3.23.1", + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/@react-spectrum/meter/-/meter-3.5.3.tgz", + "integrity": "sha512-mfsF+O4MkjaMGBQRT80zn5yd1TXtBF/aqtW2nrGFKxE/sRGJ6mWuqEuPheL+jEuQwcnAanQBk03+yaSUgYPW8Q==", + "dependencies": { + "@react-aria/meter": "^3.4.15", + "@react-spectrum/progress": "^3.7.9", + "@react-spectrum/utils": "^3.11.9", + "@react-types/meter": "^3.4.3", + "@react-types/shared": "^3.24.1", "@swc/helpers": "^0.5.0" }, "peerDependencies": { "@react-spectrum/provider": "^3.0.0", - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" } }, "node_modules/@react-spectrum/numberfield": { - "version": "3.9.3", - "resolved": "https://registry.npmjs.org/@react-spectrum/numberfield/-/numberfield-3.9.3.tgz", - "integrity": "sha512-t3LllH5NkaqlwkvfFVizmzp4+MhMCqooLlUsBIbDgqyNCWEbxiC16ZqPOPkZkBDFio1aKX0zzSb9SiuUFw2ZwA==", - "dependencies": { - "@react-aria/button": "^3.9.5", - "@react-aria/focus": "^3.17.1", - "@react-aria/i18n": "^3.11.1", - "@react-aria/interactions": "^3.21.3", - "@react-aria/numberfield": "^3.11.3", - "@react-aria/utils": "^3.24.1", - "@react-spectrum/form": "^3.7.6", - "@react-spectrum/label": "^3.16.6", - "@react-spectrum/textfield": "^3.12.1", - "@react-spectrum/utils": "^3.11.7", - "@react-stately/numberfield": "^3.9.3", - "@react-types/button": "^3.9.4", - "@react-types/numberfield": "^3.8.3", - "@react-types/shared": "^3.23.1", - "@spectrum-icons/ui": "^3.6.7", - "@spectrum-icons/workflow": "^4.2.12", + "version": "3.9.5", + "resolved": "https://registry.npmjs.org/@react-spectrum/numberfield/-/numberfield-3.9.5.tgz", + "integrity": "sha512-fmaeAarm3ay7PpbrvvIrKkHdEMSKsuRyjcfkSjLCpkkI2D2sg2iJBtlbD+FypwvkpMJh/Lk6UPpirNgsX/+kcw==", + "dependencies": { + "@react-aria/button": "^3.9.7", + "@react-aria/focus": "^3.18.1", + "@react-aria/i18n": "^3.12.1", + "@react-aria/interactions": "^3.22.1", + "@react-aria/numberfield": "^3.11.5", + "@react-aria/utils": "^3.25.1", + "@react-spectrum/form": "^3.7.8", + "@react-spectrum/label": "^3.16.8", + "@react-spectrum/textfield": "^3.12.3", + "@react-spectrum/utils": "^3.11.9", + "@react-stately/numberfield": "^3.9.5", + "@react-types/button": "^3.9.6", + "@react-types/numberfield": "^3.8.5", + "@react-types/shared": "^3.24.1", + "@spectrum-icons/ui": "^3.6.9", + "@spectrum-icons/workflow": "^4.2.14", "@swc/helpers": "^0.5.0" }, "peerDependencies": { "@react-spectrum/provider": "^3.0.0", - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0", - "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0", + "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" } }, "node_modules/@react-spectrum/overlays": { - "version": "5.6.1", - "resolved": "https://registry.npmjs.org/@react-spectrum/overlays/-/overlays-5.6.1.tgz", - "integrity": "sha512-ABacMG1V6gHCHHHtD01xt9RjTCu51Kytr/oHdUPEFd5Zvh8m/O7j3IQI4nSj5a5kDoj73NAkENq9Cq12gjwL4g==", - "dependencies": { - "@react-aria/interactions": "^3.21.3", - "@react-aria/overlays": "^3.22.1", - "@react-aria/utils": "^3.24.1", - "@react-spectrum/utils": "^3.11.7", - "@react-stately/overlays": "^3.6.7", - "@react-types/overlays": "^3.8.7", - "@react-types/shared": "^3.23.1", + "version": "5.6.3", + "resolved": "https://registry.npmjs.org/@react-spectrum/overlays/-/overlays-5.6.3.tgz", + "integrity": "sha512-EUnpn99fx3nmBQAUc1Cxgf75Ro1Cg1rey1SC/TIVllhz2D3tSOsDD22I/eWXMEdBNS+IeSFzbEGApOvJrp4RKQ==", + "dependencies": { + "@react-aria/interactions": "^3.22.1", + "@react-aria/overlays": "^3.23.1", + "@react-aria/utils": "^3.25.1", + "@react-spectrum/utils": "^3.11.9", + "@react-stately/overlays": "^3.6.9", + "@react-types/overlays": "^3.8.9", + "@react-types/shared": "^3.24.1", "@swc/helpers": "^0.5.0", "react-transition-group": "^4.4.5" }, "peerDependencies": { "@react-spectrum/provider": "^3.0.0", - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0", - "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0", + "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" } }, "node_modules/@react-spectrum/picker": { - "version": "3.14.5", - "resolved": "https://registry.npmjs.org/@react-spectrum/picker/-/picker-3.14.5.tgz", - "integrity": "sha512-FBCMibgStP62XKS2yJWHtn+XOLsxuzs0pl0jHkozuBaqC42H6fkDcINgQ08wbS2PlEEJSOYIkeL3LXFcxuewEA==", - "dependencies": { - "@react-aria/i18n": "^3.11.1", - "@react-aria/interactions": "^3.21.3", - "@react-aria/select": "^3.14.5", - "@react-aria/utils": "^3.24.1", - "@react-spectrum/button": "^3.16.4", - "@react-spectrum/form": "^3.7.6", - "@react-spectrum/label": "^3.16.6", - "@react-spectrum/listbox": "^3.12.9", - "@react-spectrum/overlays": "^5.6.1", - "@react-spectrum/progress": "^3.7.7", - "@react-spectrum/text": "^3.5.5", - "@react-spectrum/utils": "^3.11.7", - "@react-stately/collections": "^3.10.7", - "@react-stately/select": "^3.6.4", - "@react-types/select": "^3.9.4", - "@react-types/shared": "^3.23.1", - "@spectrum-icons/ui": "^3.6.7", + "version": "3.15.1", + "resolved": "https://registry.npmjs.org/@react-spectrum/picker/-/picker-3.15.1.tgz", + "integrity": "sha512-vsTRw7U7d1TppJwJtwXfZ75WgUf87nIDOhNrqykVvCXxt7C9DTJ8OwJPBfOl88ImfT4U1f6ldr681uC4VU7lIA==", + "dependencies": { + "@react-aria/i18n": "^3.12.1", + "@react-aria/interactions": "^3.22.1", + "@react-aria/select": "^3.14.7", + "@react-aria/utils": "^3.25.1", + "@react-spectrum/button": "^3.16.6", + "@react-spectrum/form": "^3.7.8", + "@react-spectrum/label": "^3.16.8", + "@react-spectrum/listbox": "^3.13.1", + "@react-spectrum/overlays": "^5.6.3", + "@react-spectrum/progress": "^3.7.9", + "@react-spectrum/text": "^3.5.7", + "@react-spectrum/utils": "^3.11.9", + "@react-stately/collections": "^3.10.9", + "@react-stately/select": "^3.6.6", + "@react-types/select": "^3.9.6", + "@react-types/shared": "^3.24.1", + "@spectrum-icons/ui": "^3.6.9", "@swc/helpers": "^0.5.0" }, "peerDependencies": { "@react-spectrum/provider": "^3.1.4", - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0", - "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0", + "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" } }, "node_modules/@react-spectrum/progress": { - "version": "3.7.7", - "resolved": "https://registry.npmjs.org/@react-spectrum/progress/-/progress-3.7.7.tgz", - "integrity": "sha512-FI/oc9hEQqbv00VJbaxqFTncBDDbxWN9cbvNNrPoROBQWL3NgB3tvEqY/fm5IXtDeFEV/U+tSm8BnZTGn6Mdxg==", - "dependencies": { - "@react-aria/progress": "^3.4.13", - "@react-aria/utils": "^3.24.1", - "@react-spectrum/utils": "^3.11.7", - "@react-types/progress": "^3.5.4", - "@react-types/shared": "^3.23.1", + "version": "3.7.9", + "resolved": "https://registry.npmjs.org/@react-spectrum/progress/-/progress-3.7.9.tgz", + "integrity": "sha512-C6sozAPqupK1geqhmbS9K28b5xW2ZdIiBrk1XGjIiBuAqQZhvqFxCliwr2pbjWPcOGLQJrgc8dGWUuvZXUtGXQ==", + "dependencies": { + "@react-aria/progress": "^3.4.15", + "@react-aria/utils": "^3.25.1", + "@react-spectrum/utils": "^3.11.9", + "@react-types/progress": "^3.5.6", + "@react-types/shared": "^3.24.1", "@swc/helpers": "^0.5.0" }, "peerDependencies": { "@react-spectrum/provider": "^3.0.0", - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" } }, "node_modules/@react-spectrum/provider": { - "version": "3.9.7", - "resolved": "https://registry.npmjs.org/@react-spectrum/provider/-/provider-3.9.7.tgz", - "integrity": "sha512-VRu8cOWrLJU/Krulo8njfPCMeJT+uu1k9GjFZ9Cw88mHGW7a3MK54IzI5p2evLPab7pgplPIoJcv3bC2XB+DAA==", - "dependencies": { - "@react-aria/i18n": "^3.11.1", - "@react-aria/overlays": "^3.22.1", - "@react-aria/utils": "^3.24.1", - "@react-spectrum/utils": "^3.11.7", - "@react-types/provider": "^3.8.1", - "@react-types/shared": "^3.23.1", + "version": "3.9.9", + "resolved": "https://registry.npmjs.org/@react-spectrum/provider/-/provider-3.9.9.tgz", + "integrity": "sha512-sVgIG0MZ/4KCrJgWjOGyEdP5nhl8fXxp6L1s7SWyzWT/e6ypD0Og9hkQo/yY2XHP2hI4ZiZ4Psc1H4olsrp5lw==", + "dependencies": { + "@react-aria/i18n": "^3.12.1", + "@react-aria/overlays": "^3.23.1", + "@react-aria/utils": "^3.25.1", + "@react-spectrum/utils": "^3.11.9", + "@react-types/provider": "^3.8.3", + "@react-types/shared": "^3.24.1", "@swc/helpers": "^0.5.0", "clsx": "^2.0.0" }, "peerDependencies": { - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0", - "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0", + "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" } }, "node_modules/@react-spectrum/radio": { - "version": "3.7.6", - "resolved": "https://registry.npmjs.org/@react-spectrum/radio/-/radio-3.7.6.tgz", - "integrity": "sha512-KRtipJfIkRWbnvhS/zZ7j3ltEQXrQeVNhmIWChuP+sC5hdA3N8llMgf30Xa9PqtFhGH4CvUlXC9NA/rhLWnm4w==", - "dependencies": { - "@react-aria/focus": "^3.17.1", - "@react-aria/interactions": "^3.21.3", - "@react-aria/radio": "^3.10.4", - "@react-spectrum/form": "^3.7.6", - "@react-spectrum/label": "^3.16.6", - "@react-spectrum/utils": "^3.11.7", - "@react-stately/radio": "^3.10.4", - "@react-types/radio": "^3.8.1", - "@react-types/shared": "^3.23.1", + "version": "3.7.8", + "resolved": "https://registry.npmjs.org/@react-spectrum/radio/-/radio-3.7.8.tgz", + "integrity": "sha512-H11U3Hf15wVhp8hoyYR2bUKgKyyihhjPw40rf2ZESnS/FEeOifVQtzr6UbEKqb1qC/LX5YhuHjUyXv+j4DuVeA==", + "dependencies": { + "@react-aria/focus": "^3.18.1", + "@react-aria/interactions": "^3.22.1", + "@react-aria/radio": "^3.10.6", + "@react-spectrum/form": "^3.7.8", + "@react-spectrum/label": "^3.16.8", + "@react-spectrum/utils": "^3.11.9", + "@react-stately/radio": "^3.10.6", + "@react-types/radio": "^3.8.3", + "@react-types/shared": "^3.24.1", "@swc/helpers": "^0.5.0" }, "peerDependencies": { "@react-spectrum/provider": "^3.0.0", - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" } }, "node_modules/@react-spectrum/searchfield": { - "version": "3.8.6", - "resolved": "https://registry.npmjs.org/@react-spectrum/searchfield/-/searchfield-3.8.6.tgz", - "integrity": "sha512-RU928ZeQsqPGMsNVtoLvahHmuRC3OAW9im5W0/CVgglINn2IapF2U0oxHVw6ymzx1NyCYrYR8pO9skMF0E68/Q==", - "dependencies": { - "@react-aria/searchfield": "^3.7.5", - "@react-spectrum/button": "^3.16.4", - "@react-spectrum/form": "^3.7.6", - "@react-spectrum/textfield": "^3.12.1", - "@react-spectrum/utils": "^3.11.7", - "@react-stately/searchfield": "^3.5.3", - "@react-types/searchfield": "^3.5.5", - "@react-types/textfield": "^3.9.3", - "@spectrum-icons/ui": "^3.6.7", + "version": "3.8.8", + "resolved": "https://registry.npmjs.org/@react-spectrum/searchfield/-/searchfield-3.8.8.tgz", + "integrity": "sha512-HR0lQNNzjNyi12bEJ39U/rASZpQuHIpUq9A3DzarRMARrHLmidHzH4F7zu9I4k3GTFm/mL+j2q44EJIP2GqtQQ==", + "dependencies": { + "@react-aria/searchfield": "^3.7.7", + "@react-spectrum/button": "^3.16.6", + "@react-spectrum/form": "^3.7.8", + "@react-spectrum/textfield": "^3.12.3", + "@react-spectrum/utils": "^3.11.9", + "@react-stately/searchfield": "^3.5.5", + "@react-types/searchfield": "^3.5.7", + "@react-types/textfield": "^3.9.5", + "@spectrum-icons/ui": "^3.6.9", "@swc/helpers": "^0.5.0" }, "peerDependencies": { "@react-spectrum/provider": "^3.0.0", - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" } }, "node_modules/@react-spectrum/slider": { - "version": "3.6.9", - "resolved": "https://registry.npmjs.org/@react-spectrum/slider/-/slider-3.6.9.tgz", - "integrity": "sha512-2X6qxlyObfowb8uZQ8UXEozozcfGLzhQI9BS9DS9Kste/REXMTcRDzFygP1D1HdkvRaWmYRNoYhi/Jl2Kkw7Eg==", - "dependencies": { - "@react-aria/focus": "^3.17.1", - "@react-aria/i18n": "^3.11.1", - "@react-aria/interactions": "^3.21.3", - "@react-aria/slider": "^3.7.8", - "@react-aria/utils": "^3.24.1", - "@react-aria/visually-hidden": "^3.8.12", - "@react-spectrum/utils": "^3.11.7", - "@react-stately/slider": "^3.5.4", - "@react-types/shared": "^3.23.1", - "@react-types/slider": "^3.7.3", + "version": "3.6.11", + "resolved": "https://registry.npmjs.org/@react-spectrum/slider/-/slider-3.6.11.tgz", + "integrity": "sha512-Rz8yzQKZTO+PBjnEwRCd+dxIMo/A7Qsj1Vs3sVowSlmLeq6qHeLajdTbe2SN95pUC/b6n+tkNxMyy2bzsW2VlQ==", + "dependencies": { + "@react-aria/focus": "^3.18.1", + "@react-aria/i18n": "^3.12.1", + "@react-aria/interactions": "^3.22.1", + "@react-aria/slider": "^3.7.10", + "@react-aria/utils": "^3.25.1", + "@react-aria/visually-hidden": "^3.8.14", + "@react-spectrum/utils": "^3.11.9", + "@react-stately/slider": "^3.5.6", + "@react-types/shared": "^3.24.1", + "@react-types/slider": "^3.7.5", "@swc/helpers": "^0.5.0" }, "peerDependencies": { "@react-spectrum/provider": "^3.0.0", - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" } }, "node_modules/@react-spectrum/statuslight": { - "version": "3.5.13", - "resolved": "https://registry.npmjs.org/@react-spectrum/statuslight/-/statuslight-3.5.13.tgz", - "integrity": "sha512-FvvsDVs9lapRf5zmOq3g8ZRpAxOTVRfhG9WyehIqgaRPtqqNpQhAGSXWz0ErXF3zV8AwVvjD70g0atcDCoDeBQ==", - "dependencies": { - "@react-aria/utils": "^3.24.1", - "@react-spectrum/utils": "^3.11.7", - "@react-types/shared": "^3.23.1", - "@react-types/statuslight": "^3.3.9", + "version": "3.5.15", + "resolved": "https://registry.npmjs.org/@react-spectrum/statuslight/-/statuslight-3.5.15.tgz", + "integrity": "sha512-gTv4HvnJNcNBTJs3Xw6ki984A7Z58CE2jlKEJ9+PrOJY+cckjeocfWR1XqQsJHCaNuGC9LYhzuJsqsPnqxFNZA==", + "dependencies": { + "@react-aria/utils": "^3.25.1", + "@react-spectrum/utils": "^3.11.9", + "@react-types/shared": "^3.24.1", + "@react-types/statuslight": "^3.3.11", "@swc/helpers": "^0.5.0" }, "peerDependencies": { "@react-spectrum/provider": "^3.0.0", - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" } }, "node_modules/@react-spectrum/switch": { - "version": "3.5.5", - "resolved": "https://registry.npmjs.org/@react-spectrum/switch/-/switch-3.5.5.tgz", - "integrity": "sha512-IIVctsGXnChqMlvf2/pMRkI84vyjf0gMsBXEgky8h8s4i91wxQvl6800/4I9rCSQdAAnQYb+Nd3St8Ik7BupQg==", - "dependencies": { - "@react-aria/focus": "^3.17.1", - "@react-aria/interactions": "^3.21.3", - "@react-aria/switch": "^3.6.4", - "@react-spectrum/utils": "^3.11.7", - "@react-stately/toggle": "^3.7.4", - "@react-types/shared": "^3.23.1", - "@react-types/switch": "^3.5.3", + "version": "3.5.7", + "resolved": "https://registry.npmjs.org/@react-spectrum/switch/-/switch-3.5.7.tgz", + "integrity": "sha512-tXkUadG3VeCGskROYUdFjYNSsQ9G1D72hCG7LoXusIUqYzvNz3xlm3TSP1LOF/lq+WGhPxhhV5LkA1HqN+ZeeA==", + "dependencies": { + "@react-aria/focus": "^3.18.1", + "@react-aria/interactions": "^3.22.1", + "@react-aria/switch": "^3.6.6", + "@react-spectrum/utils": "^3.11.9", + "@react-stately/toggle": "^3.7.6", + "@react-types/shared": "^3.24.1", + "@react-types/switch": "^3.5.5", "@swc/helpers": "^0.5.0" }, "peerDependencies": { "@react-spectrum/provider": "^3.0.0", - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" } }, "node_modules/@react-spectrum/table": { - "version": "3.12.10", - "resolved": "https://registry.npmjs.org/@react-spectrum/table/-/table-3.12.10.tgz", - "integrity": "sha512-a9Qa/1uuoChRez6GncmYdkDgSS4MDXzV4Cl/BrO44Dnph1ygXiJGmBgAvmtevcbndfuERGHoIYqzklIr6veArg==", - "dependencies": { - "@react-aria/button": "^3.9.5", - "@react-aria/focus": "^3.17.1", - "@react-aria/i18n": "^3.11.1", - "@react-aria/interactions": "^3.21.3", - "@react-aria/overlays": "^3.22.1", - "@react-aria/table": "^3.14.1", - "@react-aria/utils": "^3.24.1", - "@react-aria/virtualizer": "^3.10.1", - "@react-aria/visually-hidden": "^3.8.12", - "@react-spectrum/checkbox": "^3.9.6", - "@react-spectrum/dnd": "^3.3.10", - "@react-spectrum/layout": "^3.6.5", - "@react-spectrum/menu": "^3.19.1", - "@react-spectrum/progress": "^3.7.7", - "@react-spectrum/tooltip": "^3.6.7", - "@react-spectrum/utils": "^3.11.7", + "version": "3.13.1", + "resolved": "https://registry.npmjs.org/@react-spectrum/table/-/table-3.13.1.tgz", + "integrity": "sha512-CnxgizMey9sdAL3iyMCX0BGim+USgeKtss8ZIzWIhGmrUBpoQy32ZedXpcN7UwBIScWYo1b44fyNxw6z44K6Dw==", + "dependencies": { + "@react-aria/button": "^3.9.7", + "@react-aria/focus": "^3.18.1", + "@react-aria/i18n": "^3.12.1", + "@react-aria/interactions": "^3.22.1", + "@react-aria/overlays": "^3.23.1", + "@react-aria/selection": "^3.19.1", + "@react-aria/table": "^3.15.1", + "@react-aria/utils": "^3.25.1", + "@react-aria/virtualizer": "^4.0.1", + "@react-aria/visually-hidden": "^3.8.14", + "@react-spectrum/checkbox": "^3.9.8", + "@react-spectrum/dnd": "^3.4.1", + "@react-spectrum/layout": "^3.6.7", + "@react-spectrum/menu": "^3.20.1", + "@react-spectrum/progress": "^3.7.9", + "@react-spectrum/tooltip": "^3.6.9", + "@react-spectrum/utils": "^3.11.9", "@react-stately/flags": "^3.0.3", - "@react-stately/layout": "^3.13.9", - "@react-stately/table": "^3.11.8", - "@react-stately/virtualizer": "^3.7.1", - "@react-types/grid": "^3.2.6", - "@react-types/shared": "^3.23.1", - "@react-types/table": "^3.9.5", - "@spectrum-icons/ui": "^3.6.7", + "@react-stately/layout": "^4.0.1", + "@react-stately/table": "^3.12.1", + "@react-stately/virtualizer": "^4.0.1", + "@react-types/grid": "^3.2.8", + "@react-types/shared": "^3.24.1", + "@react-types/table": "^3.10.1", + "@spectrum-icons/ui": "^3.6.9", "@swc/helpers": "^0.5.0" }, "peerDependencies": { "@react-spectrum/provider": "^3.0.0", - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0", - "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0", + "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" } }, "node_modules/@react-spectrum/tabs": { - "version": "3.8.10", - "resolved": "https://registry.npmjs.org/@react-spectrum/tabs/-/tabs-3.8.10.tgz", - "integrity": "sha512-LoNkxalAbOjKgbF/x3NU5zhvhUgAEqJvEwzKLVSr+KDQlMAFe9LZ+HOH2NRiWR8ak9BkW3RR6C8cGo7G7fdrfA==", - "dependencies": { - "@react-aria/focus": "^3.17.1", - "@react-aria/i18n": "^3.11.1", - "@react-aria/interactions": "^3.21.3", - "@react-aria/tabs": "^3.9.1", - "@react-aria/utils": "^3.24.1", - "@react-spectrum/picker": "^3.14.5", - "@react-spectrum/text": "^3.5.5", - "@react-spectrum/utils": "^3.11.7", - "@react-stately/collections": "^3.10.7", - "@react-stately/list": "^3.10.5", - "@react-stately/tabs": "^3.6.6", - "@react-types/select": "^3.9.4", - "@react-types/shared": "^3.23.1", - "@react-types/tabs": "^3.3.7", + "version": "3.8.12", + "resolved": "https://registry.npmjs.org/@react-spectrum/tabs/-/tabs-3.8.12.tgz", + "integrity": "sha512-tvHEzV5Web6D98vLNbWVwrGGNKx/n6NeuYB6QX88lA8Pp0M9XCuQ6S6548Zk/eUHS0eExi60yX+AcPn1mZTtNQ==", + "dependencies": { + "@react-aria/focus": "^3.18.1", + "@react-aria/i18n": "^3.12.1", + "@react-aria/interactions": "^3.22.1", + "@react-aria/tabs": "^3.9.3", + "@react-aria/utils": "^3.25.1", + "@react-spectrum/picker": "^3.15.1", + "@react-spectrum/text": "^3.5.7", + "@react-spectrum/utils": "^3.11.9", + "@react-stately/collections": "^3.10.9", + "@react-stately/list": "^3.10.7", + "@react-stately/tabs": "^3.6.8", + "@react-types/select": "^3.9.6", + "@react-types/shared": "^3.24.1", + "@react-types/tabs": "^3.3.9", "@swc/helpers": "^0.5.0" }, "peerDependencies": { "@react-spectrum/provider": "^3.0.0", - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0", - "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0", + "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" } }, "node_modules/@react-spectrum/tag": { - "version": "3.2.6", - "resolved": "https://registry.npmjs.org/@react-spectrum/tag/-/tag-3.2.6.tgz", - "integrity": "sha512-OSGIL2fYLMmiPRCEGvdrQVazS6/S0nhzf/FO52pAAjDZHkd4RDlHHY00Yv/2GPJKroa4e5jdyd5NHCxlW5Vbaw==", - "dependencies": { - "@react-aria/focus": "^3.17.1", - "@react-aria/i18n": "^3.11.1", - "@react-aria/interactions": "^3.21.3", - "@react-aria/selection": "^3.18.1", - "@react-aria/tag": "^3.4.1", - "@react-aria/utils": "^3.24.1", - "@react-spectrum/button": "^3.16.4", - "@react-spectrum/form": "^3.7.6", - "@react-spectrum/label": "^3.16.6", - "@react-spectrum/text": "^3.5.5", - "@react-spectrum/utils": "^3.11.7", - "@react-stately/collections": "^3.10.7", - "@react-stately/list": "^3.10.5", - "@react-types/shared": "^3.23.1", + "version": "3.2.8", + "resolved": "https://registry.npmjs.org/@react-spectrum/tag/-/tag-3.2.8.tgz", + "integrity": "sha512-cZO745mdjwoSvEoBjWTREdZiOshuGq8jm+1XuO6eWGcxCsktU6ToPjz7wrmHi6kE4fuhXj/UxcyA+8IXSL1mhw==", + "dependencies": { + "@react-aria/focus": "^3.18.1", + "@react-aria/i18n": "^3.12.1", + "@react-aria/interactions": "^3.22.1", + "@react-aria/selection": "^3.19.1", + "@react-aria/tag": "^3.4.3", + "@react-aria/utils": "^3.25.1", + "@react-spectrum/button": "^3.16.6", + "@react-spectrum/form": "^3.7.8", + "@react-spectrum/label": "^3.16.8", + "@react-spectrum/text": "^3.5.7", + "@react-spectrum/utils": "^3.11.9", + "@react-stately/collections": "^3.10.9", + "@react-stately/list": "^3.10.7", + "@react-types/shared": "^3.24.1", "@swc/helpers": "^0.5.0" }, "peerDependencies": { "@react-spectrum/provider": "^3.0.0", - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0", - "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0", + "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" } }, "node_modules/@react-spectrum/text": { - "version": "3.5.5", - "resolved": "https://registry.npmjs.org/@react-spectrum/text/-/text-3.5.5.tgz", - "integrity": "sha512-MSRMUNWjuqjAH0eRjSw0fOCvM7haqgfy3HgwHpB5czpeUtR1p22e+UWA9gHior7S57zrQN1WotpeWZ1AmnzvWg==", - "dependencies": { - "@react-aria/utils": "^3.24.1", - "@react-spectrum/utils": "^3.11.7", - "@react-types/shared": "^3.23.1", - "@react-types/text": "^3.3.9", + "version": "3.5.7", + "resolved": "https://registry.npmjs.org/@react-spectrum/text/-/text-3.5.7.tgz", + "integrity": "sha512-Tvnto3UrWEc4iBiKYAFH9X6GzLwwzy4uWxRaPiZ3uu+I+JCd/Sz+mjdk5lOLtpPA78xtPkHO/I/iGijk4ag6mg==", + "dependencies": { + "@react-aria/utils": "^3.25.1", + "@react-spectrum/utils": "^3.11.9", + "@react-types/shared": "^3.24.1", + "@react-types/text": "^3.3.11", "@swc/helpers": "^0.5.0", - "react-aria-components": "^1.2.1" + "react-aria-components": "^1.3.1" }, "peerDependencies": { "@react-spectrum/provider": "^3.0.0", - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" } }, "node_modules/@react-spectrum/textfield": { - "version": "3.12.1", - "resolved": "https://registry.npmjs.org/@react-spectrum/textfield/-/textfield-3.12.1.tgz", - "integrity": "sha512-ehvStKrduGo71SfEieodw6NHBDvyE5wYYZh1uLwbde9hjfyOf2q56lfMdSQiBSJ5pDnpS0ToLpoomoPz315u+Q==", - "dependencies": { - "@react-aria/focus": "^3.17.1", - "@react-aria/interactions": "^3.21.3", - "@react-aria/textfield": "^3.14.5", - "@react-aria/utils": "^3.24.1", - "@react-spectrum/form": "^3.7.6", - "@react-spectrum/label": "^3.16.6", - "@react-spectrum/utils": "^3.11.7", - "@react-stately/utils": "^3.10.1", - "@react-types/shared": "^3.23.1", - "@react-types/textfield": "^3.9.3", - "@spectrum-icons/ui": "^3.6.7", + "version": "3.12.3", + "resolved": "https://registry.npmjs.org/@react-spectrum/textfield/-/textfield-3.12.3.tgz", + "integrity": "sha512-1NUTA/Wo8cPLmKcQymgzVBd37Q1mLf358stV4MxLqKjnPT+rGHBTflhV1cmRpLbWdXYnyPSEXyZx12YXctauKg==", + "dependencies": { + "@react-aria/focus": "^3.18.1", + "@react-aria/interactions": "^3.22.1", + "@react-aria/textfield": "^3.14.7", + "@react-aria/utils": "^3.25.1", + "@react-spectrum/form": "^3.7.8", + "@react-spectrum/label": "^3.16.8", + "@react-spectrum/utils": "^3.11.9", + "@react-stately/utils": "^3.10.2", + "@react-types/shared": "^3.24.1", + "@react-types/textfield": "^3.9.5", + "@spectrum-icons/ui": "^3.6.9", "@swc/helpers": "^0.5.0" }, "peerDependencies": { "@react-spectrum/provider": "^3.0.0", - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" } }, "node_modules/@react-spectrum/theme-dark": { - "version": "3.5.10", - "resolved": "https://registry.npmjs.org/@react-spectrum/theme-dark/-/theme-dark-3.5.10.tgz", - "integrity": "sha512-xDzuWY9Vtd0X7Ww5fBvhbTq7oM0PiNtKlT+cPVnKm4YmJB5RvVG/m6jYF4/9GN36NAyiRnNRdBCs7SUuKEfTkA==", + "version": "3.5.12", + "resolved": "https://registry.npmjs.org/@react-spectrum/theme-dark/-/theme-dark-3.5.12.tgz", + "integrity": "sha512-WLicILM0CDx3peenTZC9JQ7uhmZee2IiQtYMjYXGzCzHD3WG+X6OodpXG0VgtzHhb8lmtbzwxvGGPJlCPJIzqw==", "dependencies": { - "@react-types/provider": "^3.8.1", + "@react-types/provider": "^3.8.3", "@swc/helpers": "^0.5.0" }, "peerDependencies": { - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" } }, "node_modules/@react-spectrum/theme-default": { - "version": "3.5.10", - "resolved": "https://registry.npmjs.org/@react-spectrum/theme-default/-/theme-default-3.5.10.tgz", - "integrity": "sha512-qCGce11d5p0Ce4nSz25vRYoMZycb8oxbgMUM9YXXHgUBDbRRB/s0JNUXxlyikENtaNWiCyeWzVm80bJKmmIijw==", + "version": "3.5.12", + "resolved": "https://registry.npmjs.org/@react-spectrum/theme-default/-/theme-default-3.5.12.tgz", + "integrity": "sha512-bGtwv0NirmYIC4/4Tkkikn7yqKMITY8VKGEY8105EpiDZX+/8tr4dwypWi/EE0OMF8kTCW61zu5aScrNUQfGew==", "dependencies": { - "@react-types/provider": "^3.8.1", + "@react-types/provider": "^3.8.3", "@swc/helpers": "^0.5.0" }, "peerDependencies": { - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" } }, "node_modules/@react-spectrum/theme-light": { - "version": "3.4.10", - "resolved": "https://registry.npmjs.org/@react-spectrum/theme-light/-/theme-light-3.4.10.tgz", - "integrity": "sha512-MKHxBlfawja16hBlcBTFD72B+luPwhCG/pTY35WMy+gCVWUeYEwJU8ijOhG7A7a7KkrLpHgebpHojxEXYkmFIA==", + "version": "3.4.12", + "resolved": "https://registry.npmjs.org/@react-spectrum/theme-light/-/theme-light-3.4.12.tgz", + "integrity": "sha512-KrWYTQFcuKayEIJCdMA5z0Kbd2l4oeT72QSaqV+h2Hi7mnjxM7R16GZgF3swAJOvWEMSqhLLCzr/6P0prRmVmQ==", "dependencies": { - "@react-types/provider": "^3.8.1", + "@react-types/provider": "^3.8.3", "@swc/helpers": "^0.5.0" }, "peerDependencies": { - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" } }, "node_modules/@react-spectrum/tooltip": { - "version": "3.6.7", - "resolved": "https://registry.npmjs.org/@react-spectrum/tooltip/-/tooltip-3.6.7.tgz", - "integrity": "sha512-kJDFY7G5MGuKc5e4K24ftYbzFLt9ugO5zbGMAg6Zbz79+ER8jTsbGNVupK3E7m9uSimF/aPRRwf2p8UdoksH6Q==", - "dependencies": { - "@react-aria/focus": "^3.17.1", - "@react-aria/overlays": "^3.22.1", - "@react-aria/tooltip": "^3.7.4", - "@react-aria/utils": "^3.24.1", - "@react-spectrum/overlays": "^5.6.1", - "@react-spectrum/utils": "^3.11.7", - "@react-stately/tooltip": "^3.4.9", - "@react-types/overlays": "^3.8.7", - "@react-types/shared": "^3.23.1", - "@react-types/tooltip": "^3.4.9", - "@spectrum-icons/ui": "^3.6.7", + "version": "3.6.9", + "resolved": "https://registry.npmjs.org/@react-spectrum/tooltip/-/tooltip-3.6.9.tgz", + "integrity": "sha512-AVWowYE43ZyOh2tck5TKs7a5a6RaAefeRPiqLpBo8W64TwP07WZgRtUJjLSFrt1AIVwfRyjOiwBiG/Ur896Zfw==", + "dependencies": { + "@react-aria/focus": "^3.18.1", + "@react-aria/overlays": "^3.23.1", + "@react-aria/tooltip": "^3.7.6", + "@react-aria/utils": "^3.25.1", + "@react-spectrum/overlays": "^5.6.3", + "@react-spectrum/utils": "^3.11.9", + "@react-stately/tooltip": "^3.4.11", + "@react-types/overlays": "^3.8.9", + "@react-types/shared": "^3.24.1", + "@react-types/tooltip": "^3.4.11", + "@spectrum-icons/ui": "^3.6.9", "@swc/helpers": "^0.5.0" }, "peerDependencies": { "@react-spectrum/provider": "^3.0.0", - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0", - "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0", + "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" } }, "node_modules/@react-spectrum/utils": { - "version": "3.11.7", - "resolved": "https://registry.npmjs.org/@react-spectrum/utils/-/utils-3.11.7.tgz", - "integrity": "sha512-o/9zTvUor0EaRwKZWVlgOcyvH+/JIBsNxuvhDgCP5lD868KoZePmx1L64TejUqK/swwH8jr35gyULpYU2kQXRw==", - "dependencies": { - "@react-aria/i18n": "^3.11.1", - "@react-aria/ssr": "^3.9.4", - "@react-aria/utils": "^3.24.1", - "@react-types/shared": "^3.23.1", + "version": "3.11.9", + "resolved": "https://registry.npmjs.org/@react-spectrum/utils/-/utils-3.11.9.tgz", + "integrity": "sha512-k+0dwCflYejSix7FaRMp63ptgs/nc9ndOVa1qJVI/VGK+P9alZmqMXUhIztClLCcyFjJrd9O2YIaAEsBCkBNRw==", + "dependencies": { + "@react-aria/i18n": "^3.12.1", + "@react-aria/ssr": "^3.9.5", + "@react-aria/utils": "^3.25.1", + "@react-types/shared": "^3.24.1", "@swc/helpers": "^0.5.0", "clsx": "^2.0.0" }, "peerDependencies": { - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" } }, "node_modules/@react-spectrum/view": { - "version": "3.6.10", - "resolved": "https://registry.npmjs.org/@react-spectrum/view/-/view-3.6.10.tgz", - "integrity": "sha512-AbvwyORDzntt9XiP9Soc5mCuYsYOJKj+4mwX0ugZZi9I18g1JVeSPnGG/myYdHr2xXNC00pgVILOLA/B0JWMXw==", - "dependencies": { - "@react-aria/utils": "^3.24.1", - "@react-spectrum/utils": "^3.11.7", - "@react-types/shared": "^3.23.1", - "@react-types/view": "^3.4.9", + "version": "3.6.12", + "resolved": "https://registry.npmjs.org/@react-spectrum/view/-/view-3.6.12.tgz", + "integrity": "sha512-zcmeEuOUDC+fGPTyuDZWouFFMm8/58RaHJtSIvrzSCixV3RAfGeWwi6tRCDjSQuYgDBjNvxUMCbYP88CO2FULw==", + "dependencies": { + "@react-aria/utils": "^3.25.1", + "@react-spectrum/utils": "^3.11.9", + "@react-types/shared": "^3.24.1", + "@react-types/view": "^3.4.11", "@swc/helpers": "^0.5.0" }, "peerDependencies": { "@react-spectrum/provider": "^3.0.0", - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" } }, "node_modules/@react-spectrum/well": { - "version": "3.4.13", - "resolved": "https://registry.npmjs.org/@react-spectrum/well/-/well-3.4.13.tgz", - "integrity": "sha512-zKJsaWnndRvCK4crkZ/Jt5uUk5Jwkx+pRaVu40BEK41aOfavQ44GR90uLogrvDuw2LDZ9mdTj/H7bCVNjkLkgA==", - "dependencies": { - "@react-aria/utils": "^3.24.1", - "@react-spectrum/utils": "^3.11.7", - "@react-types/shared": "^3.23.1", - "@react-types/well": "^3.3.9", + "version": "3.4.15", + "resolved": "https://registry.npmjs.org/@react-spectrum/well/-/well-3.4.15.tgz", + "integrity": "sha512-bzSIZAtXjHaLzcENYracSDabjQgU1KJAXofQ/YwBqZwMDVsokG+kvR+bfGfW05tldgZH5/7Am9D/pIcSW4qBUQ==", + "dependencies": { + "@react-aria/utils": "^3.25.1", + "@react-spectrum/utils": "^3.11.9", + "@react-types/shared": "^3.24.1", + "@react-types/well": "^3.3.11", "@swc/helpers": "^0.5.0" }, "peerDependencies": { - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" } }, "node_modules/@react-spring/animated": { @@ -6184,127 +6188,127 @@ } }, "node_modules/@react-stately/calendar": { - "version": "3.5.1", - "resolved": "https://registry.npmjs.org/@react-stately/calendar/-/calendar-3.5.1.tgz", - "integrity": "sha512-7l7QhqGUJ5AzWHfvZzbTe3J4t72Ht5BmhW4hlVI7flQXtfrmYkVtl3ZdytEZkkHmWGYZRW9b4IQTQGZxhtlElA==", + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/@react-stately/calendar/-/calendar-3.5.3.tgz", + "integrity": "sha512-SRwsgszyc9FNcvkjqBe81e/tnjKpRqH+yTYpG0uI9NR1HfyddmhR3Y7QilWPcqQkq4SQb7pL68SkTPH2dX2dng==", "dependencies": { - "@internationalized/date": "^3.5.4", - "@react-stately/utils": "^3.10.1", - "@react-types/calendar": "^3.4.6", - "@react-types/shared": "^3.23.1", + "@internationalized/date": "^3.5.5", + "@react-stately/utils": "^3.10.2", + "@react-types/calendar": "^3.4.8", + "@react-types/shared": "^3.24.1", "@swc/helpers": "^0.5.0" }, "peerDependencies": { - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" } }, "node_modules/@react-stately/checkbox": { - "version": "3.6.5", - "resolved": "https://registry.npmjs.org/@react-stately/checkbox/-/checkbox-3.6.5.tgz", - "integrity": "sha512-IXV3f9k+LtmfQLE+DKIN41Q5QB/YBLDCB1YVx5PEdRp52S9+EACD5683rjVm8NVRDwjMi2SP6RnFRk7fVb5Azg==", - "dependencies": { - "@react-stately/form": "^3.0.3", - "@react-stately/utils": "^3.10.1", - "@react-types/checkbox": "^3.8.1", - "@react-types/shared": "^3.23.1", + "version": "3.6.7", + "resolved": "https://registry.npmjs.org/@react-stately/checkbox/-/checkbox-3.6.7.tgz", + "integrity": "sha512-ZOaBNXXazpwkuKj5hk6FtGbXO7HoKEGXvf3p7FcHcIHyiEJ65GBvC7e7HwMc3jYxlBwtbebSpEcf3oFqI5dl3A==", + "dependencies": { + "@react-stately/form": "^3.0.5", + "@react-stately/utils": "^3.10.2", + "@react-types/checkbox": "^3.8.3", + "@react-types/shared": "^3.24.1", "@swc/helpers": "^0.5.0" }, "peerDependencies": { - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" } }, "node_modules/@react-stately/collections": { - "version": "3.10.7", - "resolved": "https://registry.npmjs.org/@react-stately/collections/-/collections-3.10.7.tgz", - "integrity": "sha512-KRo5O2MWVL8n3aiqb+XR3vP6akmHLhLWYZEmPKjIv0ghQaEebBTrN3wiEjtd6dzllv0QqcWvDLM1LntNfJ2TsA==", + "version": "3.10.9", + "resolved": "https://registry.npmjs.org/@react-stately/collections/-/collections-3.10.9.tgz", + "integrity": "sha512-plyrng6hOQMG8LrjArMA6ts/DgWyXln3g90/hFNbqe/hdVYF53sDVsj8Jb+5LtoYTpiAlV6eOvy1XR0vPZUf8w==", "dependencies": { - "@react-types/shared": "^3.23.1", + "@react-types/shared": "^3.24.1", "@swc/helpers": "^0.5.0" }, "peerDependencies": { - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" } }, "node_modules/@react-stately/color": { - "version": "3.6.1", - "resolved": "https://registry.npmjs.org/@react-stately/color/-/color-3.6.1.tgz", - "integrity": "sha512-iW0nAhl3+fUBegHMw5EcAbFVDpgwHBrivfC85pVoTM3pyzp66hqNN6R6xWxW6ETyljS8UOer59+/w4GDVGdPig==", + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/@react-stately/color/-/color-3.7.1.tgz", + "integrity": "sha512-pJqM7fZ7+zy8wnzCUkBMkTgmjMs+lBLjQm1k+dFbmXK2SuELiDOQLirrl6j15NVBOKn8avvRHXpAQhGX43GOCQ==", "dependencies": { "@internationalized/number": "^3.5.3", "@internationalized/string": "^3.2.3", - "@react-aria/i18n": "^3.11.1", - "@react-stately/form": "^3.0.3", - "@react-stately/numberfield": "^3.9.3", - "@react-stately/slider": "^3.5.4", - "@react-stately/utils": "^3.10.1", - "@react-types/color": "3.0.0-beta.25", - "@react-types/shared": "^3.23.1", + "@react-aria/i18n": "^3.12.1", + "@react-stately/form": "^3.0.5", + "@react-stately/numberfield": "^3.9.5", + "@react-stately/slider": "^3.5.6", + "@react-stately/utils": "^3.10.2", + "@react-types/color": "3.0.0-rc.1", + "@react-types/shared": "^3.24.1", "@swc/helpers": "^0.5.0" }, "peerDependencies": { - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" } }, "node_modules/@react-stately/combobox": { - "version": "3.8.4", - "resolved": "https://registry.npmjs.org/@react-stately/combobox/-/combobox-3.8.4.tgz", - "integrity": "sha512-iLVGvKRRz0TeJXZhZyK783hveHpYA6xovOSdzSD+WGYpiPXo1QrcrNoH3AE0Z2sHtorU+8nc0j58vh5PB+m2AA==", - "dependencies": { - "@react-stately/collections": "^3.10.7", - "@react-stately/form": "^3.0.3", - "@react-stately/list": "^3.10.5", - "@react-stately/overlays": "^3.6.7", - "@react-stately/select": "^3.6.4", - "@react-stately/utils": "^3.10.1", - "@react-types/combobox": "^3.11.1", - "@react-types/shared": "^3.23.1", + "version": "3.9.1", + "resolved": "https://registry.npmjs.org/@react-stately/combobox/-/combobox-3.9.1.tgz", + "integrity": "sha512-jmeKUKs0jK18NwDAlpu79ATufgxrc6Sn3ZMmI8KPVQ5sdPTjNlnDx6gTFyOOIa87axf/c6WYU7v3jxmcp+RDdg==", + "dependencies": { + "@react-stately/collections": "^3.10.9", + "@react-stately/form": "^3.0.5", + "@react-stately/list": "^3.10.7", + "@react-stately/overlays": "^3.6.9", + "@react-stately/select": "^3.6.6", + "@react-stately/utils": "^3.10.2", + "@react-types/combobox": "^3.12.1", + "@react-types/shared": "^3.24.1", "@swc/helpers": "^0.5.0" }, "peerDependencies": { - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" } }, "node_modules/@react-stately/data": { - "version": "3.11.4", - "resolved": "https://registry.npmjs.org/@react-stately/data/-/data-3.11.4.tgz", - "integrity": "sha512-PbnUQxeE6AznSuEWYnRmrYQ9t5z1Asx98Jtrl96EeA6Iapt9kOjTN9ySqCxtPxMKleb1NIqG3+uHU3veIqmLsg==", + "version": "3.11.6", + "resolved": "https://registry.npmjs.org/@react-stately/data/-/data-3.11.6.tgz", + "integrity": "sha512-S8q1Ejuhijl8SnyVOdDNFrMrWWnLk/Oh1ZT3KHSbTdpfMRtvhi5HukoiP06jlzz75phnpSPQL40npDtUB/kk3Q==", "dependencies": { - "@react-types/shared": "^3.23.1", + "@react-types/shared": "^3.24.1", "@swc/helpers": "^0.5.0" }, "peerDependencies": { - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" } }, "node_modules/@react-stately/datepicker": { - "version": "3.9.4", - "resolved": "https://registry.npmjs.org/@react-stately/datepicker/-/datepicker-3.9.4.tgz", - "integrity": "sha512-yBdX01jn6gq4NIVvHIqdjBUPo+WN8Bujc4OnPw+ZnfA4jI0eIgq04pfZ84cp1LVXW0IB0VaCu1AlQ/kvtZjfGA==", + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/@react-stately/datepicker/-/datepicker-3.10.1.tgz", + "integrity": "sha512-KXr5cxLOLUYBf3wlDSKhvshsKOWpdV2flhS075V6dgC/EPBh7igBZGUXJ9AZzndT7Hx1w8v/ul6CIffxEJz1Nw==", "dependencies": { - "@internationalized/date": "^3.5.4", + "@internationalized/date": "^3.5.5", "@internationalized/string": "^3.2.3", - "@react-stately/form": "^3.0.3", - "@react-stately/overlays": "^3.6.7", - "@react-stately/utils": "^3.10.1", - "@react-types/datepicker": "^3.7.4", - "@react-types/shared": "^3.23.1", + "@react-stately/form": "^3.0.5", + "@react-stately/overlays": "^3.6.9", + "@react-stately/utils": "^3.10.2", + "@react-types/datepicker": "^3.8.1", + "@react-types/shared": "^3.24.1", "@swc/helpers": "^0.5.0" }, "peerDependencies": { - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" } }, "node_modules/@react-stately/dnd": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/@react-stately/dnd/-/dnd-3.3.1.tgz", - "integrity": "sha512-I/Ci5xB8hSgAXzoWYWScfMM9UK1MX/eTlARBhiSlfudewweOtNJAI+cXJgU7uiUnGjh4B4v3qDBtlAH1dWDCsw==", + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/@react-stately/dnd/-/dnd-3.4.1.tgz", + "integrity": "sha512-EXPW1vKx3vNpMaXOpPKTOU1T4S+jqjllGFDyWD659Ql0lL9SQ5Y4IU/KmIK3T3yKkjps9xrMmCjLAkb75PH5zg==", "dependencies": { - "@react-stately/selection": "^3.15.1", - "@react-types/shared": "^3.23.1", + "@react-stately/selection": "^3.16.1", + "@react-types/shared": "^3.24.1", "@swc/helpers": "^0.5.0" }, "peerDependencies": { - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" } }, "node_modules/@react-stately/flags": { @@ -6316,756 +6320,756 @@ } }, "node_modules/@react-stately/form": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@react-stately/form/-/form-3.0.3.tgz", - "integrity": "sha512-92YYBvlHEWUGUpXgIaQ48J50jU9XrxfjYIN8BTvvhBHdD63oWgm8DzQnyT/NIAMzdLnhkg7vP+fjG8LjHeyIAg==", + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@react-stately/form/-/form-3.0.5.tgz", + "integrity": "sha512-J3plwJ63HQz109OdmaTqTA8Qhvl3gcYYK7DtgKyNP6mc/Me2Q4tl2avkWoA+22NRuv5m+J8TpBk4AVHUEOwqeQ==", "dependencies": { - "@react-types/shared": "^3.23.1", + "@react-types/shared": "^3.24.1", "@swc/helpers": "^0.5.0" }, "peerDependencies": { - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" } }, "node_modules/@react-stately/grid": { - "version": "3.8.7", - "resolved": "https://registry.npmjs.org/@react-stately/grid/-/grid-3.8.7.tgz", - "integrity": "sha512-he3TXCLAhF5C5z1/G4ySzcwyt7PEiWcVIupxebJQqRyFrNWemSuv+7tolnStmG8maMVIyV3P/3j4eRBbdSlOIg==", - "dependencies": { - "@react-stately/collections": "^3.10.7", - "@react-stately/selection": "^3.15.1", - "@react-types/grid": "^3.2.6", - "@react-types/shared": "^3.23.1", + "version": "3.9.1", + "resolved": "https://registry.npmjs.org/@react-stately/grid/-/grid-3.9.1.tgz", + "integrity": "sha512-LSVIcXO/cqwG0IgDSk2juDbpARBS1IzGnsTp/8vSOejMxq5MXrwxL5hUcqNczL8Ss6aLpELm42tCS0kPm3cMKw==", + "dependencies": { + "@react-stately/collections": "^3.10.9", + "@react-stately/selection": "^3.16.1", + "@react-types/grid": "^3.2.8", + "@react-types/shared": "^3.24.1", "@swc/helpers": "^0.5.0" }, "peerDependencies": { - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" } }, "node_modules/@react-stately/layout": { - "version": "3.13.9", - "resolved": "https://registry.npmjs.org/@react-stately/layout/-/layout-3.13.9.tgz", - "integrity": "sha512-JCj2cnvRbBjah9LFZbBXMdKkoKuEpzn6hvYBw7h0fNIhNGISpiI1TW4ya1X34kD2vcv/3dc31KV/UqmI4hJCQw==", - "dependencies": { - "@react-stately/collections": "^3.10.7", - "@react-stately/table": "^3.11.8", - "@react-stately/virtualizer": "^3.7.1", - "@react-types/grid": "^3.2.6", - "@react-types/shared": "^3.23.1", - "@react-types/table": "^3.9.5", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@react-stately/layout/-/layout-4.0.1.tgz", + "integrity": "sha512-4oNYFhQprcwP1fNV/p3dbx1a6lzMGBAKLTdcvtCuBCgclNA3etqjdQAUIZ0Bpq+Z8i9qo3c85oxr6Tr8BKQV4w==", + "dependencies": { + "@react-stately/collections": "^3.10.9", + "@react-stately/table": "^3.12.1", + "@react-stately/virtualizer": "^4.0.1", + "@react-types/grid": "^3.2.8", + "@react-types/shared": "^3.24.1", + "@react-types/table": "^3.10.1", "@swc/helpers": "^0.5.0" }, "peerDependencies": { - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" } }, "node_modules/@react-stately/list": { - "version": "3.10.5", - "resolved": "https://registry.npmjs.org/@react-stately/list/-/list-3.10.5.tgz", - "integrity": "sha512-fV9plO+6QDHiewsYIhboxcDhF17GO95xepC5ki0bKXo44gr14g/LSo/BMmsaMnV+1BuGdBunB05bO4QOIaigXA==", - "dependencies": { - "@react-stately/collections": "^3.10.7", - "@react-stately/selection": "^3.15.1", - "@react-stately/utils": "^3.10.1", - "@react-types/shared": "^3.23.1", + "version": "3.10.7", + "resolved": "https://registry.npmjs.org/@react-stately/list/-/list-3.10.7.tgz", + "integrity": "sha512-W5PG7uG5GQV2Q59vXJE7QLKHZIoUNEx+JmHrBUCMKUgyngSpKIIEDR/R/C1b6ZJ9jMqqZA68Zlnd5iK1/mBi1A==", + "dependencies": { + "@react-stately/collections": "^3.10.9", + "@react-stately/selection": "^3.16.1", + "@react-stately/utils": "^3.10.2", + "@react-types/shared": "^3.24.1", "@swc/helpers": "^0.5.0" }, "peerDependencies": { - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" } }, "node_modules/@react-stately/menu": { - "version": "3.7.1", - "resolved": "https://registry.npmjs.org/@react-stately/menu/-/menu-3.7.1.tgz", - "integrity": "sha512-mX1w9HHzt+xal1WIT2xGrTQsoLvDwuB2R1Er1MBABs//MsJzccycatcgV/J/28m6tO5M9iuFQQvLV+i1dCtodg==", + "version": "3.8.1", + "resolved": "https://registry.npmjs.org/@react-stately/menu/-/menu-3.8.1.tgz", + "integrity": "sha512-HzAANHg+QUpyRok0CBIL/5qb+4TARteP0q9av2tKnQWPG91iJw84phJDJrmmY55uFFax4fxBgDM9dy1t12iKgQ==", "dependencies": { - "@react-stately/overlays": "^3.6.7", - "@react-types/menu": "^3.9.9", - "@react-types/shared": "^3.23.1", + "@react-stately/overlays": "^3.6.9", + "@react-types/menu": "^3.9.11", + "@react-types/shared": "^3.24.1", "@swc/helpers": "^0.5.0" }, "peerDependencies": { - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" } }, "node_modules/@react-stately/numberfield": { - "version": "3.9.3", - "resolved": "https://registry.npmjs.org/@react-stately/numberfield/-/numberfield-3.9.3.tgz", - "integrity": "sha512-UlPTLSabhLEuHtgzM0PgfhtEaHy3yttbzcRb8yHNvGo4KbCHeHpTHd3QghKfTFm024Mug7+mVlWCmMtW0f5ttg==", + "version": "3.9.5", + "resolved": "https://registry.npmjs.org/@react-stately/numberfield/-/numberfield-3.9.5.tgz", + "integrity": "sha512-aWilyzrZOvkgntcXd6Kl+t1QiCbnajUCN8yll6/saByKpfuOf1k6AGYNQBJ0CO/5HyffPPdbFs+45sj4e3cdjA==", "dependencies": { "@internationalized/number": "^3.5.3", - "@react-stately/form": "^3.0.3", - "@react-stately/utils": "^3.10.1", - "@react-types/numberfield": "^3.8.3", + "@react-stately/form": "^3.0.5", + "@react-stately/utils": "^3.10.2", + "@react-types/numberfield": "^3.8.5", "@swc/helpers": "^0.5.0" }, "peerDependencies": { - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" } }, "node_modules/@react-stately/overlays": { - "version": "3.6.7", - "resolved": "https://registry.npmjs.org/@react-stately/overlays/-/overlays-3.6.7.tgz", - "integrity": "sha512-6zp8v/iNUm6YQap0loaFx6PlvN8C0DgWHNlrlzMtMmNuvjhjR0wYXVaTfNoUZBWj25tlDM81ukXOjpRXg9rLrw==", + "version": "3.6.9", + "resolved": "https://registry.npmjs.org/@react-stately/overlays/-/overlays-3.6.9.tgz", + "integrity": "sha512-4chfyzKw7P2UEainm0yzjUgYwG1ovBejN88eTrn+O62x5huuMCwe0cbMxmYh4y7IhRFSee3jIJd0SP0u/+i39w==", "dependencies": { - "@react-stately/utils": "^3.10.1", - "@react-types/overlays": "^3.8.7", + "@react-stately/utils": "^3.10.2", + "@react-types/overlays": "^3.8.9", "@swc/helpers": "^0.5.0" }, "peerDependencies": { - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" } }, "node_modules/@react-stately/radio": { - "version": "3.10.4", - "resolved": "https://registry.npmjs.org/@react-stately/radio/-/radio-3.10.4.tgz", - "integrity": "sha512-kCIc7tAl4L7Hu4Wt9l2jaa+MzYmAJm0qmC8G8yPMbExpWbLRu6J8Un80GZu+JxvzgDlqDyrVvyv9zFifwH/NkQ==", - "dependencies": { - "@react-stately/form": "^3.0.3", - "@react-stately/utils": "^3.10.1", - "@react-types/radio": "^3.8.1", - "@react-types/shared": "^3.23.1", + "version": "3.10.6", + "resolved": "https://registry.npmjs.org/@react-stately/radio/-/radio-3.10.6.tgz", + "integrity": "sha512-wiJuUUQ6LuEv0J1DQtkC0+Sed7tO6y3sIPeB+5uIxIIsUpxvNlDcqr+JOkrQm7gZmkmvcfotb5Gv5PqaIl1zKA==", + "dependencies": { + "@react-stately/form": "^3.0.5", + "@react-stately/utils": "^3.10.2", + "@react-types/radio": "^3.8.3", + "@react-types/shared": "^3.24.1", "@swc/helpers": "^0.5.0" }, "peerDependencies": { - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" } }, "node_modules/@react-stately/searchfield": { - "version": "3.5.3", - "resolved": "https://registry.npmjs.org/@react-stately/searchfield/-/searchfield-3.5.3.tgz", - "integrity": "sha512-H0OvlgwPIFdc471ypw79MDjz3WXaVq9+THaY6JM4DIohEJNN5Dwei7O9g6r6m/GqPXJIn5TT3b74kJ2Osc00YQ==", + "version": "3.5.5", + "resolved": "https://registry.npmjs.org/@react-stately/searchfield/-/searchfield-3.5.5.tgz", + "integrity": "sha512-rKWIVNbxft5eGGxQ4CtcTKGXm2B1AuYSg6kLRQLq+VYspPNq3wfeMtVBeIdy4LNjWXsTmzs2b3o+zkFYdPqPPw==", "dependencies": { - "@react-stately/utils": "^3.10.1", - "@react-types/searchfield": "^3.5.5", + "@react-stately/utils": "^3.10.2", + "@react-types/searchfield": "^3.5.7", "@swc/helpers": "^0.5.0" }, "peerDependencies": { - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" } }, "node_modules/@react-stately/select": { - "version": "3.6.4", - "resolved": "https://registry.npmjs.org/@react-stately/select/-/select-3.6.4.tgz", - "integrity": "sha512-whZgF1N53D0/dS8tOFdrswB0alsk5Q5620HC3z+5f2Hpi8gwgAZ8TYa+2IcmMYRiT+bxVuvEc/NirU9yPmqGbA==", - "dependencies": { - "@react-stately/form": "^3.0.3", - "@react-stately/list": "^3.10.5", - "@react-stately/overlays": "^3.6.7", - "@react-types/select": "^3.9.4", - "@react-types/shared": "^3.23.1", + "version": "3.6.6", + "resolved": "https://registry.npmjs.org/@react-stately/select/-/select-3.6.6.tgz", + "integrity": "sha512-JEpBosWNSXRexE/iReATei1EiVdTIwOWlLcCGw6K7oC/5/f+OHMsh2Kkt/c/RzM/to3vgR+Wbbqwrb712AWgYQ==", + "dependencies": { + "@react-stately/form": "^3.0.5", + "@react-stately/list": "^3.10.7", + "@react-stately/overlays": "^3.6.9", + "@react-types/select": "^3.9.6", + "@react-types/shared": "^3.24.1", "@swc/helpers": "^0.5.0" }, "peerDependencies": { - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" } }, "node_modules/@react-stately/selection": { - "version": "3.15.1", - "resolved": "https://registry.npmjs.org/@react-stately/selection/-/selection-3.15.1.tgz", - "integrity": "sha512-6TQnN9L0UY9w19B7xzb1P6mbUVBtW840Cw1SjgNXCB3NPaCf59SwqClYzoj8O2ZFzMe8F/nUJtfU1NS65/OLlw==", + "version": "3.16.1", + "resolved": "https://registry.npmjs.org/@react-stately/selection/-/selection-3.16.1.tgz", + "integrity": "sha512-qmnmYaXY7IhhzmIiInec1a/yPxlPSBHka6vrWddvt0S6zN7FU5cv6sm69ONUwYwLKSoaNHgOGvZhmsTzyV0O2A==", "dependencies": { - "@react-stately/collections": "^3.10.7", - "@react-stately/utils": "^3.10.1", - "@react-types/shared": "^3.23.1", + "@react-stately/collections": "^3.10.9", + "@react-stately/utils": "^3.10.2", + "@react-types/shared": "^3.24.1", "@swc/helpers": "^0.5.0" }, "peerDependencies": { - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" } }, "node_modules/@react-stately/slider": { - "version": "3.5.4", - "resolved": "https://registry.npmjs.org/@react-stately/slider/-/slider-3.5.4.tgz", - "integrity": "sha512-Jsf7K17dr93lkNKL9ij8HUcoM1sPbq8TvmibD6DhrK9If2lje+OOL8y4n4qreUnfMT56HCAeS9wCO3fg3eMyrw==", + "version": "3.5.6", + "resolved": "https://registry.npmjs.org/@react-stately/slider/-/slider-3.5.6.tgz", + "integrity": "sha512-a7DZgpOVjQyGzMLPiVRCVHISPJX8E3bT+qbZpcRQN+F7T7wReOwUt2I8gQMosnnCGWgU6kdYk8snn0obXe70Fg==", "dependencies": { - "@react-stately/utils": "^3.10.1", - "@react-types/shared": "^3.23.1", - "@react-types/slider": "^3.7.3", + "@react-stately/utils": "^3.10.2", + "@react-types/shared": "^3.24.1", + "@react-types/slider": "^3.7.5", "@swc/helpers": "^0.5.0" }, "peerDependencies": { - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" } }, "node_modules/@react-stately/table": { - "version": "3.11.8", - "resolved": "https://registry.npmjs.org/@react-stately/table/-/table-3.11.8.tgz", - "integrity": "sha512-EdyRW3lT1/kAVDp5FkEIi1BQ7tvmD2YgniGdLuW/l9LADo0T+oxZqruv60qpUS6sQap+59Riaxl91ClDxrJnpg==", + "version": "3.12.1", + "resolved": "https://registry.npmjs.org/@react-stately/table/-/table-3.12.1.tgz", + "integrity": "sha512-Cg3lXrWJNrYkD1gqRclMxq0GGiR+ygxdeAqk2jbbsmHU8RSQuzoO/RtUCw6WAKfQjAq4gE0E60TlAsGgCUdJGA==", "dependencies": { - "@react-stately/collections": "^3.10.7", + "@react-stately/collections": "^3.10.9", "@react-stately/flags": "^3.0.3", - "@react-stately/grid": "^3.8.7", - "@react-stately/selection": "^3.15.1", - "@react-stately/utils": "^3.10.1", - "@react-types/grid": "^3.2.6", - "@react-types/shared": "^3.23.1", - "@react-types/table": "^3.9.5", + "@react-stately/grid": "^3.9.1", + "@react-stately/selection": "^3.16.1", + "@react-stately/utils": "^3.10.2", + "@react-types/grid": "^3.2.8", + "@react-types/shared": "^3.24.1", + "@react-types/table": "^3.10.1", "@swc/helpers": "^0.5.0" }, "peerDependencies": { - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" } }, "node_modules/@react-stately/tabs": { - "version": "3.6.6", - "resolved": "https://registry.npmjs.org/@react-stately/tabs/-/tabs-3.6.6.tgz", - "integrity": "sha512-sOLxorH2uqjAA+v1ppkMCc2YyjgqvSGeBDgtR/lyPSDd4CVMoTExszROX2dqG0c8il9RQvzFuufUtQWMY6PgSA==", + "version": "3.6.8", + "resolved": "https://registry.npmjs.org/@react-stately/tabs/-/tabs-3.6.8.tgz", + "integrity": "sha512-pLRwnMmXk/IWvbIJYSO5hm3/PiJ/VzrQlwKr6dlOcrDOSVIZpTjnGWHd6mJSDoPiDyBThlN/k3+2pUFMEOAcfw==", "dependencies": { - "@react-stately/list": "^3.10.5", - "@react-types/shared": "^3.23.1", - "@react-types/tabs": "^3.3.7", + "@react-stately/list": "^3.10.7", + "@react-types/shared": "^3.24.1", + "@react-types/tabs": "^3.3.9", "@swc/helpers": "^0.5.0" }, "peerDependencies": { - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" } }, "node_modules/@react-stately/toggle": { - "version": "3.7.4", - "resolved": "https://registry.npmjs.org/@react-stately/toggle/-/toggle-3.7.4.tgz", - "integrity": "sha512-CoYFe9WrhLkDP4HGDpJYQKwfiYCRBAeoBQHv+JWl5eyK61S8xSwoHsveYuEZ3bowx71zyCnNAqWRrmNOxJ4CKA==", + "version": "3.7.6", + "resolved": "https://registry.npmjs.org/@react-stately/toggle/-/toggle-3.7.6.tgz", + "integrity": "sha512-xRZyrjNVu1VCd1xpg5RwmNYs9fXb+JHChoUaRcBmGCCjsPD0R5uR3iNuE17RXJtWS3/8o9IJVn90+/7NW7boOg==", "dependencies": { - "@react-stately/utils": "^3.10.1", - "@react-types/checkbox": "^3.8.1", + "@react-stately/utils": "^3.10.2", + "@react-types/checkbox": "^3.8.3", "@swc/helpers": "^0.5.0" }, "peerDependencies": { - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" } }, "node_modules/@react-stately/tooltip": { - "version": "3.4.9", - "resolved": "https://registry.npmjs.org/@react-stately/tooltip/-/tooltip-3.4.9.tgz", - "integrity": "sha512-P7CDJsdoKarz32qFwf3VNS01lyC+63gXpDZG31pUu+EO5BeQd4WKN/AH1Beuswpr4GWzxzFc1aXQgERFGVzraA==", + "version": "3.4.11", + "resolved": "https://registry.npmjs.org/@react-stately/tooltip/-/tooltip-3.4.11.tgz", + "integrity": "sha512-r1ScIXau2LZ/lUUBQ5PI01S2TB2urF2zrPzNM2xgngFLlG2uTyfIgMga6/035quQQKd3Bd0qGigMvTgZ3GRGEg==", "dependencies": { - "@react-stately/overlays": "^3.6.7", - "@react-types/tooltip": "^3.4.9", + "@react-stately/overlays": "^3.6.9", + "@react-types/tooltip": "^3.4.11", "@swc/helpers": "^0.5.0" }, "peerDependencies": { - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" } }, "node_modules/@react-stately/tree": { - "version": "3.8.1", - "resolved": "https://registry.npmjs.org/@react-stately/tree/-/tree-3.8.1.tgz", - "integrity": "sha512-LOdkkruJWch3W89h4B/bXhfr0t0t1aRfEp+IMrrwdRAl23NaPqwl5ILHs4Xu5XDHqqhg8co73pHrJwUyiTWEjw==", + "version": "3.8.3", + "resolved": "https://registry.npmjs.org/@react-stately/tree/-/tree-3.8.3.tgz", + "integrity": "sha512-9sRQOxkK7ZMdtSTGHx0sMabHC39PEM4tMl+IdJKkmcp60bfsm3p6LHXhha3E58jwnZaemBfUrlQmTP/E26BbGw==", "dependencies": { - "@react-stately/collections": "^3.10.7", - "@react-stately/selection": "^3.15.1", - "@react-stately/utils": "^3.10.1", - "@react-types/shared": "^3.23.1", + "@react-stately/collections": "^3.10.9", + "@react-stately/selection": "^3.16.1", + "@react-stately/utils": "^3.10.2", + "@react-types/shared": "^3.24.1", "@swc/helpers": "^0.5.0" }, "peerDependencies": { - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" } }, "node_modules/@react-stately/utils": { - "version": "3.10.1", - "resolved": "https://registry.npmjs.org/@react-stately/utils/-/utils-3.10.1.tgz", - "integrity": "sha512-VS/EHRyicef25zDZcM/ClpzYMC5i2YGN6uegOeQawmgfGjb02yaCX0F0zR69Pod9m2Hr3wunTbtpgVXvYbZItg==", + "version": "3.10.2", + "resolved": "https://registry.npmjs.org/@react-stately/utils/-/utils-3.10.2.tgz", + "integrity": "sha512-fh6OTQtbeQC0ywp6LJuuKs6tKIgFvt/DlIZEcIpGho6/oZG229UnIk6TUekwxnDbumuYyan6D9EgUtEMmT8UIg==", "dependencies": { "@swc/helpers": "^0.5.0" }, "peerDependencies": { - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" } }, "node_modules/@react-stately/virtualizer": { - "version": "3.7.1", - "resolved": "https://registry.npmjs.org/@react-stately/virtualizer/-/virtualizer-3.7.1.tgz", - "integrity": "sha512-voHgE6EQ+oZaLv6u2umKxakvIKNkCQuUihqKACTjdslp7SJh4Mvs3oLBI0hf0JOh+rCcFIKDvQtFwy1fXFRYBA==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@react-stately/virtualizer/-/virtualizer-4.0.1.tgz", + "integrity": "sha512-HCje3SlLItQFAiBHH4JZhz74mMCe2g+Q8woJa6kdKlvFqsNdmhtFHuuIr1uW6LWj76j2N0Xaa8Z7fV1f5ovX0Q==", "dependencies": { - "@react-aria/utils": "^3.24.1", - "@react-types/shared": "^3.23.1", + "@react-aria/utils": "^3.25.1", + "@react-types/shared": "^3.24.1", "@swc/helpers": "^0.5.0" }, "peerDependencies": { - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" } }, "node_modules/@react-types/actionbar": { - "version": "3.1.7", - "resolved": "https://registry.npmjs.org/@react-types/actionbar/-/actionbar-3.1.7.tgz", - "integrity": "sha512-yohxM+R9o/HGADL7NdTH9tC9BnWrVYKsutobjWzVQZHGoaHEqBbz03dk3m9UvFMnw7g6kjtGxhOJQpztz7nk3Q==", + "version": "3.1.9", + "resolved": "https://registry.npmjs.org/@react-types/actionbar/-/actionbar-3.1.9.tgz", + "integrity": "sha512-omCribEByWYcDr27W63LpmFq+muACc949UzCcMzlc6fvkKc6Gq+HjRRoTQjX6k8hXXFqEbQoYJFVyRXnig6u5g==", "dependencies": { - "@react-types/shared": "^3.23.1" + "@react-types/shared": "^3.24.1" }, "peerDependencies": { - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" } }, "node_modules/@react-types/actiongroup": { - "version": "3.4.9", - "resolved": "https://registry.npmjs.org/@react-types/actiongroup/-/actiongroup-3.4.9.tgz", - "integrity": "sha512-n6lGBLm8HxLguG4om5ysMCexSdMWNhM5L0yGjA4pZxdoKZborPALDN/Ao57svnTwaSJmeExvTwHIFds1yr4AXQ==", + "version": "3.4.11", + "resolved": "https://registry.npmjs.org/@react-types/actiongroup/-/actiongroup-3.4.11.tgz", + "integrity": "sha512-gO/A+nbPoDwovqWlEyILNlfBY1loXFR0+P7OzH+vqppCHFz+Y2dF6Ry2LqUAmE0XPaYLzwg4Y/Nkuc20jIVujQ==", "dependencies": { - "@react-types/shared": "^3.23.1" + "@react-types/shared": "^3.24.1" }, "peerDependencies": { - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" } }, "node_modules/@react-types/avatar": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/@react-types/avatar/-/avatar-3.0.7.tgz", - "integrity": "sha512-FXws1/o0Vy3yJcBDdKYPElNzpcVjdkck6KHGQyxAkKe7vvtFUcHpzz9fxEO5kRLwTv6j7EahXsJeqsH9TpFWuA==", + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/@react-types/avatar/-/avatar-3.0.9.tgz", + "integrity": "sha512-lvzL0DHUaZxLXci9PbtnSWxO/vrcqyPm5KBq3DwiJ/FreAQZjbk7SfOO8we9mPXbe+XePexK/x9n90BtGMKdLw==", "dependencies": { - "@react-types/shared": "^3.23.1" + "@react-types/shared": "^3.24.1" }, "peerDependencies": { - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" } }, "node_modules/@react-types/badge": { - "version": "3.1.9", - "resolved": "https://registry.npmjs.org/@react-types/badge/-/badge-3.1.9.tgz", - "integrity": "sha512-GNvg3cULRiUxXZYmOOIaua0KSL72jnLwv/2LLbQeYQystLaEmsibmdoRvfQN80mEQ1f3WFfhZogiG31+4MS/xg==", + "version": "3.1.11", + "resolved": "https://registry.npmjs.org/@react-types/badge/-/badge-3.1.11.tgz", + "integrity": "sha512-ToIZOT5xRAHqZ9H9v8UkcC+Gds4dKmmIAMb7+aWXGCKIuRlV4wLD1WZJBS9gQlv+WlwvIOEVOgtwktpTrZJW0Q==", "dependencies": { - "@react-types/shared": "^3.23.1" + "@react-types/shared": "^3.24.1" }, "peerDependencies": { - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" } }, "node_modules/@react-types/breadcrumbs": { - "version": "3.7.5", - "resolved": "https://registry.npmjs.org/@react-types/breadcrumbs/-/breadcrumbs-3.7.5.tgz", - "integrity": "sha512-lV9IDYsMiu2TgdMIjEmsOE0YWwjb3jhUNK1DCZZfq6uWuiHLgyx2EncazJBUWSjHJ4ta32j7xTuXch+8Ai6u/A==", + "version": "3.7.7", + "resolved": "https://registry.npmjs.org/@react-types/breadcrumbs/-/breadcrumbs-3.7.7.tgz", + "integrity": "sha512-ZmhXwD2LLzfEA2OvOCp/QvXu8A/Edsrn5q0qUDGsmOZj9SCVeT82bIv8P+mQnATM13mi2gyoik6102Jc1OscJA==", "dependencies": { - "@react-types/link": "^3.5.5", - "@react-types/shared": "^3.23.1" + "@react-types/link": "^3.5.7", + "@react-types/shared": "^3.24.1" }, "peerDependencies": { - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" } }, "node_modules/@react-types/button": { - "version": "3.9.4", - "resolved": "https://registry.npmjs.org/@react-types/button/-/button-3.9.4.tgz", - "integrity": "sha512-raeQBJUxBp0axNF74TXB8/H50GY8Q3eV6cEKMbZFP1+Dzr09Ngv0tJBeW0ewAxAguNH5DRoMUAUGIXtSXskVdA==", + "version": "3.9.6", + "resolved": "https://registry.npmjs.org/@react-types/button/-/button-3.9.6.tgz", + "integrity": "sha512-8lA+D5JLbNyQikf8M/cPP2cji91aVTcqjrGpDqI7sQnaLFikM8eFR6l1ZWGtZS5MCcbfooko77ha35SYplSQvw==", "dependencies": { - "@react-types/shared": "^3.23.1" + "@react-types/shared": "^3.24.1" }, "peerDependencies": { - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" } }, "node_modules/@react-types/buttongroup": { - "version": "3.3.9", - "resolved": "https://registry.npmjs.org/@react-types/buttongroup/-/buttongroup-3.3.9.tgz", - "integrity": "sha512-3hEWI/GOsY8Z3db8gjEXbxl+6E0ioBNMxfN8jIeiNnSWSDG56MLNArJLowylPrwlrp5SnxLh1WBj44OHqEE3Tg==", + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/@react-types/buttongroup/-/buttongroup-3.3.11.tgz", + "integrity": "sha512-29F+GYWdbjuheDZVW9xhju03CQVK401i0DPH7TGqnlNZqteqF/aHqwxRyFT8490ad7og3ZuvXywTBQCwIfbh9Q==", "dependencies": { - "@react-types/shared": "^3.23.1" + "@react-types/shared": "^3.24.1" }, "peerDependencies": { - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" } }, "node_modules/@react-types/calendar": { - "version": "3.4.6", - "resolved": "https://registry.npmjs.org/@react-types/calendar/-/calendar-3.4.6.tgz", - "integrity": "sha512-WSntZPwtvsIYWvBQRAPvuCn55UTJBZroTvX0vQvWykJRQnPAI20G1hMQ3dNsnAL+gLZUYxBXn66vphmjUuSYew==", + "version": "3.4.8", + "resolved": "https://registry.npmjs.org/@react-types/calendar/-/calendar-3.4.8.tgz", + "integrity": "sha512-KVampt/X4uJvWU0TsxIdgPdXIAUClGtxcDWHzuFRJ7YUYkA4rH8Lad0kQ1mVehnwOLpuba8j9GCYKorkbln0gw==", "dependencies": { - "@internationalized/date": "^3.5.4", - "@react-types/shared": "^3.23.1" + "@internationalized/date": "^3.5.5", + "@react-types/shared": "^3.24.1" }, "peerDependencies": { - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" } }, "node_modules/@react-types/checkbox": { - "version": "3.8.1", - "resolved": "https://registry.npmjs.org/@react-types/checkbox/-/checkbox-3.8.1.tgz", - "integrity": "sha512-5/oVByPw4MbR/8QSdHCaalmyWC71H/QGgd4aduTJSaNi825o+v/hsN2/CH7Fq9atkLKsC8fvKD00Bj2VGaKriQ==", + "version": "3.8.3", + "resolved": "https://registry.npmjs.org/@react-types/checkbox/-/checkbox-3.8.3.tgz", + "integrity": "sha512-f4c1mnLEt0iS1NMkyZXgT3q3AgcxzDk7w6MSONOKydcnh0xG5L2oefY14DhVDLkAuQS7jThlUFwiAs+MxiO3MA==", "dependencies": { - "@react-types/shared": "^3.23.1" + "@react-types/shared": "^3.24.1" }, "peerDependencies": { - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" } }, "node_modules/@react-types/color": { - "version": "3.0.0-beta.25", - "resolved": "https://registry.npmjs.org/@react-types/color/-/color-3.0.0-beta.25.tgz", - "integrity": "sha512-D24ASvLeSWouBwOBi4ftUe4/BhrZj5AiHV7tXwrVeMGOy9Z9jyeK65Xysq+R3ecaSONLXsgai5CQMvj13cOacA==", + "version": "3.0.0-rc.1", + "resolved": "https://registry.npmjs.org/@react-types/color/-/color-3.0.0-rc.1.tgz", + "integrity": "sha512-aw6FzrBlZTWKrFaFskM7e3AFICe6JqH10wO0E919goa3LZDDFbyYEwRpatwjIyiZH1elEUkFPgwqpv3ZcPPn8g==", "dependencies": { - "@react-types/shared": "^3.23.1", - "@react-types/slider": "^3.7.3" + "@react-types/shared": "^3.24.1", + "@react-types/slider": "^3.7.5" }, "peerDependencies": { - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" } }, "node_modules/@react-types/combobox": { - "version": "3.11.1", - "resolved": "https://registry.npmjs.org/@react-types/combobox/-/combobox-3.11.1.tgz", - "integrity": "sha512-UNc3OHt5cUt5gCTHqhQIqhaWwKCpaNciD8R7eQazmHiA9fq8ROlV+7l3gdNgdhJbTf5Bu/V5ISnN7Y1xwL3zqQ==", + "version": "3.12.1", + "resolved": "https://registry.npmjs.org/@react-types/combobox/-/combobox-3.12.1.tgz", + "integrity": "sha512-bd5YwHZWtgnJx4jGbplWbYzXj7IbO5w3IY5suNR7r891rx6IktquZ8GQwyYH0pQ/x+X5LdK2xI59i6+QC2PmlA==", "dependencies": { - "@react-types/shared": "^3.23.1" + "@react-types/shared": "^3.24.1" }, "peerDependencies": { - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" } }, "node_modules/@react-types/contextualhelp": { - "version": "3.2.10", - "resolved": "https://registry.npmjs.org/@react-types/contextualhelp/-/contextualhelp-3.2.10.tgz", - "integrity": "sha512-x4rODNQfAO2YeVumkztTsUieOt4z7OXolZY7BLJgT1qonfPwJGLqf+KUayqXuX9l2CHakcGYDGaUxTUvwINQdw==", + "version": "3.2.12", + "resolved": "https://registry.npmjs.org/@react-types/contextualhelp/-/contextualhelp-3.2.12.tgz", + "integrity": "sha512-5PwE2tajqVYzjatdvux6dpGb8trmqGBDp04nuTn010U+HZhxylAe12iU0/Lz+0M7dWpBlVfusE42TLvZdD5VzA==", "dependencies": { - "@react-types/overlays": "^3.8.7", - "@react-types/shared": "^3.23.1" + "@react-types/overlays": "^3.8.9", + "@react-types/shared": "^3.24.1" }, "peerDependencies": { - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" } }, "node_modules/@react-types/datepicker": { - "version": "3.7.4", - "resolved": "https://registry.npmjs.org/@react-types/datepicker/-/datepicker-3.7.4.tgz", - "integrity": "sha512-ZfvgscvNzBJpYyVWg3nstJtA/VlWLwErwSkd1ivZYam859N30w8yH+4qoYLa6FzWLCFlrsRHyvtxlEM7lUAt5A==", + "version": "3.8.1", + "resolved": "https://registry.npmjs.org/@react-types/datepicker/-/datepicker-3.8.1.tgz", + "integrity": "sha512-ZpxHHVT3rmZ4YsYP4TWCZSMSfOUm+067mZyyGLmvHxg55eYmctiB4uMgrRCqDoeiSiOjtxad0VtpPjf6ftK1GQ==", "dependencies": { - "@internationalized/date": "^3.5.4", - "@react-types/calendar": "^3.4.6", - "@react-types/overlays": "^3.8.7", - "@react-types/shared": "^3.23.1" + "@internationalized/date": "^3.5.5", + "@react-types/calendar": "^3.4.8", + "@react-types/overlays": "^3.8.9", + "@react-types/shared": "^3.24.1" }, "peerDependencies": { - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" } }, "node_modules/@react-types/dialog": { - "version": "3.5.10", - "resolved": "https://registry.npmjs.org/@react-types/dialog/-/dialog-3.5.10.tgz", - "integrity": "sha512-S9ga+edOLNLZw7/zVOnZdT5T40etpzUYBXEKdFPbxyPYnERvRxJAsC1/ASuBU9fQAXMRgLZzADWV+wJoGS/X9g==", + "version": "3.5.12", + "resolved": "https://registry.npmjs.org/@react-types/dialog/-/dialog-3.5.12.tgz", + "integrity": "sha512-JmpQbSpXltqEyYfEwoqDolABIiojeExkqolHNdQlayIsfFuSxZxNwXZPOpz58Ri/iwv21JP7K3QF0Gb2Ohxl9w==", "dependencies": { - "@react-types/overlays": "^3.8.7", - "@react-types/shared": "^3.23.1" + "@react-types/overlays": "^3.8.9", + "@react-types/shared": "^3.24.1" }, "peerDependencies": { - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" } }, "node_modules/@react-types/divider": { - "version": "3.3.9", - "resolved": "https://registry.npmjs.org/@react-types/divider/-/divider-3.3.9.tgz", - "integrity": "sha512-SQ3XWS16j3VZg3MGByJ1CjWDfARn+viBDay6SibAFzMqlqVbSol2nw1hQ1JPaT3zeW8C/354q+OhBsIFDOaE7w==", + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/@react-types/divider/-/divider-3.3.11.tgz", + "integrity": "sha512-pnyEhIK21K8K10cvkXID1yx4V8jpY5uRO69o8npyq846p7RSercGGGQNE/vPSJXEViZrXTrf2KyNSPFU2x5INw==", "dependencies": { - "@react-types/shared": "^3.23.1" + "@react-types/shared": "^3.24.1" }, "peerDependencies": { - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" } }, "node_modules/@react-types/form": { - "version": "3.7.4", - "resolved": "https://registry.npmjs.org/@react-types/form/-/form-3.7.4.tgz", - "integrity": "sha512-HZojAWrb6feYnhDEOy3vBamDVAHDl0l2JQZ7aIDLHmeTAGQC3JNZcm2fLTxqLye46zz8w8l8OHgI+NdD4PHdOw==", + "version": "3.7.6", + "resolved": "https://registry.npmjs.org/@react-types/form/-/form-3.7.6.tgz", + "integrity": "sha512-lhS2y1bVtRnyYjkM+ylJUp2g663ZNbeZxu2o+mFfD5c2wYmVLA58IWR90c7DL8IVUitoANnZ1JPhhXvutiFpQQ==", "dependencies": { - "@react-types/shared": "^3.23.1" + "@react-types/shared": "^3.24.1" }, "peerDependencies": { - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" } }, "node_modules/@react-types/grid": { - "version": "3.2.6", - "resolved": "https://registry.npmjs.org/@react-types/grid/-/grid-3.2.6.tgz", - "integrity": "sha512-XfHenL2jEBUYrhKiPdeM24mbLRXUn79wVzzMhrNYh24nBwhsPPpxF+gjFddT3Cy8dt6tRInfT6pMEu9nsXwaHw==", + "version": "3.2.8", + "resolved": "https://registry.npmjs.org/@react-types/grid/-/grid-3.2.8.tgz", + "integrity": "sha512-6PJrpukwMqlv3IhJSDkJuVbhHM8Oe6hd2supWqd9adMXrlSP7QHt9a8SgFcFblCCTx8JzUaA0PvY5sTudcEtOQ==", "dependencies": { - "@react-types/shared": "^3.23.1" + "@react-types/shared": "^3.24.1" }, "peerDependencies": { - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" } }, "node_modules/@react-types/illustratedmessage": { - "version": "3.3.9", - "resolved": "https://registry.npmjs.org/@react-types/illustratedmessage/-/illustratedmessage-3.3.9.tgz", - "integrity": "sha512-a/X+sGzUA+pkLkKDZzy/QpUtOY6qtFpsPs6lfY37TLwCEQmS8a1VKrc1ItlQVRgIvwuqJXKvrJpGOAw+RjVwHw==", + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/@react-types/illustratedmessage/-/illustratedmessage-3.3.11.tgz", + "integrity": "sha512-GW3DCRU1YHv1VteVSTOUN3FH4Z5FCm22k5yTjhb8NjNP0eQ/tH3Gu6pZCVKTiqmuC2Z15nXZGdcPMmzKA8915Q==", "dependencies": { - "@react-types/shared": "^3.23.1" + "@react-types/shared": "^3.24.1" }, "peerDependencies": { - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" } }, "node_modules/@react-types/image": { - "version": "3.4.1", - "resolved": "https://registry.npmjs.org/@react-types/image/-/image-3.4.1.tgz", - "integrity": "sha512-6vA3vEzjXrr701i1J43DkyPziRN7jfKSdarGDP+61dOcvbiLnuTY9t+r/zXo1SdewbjF5RVliB2ys9Bb654YTg==", + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/@react-types/image/-/image-3.4.3.tgz", + "integrity": "sha512-w5oxRYDKTGXHZr4CtLdi8759v2YU3Qux6kPj4fRq67hYRCKQxJOYdqQTlfLwkshe/ddFPb3Geu5GTdQtW+GnDw==", "dependencies": { - "@react-types/shared": "^3.23.1" + "@react-types/shared": "^3.24.1" }, "peerDependencies": { - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" } }, "node_modules/@react-types/label": { - "version": "3.9.3", - "resolved": "https://registry.npmjs.org/@react-types/label/-/label-3.9.3.tgz", - "integrity": "sha512-PGVg/pBYNx3Ft59VNCvG5oqk4pXfS2Gs7t3TGnlBB1d+EXB9BbixJbOAO1PvRqt8SPCNvEAAAVfG6Vf+nOhSWw==", + "version": "3.9.5", + "resolved": "https://registry.npmjs.org/@react-types/label/-/label-3.9.5.tgz", + "integrity": "sha512-kvkPX/S7acwX2E5usekJjpFYFQyykbKFharQvYn06x4sYHevRnxzcRgPkaBynaTu2i5MeQ/Yot7VwyBfEleqSA==", "dependencies": { - "@react-types/shared": "^3.23.1" + "@react-types/shared": "^3.24.1" }, "peerDependencies": { - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" } }, "node_modules/@react-types/layout": { - "version": "3.3.15", - "resolved": "https://registry.npmjs.org/@react-types/layout/-/layout-3.3.15.tgz", - "integrity": "sha512-Rj3M0TWmsag83gvFDY6UnfUkNPrA/FLuJ0kEiOryjjffoI0wTxmTAPpIgG4h7YSxpQJD6g6xQ8bkIWEMCXWyag==", + "version": "3.3.17", + "resolved": "https://registry.npmjs.org/@react-types/layout/-/layout-3.3.17.tgz", + "integrity": "sha512-CoDVto9eq9ZX65SSrPS4XSEZKBvKdnBs41B217Yai2K/s5VyyEJ0zOGtohghJOnalBCG7Ci4if8VnE27lonvcQ==", "dependencies": { - "@react-types/shared": "^3.23.1" + "@react-types/shared": "^3.24.1" }, "peerDependencies": { - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" } }, "node_modules/@react-types/link": { - "version": "3.5.5", - "resolved": "https://registry.npmjs.org/@react-types/link/-/link-3.5.5.tgz", - "integrity": "sha512-G6P5WagHDR87npN7sEuC5IIgL1GsoY4WFWKO4734i2CXRYx24G9P0Su3AX4GA3qpspz8sK1AWkaCzBMmvnunfw==", + "version": "3.5.7", + "resolved": "https://registry.npmjs.org/@react-types/link/-/link-3.5.7.tgz", + "integrity": "sha512-2WyaVmm1qr9UrSG3Dq6iz+2ziuVp+DH8CsYZ9CA6aNNb6U18Hxju3LTPb4a5gM0eC7W0mQGNBmrgGlAdDZEJOw==", "dependencies": { - "@react-types/shared": "^3.23.1" + "@react-types/shared": "^3.24.1" }, "peerDependencies": { - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" } }, "node_modules/@react-types/listbox": { - "version": "3.4.9", - "resolved": "https://registry.npmjs.org/@react-types/listbox/-/listbox-3.4.9.tgz", - "integrity": "sha512-S5G+WmNKUIOPZxZ4svWwWQupP3C6LmVfnf8QQmPDvwYXGzVc0WovkqUWyhhjJirFDswTXRCO9p0yaTHHIlkdwQ==", + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/@react-types/listbox/-/listbox-3.5.1.tgz", + "integrity": "sha512-n5bOgD9lgfK1qaLtag9WPnu151SwXBCNn/OgGY/Br9mWRl+nPUEYtFcPX+2VCld7uThf54kwrTmzlFnaraIlcw==", "dependencies": { - "@react-types/shared": "^3.23.1" + "@react-types/shared": "^3.24.1" }, "peerDependencies": { - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" } }, "node_modules/@react-types/menu": { - "version": "3.9.9", - "resolved": "https://registry.npmjs.org/@react-types/menu/-/menu-3.9.9.tgz", - "integrity": "sha512-FamUaPVs1Fxr4KOMI0YcR2rYZHoN7ypGtgiEiJ11v/tEPjPPGgeKDxii0McCrdOkjheatLN1yd2jmMwYj6hTDg==", + "version": "3.9.11", + "resolved": "https://registry.npmjs.org/@react-types/menu/-/menu-3.9.11.tgz", + "integrity": "sha512-IguQVF70d7aHXgWB1Rd2a/PiIuLZ2Nt7lyayJshLcy/NLOYmgpTmTyn2WCtlA5lTfQwmQrNFf4EvnWkeljJXdA==", "dependencies": { - "@react-types/overlays": "^3.8.7", - "@react-types/shared": "^3.23.1" + "@react-types/overlays": "^3.8.9", + "@react-types/shared": "^3.24.1" }, "peerDependencies": { - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" } }, "node_modules/@react-types/meter": { - "version": "3.4.1", - "resolved": "https://registry.npmjs.org/@react-types/meter/-/meter-3.4.1.tgz", - "integrity": "sha512-AIJV4NDFAqKH94s02c5Da4TH2qgJjfrw978zuFM0KUBFD85WRPKh7MvgWpomvUgmzqE6lMCzIdi1KPKqrRabdw==", + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/@react-types/meter/-/meter-3.4.3.tgz", + "integrity": "sha512-Y2fX5CTAPGRKxVSeepbeyN6/K+wlF9pMRcNxTSU2qDwdoFqNCtTWMcWuCsU/Y2L/zU0jFWu4x0Vo7WkrcsgcMA==", "dependencies": { - "@react-types/progress": "^3.5.4" + "@react-types/progress": "^3.5.6" }, "peerDependencies": { - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" } }, "node_modules/@react-types/numberfield": { - "version": "3.8.3", - "resolved": "https://registry.npmjs.org/@react-types/numberfield/-/numberfield-3.8.3.tgz", - "integrity": "sha512-z5fGfVj3oh5bmkw9zDvClA1nDBSFL9affOuyk2qZ/M2SRUmykDAPCksbfcMndft0XULWKbF4s2CYbVI+E/yrUA==", + "version": "3.8.5", + "resolved": "https://registry.npmjs.org/@react-types/numberfield/-/numberfield-3.8.5.tgz", + "integrity": "sha512-LVWggkxwd1nyVZomXBPfQA1E4I4/i4PBifjcDs2AfcV7q5RE9D+DVIDXsYucVOBxPlDOxiAq/T9ypobspWSwHw==", "dependencies": { - "@react-types/shared": "^3.23.1" + "@react-types/shared": "^3.24.1" }, "peerDependencies": { - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" } }, "node_modules/@react-types/overlays": { - "version": "3.8.7", - "resolved": "https://registry.npmjs.org/@react-types/overlays/-/overlays-3.8.7.tgz", - "integrity": "sha512-zCOYvI4at2DkhVpviIClJ7bRrLXYhSg3Z3v9xymuPH3mkiuuP/dm8mUCtkyY4UhVeUTHmrQh1bzaOP00A+SSQA==", + "version": "3.8.9", + "resolved": "https://registry.npmjs.org/@react-types/overlays/-/overlays-3.8.9.tgz", + "integrity": "sha512-9ni9upQgXPnR+K9cWmbYWvm3ll9gH8P/XsEZprqIV5zNLMF334jADK48h4jafb1X9RFnj0WbHo6BqcSObzjTig==", "dependencies": { - "@react-types/shared": "^3.23.1" + "@react-types/shared": "^3.24.1" }, "peerDependencies": { - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" } }, "node_modules/@react-types/progress": { - "version": "3.5.4", - "resolved": "https://registry.npmjs.org/@react-types/progress/-/progress-3.5.4.tgz", - "integrity": "sha512-JNc246sTjasPyx5Dp7/s0rp3Bz4qlu4LrZTulZlxWyb53WgBNL7axc26CCi+I20rWL9+c7JjhrRxnLl/1cLN5g==", + "version": "3.5.6", + "resolved": "https://registry.npmjs.org/@react-types/progress/-/progress-3.5.6.tgz", + "integrity": "sha512-Nh43sjQ5adyN1bTHBPRaIPhXUdBqP0miYeJpeMY3V/KUl4qmouJLwDnccwFG4xLm6gBfYe22lgbbV7nAfNnuTQ==", "dependencies": { - "@react-types/shared": "^3.23.1" + "@react-types/shared": "^3.24.1" }, "peerDependencies": { - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" } }, "node_modules/@react-types/provider": { - "version": "3.8.1", - "resolved": "https://registry.npmjs.org/@react-types/provider/-/provider-3.8.1.tgz", - "integrity": "sha512-Sm59ufxdHh6fGfeUbviNQhRvtI0FMEX1gn9Okc8nL7iTVbAAitT746x0itM+xwhFLDI6gSY8FILDWc5/kIxzxA==", + "version": "3.8.3", + "resolved": "https://registry.npmjs.org/@react-types/provider/-/provider-3.8.3.tgz", + "integrity": "sha512-tUt/94BRS0gZFprBAErYXauyONGcJM8ZWLCae925kZ3iLdzRWxG5qoNyKZ3SRKODdLDvJAgmPjImpj8GzYc3Fg==", "dependencies": { - "@react-types/shared": "^3.23.1" + "@react-types/shared": "^3.24.1" }, "peerDependencies": { - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" } }, "node_modules/@react-types/radio": { - "version": "3.8.1", - "resolved": "https://registry.npmjs.org/@react-types/radio/-/radio-3.8.1.tgz", - "integrity": "sha512-bK0gio/qj1+0Ldu/3k/s9BaOZvnnRgvFtL3u5ky479+aLG5qf1CmYed3SKz8ErZ70JkpuCSrSwSCFf0t1IHovw==", + "version": "3.8.3", + "resolved": "https://registry.npmjs.org/@react-types/radio/-/radio-3.8.3.tgz", + "integrity": "sha512-fUVJt4Bb6jOReFqnhHVNxWXH7t6c60uSFfoPKuXt/xI9LL1i2jhpur0ggpTfIn3qLIAmNBU6bKBCWAdr4KjeVQ==", "dependencies": { - "@react-types/shared": "^3.23.1" + "@react-types/shared": "^3.24.1" }, "peerDependencies": { - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" } }, "node_modules/@react-types/searchfield": { - "version": "3.5.5", - "resolved": "https://registry.npmjs.org/@react-types/searchfield/-/searchfield-3.5.5.tgz", - "integrity": "sha512-T/NHg12+w23TxlXMdetogLDUldk1z5dDavzbnjKrLkajLb221bp8brlR/+O6C1CtFpuJGALqYHgTasU1qkQFSA==", + "version": "3.5.7", + "resolved": "https://registry.npmjs.org/@react-types/searchfield/-/searchfield-3.5.7.tgz", + "integrity": "sha512-dyuPwNWGswRZfb4i50Q1Q3tCwTBxRLkrAxcMs+Rf2Rl4t93bawBdSdIQuvxu1KEhgd0EXA9ZUW53ZplqfVmtiw==", "dependencies": { - "@react-types/shared": "^3.23.1", - "@react-types/textfield": "^3.9.3" + "@react-types/shared": "^3.24.1", + "@react-types/textfield": "^3.9.5" }, "peerDependencies": { - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" } }, "node_modules/@react-types/select": { - "version": "3.9.4", - "resolved": "https://registry.npmjs.org/@react-types/select/-/select-3.9.4.tgz", - "integrity": "sha512-xI7dnOW2st91fPPcv6hdtrTdcfetYiqZuuVPZ5TRobY7Q10/Zqqe/KqtOw1zFKUj9xqNJe4Ov3xP5GSdcO60Eg==", + "version": "3.9.6", + "resolved": "https://registry.npmjs.org/@react-types/select/-/select-3.9.6.tgz", + "integrity": "sha512-cVSFR0eJLup/ht1Uto+y8uyLmHO89J6wNh65SIHb3jeVz9oLBAedP3YNI2qB+F9qFMUcA8PBSLXIIuT6gXzLgQ==", "dependencies": { - "@react-types/shared": "^3.23.1" + "@react-types/shared": "^3.24.1" }, "peerDependencies": { - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" } }, "node_modules/@react-types/shared": { - "version": "3.23.1", - "resolved": "https://registry.npmjs.org/@react-types/shared/-/shared-3.23.1.tgz", - "integrity": "sha512-5d+3HbFDxGZjhbMBeFHRQhexMFt4pUce3okyRtUVKbbedQFUrtXSBg9VszgF2RTeQDKDkMCIQDtz5ccP/Lk1gw==", + "version": "3.24.1", + "resolved": "https://registry.npmjs.org/@react-types/shared/-/shared-3.24.1.tgz", + "integrity": "sha512-AUQeGYEm/zDTN6zLzdXolDxz3Jk5dDL7f506F07U8tBwxNNI3WRdhU84G0/AaFikOZzDXhOZDr3MhQMzyE7Ydw==", "peerDependencies": { - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" } }, "node_modules/@react-types/slider": { - "version": "3.7.3", - "resolved": "https://registry.npmjs.org/@react-types/slider/-/slider-3.7.3.tgz", - "integrity": "sha512-F8qFQaD2mqug2D0XeWMmjGBikiwbdERFlhFzdvNGbypPLz3AZICBKp1ZLPWdl0DMuy03G/jy6Gl4mDobl7RT2g==", + "version": "3.7.5", + "resolved": "https://registry.npmjs.org/@react-types/slider/-/slider-3.7.5.tgz", + "integrity": "sha512-bRitwQRQjQoOcKEdPMljnvm474dwrmsc6pdsVQDh/qynzr+KO9IHuYc3qPW53WVE2hMQJDohlqtCAWQXWQ5Vcg==", "dependencies": { - "@react-types/shared": "^3.23.1" + "@react-types/shared": "^3.24.1" }, "peerDependencies": { - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" } }, "node_modules/@react-types/statuslight": { - "version": "3.3.9", - "resolved": "https://registry.npmjs.org/@react-types/statuslight/-/statuslight-3.3.9.tgz", - "integrity": "sha512-6nC17gluvrMCJkb0mihzqAaz8wn0ghfgk1ILkL8CUobsqJU6pW4eGJXNoZCd5wHT/YjwnupzfhHcbMj93AHzWQ==", + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/@react-types/statuslight/-/statuslight-3.3.11.tgz", + "integrity": "sha512-EYxya+R4PpgB1V8pcn2w4fgFbPMCuya+TeYDoO6Izp3AQRWYgQRwM8Gz3IQ/qXFvwzT9e1fEuOHPHqPW1Tiitw==", "dependencies": { - "@react-types/shared": "^3.23.1" + "@react-types/shared": "^3.24.1" }, "peerDependencies": { - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" } }, "node_modules/@react-types/switch": { - "version": "3.5.3", - "resolved": "https://registry.npmjs.org/@react-types/switch/-/switch-3.5.3.tgz", - "integrity": "sha512-Nb6+J5MrPaFa8ZNFKGMzAsen/NNzl5UG/BbC65SLGPy7O0VDa/sUpn7dcu8V2xRpRwwIN/Oso4v63bt2sgdkgA==", + "version": "3.5.5", + "resolved": "https://registry.npmjs.org/@react-types/switch/-/switch-3.5.5.tgz", + "integrity": "sha512-SZx1Bd+COhAOs/RTifbZG+uq/llwba7VAKx7XBeX4LeIz1dtguy5bigOBgFTMQi4qsIVCpybSWEEl+daj4XFPw==", "dependencies": { - "@react-types/shared": "^3.23.1" + "@react-types/shared": "^3.24.1" }, "peerDependencies": { - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" } }, "node_modules/@react-types/table": { - "version": "3.9.5", - "resolved": "https://registry.npmjs.org/@react-types/table/-/table-3.9.5.tgz", - "integrity": "sha512-fgM2j9F/UR4Anmd28CueghCgBwOZoCVyN8fjaIFPd2MN4gCwUUfANwxLav65gZk4BpwUXGoQdsW+X50L3555mg==", + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/@react-types/table/-/table-3.10.1.tgz", + "integrity": "sha512-xsNh0Gm4GtNeSknZqkMsfGvc94fycmfhspGO+FzQKim2hB5k4yILwd+lHYQ2UKW6New9GVH/zN2Pd3v67IeZ2g==", "dependencies": { - "@react-types/grid": "^3.2.6", - "@react-types/shared": "^3.23.1" + "@react-types/grid": "^3.2.8", + "@react-types/shared": "^3.24.1" }, "peerDependencies": { - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" } }, "node_modules/@react-types/tabs": { - "version": "3.3.7", - "resolved": "https://registry.npmjs.org/@react-types/tabs/-/tabs-3.3.7.tgz", - "integrity": "sha512-ZdLe5xOcFX6+/ni45Dl2jO0jFATpTnoSqj6kLIS/BYv8oh0n817OjJkLf+DS3CLfNjApJWrHqAk34xNh6nRnEg==", + "version": "3.3.9", + "resolved": "https://registry.npmjs.org/@react-types/tabs/-/tabs-3.3.9.tgz", + "integrity": "sha512-3Q9kRVvg/qDyeJR/W1+C2z2OyvDWQrSLvOCvAezX5UKzww4rBEAA8OqBlyDwn7q3fiwrh/m64l6p+dbln+RdxQ==", "dependencies": { - "@react-types/shared": "^3.23.1" + "@react-types/shared": "^3.24.1" }, "peerDependencies": { - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" } }, "node_modules/@react-types/text": { - "version": "3.3.9", - "resolved": "https://registry.npmjs.org/@react-types/text/-/text-3.3.9.tgz", - "integrity": "sha512-JJTmUstFXikZHQhf+0VELODGz1jUcSgXOTYJxTMiMtSjLOSCW5G+pRhT80MRgxOeuD0Z7p0XghUXo3ruD694HA==", + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/@react-types/text/-/text-3.3.11.tgz", + "integrity": "sha512-e78lt//FlmrJSPNgZZYT2LoBXFqoG5MX/kaS738bO9WkUR4nE1wtBBMmztQxQTvqz0cV/gaJEHZla4Orp+Civw==", "dependencies": { - "@react-types/shared": "^3.23.1" + "@react-types/shared": "^3.24.1" }, "peerDependencies": { - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" } }, "node_modules/@react-types/textfield": { - "version": "3.9.3", - "resolved": "https://registry.npmjs.org/@react-types/textfield/-/textfield-3.9.3.tgz", - "integrity": "sha512-DoAY6cYOL0pJhgNGI1Rosni7g72GAt4OVr2ltEx2S9ARmFZ0DBvdhA9lL2nywcnKMf27PEJcKMXzXc10qaHsJw==", + "version": "3.9.5", + "resolved": "https://registry.npmjs.org/@react-types/textfield/-/textfield-3.9.5.tgz", + "integrity": "sha512-0hwZI4WXSEStPzdltKwbNUZWlgHtwbxMWE0LfqIzEW8RB7DyBflYSKzLyTBFqwUZ8j3C1gWy9c9OPSeCOq792Q==", "dependencies": { - "@react-types/shared": "^3.23.1" + "@react-types/shared": "^3.24.1" }, "peerDependencies": { - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" } }, "node_modules/@react-types/tooltip": { - "version": "3.4.9", - "resolved": "https://registry.npmjs.org/@react-types/tooltip/-/tooltip-3.4.9.tgz", - "integrity": "sha512-wZ+uF1+Zc43qG+cOJzioBmLUNjRa7ApdcT0LI1VvaYvH5GdfjzUJOorLX9V/vAci0XMJ50UZ+qsh79aUlw2yqg==", + "version": "3.4.11", + "resolved": "https://registry.npmjs.org/@react-types/tooltip/-/tooltip-3.4.11.tgz", + "integrity": "sha512-WPikHQxeT5Lb09yJEaW6Ja3ecE0g1YM6ukWYS2v/iZLUPn5YlYrGytspuCYQNSh/u7suCz4zRLEHYCl7OCigjw==", "dependencies": { - "@react-types/overlays": "^3.8.7", - "@react-types/shared": "^3.23.1" + "@react-types/overlays": "^3.8.9", + "@react-types/shared": "^3.24.1" }, "peerDependencies": { - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" } }, "node_modules/@react-types/view": { - "version": "3.4.9", - "resolved": "https://registry.npmjs.org/@react-types/view/-/view-3.4.9.tgz", - "integrity": "sha512-HY969whOXKg10ZqIrXOF12wm3rDwNaKaK9fzqhhrUc94+JR4OPKQctps+HeonAXscxy2yMy8V1/2yjiEwluvAA==", + "version": "3.4.11", + "resolved": "https://registry.npmjs.org/@react-types/view/-/view-3.4.11.tgz", + "integrity": "sha512-FgWQGppdqAHfnRUyjc01nRdMKSEpJBze99+k+xscW+Lv6XNXQR3PlC8QOpcEZ4gGy9Xx1YkbKHDX1eOCNTeYnA==", "dependencies": { - "@react-types/shared": "^3.23.1" + "@react-types/shared": "^3.24.1" }, "peerDependencies": { - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" } }, "node_modules/@react-types/well": { - "version": "3.3.9", - "resolved": "https://registry.npmjs.org/@react-types/well/-/well-3.3.9.tgz", - "integrity": "sha512-3ZlxjkWXupxx0PaxpDc4Pqxxgnzp8iJkilbJ3LY5F+RJwqDm0gkKnWcFjlVJw9LkM7Emjrvm1R8naSGzJ7wJ2A==", + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/@react-types/well/-/well-3.3.11.tgz", + "integrity": "sha512-xHe0t/4ndLIG5nrbGBEFJCeYuni4VML8t6rwEOWbQTTke6DSYZ53DPL7aepO4IP1hW0ufEOJ0WV7Bx7YTUMu+Q==", "dependencies": { - "@react-types/shared": "^3.23.1" + "@react-types/shared": "^3.24.1" }, "peerDependencies": { - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" } }, "node_modules/@rkusa/linebreak": { @@ -7099,11 +7103,11 @@ "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==" }, "node_modules/@sindresorhus/is": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-6.3.1.tgz", - "integrity": "sha512-FX4MfcifwJyFOI2lPoX7PQxCqx8BG1HCho7WdiXwpEQx1Ycij0JxkfYtGK7yqNScrZGSlt6RE6sw8QYoH7eKnQ==", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-7.0.0.tgz", + "integrity": "sha512-WDTlVTyvFivSOuyvMeedzg2hdoBLZ3f1uNVuEida2Rl9BrfjrIRjWA/VZIrMRLvSwJYCAlCRA3usDt1THytxWQ==", "engines": { - "node": ">=16" + "node": ">=18" }, "funding": { "url": "https://github.com/sindresorhus/is?sponsor=1" @@ -7115,31 +7119,31 @@ "integrity": "sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==" }, "node_modules/@spectrum-icons/ui": { - "version": "3.6.7", - "resolved": "https://registry.npmjs.org/@spectrum-icons/ui/-/ui-3.6.7.tgz", - "integrity": "sha512-l08Juk6w8UUpM+xXNVq9LBJ0pxMC1tynXBurTZ135twdtMwofrZmtSHUYdzaRJtm31S9E/+C1Toci1I8aw7Wlw==", + "version": "3.6.9", + "resolved": "https://registry.npmjs.org/@spectrum-icons/ui/-/ui-3.6.9.tgz", + "integrity": "sha512-pxgEoSfce2Vcijh+lizPgCPwAIaBYkOHwWaOXTEHn9REglAnMADdmyAyxib84JSxVY5funJ3AWPKYbEEICEXIg==", "dependencies": { - "@adobe/react-spectrum-ui": "1.2.0", - "@react-spectrum/icon": "^3.7.13", + "@adobe/react-spectrum-ui": "1.2.1", + "@react-spectrum/icon": "^3.7.15", "@swc/helpers": "^0.5.0" }, "peerDependencies": { "@react-spectrum/provider": "^3.0.0", - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" } }, "node_modules/@spectrum-icons/workflow": { - "version": "4.2.12", - "resolved": "https://registry.npmjs.org/@spectrum-icons/workflow/-/workflow-4.2.12.tgz", - "integrity": "sha512-xuyytdlM09DEZO7/vSp5z8Y2RYNXL4OOYSmOaWXeYgIa3iPNKz0HW+iVR2P+Ht0iBtKjPvRobbEFb0k280U4yQ==", + "version": "4.2.14", + "resolved": "https://registry.npmjs.org/@spectrum-icons/workflow/-/workflow-4.2.14.tgz", + "integrity": "sha512-wPz3T8sKJCM/o2sWLjHBL/tO2DmD+10zK/AjnbCoytyeMTxniUfMr7i4RM+E/H9uCUcswL9/QFX7kbgArj0A7Q==", "dependencies": { - "@adobe/react-spectrum-workflow": "2.3.4", - "@react-spectrum/icon": "^3.7.13", + "@adobe/react-spectrum-workflow": "2.3.5", + "@react-spectrum/icon": "^3.7.15", "@swc/helpers": "^0.5.0" }, "peerDependencies": { "@react-spectrum/provider": "^3.0.0", - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" } }, "node_modules/@swc/helpers": { @@ -8835,9 +8839,9 @@ "dev": true }, "node_modules/@types/chai": { - "version": "4.3.16", - "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.3.16.tgz", - "integrity": "sha512-PatH4iOdyh3MyWtmHVFXLWCCIhUbopaltqddG9BzB+gMIzee2MJrvd+jouii9Z3wzQJruGWAm7WOMjgfG8hQlQ==", + "version": "4.3.17", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.3.17.tgz", + "integrity": "sha512-zmZ21EWzR71B4Sscphjief5djsLre50M6lI622OSySTmn9DB3j+C3kWroHfBQWXbOBwbgg/M8CG/hUxDLIloow==", "dev": true }, "node_modules/@types/color": { @@ -9163,15 +9167,21 @@ "@types/ms": "*" } }, + "node_modules/@types/dom-mediacapture-record": { + "version": "1.0.19", + "resolved": "https://registry.npmjs.org/@types/dom-mediacapture-record/-/dom-mediacapture-record-1.0.19.tgz", + "integrity": "sha512-Cz/85z3YTuUPnXrOp5MvSZZSgDkWTWvj1HgE7MWc5C8d/w/soJBXjnAoYDl4P5gmenDNNZkhXzNylGqxS1FzOw==", + "dev": true + }, "node_modules/@types/dom-speech-recognition": { "version": "0.0.4", "resolved": "https://registry.npmjs.org/@types/dom-speech-recognition/-/dom-speech-recognition-0.0.4.tgz", "integrity": "sha512-zf2GwV/G6TdaLwpLDcGTIkHnXf8JEf/viMux+khqKQKDa8/8BAUtXXZS563GnvJ4Fg0PBLGAaFf2GekEVSZ6GQ==" }, "node_modules/@types/eslint": { - "version": "8.56.10", - "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.56.10.tgz", - "integrity": "sha512-Shavhk87gCtY2fhXDctcfS3e6FdxWkCx1iUZ9eEUbh7rTqlZT0/IzOkCOVt0fCjcFuZ9FPYfuezTBImfHCDBGQ==", + "version": "8.56.11", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.56.11.tgz", + "integrity": "sha512-sVBpJMf7UPo/wGecYOpk2aQya2VUGeHhe38WG7/mN5FufNSubf5VT9Uh9Uyp8/eLJpu1/tuhJ/qTo4mhSB4V4Q==", "dependencies": { "@types/estree": "*", "@types/json-schema": "*" @@ -9253,9 +9263,9 @@ "integrity": "sha512-IGKtSn0Lonfx3HdK6KMcfd5GUc1xdeLtjW1n7ZSA5Tmn1n2gj878q6IC0s4MbF9KtBpXIRqjRQxBzi2kF4WvGw==" }, "node_modules/@types/fluent-ffmpeg": { - "version": "2.1.24", - "resolved": "https://registry.npmjs.org/@types/fluent-ffmpeg/-/fluent-ffmpeg-2.1.24.tgz", - "integrity": "sha512-g5oQO8Jgi2kFS3tTub7wLvfLztr1s8tdXmRd8PiL/hLMLzTIAyMR2sANkTggM/rdEDAg3d63nYRRVepwBiCw5A==", + "version": "2.1.25", + "resolved": "https://registry.npmjs.org/@types/fluent-ffmpeg/-/fluent-ffmpeg-2.1.25.tgz", + "integrity": "sha512-a9/Jtv/RVaCG4lUwWIcuClWE5eXJFoFS/oHOecOv/RS8n+lQdJzcJVmDlxA8Xbk4B82YpO88Dijcoljb6sYTcA==", "dependencies": { "@types/node": "*" } @@ -9333,9 +9343,9 @@ "dev": true }, "node_modules/@types/http-proxy": { - "version": "1.17.14", - "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.14.tgz", - "integrity": "sha512-SSrD0c1OQzlFX7pGu1eXxSEjemej64aaNPRhhVYUGqXh0BtldAAx37MG8btcumvpgKyZp1F5Gn3JkktdxiFv6w==", + "version": "1.17.15", + "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.15.tgz", + "integrity": "sha512-25g5atgiVNTIv0LBDTg1H74Hvayx0ajtJPLLcYE3whFv75J0pWNtOBzaXJQgDTmrX1bx5U9YC2w/n65BN1HwRQ==", "dev": true, "dependencies": { "@types/node": "*" @@ -9366,6 +9376,7 @@ "version": "3.5.30", "resolved": "https://registry.npmjs.org/@types/jquery/-/jquery-3.5.30.tgz", "integrity": "sha512-nbWKkkyb919DOUxjmRVk8vwtDb0/k8FKncmUKFi+NY+QXqWltooxTrswvz4LspQwxvLdvzBN1TImr6cw3aQx2A==", + "dev": true, "dependencies": { "@types/sizzle": "*" } @@ -9423,9 +9434,9 @@ } }, "node_modules/@types/mapbox-gl": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@types/mapbox-gl/-/mapbox-gl-3.1.0.tgz", - "integrity": "sha512-hI6cQDjw1bkJw7MC/eHMqq5TWUamLwsujnUUeiIX2KDRjxRNSYMjnHz07+LATz9I9XIsKumOtUz4gRYnZOJ/FA==", + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/@types/mapbox-gl/-/mapbox-gl-3.4.0.tgz", + "integrity": "sha512-tbn++Mm94H1kE7W6FF0oVC9rMXHVzDDNUbS7KfBMRF8NV/8csFi+67ytKcZJ4LsrpsJ+8MC6Os6ZinEDCsrunw==", "dependencies": { "@types/geojson": "*" } @@ -9462,9 +9473,9 @@ "integrity": "sha512-nG96G3Wp6acyAgJqGasjODb+acrI7KltPiRxzHPXnP3NgI28bpQDRv53olbqGXbfcgF5aiiHmO3xpwEpS5Ld9g==" }, "node_modules/@types/node": { - "version": "20.14.11", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.14.11.tgz", - "integrity": "sha512-kprQpL8MMeszbz6ojB5/tU8PLN4kesnN8Gjzw349rDlNgsSzg90lAVj3llK99Dh7JON+t9AuscPPFW6mPbTnSA==", + "version": "20.14.14", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.14.14.tgz", + "integrity": "sha512-d64f00982fS9YoOgJkAMolK7MN8Iq3TDdVjchbYHdEmjth/DHowx82GnoA+tVUAN+7vxfYUgAzi+JXbKNd2SDQ==", "dependencies": { "undici-types": "~5.26.4" } @@ -9789,7 +9800,8 @@ "node_modules/@types/sizzle": { "version": "2.3.8", "resolved": "https://registry.npmjs.org/@types/sizzle/-/sizzle-2.3.8.tgz", - "integrity": "sha512-0vWLNK2D5MT9dg0iOo8GlKguPAU02QjmZitPEsXRuJXU/OGIOt9vT9Fc26wtYuavLxtO45v9PGleoL9Z0k1LHg==" + "integrity": "sha512-0vWLNK2D5MT9dg0iOo8GlKguPAU02QjmZitPEsXRuJXU/OGIOt9vT9Fc26wtYuavLxtO45v9PGleoL9Z0k1LHg==", + "dev": true }, "node_modules/@types/sockjs": { "version": "0.3.36", @@ -9825,10 +9837,17 @@ "@types/geojson": "*" } }, + "node_modules/@types/textarea-caret": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/textarea-caret/-/textarea-caret-3.0.3.tgz", + "integrity": "sha512-bsA9GdXV1wQsXyDjS5+A+czz8IAR3haH5DU+KctIoXbzobRL2NOiwF/+EbB7pofAyudMytLj4ihPtbmbJT8FWw==", + "dev": true + }, "node_modules/@types/textfit": { "version": "2.4.4", "resolved": "https://registry.npmjs.org/@types/textfit/-/textfit-2.4.4.tgz", "integrity": "sha512-AYlNcJ5j/WspQfbHIhoF0Wo63F5+REnX/VPFSH5unUUuwRcr6IoXxZki3vYhG4DRVUQe51AsFYyRxml5u+qaAg==", + "dev": true, "dependencies": { "@types/jquery": "*" } @@ -9887,6 +9906,15 @@ "webpack": "^5" } }, + "node_modules/@types/webscopeio__react-textarea-autocomplete": { + "version": "4.7.5", + "resolved": "https://registry.npmjs.org/@types/webscopeio__react-textarea-autocomplete/-/webscopeio__react-textarea-autocomplete-4.7.5.tgz", + "integrity": "sha512-B9YZ5KrKRcNNsh2v7tyc/tZ1rrPoyWoaXQvvfcG9pX85w9jy2HLnPPT7Kfms5TgzR3RGQ5TIvXQvmsizxdohyQ==", + "dev": true, + "dependencies": { + "@types/react": "*" + } + }, "node_modules/@types/whatwg-url": { "version": "11.0.5", "resolved": "https://registry.npmjs.org/@types/whatwg-url/-/whatwg-url-11.0.5.tgz", @@ -9896,18 +9924,18 @@ } }, "node_modules/@types/ws": { - "version": "8.5.11", - "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.11.tgz", - "integrity": "sha512-4+q7P5h3SpJxaBft0Dzpbr6lmMaqh0Jr2tbhJZ/luAwvD7ohSCniYkwz/pLxuT2h0EOa6QADgJj1Ko+TzRfZ+w==", + "version": "8.5.12", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.12.tgz", + "integrity": "sha512-3tPRkv1EtkDpzlgyKyI8pGsGZAGPEaXeu0DOj5DI25Ja91bdAYddYHbADRYVrZMRbfW+1l5YwXVDKohDJNQxkQ==", "dev": true, "dependencies": { "@types/node": "*" } }, "node_modules/@types/yargs": { - "version": "17.0.32", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.32.tgz", - "integrity": "sha512-xQ67Yc/laOG5uMfX/093MRlGGCIBzZMarVa+gfNKJxWAIgykYpVGkBdbqEzGDDfCrVUj6Hiff4mTZ5BA6TmAog==", + "version": "17.0.33", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.33.tgz", + "integrity": "sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA==", "dependencies": { "@types/yargs-parser": "*" } @@ -9924,16 +9952,16 @@ "dev": true }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "7.16.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.16.1.tgz", - "integrity": "sha512-SxdPak/5bO0EnGktV05+Hq8oatjAYVY3Zh2bye9pGZy6+jwyR3LG3YKkV4YatlsgqXP28BTeVm9pqwJM96vf2A==", + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.18.0.tgz", + "integrity": "sha512-94EQTWZ40mzBc42ATNIBimBEDltSJ9RQHCC8vc/PDbxi4k8dVwUAv4o98dk50M1zB+JGFxp43FP7f8+FP8R6Sw==", "dev": true, "dependencies": { "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "7.16.1", - "@typescript-eslint/type-utils": "7.16.1", - "@typescript-eslint/utils": "7.16.1", - "@typescript-eslint/visitor-keys": "7.16.1", + "@typescript-eslint/scope-manager": "7.18.0", + "@typescript-eslint/type-utils": "7.18.0", + "@typescript-eslint/utils": "7.18.0", + "@typescript-eslint/visitor-keys": "7.18.0", "graphemer": "^1.4.0", "ignore": "^5.3.1", "natural-compare": "^1.4.0", @@ -9957,14 +9985,14 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "7.16.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.16.1.tgz", - "integrity": "sha512-u+1Qx86jfGQ5i4JjK33/FnawZRpsLxRnKzGE6EABZ40KxVT/vWsiZFEBBHjFOljmmV3MBYOHEKi0Jm9hbAOClA==", - "dependencies": { - "@typescript-eslint/scope-manager": "7.16.1", - "@typescript-eslint/types": "7.16.1", - "@typescript-eslint/typescript-estree": "7.16.1", - "@typescript-eslint/visitor-keys": "7.16.1", + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.18.0.tgz", + "integrity": "sha512-4Z+L8I2OqhZV8qA132M4wNL30ypZGYOQVBfMgxDH/K5UX0PNqTu1c6za9ST5r9+tavvHiTWmBnKzpCJ/GlVFtg==", + "dependencies": { + "@typescript-eslint/scope-manager": "7.18.0", + "@typescript-eslint/types": "7.18.0", + "@typescript-eslint/typescript-estree": "7.18.0", + "@typescript-eslint/visitor-keys": "7.18.0", "debug": "^4.3.4" }, "engines": { @@ -9984,12 +10012,12 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "7.16.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.16.1.tgz", - "integrity": "sha512-nYpyv6ALte18gbMz323RM+vpFpTjfNdyakbf3nsLvF43uF9KeNC289SUEW3QLZ1xPtyINJ1dIsZOuWuSRIWygw==", + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.18.0.tgz", + "integrity": "sha512-jjhdIE/FPF2B7Z1uzc6i3oWKbGcHb87Qw7AWj6jmEqNOfDFbJWtjt/XfwCpvNkpGWlcJaog5vTR+VV8+w9JflA==", "dependencies": { - "@typescript-eslint/types": "7.16.1", - "@typescript-eslint/visitor-keys": "7.16.1" + "@typescript-eslint/types": "7.18.0", + "@typescript-eslint/visitor-keys": "7.18.0" }, "engines": { "node": "^18.18.0 || >=20.0.0" @@ -10000,13 +10028,13 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "7.16.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.16.1.tgz", - "integrity": "sha512-rbu/H2MWXN4SkjIIyWcmYBjlp55VT+1G3duFOIukTNFxr9PI35pLc2ydwAfejCEitCv4uztA07q0QWanOHC7dA==", + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.18.0.tgz", + "integrity": "sha512-XL0FJXuCLaDuX2sYqZUUSOJ2sG5/i1AAze+axqmLnSkNEVMVYLF+cbwlB2w8D1tinFuSikHmFta+P+HOofrLeA==", "dev": true, "dependencies": { - "@typescript-eslint/typescript-estree": "7.16.1", - "@typescript-eslint/utils": "7.16.1", + "@typescript-eslint/typescript-estree": "7.18.0", + "@typescript-eslint/utils": "7.18.0", "debug": "^4.3.4", "ts-api-utils": "^1.3.0" }, @@ -10027,9 +10055,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "7.16.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.16.1.tgz", - "integrity": "sha512-AQn9XqCzUXd4bAVEsAXM/Izk11Wx2u4H3BAfQVhSfzfDOm/wAON9nP7J5rpkCxts7E5TELmN845xTUCQrD1xIQ==", + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.18.0.tgz", + "integrity": "sha512-iZqi+Ds1y4EDYUtlOOC+aUmxnE9xS/yCigkjA7XpTKV6nCBd3Hp/PRGGmdwnfkV2ThMyYldP1wRpm/id99spTQ==", "engines": { "node": "^18.18.0 || >=20.0.0" }, @@ -10039,12 +10067,12 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "7.16.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.16.1.tgz", - "integrity": "sha512-0vFPk8tMjj6apaAZ1HlwM8w7jbghC8jc1aRNJG5vN8Ym5miyhTQGMqU++kuBFDNKe9NcPeZ6x0zfSzV8xC1UlQ==", + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.18.0.tgz", + "integrity": "sha512-aP1v/BSPnnyhMHts8cf1qQ6Q1IFwwRvAQGRvBFkWlo3/lH29OXA3Pts+c10nxRxIBrDnoMqzhgdwVe5f2D6OzA==", "dependencies": { - "@typescript-eslint/types": "7.16.1", - "@typescript-eslint/visitor-keys": "7.16.1", + "@typescript-eslint/types": "7.18.0", + "@typescript-eslint/visitor-keys": "7.18.0", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -10077,15 +10105,15 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "7.16.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.16.1.tgz", - "integrity": "sha512-WrFM8nzCowV0he0RlkotGDujx78xudsxnGMBHI88l5J8wEhED6yBwaSLP99ygfrzAjsQvcYQ94quDwI0d7E1fA==", + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.18.0.tgz", + "integrity": "sha512-kK0/rNa2j74XuHVcoCZxdFBMF+aq/vH83CXAOHieC+2Gis4mF8jJXT5eAfyD3K0sAxtPuwxaIOIOvhwzVDt/kw==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", - "@typescript-eslint/scope-manager": "7.16.1", - "@typescript-eslint/types": "7.16.1", - "@typescript-eslint/typescript-estree": "7.16.1" + "@typescript-eslint/scope-manager": "7.18.0", + "@typescript-eslint/types": "7.18.0", + "@typescript-eslint/typescript-estree": "7.18.0" }, "engines": { "node": "^18.18.0 || >=20.0.0" @@ -10099,11 +10127,11 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "7.16.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.16.1.tgz", - "integrity": "sha512-Qlzzx4sE4u3FsHTPQAAQFJFNOuqtuY0LFrZHwQ8IHK705XxBiWOFkfKRWu6niB7hwfgnwIpO4jTC75ozW1PHWg==", + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.18.0.tgz", + "integrity": "sha512-cDF0/Gf81QpY3xYyJKDV14Zwdmid5+uuENhjH2EqFaF0ni+yAyq/LzMaIJdhNJXZI7uLzwIlA+V7oWoyn6Curg==", "dependencies": { - "@typescript-eslint/types": "7.16.1", + "@typescript-eslint/types": "7.18.0", "eslint-visitor-keys": "^3.4.3" }, "engines": { @@ -10120,55 +10148,55 @@ "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==" }, "node_modules/@vue/compiler-core": { - "version": "3.4.33", - "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.4.33.tgz", - "integrity": "sha512-MoIREbkdPQlnGfSKDMgzTqzqx5nmEjIc0ydLVYlTACGBsfvOJ4tHSbZXKVF536n6fB+0eZaGEOqsGThPpdvF5A==", + "version": "3.4.37", + "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.4.37.tgz", + "integrity": "sha512-ZDDT/KiLKuCRXyzWecNzC5vTcubGz4LECAtfGPENpo0nrmqJHwuWtRLxk/Sb9RAKtR9iFflFycbkjkY+W/PZUQ==", "dependencies": { "@babel/parser": "^7.24.7", - "@vue/shared": "3.4.33", - "entities": "^4.5.0", + "@vue/shared": "3.4.37", + "entities": "^5.0.0", "estree-walker": "^2.0.2", "source-map-js": "^1.2.0" } }, "node_modules/@vue/compiler-dom": { - "version": "3.4.33", - "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.4.33.tgz", - "integrity": "sha512-GzB8fxEHKw0gGet5BKlpfXEqoBnzSVWwMnT+dc25wE7pFEfrU/QsvjZMP9rD4iVXHBBoemTct8mN0GJEI6ZX5A==", + "version": "3.4.37", + "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.4.37.tgz", + "integrity": "sha512-rIiSmL3YrntvgYV84rekAtU/xfogMUJIclUMeIKEtVBFngOL3IeZHhsH3UaFEgB5iFGpj6IW+8YuM/2Up+vVag==", "dependencies": { - "@vue/compiler-core": "3.4.33", - "@vue/shared": "3.4.33" + "@vue/compiler-core": "3.4.37", + "@vue/shared": "3.4.37" } }, "node_modules/@vue/compiler-sfc": { - "version": "3.4.33", - "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.4.33.tgz", - "integrity": "sha512-7rk7Vbkn21xMwIUpHQR4hCVejwE6nvhBOiDgoBcR03qvGqRKA7dCBSsHZhwhYUsmjlbJ7OtD5UFIyhP6BY+c8A==", + "version": "3.4.37", + "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.4.37.tgz", + "integrity": "sha512-vCfetdas40Wk9aK/WWf8XcVESffsbNkBQwS5t13Y/PcfqKfIwJX2gF+82th6dOpnpbptNMlMjAny80li7TaCIg==", "dependencies": { "@babel/parser": "^7.24.7", - "@vue/compiler-core": "3.4.33", - "@vue/compiler-dom": "3.4.33", - "@vue/compiler-ssr": "3.4.33", - "@vue/shared": "3.4.33", + "@vue/compiler-core": "3.4.37", + "@vue/compiler-dom": "3.4.37", + "@vue/compiler-ssr": "3.4.37", + "@vue/shared": "3.4.37", "estree-walker": "^2.0.2", "magic-string": "^0.30.10", - "postcss": "^8.4.39", + "postcss": "^8.4.40", "source-map-js": "^1.2.0" } }, "node_modules/@vue/compiler-ssr": { - "version": "3.4.33", - "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.4.33.tgz", - "integrity": "sha512-0WveC9Ai+eT/1b6LCV5IfsufBZ0HP7pSSTdDjcuW302tTEgoBw8rHVHKPbGUtzGReUFCRXbv6zQDDgucnV2WzQ==", + "version": "3.4.37", + "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.4.37.tgz", + "integrity": "sha512-TyAgYBWrHlFrt4qpdACh8e9Ms6C/AZQ6A6xLJaWrCL8GCX5DxMzxyeFAEMfU/VFr4tylHm+a2NpfJpcd7+20XA==", "dependencies": { - "@vue/compiler-dom": "3.4.33", - "@vue/shared": "3.4.33" + "@vue/compiler-dom": "3.4.37", + "@vue/shared": "3.4.37" } }, "node_modules/@vue/shared": { - "version": "3.4.33", - "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.4.33.tgz", - "integrity": "sha512-aoRY0jQk3A/cuvdkodTrM4NMfxco8n55eG4H7ML/CRy7OryHfiqvug4xrCBBMbbN+dvXAetDDwZW9DXWWjBntA==" + "version": "3.4.37", + "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.4.37.tgz", + "integrity": "sha512-nIh8P2fc3DflG8+5Uw8PT/1i17ccFn0xxN/5oE9RfV5SVnd7G0XEFRwakrnNFE/jlS95fpGXDVG5zDETS26nmg==" }, "node_modules/@webassemblyjs/ast": { "version": "1.12.1", @@ -10439,9 +10467,9 @@ } }, "node_modules/adm-zip": { - "version": "0.5.14", - "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.5.14.tgz", - "integrity": "sha512-DnyqqifT4Jrcvb8USYjp6FHtBpEIz1mnXu6pTRHZ0RL69LbQYiO+0lDFg5+OKA7U29oWSs3a/i8fhn8ZcceIWg==", + "version": "0.5.15", + "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.5.15.tgz", + "integrity": "sha512-jYPWSeOA8EFoZnucrKCNihqBjoEGQSU4HKgHYQgKNEQ0pQF9a/DYuo/+fAxY76k4qe75LUlLWpAM1QWcBMTOKw==", "engines": { "node": ">=12.0" } @@ -11049,23 +11077,23 @@ } }, "node_modules/aws4": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.13.0.tgz", - "integrity": "sha512-3AungXC4I8kKsS9PuS4JH2nc+0bVY/mjgrephHTIi8fpEeGsTHBUJeosp0Wc1myYMElmD0B3Oc4XL/HVJ4PV2g==" + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.13.1.tgz", + "integrity": "sha512-u5w79Rd7SU4JaIlA/zFqG+gOiuq25q5VLyZ8E+ijJeILuTxVzZgp2CaGw/UTw6pXYN9XMO9yiqj/nEHmhTG5CA==" }, "node_modules/axe-core": { - "version": "4.9.1", - "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.9.1.tgz", - "integrity": "sha512-QbUdXJVTpvUTHU7871ppZkdOLBeGUKBQWHkHrvN2V9IQWGMt61zf3B45BtzjxEJzYuj0JBjBZP/hmYS/R9pmAw==", + "version": "4.10.0", + "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.10.0.tgz", + "integrity": "sha512-Mr2ZakwQ7XUAjp7pAwQWRhhK8mQQ6JAaNWSjmjxil0R8BPioMtQsTLOolGYkji1rcL++3dCqZA3zWqpT+9Ew6g==", "dev": true, "engines": { "node": ">=4" } }, "node_modules/axios": { - "version": "1.7.2", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.2.tgz", - "integrity": "sha512-2A8QhOMrbomlDuiLeK9XibIBzuHeRcqqNOHp0Cyp5EoJ1IFDh+XZH3A6BkXtv0K4gFGCI0Y4BM7B1wOEi0Rmgw==", + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.3.tgz", + "integrity": "sha512-Ar7ND9pU99eJ9GpoGQKhKf58GpUOgnzuaB7ueNQ5BMi0p+LZ5oaEnfF999fAArcTIBwXTCHAmGcHOZJaWPq9Nw==", "dependencies": { "follow-redirects": "^1.15.6", "form-data": "^4.0.0", @@ -11203,12 +11231,12 @@ } }, "node_modules/babel-plugin-polyfill-corejs3": { - "version": "0.10.4", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.10.4.tgz", - "integrity": "sha512-25J6I8NGfa5YkCDogHRID3fVCadIR8/pGl1/spvCkzb6lVn6SR3ojpx9nOn9iEBcUsjY24AmdKm5khcfKdylcg==", + "version": "0.10.6", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.10.6.tgz", + "integrity": "sha512-b37+KR2i/khY5sKmWNVQAnitvquQbNdWy6lJdsr0kmquCKEEUgMKK4SboVM3HtfnZilfjr4MMQ7vY58FVWDtIA==", "dependencies": { - "@babel/helper-define-polyfill-provider": "^0.6.1", - "core-js-compat": "^3.36.1" + "@babel/helper-define-polyfill-provider": "^0.6.2", + "core-js-compat": "^3.38.0" }, "peerDependencies": { "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" @@ -14655,9 +14683,9 @@ "dev": true }, "node_modules/browserslist": { - "version": "4.23.2", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.2.tgz", - "integrity": "sha512-qkqSyistMYdxAcw+CzbZwlBy8AGmS/eEWs+sEV5TnLRGDOL+C5M2EnH6tlZyg0YoAxGJAFKh61En9BR941GnHA==", + "version": "4.23.3", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.3.tgz", + "integrity": "sha512-btwCFJVjI4YWDNfau8RhZ+B1Q/VLoUITrm3RlP6y1tYGWIOa+InuYiRGXUBXo8nA1qKmHMyLB/iVQg5TT4eFoA==", "funding": [ { "type": "opencollective", @@ -14673,9 +14701,9 @@ } ], "dependencies": { - "caniuse-lite": "^1.0.30001640", - "electron-to-chromium": "^1.4.820", - "node-releases": "^2.0.14", + "caniuse-lite": "^1.0.30001646", + "electron-to-chromium": "^1.5.4", + "node-releases": "^2.0.18", "update-browserslist-db": "^1.1.0" }, "bin": { @@ -14823,32 +14851,6 @@ "node": ">=18" } }, - "node_modules/cacheable-request/node_modules/get-stream": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-9.0.1.tgz", - "integrity": "sha512-kVCxPF3vQM/N0B1PmoqVUqgHP+EeVjmZSQn+1oCRPxd2P21P2F19lIgbR3HBosbB1PUhOAoctJnfEn2GbN2eZA==", - "dependencies": { - "@sec-ant/readable-stream": "^0.4.1", - "is-stream": "^4.0.1" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/cacheable-request/node_modules/is-stream": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-4.0.1.tgz", - "integrity": "sha512-Dnz92NInDqYckGEUJv689RbRiTSEHCQ7wOVeALbkOz999YpqT46yMRIGtSNl2iCL1waAZSx40+h59NV/EwzV/A==", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/call-bind": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", @@ -14912,9 +14914,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001643", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001643.tgz", - "integrity": "sha512-ERgWGNleEilSrHM6iUz/zJNSQTP8Mr21wDWpdgvRwcTXGAq6jMtOUPP4dqFPTdKqZ2wKTdtB+uucZ3MRpAUSmg==", + "version": "1.0.30001651", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001651.tgz", + "integrity": "sha512-9Cf+Xv1jJNe1xPZLGuUXLNkE1BoDkqRqYyFJ9TDYSqhduqA4hu4oR9HluGoWYQC/aj8WHjsGVV+bwkh0+tegRg==", "funding": [ { "type": "opencollective", @@ -15750,9 +15752,9 @@ } }, "node_modules/core-js": { - "version": "3.37.1", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.37.1.tgz", - "integrity": "sha512-Xn6qmxrQZyB0FFY8E3bgRXei3lWDJHhvI+u0q9TKIYM49G8pAr0FgnnrFRAmsbptZL1yxRADVXn+x5AGsbBfyw==", + "version": "3.38.0", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.38.0.tgz", + "integrity": "sha512-XPpwqEodRljce9KswjZShh95qJ1URisBeKCjUdq27YdenkslVe7OO0ZJhlYXAChW7OhXaRLl8AAba7IBfoIHug==", "hasInstallScript": true, "funding": { "type": "opencollective", @@ -15760,11 +15762,11 @@ } }, "node_modules/core-js-compat": { - "version": "3.37.1", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.37.1.tgz", - "integrity": "sha512-9TNiImhKvQqSUkOvk/mMRZzOANTiEVC7WaBNhHcKM7x+/5E1l5NvsysR19zuDQScE8k+kfQXWRN3AtS/eOSHpg==", + "version": "3.38.0", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.38.0.tgz", + "integrity": "sha512-75LAicdLa4OJVwFxFbQR3NdnZjNgX6ILpVcVzcC4T2smerB5lELMrJQQQoWV6TiuC/vlaFqgU2tKQx9w5s0e0A==", "dependencies": { - "browserslist": "^4.23.0" + "browserslist": "^4.23.3" }, "funding": { "type": "opencollective", @@ -15772,9 +15774,9 @@ } }, "node_modules/core-js-pure": { - "version": "3.37.1", - "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.37.1.tgz", - "integrity": "sha512-J/r5JTHSmzTxbiYYrzXg9w1VpqrYt+gexenBE9pugeyhwPZTAEJddyiReJWsLO6uNQ8xJZFbod6XC7KKwatCiA==", + "version": "3.38.0", + "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.38.0.tgz", + "integrity": "sha512-8balb/HAXo06aHP58mZMtXgD8vcnXz9tUDePgqBgJgKdmTlMt+jw3ujqniuBDQXMvTzxnMpxHFeuSM3g1jWQuQ==", "hasInstallScript": true, "funding": { "type": "opencollective", @@ -16080,9 +16082,9 @@ } }, "node_modules/csv-stringify": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/csv-stringify/-/csv-stringify-6.5.0.tgz", - "integrity": "sha512-edlXFVKcUx7r8Vx5zQucsuMg4wb/xT6qyz+Sr1vnLrdXqlLD1+UKyWNyZ9zn6mUW1ewmGxrpVwAcChGF0HQ/2Q==" + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/csv-stringify/-/csv-stringify-6.5.1.tgz", + "integrity": "sha512-+9lpZfwpLntpTIEpFbwQyWuW/hmI/eHuJZD1XzeZpfZTqkf1fyvBbBLXTJJMsBuuS11uTShMqPwzx4A6ffXgRQ==" }, "node_modules/csvtojson": { "version": "2.0.10", @@ -16106,9 +16108,9 @@ "integrity": "sha512-GAj5FOq0Hd+RsCGVJxZuKaIDXDf3h6GQoNEjFgbLLI/trgtavwUbSnZ5pVfg27DVCaWjIohryS0JFwIJyT2cMg==" }, "node_modules/cytoscape": { - "version": "3.30.1", - "resolved": "https://registry.npmjs.org/cytoscape/-/cytoscape-3.30.1.tgz", - "integrity": "sha512-TRJc3HbBPkHd50u9YfJh2FxD1lDLZ+JXnJoyBn5LkncoeuT7fapO/Hq/Ed8TdFclaKshzInge2i30bg7VKeoPQ==", + "version": "3.30.2", + "resolved": "https://registry.npmjs.org/cytoscape/-/cytoscape-3.30.2.tgz", + "integrity": "sha512-oICxQsjW8uSaRmn4UK/jkczKOqTrVqt5/1WL0POiJUT2EKNc9STM4hYFHv917yu55aTBMFNRzymlJhVAiWPCxw==", "engines": { "node": ">=0.10" } @@ -16677,9 +16679,9 @@ "integrity": "sha512-Rt2g+nTbLlDWZTwwrIXjy9MeiZmSDI375FvZs72ngxx8PDC6YXOeR3q5LAuPzjZQxhiWdRKac7RKV+YyQYfYIg==" }, "node_modules/debug": { - "version": "4.3.5", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", - "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.6.tgz", + "integrity": "sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg==", "dependencies": { "ms": "2.1.2" }, @@ -17143,6 +17145,17 @@ "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" } }, + "node_modules/dom-serializer/node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, "node_modules/dom-walk": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/dom-walk/-/dom-walk-0.1.2.tgz", @@ -17258,9 +17271,9 @@ "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" }, "node_modules/electron-to-chromium": { - "version": "1.4.832", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.832.tgz", - "integrity": "sha512-cTen3SB0H2SGU7x467NRe1eVcQgcuS6jckKfWJHia2eo0cHIGOqHoAxevIYZD4eRHcWjkvFzo93bi3vJ9W+1lA==" + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.5.tgz", + "integrity": "sha512-QR7/A7ZkMS8tZuoftC/jfqNkZLQO779SSW3YuZHP4eXpj3EffGLFcB/Xu9AAZQzLccTiCV+EmUo3ha4mQ9wnlA==" }, "node_modules/elkjs": { "version": "0.9.3", @@ -17369,9 +17382,9 @@ } }, "node_modules/enhanced-resolve": { - "version": "5.17.0", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.17.0.tgz", - "integrity": "sha512-dwDPwZL0dmye8Txp2gzFmA6sxALaSvdRDjPH0viLcKrtlOL3tw62nWWweVD1SdILDTJrbrL6tdWVN58Wo6U3eA==", + "version": "5.17.1", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.17.1.tgz", + "integrity": "sha512-LMHl3dXhTcfv8gM4kEzIUeTQ+7fpdA0l2tUf34BddXPkz2A5xJ5L/Pchd5BL6rdccM9QGvu0sWZzK1Z1t4wwyg==", "dependencies": { "graceful-fs": "^4.2.4", "tapable": "^2.2.0" @@ -17381,9 +17394,9 @@ } }, "node_modules/entities": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", - "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-5.0.0.tgz", + "integrity": "sha512-BeJFvFRJddxobhvEdm5GqHzRV/X+ACeuw0/BuuxsCh1EUZcAIz8+kYmBp/LrQuloy6K1f3a0M7+IhmZ7QnkISA==", "engines": { "node": ">=0.12" }, @@ -19634,9 +19647,9 @@ "integrity": "sha512-MWipKbbYiYI0UC7cl8m/i/IWTqfC8YXsqjzybjddLsFjStroQzsHXkc73JutMvBiXmOvapk+axIl79ig5t55Bw==" }, "node_modules/fast-xml-parser": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.4.0.tgz", - "integrity": "sha512-kLY3jFlwIYwBNDojclKsNAC12sfD6NwW74QB2CoNGPvtVxjliYehVunB3HYyNi+n4Tt1dAcgwYvmKF/Z18flqg==", + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.4.1.tgz", + "integrity": "sha512-xkjOecfnKGkSsOwtZ5Pz7Us/T6mrbPQrq0nh+aCO5V9nk5NLWmasAHumTKjiPJPWANe+kAZ84Jc8ooJkzZ88Sw==", "funding": [ { "type": "github", @@ -20082,9 +20095,9 @@ } }, "node_modules/foreground-child": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.2.1.tgz", - "integrity": "sha512-PXUUyLqrR2XCWICfv6ukppP96sdFwWbNEnfEMt7jNsISjMsvaLNinAHNDYyvkyU+SZG2BTSbT5NjG+vZslfGTA==", + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.0.tgz", + "integrity": "sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==", "dependencies": { "cross-spawn": "^7.0.0", "signal-exit": "^4.0.1" @@ -20699,11 +20712,26 @@ } }, "node_modules/get-stream": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-8.0.1.tgz", - "integrity": "sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==", + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-9.0.1.tgz", + "integrity": "sha512-kVCxPF3vQM/N0B1PmoqVUqgHP+EeVjmZSQn+1oCRPxd2P21P2F19lIgbR3HBosbB1PUhOAoctJnfEn2GbN2eZA==", + "dependencies": { + "@sec-ant/readable-stream": "^0.4.1", + "is-stream": "^4.0.1" + }, "engines": { - "node": ">=16" + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/get-stream/node_modules/is-stream": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-4.0.1.tgz", + "integrity": "sha512-Dnz92NInDqYckGEUJv689RbRiTSEHCQ7wOVeALbkOz999YpqT46yMRIGtSNl2iCL1waAZSx40+h59NV/EwzV/A==", + "engines": { + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -20852,9 +20880,9 @@ } }, "node_modules/globals": { - "version": "15.8.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-15.8.0.tgz", - "integrity": "sha512-VZAJ4cewHTExBWDHR6yptdIBlx9YSSZuwojj9Nt5mBRXQzrKakDsVKQ1J63sklLvzAJm0X5+RpO4i3Y2hcOnFw==", + "version": "15.9.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-15.9.0.tgz", + "integrity": "sha512-SmSKyLLKFbSr6rptvP8izbyxJL4ILwqO9Jg23UA0sDlGlu58V59D1//I3vlc0KJphVdUR7vMjHIplYnzBxorQA==", "dev": true, "engines": { "node": ">=18" @@ -20904,9 +20932,9 @@ "integrity": "sha512-sIVQCiRWOymHbVD1Aw/T9/ijbPYAVGBlgGYd1N9MRKfcyBNSpjr87Vg9nSHm+RCT8ELrvK8IJYJV0QRJuVUkCQ==" }, "node_modules/google-auth-library": { - "version": "9.11.0", - "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-9.11.0.tgz", - "integrity": "sha512-epX3ww/mNnhl6tL45EQ/oixsY8JLEgUFoT4A5E/5iAR4esld9Kqv6IJGk7EmGuOgDvaarwF95hU2+v7Irql9lw==", + "version": "9.13.0", + "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-9.13.0.tgz", + "integrity": "sha512-p9Y03Uzp/Igcs36zAaB0XTSwZ8Y0/tpYiz5KIde5By+H9DCVUSYtDWZu6aFXsWTqENMb8BD/pDT3hR8NVrPkfA==", "dependencies": { "base64-js": "^1.3.0", "ecdsa-sig-formatter": "^1.0.11", @@ -20996,17 +21024,16 @@ } }, "node_modules/got": { - "version": "14.4.1", - "resolved": "https://registry.npmjs.org/got/-/got-14.4.1.tgz", - "integrity": "sha512-IvDJbJBUeexX74xNQuMIVgCRRuNOm5wuK+OC3Dc2pnSoh1AOmgc7JVj7WC+cJ4u0aPcO9KZ2frTXcqK4W/5qTQ==", + "version": "14.4.2", + "resolved": "https://registry.npmjs.org/got/-/got-14.4.2.tgz", + "integrity": "sha512-+Te/qEZ6hr7i+f0FNgXx/6WQteSM/QqueGvxeYQQFm0GDfoxLVJ/oiwUKYMTeioColWUTdewZ06hmrBjw6F7tw==", "dependencies": { - "@sindresorhus/is": "^6.3.1", + "@sindresorhus/is": "^7.0.0", "@szmarczak/http-timer": "^5.0.1", "cacheable-lookup": "^7.0.0", "cacheable-request": "^12.0.1", "decompress-response": "^6.0.0", "form-data-encoder": "^4.0.2", - "get-stream": "^8.0.1", "http2-wrapper": "^2.2.1", "lowercase-keys": "^3.0.0", "p-cancelable": "^4.0.1", @@ -21609,6 +21636,17 @@ "entities": "^4.4.0" } }, + "node_modules/htmlparser2/node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, "node_modules/http-browserify": { "version": "1.7.0", "resolved": "https://registry.npmjs.org/http-browserify/-/http-browserify-1.7.0.tgz", @@ -23763,9 +23801,9 @@ } }, "node_modules/launch-editor": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/launch-editor/-/launch-editor-2.8.0.tgz", - "integrity": "sha512-vJranOAJrI/llyWGRQqiDM+adrw+k83fvmmx3+nV47g3+36xM15jE+zyZ6Ffel02+xSvuM0b2GDRosXZkbb6wA==", + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/launch-editor/-/launch-editor-2.8.1.tgz", + "integrity": "sha512-elBx2l/tp9z99X5H/qev8uyDywVh0VXAwEbjk8kJhnc5grOFkGh7aW6q55me9xnYbss261XtnUrysZ+XvGbhQA==", "dev": true, "dependencies": { "picocolors": "^1.0.0", @@ -24094,11 +24132,11 @@ } }, "node_modules/magic-string": { - "version": "0.30.10", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.10.tgz", - "integrity": "sha512-iIRwTIf0QKV3UAnYK4PU8uiEc4SRh5jX0mwpIwETPpHdhVM4f53RSwS/vXvN1JhGX+Cs7B8qIq3d6AH49O5fAQ==", + "version": "0.30.11", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.11.tgz", + "integrity": "sha512-+Wri9p0QHMy+545hKww7YAu5NyzF8iomPL/RQazugQ9+Ez4Ic3mERMd8ZTX5rfK944j+560ZJi8iAwgak1Ac7A==", "dependencies": { - "@jridgewell/sourcemap-codec": "^1.4.15" + "@jridgewell/sourcemap-codec": "^1.5.0" } }, "node_modules/magicli": { @@ -24264,6 +24302,17 @@ "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" }, + "node_modules/markdown-it/node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, "node_modules/markdown-table": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-3.0.3.tgz", @@ -31094,9 +31143,9 @@ } }, "node_modules/mongoose": { - "version": "8.5.1", - "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-8.5.1.tgz", - "integrity": "sha512-OhVcwVl91A1G6+XpjDcpkGP7l7ikZkxa0DylX7NT/lcEqAjggzSdqDxb48A+xsDxqNAr0ntSJ1yiE3+KJTOd5Q==", + "version": "8.5.2", + "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-8.5.2.tgz", + "integrity": "sha512-GZB4rHMdYfGatV+23IpCrqFbyCOjCNOHXgWbirr92KRwTEncBrtW3kgU9vmpKjsGf7nMmnAy06SwWUv1vhDkSg==", "dependencies": { "bson": "^6.7.0", "kareem": "2.6.3", @@ -34216,9 +34265,9 @@ } }, "node_modules/openai": { - "version": "4.52.7", - "resolved": "https://registry.npmjs.org/openai/-/openai-4.52.7.tgz", - "integrity": "sha512-dgxA6UZHary6NXUHEDj5TWt8ogv0+ibH+b4pT5RrWMjiRZVylNwLcw/2ubDrX5n0oUmHX/ZgudMJeemxzOvz7A==", + "version": "4.55.1", + "resolved": "https://registry.npmjs.org/openai/-/openai-4.55.1.tgz", + "integrity": "sha512-FziYJcWl+SAGbt5AcRIzVzNcnKohpEMQdtzVOmHFbBp/if7x2+ACqgxF2XUbyi2PcKONPcVpmtG5h9qoDAEXwQ==", "dependencies": { "@types/node": "^18.11.18", "@types/node-fetch": "^2.6.4", @@ -34226,17 +34275,24 @@ "agentkeepalive": "^4.2.1", "form-data-encoder": "1.7.2", "formdata-node": "^4.3.2", - "node-fetch": "^2.6.7", - "web-streams-polyfill": "^3.2.1" + "node-fetch": "^2.6.7" }, "bin": { "openai": "bin/cli" + }, + "peerDependencies": { + "zod": "^3.23.8" + }, + "peerDependenciesMeta": { + "zod": { + "optional": true + } } }, "node_modules/openai/node_modules/@types/node": { - "version": "18.19.41", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.41.tgz", - "integrity": "sha512-LX84pRJ+evD2e2nrgYCHObGWkiQJ1mL+meAgbvnwk/US6vmMY7S2ygBTGV2Jw91s9vUsLSXeDEkUHZIJGLrhsg==", + "version": "18.19.43", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.43.tgz", + "integrity": "sha512-Mw/YlgXnyJdEwLoFv2dpuJaDFriX+Pc+0qOBJ57jC1H6cDxIj2xc5yUrdtArDVG0m+KV6622a4p2tenEqB3C/g==", "dependencies": { "undici-types": "~5.26.4" } @@ -34486,6 +34542,17 @@ "url": "https://github.com/inikulin/parse5?sponsor=1" } }, + "node_modules/parse5/node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, "node_modules/parseley": { "version": "0.12.1", "resolved": "https://registry.npmjs.org/parseley/-/parseley-0.12.1.tgz", @@ -34720,15 +34787,15 @@ } }, "node_modules/pdfjs-dist": { - "version": "4.4.168", - "resolved": "https://registry.npmjs.org/pdfjs-dist/-/pdfjs-dist-4.4.168.tgz", - "integrity": "sha512-MbkAjpwka/dMHaCfQ75RY1FXX3IewBVu6NGZOcxerRFlaBiIkZmUoR0jotX5VUzYZEXAGzSFtknWs5xRKliXPA==", + "version": "4.5.136", + "resolved": "https://registry.npmjs.org/pdfjs-dist/-/pdfjs-dist-4.5.136.tgz", + "integrity": "sha512-V1BALcAN/FmxBEShLxoP73PlQZAZtzlaNfRbRhJrKvXzjLC5VaIlBAQUJuWP8iaYUmIdmdLHmt3E2TBglxOm3w==", "engines": { "node": ">=18" }, "optionalDependencies": { "canvas": "^2.11.2", - "path2d": "^0.2.0" + "path2d": "^0.2.1" } }, "node_modules/pdfjs/node_modules/pako": { @@ -34961,9 +35028,9 @@ } }, "node_modules/postcss": { - "version": "8.4.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.39.tgz", - "integrity": "sha512-0vzE+lAiG7hZl1/9I8yzKLx3aR9Xbof3fBHKunvMfOCYAtMhrsnccJY2iTURb9EZd5+pLuiNV9/c/GZJOHsgIw==", + "version": "8.4.41", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.41.tgz", + "integrity": "sha512-TesUflQ0WKZqAvg52PWL6kHgLKP6xB6heTOdoYM0Wt2UHyxNa4K25EZZMgKns3BH1RLVbZCREPpLY0rhnNoHVQ==", "funding": [ { "type": "opencollective", @@ -35189,9 +35256,9 @@ "peer": true }, "node_modules/prosemirror-commands": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/prosemirror-commands/-/prosemirror-commands-1.5.2.tgz", - "integrity": "sha512-hgLcPaakxH8tu6YvVAaILV2tXYsW3rAdDR8WNkeKGcgeMVQg3/TMhPdVoh7iAmfgVjZGtcOSjKiQaoeKjzd2mQ==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/prosemirror-commands/-/prosemirror-commands-1.6.0.tgz", + "integrity": "sha512-xn1U/g36OqXn2tn5nGmvnnimAj/g1pUx2ypJJIe8WkVX83WyJVC5LTARaxZa2AtQRwntu9Jc5zXs9gL9svp/mg==", "dependencies": { "prosemirror-model": "^1.0.0", "prosemirror-state": "^1.0.0", @@ -35236,9 +35303,9 @@ } }, "node_modules/prosemirror-model": { - "version": "1.22.2", - "resolved": "https://registry.npmjs.org/prosemirror-model/-/prosemirror-model-1.22.2.tgz", - "integrity": "sha512-I4lS7HHIW47D0Xv/gWmi4iUWcQIDYaJKd8Hk4+lcSps+553FlQrhmxtItpEvTr75iAruhzVShVp6WUwsT6Boww==", + "version": "1.22.3", + "resolved": "https://registry.npmjs.org/prosemirror-model/-/prosemirror-model-1.22.3.tgz", + "integrity": "sha512-V4XCysitErI+i0rKFILGt/xClnFJaohe/wrrlT2NSZ+zk8ggQfDH4x2wNK7Gm0Hp4CIoWizvXFP7L9KMaCuI0Q==", "dependencies": { "orderedmap": "^2.0.0" } @@ -35669,85 +35736,90 @@ } }, "node_modules/react-aria": { - "version": "3.33.1", - "resolved": "https://registry.npmjs.org/react-aria/-/react-aria-3.33.1.tgz", - "integrity": "sha512-hFC3K/UA+90Krlx2IgRTgzFbC6FSPi4pUwHT+STperPLK+cTEHkI+3Lu0YYwQSBatkgxnIv9+GtFuVbps2kROw==", + "version": "3.34.1", + "resolved": "https://registry.npmjs.org/react-aria/-/react-aria-3.34.1.tgz", + "integrity": "sha512-vA4BP+SWjFFRfOTQcNJtIp9gKlxuC7kPUXQK9fuNA+2K4mJdIc9mBnmwXQiLl/eAthMf43fD4fETfY9SiCm1Zg==", "dependencies": { "@internationalized/string": "^3.2.3", - "@react-aria/breadcrumbs": "^3.5.13", - "@react-aria/button": "^3.9.5", - "@react-aria/calendar": "^3.5.8", - "@react-aria/checkbox": "^3.14.3", - "@react-aria/combobox": "^3.9.1", - "@react-aria/datepicker": "^3.10.1", - "@react-aria/dialog": "^3.5.14", - "@react-aria/dnd": "^3.6.1", - "@react-aria/focus": "^3.17.1", - "@react-aria/gridlist": "^3.8.1", - "@react-aria/i18n": "^3.11.1", - "@react-aria/interactions": "^3.21.3", - "@react-aria/label": "^3.7.8", - "@react-aria/link": "^3.7.1", - "@react-aria/listbox": "^3.12.1", - "@react-aria/menu": "^3.14.1", - "@react-aria/meter": "^3.4.13", - "@react-aria/numberfield": "^3.11.3", - "@react-aria/overlays": "^3.22.1", - "@react-aria/progress": "^3.4.13", - "@react-aria/radio": "^3.10.4", - "@react-aria/searchfield": "^3.7.5", - "@react-aria/select": "^3.14.5", - "@react-aria/selection": "^3.18.1", - "@react-aria/separator": "^3.3.13", - "@react-aria/slider": "^3.7.8", - "@react-aria/ssr": "^3.9.4", - "@react-aria/switch": "^3.6.4", - "@react-aria/table": "^3.14.1", - "@react-aria/tabs": "^3.9.1", - "@react-aria/tag": "^3.4.1", - "@react-aria/textfield": "^3.14.5", - "@react-aria/tooltip": "^3.7.4", - "@react-aria/utils": "^3.24.1", - "@react-aria/visually-hidden": "^3.8.12", - "@react-types/shared": "^3.23.1" - }, - "peerDependencies": { - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0", - "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + "@react-aria/breadcrumbs": "^3.5.15", + "@react-aria/button": "^3.9.7", + "@react-aria/calendar": "^3.5.10", + "@react-aria/checkbox": "^3.14.5", + "@react-aria/combobox": "^3.10.1", + "@react-aria/datepicker": "^3.11.1", + "@react-aria/dialog": "^3.5.16", + "@react-aria/dnd": "^3.7.1", + "@react-aria/focus": "^3.18.1", + "@react-aria/gridlist": "^3.9.1", + "@react-aria/i18n": "^3.12.1", + "@react-aria/interactions": "^3.22.1", + "@react-aria/label": "^3.7.10", + "@react-aria/link": "^3.7.3", + "@react-aria/listbox": "^3.13.1", + "@react-aria/menu": "^3.15.1", + "@react-aria/meter": "^3.4.15", + "@react-aria/numberfield": "^3.11.5", + "@react-aria/overlays": "^3.23.1", + "@react-aria/progress": "^3.4.15", + "@react-aria/radio": "^3.10.6", + "@react-aria/searchfield": "^3.7.7", + "@react-aria/select": "^3.14.7", + "@react-aria/selection": "^3.19.1", + "@react-aria/separator": "^3.4.1", + "@react-aria/slider": "^3.7.10", + "@react-aria/ssr": "^3.9.5", + "@react-aria/switch": "^3.6.6", + "@react-aria/table": "^3.15.1", + "@react-aria/tabs": "^3.9.3", + "@react-aria/tag": "^3.4.3", + "@react-aria/textfield": "^3.14.7", + "@react-aria/tooltip": "^3.7.6", + "@react-aria/utils": "^3.25.1", + "@react-aria/visually-hidden": "^3.8.14", + "@react-types/shared": "^3.24.1" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0", + "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" } }, "node_modules/react-aria-components": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/react-aria-components/-/react-aria-components-1.2.1.tgz", - "integrity": "sha512-iGIdDjbTyLLn0/tGUyBQxxu+E1bw4/H4AU89d0cRcu8yIdw6MXG29YElmRHn0ugiyrERrk/YQALihstnns5kRQ==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/react-aria-components/-/react-aria-components-1.3.1.tgz", + "integrity": "sha512-yUTA8uHbioQHU5d7iNvSLZLEfQlcTAmyhhkY+NMc8pIGPdtf0qnrlF0nPtJq8Mro5irpVrgUlqKBvvCiKwFNiQ==", "dependencies": { - "@internationalized/date": "^3.5.4", + "@internationalized/date": "^3.5.5", "@internationalized/string": "^3.2.3", - "@react-aria/color": "3.0.0-beta.33", - "@react-aria/focus": "^3.17.1", - "@react-aria/interactions": "^3.21.3", - "@react-aria/menu": "^3.14.1", - "@react-aria/toolbar": "3.0.0-beta.5", - "@react-aria/tree": "3.0.0-alpha.1", - "@react-aria/utils": "^3.24.1", - "@react-stately/color": "^3.6.1", - "@react-stately/menu": "^3.7.1", - "@react-stately/table": "^3.11.8", - "@react-stately/utils": "^3.10.1", - "@react-types/color": "3.0.0-beta.25", - "@react-types/form": "^3.7.4", - "@react-types/grid": "^3.2.6", - "@react-types/shared": "^3.23.1", - "@react-types/table": "^3.9.5", + "@react-aria/collections": "3.0.0-alpha.3", + "@react-aria/color": "3.0.0-rc.1", + "@react-aria/dnd": "^3.7.1", + "@react-aria/focus": "^3.18.1", + "@react-aria/interactions": "^3.22.1", + "@react-aria/menu": "^3.15.1", + "@react-aria/toolbar": "3.0.0-beta.7", + "@react-aria/tree": "3.0.0-alpha.3", + "@react-aria/utils": "^3.25.1", + "@react-aria/virtualizer": "^4.0.1", + "@react-stately/color": "^3.7.1", + "@react-stately/layout": "^4.0.1", + "@react-stately/menu": "^3.8.1", + "@react-stately/table": "^3.12.1", + "@react-stately/utils": "^3.10.2", + "@react-stately/virtualizer": "^4.0.1", + "@react-types/color": "3.0.0-rc.1", + "@react-types/form": "^3.7.6", + "@react-types/grid": "^3.2.8", + "@react-types/shared": "^3.24.1", + "@react-types/table": "^3.10.1", "@swc/helpers": "^0.5.0", "client-only": "^0.0.1", - "react-aria": "^3.33.1", - "react-stately": "^3.31.1", + "react-aria": "^3.34.1", + "react-stately": "^3.32.1", "use-sync-external-store": "^1.2.0" }, "peerDependencies": { - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0", - "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0", + "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" } }, "node_modules/react-autosuggest": { @@ -35766,9 +35838,9 @@ } }, "node_modules/react-awesome-reveal": { - "version": "4.2.12", - "resolved": "https://registry.npmjs.org/react-awesome-reveal/-/react-awesome-reveal-4.2.12.tgz", - "integrity": "sha512-cablqrGypakw34h+rMcn+CmDCMfS+n4MznL/0LBQpFksZ2FCRtKFWIYuKWWpY8lL2ttyBnWnMdlJJiuLHR99uA==", + "version": "4.2.14", + "resolved": "https://registry.npmjs.org/react-awesome-reveal/-/react-awesome-reveal-4.2.14.tgz", + "integrity": "sha512-wknbDl+z5MIhQFfKKSj3iBJzvssqJLP8LbxQjW9OCyXPGtMSYvOFKwjG4/2p1de+qh5gqb8WBMQIYS6wVN3tNw==", "funding": [ { "type": "github", @@ -35780,7 +35852,7 @@ } ], "dependencies": { - "react-intersection-observer": "^9.10.3", + "react-intersection-observer": "^9.13.0", "react-is": "^18.3.1" }, "peerDependencies": { @@ -36100,36 +36172,36 @@ } }, "node_modules/react-stately": { - "version": "3.31.1", - "resolved": "https://registry.npmjs.org/react-stately/-/react-stately-3.31.1.tgz", - "integrity": "sha512-wuq673NHkYSdoceGryjtMJJvB9iQgyDkQDsnTN0t2v91pXjGDsN/EcOvnUrxXSBtY9eLdIw74R54z9GX5cJNEg==", - "dependencies": { - "@react-stately/calendar": "^3.5.1", - "@react-stately/checkbox": "^3.6.5", - "@react-stately/collections": "^3.10.7", - "@react-stately/combobox": "^3.8.4", - "@react-stately/data": "^3.11.4", - "@react-stately/datepicker": "^3.9.4", - "@react-stately/dnd": "^3.3.1", - "@react-stately/form": "^3.0.3", - "@react-stately/list": "^3.10.5", - "@react-stately/menu": "^3.7.1", - "@react-stately/numberfield": "^3.9.3", - "@react-stately/overlays": "^3.6.7", - "@react-stately/radio": "^3.10.4", - "@react-stately/searchfield": "^3.5.3", - "@react-stately/select": "^3.6.4", - "@react-stately/selection": "^3.15.1", - "@react-stately/slider": "^3.5.4", - "@react-stately/table": "^3.11.8", - "@react-stately/tabs": "^3.6.6", - "@react-stately/toggle": "^3.7.4", - "@react-stately/tooltip": "^3.4.9", - "@react-stately/tree": "^3.8.1", - "@react-types/shared": "^3.23.1" - }, - "peerDependencies": { - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + "version": "3.32.1", + "resolved": "https://registry.npmjs.org/react-stately/-/react-stately-3.32.1.tgz", + "integrity": "sha512-znw+bqHJk1fvv34O3HoVH61otyYJomRu1gI7A4B3UHCnSFS6E6nMI6D3nRv9RrAWhf4ekLLg35FwDTHDcG1zdg==", + "dependencies": { + "@react-stately/calendar": "^3.5.3", + "@react-stately/checkbox": "^3.6.7", + "@react-stately/collections": "^3.10.9", + "@react-stately/combobox": "^3.9.1", + "@react-stately/data": "^3.11.6", + "@react-stately/datepicker": "^3.10.1", + "@react-stately/dnd": "^3.4.1", + "@react-stately/form": "^3.0.5", + "@react-stately/list": "^3.10.7", + "@react-stately/menu": "^3.8.1", + "@react-stately/numberfield": "^3.9.5", + "@react-stately/overlays": "^3.6.9", + "@react-stately/radio": "^3.10.6", + "@react-stately/searchfield": "^3.5.5", + "@react-stately/select": "^3.6.6", + "@react-stately/selection": "^3.16.1", + "@react-stately/slider": "^3.5.6", + "@react-stately/table": "^3.12.1", + "@react-stately/tabs": "^3.6.8", + "@react-stately/toggle": "^3.7.6", + "@react-stately/tooltip": "^3.4.11", + "@react-stately/tree": "^3.8.3", + "@react-types/shared": "^3.24.1" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" } }, "node_modules/react-textarea-autosize": { @@ -39388,9 +39460,9 @@ "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" }, "node_modules/terser": { - "version": "5.31.3", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.31.3.tgz", - "integrity": "sha512-pAfYn3NIZLyZpa83ZKigvj6Rn9c/vd5KfYGX7cN1mnzqgDcxWvrU5ZtAfIKhEXz9nRecw4z3LXkjaq96/qZqAA==", + "version": "5.31.5", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.31.5.tgz", + "integrity": "sha512-YPmas0L0rE1UyLL/llTWA0SiDOqIcAQYLeUj7cJYzXHlRTAnMSg9pPe4VJ5PlKvTrPQsdVFuiRiwyeNlYgwh2Q==", "dependencies": { "@jridgewell/source-map": "^0.3.3", "acorn": "^8.8.2", @@ -40383,9 +40455,9 @@ } }, "node_modules/type-fest": { - "version": "4.23.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.23.0.tgz", - "integrity": "sha512-ZiBujro2ohr5+Z/hZWHESLz3g08BBdrdLMieYFULJO+tWc437sn8kQsWLJoZErY8alNhxre9K4p3GURAG11n+w==", + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.24.0.tgz", + "integrity": "sha512-spAaHzc6qre0TlZQQ2aA/nGMe+2Z/wyGk5Z+Ru2VUfdNwT6kWO6TjevOlpebsATEG1EIQ2sOiDszud3lO5mt/Q==", "engines": { "node": ">=16" }, @@ -40479,9 +40551,9 @@ } }, "node_modules/typescript": { - "version": "5.5.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.5.3.tgz", - "integrity": "sha512-/hreyEujaB0w76zKo6717l3L0o/qEUtRgdvUBvlkhoWeOVMjMuHNHk0BRBzikzuGDqNmPQbg5ifMEqsHLiIUcQ==", + "version": "5.5.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.5.4.tgz", + "integrity": "sha512-Mtq29sKDAEYP7aljRgtPOpTvOfbwRWlS6dPRzwjdE+C0R4brX/GUyhHSecbHMFLNBLcJIPt9nl9yG5TZ1weH+Q==", "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -40496,14 +40568,14 @@ "integrity": "sha512-7sI4e/bZijOzyURng88oOFZCISQPTHozfE2sUu5AviFYk5QV7fYGb6YiDl+vKjF/pICA354JImBImL9XJWUvdQ==" }, "node_modules/typescript-eslint": { - "version": "7.16.1", - "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-7.16.1.tgz", - "integrity": "sha512-889oE5qELj65q/tGeOSvlreNKhimitFwZqQ0o7PcWC7/lgRkAMknznsCsV8J8mZGTP/Z+cIbX8accf2DE33hrA==", + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-7.18.0.tgz", + "integrity": "sha512-PonBkP603E3tt05lDkbOMyaxJjvKqQrXsnow72sVeOFINDE/qNmnnd+f9b4N+U7W6MXnnYyrhtmF2t08QWwUbA==", "dev": true, "dependencies": { - "@typescript-eslint/eslint-plugin": "7.16.1", - "@typescript-eslint/parser": "7.16.1", - "@typescript-eslint/utils": "7.16.1" + "@typescript-eslint/eslint-plugin": "7.18.0", + "@typescript-eslint/parser": "7.18.0", + "@typescript-eslint/utils": "7.18.0" }, "engines": { "node": "^18.18.0 || >=20.0.0" @@ -40879,12 +40951,15 @@ } }, "node_modules/url": { - "version": "0.11.3", - "resolved": "https://registry.npmjs.org/url/-/url-0.11.3.tgz", - "integrity": "sha512-6hxOLGfZASQK/cijlZnZJTq8OXAkt/3YGfQX45vvMYXpZoo8NdWZcY73K108Jf759lS1Bv/8wXnHDTSz17dSRw==", + "version": "0.11.4", + "resolved": "https://registry.npmjs.org/url/-/url-0.11.4.tgz", + "integrity": "sha512-oCwdVC7mTuWiPyjLUz/COz5TLk6wgp0RCsN+wHZ2Ekneac9w8uuV0njcbbie2ME+Vs+d6duwmYuR3HgQXs1fOg==", "dependencies": { "punycode": "^1.4.1", - "qs": "^6.11.2" + "qs": "^6.12.3" + }, + "engines": { + "node": ">= 0.4" } }, "node_modules/url-loader": { @@ -40950,9 +41025,9 @@ "integrity": "sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ==" }, "node_modules/url/node_modules/qs": { - "version": "6.12.3", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.12.3.tgz", - "integrity": "sha512-AWJm14H1vVaO/iNZ4/hO+HyaTehuy9nRqVdkTqlJt0HWvBiBIEXFmb4C0DGeYo3Xes9rrEW+TxHsaigCbN5ICQ==", + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", + "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", "dependencies": { "side-channel": "^1.0.6" }, @@ -41313,9 +41388,11 @@ } }, "node_modules/web-streams-polyfill": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz", - "integrity": "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-4.0.0.tgz", + "integrity": "sha512-0zJXHRAYEjM2tUfZ2DiSOHAa2aw1tisnnhU3ufD57R8iefL+DcdJyRBRyJpG+NUimDgbTI/lH+gAE1PAvV3Cgw==", + "optional": true, + "peer": true, "engines": { "node": ">= 8" } @@ -41479,12 +41556,12 @@ } }, "node_modules/webpack-dev-middleware/node_modules/memfs": { - "version": "4.9.3", - "resolved": "https://registry.npmjs.org/memfs/-/memfs-4.9.3.tgz", - "integrity": "sha512-bsYSSnirtYTWi1+OPMFb0M048evMKyUYe0EbtuGQgq6BVQM1g1W8/KIUJCCvjgI/El0j6Q4WsmMiBwLUBSw8LA==", + "version": "4.11.1", + "resolved": "https://registry.npmjs.org/memfs/-/memfs-4.11.1.tgz", + "integrity": "sha512-LZcMTBAgqUUKNXZagcZxvXXfgF1bHX7Y7nQ0QyEiNbRJgE29GhgPd8Yna1VQcLlPiHt/5RFJMWYN9Uv/VPNvjQ==", "dependencies": { "@jsonjoy.com/json-pack": "^1.0.3", - "@jsonjoy.com/util": "^1.1.2", + "@jsonjoy.com/util": "^1.3.0", "tree-dump": "^1.0.1", "tslib": "^2.0.0" }, @@ -41565,9 +41642,9 @@ } }, "node_modules/webpack-dev-server/node_modules/rimraf": { - "version": "5.0.9", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.9.tgz", - "integrity": "sha512-3i7b8OcswU6CpU8Ej89quJD4O98id7TtVM5U4Mybh84zQXdrFmDLouWBEEaD/QfO3gDDfH+AGFCGsR7kngzQnA==", + "version": "5.0.10", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.10.tgz", + "integrity": "sha512-l0OE8wL34P4nJH/H2ffoaniAokM2qSmrtXHmlpvYr5AVVX8msAyW0l8NVJFDxlSK4u3Uh/f41cQheDVdnYijwQ==", "dev": true, "dependencies": { "glob": "^10.3.7" @@ -41575,9 +41652,6 @@ "bin": { "rimraf": "dist/esm/bin.mjs" }, - "engines": { - "node": "14 >=14.20 || 16 >=16.20 || >=18" - }, "funding": { "url": "https://github.com/sponsors/isaacs" } @@ -41760,13 +41834,13 @@ } }, "node_modules/which-builtin-type": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/which-builtin-type/-/which-builtin-type-1.1.3.tgz", - "integrity": "sha512-YmjsSMDBYsM1CaFiayOVT06+KJeXf0o5M/CAd4o1lTadFAtacTUM49zoYxr/oroopFDfhvN6iEcBxUyc3gvKmw==", + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/which-builtin-type/-/which-builtin-type-1.1.4.tgz", + "integrity": "sha512-bppkmBSsHFmIMSl8BO9TbsyzsvGjVoppt8xUiGzwiu/bhDCGxnpOKCxgqj6GuyHE0mINMDecBFPlOm2hzY084w==", "dev": true, "dependencies": { - "function.prototype.name": "^1.1.5", - "has-tostringtag": "^1.0.0", + "function.prototype.name": "^1.1.6", + "has-tostringtag": "^1.0.2", "is-async-function": "^2.0.0", "is-date-object": "^1.0.5", "is-finalizationregistry": "^1.0.2", @@ -41775,8 +41849,8 @@ "is-weakref": "^1.0.2", "isarray": "^2.0.5", "which-boxed-primitive": "^1.0.2", - "which-collection": "^1.0.1", - "which-typed-array": "^1.1.9" + "which-collection": "^1.0.2", + "which-typed-array": "^1.1.15" }, "engines": { "node": ">= 0.4" diff --git a/package.json b/package.json index 899b2968e..302831bd2 100644 --- a/package.json +++ b/package.json @@ -36,6 +36,7 @@ "@types/cookie-parser": "^1.4.6", "@types/cookie-session": "^2.0.48", "@types/d3": "^7.4.3", + "@types/dom-mediacapture-record": "^1.0.19", "@types/exif": "^0.6.5", "@types/express": "^4.17.21", "@types/express-session": "^1.17.10", @@ -63,10 +64,12 @@ "@types/request": "^2.48.12", "@types/request-promise": "^4.1.51", "@types/shelljs": "^0.8.15", + "@types/textarea-caret": "^3.0.3", "@types/textfit": "^2.4.4", "@types/uuid": "^10.0.0", "@types/valid-url": "^1.0.7", "@types/webpack": "^5.28.5", + "@types/webscopeio__react-textarea-autocomplete": "^4.7.5", "@types/youtube": "0.0.50", "chai": "^5.0.0", "cross-env": "^7.0.3", diff --git a/src/ClientUtils.ts b/src/ClientUtils.ts index fc415d589..f9e282993 100644 --- a/src/ClientUtils.ts +++ b/src/ClientUtils.ts @@ -17,7 +17,7 @@ export function DashColor(color: string | undefined) { } } -export function lightOrDark(color: any) { +export function lightOrDark(color: string | undefined) { if (color === 'transparent' || !color) return Colors.BLACK; if (color.startsWith?.('linear')) return Colors.BLACK; if (DashColor(color).isLight()) return Colors.BLACK; @@ -351,9 +351,9 @@ export namespace ClientUtils { } } -export function OmitKeys(obj: any, keys: string[], pattern?: string, addKeyFunc?: (dup: any) => void): { omit: any; extract: any } { - const omit: any = { ...obj }; - const extract: any = {}; +export function OmitKeys(obj: object, keys: string[], pattern?: string, addKeyFunc?: (dup: object) => void): { omit: { [key: string]: unknown }; extract: { [key: string]: unknown } } { + const omit: { [key: string]: unknown } = { ...obj }; + const extract: { [key: string]: unknown } = {}; keys.forEach(key => { extract[key] = omit[key]; delete omit[key]; @@ -369,8 +369,8 @@ export function OmitKeys(obj: any, keys: string[], pattern?: string, addKeyFunc? return { omit, extract }; } -export function WithKeys(obj: any, keys: string[], addKeyFunc?: (dup: any) => void) { - const dup: any = {}; +export function WithKeys(obj: object & { [key: string]: unknown }, keys: string[], addKeyFunc?: (dup: unknown) => void) { + const dup: { [key: string]: unknown } = {}; keys.forEach(key => { dup[key] = obj[key]; }); @@ -521,7 +521,7 @@ export function simulateMouseClick(element: Element | null | undefined, x: numbe } } -export function getWordAtPoint(elem: any, x: number, y: number): string | undefined { +export function getWordAtPoint(elem: Element, x: number, y: number): string | undefined { if (elem.tagName === 'INPUT') return 'input'; if (elem.tagName === 'TEXTAREA') return 'textarea'; if (elem.nodeType === elem.TEXT_NODE || elem.textContent) { @@ -534,7 +534,7 @@ export function getWordAtPoint(elem: any, x: number, y: number): string | undefi range.setEnd(elem, currentPos + 1); const rangeRect = range.getBoundingClientRect(); if (rangeRect.left <= x && rangeRect.right >= x && rangeRect.top <= y && rangeRect.bottom >= y) { - range.expand?.('word'); // doesn't exist in firefox + 'expand' in range && (range.expand as (val: string) => void)('word'); // doesn't exist in firefox const ret = range.toString(); range.detach(); return ret; @@ -542,16 +542,18 @@ export function getWordAtPoint(elem: any, x: number, y: number): string | undefi currentPos += 1; } } else { - Array.from(elem.childNodes).forEach((childNode: any) => { - const range = childNode.ownerDocument.createRange(); - range.selectNodeContents(childNode); - const rangeRect = range.getBoundingClientRect(); - if (rangeRect.left <= x && rangeRect.right >= x && rangeRect.top <= y && rangeRect.bottom >= y) { - range.detach(); - const word = getWordAtPoint(childNode, x, y); - if (word) return word; - } else { - range.detach(); + Array.from(elem.children).forEach(childNode => { + const range = childNode.ownerDocument?.createRange(); + if (range) { + range.selectNodeContents(childNode); + const rangeRect = range.getBoundingClientRect(); + if (rangeRect.left <= x && rangeRect.right >= x && rangeRect.top <= y && rangeRect.bottom >= y) { + range.detach(); + const word = getWordAtPoint(childNode, x, y); + if (word) return word; + } else { + range.detach(); + } } return undefined; }); @@ -576,17 +578,18 @@ export function setupMoveUpEvents( target: object, e: React.PointerEvent, moveEvent: (e: PointerEvent, down: number[], delta: number[]) => boolean, - upEvent: (e: PointerEvent, movement: number[], isClick: boolean) => any, - clickEvent: (e: PointerEvent, doubleTap?: boolean) => any, + upEvent: (e: PointerEvent, movement: number[], isClick: boolean) => void, + clickEvent: (e: PointerEvent, doubleTap?: boolean) => unknown, // eslint-disable-next-line default-param-last stopPropagation: boolean = true, // eslint-disable-next-line default-param-last stopMovePropagation: boolean = true, noDoubleTapTimeout?: () => void ) { - const targetAny = target as any; + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const targetAny: object & { _downX: number; _downY: number; _lastX: number; _lastY: number; _doubleTap: boolean; _doubleTime?: NodeJS.Timeout; _lastTap: number; _noClick: boolean } = target as any; const doubleTapTimeout = 300; - targetAny._doubleTap = Date.now() - (target as any)._lastTap < doubleTapTimeout; + targetAny._doubleTap = Date.now() - targetAny._lastTap < doubleTapTimeout; targetAny._lastTap = Date.now(); targetAny._downX = targetAny._lastX = e.clientX; targetAny._downY = targetAny._lastY = e.clientY; @@ -594,13 +597,13 @@ export function setupMoveUpEvents( let moving = false; const _moveEvent = (moveEv: PointerEvent): void => { - if (moving || Math.abs(moveEv.clientX - (target as any)._downX) > ClientUtils.DRAG_THRESHOLD || Math.abs(moveEv.clientY - (target as any)._downY) > ClientUtils.DRAG_THRESHOLD) { + if (moving || Math.abs(moveEv.clientX - targetAny._downX) > ClientUtils.DRAG_THRESHOLD || Math.abs(moveEv.clientY - targetAny._downY) > ClientUtils.DRAG_THRESHOLD) { moving = true; - if ((target as any)._doubleTime) { - clearTimeout((target as any)._doubleTime); + if (targetAny._doubleTime) { + targetAny._doubleTime && clearTimeout(targetAny._doubleTime); targetAny._doubleTime = undefined; } - if (moveEvent(moveEv, [(target as any)._downX, (target as any)._downY], [moveEv.clientX - (target as any)._lastX, moveEv.clientY - (target as any)._lastY])) { + if (moveEvent(moveEv, [targetAny._downX, targetAny._downY], [moveEv.clientX - targetAny._lastX, moveEv.clientY - targetAny._lastY])) { document.removeEventListener('pointermove', _moveEvent); // eslint-disable-next-line no-use-before-define document.removeEventListener('pointerup', _upEvent); @@ -621,16 +624,16 @@ export function setupMoveUpEvents( }, doubleTapTimeout); } if (targetAny._doubleTime && targetAny._doubleTap) { - clearTimeout(targetAny._doubleTime); + targetAny._doubleTime && clearTimeout(targetAny._doubleTime); targetAny._doubleTime = undefined; } - targetAny._noClick = clickEvent(upEv, targetAny._doubleTap); + targetAny._noClick = clickEvent(upEv, targetAny._doubleTap) ? true : false; } document.removeEventListener('pointermove', _moveEvent); document.removeEventListener('pointerup', _upEvent, true); }; const _clickEvent = (clickev: MouseEvent): void => { - if ((target as any)._noClick) clickev.stopPropagation(); + if (targetAny._noClick) clickev.stopPropagation(); document.removeEventListener('click', _clickEvent, true); }; if (stopPropagation) { @@ -642,11 +645,11 @@ export function setupMoveUpEvents( document.addEventListener('click', _clickEvent, true); } -export function DivHeight(ele: HTMLElement): number { - return Number(getComputedStyle(ele).height.replace('px', '')); +export function DivHeight(ele: HTMLElement | null): number { + return ele ? Number(getComputedStyle(ele).height.replace('px', '')) : 0; } -export function DivWidth(ele: HTMLElement): number { - return Number(getComputedStyle(ele).width.replace('px', '')); +export function DivWidth(ele: HTMLElement | null): number { + return ele ? Number(getComputedStyle(ele).width.replace('px', '')) : 0; } export function dateRangeStrToDates(dateStr: string) { @@ -709,7 +712,7 @@ export function UpdateIcon( realNativeHeight: number, noSuffix: boolean, replaceRootFilename: string | undefined, - cb: (iconFile: string, nativeWidth: number, nativeHeight: number) => any + cb: (iconFile: string, nativeWidth: number, nativeHeight: number) => void ) { const newDiv = docViewContent.cloneNode(true) as HTMLDivElement; newDiv.style.width = width.toString(); @@ -719,9 +722,9 @@ export function UpdateIcon( const nativeWidth = width; const nativeHeight = height; return CreateImage(ClientUtils.prepend(''), document.styleSheets, htmlString, nativeWidth, (nativeWidth * panelHeight) / panelWidth, (scrollTop * panelHeight) / realNativeHeight) - .then(async (dataUrl: any) => { + .then(async dataUrl => { const returnedFilename = await ClientUtils.convertDataUri(dataUrl, filename, noSuffix, replaceRootFilename); cb(returnedFilename as string, nativeWidth, nativeHeight); }) - .catch((error: any) => console.error('oops, something went wrong!', error)); + .catch(error => console.error('oops, something went wrong!', error)); } diff --git a/src/JSZipUtils.js b/src/JSZipUtils.js index 5ce1bd471..755de7226 100644 --- a/src/JSZipUtils.js +++ b/src/JSZipUtils.js @@ -12,13 +12,17 @@ JSZipUtils._getBinaryFromXHR = function (xhr) { function createStandardXHR() { try { return new window.XMLHttpRequest(); - } catch (e) {} + } catch (e) { + /* empty */ + } } function createActiveXHR() { try { return new window.ActiveXObject('Microsoft.XMLHTTP'); - } catch (e) {} + } catch (e) { + /* empty */ + } } // Create the request object @@ -101,7 +105,7 @@ JSZipUtils.getBinaryContent = function (path, options) { xhr.overrideMimeType('text/plain; charset=x-user-defined'); } - xhr.onreadystatechange = function (event) { + xhr.onreadystatechange = function (/* event */) { // use `xhr` and not `this`... thanks IE if (xhr.readyState === 4) { if (xhr.status === 200 || xhr.status === 0) { diff --git a/src/client/DocServer.ts b/src/client/DocServer.ts index ac865382d..2bf3a6f9f 100644 --- a/src/client/DocServer.ts +++ b/src/client/DocServer.ts @@ -1,14 +1,14 @@ -import { runInAction } from 'mobx'; +/* eslint-disable @typescript-eslint/no-namespace */ +import { action } from 'mobx'; import { Socket, io } from 'socket.io-client'; import { ClientUtils } from '../ClientUtils'; import { Utils, emptyFunction } from '../Utils'; -import { Doc, Opt } from '../fields/Doc'; +import { Doc, FieldType, Opt, SetObjGetRefField, SetObjGetRefFields } from '../fields/Doc'; import { UpdatingFromServer } from '../fields/DocSymbols'; import { FieldLoader } from '../fields/FieldLoader'; import { HandleUpdate, Id, Parent } from '../fields/FieldSymbols'; -import { ObjectField, SetObjGetRefField, SetObjGetRefFields } from '../fields/ObjectField'; -import { RefField } from '../fields/RefField'; -import { GestureContent, Message, MessageStore, MobileDocumentUploadContent, MobileInkOverlayContent, UpdateMobileInkOverlayPositionContent, YoutubeQueryTypes } from '../server/Message'; +import { ObjectField, serverOpType } from '../fields/ObjectField'; +import { GestureContent, Message, MessageStore, MobileDocumentUploadContent, MobileInkOverlayContent, UpdateMobileInkOverlayPositionContent } from '../server/Message'; import { SerializationHelper } from './util/SerializationHelper'; /** @@ -25,8 +25,7 @@ import { SerializationHelper } from './util/SerializationHelper'; * or update ourselves based on the server's update message, that occurs here */ export namespace DocServer { - // eslint-disable-next-line import/no-mutable-exports - let _cache: { [id: string]: RefField | Promise> } = {}; + let _cache: { [id: string]: Doc | Promise> } = {}; export function Cache() { return _cache; } @@ -34,24 +33,24 @@ export namespace DocServer { function errorFunc(): never { throw new Error("Can't use DocServer without calling init first"); } - let _UpdateField: (id: string, diff: any) => void = errorFunc; - let _CreateField: (field: RefField) => void = errorFunc; + let _UpdateField: (id: string, diff: serverOpType) => void = errorFunc; + let _CreateField: (field: Doc) => void = errorFunc; - export function AddServerHandler(socket: Socket, message: Message, handler: (args: T) => any) { + export function AddServerHandler(socket: Socket, message: Message, handler: (args: T) => void) { socket.on(message.Message, Utils.loggingCallback('Incoming', handler, message.Name)); } export function Emit(socket: Socket, message: Message, args: T) { // log('Emit', message.Name, args, false); socket.emit(message.Message, args); } - export function EmitCallback(socket: Socket, message: Message, args: T): Promise; - export function EmitCallback(socket: Socket, message: Message, args: T, fn: (args: any) => any): void; - export function EmitCallback(socket: Socket, message: Message, args: T, fn?: (args: any) => any): void | Promise { + export function EmitCallback(socket: Socket, message: Message, args: T): Promise; + export function EmitCallback(socket: Socket, message: Message, args: T, fn: (args: unknown) => unknown): void; + export function EmitCallback(socket: Socket, message: Message, args: T, fn?: (args: unknown) => unknown): void | Promise { // log('Emit', message.Name, args, false); if (fn) { socket.emit(message.Message, args, Utils.loggingCallback('Receiving', fn, message.Name)); } else { - return new Promise(res => { + return new Promise(res => { socket.emit(message.Message, args, Utils.loggingCallback('Receiving', res, message.Name)); }); } @@ -99,7 +98,7 @@ export namespace DocServer { return ClientUtils.CurrentUserEmail() === 'guest' ? WriteMode.LivePlayground : fieldWriteModes[field] || WriteMode.Default; } - export function registerDocWithCachedUpdate(doc: Doc, field: string, oldValue: any) { + export function registerDocWithCachedUpdate(doc: Doc, field: string, oldValue: FieldType) { let list = docsWithUpdates[field]; if (!list) { list = docsWithUpdates[field] = new Set(); @@ -203,7 +202,7 @@ export namespace DocServer { * the server if the document has not been cached. * @param id the id of the requested document */ - const _GetRefFieldImpl = (id: string, force: boolean = false): Promise> => { + const _GetRefFieldImpl = (id: string, force: boolean = false): Promise> => { // an initial pass through the cache to determine whether the document needs to be fetched, // is already in the process of being fetched or already exists in the // cache @@ -221,7 +220,7 @@ export namespace DocServer { // future .proto calls on the Doc won't have to go farther than the cache to get their actual value. const deserializeField = getSerializedField.then(async fieldJson => { // deserialize - const field = await SerializationHelper.Deserialize(fieldJson); + const field = (await SerializationHelper.Deserialize(fieldJson)) as Doc; if (force && field && cached instanceof Doc) { cached[UpdatingFromServer] = true; Array.from(Object.keys(field)).forEach(key => { @@ -247,7 +246,7 @@ export namespace DocServer { // here, indicate that the document associated with this id is currently // being retrieved and cached !force && (_cache[id] = deserializeField); - return force ? (cached as any) : deserializeField; + return force ? (cached instanceof Promise ? cached : new Promise(res => res(cached))) : deserializeField; } if (cached instanceof Promise) { // BEING RETRIEVED AND CACHED => some other caller previously (likely recently) called GetRefField(s), @@ -261,7 +260,7 @@ export namespace DocServer { // (field instanceof Doc) && fetchProto(field); ); }; - const _GetCachedRefFieldImpl = (id: string): Opt => { + const _GetCachedRefFieldImpl = (id: string): Opt => { const cached = _cache[id]; if (cached !== undefined && !(cached instanceof Promise)) { return cached; @@ -269,174 +268,102 @@ export namespace DocServer { return undefined; }; - let _GetRefField: (id: string, force: boolean) => Promise> = errorFunc; - let _GetCachedRefField: (id: string) => Opt = errorFunc; + let _GetRefField: (id: string, force: boolean) => Promise> = errorFunc; + let _GetCachedRefField: (id: string) => Opt = errorFunc; - export function GetRefField(id: string, force = false): Promise> { + export function GetRefField(id: string, force = false): Promise> { return _GetRefField(id, force); } - export function GetCachedRefField(id: string): Opt { + export function GetCachedRefField(id: string): Opt { return _GetCachedRefField(id); } - export async function getYoutubeChannels() { - return DocServer.EmitCallback(_socket, MessageStore.YoutubeApiQuery, { type: YoutubeQueryTypes.Channels }); - } - - export function getYoutubeVideos(videoTitle: string, callBack: (videos: any[]) => void) { - DocServer.EmitCallback(_socket, MessageStore.YoutubeApiQuery, { type: YoutubeQueryTypes.SearchVideo, userInput: videoTitle }, callBack); - } - - export function getYoutubeVideoDetails(videoIds: string, callBack: (videoDetails: any[]) => void) { - DocServer.EmitCallback(_socket, MessageStore.YoutubeApiQuery, { type: YoutubeQueryTypes.VideoDetails, videoIds: videoIds }, callBack); - } - /** * Given a list of Doc GUIDs, this utility function will asynchronously attempt to each id's associated * field, first looking in the RefField cache and then communicating with * the server if the document has not been cached. * @param ids the ids that map to the reqested documents */ - const _GetRefFieldsImpl = async (ids: string[]): Promise<{ [id: string]: Opt }> => { - const requestedIds: string[] = []; - const promises: Promise[] = []; - - let defaultRes: any; - const defaultPromise = new Promise(res => { - defaultRes = res; + const _GetRefFieldsImpl = async (ids: string[]): Promise>> => { + const uncachedRequestedIds: string[] = []; + const deserializeDocPromises: Promise>[] = []; + + // setup a Promise that we will resolve after all cached Docs have been acquired. + let allCachesFilledResolver!: (value: Opt | PromiseLike>) => void; + const allCachesFilledPromise = new Promise>(res => { + allCachesFilledResolver = res; }); - const defaultPromises: { p: Promise; id: string }[] = []; - // 1) an initial pass through the cache to determine - // i) which documents need to be fetched - // ii) which are already in the process of being fetched - // iii) which already exist in the cache + + const fetchDocPromises: Map>> = new Map(); // { p: Promise; id: string }[] = []; // promises to fetch the value for a requested Doc + // Determine which requested documents need to be fetched // eslint-disable-next-line no-restricted-syntax for (const id of ids.filter(filterid => filterid)) { - const cached = _cache[id]; - if (cached === undefined) { - defaultPromises.push({ - id, - // eslint-disable-next-line no-loop-func - p: (_cache[id] = new Promise(res => { - defaultPromise.then(() => res(_cache[id])); - })), - }); - // NOT CACHED => we'll have to send a request to the server - requestedIds.push(id); - } else if (cached instanceof Promise) { - // BEING RETRIEVED AND CACHED => some other caller previously (likely recently) called GetRefField(s), - // and requested one of the documents I'm looking for. Shouldn't fetch again, just - // wait until this promise is resolved (see 7) - promises.push(cached); - // waitingIds.push(id); - } else { - // CACHED => great, let's just add it to the field map - // map[id] = cached; + if (_cache[id] === undefined) { + // EMPTY CACHE - make promise that we resolve after all batch-requested Docs have been fetched and deserialized and we know we have this Doc + const fetchPromise = new Promise>(res => + allCachesFilledPromise.then(() => { + // if all Docs have been cached, then we can be sure the fetched Doc has been found and cached. So return it to anyone who had been awaiting it. + const cache = _cache[id]; + if (!(cache instanceof Doc)) console.log('CACHE WAS NEVER FILLED!!'); + res(cache instanceof Doc ? cache : undefined); + }) + ); + // eslint-disable-next-line no-loop-func + fetchDocPromises.set(id, (_cache[id] = fetchPromise)); + uncachedRequestedIds.push(id); // add to list of Doc requests from server } + // else CACHED => do nothing, Doc or promise of Doc is already in cache } - if (requestedIds.length) { - // 2) synchronously, we emit a single callback to the server requesting the serialized (i.e. represented by a string) - // fields for the given ids. This returns a promise, which, when resolved, indicates that all the JSON serialized versions of - // the fields have been returned from the server - console.log('Requesting ' + requestedIds.length); - setTimeout(() => - runInAction(() => { - FieldLoader.ServerLoadStatus.requested = requestedIds.length; - }) - ); - const serializedFields = await DocServer.EmitCallback(_socket, MessageStore.GetRefFields, requestedIds); - - // 3) when the serialized RefFields have been received, go head and begin deserializing them into objects. - // Here, once deserialized, we also invoke .proto to 'load' the documents' prototypes, which ensures that all - // future .proto calls on the Doc won't have to go farther than the cache to get their actual value. + if (uncachedRequestedIds.length) { + console.log('Requesting ' + uncachedRequestedIds.length); + setTimeout(action(() => { FieldLoader.ServerLoadStatus.requested = uncachedRequestedIds.length; })); // prettier-ignore + + // Synchronously emit a single server request for the serialized (i.e. represented by a string) Doc ids + // This returns a promise, that resolves when all the JSON serialized Docs have been retrieved + const serializedFields = (await DocServer.EmitCallback(_socket, MessageStore.GetRefFields, uncachedRequestedIds)) as { id: string; fields: unknown[]; __type: string }[]; + let processed = 0; - console.log('deserializing ' + serializedFields.length + ' fields'); + console.log('Retrieved ' + serializedFields.length + ' fields'); + // After the serialized Docs have been received, deserialize them into objects. // eslint-disable-next-line no-restricted-syntax for (const field of serializedFields) { - processed++; - if (processed % 150 === 0) { + // eslint-disable-next-line no-await-in-loop + ++processed % 150 === 0 && + (await new Promise( + res => + setTimeout(action(() => res(FieldLoader.ServerLoadStatus.retrieved = processed))) // prettier-ignore + )); // force loading to yield to splash screen rendering to update progress + + if (fetchDocPromises.has(field.id)) { + // Doc hasn't started deserializing yet - the cache still has the fetch promise // eslint-disable-next-line no-loop-func - runInAction(() => { - FieldLoader.ServerLoadStatus.retrieved = processed; + const deserializePromise = SerializationHelper.Deserialize(field).then((deserialized: unknown) => { + const doc = deserialized as Doc; + // overwrite any fetch or deserialize cache promise with deserialized value. + // fetch promises wait to resolve until after all deserializations; deserialize promises resolve upon deserializaton + if (deserialized !== undefined) _cache[field.id] = doc; + else delete _cache[field.id]; + + return doc; }); - // eslint-disable-next-line no-await-in-loop - await new Promise(res => { - setTimeout(res); - }); // force loading to yield to splash screen rendering to update progress - } - const cached = _cache[field.id]; - if (!cached || (cached instanceof Promise && defaultPromises.some(dp => dp.p === cached))) { - // deserialize - // adds to a list of promises that will be awaited asynchronously - promises.push( - // eslint-disable-next-line no-loop-func - (_cache[field.id] = SerializationHelper.Deserialize(field).then(deserialized => { - // overwrite or delete any promises (that we inserted as flags - // to indicate that the field was in the process of being fetched). Now everything - // should be an actual value within or entirely absent from the cache. - if (deserialized !== undefined) { - _cache[field.id] = deserialized; - } else { - delete _cache[field.id]; - } - const promInd = defaultPromises.findIndex(dp => dp.id === field.id); - promInd !== -1 && defaultPromises.splice(promInd, 1); - return deserialized; - })) - ); - // 4) here, for each of the documents we've requested *ourselves* (i.e. weren't promises or found in the cache) - // we set the value at the field's id to a promise that will resolve to the field. - // When we find that promises exist at keys in the cache, THIS is where they were set, just by some other caller (method). - // The mapping in the .then call ensures that when other callers await these promises, they'll - // get the resolved field - } else if (cached instanceof Promise) { + deserializeDocPromises.push((_cache[field.id] = deserializePromise)); // replace the cache's placeholder fetch promise with the deserializePromise + fetchDocPromises.delete(field.id); + } else if (_cache[field.id] instanceof Promise) { console.log('.'); - // promises.push(cached); - } else if (field) { - // console.log('-'); } } } - await Promise.all(promises); - defaultPromises.forEach(df => delete _cache[df.id]); - defaultRes(); - - // 5) at this point, all fields have a) been returned from the server and b) been deserialized into actual Field objects whose - // prototype documents, if any, have also been fetched and cached. - console.log('Deserialized ' + (requestedIds.length - defaultPromises.length) + ' fields'); - // 6) with this confidence, we can now go through and update the cache at the ids of the fields that - // we explicitly had to fetch. To finish it off, we add whatever value we've come up with for a given - // id to the soon-to-be-returned field mapping. - // ids.forEach(id => (map[id] = _cache[id] as any)); - - // 7) those promises we encountered in the else if of 1), which represent - // other callers having already submitted a request to the server for (a) document(s) - // in which we're interested, must still be awaited so that we can return the proper - // values for those as well. - // - // fortunately, those other callers will also hit their own version of 6) and clean up - // the shared cache when these promises resolve, so all we have to do is... - // const otherCallersFetching = await Promise.all(promises); - // ...extract the RefFields returned from the resolution of those promises and add them to our - // own map. - // waitingIds.forEach((id, index) => (map[id] = otherCallersFetching[index])); - - // now, we return our completed mapping from all of the ids that were passed into the method - // to their actual RefField | undefined values. This return value either becomes the input - // argument to the caller's promise (i.e. GetRefFields(["_id1_", "_id2_", "_id3_"]).then(map => //do something with map...)) - // or it is the direct return result if the promise is awaited (i.e. let fields = await GetRefFields(["_id1_", "_id2_", "_id3_"])). - return ids.reduce( - (map, id) => { - map[id] = _cache[id] as any; - return map; - }, - {} as { [id: string]: Opt } - ); + await Promise.all(deserializeDocPromises); // promise resolves when cache is up-to-date with all requested Docs + Array.from(fetchDocPromises).forEach(([id]) => delete _cache[id]); + allCachesFilledResolver(undefined); // notify anyone who was promised a Doc fron when it was just being fetched (since all requested Docs have now been fetched and deserialized) + + console.log('Deserialized ' + (uncachedRequestedIds.length - fetchDocPromises.size) + ' fields'); + return new Map>(ids.map(id => [id, _cache[id] instanceof Doc ? (_cache[id] as Doc) : undefined]) as [string, Opt][]); }; - let _GetRefFields: (ids: string[]) => Promise<{ [id: string]: Opt }> = errorFunc; + let _GetRefFields: (ids: string[]) => Promise>> = errorFunc; export function GetRefFields(ids: string[]) { return _GetRefFields(ids); @@ -454,12 +381,12 @@ export namespace DocServer { * calling the same function throughout the code base (such as in Util.makeReadonly()) * @param field the [RefField] to be serialized and sent to the server to be stored in the database */ - export function CreateField(field: RefField) { + export function CreateField(field: Doc) { _cacheNeedsUpdate = true; _CreateField(field); } - function _CreateFieldImpl(field: RefField) { + function _CreateFieldImpl(field: Doc) { _cache[field[Id]] = field; const initialState = SerializationHelper.Serialize(field); ClientUtils.CurrentUserEmail() !== 'guest' && DocServer.Emit(_socket, MessageStore.CreateField, initialState); @@ -475,22 +402,22 @@ export namespace DocServer { * @param updatedState the new value of the document. At some point, this * should actually be a proper diff, to improve efficiency */ - export function UpdateField(id: string, updatedState: any) { + export function UpdateField(id: string, updatedState: serverOpType) { _UpdateField(id, updatedState); } - function _UpdateFieldImpl(id: string, diff: any) { + function _UpdateFieldImpl(id: string, diff: serverOpType) { !DocServer.Control.isReadOnly() && ClientUtils.CurrentUserEmail() !== 'guest' && DocServer.Emit(_socket, MessageStore.UpdateField, { id, diff }); } - function _respondToUpdateImpl(diff: any) { - const { id } = diff; + function _respondToUpdateImpl(change: { id: string; diff: serverOpType }) { + const { id } = change; // to be valid, the Diff object must reference // a document's id if (id === undefined) { return; } - const update = (f: Opt) => { + const update = (f: Opt) => { // if the RefField is absent from the cache or // its promise in the cache resolves to undefined, there // can't be anything to update @@ -500,7 +427,7 @@ export namespace DocServer { // extract this Doc's update handler const handler = f[HandleUpdate]; if (handler) { - handler.call(f, diff.diff); + handler.call(f, change.diff as { $set: { [key: string]: FieldType } } | { $unset: unknown }); } }; // check the cache for the field @@ -536,8 +463,8 @@ export namespace DocServer { const _RespondToUpdate = _respondToUpdateImpl; const _respondToDelete = _respondToDeleteImpl; - function respondToUpdate(diff: any) { - _RespondToUpdate(diff); + function respondToUpdate(change: { id: string; diff: serverOpType }) { + _RespondToUpdate(change); } function respondToDelete(ids: string | string[]) { @@ -548,7 +475,7 @@ export namespace DocServer { _cache = {}; USER_ID = identifier; _socket = io(`${protocol.startsWith('https') ? 'wss' : 'ws'}://${hostname}:${port}`, { transports: ['websocket'], rejectUnauthorized: false }); - _socket.on('connect_error', (err: any) => console.log(err)); + _socket.on('connect_error', (err: unknown) => console.log(err)); // io.connect(`https://7f079dda.ngrok.io`);// if using ngrok, create a special address for the websocket _GetCachedRefField = _GetCachedRefFieldImpl; diff --git a/src/client/Network.ts b/src/client/Network.ts index 968c407b2..8876d8190 100644 --- a/src/client/Network.ts +++ b/src/client/Network.ts @@ -8,12 +8,13 @@ import { Upload } from '../server/SharedMediaTypes'; * mainly provides methods that the client can use to begin the process of * interacting with the server, such as fetching or uploading files. */ +// eslint-disable-next-line @typescript-eslint/no-namespace export namespace Networking { export async function FetchFromServer(relativeRoute: string) { return (await fetch(relativeRoute)).text(); } - export async function PostToServer(relativeRoute: string, body?: any) { + export async function PostToServer(relativeRoute: string, body?: unknown) { const options = { uri: ClientUtils.prepend(relativeRoute), method: 'POST', @@ -31,7 +32,7 @@ export namespace Networking { * used as the guid. Otherwise, a new guid is generated. */ export interface FileGuidPair { - file: File; + file: File | Blob; guid?: string; } /** @@ -48,15 +49,14 @@ export namespace Networking { if (!fileguidpairs.length) { return []; } - const maxFileSize = 50000000; + const maxFileSize = 5000000; if (fileguidpairs.some(f => f.file.size > maxFileSize)) { - return new Promise(res => { - res([ - { - source: { name: '', type: '', size: 0, toJson: () => ({ name: '', type: '' }) }, - result: { name: '', message: `max file size (${maxFileSize / 1000000}MB) exceeded` }, - }, - ]); + return new Promise[]>(res => { + res([{ + source: { size: 0, filepath: '', mimetype: '', originalFilename: '', newFilename: '',hashAlgorithm: false, + toJSON: () => ({ size: 0, filepath: '', mimetype: '', originalFilename: '', newFilename: '',name: '', length: 0, mtime: new Date(), type: '' }) }, + result: { name: '', message: `max file size (${maxFileSize / 1000000}MB) exceeded` } + }]) // prettier-ignore }); } formData.set('fileguids', fileguidpairs.map(pair => pair.guid).join(';')); @@ -77,7 +77,12 @@ export namespace Networking { const endpoint = browndash ? '[insert endpoint allowing local => browndash]' : '/uploadFormData'; const response = await fetch(endpoint, parameters); - return response.json(); + return response.json().then((json: Upload.FileResponse[]) => + json.map(fileresponse => { + if ('message' in fileresponse.result) fileresponse.result = new Error(fileresponse.result.message); + return fileresponse; + }) + ); } export async function UploadYoutubeToServer(videoId: string, overwriteId?: string): Promise[]> { diff --git a/src/client/documents/DocUtils.ts b/src/client/documents/DocUtils.ts index 0c9fe0315..a503d732b 100644 --- a/src/client/documents/DocUtils.ts +++ b/src/client/documents/DocUtils.ts @@ -35,14 +35,16 @@ import { TaskCompletionBox } from '../views/nodes/TaskCompletedBox'; import { DocumentType } from './DocumentTypes'; import { Docs, DocumentOptions } from './Documents'; +// eslint-disable-next-line @typescript-eslint/no-var-requires const { DFLT_IMAGE_NATIVE_DIM } = require('../views/global/globalCssVariables.module.scss'); // prettier-ignore const defaultNativeImageDim = Number(DFLT_IMAGE_NATIVE_DIM.replace('px', '')); +// eslint-disable-next-line @typescript-eslint/no-namespace export namespace DocUtils { - function matchFieldValue(doc: Doc, key: string, valueIn: any): boolean { + function matchFieldValue(doc: Doc, key: string, valueIn: unknown): boolean { let value = valueIn; - const hasFunctionFilter = ClientUtils.HasFunctionFilter(value); + const hasFunctionFilter = ClientUtils.HasFunctionFilter(value as string); if (hasFunctionFilter) { return hasFunctionFilter(StrCast(doc[key])); } @@ -57,8 +59,8 @@ export namespace DocUtils { // prettier-ignore return (value === Doc.FilterNone && !allLinks.length) || (value === Doc.FilterAny && !!allLinks.length) || - (allLinks.some(link => matchLink(value,DocCast(link.link_anchor_1)) || - matchLink(value,DocCast(link.link_anchor_2)) )); + (allLinks.some(link => matchLink(value as string, DocCast(link.link_anchor_1)) || + matchLink(value as string, DocCast(link.link_anchor_2)) )); } if (typeof value === 'string') { value = value.replace(`,${ClientUtils.noRecursionHack}`, ''); @@ -71,9 +73,9 @@ export namespace DocUtils { } const vals = StrListCast(fieldVal); // list typing is very imperfect. casting to a string list doesn't mean that the entries will actually be strings if (vals.length) { - return vals.some(v => typeof v === 'string' && v.includes(value)); // bcz: arghh: Todo: comparison should be parameterized as exact, or substring + return vals.some(v => typeof v === 'string' && v.includes(value as string)); // bcz: arghh: Todo: comparison should be parameterized as exact, or substring } - return Field.toString(fieldVal as FieldType).includes(value); // bcz: arghh: Todo: comparison should be parameterized as exact, or substring + return Field.toString(fieldVal as FieldType).includes(value as string); // bcz: arghh: Todo: comparison should be parameterized as exact, or substring } /** * @param docs @@ -215,13 +217,13 @@ export namespace DocUtils { { acl_Guest: SharingPermissions.Augment, _acl_Guest: SharingPermissions.Augment, - title: ComputedField.MakeFunction('generateLinkTitle(this)') as any, + title: ComputedField.MakeFunction('generateLinkTitle(this)') as unknown as string, // title can accept functions even though type says it can't link_anchor_1_useSmallAnchor: source.useSmallAnchor ? true : undefined, link_anchor_2_useSmallAnchor: target.useSmallAnchor ? true : undefined, link_relationship: linkSettings.link_relationship, link_description: linkSettings.link_description, - x: ComputedField.MakeFunction(`((this.${a}?.x||0)+(this.${b}?.x||0))/2`) as any, - y: ComputedField.MakeFunction(`((this.${a}?.y||0)+(this.${b}?.y||0))/2`) as any, + x: ComputedField.MakeFunction(`((this.${a}?.x||0)+(this.${b}?.x||0))/2`) as unknown as number, // x can accept functions even though type says it can't + y: ComputedField.MakeFunction(`((this.${a}?.y||0)+(this.${b}?.y||0))/2`) as unknown as number, // y can accept functions even though type says it can't link_autoMoveAnchors: true, _lockedPosition: true, _layout_showCaption: '', // removed since they conflict with showing a link with a LinkBox (ie, line, not comparison box) @@ -235,10 +237,10 @@ export namespace DocUtils { ); } - export function AssignScripts(doc: Doc, scripts?: { [key: string]: string | undefined }, funcs?: { [key: string]: string }) { + export function AssignScripts(doc: Doc, scripts?: { [key: string]: string | undefined }, funcs?: { [key: string]: string | undefined }) { scripts && Object.keys(scripts).forEach(key => { - const script = scripts[key]; + const script = scripts[key] as string; if (ScriptCast(doc[key])?.script.originalScript !== scripts[key] && script) { (key.startsWith('_') ? doc : Doc.GetProto(doc))[key] = ScriptField.MakeScript(script, { this: Doc.name, @@ -261,16 +263,17 @@ export namespace DocUtils { .filter(key => !key.endsWith('-setter')) .forEach(key => { const cfield = ComputedField.WithoutComputed(() => FieldValue(doc[key])); - if (ScriptCast(cfield)?.script.originalScript !== funcs[key]) { + const func = funcs[key]; + if (ScriptCast(cfield)?.script.originalScript !== func) { const setFunc = Cast(funcs[key + '-setter'], 'string', null); - (key.startsWith('_') ? doc : Doc.GetProto(doc))[key] = funcs[key] ? ComputedField.MakeFunction(funcs[key], { dragData: Doc.DocDragDataName }, { _readOnly_: true }, setFunc) : undefined; + (key.startsWith('_') ? doc : Doc.GetProto(doc))[key] = func ? ComputedField.MakeFunction(func, { dragData: Doc.DocDragDataName }, { _readOnly_: true }, setFunc) : undefined; } }); return doc; } export function AssignOpts(doc: Doc | undefined, reqdOpts: DocumentOptions, items?: Doc[]) { if (doc) { - const compareValues = (val1: any, val2: any) => { + const compareValues = (val1: unknown, val2: unknown) => { if (val1 instanceof List && val2 instanceof List && val1.length === val2.length) { return !val1.some(v => !val2.includes(v)) || !val2.some(v => val1.includes(v)); } @@ -334,7 +337,7 @@ export namespace DocUtils { if (path.includes(window.location.hostname)) { const s = path.split('/'); const id = s[s.length - 1]; - return DocServer.GetRefField(id).then(field => { + return DocServer.GetRefField(id)?.then(field => { if (field instanceof Doc) { const embedding = Doc.MakeEmbedding(field); embedding.x = (options.x as number) || 0; @@ -354,7 +357,7 @@ export namespace DocUtils { return ctor ? ctor(path, overwriteDoc ? { ...options, title: StrCast(overwriteDoc.title, path) } : options, overwriteDoc) : undefined; } - export function addDocumentCreatorMenuItems(docTextAdder: (d: Doc) => void, docAdder: (d: Doc) => void, x: number, y: number, simpleMenu: boolean = false, pivotField?: string, pivotValue?: string): void { + export function addDocumentCreatorMenuItems(docTextAdder: (d: Doc) => void, docAdder: (d: Doc) => void, x: number, y: number, simpleMenu: boolean = false, pivotField?: string, pivotValue?: string | number | boolean): void { const documentList: ContextMenuProps[] = DocListCast(DocListCast(Doc.MyTools?.data)[0]?.data) .filter(btnDoc => !btnDoc.hidden) .map(btnDoc => Cast(btnDoc?.dragFactory, Doc, null)) @@ -451,7 +454,7 @@ export namespace DocUtils { batch.end(); return doc; } - export function findTemplate(templateName: string, type: string) { + export function findTemplate(templateName: string, doc: Doc) { let docLayoutTemplate: Opt; const iconViews = DocListCast(Cast(Doc.UserDoc().template_icons, Doc, null)?.data); const templBtns = DocListCast(Cast(Doc.UserDoc().template_buttons, Doc, null)?.data); @@ -469,7 +472,8 @@ export namespace DocUtils { // first try to find a template that matches the specific document type (_). otherwise, fallback to a general match on !docLayoutTemplate && allTemplates.forEach(tempDoc => { - StrCast(tempDoc.title) === templateName + '_' + type && (docLayoutTemplate = tempDoc); + const templateType = StrCast(doc[templateName + '_fieldKey'] || doc.type); + StrCast(tempDoc.title) === templateName + '_' + templateType && (docLayoutTemplate = tempDoc); }); !docLayoutTemplate && allTemplates.forEach(tempDoc => { @@ -481,7 +485,7 @@ export namespace DocUtils { const templateName = templateSignature.replace(/\(.*\)/, ''); doc.layout_fieldKey = 'layout_' + (templateSignature || (docLayoutTemplate?.title ?? '')); // eslint-disable-next-line no-param-reassign - docLayoutTemplate = docLayoutTemplate || findTemplate(templateName, StrCast(doc.isGroup && doc.transcription ? 'transcription' : doc.type)); + docLayoutTemplate = docLayoutTemplate || findTemplate(templateName, doc); const customName = 'layout_' + templateSignature; const _width = NumCast(doc._width); @@ -619,7 +623,7 @@ export namespace DocUtils { const proto = protoIn; if (Upload.isImageInformation(result)) { const maxNativeDim = Math.min(Math.max(result.nativeHeight, result.nativeWidth), defaultNativeImageDim); - const exifRotation = StrCast((result.exifData?.data as any)?.Orientation).toLowerCase(); + const exifRotation = StrCast(result.exifData?.data?.Orientation).toLowerCase(); proto.data_nativeOrientation = result.exifData?.data?.image?.Orientation ?? (exifRotation.includes('rotate 90') || exifRotation.includes('rotate 270') ? 5 : undefined); proto.data_nativeWidth = result.nativeWidth < result.nativeHeight ? (maxNativeDim * result.nativeWidth) / result.nativeHeight : maxNativeDim; proto.data_nativeHeight = result.nativeWidth < result.nativeHeight ? maxNativeDim : maxNativeDim / (result.nativeWidth / result.nativeHeight); @@ -697,10 +701,10 @@ export namespace DocUtils { source: { newFilename, mimetype }, result, } = upfiles.lastElement(); - if ((result as any).message) { + if (result instanceof Error) { if (overwriteDoc) { overwriteDoc.isLoading = false; - overwriteDoc.loadingError = (result as any).message; + overwriteDoc.loadingError = result.message; Doc.removeCurrentlyLoading(overwriteDoc); } } else newFilename && processFileupload(generatedDocuments, newFilename, mimetype ?? '', result, options, overwriteDoc); @@ -736,9 +740,9 @@ export namespace DocUtils { source: { newFilename, mimetype }, result, } = upfiles.lastElement() ?? { source: { newFilename: '', mimetype: '' }, result: { message: 'upload failed' } }; - if ((result as any).message) { + if (result instanceof Error) { if (overwriteDoc) { - overwriteDoc.loadingError = (result as any).message; + overwriteDoc.loadingError = result.message; Doc.removeCurrentlyLoading(overwriteDoc); } } else newFilename && mimetype && processFileupload(generatedDocuments, newFilename, mimetype, result, options, overwriteDoc); @@ -768,7 +772,7 @@ export namespace DocUtils { export async function Zip(doc: Doc, zipFilename = 'dashExport.zip') { const { clone, map, linkMap } = await Doc.MakeClone(doc); const proms = new Set(); - function replacer(key: any, value: any) { + function replacer(key: string, value: { url: string; [key: string]: unknown }) { if (key && ['branchOf', 'cloneOf', 'cursors'].includes(key)) return undefined; if (value?.__type === 'image') { const extension = value.url.replace(/.*\./, ''); @@ -804,8 +808,8 @@ export namespace DocUtils { return value; } - const docs: { [id: string]: any } = {}; - const links: { [id: string]: any } = {}; + const docs: { [id: string]: unknown } = {}; + const links: { [id: string]: unknown } = {}; Array.from(map.entries()).forEach(f => { docs[f[0]] = f[1]; }); @@ -826,13 +830,13 @@ export namespace DocUtils { } else promArr.forEach((url, i) => { // loading a file and add it in a zip file - JSZipUtils.getBinaryContent(window.location.origin + '/' + url, (err: any, data: any) => { + JSZipUtils.getBinaryContent(window.location.origin + '/' + url, (err: unknown, data: unknown) => { if (err) throw err; // or handle the error // // Generate a directory within the Zip file structure // const assets = zip.folder("assets"); // assets.file(filename, data, {binary: true}); const assetPathOnServer = promArr[i].replace(window.location.origin + '/', '').replace(/\//g, '%%%'); - zip.file(assetPathOnServer, data, { binary: true }); + zip.file(assetPathOnServer, data as string, { binary: true }); console.log(' => ' + url); if (++count === promArr.length) { zip.file('docs.json', jsonDocs); @@ -862,7 +866,7 @@ ScriptingGlobals.add(function copyDragFactory(dragFactory: Doc, asDelegate?: boo return dragFactory instanceof Doc ? (asDelegate ? DocUtils.delegateDragFactory(dragFactory) : DocUtils.copyDragFactory(dragFactory)) : dragFactory; }); // eslint-disable-next-line prefer-arrow-callback -ScriptingGlobals.add(function makeDelegate(proto: any) { +ScriptingGlobals.add(function makeDelegate(proto: Doc) { const d = Docs.Create.DelegateDocument(proto, { title: 'child of ' + proto.title }); return d; }); diff --git a/src/client/documents/DocumentTypes.ts b/src/client/documents/DocumentTypes.ts index 8f95068db..53edb2e31 100644 --- a/src/client/documents/DocumentTypes.ts +++ b/src/client/documents/DocumentTypes.ts @@ -31,7 +31,6 @@ export enum DocumentType { // special purpose wrappers that either take no data or are compositions of lower level types LINK = 'link', - IMPORT = 'import', PRES = 'presentation', PRESELEMENT = 'preselement', COMPARISON = 'comparison', diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index b96fdb4bd..d7fdf016c 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -141,12 +141,12 @@ class RtfInfo extends FInfo { } class ListInfo extends FInfo { fieldType? = FInfoFieldType.list; - values?: List[] = []; + values?: List[] = []; } type BOOLt = BoolInfo | boolean; type NUMt = NumInfo | number; type STRt = StrInfo | string; -type LISTt = ListInfo | List; +type LISTt = ListInfo | List; type DOCt = DocInfo | Doc; type RTFt = RtfInfo | RichTextField; type DIMt = DimInfo; // | typeof DimUnit.Pixel | typeof DimUnit.Ratio; @@ -358,7 +358,7 @@ export class DocumentOptions { presentation_duration?: NUMt = new NumInfo('the duration of the slide in presentation view', false); presentation_zoomText?: BOOLt = new BoolInfo('whether text anchors should shown in a larger box when following links to make them stand out', false); - data?: any; + data?: FieldType; data_useCors?: BOOLt = new BoolInfo('whether CORS protocol should be used for web page'); columnHeaders?: List; // headers for stacking views schemaHeaders?: List; // headers for schema view @@ -464,13 +464,14 @@ export class DocumentOptions { sidebar_color?: string; // background color of text sidebar sidebar_type_collection?: string; // collection type of text sidebar - data_dashboards?: List; // list of dashboards used in shareddocs; + data_dashboards?: List; // list of dashboards used in shareddocs; textTransform?: string; letterSpacing?: string; iconTemplate?: string; // name of icon template style + icon_fieldKey?: string; // specifies the icon template to use (e.g., icon_fieldKey='george', then the icon template's name is icon_george; otherwise, the template's name would be icon_ where type is the Doc's type(pdf,rich text, etc)) selectedIndex?: NUMt = new NumInfo("which item in a linear view has been selected using the 'thumb doc' ui"); - fieldValues?: List; // possible values a field can have (used by FieldInfo's only) + fieldValues?: List; // possible values a field can have (used by FieldInfo's only) fieldType?: string; // display type of a field, e.g. string, number, enumeration (used by FieldInfo's only) clipboard?: Doc; @@ -484,7 +485,10 @@ export class DocumentOptions { } export const DocOptions = new DocumentOptions(); + +// eslint-disable-next-line @typescript-eslint/no-namespace export namespace Docs { + // eslint-disable-next-line @typescript-eslint/no-namespace export namespace Prototypes { type LayoutSource = { LayoutString: (key: string) => string }; type PrototypeTemplate = { @@ -492,7 +496,6 @@ export namespace Docs { view: LayoutSource; dataField: string; }; - data?: any; options?: Partial; }; type TemplateMap = Map; @@ -554,7 +557,7 @@ export namespace Docs { const actualProtos = await DocServer.GetRefFields(prototypeIds); // update this object to include any default values: DocumentOptions for all prototypes prototypeIds.forEach(id => { - const existing = actualProtos[id] as Doc; + const existing = actualProtos.get(id); const type = id.replace(suffix, '') as DocumentType; // get or create prototype of the specified type... const target = buildPrototype(type, id, existing); @@ -627,16 +630,15 @@ export namespace Docs { acl_Guest: SharingPermissions.View, ...(template.options || {}), layout: layout.view?.LayoutString(layout.dataField), - data: template.data, }; Object.entries(options) .filter(pair => typeof pair[1] === 'string' && pair[1].startsWith('@')) .forEach(pair => { if (!existing || ScriptCast(existing[pair[0]])?.script.originalScript !== pair[1].substring(1)) { - (options as any)[pair[0]] = ComputedField.MakeFunction(pair[1].substring(1)); + (options as { [key: string]: unknown })[pair[0]] = ComputedField.MakeFunction(pair[1].substring(1)); } }); - return Doc.assign(existing ?? new Doc(prototypeId, true), OmitKeys(options, Object.keys(existing ?? {})).omit, undefined, true); + return Doc.assign(existing ?? new Doc(prototypeId, true), OmitKeys(options, Object.keys(existing ?? {})).omit as { [key: string]: FieldType }, undefined, true); } } @@ -644,6 +646,7 @@ export namespace Docs { * Encapsulates the factory used to create new document instances * delegated from top-level prototypes */ + // eslint-disable-next-line @typescript-eslint/no-namespace export namespace Create { /** * This function receives the relevant document prototype and uses @@ -667,10 +670,10 @@ export namespace Docs { function InstanceFromProto(proto: Doc, data: FieldType | undefined, options: DocumentOptions, delegId?: string, fieldKey: string = 'data', protoId?: string, placeholderDocIn?: Doc, noView?: boolean) { const placeholderDoc = placeholderDocIn; const viewKeys = ['x', 'y', 'isSystem']; // keys that should be addded to the view document even though they don't begin with an "_" - const { omit: dataProps, extract: viewProps } = OmitKeys(options, viewKeys, '^_'); + const { omit: dataProps, extract: viewProps } = OmitKeys(options, viewKeys, '^_') as { omit: { [key: string]: FieldType | undefined }; extract: { [key: string]: FieldType | undefined } }; // dataProps.acl_Override = SharingPermissions.Unset; - dataProps.acl_Guest = options.acl_Guest ?? (Doc.defaultAclPrivate ? SharingPermissions.None : SharingPermissions.View); + dataProps.acl_Guest = options.acl_Guest?.toString() ?? (Doc.defaultAclPrivate ? SharingPermissions.None : SharingPermissions.View); dataProps.isSystem = viewProps.isSystem; dataProps.isDataDoc = true; dataProps.author = ClientUtils.CurrentUserEmail(); @@ -693,7 +696,7 @@ export namespace Docs { } if (!noView) { - const viewFirstProps: { [id: string]: any } = { author: ClientUtils.CurrentUserEmail() }; + const viewFirstProps: { [id: string]: FieldType } = { author: ClientUtils.CurrentUserEmail() }; viewFirstProps.acl_Guest = options._acl_Guest ?? (Doc.defaultAclPrivate ? SharingPermissions.None : SharingPermissions.View); let viewDoc: Doc; // determines whether viewDoc should be created using placeholder Doc or default @@ -710,7 +713,7 @@ export namespace Docs { viewDoc = Doc.assign(Doc.MakeDelegate(dataDoc, delegId), viewFirstProps, true, true); } Doc.assign(viewDoc, viewProps, true, true); - if (![DocumentType.LINK, DocumentType.CONFIG, DocumentType.LABEL].includes(viewDoc.type as any)) { + if (![DocumentType.LINK, DocumentType.CONFIG, DocumentType.LABEL].includes(viewDoc.type as DocumentType)) { CreateLinkToActiveAudio(() => viewDoc); } updateCachedAcls(dataDoc); @@ -909,7 +912,7 @@ export namespace Docs { } export function ConfigDocument(options: DocumentOptions, id?: string) { - return InstanceFromProto(Prototypes.get(DocumentType.CONFIG), options?.data, options, id, '', undefined, undefined, true); + return InstanceFromProto(Prototypes.get(DocumentType.CONFIG), undefined, options, id, '', undefined, undefined, true); } export function PileDocument(documents: Array, options: DocumentOptions, id?: string) { diff --git a/src/client/util/CalendarManager.tsx b/src/client/util/CalendarManager.tsx index 77cf80151..d0cd69273 100644 --- a/src/client/util/CalendarManager.tsx +++ b/src/client/util/CalendarManager.tsx @@ -1,5 +1,3 @@ -/* eslint-disable jsx-a11y/no-static-element-interactions */ -/* eslint-disable jsx-a11y/click-events-have-key-events */ import { DateRangePicker, Provider, defaultTheme } from '@adobe/react-spectrum'; import { IconLookup, faPlus } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; @@ -19,6 +17,7 @@ import { DocumentView } from '../views/nodes/DocumentView'; import { TaskCompletionBox } from '../views/nodes/TaskCompletedBox'; import './CalendarManager.scss'; import { SnappingManager } from './SnappingManager'; +import { CalendarDate, DateValue } from '@internationalized/date'; // import 'react-date-range/dist/styles.css'; // import 'react-date-range/dist/theme/default.css'; @@ -29,7 +28,7 @@ interface CalendarSelectOptions { value: string; } -const formatCalendarDateToString = (calendarDate: any) => { +const formatCalendarDateToString = (calendarDate: DateValue) => { console.log('Formatting the following date: ', calendarDate); const date = new Date(calendarDate.year, calendarDate.month - 1, calendarDate.day); console.log(typeof date); @@ -44,7 +43,7 @@ const formatCalendarDateToString = (calendarDate: any) => { // TODO: For a doc already in a calendar: give option to edit date range, delete from calendar @observer -export class CalendarManager extends ObservableReactComponent<{}> { +export class CalendarManager extends ObservableReactComponent { // eslint-disable-next-line no-use-before-define public static Instance: CalendarManager; @observable private isOpen = false; @@ -101,7 +100,7 @@ export class CalendarManager extends ObservableReactComponent<{}> { this.layoutDocAcls = false; }); - constructor(props: {}) { + constructor(props: object) { super(props); CalendarManager.Instance = this; makeObservable(this); @@ -109,15 +108,6 @@ export class CalendarManager extends ObservableReactComponent<{}> { componentDidMount(): void {} - @action - handleSelectChange = (option: any) => { - if (option) { - const selectOpt = option as CalendarSelectOptions; - this.selectedExistingCalendarOption = selectOpt; - this.calendarName = selectOpt.value; // or label - } - }; - @action handleCalendarTitleChange = (event: React.ChangeEvent) => { console.log('Existing calendars: ', this.existingCalendars); @@ -212,15 +202,13 @@ export class CalendarManager extends ObservableReactComponent<{}> { }; @observable - selectedDateRange: any = [ - { - start: new Date(), - end: new Date(), - }, - ]; + selectedDateRange: { start: DateValue; end: DateValue } = { + start: new CalendarDate(2024, 1, 1), + end: new CalendarDate(2024, 1, 1), + }; @action - setSelectedDateRange = (range: any) => { + setSelectedDateRange = (range: { start: DateValue; end: DateValue }) => { console.log('Range: ', range); this.selectedDateRange = range; }; @@ -228,14 +216,14 @@ export class CalendarManager extends ObservableReactComponent<{}> { @computed get createButtonActive() { if (this.calendarName.length === 0 || this.errorMessage.length > 0) return false; // disabled if no calendar name - let startDate: Date | undefined; - let endDate: Date | undefined; + let startDate: DateValue | undefined; + let endDate: DateValue | undefined; try { startDate = this.selectedDateRange.start; endDate = this.selectedDateRange.end; console.log(startDate); console.log(endDate); - } catch (e: any) { + } catch (e) { console.log(e); return false; // disabled } @@ -288,7 +276,13 @@ export class CalendarManager extends ObservableReactComponent<{}> { isSearchable options={this.selectOptions} value={this.selectedExistingCalendarOption} - onChange={this.handleSelectChange} + onChange={change => { + if (change) { + const selectOpt = change; + this.selectedExistingCalendarOption = selectOpt; + this.calendarName = selectOpt.value; // or label + } + }} styles={{ control: () => ({ display: 'inline-flex', diff --git a/src/client/util/CaptureManager.tsx b/src/client/util/CaptureManager.tsx index 253cdd8b5..47f31612f 100644 --- a/src/client/util/CaptureManager.tsx +++ b/src/client/util/CaptureManager.tsx @@ -1,26 +1,24 @@ -/* eslint-disable jsx-a11y/no-static-element-interactions */ -/* eslint-disable jsx-a11y/click-events-have-key-events */ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { action, computed, makeObservable, observable } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; import { addStyleSheet } from '../../ClientUtils'; -import { Doc } from '../../fields/Doc'; +import { Doc, Opt } from '../../fields/Doc'; import { DocCast, StrCast } from '../../fields/Types'; import { MainViewModal } from '../views/MainViewModal'; import { DocumentView } from '../views/nodes/DocumentView'; import './CaptureManager.scss'; @observer -export class CaptureManager extends React.Component<{}> { +export class CaptureManager extends React.Component { // eslint-disable-next-line no-use-before-define public static Instance: CaptureManager; static _settingsStyle = addStyleSheet(); - @observable _document: any = undefined; + @observable _document: Opt = undefined; @observable isOpen: boolean = false; // whether the CaptureManager is to be displayed or not. // eslint-disable-next-line react/sort-comp - constructor(props: {}) { + constructor(props: object) { super(props); makeObservable(this); CaptureManager.Instance = this; diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts index e095bc659..c99ce1832 100644 --- a/src/client/util/CurrentUserUtils.ts +++ b/src/client/util/CurrentUserUtils.ts @@ -1,7 +1,7 @@ import { reaction, runInAction } from "mobx"; import * as rp from 'request-promise'; import { ClientUtils, OmitKeys } from "../../ClientUtils"; -import { Doc, DocListCast, DocListCastAsync, Opt } from "../../fields/Doc"; +import { Doc, DocListCast, DocListCastAsync, FieldType, Opt } from "../../fields/Doc"; import { DocData } from "../../fields/DocSymbols"; import { InkTool } from "../../fields/InkField"; import { List } from "../../fields/List"; @@ -60,11 +60,10 @@ interface Button { // fields that do not correspond to DocumentOption fields scripts?: { script?: string; onClick?: string; onDoubleClick?: string } - funcs?: { [key:string]: any}; + funcs?: { [key:string]: string}; subMenu?: Button[]; } -// eslint-disable-next-line import/no-mutable-exports export let resolvedPorts: { server: number, socket: number }; export class CurrentUserUtils { @@ -174,8 +173,8 @@ export class CurrentUserUtils { const imageBox = (opts: DocumentOptions, fieldKey:string) => Docs.Create.ImageDocument( "http://www.cs.brown.edu/~bcz/noImage.png", { layout:ImageBox.LayoutString(fieldKey), "icon_nativeWidth": 360 / 4, "icon_nativeHeight": 270 / 4, iconTemplate:DocumentType.IMG, _width: 360 / 4, _height: 270 / 4, _layout_showTitle: "title", ...opts }); const fontBox = (opts:DocumentOptions, fieldKey:string) => Docs.Create.FontIconDocument({ layout:FontIconBox.LayoutString(fieldKey), _nativeHeight: 30, _nativeWidth: 30, _width: 30, _height: 30, ...opts }); - const makeIconTemplate = (type: DocumentType | undefined, templateField: string, opts:DocumentOptions) => { - const title = "icon" + (type ? "_" + type : ""); + const makeIconTemplate = (name: DocumentType | string | undefined, templateField: string, opts:DocumentOptions) => { + const title = "icon" + (name ? "_" + name : ""); const curIcon = DocCast(templateIconsDoc[title]); const creator = (() => { switch (opts.iconTemplate) { case DocumentType.IMG : return imageBox; @@ -189,6 +188,10 @@ export class CurrentUserUtils { {onClick:"deiconifyView(documentView)", onDoubleClick: "deiconifyViewToLightbox(documentView)", }); }; const iconTemplates = [ + // see createCustomView for where icon templates are created at run time + // templates defined by a Docs icon_fieldKey (e.g., ink with a transciprtion shows a template of the transcribed text, not miniature ink) + makeIconTemplate("transcription", "text", { iconTemplate:DocumentType.LABEL, backgroundColor: "orange" }), + // templates defined by a Doc's type makeIconTemplate(undefined, "title", { iconTemplate:DocumentType.LABEL, backgroundColor: "dimgray"}), makeIconTemplate(DocumentType.AUDIO, "title", { iconTemplate:DocumentType.LABEL, backgroundColor: "lightgreen"}), makeIconTemplate(DocumentType.PDF, "title", { iconTemplate:DocumentType.LABEL, backgroundColor: "pink"}), @@ -199,10 +202,9 @@ export class CurrentUserUtils { makeIconTemplate(DocumentType.COL, "icon", { iconTemplate:DocumentType.IMG}), makeIconTemplate(DocumentType.VID, "icon", { iconTemplate:DocumentType.IMG}), makeIconTemplate(DocumentType.BUTTON,"title", { iconTemplate:DocumentType.FONTICON}), - // nasty hack .. templates are looked up exclusively by type -- but we want a template for a document with a certain field (transcription) .. so this hack and the companion hack in createCustomView does this for now - makeIconTemplate("transcription" as any, "transcription", { iconTemplate:DocumentType.LABEL, backgroundColor: "orange" }), - // makeIconTemplate(DocumentType.PDF, "icon", {iconTemplate:DocumentType.IMG}, (opts) => imageBox("http://www.cs.brown.edu/~bcz/noImage.png", opts)) - ].filter(d => d).map(d => d!); + // makeIconTemplate(DocumentType.PDF, "icon", { iconTemplate:DocumentType.IMG}), + ].filter(d => d).map(d => d!); + DocUtils.AssignOpts(DocCast(doc[field]), {}, iconTemplates); } @@ -349,9 +351,9 @@ pie title Minerals in my tap water plotlyApi(); mermaidsApi(); const emptyThings:{key:string, // the field name where the empty thing will be stored opts:DocumentOptions, // the document options that are required for the empty thing - funcs?:{[key:string]: any}, // computed fields that are rquired for the empth thing - scripts?:{[key:string]: any}, - creator:(opts:DocumentOptions)=> any // how to create the empty thing if it doesn't exist + funcs?:{[key:string]: string}, // computed fields that are rquired for the empth thing + scripts?:{[key:string]: string}, + creator:(opts:DocumentOptions)=> Doc // how to create the empty thing if it doesn't exist }[] = [ {key: "Note", creator: opts => Docs.Create.TextDocument("", opts), opts: { _width: 200, _layout_autoHeight: true }}, {key: "Flashcard", creator: opts => Docs.Create.ComparisonDocument("", opts), opts: { _layout_isFlashcard: true, _width: 300, _height: 300}}, @@ -402,7 +404,7 @@ pie title Minerals in my tap water { toolTip: "Tap or drag to create a collection", title: "Col", icon: "folder", dragFactory: doc.emptyCollection as Doc, clickFactory: DocCast(doc.emptyTab)}, { toolTip: "Tap or drag to create a webpage", title: "Web", icon: "globe-asia", dragFactory: doc.emptyWebpage as Doc, clickFactory: DocCast(doc.emptyWebpage)}, { toolTip: "Tap or drag to create a comparison box", title: "Compare", icon: "columns", dragFactory: doc.emptyComparison as Doc, clickFactory: DocCast(doc.emptyComparison)}, - { toolTip: "Tap or drag to create a diagram", title: "Diagram", icon: "tree", dragFactory: doc.emptyDiagram as Doc, clickFactory: DocCast(doc.emptyDiagram)}, + { toolTip: "Tap or drag to create a diagram", title: "Diagram", icon: "tree", dragFactory: doc.emptyDiagram as Doc, clickFactory: DocCast(doc.emptyDiagram)}, { toolTip: "Tap or drag to create an audio recorder", title: "Audio", icon: "microphone", dragFactory: doc.emptyAudio as Doc, clickFactory: DocCast(doc.emptyAudio), openFactoryLocation: OpenWhere.overlay}, { toolTip: "Tap or drag to create a map", title: "Map", icon: "map-marker-alt", dragFactory: doc.emptyMap as Doc, clickFactory: DocCast(doc.emptyMap)}, { toolTip: "Tap or drag to create a chat assistant", title: "Assistant Chat", icon: "book",dragFactory: doc.emptyChat as Doc, clickFactory: DocCast(doc.emptyChat)}, @@ -411,11 +413,11 @@ pie title Minerals in my tap water { toolTip: "Tap or drag to create a button", title: "Button", icon: "circle", dragFactory: doc.emptyButton as Doc, clickFactory: DocCast(doc.emptyButton)}, { toolTip: "Tap or drag to create a scripting box", title: "Script", icon: "terminal", dragFactory: doc.emptyScript as Doc, clickFactory: DocCast(doc.emptyScript), funcs: { hidden: "IsNoviceMode()"}}, { toolTip: "Tap or drag to create a data viz node", title: "DataViz", icon: "chart-bar", dragFactory: doc.emptyDataViz as Doc, clickFactory: DocCast(doc.emptyDataViz)}, - { toolTip: "Tap or drag to create a bullet slide", title: "PPT Slide", icon: "person-chalkboard", dragFactory: doc.emptySlide as Doc, clickFactory: DocCast(doc.emptySlide), openFactoryLocation: OpenWhere.overlay, funcs: { hidden: "IsNoviceMode()"}}, - { toolTip: "Tap or drag to create a view slide", title: "View Slide", icon: "address-card", dragFactory: doc.emptyViewSlide as Doc,clickFactory: DocCast(doc.emptyViewSlide),openFactoryLocation: OpenWhere.overlay,funcs: { hidden: "IsNoviceMode()"}}, - { toolTip: "Tap or drag to create a data note", title: "DataNote", icon: "window-maximize",dragFactory: doc.emptyHeader as Doc,clickFactory: DocCast(doc.emptyHeader), openFactoryAsDelegate: true, funcs: { hidden: "IsNoviceMode()"} }, - { toolTip: "Toggle a Calculator REPL", title: "replviewer", icon: "calculator", clickFactory: '' as any, openFactoryLocation: OpenWhere.overlay}, // hack: clickFactory is not a Doc but will get interpreted as a custom UI by the openDoc() onClick script - // { toolTip: "Toggle an UndoStack", title: "undostacker", icon: "calculator", clickFactory: "" as any, openFactoryLocation: OpenWhere.overlay}, + { toolTip: "Tap or drag to create a bullet slide", title: "PPT Slide", icon: "person-chalkboard",dragFactory: doc.emptySlide as Doc,clickFactory: DocCast(doc.emptySlide), openFactoryLocation: OpenWhere.overlay, funcs: { hidden: "IsNoviceMode()"}}, + { toolTip: "Tap or drag to create a view slide", title: "View Slide", icon: "address-card", dragFactory: doc.emptyViewSlide as Doc,clickFactory: DocCast(doc.emptyViewSlide), openFactoryLocation: OpenWhere.overlay,funcs: { hidden: "IsNoviceMode()"}}, + { toolTip: "Tap or drag to create a data note", title: "DataNote", icon: "window-maximize",dragFactory: doc.emptyHeader as Doc,clickFactory: DocCast(doc.emptyHeader), openFactoryAsDelegate: true, funcs: { hidden: "IsNoviceMode()"} }, + { toolTip: "Toggle a Calculator REPL", title: "replviewer", icon: "calculator", clickFactory: '' as unknown as Doc, openFactoryLocation: OpenWhere.overlay}, // hack: clickFactory is not a Doc but will get interpreted as a custom UI by the openDoc() onClick script + // { toolTip: "Toggle an UndoStack", title: "undostacker", icon: "calculator", clickFactory: "" as any, openFactoryLocation: OpenWhere.overlay}, ].map(tuple => ( { openFactoryLocation: OpenWhere.addRight, scripts: { onClick: 'openDoc(copyDragFactory(this.clickFactory,this.openFactoryAsDelegate), this.openFactoryLocation)', @@ -445,7 +447,7 @@ pie title Minerals in my tap water } /// returns descriptions needed to buttons for the left sidebar to open up panes displaying different collections of documents - static leftSidebarMenuBtnDescriptions(doc: Doc):{title:string, target:Doc, icon:string, toolTip: string, scripts:{[key:string]:any}, funcs?:{[key:string]:any}, hidden?: boolean}[] { + static leftSidebarMenuBtnDescriptions(doc: Doc):{title:string, target:Doc, icon:string, toolTip: string, scripts:{[key:string]:undefined|string}, funcs?:{[key:string]:undefined|string}, hidden?: boolean}[] { const badgeValue = "((len) => len && len !== '0' ? len: undefined)(docList(this.target?.data).filter(doc => !docList(this.target.viewed).includes(doc)).length.toString())"; const getActiveDashTrails = "Doc.ActiveDashboard?.myTrails"; return [ @@ -463,7 +465,7 @@ pie title Minerals in my tap water /// the empty panel that is filled with whichever left menu button's panel has been selected static setupLeftSidebarPanel(doc: Doc, field="myLeftSidebarPanel") { - DocUtils.AssignDocField(doc, field, (opts) => Doc.assign(new Doc(), opts as any), {title:"leftSidebarPanel", isSystem:true, undoIgnoreFields: new List(['proto'])}); + DocUtils.AssignDocField(doc, field, (opts) => Doc.assign(new Doc(), opts as {[key:string]: FieldType}), {title:"leftSidebarPanel", isSystem:true, undoIgnoreFields: new List(['proto'])}); } /// Initializes the left sidebar menu buttons and the panels they open up @@ -523,7 +525,7 @@ pie title Minerals in my tap water const contextMenuLabels = [/* "Create New Dashboard" */] as string[]; const contextMenuIcons = [/* "plus" */] as string[]; const childContextMenuScripts = [`toggleComicMode()`, `snapshotDashboard()`, `shareDashboard(this)`, 'removeDashboard(this)', 'resetDashboard(this)']; // entries must be kept in synch with childContextMenuLabels, childContextMenuIcons, and childContextMenuFilters - const childContextMenuFilters = ['!IsNoviceMode()', '!IsNoviceMode()', undefined as any, undefined as any, '!IsNoviceMode()'];// entries must be kept in synch with childContextMenuLabels, childContextMenuIcons, and childContextMenuScripts + const childContextMenuFilters = ['!IsNoviceMode()', '!IsNoviceMode()', undefined, undefined, '!IsNoviceMode()'];// entries must be kept in synch with childContextMenuLabels, childContextMenuIcons, and childContextMenuScripts const childContextMenuLabels = ["Toggle Comic Mode", "Snapshot Dashboard", "Share Dashboard", "Remove Dashboard", "Reset Dashboard"];// entries must be kept in synch with childContextMenuScripts, childContextMenuIcons, and childContextMenuFilters const childContextMenuIcons = ["tv", "camera", "users", "times", "trash"]; // entries must be kept in synch with childContextMenuScripts, childContextMenuLabels, and childContextMenuFilters const reqdOpts:DocumentOptions = { @@ -545,7 +547,7 @@ pie title Minerals in my tap water myDashboards.childContextMenuScripts = new List(childContextMenuScripts.map(script => ScriptField.MakeFunction(script)!)); } if (Cast(myDashboards.childContextMenuFilters, listSpec(ScriptField), null)?.length !== childContextMenuFilters.length) { - myDashboards.childContextMenuFilters = new List(childContextMenuFilters.map(script => !script ? script: ScriptField.MakeFunction(script)!)); + myDashboards.childContextMenuFilters = new List(childContextMenuFilters.map(script => !script ? script as unknown as ScriptField: ScriptField.MakeFunction(script)!)); } return myDashboards; } @@ -611,7 +613,7 @@ pie title Minerals in my tap water _lockedPosition: true, isSystem: true, flexDirection: "row" }) static multiToggleList = (opts: DocumentOptions, docs: Doc[]) => Docs.Create.FontIconDocument({ - ...opts, data:docs, _gridGap: 0, _xMargin: 5, _yMargin: 5, layout_boxShadow: "0 0", _forceActive: true, + ...opts, data: new List(docs), _gridGap: 0, _xMargin: 5, _yMargin: 5, layout_boxShadow: "0 0", _forceActive: true, dropConverter: ScriptField.MakeScript("convertToButtons(dragData)", { dragData: DragManager.DocumentDragData.name }), _lockedPosition: true, isSystem: true, flexDirection: "row" }) @@ -806,7 +808,7 @@ pie title Minerals in my tap water /// initializes a context menu button for the top bar context menu static setupContextMenuButton(params:Button, btnDoc?:Doc, btnContainer?:Doc) { const reqdOpts:DocumentOptions = { - ...OmitKeys(params, ["scripts", "funcs", "subMenu"]).omit, + ...OmitKeys(params, ["scripts", "funcs", "subMenu"]).omit as {[key:string]: string|undefined}, color: Colors.WHITE, isSystem: true, _nativeWidth: params.width ?? 30, _width: params.width ?? 30, _height: 30, _nativeHeight: 30, linearBtnWidth: params.linearBtnWidth, @@ -814,7 +816,7 @@ pie title Minerals in my tap water _dragOnlyWithinContainer: true, _lockedPosition: true, _embedContainer: btnContainer }; - const reqdFuncs:{[key:string]:any} = { + const reqdFuncs:{[key:string]:string} = { ...params.funcs, } return DocUtils.AssignScripts(DocUtils.AssignOpts(btnDoc, reqdOpts) ?? Docs.Create.FontIconDocument(reqdOpts), params.scripts, reqdFuncs); @@ -853,14 +855,14 @@ pie title Minerals in my tap water Doc.UserDoc().workspaceRecordingState = undefined; Doc.UserDoc().workspaceReplayingState = undefined; const dockedBtns = DocCast(doc[field]); - const dockBtn = (opts: DocumentOptions, scripts: {[key:string]:string|undefined}, funcs?: {[key:string]:any}) => + const dockBtn = (opts: DocumentOptions, scripts: {[key:string]:string|undefined}, funcs?: {[key:string]:string|undefined}) => DocUtils.AssignScripts(DocUtils.AssignOpts(DocListCast(dockedBtns?.data)?.find(fdoc => fdoc.title === opts.title), opts) ?? CurrentUserUtils.createToolButton(opts), scripts, funcs); const btnDescs = [// setup reactions to change the highlights on the undo/redo buttons -- would be better to encode this in the undo/redo buttons, but the undo/redo stacks are not wired up that way yet - { opts: { title: "Replicate",icon:"camera",toolTip: "Copy dashboard layout",btnType: ButtonType.ClickButton, expertMode: true}, scripts: { onClick: `snapshotDashboard()`}}, - { opts: { title: "Recordings", toolTip: "Workspace Recordings", btnType: ButtonType.DropdownList,expertMode: false, ignoreClick: true, width: 100}, funcs: {hidden: `false`, btnList:`getWorkspaceRecordings()`}, scripts: { script: `{ return replayWorkspace(value, _readOnly_); }`, onDragScript: `{ return startRecordingDrag(value); }`}}, - { opts: { title: "Stop Rec",icon: "stop", toolTip: "Stop recording", btnType: ButtonType.ClickButton, expertMode: false}, funcs: {hidden: `!isWorkspaceRecording()`}, scripts: { onClick: `stopWorkspaceRecording()`}}, + { opts: { title: "Replicate",icon:"camera",toolTip: "Copy dashboard layout",btnType: ButtonType.ClickButton, expertMode: true}, scripts: { onClick: `snapshotDashboard()`}}, + { opts: { title: "Recordings", toolTip: "Workspace Recordings", btnType: ButtonType.DropdownList,expertMode: false, ignoreClick: true, width: 100}, funcs: {hidden: `false`, btnList:`getWorkspaceRecordings()`},scripts: { script: `{ return replayWorkspace(value, _readOnly_); }`, onDragScript: `{ return startRecordingDrag(value); }`}}, + { opts: { title: "Stop Rec",icon: "stop", toolTip: "Stop recording", btnType: ButtonType.ClickButton, expertMode: false}, funcs: {hidden: `!isWorkspaceRecording()`}, scripts: { onClick: `stopWorkspaceRecording()`}}, { opts: { title: "Play", icon: "play", toolTip: "Play recording", btnType: ButtonType.ClickButton, expertMode: false}, funcs: {hidden: `isWorkspaceReplaying() !== "${mediaState.Paused}"`}, scripts: { onClick: `resumeWorkspaceReplaying(getCurrentRecording())`}}, { opts: { title: "Pause", icon: "pause",toolTip: "Pause playback", btnType: ButtonType.ClickButton, expertMode: false}, funcs: {hidden: `isWorkspaceReplaying() !== "${mediaState.Playing}"`}, scripts: { onClick: `pauseWorkspaceReplaying(getCurrentRecording())`}}, { opts: { title: "Stop", icon: "stop", toolTip: "Stop playback", btnType: ButtonType.ClickButton, expertMode: false}, funcs: {hidden: `isWorkspaceReplaying() !== "${mediaState.Paused}"`}, scripts: { onClick: `stopWorkspaceReplaying(getCurrentRecording())`}}, @@ -1002,20 +1004,20 @@ pie title Minerals in my tap water return doc; } static setupFieldInfos(doc:Doc, field="fieldInfos") { - const fieldInfoOpts = { title: "Field Infos", isSystem: true}; // bcz: all possible document options have associated field infos which are stored onn the FieldInfos document **except for title and system which are used as part of the definition of the fieldInfos object - const infos = DocUtils.AssignDocField(doc, field, opts => Doc.assign(new Doc(), opts as any), fieldInfoOpts); + const fieldInfoOpts = { title: "Field Infos", isSystem: true}; // bcz: all possible document options have associated field infos which are stored on the FieldInfos document **except for title and system which are used as part of the definition of the fieldInfos object + const infos = DocUtils.AssignDocField(doc, field, opts => Doc.assign(new Doc(), opts as {[key:string]: FieldType}), fieldInfoOpts); const entries = Object.entries(new DocumentOptions()); entries.forEach(pair => { if (!Array.from(Object.keys(fieldInfoOpts)).includes(pair[0])) { const options = pair[1] as FInfo; - const opts:DocumentOptions = { isSystem: true, title: pair[0], ...OmitKeys(options, ["values"]).omit, fieldIsLayout: pair[0].startsWith("_")}; + const opts:DocumentOptions = { isSystem: true, title: pair[0], ...OmitKeys(options, ["values"]).omit}; switch (options.fieldType) { - case FInfoFieldType.boolean: opts.fieldValues = new List(options.values as any); break; - case FInfoFieldType.number: opts.fieldValues = new List(options.values as any); break; - case FInfoFieldType.Doc: opts.fieldValues = new List(options.values as any); break; - default: opts.fieldValues = new List(options.values as any); break;// string, pointerEvents, dimUnit, dropActionType + case FInfoFieldType.boolean: opts.fieldValues = new List(options.values as boolean[]); break; + case FInfoFieldType.number: opts.fieldValues = new List(options.values as number[]); break; + case FInfoFieldType.Doc: opts.fieldValues = new List(options.values as Doc[]); break; + default: opts.fieldValues = new List(options.values); break;// string, pointerEvents, dimUnit, dropActionType } - DocUtils.AssignDocField(infos, pair[0], docOpts => Doc.assign(new Doc(), OmitKeys(docOpts,["values"]).omit), opts); + DocUtils.AssignDocField(infos, pair[0], docOpts => Doc.assign(new Doc(), OmitKeys(docOpts,["values"]).omit as {[key:string]: FieldType}), opts); } }); } @@ -1023,10 +1025,10 @@ pie title Minerals in my tap water public static async loadCurrentUser() { return rp.get(ClientUtils.prepend("/getCurrentUser")).then(async response => { if (response) { - const result: { version: string, userDocumentId: string, sharingDocumentId: string, linkDatabaseId: string, email: string, cacheDocumentIds: string, resolvedPorts: string } = JSON.parse(response); + const result: { version: string, userDocumentId: string, sharingDocumentId: string, linkDatabaseId: string, email: string, cacheDocumentIds: string, resolvedPorts: {server: number, socket: number} } = JSON.parse(response); runInAction(() => { SnappingManager.SetServerVersion(result.version); }); ClientUtils.SetCurrentUserEmail(result.email); - resolvedPorts = result.resolvedPorts as any; + resolvedPorts = result.resolvedPorts; DocServer.init(window.location.protocol, window.location.hostname, resolvedPorts?.socket, result.email); if (result.cacheDocumentIds) { diff --git a/src/client/util/DictationManager.ts b/src/client/util/DictationManager.ts index bc9fe813f..16a0df120 100644 --- a/src/client/util/DictationManager.ts +++ b/src/client/util/DictationManager.ts @@ -1,7 +1,5 @@ /* eslint-disable no-use-before-define */ import * as interpreter from 'words-to-numbers'; -// @ts-ignore bcz: how are you supposed to include these definitions since dom-speech-recognition isn't a module? -import type {} from '@types/dom-speech-recognition'; import { ClientUtils } from '../../ClientUtils'; import { Doc, Opt } from '../../fields/Doc'; import { DocData } from '../../fields/DocSymbols'; @@ -33,19 +31,24 @@ import { UndoManager } from './UndoManager'; * In addition to compile-time default commands, you can invoke DictationManager.Commands.Register(Independent|Dependent) * to add new commands as classes or components are constructed. */ + +// eslint-disable-next-line @typescript-eslint/no-namespace export namespace DictationManager { /** * Some type maneuvering to access Webkit's built-in * speech recognizer. */ + + // eslint-disable-next-line @typescript-eslint/no-namespace namespace CORE { export interface IWindow extends Window { - webkitSpeechRecognition: any; + webkitSpeechRecognition: { new (): SpeechRecognition }; } } - const { webkitSpeechRecognition }: CORE.IWindow = window as any as CORE.IWindow; + const { webkitSpeechRecognition }: CORE.IWindow = window as unknown as CORE.IWindow; export const placeholder = 'Listening...'; + // eslint-disable-next-line @typescript-eslint/no-namespace export namespace Controls { export const Infringed = 'unable to process: dictation manager still involved in previous session'; const browser = (() => { @@ -74,7 +77,7 @@ export namespace DictationManager { // eslint-disable-next-line new-cap const recognizer: Opt = webkitSpeechRecognition ? new webkitSpeechRecognition() : undefined; - export type InterimResultHandler = (results: string) => any; + export type InterimResultHandler = (results: string) => void; export type ContinuityArgs = { indefinite: boolean } | false; export type DelimiterArgs = { inter: string; intra: string }; export type ListeningUIStatus = { interim: boolean } | false; @@ -117,11 +120,11 @@ export namespace DictationManager { } options?.tryExecute && (await DictationManager.Commands.execute(results)); } - } catch (e: any) { + } catch (e) { console.log(e); if (overlay) { DictationOverlay.Instance.isListening = false; - DictationOverlay.Instance.dictatedPhrase = results = `dictation error: ${'error' in e ? e.error : 'unknown error'}`; + DictationOverlay.Instance.dictatedPhrase = results = `dictation error: ${(e as { error: string }).error || 'unknown error'}`; DictationOverlay.Instance.dictationSuccess = false; } } finally { @@ -156,11 +159,11 @@ export namespace DictationManager { recognizer.start(); return new Promise(resolve => { - recognizer.onerror = (e: any) => { + recognizer.onerror = e => { // e is SpeechRecognitionError but where is that defined? if (!(indefinite && e.error === 'no-speech')) { recognizer.stop(); - resolve(e); + resolve(e.message); } }; @@ -227,13 +230,14 @@ export namespace DictationManager { }; } + // eslint-disable-next-line @typescript-eslint/no-namespace export namespace Commands { export const dictationFadeDuration = 2000; - export type IndependentAction = (target: DocumentView) => any | Promise; + export type IndependentAction = (target: DocumentView) => void | Promise; export type IndependentEntry = { action: IndependentAction; restrictTo?: DocumentType[] }; - export type DependentAction = (target: DocumentView, matches: RegExpExecArray) => any | Promise; + export type DependentAction = (target: DocumentView, matches: RegExpExecArray) => void | Promise; export type DependentEntry = { expression: RegExp; action: DependentAction; restrictTo?: DocumentType[] }; export const RegisterIndependent = (key: string, value: IndependentEntry) => Independent.set(key, value); @@ -295,7 +299,6 @@ export namespace DictationManager { [DocumentType.COL, listSpec(Doc)], [DocumentType.AUDIO, AudioField], [DocumentType.IMG, ImageField], - [DocumentType.IMPORT, listSpec(Doc)], [DocumentType.RTF, 'string'], ]); @@ -397,8 +400,8 @@ export namespace DictationManager { ]; } export function recordAudioAnnotation(dataDoc: Doc, field: string, onRecording?: (stop: () => void) => void, onEnd?: () => void) { - let gumStream: any; - let recorder: any; + let gumStream: MediaStream | undefined; + let recorder: MediaRecorder | undefined; navigator.mediaDevices.getUserMedia({ audio: true }).then(stream => { let audioTextAnnos = Cast(dataDoc[field + '_audioAnnotations_text'], listSpec('string'), null); if (audioTextAnnos) audioTextAnnos.push(''); @@ -415,8 +418,12 @@ export namespace DictationManager { gumStream = stream; recorder = new MediaRecorder(stream); - recorder.ondataavailable = async (e: any) => { - const [{ result }] = await Networking.UploadFilesToServer({ file: e.data }); + recorder.ondataavailable = async (e: BlobEvent) => { + const file: Blob & { name?: string; lastModified?: number; webkitRelativePath?: string } = e.data; + file.name = ''; + file.lastModified = 0; + file.webkitRelativePath = ''; + const [{ result }] = await Networking.UploadFilesToServer({ file: file as Blob & { name: string; lastModified: number; webkitRelativePath: string } }); if (!(result instanceof Error)) { const audioField = new AudioField(result.accessPaths.agnostic.client); const audioAnnos = Cast(dataDoc[field + '_audioAnnotations'], listSpec(AudioField), null); @@ -426,10 +433,10 @@ export namespace DictationManager { }; recorder.start(); const stopFunc = () => { - recorder.stop(); + recorder?.stop(); DictationManager.Controls.stop(/* false */); dataDoc.audioAnnoState = AudioAnnoState.stopped; - gumStream.getAudioTracks()[0].stop(); + gumStream?.getAudioTracks()[0].stop(); }; if (onRecording) onRecording(stopFunc); else setTimeout(stopFunc, 5000); diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts index e41546d09..b12bf4390 100644 --- a/src/client/util/DocumentManager.ts +++ b/src/client/util/DocumentManager.ts @@ -50,22 +50,19 @@ export class DocumentManager { DocumentView.getLightboxDocumentView = this.getLightboxDocumentView; observe(Doc.CurrentlyLoading, change => { // watch CurrentlyLoading-- when something is loaded, it's removed from the list and we have to update its icon if it were iconified since LoadingBox icons are different than the media they become - switch (change.type as any) { + switch (change.type) { case 'update': break; - case 'remove': - // DocumentManager.Instance.getAllDocumentViews(change as any).forEach(dv => StrCast(dv.Document.layout_fieldKey) === 'layout_icon' && dv.iconify(() => dv.iconify())); - break; case 'splice': - (change as any).removed.forEach((doc: Doc) => DocumentManager.Instance.getAllDocumentViews(doc).forEach(dv => StrCast(dv.Document.layout_fieldKey) === 'layout_icon' && dv.iconify(() => dv.iconify()))); + change.removed.forEach((doc: Doc) => DocumentManager.Instance.getAllDocumentViews(doc).forEach(dv => StrCast(dv.Document.layout_fieldKey) === 'layout_icon' && dv.iconify(() => dv.iconify()))); break; default: } }); } - private _viewRenderedCbs: { doc: Doc; func: (dv: DocumentView) => any }[] = []; - public AddViewRenderedCb = (doc: Opt, func: (dv: DocumentView) => any) => { + private _viewRenderedCbs: { doc: Doc; func: (dv: DocumentView) => unknown }[] = []; + public AddViewRenderedCb = (doc: Opt, func: (dv: DocumentView) => unknown) => { if (doc) { const dv = DocumentView.LightboxDoc() ? this.getLightboxDocumentView(doc) : this.getDocumentView(doc); this._viewRenderedCbs.push({ doc, func }); @@ -74,6 +71,7 @@ export class DocumentManager { return true; } } else { + // eslint-disable-next-line @typescript-eslint/no-explicit-any func(undefined as any); } return false; @@ -341,18 +339,21 @@ export class DocumentManager { // if there's an options.effect, it will be handled from linkFollowHighlight. We delay the start of // the highlight so that the target document can be somewhat centered so that the effect/highlight will be seen // bcz: should this delay be an options parameter? - setTimeout(() => { - Doc.linkFollowHighlight(viewSpec ? [docView.Document, viewSpec] : docView.Document, undefined, options.effect); - if (options.zoomTextSelections && Doc.IsUnhighlightTimerSet() && contextView && targetDoc.text_html) { - // if the docView is a text anchor, the contextView is the PDF/Web/Text doc - contextView.setTextHtmlOverlay(StrCast(targetDoc.text_html), options.effect); - DocumentManager._overlayViews.add(contextView); - } - Doc.AddUnHighlightWatcher(() => { - docView.Document[Animation] = undefined; - DocumentManager.removeOverlayViews(); - }); - }, (options.zoomTime ?? 0) * 0.5); + setTimeout( + () => { + Doc.linkFollowHighlight(viewSpec ? [docView.Document, viewSpec] : docView.Document, undefined, options.effect); + if (options.zoomTextSelections && Doc.IsUnhighlightTimerSet() && contextView && targetDoc.text_html) { + // if the docView is a text anchor, the contextView is the PDF/Web/Text doc + contextView.setTextHtmlOverlay(StrCast(targetDoc.text_html), options.effect); + DocumentManager._overlayViews.add(contextView); + } + Doc.AddUnHighlightWatcher(() => { + docView.Document[Animation] = undefined; + DocumentManager.removeOverlayViews(); + }); + }, + (options.zoomTime ?? 0) * 0.5 + ); if (options.playMedia) docView.ComponentView?.playFrom?.(NumCast(docView.Document._layout_currentTimecode)); if (options.playAudio) DocumentManager.playAudioAnno(docView.Document); if (options.toggleTarget && (!options.didMove || docView.Document.hidden)) docView.Document.hidden = !docView.Document.hidden; diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts index fda505420..c237a75de 100644 --- a/src/client/util/DragManager.ts +++ b/src/client/util/DragManager.ts @@ -1,4 +1,3 @@ -/* eslint-disable import/no-mutable-exports */ /* eslint-disable no-use-before-define */ /** * The DragManager handles all dragging interactions that occur entirely within Dash (as opposed to external drag operations from the file system, etc) @@ -23,13 +22,14 @@ import { DocData } from '../../fields/DocSymbols'; import { List } from '../../fields/List'; import { PrefetchProxy } from '../../fields/Proxy'; import { ScriptField } from '../../fields/ScriptField'; -import { ScriptCast } from '../../fields/Types'; +import { ScriptCast, StrCast } from '../../fields/Types'; import { Docs } from '../documents/Documents'; import { DocumentView } from '../views/nodes/DocumentView'; import { dropActionType } from './DropActionTypes'; import { SnappingManager } from './SnappingManager'; import { UndoManager } from './UndoManager'; +// eslint-disable-next-line @typescript-eslint/no-var-requires const { contextMenuZindex } = require('../views/global/globalCssVariables.module.scss'); // prettier-ignore /** @@ -70,6 +70,7 @@ export function SetupDrag(_reference: React.RefObject, docFunc: () return onItemDown; } +// eslint-disable-next-line @typescript-eslint/no-namespace export namespace DragManager { export const dragClassName = 'collectionFreeFormDocumentView-container'; let dragDiv: HTMLDivElement; @@ -78,7 +79,7 @@ export namespace DragManager { export let CompleteWindowDrag: Opt<(aborted: boolean) => void>; export let AbortDrag: () => void = emptyFunction; export const docsBeingDragged: Doc[] = observable([]); - export let DocDragData: DocumentDragData | undefined; + export let DraggedDocs: Doc[] | undefined; export function Root() { const root = document.getElementById('root'); @@ -118,7 +119,7 @@ export namespace DragManager { // event called when the drag operation has completed (aborted or completed a drop) -- this will be after any drop event has been generated export class DragCompleteEvent { - constructor(aborted: boolean, dragData: { [id: string]: any }) { + constructor(aborted: boolean, dragData: DocumentDragData | AnchorAnnoDragData | LinkDragData | ColumnDragData) { this.aborted = aborted; this.docDragData = dragData instanceof DocumentDragData ? dragData : undefined; this.annoDragData = dragData instanceof AnchorAnnoDragData ? dragData : undefined; @@ -167,6 +168,9 @@ export namespace DragManager { linkSourceGetAnchor: () => Doc; linkSourceDoc?: Doc; linkDragView: DocumentView; + get canEmbed() { + return true; + } } export class ColumnDragData { // constructor(colKey: SchemaHeaderField) { @@ -177,6 +181,9 @@ export namespace DragManager { this.colIndex = colIndex; } colIndex: number; + get canEmbed() { + return true; + } } // used by PDFs,Text,Image,Video,Web to conditionally (if the drop completes) create a text annotation when dragging the annotate button from the AnchorMenu when a text/region selection has been made. // this is pretty clunky and should be rethought out using linkDrag or DocumentDrag @@ -191,6 +198,9 @@ export namespace DragManager { offset: number[]; dropAction?: dropActionType; userDropAction?: dropActionType; + get canEmbed() { + return true; + } } const defaultPreDropFunc = (e: Event, de: DragManager.DropEvent, targetAction: dropActionType) => { @@ -208,7 +218,7 @@ export namespace DragManager { const handler = (e: Event) => dropFunc(e, (e as CustomEvent).detail); const preDropHandler = (e: Event) => { const de = (e as CustomEvent).detail; - (preDropFunc ?? defaultPreDropFunc)(e, de, doc.dropAction as any as dropActionType); + (preDropFunc ?? defaultPreDropFunc)(e, de, StrCast(doc.dropAction) as dropActionType); }; element.addEventListener('dashOnDrop', handler); element.addEventListener('dashPreDrop', preDropHandler); @@ -220,8 +230,8 @@ export namespace DragManager { } // drag a document and drop it (or make an embed/copy on drop) - export function StartDocumentDrag(eles: HTMLElement[], dragData: DocumentDragData, downX: number, downY: number, options?: DragOptions, onDropCompleted?: (e?: DragCompleteEvent) => any) { - const addAudioTag = (dropDoc: any) => { + export function StartDocumentDrag(eles: HTMLElement[], dragData: DocumentDragData, downX: number, downY: number, options?: DragOptions, onDropCompleted?: (e?: DragCompleteEvent) => unknown) { + const addAudioTag = (dropDoc: Doc) => { dropDoc && !dropDoc.author_date && (dropDoc.author_date = new DateField()); dropDoc instanceof Doc && CreateLinkToActiveAudio(() => dropDoc); return dropDoc; @@ -236,7 +246,7 @@ export namespace DragManager { await Promise.all( dragData.draggedDocuments.map(async d => !dragData.isDocDecorationMove && !dragData.userDropAction && ScriptCast(d.onDragStart) - ? addAudioTag(ScriptCast(d.onDragStart).script.run({ this: d }).result) + ? addAudioTag(ScriptCast(d.onDragStart).script.run({ this: d }).result as Doc) : docDragData.dropAction === dropActionType.embed ? Doc.BestEmbedding(d) : docDragData.dropAction === dropActionType.add @@ -249,7 +259,7 @@ export namespace DragManager { ) ) ).filter(d => d); - ![dropActionType.same, dropActionType.proto].includes(docDragData.dropAction as any) && + ![dropActionType.same, dropActionType.proto].includes(StrCast(docDragData.dropAction) as dropActionType) && docDragData.droppedDocuments // .filter(drop => !drop.dragOnlyWithinContainer || ['embed', 'copy'].includes(docDragData.dropAction as any)) .forEach((drop: Doc, i: number) => { @@ -376,9 +386,18 @@ export namespace DragManager { options?.dragComplete?.(complete); endDrag?.(); } - export function StartDrag(elesIn: HTMLElement[], dragData: { [id: string]: any }, downX: number, downY: number, options?: DragOptions, finishDrag?: (dropData: DragCompleteEvent) => void, dragUndoName?: string) { - if (dragData.dropAction === 'none' || SnappingManager.ExploreMode) return; - DocDragData = dragData as DocumentDragData; + export function StartDrag( + elesIn: HTMLElement[], + dragData: DocumentDragData | LinkDragData | ColumnDragData | AnchorAnnoDragData, + downX: number, + downY: number, + options?: DragOptions, + finishDrag?: (dropData: DragCompleteEvent) => void, + dragUndoName?: string + ) { + if (SnappingManager.ExploreMode) return; + const docDragData = dragData instanceof DocumentDragData ? dragData : undefined; + DraggedDocs = docDragData?.draggedDocuments; const batch = UndoManager.StartBatch(dragUndoName ?? 'document drag'); const eles = elesIn.filter(e => e); SnappingManager.SetCanEmbed(dragData.canEmbed || false); @@ -437,8 +456,9 @@ export namespace DragManager { next && children.push(...Array.from(next.children)); if (next) { ['marker-start', 'marker-mid', 'marker-end'].forEach(field => { - if (next.localName.startsWith('path') && (next.attributes as any)[field]) { - next.setAttribute(field, (next.attributes as any)[field].value.replace('#', '#X')); + if (next.localName.startsWith('path')) { + const item = next.attributes.getNamedItem(field); + item && next.setAttribute(field, item.value.replace('#', '#X')); } }); if (next.localName.startsWith('marker')) { @@ -495,7 +515,7 @@ export namespace DragManager { .map((pb, i) => pb.getContext('2d')!.drawImage(pdfBoxSrc[i], 0, 0)); } [dragElement, ...Array.from(dragElement.getElementsByTagName('*'))] - .map(dele => (dele as any).style) + .map(dele => (dele as HTMLElement)?.style) .forEach(style => { style && (style.pointerEvents = 'none'); }); @@ -536,34 +556,35 @@ export namespace DragManager { const yFromBottom = elesCont.bottom - downY; let scrollAwaiter: Opt; - let startWindowDragTimer: any; + let startWindowDragTimer: NodeJS.Timeout | undefined; const moveHandler = (e: PointerEvent) => { e.preventDefault(); // required or dragging text menu link item ends up dragging the link button as native drag/drop - if (dragData instanceof DocumentDragData) { - dragData.userDropAction = e.ctrlKey && e.altKey ? dropActionType.copy : e.shiftKey ? dropActionType.move : e.ctrlKey ? dropActionType.embed : dragData.defaultDropAction; - } - if (['lm_tab', 'lm_title_wrap', 'lm_tabs', 'lm_header'].includes(typeof (e.target as any).className === 'string' ? (e.target as any)?.className : '') && dragData.draggedDocuments.length === 1) { - if (!startWindowDragTimer) { - startWindowDragTimer = setTimeout(async () => { - startWindowDragTimer = undefined; - dragData.dropAction = dragData.userDropAction || 'same'; - AbortDrag(); - await finishDrag?.(new DragCompleteEvent(true, dragData)); - DragManager.StartWindowDrag?.(e, dragData.droppedDocuments, aborted => { - if (!aborted && (dragData.dropAction === 'move' || dragData.dropAction === 'same')) { - dragData.removeDocument?.(dragData.draggedDocuments[0]); - } - }); - }, 500); + if (docDragData) { + docDragData.userDropAction = e.ctrlKey && e.altKey ? dropActionType.copy : e.shiftKey ? dropActionType.move : e.ctrlKey ? dropActionType.embed : docDragData.defaultDropAction; + const targClassName = e.target instanceof HTMLElement && typeof e.target.className === 'string' ? e.target.className : ''; + if (['lm_tab', 'lm_title_wrap', 'lm_tabs', 'lm_header'].includes(targClassName) && docDragData.draggedDocuments.length === 1) { + if (!startWindowDragTimer) { + startWindowDragTimer = setTimeout(async () => { + startWindowDragTimer = undefined; + docDragData.dropAction = docDragData.userDropAction || dropActionType.same; + AbortDrag(); + await finishDrag?.(new DragCompleteEvent(true, docDragData)); + DragManager.StartWindowDrag?.(e, docDragData.droppedDocuments, aborted => { + if (!aborted && (docDragData?.dropAction === 'move' || docDragData?.dropAction === 'same')) { + docDragData.removeDocument?.(docDragData?.draggedDocuments[0]); + } + }); + }, 500); + } + } else { + clearTimeout(startWindowDragTimer); + startWindowDragTimer = undefined; } - } else { - clearTimeout(startWindowDragTimer); - startWindowDragTimer = undefined; } const target = document.elementFromPoint(e.x, e.y); - if (target && !Doc.UserDoc()._noAutoscroll && !options?.noAutoscroll && !dragData.draggedDocuments?.some((d: any) => d._freeform_noAutoPan)) { + if (target && !Doc.UserDoc()._noAutoscroll && !options?.noAutoscroll && !(docDragData?.draggedDocuments as Doc[])?.some(d => d._freeform_noAutoPan)) { const autoScrollHandler = () => { target.dispatchEvent( new CustomEvent('dashDragMovePause', { @@ -587,7 +608,7 @@ export namespace DragManager { screenX: e.screenX, screenY: e.screenY, detail: e.detail, - view: e.view ? e.view : (new Window() as any), + view: { ...(e.view ?? new Window()), styleMedia: { type: '', matchMedium: () => false } }, // bcz: Ugh.. this looks wrong nativeEvent: new DragEvent('dashDragMovePause'), currentTarget: target, target: target, @@ -596,10 +617,10 @@ export namespace DragManager { defaultPrevented: true, eventPhase: e.eventPhase, isTrusted: true, - preventDefault: () => 'not implemented for this event' && false, - isDefaultPrevented: () => 'not implemented for this event' && false, - stopPropagation: () => 'not implemented for this event' && false, - isPropagationStopped: () => 'not implemented for this event' && false, + preventDefault: () => 'not implemented for this event', + isDefaultPrevented: () => false, + stopPropagation: () => 'not implemented for this event', + isPropagationStopped: () => false, persist: emptyFunction, timeStamp: e.timeStamp, type: 'dashDragMovePause', diff --git a/src/client/util/DropConverter.ts b/src/client/util/DropConverter.ts index 0314af06b..eb2011b77 100644 --- a/src/client/util/DropConverter.ts +++ b/src/client/util/DropConverter.ts @@ -26,9 +26,10 @@ function makeTemplate(doc: Doc, first: boolean = true): boolean { if (layoutDoc.layout instanceof Doc) { return true; // its already a template } - const layout = StrCast(layoutDoc.layout).match(/fieldKey={'[^']*'}/)![0]; - const fieldKey = layout.replace("fieldKey={'", '').replace(/'}$/, ''); - const docs = DocListCast(layoutDoc[fieldKey]); + const layout = StrCast(layoutDoc.layout).match(/fieldKey={'[^']*'}/)?.[0]; + const fieldKey = layout?.replace("fieldKey={'", '').replace(/'}$/, ''); + const docData = fieldKey ? layoutDoc[fieldKey] : undefined; + const docs = DocListCast(docData); let isTemplate = false; docs.forEach(d => { if (!StrCast(d.title).startsWith('-')) { @@ -40,7 +41,7 @@ function makeTemplate(doc: Doc, first: boolean = true): boolean { if (first && !docs.length) { // bcz: feels hacky : if the root level document has items, it's not a field template isTemplate = Doc.MakeMetadataFieldTemplate(doc, layoutDoc[DocData], true) || isTemplate; - } else if (layoutDoc[fieldKey] instanceof RichTextField || layoutDoc[fieldKey] instanceof ImageField) { + } else if (docData instanceof RichTextField || docData instanceof ImageField) { if (!StrCast(layoutDoc.title).startsWith('-')) { isTemplate = Doc.MakeMetadataFieldTemplate(layoutDoc, layoutDoc[DocData], true); } @@ -110,8 +111,8 @@ export function convertDropDataToButtons(data: DragManager.DocumentDragData) { } ScriptingGlobals.add( // eslint-disable-next-line prefer-arrow-callback - function convertToButtons(dragData: any) { - convertDropDataToButtons(dragData as DragManager.DocumentDragData); + function convertToButtons(dragData: DragManager.DocumentDragData) { + convertDropDataToButtons(dragData); }, 'converts the dropped data to buttons', '(dragData: any)' diff --git a/src/client/util/GroupManager.tsx b/src/client/util/GroupManager.tsx index 5701a22c0..9d0817a06 100644 --- a/src/client/util/GroupManager.tsx +++ b/src/client/util/GroupManager.tsx @@ -1,8 +1,6 @@ -/* eslint-disable jsx-a11y/no-static-element-interactions */ -/* eslint-disable jsx-a11y/click-events-have-key-events */ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { Button, IconButton, Size, Type } from 'browndash-components'; -import { action, computed, makeObservable, observable } from 'mobx'; +import { action, computed, makeObservable, observable, runInAction } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; import Select from 'react-select'; @@ -31,7 +29,7 @@ export interface UserOptions { } @observer -export class GroupManager extends ObservableReactComponent<{}> { +export class GroupManager extends ObservableReactComponent { // eslint-disable-next-line no-use-before-define static Instance: GroupManager; @observable isOpen: boolean = false; // whether the GroupManager is to be displayed or not. @@ -44,7 +42,7 @@ export class GroupManager extends ObservableReactComponent<{}> { @observable private buttonColour: '#979797' | 'black' = '#979797'; @observable private groupSort: 'ascending' | 'descending' | 'none' = 'none'; - constructor(props: Readonly<{}>) { + constructor(props: Readonly) { super(props); makeObservable(this); GroupManager.Instance = this; @@ -226,15 +224,6 @@ export class GroupManager extends ObservableReactComponent<{}> { } } - /** - * Handles changes in the users selected in the "Select users" dropdown. - * @param selectedOptions - */ - @action - handleChange = (selectedOptions: any) => { - this.selectedUsers = selectedOptions as UserOptions[]; - }; - /** * Creates the group when the enter key has been pressed (when in the input). * @param e @@ -309,7 +298,6 @@ export class GroupManager extends ObservableReactComponent<{}> { { className="select-users" isMulti options={this.options} - onChange={this.handleChange} + onChange={selectedOptions => { + runInAction(() => (this.selectedUsers = Array.from(selectedOptions))); + }} placeholder="Select users" value={this.selectedUsers} closeMenuOnSelect={false} diff --git a/src/client/util/GroupMemberView.tsx b/src/client/util/GroupMemberView.tsx index da9e1aa28..88d73d742 100644 --- a/src/client/util/GroupMemberView.tsx +++ b/src/client/util/GroupMemberView.tsx @@ -1,5 +1,3 @@ -/* eslint-disable jsx-a11y/no-static-element-interactions */ -/* eslint-disable jsx-a11y/click-events-have-key-events */ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { Button, IconButton, Size, Type } from 'browndash-components'; import { action, observable } from 'mobx'; diff --git a/src/client/util/History.ts b/src/client/util/History.ts index 52d0223d5..067c28c6b 100644 --- a/src/client/util/History.ts +++ b/src/client/util/History.ts @@ -10,6 +10,7 @@ import { OmitKeys, ClientUtils } from '../../ClientUtils'; import { DocServer } from '../DocServer'; import { DashboardView } from '../views/DashboardView'; +// eslint-disable-next-line @typescript-eslint/no-namespace export namespace HistoryUtil { export interface DocInitializerList { [key: string]: string | number; @@ -85,7 +86,7 @@ export namespace HistoryUtil { const parsers: { [type: string]: (pathname: string[], opts: qs.ParsedQuery) => ParsedUrl | undefined } = {}; const stringifiers: { [type: string]: (state: ParsedUrl) => string } = {}; - type ParserValue = true | 'none' | 'json' | ((value: string) => any); + type ParserValue = true | 'none' | 'json' | ((value: string) => string | null | (string | null)[]); type Parser = { [key: string]: ParserValue; @@ -106,7 +107,7 @@ export namespace HistoryUtil { return value; } parsers[type] = (pathname, opts) => { - const current: any = { type }; + const current: DocUrl & { [key: string]: null | (string | null)[] | string } = { type: 'doc', docId: '' }; for (const required in requiredFields) { if (!(required in opts)) { return undefined; @@ -148,7 +149,7 @@ export namespace HistoryUtil { path = customStringifier(state, path); } const queryObj = OmitKeys(state, keys).extract; - const query: any = {}; + const query: { [key: string]: string | null } = {}; Object.keys(queryObj).forEach(key => { query[key] = queryObj[key] === null ? null : JSON.stringify(queryObj[key]); }); diff --git a/src/client/util/Import & Export/ImageUtils.ts b/src/client/util/Import & Export/ImageUtils.ts index 8d4eefa7e..266e05f08 100644 --- a/src/client/util/Import & Export/ImageUtils.ts +++ b/src/client/util/Import & Export/ImageUtils.ts @@ -1,3 +1,4 @@ +/* eslint-disable @typescript-eslint/no-namespace */ import { ClientUtils } from '../../../ClientUtils'; import { Doc } from '../../../fields/Doc'; import { DocData } from '../../../fields/DocSymbols'; diff --git a/src/client/util/Import & Export/ImportMetadataEntry.tsx b/src/client/util/Import & Export/ImportMetadataEntry.tsx index db1e3d6cd..63dedf820 100644 --- a/src/client/util/Import & Export/ImportMetadataEntry.tsx +++ b/src/client/util/Import & Export/ImportMetadataEntry.tsx @@ -1,5 +1,3 @@ -/* eslint-disable jsx-a11y/no-static-element-interactions */ -/* eslint-disable jsx-a11y/click-events-have-key-events */ /* eslint-disable no-use-before-define */ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { action, computed } from 'mobx'; diff --git a/src/client/util/InteractionUtils.tsx b/src/client/util/InteractionUtils.tsx index a07550e09..f3ede596d 100644 --- a/src/client/util/InteractionUtils.tsx +++ b/src/client/util/InteractionUtils.tsx @@ -1,8 +1,10 @@ +import { Property } from 'csstype'; import * as React from 'react'; import { Utils } from '../../Utils'; import { Gestures } from '../../pen-gestures/GestureTypes'; import './InteractionUtils.scss'; +// eslint-disable-next-line @typescript-eslint/no-namespace export namespace InteractionUtils { export const MOUSETYPE = 'mouse'; export const TOUCHTYPE = 'touch'; @@ -11,7 +13,7 @@ export namespace InteractionUtils { const ERASER_BUTTON = 5; - export function makePolygon(shape: string, points: { X: number; Y: number }[]) { + export function makePolygon(shape: Gestures, points: { X: number; Y: number }[]) { // if arrow/line/circle, the two end points should be the starting and the ending point let left = points[0].X; let top = points[0].Y; @@ -19,7 +21,7 @@ export namespace InteractionUtils { let bottom = points[1].Y; if (points.length > 1 && points[points.length - 1].X === points[0].X && points[points.length - 1].Y + 1 === points[0].Y) { // pointer is up (first and last points are the same) - if (![Gestures.Arrow, Gestures.Line, Gestures.Circle].includes(shape as any as Gestures)) { + if (![Gestures.Arrow, Gestures.Line, Gestures.Circle].includes(shape)) { // otherwise take max and min const xs = points.map(p => p.X); const ys = points.map(p => p.Y); @@ -98,8 +100,8 @@ export namespace InteractionUtils { color: string, width: number, strokeWidth: number, - lineJoin: string, - strokeLineCap: string, + lineJoin: Property.StrokeLinejoin, + strokeLineCap: Property.StrokeLinecap, bezier: string, fill: string, arrowStart: string, @@ -108,8 +110,8 @@ export namespace InteractionUtils { dash: string | undefined, scalexIn: number, scaleyIn: number, - shape: string, - pevents: string, + shape: Gestures, + pevents: Property.PointerEvents, opacity: number, nodefs: boolean, downHdlr?: (e: React.PointerEvent) => void, @@ -154,7 +156,7 @@ export namespace InteractionUtils { @@ -184,10 +186,10 @@ export namespace InteractionUtils { filter: mask ? `url(#mask${defGuid})` : undefined, opacity: 1.0, // opacity: strokeWidth !== width ? 0.5 : undefined, - pointerEvents: (pevents as any) === 'all' ? 'visiblepainted' : (pevents as any), + pointerEvents: pevents === 'all' ? 'visiblePainted' : pevents, stroke: color ?? 'rgb(0, 0, 0)', strokeWidth, - strokeLinecap: strokeLineCap as any, + strokeLinecap: strokeLineCap, strokeDasharray: dashArray, transition: 'inherit', }} diff --git a/src/client/util/LinkFollower.ts b/src/client/util/LinkFollower.ts index 9a0edcfec..0a3a0ba49 100644 --- a/src/client/util/LinkFollower.ts +++ b/src/client/util/LinkFollower.ts @@ -50,7 +50,7 @@ export class LinkFollower { const backLinks = linkDocs.filter(l => isAnchor(sourceDoc, l.link_anchor_2 as Doc)); // link docs where 'sourceDoc' is link_anchor_2 const fwdLinkWithoutTargetView = fwdLinks.find(l => !getView(DocCast(l.link_anchor_2))); const backLinkWithoutTargetView = backLinks.find(l => !getView(DocCast(l.link_anchor_1))); - const linkWithoutTargetDoc = traverseBacklink === undefined ? fwdLinkWithoutTargetView ?? backLinkWithoutTargetView : traverseBacklink ? backLinkWithoutTargetView : fwdLinkWithoutTargetView; + const linkWithoutTargetDoc = traverseBacklink === undefined ? (fwdLinkWithoutTargetView ?? backLinkWithoutTargetView) : traverseBacklink ? backLinkWithoutTargetView : fwdLinkWithoutTargetView; const linkDocList = linkWithoutTargetDoc && !sourceDoc.followAllLinks ? [linkWithoutTargetDoc] : traverseBacklink === undefined ? fwdLinks.concat(backLinks) : traverseBacklink ? backLinks : fwdLinks; const followLinks = sourceDoc.followLinkToggle || sourceDoc.followAllLinks ? linkDocList : linkDocList.slice(0, 1); let count = 0; @@ -82,7 +82,7 @@ export class LinkFollower { willZoomCentered: BoolCast(srcAnchor.followLinkZoom, false), zoomTime: NumCast(srcAnchor.followLinkTransitionTime, 500), zoomScale: Cast(srcAnchor.followLinkZoomScale, 'number', null), - easeFunc: StrCast(srcAnchor.followLinkEase, 'ease') as any, + easeFunc: StrCast(srcAnchor.followLinkEase, 'ease') as 'ease' | 'linear', openLocation: StrCast(srcAnchor.followLinkLocation, OpenWhere.lightbox) as OpenWhere, effect: srcAnchor, zoomTextSelections: BoolCast(srcAnchor.followLinkZoomText), diff --git a/src/client/util/LinkManager.ts b/src/client/util/LinkManager.ts index 56d5dce4e..e11482572 100644 --- a/src/client/util/LinkManager.ts +++ b/src/client/util/LinkManager.ts @@ -31,13 +31,13 @@ export class LinkManager { @observable public currentLink: Opt = undefined; @observable public currentLinkAnchor: Opt = undefined; public static get Instance(): LinkManager { - return Doc.UserDoc() ? LinkManager._instance ?? new LinkManager() : (undefined as any as LinkManager); + return Doc.UserDoc() ? (LinkManager._instance ?? new LinkManager()) : (undefined as unknown as LinkManager); } public static Links(doc: Doc | undefined) { return doc ? LinkManager.Instance.getAllRelatedLinks(doc) : []; } - public addLinkDB = async (linkDb: any) => { + public addLinkDB = async (linkDb: Doc) => { await Promise.all( ((await DocListCastAsync(linkDb.data)) ?? []).map(link => // makes sure link anchors are loaded to avoid incremental updates to computedFns in LinkManager @@ -95,35 +95,24 @@ export class LinkManager { const watchUserLinkDB = (userLinkDBDoc: Doc) => { const toRealField = (field: FieldType) => (field instanceof ProxyField ? field.value : field); // see List.ts. data structure is not a simple list of Docs, but a list of ProxyField/Fields if (userLinkDBDoc.data) { + // observe pushes/splices on a user link DB 'data' field (should only happen for local changes) observe( - userLinkDBDoc.data, + userLinkDBDoc.data as unknown as Doc[], change => { - // observe pushes/splices on a user link DB 'data' field (should only happen for local changes) - switch (change.type as any) { + switch (change.type) { case 'splice': - (change as any).added.forEach((link: any) => addLinkToDoc(toRealField(link))); - (change as any).removed.forEach((link: any) => remLinkFromDoc(toRealField(link))); + change.added.forEach(link => addLinkToDoc(toRealField(link))); + change.removed.forEach(link => remLinkFromDoc(toRealField(link))); break; - case 'update': // let oldValue = change.oldValue; - default: - } - }, - true - ); - observe( - userLinkDBDoc, - 'data', // obsever when a new array of links is assigned as the link DB 'data' field (should happen whenever a remote user adds/removes a link) - change => { - switch (change.type as any) { case 'update': - Promise.all([...((change.oldValue as any as Doc[]) || []), ...((change.newValue as any as Doc[]) || [])]).then(doclist => { - const oldDocs = doclist.slice(0, ((change.oldValue as any as Doc[]) || []).length); - const newDocs = doclist.slice(((change.oldValue as any as Doc[]) || []).length, doclist.length); + Promise.all([...((change.oldValue as unknown as Doc[]) || []), ...((change.newValue as unknown as Doc[]) || [])]).then(doclist => { + const oldDocs = doclist.slice(0, ((change.oldValue as unknown as Doc[]) || []).length); + const newDocs = doclist.slice(((change.oldValue as unknown as Doc[]) || []).length, doclist.length); const added = newDocs?.filter(link => !(oldDocs || []).includes(link)); const removed = oldDocs?.filter(link => !(newDocs || []).includes(link)); - added?.forEach((link: any) => addLinkToDoc(toRealField(link))); - removed?.forEach((link: any) => remLinkFromDoc(toRealField(link))); + added?.forEach(link => addLinkToDoc(toRealField(link))); + removed?.forEach(link => remLinkFromDoc(toRealField(link))); }); break; default: @@ -136,9 +125,9 @@ export class LinkManager { observe( this.userLinkDBs, change => { - switch (change.type as any) { + switch (change.type) { case 'splice': - (change as any).added.forEach(watchUserLinkDB); + change.added.forEach(watchUserLinkDB); break; case 'update': // let oldValue = change.oldValue; default: @@ -188,7 +177,7 @@ export class LinkManager { return []; } - const dirLinks = Array.from(anchor[DocData][DirectLinks]).filter(l => Doc.GetProto(anchor) === anchor[DocData] || ['1', '2'].includes(LinkManager.anchorIndex(l, anchor) as any)); + const dirLinks = Array.from(anchor[DocData][DirectLinks]).filter(l => Doc.GetProto(anchor) === anchor[DocData] || ['1', '2'].includes(LinkManager.anchorIndex(l, anchor) as '0' | '1' | '2')); const anchorRoot = DocCast(anchor.rootDocument, anchor); // template Doc fields store annotations on the topmost root of a template (not on themselves since the template layout items are only for layout) const annos = DocListCast(anchorRoot[Doc.LayoutFieldKey(anchor) + '_annotations']); return Array.from( @@ -283,7 +272,7 @@ export function UPDATE_SERVER_CACHE() { ScriptingGlobals.add( // eslint-disable-next-line prefer-arrow-callback - function links(doc: any) { + function links(doc: Doc) { return new List(LinkManager.Links(doc)); }, 'returns all the links to the document or its annotations', diff --git a/src/client/util/ProsemirrorCopy/prompt.js b/src/client/util/ProsemirrorCopy/prompt.js deleted file mode 100644 index b9068195f..000000000 --- a/src/client/util/ProsemirrorCopy/prompt.js +++ /dev/null @@ -1,179 +0,0 @@ -const prefix = "ProseMirror-prompt" - -export function openPrompt(options) { - let wrapper = document.body.appendChild(document.createElement("div")) - wrapper.className = prefix - wrapper.style.zIndex = 1000; - wrapper.style.width = 250; - wrapper.style.textAlign = "center"; - - let mouseOutside = e => { if (!wrapper.contains(e.target)) close() } - setTimeout(() => window.addEventListener("mousedown", mouseOutside), 50) - let close = () => { - window.removeEventListener("mousedown", mouseOutside) - if (wrapper.parentNode) wrapper.parentNode.removeChild(wrapper) - } - - let domFields = [] - for (let name in options.fields) domFields.push(options.fields[name].render()) - - let submitButton = document.createElement("button") - submitButton.type = "submit" - submitButton.className = prefix + "-submit" - submitButton.textContent = "OK" - let cancelButton = document.createElement("button") - cancelButton.type = "button" - cancelButton.className = prefix + "-cancel" - cancelButton.textContent = "Cancel" - cancelButton.addEventListener("click", close) - - let form = wrapper.appendChild(document.createElement("form")) - let title = document.createElement("h5") - title.style.marginBottom = 15 - title.style.marginTop = 10 - if (options.title) form.appendChild(title).textContent = options.title - domFields.forEach(field => { - form.appendChild(document.createElement("div")).appendChild(field) - }) - let b = document.createElement("div"); - b.style.marginTop = 15; - let buttons = form.appendChild(b) - // buttons.className = prefix + "-buttons" - buttons.appendChild(submitButton) - buttons.appendChild(document.createTextNode(" ")) - buttons.appendChild(cancelButton) - - let box = wrapper.getBoundingClientRect() - wrapper.style.top = options.flyout_top + "px" - wrapper.style.left = options.flyout_left + "px" - - let submit = () => { - let params = getValues(options.fields, domFields) - if (params) { - close() - options.callback(params) - } - } - - form.addEventListener("submit", e => { - e.preventDefault() - submit() - }) - - form.addEventListener("keydown", e => { - if (e.keyCode == 27) { - e.preventDefault() - close() - } else if (e.keyCode == 13 && !(e.ctrlKey || e.metaKey || e.shiftKey)) { - e.preventDefault() - submit() - } else if (e.keyCode == 9) { - window.setTimeout(() => { - if (!wrapper.contains(document.activeElement)) close() - }, 500) - } - }) - - let input = form.elements[0] - if (input) input.focus() -} - -function getValues(fields, domFields) { - let result = Object.create(null), i = 0 - for (let name in fields) { - let field = fields[name], dom = domFields[i++] - let value = field.read(dom), bad = field.validate(value) - if (bad) { - reportInvalid(dom, bad) - return null - } - result[name] = field.clean(value) - } - return result -} - -function reportInvalid(dom, message) { - // FIXME this is awful and needs a lot more work - let parent = dom.parentNode - let msg = parent.appendChild(document.createElement("div")) - msg.style.left = (dom.offsetLeft + dom.offsetWidth + 2) + "px" - msg.style.top = (dom.offsetTop - 5) + "px" - msg.className = "ProseMirror-invalid" - msg.textContent = message - setTimeout(() => parent.removeChild(msg), 1500) -} - -// ::- The type of field that `FieldPrompt` expects to be passed to it. -export class Field { - // :: (Object) - // Create a field with the given options. Options support by all - // field types are: - // - // **`value`**`: ?any` - // : The starting value for the field. - // - // **`label`**`: string` - // : The label for the field. - // - // **`required`**`: ?bool` - // : Whether the field is required. - // - // **`validate`**`: ?(any) → ?string` - // : A function to validate the given value. Should return an - // error message if it is not valid. - constructor(options) { this.options = options } - - // render:: (state: EditorState, props: Object) → dom.Node - // Render the field to the DOM. Should be implemented by all subclasses. - - // :: (dom.Node) → any - // Read the field's value from its DOM node. - read(dom) { return dom.value } - - // :: (any) → ?string - // A field-type-specific validation function. - validateType(_value) { } - - validate(value) { - if (!value && this.options.required) - return "Required field" - return this.validateType(value) || (this.options.validate && this.options.validate(value)) - } - - clean(value) { - return this.options.clean ? this.options.clean(value) : value - } -} - -// ::- A field class for single-line text fields. -export class TextField extends Field { - render() { - let input = document.createElement("input") - input.type = "text" - input.placeholder = this.options.label - input.value = this.options.value || "" - input.autocomplete = "off" - input.style.marginBottom = 4 - input.style.border = "1px solid black" - input.style.padding = "4px 4px" - return input - } -} - - -// ::- A field class for dropdown fields based on a plain ` tag, but for some reason we do... @@ -211,13 +211,15 @@ export class ContextMenu extends ObservableReactComponent<{}> { return (
{ - if (r) { - this._width = DivWidth(r); - this._height = DivHeight(r); - } - this._searchRef.current?.focus(); - })} + ref={r => + runInAction(() => { + if (r) { + this._width = DivWidth(r); + this._height = DivHeight(r); + } + this._searchRef.current?.focus(); + }) + } style={{ display: this._display ? '' : 'none', left: this.pageX, @@ -239,7 +241,6 @@ export class ContextMenu extends ObservableReactComponent<{}> { value={this._searchString} onKeyDown={this.onKeyDown} onChange={this.onChange} - // eslint-disable-next-line jsx-a11y/no-autofocus autoFocus /> diff --git a/src/client/views/ContextMenuItem.tsx b/src/client/views/ContextMenuItem.tsx index eb1030eec..3b87ea58b 100644 --- a/src/client/views/ContextMenuItem.tsx +++ b/src/client/views/ContextMenuItem.tsx @@ -10,8 +10,10 @@ import { ObservableReactComponent } from './ObservableReactComponent'; export interface OriginalMenuProps { description: string; - event: (stuff?: any) => void; + event: (stuff?: unknown) => void; undoable?: boolean; + noexpand?: boolean; + subitems?: ContextMenuProps[]; icon: IconProp | JSX.Element; // maybe should be optional (icon?) closeMenu?: () => void; } @@ -33,7 +35,7 @@ export class ContextMenuItem extends ObservableReactComponent = []; @observable private overItem = false; - constructor(props: any) { + constructor(props: ContextMenuProps & { selected?: boolean }) { super(props); makeObservable(this); } @@ -56,7 +58,7 @@ export class ContextMenuItem extends ObservableReactComponent { +export class DashboardView extends ObservableReactComponent { public static _urlState: HistoryUtil.DocUrl; public static makeDocumentConfig(document: Doc, panelName?: string, width?: number, keyValue?: boolean) { return { @@ -82,7 +80,7 @@ export class DashboardView extends ObservableReactComponent<{}> { }); return doc; } - constructor(props: any) { + constructor(props: object) { super(props); makeObservable(this); } diff --git a/src/client/views/FilterPanel.tsx b/src/client/views/FilterPanel.tsx index c97edd7f0..b11fa3bd5 100644 --- a/src/client/views/FilterPanel.tsx +++ b/src/client/views/FilterPanel.tsx @@ -1,6 +1,4 @@ /* eslint-disable react/jsx-props-no-spreading */ -/* eslint-disable jsx-a11y/no-static-element-interactions */ -/* eslint-disable jsx-a11y/click-events-have-key-events */ import { action, computed, makeObservable, observable, ObservableMap } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; @@ -28,7 +26,7 @@ interface filterProps { export class FilterPanel extends ObservableReactComponent { @observable _selectedFacetHeaders = new Set(); - constructor(props: any) { + constructor(props: filterProps) { super(props); makeObservable(this); } @@ -41,7 +39,7 @@ export class FilterPanel extends ObservableReactComponent { } @computed get targetDocChildKey() { const targetView = DocumentView.getFirstDocumentView(this.Document); - return targetView?.ComponentView?.annotationKey ?? targetView?.ComponentView?.fieldKey ?? 'data'; + return targetView?.ComponentView?.annotationKey || (targetView?.ComponentView?.fieldKey ?? 'data'); } @computed get targetDocChildren() { return [...DocListCast(this.Document?.[this.targetDocChildKey] || Doc.ActiveDashboard?.data), ...DocListCast(this.Document[Doc.LayoutFieldKey(this.Document) + '_sidebar'])]; @@ -240,7 +238,7 @@ export class FilterPanel extends ObservableReactComponent { {Array.from(this.activeRenderedFacetInfos.keys()).map( // iterate over activeFacetRenderInfos ==> renderInfo which you can renderInfo.facetHeader renderInfo => ( -
+
{renderInfo.facetHeader.charAt(0).toUpperCase() + renderInfo.facetHeader.slice(1)} @@ -308,7 +306,7 @@ export class FilterPanel extends ObservableReactComponent { return this.facetValues(facetHeader).map(fval => { const facetValue = fval; return ( -
+
{
{handles.map(handle => ( // const value = i === 0 ? defaultValues[0] : defaultValues[1]; -
+
))} diff --git a/src/client/views/GestureOverlay.tsx b/src/client/views/GestureOverlay.tsx index e3e252593..804c41091 100644 --- a/src/client/views/GestureOverlay.tsx +++ b/src/client/views/GestureOverlay.tsx @@ -78,7 +78,7 @@ export class GestureOverlay extends ObservableReactComponent { - if (!(e.target as any)?.className?.toString().startsWith('lm_')) { + if (!(e.target as HTMLElement)?.className?.toString().startsWith('lm_')) { if ([InkTool.Highlighter, InkTool.Pen, InkTool.Write].includes(Doc.ActiveTool)) { this._points.push({ X: e.clientX, Y: e.clientY }); setupMoveUpEvents(this, e, this.onPointerMove, this.onPointerUp, emptyFunction); @@ -173,8 +173,8 @@ export class GestureOverlay extends ObservableReactComponent { + const bezierCurves = fitCurve.default(newPoints, 10); + Array.from(bezierCurves).forEach(curve => { controlPoints.push({ X: curve[0][0], Y: curve[0][1] }); controlPoints.push({ X: curve[1][0], Y: curve[1][1] }); controlPoints.push({ X: curve[2][0], Y: curve[2][1] }); @@ -351,7 +351,7 @@ export class GestureOverlay extends ObservableReactComponent { + dispatchGesture = (gesture: Gestures, stroke?: InkData, text?: string) => { const points = (stroke ?? this._points).slice(); return ( document.elementFromPoint(points[0].X, points[0].Y)?.dispatchEvent( @@ -411,7 +411,7 @@ export class GestureOverlay extends ObservableReactComponent { - GestureOverlay.Instance.Tool = tool; - }); -}); -// eslint-disable-next-line prefer-arrow-callback -ScriptingGlobals.add(function setPen(width: any, color: any, fill: any, arrowStart: any, arrowEnd: any, dash: any) { +ScriptingGlobals.add(function setPen(width: string, color: string, fill: string, arrowStart: string, arrowEnd: string, dash: string) { runInAction(() => { GestureOverlay.Instance.SavedColor = ActiveInkColor(); SetActiveInkColor(color); @@ -543,8 +537,8 @@ ScriptingGlobals.add(function resetPen() { }, 'resets the pen tool'); ScriptingGlobals.add( // eslint-disable-next-line prefer-arrow-callback - function createText(text: any, x: any, y: any) { - GestureOverlay.Instance.dispatchGesture(Gestures.Text, [{ X: x, Y: y }], text); + function createText(text: string, X: number, Y: number) { + GestureOverlay.Instance.dispatchGesture(Gestures.Text, [{ X, Y }], text); }, 'creates a text document with inputted text and coordinates', '(text: any, x: any, y: any)' diff --git a/src/client/views/InkTranscription.tsx b/src/client/views/InkTranscription.tsx index 1ed8de1be..33db72960 100644 --- a/src/client/views/InkTranscription.tsx +++ b/src/client/views/InkTranscription.tsx @@ -240,7 +240,8 @@ // const text = exports['text/plain']; // if (this.currGroup) { -// this.currGroup.transcription = text; +// this.currGroup.text = text; // transcription text +// this.currGroup.icon_fieldKey = 'transcription'; // use the transcription icon template when iconifying // this.currGroup.title = text.split('\n')[0]; // } diff --git a/src/client/views/InkingStroke.tsx b/src/client/views/InkingStroke.tsx index 784d252a3..2e82371cb 100644 --- a/src/client/views/InkingStroke.tsx +++ b/src/client/views/InkingStroke.tsx @@ -20,6 +20,7 @@ Most of the operations that can be performed on an InkStroke (eg delete a point, rotate, stretch) are implemented in the InkStrokeProperties helper class */ +import { Property } from 'csstype'; import { action, computed, IReactionDisposer, observable, reaction } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; @@ -28,6 +29,7 @@ import { Doc } from '../../fields/Doc'; import { InkData, InkField } from '../../fields/InkField'; import { BoolCast, Cast, NumCast, RTFCast, StrCast } from '../../fields/Types'; import { TraceMobx } from '../../fields/util'; +import { Gestures } from '../../pen-gestures/GestureTypes'; import { CognitiveServices } from '../cognitive_services/CognitiveServices'; import { Docs } from '../documents/Documents'; import { DocumentType } from '../documents/DocumentTypes'; @@ -35,7 +37,6 @@ import { InteractionUtils } from '../util/InteractionUtils'; import { SnappingManager } from '../util/SnappingManager'; import { UndoManager } from '../util/UndoManager'; import { ContextMenu } from './ContextMenu'; -import { ViewBoxInterface } from './ViewBoxInterface'; import { ViewBoxAnnotatableComponent } from './DocComponent'; import { Colors } from './global/globalEnums'; import { InkControlPtHandles, InkEndPtHandles } from './InkControlPtHandles'; @@ -46,6 +47,7 @@ import { FieldView, FieldViewProps } from './nodes/FieldView'; import { FormattedTextBox, FormattedTextBoxProps } from './nodes/formattedText/FormattedTextBox'; import { PinDocView, PinProps } from './PinFuncs'; import { StyleProp } from './StyleProp'; +import { ViewBoxInterface } from './ViewBoxInterface'; // eslint-disable-next-line @typescript-eslint/no-var-requires const { INK_MASK_SIZE } = require('./global/globalCssVariables.module.scss'); // prettier-ignore @@ -318,8 +320,8 @@ export class InkingStroke extends ViewBoxAnnotatableComponent() Colors.MEDIUM_BLUE, screenInkWidth[0], screenSpaceCenterlineStrokeWidth, - StrCast(inkDoc.stroke_lineJoin), - StrCast(this.layoutDoc.stroke_lineCap), + StrCast(inkDoc.stroke_lineJoin) as Property.StrokeLinejoin, + StrCast(this.layoutDoc.stroke_lineCap) as Property.StrokeLinecap, StrCast(inkDoc.stroke_bezier), 'none', startMarker, @@ -328,7 +330,7 @@ export class InkingStroke extends ViewBoxAnnotatableComponent() StrCast(inkDoc.stroke_dash), 1, 1, - '', + '' as Gestures, 'none', 1.0, false @@ -383,8 +385,8 @@ export class InkingStroke extends ViewBoxAnnotatableComponent() this.strokeColor, inkStrokeWidth, inkStrokeWidth, - StrCast(this.layoutDoc.stroke_lineJoin), - StrCast(this.layoutDoc.stroke_lineCap), + StrCast(this.layoutDoc.stroke_lineJoin) as Property.StrokeLinejoin, + StrCast(this.layoutDoc.stroke_lineCap) as Property.StrokeLinecap, StrCast(this.layoutDoc.stroke_bezier), !closed ? 'none' : fillColor === 'transparent' ? 'none' : fillColor, startMarker, @@ -393,7 +395,7 @@ export class InkingStroke extends ViewBoxAnnotatableComponent() StrCast(this.layoutDoc.stroke_dash), inkScaleX, inkScaleY, - '', + '' as Gestures, 'none', 1.0, false, @@ -410,8 +412,8 @@ export class InkingStroke extends ViewBoxAnnotatableComponent() mask && color === 'transparent' ? this.strokeColor : (highlightColor ?? color), inkStrokeWidth, inkStrokeWidth + NumCast(this.layoutDoc.stroke_borderWidth) + (fillColor ? (closed ? higlightMargin : (highlightIndex ?? 0) + higlightMargin) : higlightMargin), - StrCast(this.layoutDoc.stroke_lineJoin), - StrCast(this.layoutDoc.stroke_lineCap), + StrCast(this.layoutDoc.stroke_lineJoin) as Property.StrokeLinejoin, + StrCast(this.layoutDoc.stroke_lineCap) as Property.StrokeLinecap, StrCast(this.layoutDoc.stroke_bezier), !closed || !fillColor || DashColor(fillColor).alpha() === 0 ? 'none' : fillColor, startMarker, @@ -420,7 +422,7 @@ export class InkingStroke extends ViewBoxAnnotatableComponent() StrCast(this.layoutDoc.stroke_dash), inkScaleX, inkScaleY, - '', + '' as Gestures, this._props.pointerEvents?.() ?? 'visiblePainted', 0.0, false, diff --git a/src/client/views/LightboxView.tsx b/src/client/views/LightboxView.tsx index 7198c7f05..adbe20a63 100644 --- a/src/client/views/LightboxView.tsx +++ b/src/client/views/LightboxView.tsx @@ -1,6 +1,4 @@ /* eslint-disable no-use-before-define */ -/* eslint-disable jsx-a11y/no-static-element-interactions */ -/* eslint-disable jsx-a11y/click-events-have-key-events */ import { IconProp } from '@fortawesome/fontawesome-svg-core'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { Toggle, ToggleType, Type } from 'browndash-components'; @@ -12,7 +10,7 @@ import { emptyFunction } from '../../Utils'; import { CreateLinkToActiveAudio, Doc, DocListCast, FieldResult, Opt } from '../../fields/Doc'; import { Id } from '../../fields/FieldSymbols'; import { InkTool } from '../../fields/InkField'; -import { Cast, NumCast, toList } from '../../fields/Types'; +import { BoolCast, Cast, NumCast, toList } from '../../fields/Types'; import { SnappingManager } from '../util/SnappingManager'; import { Transform } from '../util/Transform'; import { GestureOverlay } from './GestureOverlay'; @@ -28,7 +26,7 @@ interface LightboxViewProps { PanelWidth: number; PanelHeight: number; maxBorder: number[]; - addSplit: (document: Doc, pullSide: OpenWhereMod, stack?: any, panelName?: string | undefined, keyValue?: boolean | undefined) => boolean; + addSplit: (document: Doc, pullSide: OpenWhereMod, stack?: unknown, panelName?: string | undefined, keyValue?: boolean | undefined) => boolean; } const savedKeys = ['freeform_panX', 'freeform_panY', 'freeform_scale', 'layout_scrollTop', 'layout_fieldKey']; @@ -63,7 +61,7 @@ export class LightboxView extends ObservableReactComponent { @computed get leftBorder() { return Math.min(this._props.PanelWidth / 4, this._props.maxBorder[0]); } // prettier-ignore @computed get topBorder() { return Math.min(this._props.PanelHeight / 4, this._props.maxBorder[1]); } // prettier-ignore - constructor(props: any) { + constructor(props: LightboxViewProps) { super(props); makeObservable(this); LightboxView.Instance = this; @@ -214,7 +212,7 @@ export class LightboxView extends ObservableReactComponent { lightboxDocTemplate = () => this._layoutTemplate; future = () => this._future; - renderNavBtn = (left: Opt, bottom: Opt, top: number, icon: IconProp, display: any, click: () => void, color?: string) => ( + renderNavBtn = (left: Opt, bottom: Opt, top: number, icon: IconProp, display: boolean, click: () => void, color?: string) => (
{ render() { let downx = 0; let downy = 0; - const toggleBtn = (classname: string, tooltip: string, toggleBackground: any, icon: IconProp, icon2: IconProp | string, onClick: () => void) => ( + const toggleBtn = (classname: string, tooltip: string, toggleBackground: boolean, icon: IconProp, icon2: IconProp | string, onClick: () => void) => (
{
- {this.renderNavBtn(0, undefined, this._props.PanelHeight / 2 - 12.5, 'chevron-left', this._doc && this._history.length, this.previous)} + {this.renderNavBtn(0, undefined, this._props.PanelHeight / 2 - 12.5, 'chevron-left', this._doc && this._history.length ? true : false, this.previous)} {this.renderNavBtn( this._props.PanelWidth - Math.min(this._props.PanelWidth / 4, this._props.maxBorder[0]), undefined, this._props.PanelHeight / 2 - 12.5, 'chevron-right', - this._doc && this._future.length, + this._doc && this._future.length ? true : false, this.next, this.future().length.toString() )} - {toggleBtn('lightboxView-navBtn', 'toggle reading view', this._doc?._layout_fitWidth, 'book-open', 'book', this.toggleFitWidth)} + {toggleBtn('lightboxView-navBtn', 'toggle reading view', BoolCast(this._doc?._layout_fitWidth), 'book-open', 'book', this.toggleFitWidth)} {toggleBtn('lightboxView-tabBtn', 'open document in a tab', false, 'file-download', '', this.downloadDoc)} {toggleBtn('lightboxView-penBtn', 'toggle pen annotation', Doc.ActiveTool === InkTool.Pen, 'pen', '', this.togglePen)} {toggleBtn('lightboxView-exploreBtn', 'toggle navigate only mode', SnappingManager.ExploreMode, 'globe-americas', '', this.toggleExplore)} @@ -326,7 +324,7 @@ export class LightboxView extends ObservableReactComponent { } } interface LightboxTourBtnProps { - navBtn: (left: Opt, bottom: Opt, top: number, icon: IconProp, display: any, click: () => void, color?: string) => JSX.Element; + navBtn: (left: Opt, bottom: Opt, top: number, icon: IconProp, display: boolean, click: () => void, color?: string) => JSX.Element; // eslint-disable-next-line react/no-unused-prop-types future: () => Opt; stepInto: () => void; @@ -335,7 +333,7 @@ interface LightboxTourBtnProps { @observer export class LightboxTourBtn extends React.Component { render() { - return this.props.navBtn('50%', 0, 0, 'chevron-down', this.props.lightboxDoc(), this.props.stepInto, ''); + return this.props.navBtn('50%', 0, 0, 'chevron-down', this.props.lightboxDoc() ? true : false, this.props.stepInto, ''); } } diff --git a/src/client/views/Main.tsx b/src/client/views/Main.tsx index 43b9a6b39..044162e4e 100644 --- a/src/client/views/Main.tsx +++ b/src/client/views/Main.tsx @@ -50,6 +50,7 @@ import { ScreenshotBox } from './nodes/ScreenshotBox'; import { ScriptingBox } from './nodes/ScriptingBox'; import { VideoBox } from './nodes/VideoBox'; import { WebBox } from './nodes/WebBox'; +import { CalendarBox } from './nodes/calendarBox/CalendarBox'; import { DashDocCommentView } from './nodes/formattedText/DashDocCommentView'; import { DashDocView } from './nodes/formattedText/DashDocView'; import { DashFieldView } from './nodes/formattedText/DashFieldView'; @@ -60,6 +61,8 @@ import { SummaryView } from './nodes/formattedText/SummaryView'; import { ImportElementBox } from './nodes/importBox/ImportElementBox'; import { PresBox, PresElementBox } from './nodes/trails'; import { SearchBox } from './search/SearchBox'; +import { Node } from 'prosemirror-model'; +import { EditorView } from 'prosemirror-view'; dotenv.config(); @@ -83,7 +86,7 @@ FieldLoader.ServerLoadStatus = { requested: 0, retrieved: 0, message: 'cache' }; setTimeout(() => { // prevent zooming browser document.getElementById('root')!.addEventListener('wheel', event => event.ctrlKey && event.preventDefault(), true); - const startload = (document as any).startLoad; + const startload = (document as unknown as { startLoad: number }).startLoad; // see index.html in deploy/ const loading = Date.now() - (startload ? Number(startload) : Date.now() - 3000); console.log('Loading Time = ' + loading); const d = new Date(); @@ -99,12 +102,12 @@ FieldLoader.ServerLoadStatus = { requested: 0, retrieved: 0, message: 'cache' }; // initialize plugins and classes that require plugins CollectionDockingView.Init(TabDocView); FormattedTextBox.Init((tbox: FormattedTextBox) => ({ - dashComment(node: any, view: any, getPos: any) { return new DashDocCommentView(node, view, getPos); }, // prettier-ignore - dashDoc(node: any, view: any, getPos: any) { return new DashDocView(node, view, getPos, tbox); }, // prettier-ignore - dashField(node: any, view: any, getPos: any) { return new DashFieldView(node, view, getPos, tbox); }, // prettier-ignore - equation(node: any, view: any, getPos: any) { return new EquationView(node, view, getPos, tbox); }, // prettier-ignore - summary(node: any, view: any, getPos: any) { return new SummaryView(node, view, getPos); }, // prettier-ignore - footnote(node: any, view: any, getPos: any) { return new FootnoteView(node, view, getPos); }, // prettier-ignore + dashComment(node: Node, view: EditorView, getPos: () => number | undefined) { return new DashDocCommentView(node, view, getPos); }, // prettier-ignore + dashDoc(node: Node, view: EditorView, getPos: () => number | undefined) { return new DashDocView(node, view, getPos, tbox); }, // prettier-ignore + dashField(node: Node, view: EditorView, getPos: () => number | undefined) { return new DashFieldView(node, view, getPos, tbox); }, // prettier-ignore + equation(node: Node, view: EditorView, getPos: () => number | undefined) { return new EquationView(node, view, getPos, tbox); }, // prettier-ignore + summary(node: Node, view: EditorView, getPos: () => number | undefined) { return new SummaryView(node, view, getPos); }, // prettier-ignore + footnote(node: Node, view: EditorView, getPos: () => number | undefined) { return new FootnoteView(node, view, getPos); }, // prettier-ignore })); CollectionFreeFormInfoUI.Init(); LinkFollower.Init(); @@ -141,6 +144,7 @@ FieldLoader.ServerLoadStatus = { requested: 0, retrieved: 0, message: 'cache' }; ChatBox, DiagramBox, HTMLtag, + CalendarBox, ComparisonBox, LoadingBox, PhysicsSimulationBox, diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index ef1bcfb64..ac30c5a14 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -1,4 +1,3 @@ -/* eslint-disable node/no-unpublished-import */ import { library } from '@fortawesome/fontawesome-svg-core'; import { faBuffer, faHireAHelper } from '@fortawesome/free-brands-svg-icons'; import * as far from '@fortawesome/free-regular-svg-icons'; @@ -7,7 +6,7 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { action, computed, configure, makeObservable, observable, reaction, runInAction } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; -// eslint-disable-next-line import/no-relative-packages +import ResizeObserver from 'resize-observer-polyfill'; import '../../../node_modules/browndash-components/dist/styles/global.min.css'; import { ClientUtils, lightOrDark, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnTrue, returnZero, setupMoveUpEvents } from '../../ClientUtils'; import { emptyFunction } from '../../Utils'; @@ -58,7 +57,6 @@ import { ImageLabelHandler } from './collections/collectionFreeForm/ImageLabelHa import { MarqueeOptionsMenu } from './collections/collectionFreeForm/MarqueeOptionsMenu'; import { CollectionLinearView } from './collections/collectionLinear'; import { LinkMenu } from './linking/LinkMenu'; -import { AudioBox } from './nodes/AudioBox'; import { SchemaCSVPopUp } from './nodes/DataVizBox/SchemaCSVPopUp'; import { DocButtonState } from './nodes/DocumentLinksButton'; import { DocumentView, DocumentViewInternal } from './nodes/DocumentView'; @@ -77,11 +75,11 @@ import { AnchorMenu } from './pdf/AnchorMenu'; import { GPTPopup } from './pdf/GPTPopup/GPTPopup'; import { TopBar } from './topbar/TopBar'; +// eslint-disable-next-line @typescript-eslint/no-var-requires const { LEFT_MENU_WIDTH, TOPBAR_HEIGHT } = require('./global/globalCssVariables.module.scss'); // prettier-ignore -const _global = (window /* browser */ || global) /* node */ as any; @observer -export class MainView extends ObservableReactComponent<{}> { +export class MainView extends ObservableReactComponent { // eslint-disable-next-line no-use-before-define public static Instance: MainView; public static Live: boolean = false; @@ -92,7 +90,7 @@ export class MainView extends ObservableReactComponent<{}> { @observable private _dashUIWidth: number = 0; // width of entire main dashboard region including left menu buttons and properties panel (but not including the dashboard selector button row) @observable private _dashUIHeight: number = 0; // height of entire main dashboard region including top menu buttons @observable private _panelContent: string = 'none'; - @observable private _sidebarContent: any = Doc.MyLeftSidebarPanel; + @observable private _sidebarContent: Doc = Doc.MyLeftSidebarPanel; @observable private _leftMenuFlyoutWidth: number = 0; @computed get _hideUI() { return this.mainDoc && this.mainDoc._type_collection !== CollectionViewType.Docking; @@ -152,7 +150,7 @@ export class MainView extends ObservableReactComponent<{}> { } }; headerBarDocWidth = () => this.mainDocViewWidth(); - headerBarDocHeight = () => (this._hideUI ? 0 : this.headerBarHeight ?? 0); + headerBarDocHeight = () => (this._hideUI ? 0 : (this.headerBarHeight ?? 0)); topMenuHeight = () => (this._hideUI ? 0 : 35); topMenuWidth = returnZero; // value is ignored ... leftMenuWidth = () => (this._hideUI ? 0 : Number(LEFT_MENU_WIDTH.replace('px', ''))); @@ -169,7 +167,7 @@ export class MainView extends ObservableReactComponent<{}> { reaction( // when a multi-selection occurs, remove focus from all active elements to allow keyboad input to go only to global key manager to act upon selection () => DocumentView.Selected().slice(), - views => views.length > 1 && (document.activeElement as any)?.blur !== undefined && (document.activeElement as any)!.blur() + views => views.length > 1 && document.activeElement instanceof HTMLElement && document.activeElement?.blur() ); reaction( () => Doc.MyDockedBtns.linearView_IsOpen, @@ -234,9 +232,9 @@ export class MainView extends ObservableReactComponent<{}> { tag.src = 'https://www.youtube.com/iframe_api'; const firstScriptTag = document.getElementsByTagName('script')[0]; firstScriptTag.parentNode!.insertBefore(tag, firstScriptTag); - document.addEventListener('dash', (e: any) => { + document.addEventListener('dash', (e: Event) => { // event used by chrome plugin to tell Dash which document to focus on - const id = GetDocFromUrl(e.detail); + const id = GetDocFromUrl((e as Event & { detail: string }).detail); DocServer.GetRefField(id).then(doc => (doc instanceof Doc ? DocumentView.showDocument(doc, { willPan: false }) : null)); }); document.addEventListener('linkAnnotationToDash', Hypothesis.linkListener); @@ -253,12 +251,12 @@ export class MainView extends ObservableReactComponent<{}> { // document.removeEventListener('linkAnnotationToDash', Hypothesis.linkListener); } - constructor(props: any) { + constructor(props: object) { super(props); makeObservable(this); DocumentViewInternal.addDocTabFunc = MainView.addDocTabFunc_impl; MainView.Instance = this; - DashboardView._urlState = HistoryUtil.parseUrl(window.location) || ({} as any); + DashboardView._urlState = HistoryUtil.parseUrl(window.location) ?? { type: 'doc', docId: '' }; // causes errors to be generated when modifying an observable outside of an action configure({ enforceActions: 'observed' }); @@ -293,7 +291,7 @@ export class MainView extends ObservableReactComponent<{}> { fa.faExternalLinkAlt, fa.faCalendar, fa.faSquare, - far.faSquare as any, + far.faSquare, fa.faConciergeBell, fa.faWindowRestore, fa.faFolder, @@ -445,7 +443,7 @@ export class MainView extends ObservableReactComponent<{}> { fa.faHandPaper, fa.faMap, fa.faUser, - faHireAHelper as any, + faHireAHelper, fa.faTrashRestore, fa.faUsers, fa.faWrench, @@ -456,14 +454,14 @@ export class MainView extends ObservableReactComponent<{}> { fa.faArchive, fa.faBezierCurve, fa.faCircle, - far.faCircle as any, + far.faCircle, fa.faLongArrowAltRight, fa.faPenFancy, fa.faAngleDoubleRight, fa.faAngleDoubleDown, fa.faAngleDoubleLeft, fa.faAngleDoubleUp, - faBuffer as any, + faBuffer, fa.faExpand, fa.faUndo, fa.faSlidersH, @@ -570,7 +568,6 @@ export class MainView extends ObservableReactComponent<{}> { ); DocumentManager.removeOverlayViews(); Doc.linkFollowUnhighlight(); - AudioBox.Enabled = true; const targets = document.elementsFromPoint(e.x, e.y); if (targets.length) { let targClass = targets[0].className.toString(); @@ -590,18 +587,6 @@ export class MainView extends ObservableReactComponent<{}> { document.addEventListener('pointerdown', this.globalPointerDown, true); document.addEventListener('pointermove', this.globalPointerMove, true); document.addEventListener('pointerup', this.globalPointerClick, true); - document.addEventListener( - 'click', - (e: MouseEvent) => { - if (!e.cancelBubble) { - const pathstr = (e as any)?.path?.map((p: any) => p.classList?.toString()).join(); - if (pathstr?.includes('libraryFlyout')) { - DocumentView.DeselectAll(); - } - } - }, - false - ); document.oncontextmenu = () => false; }; @@ -777,7 +762,7 @@ export class MainView extends ObservableReactComponent<{}> {
{ className="mainView-dashboardArea" ref={r => { r && - new _global.ResizeObserver( + new ResizeObserver( action(() => { this._dashUIWidth = r.getBoundingClientRect().width; this._dashUIHeight = r.getBoundingClientRect().height; @@ -976,11 +961,11 @@ export class MainView extends ObservableReactComponent<{}> { {[ ...SnappingManager.HorizSnapLines.map((l, i) => ( // eslint-disable-next-line react/no-array-index-key - + )), ...SnappingManager.VertSnapLines.map((l, i) => ( // eslint-disable-next-line react/no-array-index-key - + )), ]} @@ -1038,7 +1023,7 @@ export class MainView extends ObservableReactComponent<{}> { } ref={r => { r && - new _global.ResizeObserver( + new ResizeObserver( action(() => { this._windowWidth = r.getBoundingClientRect().width; this._windowHeight = r.getBoundingClientRect().height; diff --git a/src/client/views/OverlayView.tsx b/src/client/views/OverlayView.tsx index a7907a565..7bf10467e 100644 --- a/src/client/views/OverlayView.tsx +++ b/src/client/views/OverlayView.tsx @@ -3,6 +3,7 @@ import { observer } from 'mobx-react'; import { computedFn } from 'mobx-utils'; import * as React from 'react'; import ReactLoading from 'react-loading'; +import ResizeObserver from 'resize-observer-polyfill'; import { returnEmptyDoclist, returnEmptyFilter, returnTrue, setupMoveUpEvents } from '../../ClientUtils'; import { Utils, emptyFunction } from '../../Utils'; import { Doc } from '../../fields/Doc'; @@ -18,8 +19,6 @@ import './OverlayView.scss'; import { DefaultStyleProvider } from './StyleProvider'; import { DocumentView, DocumentViewInternal } from './nodes/DocumentView'; -const _global = (window /* browser */ || global) /* node */ as any; - export type OverlayDisposer = () => void; export type OverlayElementOptions = { @@ -109,19 +108,19 @@ export class OverlayWindow extends ObservableReactComponent } @observer -export class OverlayView extends ObservableReactComponent<{}> { +export class OverlayView extends ObservableReactComponent { // eslint-disable-next-line no-use-before-define public static Instance: OverlayView; @observable.shallow _elements: JSX.Element[] = []; - constructor(props: any) { + constructor(props: object) { super(props); makeObservable(this); if (!OverlayView.Instance) { OverlayView.Instance = this; - new _global.ResizeObserver( - action((entries: any) => { - Array.from(entries).forEach((entry: any) => { + new ResizeObserver( + action(entries => { + Array.from(entries).forEach(entry => { Doc.MyOverlayDocs.forEach(docIn => { const doc = docIn; if (NumCast(doc.overlayX) > entry.contentRect.width - 10) { @@ -162,17 +161,17 @@ export class OverlayView extends ObservableReactComponent<{}> { @action addWindow(contents: JSX.Element, options: OverlayElementOptions): OverlayDisposer { - const remove = action(() => { - const index = this._elements.indexOf(contents); + const remove = action((wincontents: JSX.Element) => { + const index = this._elements.indexOf(wincontents); if (index !== -1) this._elements.splice(index, 1); }); const wincontents = ( - + remove(wincontents)} key={Utils.GenerateGuid()} overlayOptions={options}> {contents} ); this._elements.push(wincontents); - return remove; + return () => remove(wincontents); } removeOverlayDoc = (docs: Doc | Doc[]) => toList(docs).every(Doc.RemFromMyOverlay); diff --git a/src/client/views/ScriptingRepl.tsx b/src/client/views/ScriptingRepl.tsx index 1a2eb460f..2de867746 100644 --- a/src/client/views/ScriptingRepl.tsx +++ b/src/client/views/ScriptingRepl.tsx @@ -1,6 +1,4 @@ /* eslint-disable react/no-array-index-key */ -/* eslint-disable jsx-a11y/no-static-element-interactions */ -/* eslint-disable jsx-a11y/click-events-have-key-events */ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { action, makeObservable, observable } from 'mobx'; import { observer } from 'mobx-react'; @@ -14,21 +12,26 @@ import { OverlayView } from './OverlayView'; import './ScriptingRepl.scss'; import { DocumentIconContainer } from './nodes/DocumentIcon'; import { DocumentView } from './nodes/DocumentView'; +import { returnFalse, setupMoveUpEvents } from '../../ClientUtils'; +import { emptyFunction } from '../../Utils'; +import { ObjectField } from '../../fields/ObjectField'; +import { RefField } from '../../fields/RefField'; +import { Doc, FieldResult, FieldType, Opt } from '../../fields/Doc'; interface replValueProps { scrollToBottom: () => void; - value: any; + value: Opt>; name?: string; } @observer export class ScriptingValueDisplay extends ObservableReactComponent { - constructor(props: any) { + constructor(props: replValueProps) { super(props); makeObservable(this); } render() { - const val = this._props.name ? this._props.value[this._props.name] : this._props.value; + const val = this._props.value instanceof Doc && this._props.name ? this._props.value[this._props.name] : this._props.value; const title = (name: string) => ( <> {this._props.name ? {this._props.name} : : <> } @@ -47,13 +50,14 @@ export class ScriptingValueDisplay extends ObservableReactComponent void; - value: { [key: string]: any }; + value: Opt>; name?: string; } +@observer export class ScriptingObjectDisplay extends ObservableReactComponent { @observable collapsed = true; - constructor(props: any) { + constructor(props: ReplProps) { super(props); makeObservable(this); } @@ -74,10 +78,12 @@ export class ScriptingObjectDisplay extends ObservableReactComponent {name} ); + if (val === undefined) return '--undefined--'; + if (val instanceof Promise) return '...Promise...'; if (this.collapsed) { return (
- + setupMoveUpEvents(this, e, returnFalse, emptyFunction, this.toggle)} className="scriptingObject-icon scriptingObject-iconCollapsed"> {title} (+{Object.keys(val).length}) @@ -94,8 +100,7 @@ export class ScriptingObjectDisplay extends ObservableReactComponent
{Object.keys(val).map(key => ( - // eslint-disable-next-line react/jsx-props-no-spreading - + ))}
@@ -104,13 +109,13 @@ export class ScriptingObjectDisplay extends ObservableReactComponent } @observer -export class ScriptingRepl extends ObservableReactComponent<{}> { - constructor(props: any) { +export class ScriptingRepl extends ObservableReactComponent { + constructor(props: object) { super(props); makeObservable(this); } - @observable private commands: { command: string; result: any }[] = []; + @observable private commands: { command: string; result: unknown }[] = []; private commandsHistory: string[] = []; @observable private commandString: string = ''; @@ -120,13 +125,11 @@ export class ScriptingRepl extends ObservableReactComponent<{}> { private commandsRef = React.createRef(); - private args: any = {}; - getTransformer = (): Transformer => ({ transformer: context => { const knownVars: { [name: string]: number } = {}; const usedDocuments: number[] = []; - ScriptingGlobals.getGlobals().forEach((global: any) => { + ScriptingGlobals.getGlobals().forEach((global: string) => { knownVars[global] = 1; }); return root => { @@ -168,7 +171,7 @@ export class ScriptingRepl extends ObservableReactComponent<{}> { switch (e.key) { case 'Enter': { e.stopPropagation(); - const docGlobals: { [name: string]: any } = {}; + const docGlobals: { [name: string]: FieldType } = {}; DocumentView.allViews().forEach((dv, i) => { docGlobals[`d${i}`] = dv.Document; }); @@ -176,19 +179,20 @@ export class ScriptingRepl extends ObservableReactComponent<{}> { const script = CompileScript(this.commandString, { typecheck: false, addReturn: true, editable: true, params: { args: 'any' }, transformer: this.getTransformer(), globals }); if (!script.compiled) { this.commands.push({ command: this.commandString, result: script.errors }); + this.maybeScrollToBottom(); return; } - const result = undoable(() => script.run({ args: this.args }, () => this.commands.push({ command: this.commandString, result: e.toString() })), 'run:' + this.commandString)(); + const result = undoable(() => script.run({}, e => this.commands.push({ command: this.commandString, result: e as string })), 'run:' + this.commandString)(); if (result.success) { this.commands.push({ command: this.commandString, result: result.result }); this.commandsHistory.push(this.commandString); - this.maybeScrollToBottom(); - this.commandString = ''; this.commandBuffer = ''; this.historyIndex = -1; } + + this.maybeScrollToBottom(); break; } case 'ArrowUp': { @@ -232,7 +236,7 @@ export class ScriptingRepl extends ObservableReactComponent<{}> { private shouldScroll: boolean = false; private maybeScrollToBottom = () => { const ele = this.commandsRef.current; - if (ele && ele.scrollTop === ele.scrollHeight - ele.offsetHeight) { + if (ele && Math.abs(Math.ceil(ele.scrollTop) - (ele.scrollHeight - ele.offsetHeight)) < 2) { this.shouldScroll = true; this.forceUpdate(); } @@ -240,14 +244,14 @@ export class ScriptingRepl extends ObservableReactComponent<{}> { private scrollToBottom() { const ele = this.commandsRef.current; - ele && ele.scroll({ behavior: 'auto', top: ele.scrollHeight }); + ele?.scroll({ behavior: 'smooth', top: ele.scrollHeight }); } - componentDidUpdate(prevProps: Readonly<{}>) { + componentDidUpdate(prevProps: Readonly) { super.componentDidUpdate(prevProps); if (this.shouldScroll) { this.shouldScroll = false; - this.scrollToBottom(); + setTimeout(() => this.scrollToBottom(), 0); } } @@ -269,7 +273,7 @@ export class ScriptingRepl extends ObservableReactComponent<{}> { {command ||
}
- +
))} diff --git a/src/client/views/StyleProvider.tsx b/src/client/views/StyleProvider.tsx index 8a07a6bd7..b111904f3 100644 --- a/src/client/views/StyleProvider.tsx +++ b/src/client/views/StyleProvider.tsx @@ -21,7 +21,7 @@ import { undoBatch, UndoManager } from '../util/UndoManager'; import { TreeSort } from './collections/TreeSort'; import { Colors } from './global/globalEnums'; import { DocumentView, DocumentViewProps } from './nodes/DocumentView'; -import { FieldViewProps, StyleProviderFuncType } from './nodes/FieldView'; +import { FieldViewProps } from './nodes/FieldView'; import { StyleProp } from './StyleProp'; import './StyleProvider.scss'; @@ -46,7 +46,7 @@ export function styleFromLayoutString(doc: Doc, props: FieldViewProps, scale: nu // bcz: this executes a script to convert a property expression string: { script } into a value ScriptField.MakeFunction(expr, { this: Doc.name, scale: 'number' })?.script.run({ this: doc, scale }).result?.toString() ?? ''; divKeys.forEach((prop: string) => { - const p = (props as any)[prop]; + const p = (props as FieldViewProps & { [key: string]: unknown })[prop]; typeof p === 'string' && (style[prop] = p?.replace(/{([^.'][^}']+)}/g, replacer)); }); return style; @@ -69,7 +69,7 @@ export function SetFilterOpener(func: () => void) { // a preliminary implementation of a dash style sheet for setting rendering properties of documents nested within a Tab // -export function DefaultStyleProvider(doc: Opt, props: Opt, property: string) : StyleProviderFuncType { +export function DefaultStyleProvider(doc: Opt, props: Opt, property: string) { const remoteDocHeader = 'author;author_date;noMargin'; const isCaption = property.includes(':caption'); const isAnchor = property.includes(':anchor'); diff --git a/src/client/views/ViewBoxInterface.ts b/src/client/views/ViewBoxInterface.ts index c633f34fb..dce64ab92 100644 --- a/src/client/views/ViewBoxInterface.ts +++ b/src/client/views/ViewBoxInterface.ts @@ -18,6 +18,9 @@ export abstract class ViewBoxInterface

extends ObservableReactComponent void; // moves contents of collection to parent updateIcon?: () => void; // updates the icon representation of the document getAnchor?: (addAsAnnotation: boolean, pinData?: PinProps) => Doc; // returns an Anchor Doc that represents the current state of the doc's componentview (e.g., the current playhead location of a an audio/video box) diff --git a/src/client/views/collections/CollectionCalendarView.tsx b/src/client/views/collections/CollectionCalendarView.tsx index a08a7c7c1..9eb16917b 100644 --- a/src/client/views/collections/CollectionCalendarView.tsx +++ b/src/client/views/collections/CollectionCalendarView.tsx @@ -6,11 +6,11 @@ import { dateRangeStrToDates, returnTrue } from '../../../ClientUtils'; import { Doc, DocListCast } from '../../../fields/Doc'; import { StrCast } from '../../../fields/Types'; import { CollectionStackingView } from './CollectionStackingView'; -import { CollectionSubView } from './CollectionSubView'; +import { CollectionSubView, SubCollectionViewProps } from './CollectionSubView'; @observer export class CollectionCalendarView extends CollectionSubView() { - constructor(props: any) { + constructor(props: SubCollectionViewProps) { super(props); makeObservable(this); } diff --git a/src/client/views/collections/CollectionCardDeckView.tsx b/src/client/views/collections/CollectionCardDeckView.tsx index de46180e6..28a769896 100644 --- a/src/client/views/collections/CollectionCardDeckView.tsx +++ b/src/client/views/collections/CollectionCardDeckView.tsx @@ -18,7 +18,7 @@ import { StyleProp } from '../StyleProp'; import { DocumentView } from '../nodes/DocumentView'; import { GPTPopup, GPTPopupMode } from '../pdf/GPTPopup/GPTPopup'; import './CollectionCardDeckView.scss'; -import { CollectionSubView } from './CollectionSubView'; +import { CollectionSubView, SubCollectionViewProps } from './CollectionSubView'; enum cardSortings { Time = 'time', @@ -68,7 +68,7 @@ export class CollectionCardView extends CollectionSubView() { } }; - constructor(props: any) { + constructor(props: SubCollectionViewProps) { super(props); makeObservable(this); } @@ -86,11 +86,11 @@ export class CollectionCardView extends CollectionSubView() { } @computed get cardSort_customField() { - return StrCast(this.Document.cardSort_customField) as any as 'chat' | 'star' | 'idea' | 'like'; + return StrCast(this.Document.cardSort_customField) as 'chat' | 'star' | 'idea' | 'like'; } @computed get cardSort() { - return StrCast(this.Document.cardSort) as any as cardSortings; + return StrCast(this.Document.cardSort) as cardSortings; } /** * how much to scale down the contents of the view so that everything will fit @@ -428,7 +428,6 @@ export class CollectionCardView extends CollectionSubView() { return (

{numberRange(amButtons).map(i => ( - // eslint-disable-next-line jsx-a11y/control-has-associated-label
); @@ -451,7 +453,7 @@ export class TableBox extends ObservableReactComponent { if (this._props.titleCol === col) colSelected = true; return ( -
{this._props.records[rowId][col]}
+
{this._props.records[rowId][col] as string | number}
); })} diff --git a/src/client/views/nodes/DocumentContentsView.tsx b/src/client/views/nodes/DocumentContentsView.tsx index 192c7875e..8a2c4e530 100644 --- a/src/client/views/nodes/DocumentContentsView.tsx +++ b/src/client/views/nodes/DocumentContentsView.tsx @@ -43,26 +43,37 @@ interface HTMLtagProps { @observer export class HTMLtag extends React.Component { click = () => { - const clickScript = (this.props as any).onClick as Opt; + const clickScript = this.props.onClick as Opt; clickScript?.script.run({ this: this.props.Document, scale: this.props.scaling }); }; - onInput = (e: React.FormEvent) => { - const onInputScript = (this.props as any).onInput as Opt; - onInputScript?.script.run({ this: this.props.Document, value: (e.target as any).textContent }); + onInput = (e: React.FormEvent) => { + const onInputScript = this.props.onInput as Opt; + onInputScript?.script.run({ this: this.props.Document, value: (e.target as HTMLElement).textContent }); }; render() { - const style: { [key: string]: any } = {}; - const divKeys = OmitKeys(this.props, ['children', 'dragStarting', 'dragEnding', 'htmltag', 'scaling', 'Document', 'key', 'onInput', 'onClick', '__proto__']).omit; - const replacer = (match: any, expr: string) => + const style: { [key: string]: unknown } = {}; + const divKeys = OmitKeys(this.props, [ + 'children', // + 'dragStarting', + 'dragEnding', + 'htmltag', + 'scaling', + 'Document', + 'key', + 'onInput', + 'onClick', + '__proto__', + ]).omit; + const replacer = (match: string, expr: string) => // bcz: this executes a script to convert a property expression string: { script } into a value (ScriptField.MakeFunction(expr, { this: Doc.name, scale: 'number' })?.script.run({ this: this.props.Document, scale: this.props.scaling }).result as string) || ''; Object.keys(divKeys).forEach((prop: string) => { - const p = (this.props as any)[prop] as string; + const p = (this.props as unknown as { [key: string]: string })[prop] as string; style[prop] = p?.replace(/{([^.'][^}']+)}/g, replacer); }); const Tag = this.props.htmltag as keyof JSX.IntrinsicElements; return ( - + {this.props.children} ); @@ -78,12 +89,12 @@ export class DocumentContentsView extends ObservableReactComponent{content}< as in {this.title} - const replacer = (match: any, prefix: string, expr: string, postfix: string) => prefix + ((ScriptField.MakeFunction(expr, { this: Doc.name })?.script.run({ this: this._props.Document }).result as string) || '') + postfix; + const replacer = (match: string, prefix: string, expr: string, postfix: string) => prefix + ((ScriptField.MakeFunction(expr, { this: Doc.name })?.script.run({ this: this._props.Document }).result as string) || '') + postfix; layoutFrame = layoutFrame.replace(/(>[^{]*)[^=]\{([^.'][^<}]+)\}([^}]*<)/g, replacer); // replace HTML with corresponding HTML tag as in: becomes - const replacer2 = (match: any, p1: string) => ` ` with as in: becomes @@ -194,6 +205,7 @@ export class DocumentContentsView extends ObservableReactComponent { console.log('DocumentContentsView:' + test, bindings, layoutFrame); }} diff --git a/src/client/views/nodes/DocumentLinksButton.tsx b/src/client/views/nodes/DocumentLinksButton.tsx index 0c5156339..c35a329c9 100644 --- a/src/client/views/nodes/DocumentLinksButton.tsx +++ b/src/client/views/nodes/DocumentLinksButton.tsx @@ -1,5 +1,3 @@ -/* eslint-disable jsx-a11y/no-static-element-interactions */ -/* eslint-disable jsx-a11y/click-events-have-key-events */ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { Tooltip } from '@mui/material'; import { action, computed, makeObservable, observable, runInAction } from 'mobx'; @@ -55,7 +53,7 @@ export class DocumentLinksButton extends ObservableReactComponent> = undefined; // needs to be accessed from DocumentView wrapper class @observable _animateScaleTime: Opt = undefined; // milliseconds for animating between views. defaults to 300 if not uset @observable _animateScalingTo = 0; @@ -216,7 +217,7 @@ export class DocumentViewInternal extends DocComponent this.style(this.Document, StyleProp.PointerEvents) as 'all' | 'none' | 'visiblePainted' | undefined, + () => this.style(this.Document, StyleProp.PointerEvents) as Property.PointerEvents | undefined, pointerevents => { this._pointerEvents = pointerevents; }, @@ -243,7 +244,7 @@ export class DocumentViewInternal extends DocComponent disposer?.()); } - startDragging(x: number, y: number, dropAction: dropActionType, hideSource = false) { + startDragging(x: number, y: number, dropAction: dropActionType | undefined, hideSource = false) { const docView = this._docView; if (this._mainCont.current && docView) { const views = DocumentView.Selected().filter(dv => dv.ContentDiv); @@ -310,7 +311,8 @@ export class DocumentViewInternal extends DocComponent { if (this.onDoubleClickHdlr?.script) { - this.onDoubleClickHdlr.script.run(scriptProps, console.log).result?.select && this._props.select(false); + const res = this.onDoubleClickHdlr.script.run(scriptProps, console.log).result as { select: boolean }; + res.select && this._props.select(false); } else if (!Doc.IsSystem(this.Document) && defaultDblclick !== 'ignore') { this._props.addDocTab(this.Document, OpenWhere.lightboxAlways); DocumentView.DeselectAll(); @@ -558,7 +560,7 @@ export class DocumentViewInternal extends DocComponent DocumentView.SetLightboxDoc(this.Document), icon: 'external-link-alt' }); @@ -574,7 +576,7 @@ export class DocumentViewInternal extends DocComponent { this.layoutDoc[`_${this._props.fieldKey}_revealOp`] = 'hover'; }, icon: 'hand-point-up' }); // prettier-ignore revealItems.push({ description: 'Flip', event: () => { this.layoutDoc[`_${this._props.fieldKey}_revealOp`] = 'flip'; }, icon: 'rotate' }); // prettier-ignore !revealOptions && cm.addItem({ description: 'Reveal Options', addDivider: false, noexpand: true, subitems: revealItems, icon: 'layer-group' }); @@ -582,15 +584,16 @@ export class DocumentViewInternal extends DocComponent DocumentView.Selected().forEach(dv => dv._props.bringToFront?.(dv.Document, false)), icon: 'arrow-up' }); zorderItems.push({ description: 'Send to Back', event: () => DocumentView.Selected().forEach(dv => dv._props.bringToFront?.(dv.Document, true)), icon: 'arrow-down' }); zorderItems.push({ description: !this.layoutDoc._keepZDragged ? 'Keep ZIndex when dragged' : 'Allow ZIndex to change when dragged', - event: undoBatch( + event: undoable( action(() => { this.layoutDoc._keepZWhenDragged = !this.layoutDoc._keepZWhenDragged; - }) + }), + 'set zIndex drag' ), icon: 'hand-point-up', }); @@ -599,7 +602,7 @@ export class DocumentViewInternal extends DocComponent DocUtils.makeIntoPortal(this.Document, this.layoutDoc, this._allLinks), 'make into portal'), icon: 'window-restore' }); !Doc.noviceMode && onClicks.push({ description: 'Toggle Detail', event: this.setToggleDetail, icon: 'concierge-bell' }); @@ -624,7 +627,7 @@ export class DocumentViewInternal extends DocComponent Doc.MakeMetadataFieldTemplate(this.Document, this._props.TemplateDataDocument), icon: 'concierge-bell' }); @@ -648,7 +651,7 @@ export class DocumentViewInternal extends DocComponent this._props.addDocTab(Docs.Create.PdfDocument('/assets/cheat-sheet.pdf', { _width: 300, _height: 300 }), OpenWhere.addRight), icon: 'keyboard' }); !Doc.noviceMode && helpItems.push({ description: 'Print Document in Console', event: () => console.log(this.Document), icon: 'hand-point-right' }); !Doc.noviceMode && helpItems.push({ description: 'Print DataDoc in Console', event: () => console.log(this.dataDoc), icon: 'hand-point-right' }); @@ -844,7 +847,7 @@ export class DocumentViewInternal extends DocComponent Field.toKeyValueString(this.Document, field)) .join('\\') } - SetValue={undoBatch((input: string) => { + SetValue={undoable((input: string) => { if (input?.startsWith('$')) { if (this.layoutDoc.layout_showTitle) { this.layoutDoc._layout_showTitle = input?.substring(1) ? input.substring(1) : undefined; @@ -855,7 +858,7 @@ export class DocumentViewInternal extends DocComponent @@ -1245,7 +1248,7 @@ export class DocumentView extends DocComponent() { public setToggleDetail = (scriptFieldKey = 'onClick') => this._docViewInternal?.setToggleDetail(scriptFieldKey); public onContextMenu = (e?: React.MouseEvent, pageX?: number, pageY?: number) => this._docViewInternal?.onContextMenu?.(e, pageX, pageY); public cleanupPointerEvents = () => this._docViewInternal?.cleanupPointerEvents(); - public startDragging = (x: number, y: number, dropAction: dropActionType, hideSource = false) => this._docViewInternal?.startDragging(x, y, dropAction, hideSource); + public startDragging = (x: number, y: number, dropAction: dropActionType | undefined, hideSource = false) => this._docViewInternal?.startDragging(x, y, dropAction, hideSource); public showContextMenu = (pageX: number, pageY: number) => this._docViewInternal?.onContextMenu(undefined, pageX, pageY); public toggleNativeDimensions = () => this._docViewInternal && this.Document.type !== DocumentType.INK && Doc.toggleNativeDimensions(this.layoutDoc, this.NativeDimScaling() ?? 1, this._props.PanelWidth(), this._props.PanelHeight()); @@ -1288,7 +1291,7 @@ export class DocumentView extends DocComponent() { this.dataDoc.audioAnnoState = AudioAnnoState.playing; break; case AudioAnnoState.playing: - this.dataDoc[AudioPlay]?.stop(); + (this.dataDoc[AudioPlay] as Howl)?.stop(); this.dataDoc.audioAnnoState = AudioAnnoState.stopped; break; default: diff --git a/src/client/views/nodes/EquationBox.tsx b/src/client/views/nodes/EquationBox.tsx index 1f5c9b84b..fefe25764 100644 --- a/src/client/views/nodes/EquationBox.tsx +++ b/src/client/views/nodes/EquationBox.tsx @@ -1,4 +1,3 @@ -/* eslint-disable jsx-a11y/no-static-element-interactions */ import { action, makeObservable, reaction } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; @@ -50,8 +49,8 @@ export class EquationBox extends ViewBoxBaseComponent() { () => this._props.isSelected(), selected => { if (this._ref.current) { - if (selected) this._ref.current.element.current.children[0].addEventListener('keydown', this.keyPressed, true); - else this._ref.current.element.current.children[0].removeEventListener('keydown', this.keyPressed); + if (selected) (this._ref.current.element.current?.children[0] as HTMLElement).addEventListener('keydown', this.keyPressed, true); + else (this._ref.current.element.current?.children[0] as HTMLElement).removeEventListener('keydown', this.keyPressed); } }, { fireImmediately: true } @@ -60,8 +59,8 @@ export class EquationBox extends ViewBoxBaseComponent() { @action keyPressed = (e: KeyboardEvent) => { - const _height = DivHeight(this._ref.current!.element.current); - const _width = DivWidth(this._ref.current!.element.current); + const _height = DivHeight(this._ref.current!.element?.current); + const _width = DivWidth(this._ref.current!.element?.current); if (e.key === 'Enter') { const nextEq = Docs.Create.EquationDocument(e.shiftKey ? StrCast(this.dataDoc.text) : 'x', { title: '# math', @@ -95,7 +94,7 @@ export class EquationBox extends ViewBoxBaseComponent() { }; updateSize = () => { - const style = this._ref.current && getComputedStyle(this._ref.current.element.current); + const style = this._ref.current?.element.current && getComputedStyle(this._ref.current.element.current); if (style?.width.endsWith('px') && style?.height.endsWith('px')) { if (this.layoutDoc._nativeWidth) { // if equation has been scaled then editing the expression must also edit the native dimensions to keep the aspect ratio diff --git a/src/client/views/nodes/FieldView.tsx b/src/client/views/nodes/FieldView.tsx index fc59e9e26..dd71fd946 100644 --- a/src/client/views/nodes/FieldView.tsx +++ b/src/client/views/nodes/FieldView.tsx @@ -1,5 +1,6 @@ /* eslint-disable react/no-unused-prop-types */ /* eslint-disable react/require-default-props */ +import { Property } from 'csstype'; import { computed } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; @@ -95,7 +96,7 @@ export interface FieldViewSharedProps { bringToFront?: (doc: Doc, sendToBack?: boolean) => void; waitForDoubleClickToClick?: () => 'never' | 'always' | undefined; defaultDoubleClick?: () => 'default' | 'ignore' | undefined; - pointerEvents?: () => Opt<'none' | 'all' | 'visiblePainted'>; + pointerEvents?: () => Opt; suppressSetHeight?: boolean; } diff --git a/src/client/views/nodes/FontIconBox/ButtonInterface.ts b/src/client/views/nodes/FontIconBox/ButtonInterface.ts deleted file mode 100644 index 0d0d7b1c3..000000000 --- a/src/client/views/nodes/FontIconBox/ButtonInterface.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { IconProp } from '@fortawesome/fontawesome-svg-core'; -import { Doc } from '../../../../fields/Doc'; -import { ButtonType } from './FontIconBox'; - -export interface IButtonProps { - type: string | ButtonType; - Document: Doc; - label: any; - icon: IconProp; - color: string; - backgroundColor: string; -} diff --git a/src/client/views/nodes/FontIconBox/FontIconBox.tsx b/src/client/views/nodes/FontIconBox/FontIconBox.tsx index ffb668b03..f2f7f39bb 100644 --- a/src/client/views/nodes/FontIconBox/FontIconBox.tsx +++ b/src/client/views/nodes/FontIconBox/FontIconBox.tsx @@ -73,12 +73,12 @@ export class FontIconBox extends ViewBoxBaseComponent() { Icon = (color: string, iconFalse?: boolean) => { let icon; if (iconFalse) { - icon = StrCast(this.dataDoc[this.fieldKey ?? 'iconFalse'] ?? this.dataDoc.icon, 'user') as any; + icon = StrCast(this.dataDoc[this.fieldKey ?? 'iconFalse'] ?? this.dataDoc.icon, 'user') as IconProp; if (icon) return ; return null; } - icon = StrCast(this.dataDoc[this.fieldKey ?? 'icon'] ?? this.dataDoc.icon, 'user') as any; - return !icon ? null : icon === 'pres-trail' ? TrailsIcon(color) : ; + icon = StrCast(this.dataDoc[this.fieldKey ?? 'icon'] ?? this.dataDoc.icon, 'user') as IconProp; + return !icon ? null : icon === ('pres-trail' as IconProp) ? TrailsIcon(color) : ; }; @computed get dropdown() { return BoolCast(this.Document.dropDownOpen); @@ -117,7 +117,7 @@ export class FontIconBox extends ViewBoxBaseComponent() { break; } // prettier-ignore const numScript = (value?: number) => ScriptCast(this.Document.script).script.run({ this: this.Document, value, _readOnly_: value === undefined }); - const color = this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.Color); + const color = this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.Color) as string; // Script for checking the outcome of the toggle const checkResult = Number(Number(numScript().result ?? 0).toPrecision(NumCast(this.dataDoc.numPrecision, 3))); @@ -142,7 +142,7 @@ export class FontIconBox extends ViewBoxBaseComponent() { setupMoveUpEvents( this, e, - () => ScriptCast(this.Document.onDragScript)?.script.run({ this: this.Document, value: { doc: value, e } }).result, + () => ScriptCast(this.Document.onDragScript)?.script.run({ this: this.Document, value: { doc: value, e } }).result as boolean, emptyFunction, emptyFunction ); // prettier-ignore @@ -157,11 +157,11 @@ export class FontIconBox extends ViewBoxBaseComponent() { let noviceList: string[] = []; let text: string | undefined; - let getStyle: (val: string) => any = () => {}; + let getStyle: (val: string) => { [key: string]: string } = () => ({}); let icon: IconProp = 'caret-down'; const isViewDropdown = script?.script.originalScript.startsWith('{ return setView'); if (isViewDropdown) { - const selected = Array.from(script?.script.run({ _readOnly_: true }).result) as Doc[]; + const selected = Array.from(script?.script.run({ _readOnly_: true }).result as Doc[]); // const selected = DocumentView.SelectedDocs(); if (selected.lastElement()) { if (StrCast(selected.lastElement().type) === DocumentType.COL) { @@ -190,7 +190,7 @@ export class FontIconBox extends ViewBoxBaseComponent() { } noviceList = [CollectionViewType.Freeform, CollectionViewType.Schema, CollectionViewType.Carousel3D, CollectionViewType.Stacking, CollectionViewType.NoteTaking]; } else { - text = script?.script.run({ this: this.Document, value: '', _readOnly_: true }).result; + text = script?.script.run({ this: this.Document, value: '', _readOnly_: true }).result as string; // text = StrCast((RichTextMenu.Instance?.TextView?.EditorView ? RichTextMenu.Instance : Doc.UserDoc()).fontFamily); getStyle = (val: string) => ({ fontFamily: val }); } @@ -231,8 +231,8 @@ export class FontIconBox extends ViewBoxBaseComponent() { * Color button */ @computed get colorButton() { - const color = this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.Color); - const curColor = this.colorScript?.script.run({ this: this.Document, value: undefined, _readOnly_: true }).result ?? 'transparent'; + const color = this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.Color) as string; + const curColor = (this.colorScript?.script.run({ this: this.Document, value: undefined, _readOnly_: true }).result as string) ?? 'transparent'; const tooltip: string = StrCast(this.Document.toolTip); return ( @@ -251,7 +251,7 @@ export class FontIconBox extends ViewBoxBaseComponent() { type={Type.PRIM} color={color} background={SnappingManager.userBackgroundColor} - icon={this.Icon(color)!} + icon={this.Icon(color) ?? undefined} tooltip={tooltip} label={this.label} /> @@ -262,9 +262,9 @@ export class FontIconBox extends ViewBoxBaseComponent() { const tooltip: string = StrCast(this.Document.toolTip); const script = ScriptCast(this.Document.onClick)?.script; - const toggleStatus = script?.run({ this: this.Document, self: this.Document, value: undefined, _readOnly_: true }).result; + const toggleStatus = script?.run({ this: this.Document, self: this.Document, value: undefined, _readOnly_: true }).result as boolean; // Colors - const color = this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.Color); + const color = this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.Color) as string; const items = DocListCast(this.dataDoc.data); const multiDoc = this.Document; return ( @@ -272,13 +272,13 @@ export class FontIconBox extends ViewBoxBaseComponent() { tooltip={`Toggle ${tooltip}`} type={Type.PRIM} color={color} - onPointerDown={e => script && !toggleStatus && setupMoveUpEvents(this, e, returnFalse, emptyFunction, e => script.run({ this: multiDoc, value: undefined, _readOnly_: false }))} + onPointerDown={e => script && !toggleStatus && setupMoveUpEvents(this, e, returnFalse, emptyFunction, () => script.run({ this: multiDoc, value: undefined, _readOnly_: false }))} isToggle={script ? true : false} toggleStatus={toggleStatus} //background={SnappingManager.userBackgroundColor} label={this.label} items={DocListCast(this.dataDoc.data).map(item => ({ - icon: , + icon: , tooltip: StrCast(item.toolTip), val: StrCast(item.toolType), }))} @@ -300,9 +300,9 @@ export class FontIconBox extends ViewBoxBaseComponent() { const script = ScriptCast(this.Document.onClick); const double = ScriptCast(this.Document.onDoubleClick); - const toggleStatus = script?.script.run({ this: this.Document, value: undefined, _readOnly_: true }).result ?? false; + const toggleStatus = (script?.script.run({ this: this.Document, value: undefined, _readOnly_: true }).result as boolean) ?? false; // Colors - const color = this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.Color); + const color = this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.Color) as string; // const backgroundColor = this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.BackgroundColor); return ( @@ -337,30 +337,30 @@ export class FontIconBox extends ViewBoxBaseComponent() { * Default */ @computed get defaultButton() { - const color = this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.Color); - const tooltip: string = StrCast(this.Document.toolTip); + const color = this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.Color) as string; + const tooltip = StrCast(this.Document.toolTip); - return ; + return ; } @computed get editableText() { const script = ScriptCast(this.Document.script); const checkResult = script?.script.run({ this: this.Document, value: '', _readOnly_: true }).result; - const setValue = (value: string): boolean => script?.script.run({ this: this.Document, value, _readOnly_: false }).result; + const setValue = (value: string) => script?.script.run({ this: this.Document, value, _readOnly_: false }).result as boolean; return (
- script?.script.run({ this: this.Document, value: '', _readOnly_: true }).result} SetValue={setValue} oneLine contents={checkResult} /> + script?.script.run({ this: this.Document, value: '', _readOnly_: true }).result as string} SetValue={setValue} oneLine contents={checkResult} />
); } renderButton = () => { - const color = this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.Color); + const color = this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.Color) as string; const tooltip = StrCast(this.Document.toolTip); const scriptFunc = () => ScriptCast(this.Document.onClick)?.script.run({ this: this.Document, _readOnly_: false }); const btnProps = { tooltip, icon: this.Icon(color)!, label: this.label }; diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx index ce7552047..51dd494da 100644 --- a/src/client/views/nodes/ImageBox.tsx +++ b/src/client/views/nodes/ImageBox.tsx @@ -35,6 +35,7 @@ import { FieldView, FieldViewProps } from './FieldView'; import { FocusViewOptions } from './FocusViewOptions'; import './ImageBox.scss'; import { OpenWhere } from './OpenWhere'; +import { SnappingManager } from '../../util/SnappingManager'; export class ImageEditorData { // eslint-disable-next-line no-use-before-define @@ -73,7 +74,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent() { private _marqueeref = React.createRef(); private _mainCont: React.RefObject = React.createRef(); private _annotationLayer: React.RefObject = React.createRef(); - @observable _savedAnnotations = new ObservableMap(); + @observable _savedAnnotations = new ObservableMap(); @observable _curSuffix = ''; @observable _error = ''; @observable _isHovering = false; // flag to switch between primary and alternate images on hover @@ -328,7 +329,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent() { }) } style={{ - display: (this._props.isContentActive() !== false && DragManager.DocDragData?.canEmbed) || this.dataDoc[this.fieldKey + '_alternates'] ? 'block' : 'none', + display: (this._props.isContentActive() !== false && SnappingManager.CanEmbed) || this.dataDoc[this.fieldKey + '_alternates'] ? 'block' : 'none', width: 'min(10%, 25px)', height: 'min(10%, 25px)', background: usePath === undefined ? 'white' : usePath === 'alternate' ? 'black' : 'gray', @@ -346,7 +347,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent() { const defaultUrl = new URL(ClientUtils.prepend('/assets/unknown-file-icon-hi.png')); const altpaths = alts - ?.map(doc => (doc instanceof Doc ? ImageCast(doc[Doc.LayoutFieldKey(doc)])?.url ?? defaultUrl : defaultUrl)) + ?.map(doc => (doc instanceof Doc ? (ImageCast(doc[Doc.LayoutFieldKey(doc)])?.url ?? defaultUrl) : defaultUrl)) .filter(url => url) .map(url => this.choosePath(url)) ?? []; // acc ess the primary layout data of the alternate documents const paths = field ? [this.choosePath(field.url), ...altpaths] : altpaths; @@ -356,7 +357,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent() { @computed get content() { TraceMobx(); - const backColor = DashColor(this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.BackgroundColor) as string ?? Colors.WHITE); + const backColor = DashColor((this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.BackgroundColor) as string) ?? Colors.WHITE); const backAlpha = backColor.red() === 0 && backColor.green() === 0 && backColor.blue() === 0 ? backColor.alpha() : 1; const srcpath = this.layoutDoc.hideImage ? '' : this.paths[0]; const fadepath = this.layoutDoc.hideImage ? '' : this.paths.lastElement(); diff --git a/src/client/views/nodes/KeyValueBox.tsx b/src/client/views/nodes/KeyValueBox.tsx index 66e210c03..9e77e0973 100644 --- a/src/client/views/nodes/KeyValueBox.tsx +++ b/src/client/views/nodes/KeyValueBox.tsx @@ -1,4 +1,3 @@ -/* eslint-disable jsx-a11y/control-has-associated-label */ import { action, computed, makeObservable, observable } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; @@ -35,7 +34,7 @@ export class KeyValueBox extends ViewBoxBaseComponent() { public static LayoutString() { return FieldView.LayoutString(KeyValueBox, 'data'); } - constructor(props: any) { + constructor(props: FieldViewProps) { super(props); makeObservable(this); } @@ -88,7 +87,7 @@ export class KeyValueBox extends ViewBoxBaseComponent() { const type: 'computed' | 'script' | false = rawvalue.startsWith(':=') ? 'computed' : rawvalue.startsWith('$=') ? 'script' : false; rawvalue = type ? rawvalue.substring(2) : rawvalue; rawvalue = rawvalue.replace(/.*\(\((.*)\)\)/, 'dashCallChat(_setCacheResult_, this, `$1`)'); - const value = ["'", '"', '`'].includes(rawvalue.length ? rawvalue[0] : '') || !isNaN(rawvalue as any) ? rawvalue : '`' + rawvalue + '`'; + const value = ["'", '"', '`'].includes(rawvalue.length ? rawvalue[0] : '') || !isNaN(+rawvalue) ? rawvalue : '`' + rawvalue + '`'; let script = ScriptField.CompileScript(rawvalue, {}, true, undefined, DocumentIconContainer.getTransformer()); if (!script.compiled) { @@ -116,7 +115,7 @@ export class KeyValueBox extends ViewBoxBaseComponent() { if (key) target[key] = script.originalScript; return false; } - field === undefined && (field = res.result instanceof Array ? new List(res.result) : res.result); + field === undefined && (field = res.result instanceof Array ? new List(res.result) : (res.result as FieldType)); } } if (!key) return false; @@ -165,7 +164,6 @@ export class KeyValueBox extends ViewBoxBaseComponent() { const rows: JSX.Element[] = []; let i = 0; - const self = this; const keys = Object.keys(ids).slice(); // for (const key of [...keys.filter(id => id !== 'layout' && !id.includes('_')).sort(), ...keys.filter(id => id === 'layout' || id.includes('_')).sort()]) { const sortedKeys = keys.sort((a: string, b: string) => { @@ -184,12 +182,12 @@ export class KeyValueBox extends ViewBoxBaseComponent() { addDocTab={this._props.addDocTab} PanelWidth={this._props.PanelWidth} PanelHeight={this.rowHeight} - ref={(function () { + ref={(() => { let oldEl: KeyValuePair | undefined; return (el: KeyValuePair) => { - if (oldEl) self.rows.splice(self.rows.indexOf(oldEl), 1); + if (oldEl) this.rows.splice(this.rows.indexOf(oldEl), 1); oldEl = el; - if (el) self.rows.push(el); + if (el) this.rows.push(el); }; })()} keyWidth={100 - this._splitPercentage} diff --git a/src/client/views/nodes/KeyValuePair.tsx b/src/client/views/nodes/KeyValuePair.tsx index 0956be3e9..3023716b1 100644 --- a/src/client/views/nodes/KeyValuePair.tsx +++ b/src/client/views/nodes/KeyValuePair.tsx @@ -1,4 +1,3 @@ -/* eslint-disable jsx-a11y/control-has-associated-label */ import { Tooltip } from '@mui/material'; import { action, makeObservable, observable } from 'mobx'; import { observer } from 'mobx-react'; @@ -9,7 +8,7 @@ import { Doc, Field } from '../../../fields/Doc'; import { DocCast } from '../../../fields/Types'; import { DocumentOptions, FInfo } from '../../documents/Documents'; import { Transform } from '../../util/Transform'; -import { undoBatch } from '../../util/UndoManager'; +import { undoable } from '../../util/UndoManager'; import { ContextMenu } from '../ContextMenu'; import { EditableView } from '../EditableView'; import { ObservableReactComponent } from '../ObservableReactComponent'; @@ -34,7 +33,7 @@ export class KeyValuePair extends ObservableReactComponent { @observable private isPointerOver = false; @observable public isChecked = false; private checkbox = React.createRef(); - constructor(props: any) { + constructor(props: KeyValuePairProps) { super(props); makeObservable(this); } @@ -91,11 +90,11 @@ export class KeyValuePair extends ObservableReactComponent { type="button" style={hover} className="keyValuePair-td-key-delete" - onClick={undoBatch(() => { + onClick={undoable(() => { if (Object.keys(this._props.doc).indexOf(this._props.keyName) !== -1) { delete this._props.doc[this._props.keyName]; } else delete DocCast(this._props.doc.proto)?.[this._props.keyName]; - })}> + }, 'set key value')}> X diff --git a/src/client/views/nodes/LinkBox.tsx b/src/client/views/nodes/LinkBox.tsx index 8d6ae9f73..4d9d2460e 100644 --- a/src/client/views/nodes/LinkBox.tsx +++ b/src/client/views/nodes/LinkBox.tsx @@ -27,6 +27,7 @@ export class LinkBox extends ViewBoxBaseComponent() { public static LayoutString(fieldKey: string = 'link') { return FieldView.LayoutString(LinkBox, fieldKey); } + _hackToSeeIfDeleted: NodeJS.Timeout | undefined; _disposers: { [name: string]: IReactionDisposer } = {}; @observable _forceAnimate: number = 0; // forces xArrow to animate when a transition animation is detected on something that affects an anchor @observable _hide = false; // don't render if anchor is not visible since that breaks xAnchor @@ -43,7 +44,6 @@ export class LinkBox extends ViewBoxBaseComponent() { const anchor = anch?.layout_unrendered ? DocCast(anch.annotationOn) : anch; return DocumentView.getDocumentView(anchor, this.DocumentView?.().containerViewPath?.().lastElement()); }; - _hackToSeeIfDeleted: any; componentWillUnmount() { this._hackToSeeIfDeleted && clearTimeout(this._hackToSeeIfDeleted); Object.keys(this._disposers).forEach(key => this._disposers[key]()); @@ -68,7 +68,7 @@ export class LinkBox extends ViewBoxBaseComponent() { let a1 = a && document.getElementById(a.ViewGuid); let a2 = b && document.getElementById(b.ViewGuid); // test whether the anchors themselves are hidden,... - if (!a1 || !a2 || (a?.ContentDiv as any)?.hidden || (b?.ContentDiv as any)?.hidden) this._hide = true; + if (!a1 || !a2 || a?.ContentDiv?.hidden || b?.ContentDiv?.hidden) this._hide = true; else { // .. or whether any of their DOM parents are hidden for (; a1 && !a1.hidden; a1 = a1.parentElement); @@ -151,11 +151,11 @@ export class LinkBox extends ViewBoxBaseComponent() { this._forceAnimate += 0.01; }) ); // this forces an update during a transition animation - const highlight = this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.Highlighting); + const highlight = this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.Highlighting) as { highlightStyle: string; highlightColor: string; highlightIndex: number; highlightStroke: boolean }; const highlightColor = highlight?.highlightIndex ? highlight?.highlightColor : undefined; - const color = this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.Color); - const fontFamily = this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.FontFamily); - const fontSize = this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.FontSize); + const color = this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.Color) as string; + const fontFamily = this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.FontFamily) as string; + const fontSize = this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.FontSize) as number; const fontColor = (c => (c !== 'transparent' ? c : undefined))(StrCast(this.layoutDoc.link_fontColor)); // eslint-disable-next-line camelcase const { stroke_markerScale: strokeMarkerScale, stroke_width: strokeRawWidth, stroke_startMarker: strokeStartMarker, stroke_endMarker: strokeEndMarker, stroke_dash: strokeDash } = this.Document; @@ -248,7 +248,7 @@ export class LinkBox extends ViewBoxBaseComponent() { 2 ); return ( -
+
= undefined; @observable _toolTipText = ''; @observable _hrefInd = 0; - constructor(props: any) { + constructor(props: LinkDocPreviewProps) { super(props); makeObservable(this); } @@ -104,7 +104,7 @@ export class LinkDocPreview extends ObservableReactComponent { - !this._linkDocRef.current?.contains(e.target as any) && LinkInfo.Clear(); // close preview when not clicking anywhere other than the info bar of the preview + !this._linkDocRef.current?.contains(e.target as HTMLElement) && LinkInfo.Clear(); // close preview when not clicking anywhere other than the info bar of the preview }; @action @@ -144,7 +144,7 @@ export class LinkDocPreview extends ObservableReactComponent() { return FieldView.LayoutString(LoadingBox, fieldKey); } - _timer: any; + _timer: NodeJS.Timeout | undefined; @observable progress = ''; componentDidMount() { if (!Doc.CurrentlyLoading?.includes(this.Document)) { diff --git a/src/client/views/nodes/MapBox/MapBox.tsx b/src/client/views/nodes/MapBox/MapBox.tsx index d7687e03e..c66f7c726 100644 --- a/src/client/views/nodes/MapBox/MapBox.tsx +++ b/src/client/views/nodes/MapBox/MapBox.tsx @@ -1,5 +1,3 @@ -/* eslint-disable jsx-a11y/no-static-element-interactions */ -/* eslint-disable jsx-a11y/click-events-have-key-events */ import { IconLookup, faCircleXmark, faGear, faPause, faPlay, faRotate } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { Checkbox, FormControlLabel, TextField } from '@mui/material'; @@ -481,8 +479,8 @@ export class MapBox extends ViewBoxAnnotatableComponent() { console.log('deleting'); if (this._selectedPinOrRoute) { // Removes filter - Doc.setDocFilter(this.Document, 'latitude', this._selectedPinOrRoute.latitude, 'remove'); - Doc.setDocFilter(this.Document, 'longitude', this._selectedPinOrRoute.longitude, 'remove'); + Doc.setDocFilter(this.Document, 'latitude', NumCast(this._selectedPinOrRoute.latitude), 'remove'); + Doc.setDocFilter(this.Document, 'longitude', NumCast(this._selectedPinOrRoute.longitude), 'remove'); Doc.setDocFilter(this.Document, LinkedTo, `mapPin=${Field.toScriptString(DocCast(this._selectedPinOrRoute))}`, 'remove'); this.removePushpinOrRoute(this._selectedPinOrRoute); @@ -1152,7 +1150,7 @@ export class MapBox extends ViewBoxAnnotatableComponent() { _textRef = React.createRef(); render() { const scale = this._props.NativeDimScaling?.() || 1; - const parscale = scale === 1 ? 1 : this.ScreenToLocalBoxXf().Scale ?? 1; + const parscale = scale === 1 ? 1 : (this.ScreenToLocalBoxXf().Scale ?? 1); return (
diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx index 8db68ddfe..c03694dd9 100644 --- a/src/client/views/nodes/PDFBox.tsx +++ b/src/client/views/nodes/PDFBox.tsx @@ -1,5 +1,3 @@ -/* eslint-disable jsx-a11y/no-static-element-interactions */ -/* eslint-disable jsx-a11y/control-has-associated-label */ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { action, computed, IReactionDisposer, makeObservable, observable, reaction, runInAction } from 'mobx'; import { observer } from 'mobx-react'; @@ -76,7 +74,7 @@ export class PDFBox extends ViewBoxAnnotatableComponent() { }); else if (PDFBox.pdfpromise.get(this.pdfUrl.url.href)) PDFBox.pdfpromise.get(this.pdfUrl.url.href)?.then( - action((pdf: any) => { + action(pdf => { this._pdf = pdf; }) ); @@ -108,7 +106,8 @@ export class PDFBox extends ViewBoxAnnotatableComponent() { }; crop = (region: Doc | undefined, addCrop?: boolean) => { - if (!region) return undefined; + const docViewContent = this.DocumentView?.().ContentDiv; + if (!region || !docViewContent) return undefined; const cropping = Doc.MakeCopy(region, true); cropping.layout_unrendered = false; // text selection have this cropping.text_inlineAnnotations = undefined; // text selections have this -- it causes them not to be rendered. @@ -120,7 +119,6 @@ export class PDFBox extends ViewBoxAnnotatableComponent() { regionData.followLinkToggle = true; this.addDocument(region); - const docViewContent = this.DocumentView?.().ContentDiv!; const newDiv = docViewContent.cloneNode(true) as HTMLDivElement; newDiv.style.width = NumCast(this.layoutDoc._width).toString(); newDiv.style.height = NumCast(this.layoutDoc._height).toString(); @@ -162,7 +160,7 @@ export class PDFBox extends ViewBoxAnnotatableComponent() { (NumCast(region.x) * this._props.PanelWidth()) / NumCast(this.dataDoc[this.fieldKey + '_nativeWidth']), 4 ) - .then((dataUrl: any) => { + .then(dataUrl => { ClientUtils.convertDataUri(dataUrl, region[Id]).then(returnedfilename => setTimeout( action(() => { @@ -172,7 +170,7 @@ export class PDFBox extends ViewBoxAnnotatableComponent() { ) ); }) - .catch((error: any) => { + .catch(error => { console.error('oops, something went wrong!', error); }); @@ -181,9 +179,10 @@ export class PDFBox extends ViewBoxAnnotatableComponent() { updateIcon = () => { // currently we render pdf icons as text labels - const docViewContent = this.DocumentView?.().ContentDiv!; + const docViewContent = this.DocumentView?.().ContentDiv; const filename = this.layoutDoc[Id] + '-icon' + new Date().getTime(); this._pdfViewer?._mainCont.current && + docViewContent && UpdateIcon( filename, docViewContent, @@ -475,6 +474,7 @@ export class PDFBox extends ViewBoxAnnotatableComponent() { const cm = ContextMenu.Instance; const options = cm.findByDescription('Options...'); const optionItems: ContextMenuProps[] = options && 'subitems' in options ? options.subitems : []; + !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" }); @@ -656,7 +656,7 @@ export class PDFBox extends ViewBoxAnnotatableComponent() { else { if (!PDFBox.pdfpromise.get(href)) PDFBox.pdfpromise.set(href, Pdfjs.getDocument(href).promise); PDFBox.pdfpromise.get(href)?.then( - action((pdf: any) => { + action(pdf => { PDFBox.pdfcache.set(href, (this._pdf = pdf)); }) ); diff --git a/src/client/views/nodes/PhysicsBox/PhysicsSimulationBox.tsx b/src/client/views/nodes/PhysicsBox/PhysicsSimulationBox.tsx index f88eb3bca..31a1a398b 100644 --- a/src/client/views/nodes/PhysicsBox/PhysicsSimulationBox.tsx +++ b/src/client/views/nodes/PhysicsBox/PhysicsSimulationBox.tsx @@ -1,8 +1,5 @@ /* eslint-disable camelcase */ -/* eslint-disable jsx-a11y/control-has-associated-label */ /* eslint-disable @typescript-eslint/no-unused-vars */ -/* eslint-disable jsx-a11y/no-noninteractive-element-interactions */ -/* eslint-disable jsx-a11y/click-events-have-key-events */ /* eslint-disable react/no-array-index-key */ /* eslint-disable react/jsx-props-no-spreading */ /* eslint-disable no-return-assign */ @@ -1009,7 +1006,7 @@ export class PhysicsSimulationBox extends ViewBoxAnnotatableComponent (this.dataDoc.hintDialogueOpen = false)}> Hints - {this.selectedQuestion.hints?.map((hint: any, index: number) => ( + {this.selectedQuestion.hints?.map((hint: { description: string; content: string }, index: number) => (
@@ -1985,7 +1982,13 @@ export class PhysicsSimulationBox extends ViewBoxAnnotatableComponent() { this.dataDoc[this._props.fieldKey] = new VideoField(this.result.accessPaths.client); // stringify the presentation and store it if (presentation?.movements) { - const presCopy = { ...presentation }; - presCopy.movements = presentation.movements.map(movement => ({ ...movement, doc: movement.doc[Id] })) as any; + const presCopy = { ...presentation, movements: presentation.movements.map(movement => ({ ...movement, doc: (movement.doc as Doc)[Id] })) }; this.dataDoc[this.fieldKey + '_presentation'] = JSON.stringify(presCopy); } }; @@ -210,7 +209,7 @@ ScriptingGlobals.add(function getCurrentRecording() { }); // eslint-disable-next-line prefer-arrow-callback ScriptingGlobals.add(function getWorkspaceRecordings() { - return new List(['Record Workspace', `Record Webcam`, ...DocListCast(Doc.UserDoc().workspaceRecordings)]); + return new List(['Record Workspace', `Record Webcam`, ...DocListCast(Doc.UserDoc().workspaceRecordings)]); }); // eslint-disable-next-line prefer-arrow-callback ScriptingGlobals.add(function isWorkspaceRecording() { diff --git a/src/client/views/nodes/ScreenshotBox.tsx b/src/client/views/nodes/ScreenshotBox.tsx index 9ef1071f7..6289470b6 100644 --- a/src/client/views/nodes/ScreenshotBox.tsx +++ b/src/client/views/nodes/ScreenshotBox.tsx @@ -20,7 +20,7 @@ import { DocumentType } from '../../documents/DocumentTypes'; import { Docs } from '../../documents/Documents'; import { CaptureManager } from '../../util/CaptureManager'; import { SettingsManager } from '../../util/SettingsManager'; -import { TrackMovements } from '../../util/TrackMovements'; +import { Movement, TrackMovements } from '../../util/TrackMovements'; import { ContextMenu } from '../ContextMenu'; import { ViewBoxAnnotatableComponent } from '../DocComponent'; import { DocViewUtils } from '../DocViewUtils'; @@ -31,10 +31,11 @@ import { FieldView, FieldViewProps } from './FieldView'; import './ScreenshotBox.scss'; import { VideoBox } from './VideoBox'; import { FormattedTextBox } from './formattedText/FormattedTextBox'; +import { IconProp } from '@fortawesome/fontawesome-svg-core'; -declare class MediaRecorder { - constructor(e: any, options?: any); // whatever MediaRecorder has -} +// declare class MediaRecorder { +// constructor(e: any, options?: any); // whatever MediaRecorder has +// } // interface VideoTileProps { // raised: { coord: Vector2, off: Vector3 }[]; @@ -117,8 +118,8 @@ export class ScreenshotBox extends ViewBoxAnnotatableComponent() public static LayoutString(fieldKey: string) { return FieldView.LayoutString(ScreenshotBox, fieldKey); } - private _audioRec: any; - private _videoRec: any; + private _audioRec: MediaRecorder | undefined; + private _videoRec: MediaRecorder | undefined; @observable private _videoRef: HTMLVideoElement | null = null; @observable _screenCapture = false; @computed get recordingStart() { @@ -136,7 +137,7 @@ export class ScreenshotBox extends ViewBoxAnnotatableComponent() }; videoLoad = () => { - const aspect = this._videoRef!.videoWidth / this._videoRef!.videoHeight; + const aspect = (this._videoRef?.videoWidth || 0) / (this._videoRef?.videoHeight || 1); const nativeWidth = Doc.NativeWidth(this.layoutDoc); const nativeHeight = Doc.NativeHeight(this.layoutDoc); if (!nativeWidth || !nativeHeight) { @@ -166,7 +167,7 @@ export class ScreenshotBox extends ViewBoxAnnotatableComponent() } specificContextMenu = (): void => { - const subitems = [{ description: 'Screen Capture', event: this.toggleRecording, icon: 'expand-arrows-alt' as any }]; + const subitems = [{ description: 'Screen Capture', event: this.toggleRecording, icon: 'expand-arrows-alt' as IconProp }]; ContextMenu.Instance.addItem({ description: 'Options...', subitems, icon: 'video' }); }; @@ -221,29 +222,29 @@ export class ScreenshotBox extends ViewBoxAnnotatableComponent() Pause = () => this._screenCapture && this.toggleRecording(); toggleRecording = async () => { - if (!this._screenCapture) { + if (!this._screenCapture && this._videoRef) { this._audioRec = new MediaRecorder(await navigator.mediaDevices.getUserMedia({ audio: true })); - const audChunks: any = []; - this._audioRec.ondataavailable = (e: any) => audChunks.push(e.data); + const audChunks: Blob[] = []; + this._audioRec.ondataavailable = e => audChunks.push(e.data); this._audioRec.onstop = async () => { - const [{ result }] = await Networking.UploadFilesToServer(audChunks.map((file: any) => ({ file }))); + const [{ result }] = await Networking.UploadFilesToServer(audChunks.map(file => ({ file }))); if (!(result instanceof Error)) { this.dataDoc[this._props.fieldKey + '_audio'] = new AudioField(result.accessPaths.agnostic.client); } }; - this._videoRef!.srcObject = await (navigator.mediaDevices as any).getDisplayMedia({ video: true }); - this._videoRec = new MediaRecorder(this._videoRef!.srcObject); - const vidChunks: any = []; + this._videoRef.srcObject = await navigator.mediaDevices.getDisplayMedia({ video: true }); + this._videoRec = new MediaRecorder(this._videoRef.srcObject); + const vidChunks: Blob[] = []; this._videoRec.onstart = () => { if (this.dataDoc[this._props.fieldKey + '_trackScreen']) TrackMovements.Instance.start(); this.dataDoc[this._props.fieldKey + '_recordingStart'] = new DateField(new Date()); }; - this._videoRec.ondataavailable = (e: any) => vidChunks.push(e.data); + this._videoRec.ondataavailable = e => vidChunks.push(e.data); this._videoRec.onstop = async () => { const presentation = TrackMovements.Instance.yieldPresentation(); if (presentation?.movements) { const presCopy = { ...presentation }; - presCopy.movements = presentation.movements.map(movement => ({ ...movement, doc: movement.doc[Id] })) as any; + presCopy.movements = presentation.movements.map(movement => ({ ...movement, doc: (movement.doc as Doc)[Id] }) as Movement); this.dataDoc[this.fieldKey + '_presentation'] = JSON.stringify(presCopy); } TrackMovements.Instance.finish(); diff --git a/src/client/views/nodes/ScriptingBox.tsx b/src/client/views/nodes/ScriptingBox.tsx index bc19d7ad1..8da422039 100644 --- a/src/client/views/nodes/ScriptingBox.tsx +++ b/src/client/views/nodes/ScriptingBox.tsx @@ -1,8 +1,8 @@ /* eslint-disable react/button-has-type */ -/* eslint-disable jsx-a11y/no-static-element-interactions */ import { action, computed, makeObservable, observable } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; +import ResizeObserver from 'resize-observer-polyfill'; import { returnAlways, returnEmptyString } from '../../../ClientUtils'; import { Doc } from '../../../fields/Doc'; import { List } from '../../../fields/List'; @@ -10,21 +10,26 @@ import { listSpec } from '../../../fields/Schema'; import { ScriptField } from '../../../fields/ScriptField'; import { BoolCast, Cast, DocCast, NumCast, ScriptCast, StrCast } from '../../../fields/Types'; import { TraceMobx } from '../../../fields/util'; +import { DocumentType } from '../../documents/DocumentTypes'; +import { Docs } from '../../documents/Documents'; import { DragManager } from '../../util/DragManager'; import { ScriptManager } from '../../util/ScriptManager'; -import { CompileScript, ScriptParam } from '../../util/Scripting'; +import { CompileError, CompileScript, ScriptParam } from '../../util/Scripting'; import { ScriptingGlobals } from '../../util/ScriptingGlobals'; import { ContextMenu } from '../ContextMenu'; import { ViewBoxAnnotatableComponent } from '../DocComponent'; import { EditableView } from '../EditableView'; import { OverlayView } from '../OverlayView'; -import { FieldView, FieldViewProps } from './FieldView'; import { DocumentIconContainer } from './DocumentIcon'; +import { FieldView, FieldViewProps } from './FieldView'; import './ScriptingBox.scss'; -import { Docs } from '../../documents/Documents'; -import { DocumentType } from '../../documents/DocumentTypes'; +import * as ts from 'typescript'; +import { FieldType } from '../../../fields/ObjectField'; + +// eslint-disable-next-line @typescript-eslint/no-var-requires +const getCaretCoordinates = require('textarea-caret'); -const _global = (window /* browser */ || global) /* node */ as any; +// eslint-disable-next-line @typescript-eslint/no-var-requires const ReactTextareaAutocomplete = require('@webscopeio/react-textarea-autocomplete').default; @observer @@ -41,9 +46,9 @@ export class ScriptingBox extends ViewBoxAnnotatableComponent() @observable private _function: boolean = false; @observable private _spaced: boolean = false; - @observable private _scriptKeys: any = ScriptingGlobals.getGlobals(); - @observable private _scriptingDescriptions: any = ScriptingGlobals.getDescriptions(); - @observable private _scriptingParams: any = ScriptingGlobals.getParameters(); + @observable private _scriptKeys = ScriptingGlobals.getGlobals(); + @observable private _scriptingDescriptions = ScriptingGlobals.getDescriptions(); + @observable private _scriptingParams = ScriptingGlobals.getParameters(); @observable private _currWord: string = ''; @observable private _suggestions: string[] = []; @@ -52,20 +57,20 @@ export class ScriptingBox extends ViewBoxAnnotatableComponent() @observable private _suggestionBoxY: number = 0; @observable private _lastChar: string = ''; - @observable private _suggestionRef: any = React.createRef(); - @observable private _scriptTextRef: any = React.createRef(); + @observable private _suggestionRef = React.createRef(); + @observable private _scriptTextRef = React.createRef(); - @observable private _selection: any = 0; + @observable private _selection = 0; @observable private _paramSuggestion: boolean = false; - @observable private _scriptSuggestedParams: any = ''; - @observable private _scriptParamsText: any = ''; + @observable private _scriptSuggestedParams: JSX.Element | string = ''; + @observable private _scriptParamsText = ''; constructor(props: FieldViewProps) { super(props); makeObservable(this); if (!this.compileParams.length) { - const params = ScriptCast(this.dataDoc[this._props.fieldKey])?.script.options.params as { [key: string]: any }; + const params = ScriptCast(this.dataDoc[this._props.fieldKey])?.script.options.params as { [key: string]: string }; if (params) { this.compileParams = Array.from(Object.keys(params)) .filter(p => !p.startsWith('_')) @@ -106,26 +111,16 @@ export class ScriptingBox extends ViewBoxAnnotatableComponent() this.dataDoc[this.fieldKey + '-params'] = new List(value); } - getValue(result: any, descrip: boolean) { - if (typeof result === 'object') { - const text = descrip ? result[1] : result[2]; - return text !== undefined ? text : ''; - } - return ''; - } - onClickScriptDisable = returnAlways; @action componentDidMount() { this._props.setContentViewBox?.(this); this.rawText = this.rawScript; - const resizeObserver = new _global.ResizeObserver( + const resizeObserver = new ResizeObserver( action(() => { const area = document.querySelector('textarea'); if (area) { - // eslint-disable-next-line global-require - const getCaretCoordinates = require('textarea-caret'); const caret = getCaretCoordinates(area, this._selection); this.resetSuggestionPos(caret); } @@ -135,12 +130,12 @@ export class ScriptingBox extends ViewBoxAnnotatableComponent() } @action - resetSuggestionPos(caret: any) { + resetSuggestionPos(caret: { top: number; left: number; height: number }) { if (!this._suggestionRef.current || !this._scriptTextRef.current) return; const suggestionWidth = this._suggestionRef.current.offsetWidth; const scriptWidth = this._scriptTextRef.current.offsetWidth; const { top } = caret; - const { x } = this.dataDoc; + const x = NumCast(this.layoutDoc.x); let { left } = caret; if (left + suggestionWidth > x + scriptWidth) { const diff = left + suggestionWidth - (x + scriptWidth); @@ -171,8 +166,8 @@ export class ScriptingBox extends ViewBoxAnnotatableComponent() // displays error message @action - onError = (error: any) => { - this._errorMessage = error?.message ? error.message : error?.map((entry: any) => entry.messageText).join(' ') || ''; + onError = (errors: ts.Diagnostic[] | string) => { + this._errorMessage = typeof errors === 'string' ? errors : errors.map(entry => entry.toString()).join(' ') || ''; }; // checks if the script compiles using CompileScript method and inputting params @@ -184,7 +179,7 @@ export class ScriptingBox extends ViewBoxAnnotatableComponent() }); const result = !this.rawText.trim() - ? ({ compiled: false, errors: undefined } as any) + ? ({ compiled: false, errors: [] } as CompileError) : CompileScript(this.rawText, { editable: true, transformer: DocumentIconContainer.getTransformer(), @@ -192,7 +187,7 @@ export class ScriptingBox extends ViewBoxAnnotatableComponent() typecheck: false, }); this.dataDoc[this.fieldKey] = result.compiled ? new ScriptField(result, undefined, this.rawText) : undefined; - this.onError(result.compiled ? undefined : result.errors); + this.onError(result.compiled ? [] : result.errors); return result.compiled; }; @@ -200,7 +195,7 @@ export class ScriptingBox extends ViewBoxAnnotatableComponent() @action onRun = () => { if (this.onCompile()) { - const bindings: { [name: string]: any } = {}; + const bindings: { [name: string]: unknown } = {}; this.paramsNames.forEach(key => { bindings[key] = this.dataDoc[key]; }); @@ -294,8 +289,8 @@ export class ScriptingBox extends ViewBoxAnnotatableComponent() // sets field of the param name to the selected value in drop down box @action - viewChanged = (e: React.ChangeEvent, name: string) => { - const val = (e.target as any).selectedOptions[0].value; + viewChanged = (e: React.ChangeEvent, name: string) => { + const val = e.target.selectedOptions[0].value; this.dataDoc[name] = val[0] === 'S' ? val.substring(1) : val[0] === 'N' ? parseInt(val.substring(1)) : val.substring(1) === 'true'; }; @@ -309,7 +304,7 @@ export class ScriptingBox extends ViewBoxAnnotatableComponent() // adds option to create a copy to the context menu specificContextMenu = (): void => { const existingOptions = ContextMenu.Instance.findByDescription('Options...'); - const options = existingOptions && 'subitems' in existingOptions ? existingOptions.subitems : []; + const options = existingOptions?.subitems ?? []; options.push({ description: 'Create a Copy', event: this.onCopy, icon: 'copy' }); !existingOptions && ContextMenu.Instance.addItem({ description: 'Options...', subitems: options, icon: 'hand-point-right' }); }; @@ -381,7 +376,7 @@ export class ScriptingBox extends ViewBoxAnnotatableComponent() const results = script.compiled && script.run(); if (results && results.success) { this._errorMessage = ''; - this.dataDoc[parameter] = results.result; + this.dataDoc[parameter] = results.result as FieldType; return true; } this._errorMessage = 'invalid document'; @@ -524,18 +519,17 @@ export class ScriptingBox extends ViewBoxAnnotatableComponent() @action suggestionPos = () => { - // eslint-disable-next-line global-require - const getCaretCoordinates = require('textarea-caret'); + // eslint-disable-next-line @typescript-eslint/no-this-alias const This = this; document.querySelector('textarea')?.addEventListener('input', function () { - const caret = getCaretCoordinates(this, this.selectionEnd); - This._selection = this; + const caret = getCaretCoordinates(this, this.selectionEnd) as { top: number; left: number; height: number }; + // This._selection = this; This.resetSuggestionPos(caret); }); }; @action - keyHandler(e: any, pos: number) { + keyHandler(e: React.KeyboardEvent, pos: number) { e.stopPropagation(); if (this._lastChar === 'Enter') { this.rawText += ' '; @@ -602,7 +596,7 @@ export class ScriptingBox extends ViewBoxAnnotatableComponent() } @action - handlePosChange(number: any) { + handlePosChange(number: number) { this._caretPos = number; if (this._caretPos === 0) { this.rawText = ' ' + this.rawText; @@ -625,7 +619,7 @@ export class ScriptingBox extends ViewBoxAnnotatableComponent() placeholder="write your script here" onFocus={this.onFocus} onBlur={() => this._overlayDisposer?.()} - onChange={action((e: any) => { + onChange={action((e: React.ChangeEvent) => { this.rawText = e.target.value; })} value={this.rawText} @@ -633,24 +627,24 @@ export class ScriptingBox extends ViewBoxAnnotatableComponent() loadingComponent={() => Loading} trigger={{ ' ': { - dataProvider: (token: any) => this.handleToken(token), - component: (blob: any) => this.renderFuncListElement(blob.entity), - output: (item: any, trigger: any) => { + dataProvider: this.handleToken, + component: (blob: { entity: string }) => this.renderFuncListElement(blob.entity), + output: (item: string, trigger: string) => { this._spaced = true; return trigger + item.trim(); }, }, '.': { - dataProvider: (token: any) => this.handleToken(token), - component: (blob: any) => this.renderFuncListElement(blob.entity), - output: (item: any, trigger: any) => { + dataProvider: this.handleToken, + component: (blob: { entity: string }) => this.renderFuncListElement(blob.entity), + output: (item: string, trigger: string) => { this._spaced = true; return trigger + item.trim(); }, }, }} onKeyDown={(e: React.KeyboardEvent) => this.keyHandler(e, this._caretPos)} - onCaretPositionChange={(number: any) => this.handlePosChange(number)} + onCaretPositionChange={this.handlePosChange} />
); diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx index 1f285b300..4933869a7 100644 --- a/src/client/views/nodes/VideoBox.tsx +++ b/src/client/views/nodes/VideoBox.tsx @@ -125,8 +125,8 @@ export class VideoBox extends ViewBoxAnnotatableComponent() { } override PlayerTime = () => this.player?.currentTime; - override Pause = (update: boolean = true) => { - this.pause(update); + override Pause = () => { + this.pause(true); !this._keepCurrentlyPlaying && this.removeCurrentlyPlaying(); }; @@ -157,7 +157,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent() { }; // plays video - @action public Play = (update: boolean = true) => { + @action public Play = () => { if (this._playRegionTimer) return; this._playing = true; @@ -172,8 +172,8 @@ export class VideoBox extends ViewBoxAnnotatableComponent() { } try { this._audioPlayer && this.player && (this._audioPlayer.currentTime = this.player?.currentTime); - update && this.player && this.playFrom(start, undefined, true); - update && this._audioPlayer?.play(); + this.player && this.playFrom(start, undefined, true); + this._audioPlayer?.play(); } catch (e) { console.log('Video Play Exception:', e); } @@ -384,7 +384,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent() { getVideoThumbnails = () => { if (this.dataDoc[this.fieldKey + '_thumbnails'] !== undefined) return; this.dataDoc[this.fieldKey + '_thumbnails'] = new List(); - const thumbnailPromises: Promise[] = []; + const thumbnailPromises: Promise[] = []; const video = document.createElement('video'); video.onloadedmetadata = () => { @@ -467,7 +467,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent() { runInAction(() => { this._screenCapture = !this._screenCapture; }); - this._videoRef!.srcObject = !this._screenCapture ? null : await (navigator.mediaDevices).getDisplayMedia({ video: true }); + this._videoRef!.srcObject = !this._screenCapture ? null : await navigator.mediaDevices.getDisplayMedia({ video: true }); }, icon: 'expand-arrows-alt', }); @@ -557,9 +557,9 @@ export class VideoBox extends ViewBoxAnnotatableComponent() { style={this._fullScreen ? this.fullScreenSize() : this.isCropped ? { width: 'max-content', height: 'max-content', transform: `scale(${1 / NumCast(this.layoutDoc._freeform_scale)})`, transformOrigin: 'top left' } : {}} onCanPlay={this.videoLoad} controls={false} - onPlay={() => this.Play()} + onPlay={this.Play} onSeeked={this.updateTimecode} - onPause={() => this.Pause()} + onPause={this.Pause} onClick={this._fullScreen ? () => (this.playing() ? this.Pause() : this.Play()) : e => e.preventDefault()}> Not supported. diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx index be7e0f483..1fd73c226 100644 --- a/src/client/views/nodes/WebBox.tsx +++ b/src/client/views/nodes/WebBox.tsx @@ -1,4 +1,5 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { Property } from 'csstype'; import { htmlToText } from 'html-to-text'; import { action, computed, IReactionDisposer, makeObservable, observable, ObservableMap, reaction, runInAction } from 'mobx'; import { observer } from 'mobx-react'; @@ -21,7 +22,7 @@ import { DocumentType } from '../../documents/DocumentTypes'; import { DocUtils } from '../../documents/DocUtils'; import { ScriptingGlobals } from '../../util/ScriptingGlobals'; import { SnappingManager } from '../../util/SnappingManager'; -import { undoBatch, UndoManager } from '../../util/UndoManager'; +import { undoable, UndoManager } from '../../util/UndoManager'; import { MarqueeOptionsMenu } from '../collections/collectionFreeForm'; import { CollectionFreeFormView } from '../collections/collectionFreeForm/CollectionFreeFormView'; import { ContextMenu } from '../ContextMenu'; @@ -83,7 +84,7 @@ export class WebBox extends ViewBoxAnnotatableComponent() { this._marqueeing = val; } @observable private _iframe: HTMLIFrameElement | null = null; - @observable private _savedAnnotations = new ObservableMap(); + @observable private _savedAnnotations = new ObservableMap(); @observable private _scrollHeight = NumCast(this.layoutDoc.scrollHeight); @computed get _url() { return this.webField?.toString() || ''; @@ -121,11 +122,12 @@ export class WebBox extends ViewBoxAnnotatableComponent() { }); } try { + const contentWindow = this._iframe?.contentWindow; if (clear) { - this._iframe?.contentWindow?.getSelection()?.empty(); + contentWindow?.getSelection()?.empty(); } - if (searchString) { - (this._iframe?.contentWindow as any)?.find(searchString, false, bwd, true); + if (searchString && contentWindow && 'find' in contentWindow) { + (contentWindow.find as (str: string, caseSens?: boolean, backward?: boolean, wrapAround?: boolean) => void)(searchString, false, bwd, true); } } catch (e) { console.log('WebBox search error', e); @@ -142,7 +144,7 @@ export class WebBox extends ViewBoxAnnotatableComponent() { } }; - updateThumb = async () => { + updateIcon = async () => { if (!this._iframe) return; const scrollTop = NumCast(this.layoutDoc._layout_scrollTop); const nativeWidth = NumCast(this.layoutDoc.nativeWidth); @@ -154,7 +156,7 @@ export class WebBox extends ViewBoxAnnotatableComponent() { this.layoutDoc.thumb = undefined; this.Document.thumbLockout = true; // lock to prevent multiple thumb updates. CreateImage(this._webUrl.endsWith('/') ? this._webUrl.substring(0, this._webUrl.length - 1) : this._webUrl, this._iframe.contentDocument?.styleSheets ?? [], htmlString, nativeWidth, nativeHeight, scrollTop) - .then((dataUrl: any) => { + .then((dataUrl: string) => { if (dataUrl.includes('() { ) ); }) - .catch((error: any) => { + .catch((error: object) => { console.error('oops, something went wrong!', error); }); }; @@ -359,8 +361,8 @@ export class WebBox extends ViewBoxAnnotatableComponent() { return anchor; }; - _textAnnotationCreator: (() => ObservableMap) | undefined; - savedAnnotationsCreator: () => ObservableMap = () => this._textAnnotationCreator?.() || this._savedAnnotations; + _textAnnotationCreator: (() => ObservableMap) | undefined; + savedAnnotationsCreator: () => ObservableMap = () => this._textAnnotationCreator?.() || this._savedAnnotations; @action iframeMove = (e: PointerEvent) => { @@ -424,11 +426,11 @@ export class WebBox extends ViewBoxAnnotatableComponent() { sel.empty(); // Chrome else if (sel?.removeAllRanges) sel.removeAllRanges(); // Firefox // bcz: NEED TO unrotate e.clientX and e.clientY - const word = getWordAtPoint(e.target, e.clientX, e.clientY); + const target = e.target as HTMLElement; + const word = target && getWordAtPoint(target, e.clientX, e.clientY); this._setPreviewCursor?.(e.clientX, e.clientY, false, true, this.Document); MarqueeAnnotator.clearAnnotations(this._savedAnnotations); - const target = e.target as HTMLElement; if (!word && !target?.className?.includes('rangeslider') && !target?.onclick && !target?.parentElement?.onclick) { if (e.button !== 2) this.marqueeing = [e.clientX, e.clientY]; e.preventDefault(); @@ -468,8 +470,8 @@ export class WebBox extends ViewBoxAnnotatableComponent() { .inverse() .transformPoint(e.clientX, e.clientY - NumCast(this.layoutDoc.layout_scrollTop)); MarqueeAnnotator.clearAnnotations(this._savedAnnotations); - const word = getWordAtPoint(e.target, e.clientX, e.clientY); const target = e.target as HTMLElement; + const word = target && getWordAtPoint(target, e.clientX, e.clientY); if (!word && !target?.className?.includes('rangeslider') && !target?.onclick && !target?.parentElement?.onclick) { this.marqueeing = theclick; this._marqueeref.current?.onInitiateSelection(this.marqueeing); @@ -488,7 +490,7 @@ export class WebBox extends ViewBoxAnnotatableComponent() { } return undefined; } - addWebStyleSheetRule(sheet: CSSStyleSheet | null | undefined, selector: string, css: {[key:string]: string}, selectorPrefix = '.') { + addWebStyleSheetRule(sheet: CSSStyleSheet | null | undefined, selector: string, css: { [key: string]: string }, selectorPrefix = '.') { const propText = typeof css === 'string' ? css @@ -498,7 +500,7 @@ export class WebBox extends ViewBoxAnnotatableComponent() { return sheet?.insertRule(selectorPrefix + selector + '{' + propText + '}', sheet.cssRules.length); } - _iframetimeout: NodeJS.Timeout|undefined = undefined; + _iframetimeout: NodeJS.Timeout | undefined = undefined; @observable _warning = 0; @action iframeLoaded = () => { @@ -520,7 +522,7 @@ export class WebBox extends ViewBoxAnnotatableComponent() { if (requrlraw !== this._url.toString()) { if (requrlraw.match(/q=.*&/)?.length && this._url.toString().match(/q=.*&/)?.length) { const matches = requrlraw.match(/[^a-zA-z]q=[^&]*/g); - const newsearch = matches?.lastElement() || ""; + const newsearch = matches?.lastElement() || ''; if (matches) { requrlraw = requrlraw.substring(0, requrlraw.indexOf(newsearch)); for (let i = 1; i < Array.from(matches)?.length; i++) { @@ -567,12 +569,12 @@ export class WebBox extends ViewBoxAnnotatableComponent() { ); iframeContent.addEventListener( 'click', - undoBatch( + undoable( action((e: MouseEvent) => { let eleHref = ''; for (let ele = e.target as HTMLElement | Element | null; ele; ele = ele.parentElement) { if (ele instanceof HTMLAnchorElement) { - eleHref = (typeof ele.href === 'string' ? ele.href : eleHref) || (ele.parentElement && ("href" in ele.parentElement) ? ele.parentElement.href as string: eleHref); + eleHref = (typeof ele.href === 'string' ? ele.href : eleHref) || (ele.parentElement && 'href' in ele.parentElement ? (ele.parentElement.href as string) : eleHref); } } const origin = this.webField?.origin; @@ -588,7 +590,8 @@ export class WebBox extends ViewBoxAnnotatableComponent() { this._outerRef.current.scrollLeft = 0; } } - }) + }), + 'follow web link' ) ); iframe.contentDocument.addEventListener('wheel', this.iframeWheel, { passive: false }); @@ -792,7 +795,7 @@ export class WebBox extends ViewBoxAnnotatableComponent() { }, icon: 'snowflake', }); - funcs.push({ description: 'Create Thumbnail', event: () => this.updateThumb(), icon: 'portrait' }); + !Doc.noviceMode && funcs.push({ description: 'Update Icon', event: () => this.updateIcon(), icon: 'portrait' }); cm.addItem({ description: 'Options...', subitems: funcs, icon: 'asterisk' }); } }; @@ -1085,7 +1088,7 @@ export class WebBox extends ViewBoxAnnotatableComponent() { @computed get webpage() { TraceMobx(); const previewScale = this._previewNativeWidth ? 1 - this.sidebarWidth() / this._previewNativeWidth : 1; - const pointerEvents = this.layoutDoc._lockedPosition ? 'none' : (this._props.pointerEvents?.() as "none" | "all" | "visiblePainted" | undefined) + const pointerEvents = this.layoutDoc._lockedPosition ? 'none' : (this._props.pointerEvents?.() as Property.PointerEvents | undefined); const scale = previewScale * (this._props.NativeDimScaling?.() || 1); return (
() { render() { TraceMobx(); const previewScale = this._previewNativeWidth ? 1 - this.sidebarWidth() / this._previewNativeWidth : 1; - const pointerEvents = this.layoutDoc._lockedPosition ? 'none' : (this._props.pointerEvents?.() as 'none' | 'all' | 'visiblePainted' | undefined); + const pointerEvents = this.layoutDoc._lockedPosition ? 'none' : (this._props.pointerEvents?.() as Property.PointerEvents); const scale = previewScale * (this._props.NativeDimScaling?.() || 1); return (
new Promise(resolve => { - const img = new Image(); - img.onload = function () { - console.log(`IMAGE SVG created: ${webUrl}`); - resolve(img); - }; console.log(`BUILDING SVG for: ${webUrl}`); buildSvgDataUri(webUrl, html, width, height, scroll, xoff).then(uri => { + const img = new Image(); img.src = uri; - return img; + img.onload = () => { + console.log(`IMAGE SVG created: ${webUrl}`); + resolve(img); + }; }); }); @@ -272,7 +269,7 @@ const ForeignHtmlRenderer = function (styleSheets) { * @return {Promise} */ this.renderToCanvas = (webUrl, html, width, height, scroll, xoff, oversample) => - self.renderToImage(webUrl, html, width, height, scroll, xoff).then(img => { + this.renderToImage(webUrl, html, width, height, scroll, xoff).then(img => { const canvas = document.createElement('canvas'); canvas.width = img.width * oversample; canvas.height = img.height * oversample; @@ -290,8 +287,7 @@ const ForeignHtmlRenderer = function (styleSheets) { * @return {Promise} */ this.renderToBase64Png = (webUrl, html, width, height, scroll, xoff, oversample) => - self - .renderToCanvas(webUrl, html, width, height, scroll, xoff, oversample) // + this.renderToCanvas(webUrl, html, width, height, scroll, xoff, oversample) // .then(canvas => canvas.toDataURL('image/png')); }; diff --git a/src/client/views/nodes/audio/AudioWaveform.tsx b/src/client/views/nodes/audio/AudioWaveform.tsx index 2d1d3d7db..297deb575 100644 --- a/src/client/views/nodes/audio/AudioWaveform.tsx +++ b/src/client/views/nodes/audio/AudioWaveform.tsx @@ -39,7 +39,7 @@ export class AudioWaveform extends ObservableReactComponent public static NUMBER_OF_BUCKETS = 100; // number of buckets data is divided into to draw waveform lines _disposer: IReactionDisposer | undefined; - constructor(props: any) { + constructor(props: AudioWaveformProps) { super(props); makeObservable(this); } diff --git a/src/client/views/nodes/formattedText/DashDocCommentView.tsx b/src/client/views/nodes/formattedText/DashDocCommentView.tsx index 3ec49fa27..0304ddc86 100644 --- a/src/client/views/nodes/formattedText/DashDocCommentView.tsx +++ b/src/client/views/nodes/formattedText/DashDocCommentView.tsx @@ -5,18 +5,20 @@ import { IReactionDisposer, computed, reaction } from 'mobx'; import { Doc } from '../../../../fields/Doc'; import { DocServer } from '../../../DocServer'; import { NumCast } from '../../../../fields/Types'; +import { Node } from 'prosemirror-model'; +import { EditorView } from 'prosemirror-view'; interface IDashDocCommentViewInternal { docId: string; - view: any; - getPos: any; + view: EditorView; + getPos: () => number; setHeight: (height: number) => void; } export class DashDocCommentViewInternal extends React.Component { _reactionDisposer: IReactionDisposer | undefined; - constructor(props: any) { + constructor(props: IDashDocCommentViewInternal) { super(props); this.onPointerLeaveCollapsed = this.onPointerLeaveCollapsed.bind(this); this.onPointerEnterCollapsed = this.onPointerEnterCollapsed.bind(this); @@ -43,19 +45,19 @@ export class DashDocCommentViewInternal extends React.Component { + onPointerLeaveCollapsed = (e: React.PointerEvent) => { this._dashDoc.then(async dashDoc => dashDoc instanceof Doc && Doc.linkFollowUnhighlight()); e.preventDefault(); e.stopPropagation(); }; - onPointerEnterCollapsed = (e: any) => { + onPointerEnterCollapsed = (e: React.PointerEvent) => { this._dashDoc.then(async dashDoc => dashDoc instanceof Doc && Doc.linkFollowHighlight(dashDoc, false)); e.preventDefault(); e.stopPropagation(); }; - onPointerUpCollapsed = (e: any) => { + onPointerUpCollapsed = (e: React.PointerEvent) => { const target = this.targetNode(); if (target) { @@ -65,7 +67,7 @@ export class DashDocCommentViewInternal extends React.Component { expand && this._dashDoc.then(async dashDoc => dashDoc instanceof Doc && Doc.linkFollowHighlight(dashDoc)); try { - this.props.view.dispatch(this.props.view.state.tr.setSelection(TextSelection.create(this.props.view.state.tr.doc, this.props.getPos() + (expand ? 2 : 1)))); + this.props.view.dispatch(this.props.view.state.tr.setSelection(TextSelection.create(this.props.view.state.tr.doc, (this.props.getPos() ?? 0) + (expand ? 2 : 1)))); } catch (err) { /* empty */ } @@ -74,7 +76,7 @@ export class DashDocCommentViewInternal extends React.Component { + onPointerDownCollapsed = (e: React.PointerEvent) => { e.stopPropagation(); }; @@ -84,7 +86,7 @@ export class DashDocCommentViewInternal extends React.Component number | undefined) { this.node = node; this.dom = document.createElement('div'); this.dom.style.width = node.attrs.width; @@ -130,22 +132,22 @@ export class DashDocCommentView { this.dom.style.fontWeight = 'bold'; this.dom.style.position = 'relative'; this.dom.style.display = 'inline-block'; - this.dom.onkeypress = function (e: any) { + this.dom.onkeypress = function (e) { e.stopPropagation(); }; - this.dom.onkeydown = function (e: any) { + this.dom.onkeydown = function (e) { e.stopPropagation(); }; - this.dom.onkeyup = function (e: any) { + this.dom.onkeyup = function (e) { e.stopPropagation(); }; - this.dom.onmousedown = function (e: any) { + this.dom.onmousedown = function (e) { e.stopPropagation(); }; + const getPosition = () => getPos() ?? 0; this.root = ReactDOM.createRoot(this.dom); - this.root.render(); - (this as any).dom = this.dom; + this.root.render(); } setHeight = (hgt: number) => { diff --git a/src/client/views/nodes/formattedText/DashDocView.tsx b/src/client/views/nodes/formattedText/DashDocView.tsx index 93371685d..e7f2cdba8 100644 --- a/src/client/views/nodes/formattedText/DashDocView.tsx +++ b/src/client/views/nodes/formattedText/DashDocView.tsx @@ -1,4 +1,3 @@ -/* eslint-disable jsx-a11y/no-static-element-interactions */ import { action, computed, IReactionDisposer, makeObservable, observable, reaction } from 'mobx'; import { observer } from 'mobx-react'; import { NodeSelection } from 'prosemirror-state'; @@ -16,6 +15,8 @@ import { ObservableReactComponent } from '../../ObservableReactComponent'; import { DocumentView } from '../DocumentView'; import { FocusViewOptions } from '../FocusViewOptions'; import { FormattedTextBox } from './FormattedTextBox'; +import { EditorView } from 'prosemirror-view'; +import { Node } from 'prosemirror-model'; const horizPadding = 3; // horizontal padding to container to allow cursor to show up on either side. interface IDashDocViewInternal { @@ -26,9 +27,9 @@ interface IDashDocViewInternal { height: string; hidden: boolean; fieldKey: string; - view: any; - node: any; - getPos: any; + view: EditorView; + node: Node; + getPos: () => number; } @observer @@ -109,7 +110,7 @@ export class DashDocViewInternal extends ObservableReactComponent this._textBox.focus(target, options); // ideally, this would scroll to show the focus target - onKeyDown = (e: any) => { + onKeyDown = (e: React.KeyboardEvent) => { e.stopPropagation(); if (e.key === 'Tab' || e.key === 'Enter') { e.preventDefault(); @@ -176,29 +177,31 @@ export class DashDocViewInternal extends ObservableReactComponent number | undefined, tbox: FormattedTextBox) { this.dom = document.createElement('span'); this.dom.style.position = 'relative'; this.dom.style.textIndent = '0'; this.dom.style.width = (+node.attrs.width.toString().replace('px', '') + horizPadding).toString(); this.dom.style.height = node.attrs.height; this.dom.style.display = node.attrs.hidden ? 'none' : 'inline-block'; - (this.dom.style as any).float = node.attrs.float; - this.dom.onkeypress = function (e: any) { + this.dom.style.float = node.attrs.float; + this.dom.onkeypress = function (e: KeyboardEvent) { e.stopPropagation(); }; - this.dom.onkeydown = function (e: any) { + this.dom.onkeydown = function (e: KeyboardEvent) { e.stopPropagation(); }; - this.dom.onkeyup = function (e: any) { + this.dom.onkeyup = function (e: KeyboardEvent) { e.stopPropagation(); }; - this.dom.onmousedown = function (e: any) { + this.dom.onmousedown = function (e: MouseEvent) { e.stopPropagation(); }; + const getPosition = () => getPos() ?? 0; + this.root = ReactDOM.createRoot(this.dom); this.root.render( ); } diff --git a/src/client/views/nodes/formattedText/DashFieldView.tsx b/src/client/views/nodes/formattedText/DashFieldView.tsx index 9903d0e8a..f0313fba4 100644 --- a/src/client/views/nodes/formattedText/DashFieldView.tsx +++ b/src/client/views/nodes/formattedText/DashFieldView.tsx @@ -1,6 +1,3 @@ -/* eslint-disable jsx-a11y/no-static-element-interactions */ -/* eslint-disable jsx-a11y/click-events-have-key-events */ -/* eslint-disable jsx-a11y/control-has-associated-label */ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { Tooltip } from '@mui/material'; import { action, computed, IReactionDisposer, makeObservable, observable, reaction, runInAction } from 'mobx'; @@ -26,6 +23,8 @@ import { ObservableReactComponent } from '../../ObservableReactComponent'; import { OpenWhere } from '../OpenWhere'; import './DashFieldView.scss'; import { FormattedTextBox } from './FormattedTextBox'; +import { Node } from 'prosemirror-model'; +import { EditorView } from 'prosemirror-view'; @observer export class DashFieldViewMenu extends AntimodeMenu { @@ -34,7 +33,7 @@ export class DashFieldViewMenu extends AntimodeMenu { static createFieldView: (e: React.MouseEvent) => void = emptyFunction; static toggleFieldHide: () => void = emptyFunction; static toggleValueHide: () => void = emptyFunction; - constructor(props: any) { + constructor(props: AntimodeMenuProps) { super(props); DashFieldViewMenu.Instance = this; } @@ -100,8 +99,8 @@ interface IDashFieldViewInternal { height: number; editable: boolean; nodeSelected: () => boolean; - node: any; - getPos: any; + node: Node; + getPos: () => number; unclickable: () => boolean; } @@ -274,7 +273,9 @@ export class DashFieldViewInternal extends ObservableReactComponent {this.values.map(val => ( - + ))} )} @@ -284,16 +285,17 @@ export class DashFieldViewInternal extends ObservableReactComponent number | undefined; @observable _nodeSelected = false; NodeSelected = () => this._nodeSelected; - unclickable = () => !this.tbox._props.rootSelected?.() && this.node.marks.some((m: any) => m.type === this.tbox.EditorView?.state.schema.marks.linkAnchor && m.attrs.noPreview); - constructor(node: any, view: any, getPos: any, tbox: FormattedTextBox) { + unclickable = () => !this.tbox._props.rootSelected?.() && this.node.marks.some(m => m.type === this.tbox.EditorView?.state.schema.marks.linkAnchor && m.attrs.noPreview); + constructor(node: Node, view: EditorView, getPos: () => number | undefined, tbox: FormattedTextBox) { makeObservable(this); + const getPosition = () => getPos() ?? 0; this.node = node; this.tbox = tbox; this.getpos = getPos; @@ -312,7 +314,7 @@ export class DashFieldView { const editor = tbox.EditorView; if (editor) { const { state } = editor; - for (let i = this.getpos() + 1; i < state.doc.content.size; i++) { + for (let i = getPosition() + 1; i < state.doc.content.size; i++) { if (state.doc.nodeAt(i)?.type.name === state.schema.nodes.dashField.name) { editor.dispatch(state.tr.setSelection(new NodeSelection(state.doc.resolve(i)))); return; @@ -321,10 +323,10 @@ export class DashFieldView { } } }; - this.dom.onkeyup = function (e: any) { + this.dom.onkeyup = function (e: KeyboardEvent) { e.stopPropagation(); }; - this.dom.onmousedown = function (e: any) { + this.dom.onmousedown = function (e: MouseEvent) { e.stopPropagation(); }; @@ -333,7 +335,7 @@ export class DashFieldView { } */ class EquationEditor extends Component { - element: any; + element: React.RefObject; + // eslint-disable-next-line @typescript-eslint/no-explicit-any mathField: any; ignoreEditEvents: number; // Element needs to be in the class format and thus requires a constructor. The steps that are run // in the constructor is to make sure that React can succesfully communicate with the equation // editor. - constructor(props: any) { + constructor(props: EquationEditorProps) { super(props); - this.element = createRef(); + this.element = createRef(); this.mathField = null; // MathJax apparently fire 2 edit events on startup. @@ -74,6 +72,7 @@ class EquationEditor extends Component { autoOperatorNames, }; + // eslint-disable-next-line @typescript-eslint/no-explicit-any this.mathField = (window as any).MathQuill.MathField(this.element.current, config); this.mathField.latex(value || ''); } diff --git a/src/client/views/nodes/formattedText/EquationView.tsx b/src/client/views/nodes/formattedText/EquationView.tsx index 5167c8f2a..4d0e9efee 100644 --- a/src/client/views/nodes/formattedText/EquationView.tsx +++ b/src/client/views/nodes/formattedText/EquationView.tsx @@ -1,15 +1,16 @@ -/* eslint-disable jsx-a11y/no-static-element-interactions */ import { IReactionDisposer } from 'mobx'; import { observer } from 'mobx-react'; +import { Node } from 'prosemirror-model'; import { TextSelection } from 'prosemirror-state'; +import { EditorView } from 'prosemirror-view'; import * as React from 'react'; import * as ReactDOM from 'react-dom/client'; import { Doc } from '../../../../fields/Doc'; +import { DocData } from '../../../../fields/DocSymbols'; import { StrCast } from '../../../../fields/Types'; import './DashFieldView.scss'; import EquationEditor from './EquationEditor'; import { FormattedTextBox } from './FormattedTextBox'; -import { DocData } from '../../../../fields/DocSymbols'; interface IEquationViewInternal { fieldKey: string; @@ -27,7 +28,7 @@ export class EquationViewInternal extends React.Component _fieldKey: string; _ref: React.RefObject = React.createRef(); - constructor(props: any) { + constructor(props: IEquationViewInternal) { super(props); this._fieldKey = props.fieldKey; this._textBoxDoc = props.tbox.Document; @@ -63,7 +64,7 @@ export class EquationViewInternal extends React.Component { + onChange={str => { this._textBoxDoc[DocData][this._fieldKey] = str; }} autoCommands="pi theta sqrt sum prod alpha beta gamma rho" @@ -77,25 +78,27 @@ export class EquationViewInternal extends React.Component export class EquationView { dom: HTMLDivElement; // container for label and value - root: any; + root: ReactDOM.Root; tbox: FormattedTextBox; - view: any; - constructor(node: any, view: any, getPos: any, tbox: FormattedTextBox) { + view: EditorView; + _editor: EquationEditor | undefined; + getPos: () => number; + constructor(node: Node, view: EditorView, getPos: () => number, tbox: FormattedTextBox) { this.tbox = tbox; this.view = view; + this.getPos = getPos; this.dom = document.createElement('div'); this.dom.style.width = node.attrs.width; this.dom.style.height = node.attrs.height; this.dom.style.position = 'relative'; this.dom.style.display = 'inline-block'; - this.dom.onmousedown = function (e: any) { + this.dom.onmousedown = (e: MouseEvent) => { e.stopPropagation(); }; this.root = ReactDOM.createRoot(this.dom); this.root.render(); } - _editor: EquationEditor | undefined; setEditor = (editor?: EquationEditor) => { this._editor = editor; }; @@ -106,6 +109,7 @@ export class EquationView { this._editor?.mathField.focus(); } selectNode() { + this.view.dispatch(this.view.state.tr.setSelection(new TextSelection(this.view.state.doc.resolve(this.getPos())))); this.tbox._applyingChange = this.tbox.fieldKey; // setting focus will make prosemirror lose focus, which will cause it to change its selection to a text selection, which causes this view to get rebuilt but it's no longer node selected, so the equationview won't have focus setTimeout(() => { this._editor?.mathField.focus(); diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx index 39e237986..c8b25e184 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx +++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx @@ -96,7 +96,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent(); private _ref: React.RefObject = React.createRef(); private _scrollRef: HTMLDivElement | null = null; - private _editorView: Opt; + private _editorView: Opt; public _applyingChange: string = ''; private _inDrop = false; private _finishingLink = false; @@ -113,7 +113,9 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent new FormattedTextBoxComment() }), - ] }; + return { + schema, + plugins: [ + inputRules(this._rules.inpRules), + this.richTextMenuPlugin(), + history(), + keymap(this._keymap), + keymap(baseKeymap), + new Plugin({ props: { attributes: { class: 'ProseMirror-example-setup-style' } } }), + new Plugin({ view: () => new FormattedTextBoxComment() }), + ], + }; } - public get EditorView() { return this._editorView; } - public get SidebarKey() { return this.fieldKey + '_sidebar'; } + public get EditorView() { + return this._editorView; + } + public get SidebarKey() { + return this.fieldKey + '_sidebar'; + } public makeAIFlashcards: () => void = unimplementedFunction; public addToCollection: ((doc: Doc | Doc[], annotationKey?: string | undefined) => boolean) | undefined; @@ -777,7 +785,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent { const cm = ContextMenu.Instance; - let target:Element|HTMLElement|null = e.target as HTMLElement; // hrefs are stored on the database of the node that wraps the hyerlink + let target: Element | HTMLElement | null = e.target as HTMLElement; // hrefs are stored on the database of the node that wraps the hyerlink while (target && (!(target instanceof HTMLElement) || !target.dataset?.targethrefs)) target = target.parentElement; const editor = this._editorView; if (editor && target && !(e.nativeEvent instanceof simMouseEvent ? e.nativeEvent.dash : false)) { @@ -789,10 +797,10 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent { + const deleteMarkups = undoable(() => { const { selection } = editor.state; editor.dispatch(editor.state.tr.removeMark(selection.from, selection.to, editor.state.schema.marks.linkAnchor)); - }); + }, 'delete markups'); e.persist(); anchorDoc && DocServer.GetRefField(anchorDoc).then( @@ -816,21 +824,21 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent { + event: undoable(() => { Doc.setNativeView(this.Document); this.layoutDoc.layout_autoHeightMargins = undefined; - }), + }, 'set plain view'), icon: 'eye', }); changeItems.push({ description: 'metadata', - event: undoBatch(() => { + event: undoable(() => { this.dataDoc.layout_meta = Cast(Doc.UserDoc().emptyHeader, Doc, null)?.layout; this.Document.layout_fieldKey = 'layout_meta'; setTimeout(() => { this.layoutDoc._header_height = this.layoutDoc._layout_autoHeightMargins = 50; }, 50); - }), + }, 'set metadata view'), icon: 'eye', }); const noteTypesDoc = Cast(Doc.UserDoc().template_notes, Doc, null); @@ -838,11 +846,14 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent { - this.layoutDoc.layout_autoHeightMargins = undefined; - Doc.setNativeView(this.Document); - DocUtils.makeCustomViewClicked(this.Document, Docs.Create.TreeDocument, StrCast(note.title), note); - }), + event: undoable( + () => { + this.layoutDoc.layout_autoHeightMargins = undefined; + Doc.setNativeView(this.Document); + DocUtils.makeCustomViewClicked(this.Document, Docs.Create.TreeDocument, StrCast(note.title), note); + }, + `set ${StrCast(note.title)} view}` + ), icon: icon, }); }); @@ -1229,9 +1240,9 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent= layoutTime ? (protoTime >= dataTime ? protoData : dataData) : layoutTime >= protoTime ? layoutData : protoData; const whichData = recentData ?? (this.layoutDoc.isTemplateDoc ? layoutData : protoData) ?? protoData; return !whichData ? undefined : { data: RTFCast(whichData), str: Field.toString(DocCast(whichData) ?? StrCast(whichData)) }; @@ -1370,11 +1381,13 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent { + return new Plugin({ + view: action((newView: EditorView) => { this._props.rootSelected?.() && RichTextMenu.Instance && (RichTextMenu.Instance.view = newView); return new RichTextMenuPlugin({ editorProps: this._props }); - })}); - }; + }), + }); + } _didScroll = false; _scrollStopper: undefined | (() => void); // eslint-disable-next-line @typescript-eslint/no-explicit-any @@ -1509,7 +1522,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent { + DocServer.GetRefField(target.dataset?.audioid || '').then(anchor => { if (anchor instanceof Doc) { // const timecode = NumCast(anchor.timecodeToShow, 0); const audiodoc = anchor.annotationOn as Doc; @@ -1549,8 +1562,8 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent node that wraps the hyerlink - for (let target:HTMLElement|Element|null = clickTarget as HTMLElement; target instanceof HTMLElement && !target.dataset?.targethrefs; target = target.parentElement); + let clickTarget: HTMLElement | Element | null = e.target as HTMLElement; // hrefs are stored on the dataset of the node that wraps the hyerlink + for (let target: HTMLElement | Element | null = clickTarget as HTMLElement; target instanceof HTMLElement && !target.dataset?.targethrefs; target = target.parentElement); while (clickTarget instanceof HTMLElement && !clickTarget.dataset?.targethrefs) clickTarget = clickTarget.parentElement; const dataset = clickTarget instanceof HTMLElement ? clickTarget?.dataset : undefined; FormattedTextBoxComment.update(this, this.EditorView!, undefined, dataset?.targethrefs, dataset?.linkdoc, dataset?.nopreview === 'true'); @@ -1588,7 +1601,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent { if (!this._props.isContentActive()) return; const editorView = this._editorView; - const editorRoot = editorView?.root instanceof Document ?editorView.root : undefined; + const editorRoot = editorView?.root instanceof Document ? editorView.root : undefined; if (editorView && (!this._forceUncollapse || editorRoot?.getSelection()?.isCollapsed)) { // this is a hack to allow the cursor to be placed at the end of a document when the document ends in an inline dash comment. Apparently Chrome on Windows has a bug/feature which breaks this when clicking after the end of the text. const pcords = editorView.posAtCoords({ left: e.clientX, top: e.clientY }); @@ -1834,7 +1847,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent d?.author).length; const color = !annotated ? Colors.WHITE : Colors.BLACK; - const backgroundColor = !annotated ? (this.sidebarWidth() ? Colors.MEDIUM_BLUE : Colors.BLACK) : this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.WidgetColor + (annotated ? ':annotated' : '')) as string; + const backgroundColor = !annotated ? (this.sidebarWidth() ? Colors.MEDIUM_BLUE : Colors.BLACK) : (this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.WidgetColor + (annotated ? ':annotated' : '')) as string); return !annotated && (!this._props.isContentActive() || SnappingManager.IsDragging || Doc.ActiveTool !== InkTool.None) ? null : (
{ - const { textBox, startUserMarkRegion, endUserMarkRegion, userMark } = FormattedTextBoxComment; - false && startUserMarkRegion !== undefined && textBox?.adoptAnnotation(startUserMarkRegion, endUserMarkRegion, userMark); + // const { textBox, startUserMarkRegion, endUserMarkRegion, userMark } = FormattedTextBoxComment; + // startUserMarkRegion !== undefined && textBox?.adoptAnnotation(startUserMarkRegion, endUserMarkRegion, userMark); e.stopPropagation(); e.preventDefault(); }; diff --git a/src/client/views/nodes/formattedText/ParagraphNodeSpec.ts b/src/client/views/nodes/formattedText/ParagraphNodeSpec.ts index 8799964b3..d41938698 100644 --- a/src/client/views/nodes/formattedText/ParagraphNodeSpec.ts +++ b/src/client/views/nodes/formattedText/ParagraphNodeSpec.ts @@ -1,18 +1,18 @@ -import { Node, DOMOutputSpec } from 'prosemirror-model'; +import { Node, DOMOutputSpec, AttributeSpec, TagParseRule } from 'prosemirror-model'; import clamp from '../../../util/clamp'; import convertToCSSPTValue from '../../../util/convertToCSSPTValue'; import toCSSLineSpacing from '../../../util/toCSSLineSpacing'; // import type { NodeSpec } from './Types'; type NodeSpec = { - attrs?: { [key: string]: any }; + attrs?: { [key: string]: AttributeSpec }; content?: string; draggable?: boolean; group?: string; inline?: boolean; name?: string; - parseDOM?: Array; - toDOM?: (node: any) => DOMOutputSpec; + parseDOM?: Array; + toDOM?: (node: Node) => DOMOutputSpec; }; // This assumes that every 36pt maps to one indent level. @@ -30,7 +30,7 @@ function convertMarginLeftToIndentValue(marginLeft: string): number { return clamp(MIN_INDENT_LEVEL, Math.floor(ptValue / INDENT_MARGIN_PT_SIZE), MAX_INDENT_LEVEL); } -function getAttrs(dom: HTMLElement): Object { +export function getAttrs(dom: HTMLElement): object { const { lineHeight, textAlign, marginLeft, paddingTop, paddingBottom } = dom.style; let align = dom.getAttribute('align') || textAlign || ''; @@ -50,9 +50,31 @@ function getAttrs(dom: HTMLElement): Object { return { align, indent, lineSpacing, paddingTop, paddingBottom, id }; } -function toDOM(node: Node): DOMOutputSpec { +export function getHeadingAttrs(dom: HTMLElement): { align?: string; indent?: number; lineSpacing?: string; paddingTop?: string; paddingBottom?: string; id: string; level?: number } { + const { lineHeight, textAlign, marginLeft, paddingTop, paddingBottom } = dom.style; + + let align = dom.getAttribute('align') || textAlign || ''; + align = ALIGN_PATTERN.test(align) ? align : ''; + + let indent = parseInt(dom.getAttribute(ATTRIBUTE_INDENT) || '', 10); + + if (!indent && marginLeft) { + indent = convertMarginLeftToIndentValue(marginLeft); + } + + indent = indent || MIN_INDENT_LEVEL; + + const lineSpacing = lineHeight ? toCSSLineSpacing(lineHeight) : undefined; + + const level = Number(dom.nodeName.substring(1)) || 1; + + const id = dom.getAttribute('id') || ''; + return { align, indent, lineSpacing, paddingTop, paddingBottom, id, level }; +} + +export function toDOM(node: Node): DOMOutputSpec { const { align, indent, inset, lineSpacing, paddingTop, paddingBottom, id } = node.attrs; - const attrs: { [key: string]: any } | null = {}; + const attrs: { [key: string]: unknown } | null = {}; let style = ''; if (align && align !== 'left') { diff --git a/src/client/views/nodes/formattedText/RichTextMenu.tsx b/src/client/views/nodes/formattedText/RichTextMenu.tsx index 247b7c097..738f6d699 100644 --- a/src/client/views/nodes/formattedText/RichTextMenu.tsx +++ b/src/client/views/nodes/formattedText/RichTextMenu.tsx @@ -1,8 +1,8 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { Tooltip } from '@mui/material'; -import { action, computed, IReactionDisposer, makeObservable, observable, reaction } from 'mobx'; +import { action, computed, IReactionDisposer, makeObservable, observable } from 'mobx'; import { observer } from 'mobx-react'; -import { lift, wrapIn } from 'prosemirror-commands'; +import { lift, toggleMark, wrapIn } from 'prosemirror-commands'; import { Mark, MarkType } from 'prosemirror-model'; import { wrapInList } from 'prosemirror-schema-list'; import { EditorState, NodeSelection, TextSelection, Transaction } from 'prosemirror-state'; @@ -22,8 +22,6 @@ import { updateBullets } from './ProsemirrorExampleTransfer'; import './RichTextMenu.scss'; import { schema } from './schema_rts'; -const { toggleMark } = require('prosemirror-commands'); - @observer export class RichTextMenu extends AntimodeMenu { // eslint-disable-next-line no-use-before-define @@ -35,8 +33,8 @@ export class RichTextMenu extends AntimodeMenu { private _linkToRef = React.createRef(); layoutDoc: Doc | undefined; - @observable public view?: EditorView & { TextView ?: FormattedTextBox } = undefined; - public editorProps: FieldViewProps | AntimodeMenuProps |undefined; + @observable public view?: EditorView & { TextView?: FormattedTextBox } = undefined; + public editorProps: FieldViewProps | AntimodeMenuProps | undefined; public _brushMap: Map> = new Map(); @@ -124,7 +122,7 @@ export class RichTextMenu extends AntimodeMenu { } @action - public updateMenu(view: EditorView | undefined, lastState: EditorState | undefined, props: FormattedTextBoxProps|AntimodeMenuProps|undefined, layoutDoc: Doc | undefined) { + public updateMenu(view: EditorView | undefined, lastState: EditorState | undefined, props: FormattedTextBoxProps | AntimodeMenuProps | undefined, layoutDoc: Doc | undefined) { if (this._linkToRef.current?.getBoundingClientRect().width) { return; } @@ -158,7 +156,7 @@ export class RichTextMenu extends AntimodeMenu { this.getTextLinkTargetTitle().then(targetTitle => this.setCurrentLink(targetTitle)); } - setMark = (mark: Mark, state: EditorState, dispatch: (tr:Transaction) => void, dontToggle: boolean = false) => { + setMark = (mark: Mark, state: EditorState, dispatch: (tr: Transaction) => void, dontToggle: boolean = false) => { if (mark) { const newPos = state.selection.$anchor.node()?.type === schema.nodes.ordered_list ? state.selection.from : state.selection.from; const node = (state.selection as NodeSelection).node ?? (newPos >= 0 ? state.doc.nodeAt(newPos) : undefined); @@ -177,7 +175,7 @@ export class RichTextMenu extends AntimodeMenu { toggleMark(mark.type, mark.attrs)(state, dispatch); } } - // this.updateMenu(this.view, undefined, undefined, this.layoutDoc); + // this.updateMenu(this.view, undefined, undefined, this.layoutDoc); } }; @@ -193,7 +191,7 @@ export class RichTextMenu extends AntimodeMenu { } } return 'left'; - } + }; // finds font sizes and families in selection getActiveListStyle = () => { @@ -208,7 +206,7 @@ export class RichTextMenu extends AntimodeMenu { } } return ''; - } + }; // finds font sizes and families in selection getActiveFontStylesOnSelection() { @@ -365,7 +363,7 @@ export class RichTextMenu extends AntimodeMenu { this.view.focus(); } else { Doc.UserDoc()[fontField] = value; - // this.updateMenu(this.view, undefined, this.props, this.layoutDoc); + // this.updateMenu(this.view, undefined, this.props, this.layoutDoc); } }; @@ -391,10 +389,10 @@ export class RichTextMenu extends AntimodeMenu { this.view!.dispatch(tx3); }); this.view.focus(); - // this.updateMenu(this.view, undefined, this.props, this.layoutDoc); + // this.updateMenu(this.view, undefined, this.props, this.layoutDoc); }; - insertSummarizer(state: EditorState, dispatch: (tr:Transaction) => void) { + insertSummarizer(state: EditorState, dispatch: (tr: Transaction) => void) { if (state.selection.empty) return false; const mark = state.schema.marks.summarize.create(); const { tr } = state; @@ -408,7 +406,7 @@ export class RichTextMenu extends AntimodeMenu { vcenterToggle = () => { this.layoutDoc && (this.layoutDoc._layout_centered = !this.layoutDoc._layout_centered); }; - align = (view: EditorView, dispatch: (tr:Transaction) => void, alignment: 'left' | 'right' | 'center') => { + align = (view: EditorView, dispatch: (tr: Transaction) => void, alignment: 'left' | 'right' | 'center') => { if (this.TextView?._props.rootSelected?.()) { let { tr } = view.state; view.state.doc.nodesBetween(view.state.selection.from, view.state.selection.to, (node, pos) => { @@ -424,7 +422,7 @@ export class RichTextMenu extends AntimodeMenu { } }; - paragraphSetup(state: EditorState, dispatch: (tr:Transaction) => void, field: 'inset' | 'indent', value?: 0 | 10 | -10) { + paragraphSetup(state: EditorState, dispatch: (tr: Transaction) => void, field: 'inset' | 'indent', value?: 0 | 10 | -10) { let { tr } = state; state.doc.nodesBetween(state.selection.from, state.selection.to, (node, pos) => { if (node.type === schema.nodes.paragraph || node.type === schema.nodes.heading) { @@ -440,8 +438,8 @@ export class RichTextMenu extends AntimodeMenu { return true; } - insertBlockquote(state: EditorState, dispatch: (tr:Transaction) => void) { - const node = state.selection.$from.depth ? state.selection.$from.node(state.selection.$from.depth-1): undefined; + insertBlockquote(state: EditorState, dispatch: (tr: Transaction) => void) { + const node = state.selection.$from.depth ? state.selection.$from.node(state.selection.$from.depth - 1) : undefined; if (node?.type === schema.nodes.blockquote) { lift(state, dispatch); } else { @@ -450,7 +448,7 @@ export class RichTextMenu extends AntimodeMenu { return true; } - insertHorizontalRule(state: EditorState, dispatch: (tr:Transaction) => void) { + insertHorizontalRule(state: EditorState, dispatch: (tr: Transaction) => void) { dispatch(state.tr.replaceSelectionWith(state.schema.nodes.horizontal_rule.create()).scrollIntoView()); return true; } @@ -516,7 +514,7 @@ export class RichTextMenu extends AntimodeMenu { const onLinkChange = (e: React.ChangeEvent) => { this.TextView?.endUndoTypingBatch(); UndoManager.RunInBatch(() => this.setCurrentLink(e.target.value), 'link change'); - } + }; const link = this.currentLink ? this.currentLink : ''; @@ -595,7 +593,7 @@ export class RichTextMenu extends AntimodeMenu { if (this.view) { const linkAnchor = this.view.state.selection.$from.nodeAfter?.marks.find(m => m.type === this.view!.state.schema.marks.linkAnchor); if (linkAnchor) { - const allAnchors = (linkAnchor.attrs.allAnchors as { href: string; title: string; linkId: string; targetId: string; }[]).slice(); + const allAnchors = (linkAnchor.attrs.allAnchors as { href: string; title: string; linkId: string; targetId: string }[]).slice(); this.TextView?.RemoveAnchorFromSelection(allAnchors); // bcz: Argh ... this will remove the link from the document even it's anchored somewhere else in the text which happens if only part of the anchor text was selected. allAnchors @@ -698,7 +696,7 @@ interface RichTextMenuPluginProps { } export class RichTextMenuPlugin extends React.Component { // eslint-disable-next-line react/no-unused-class-component-methods - update(view: EditorView & {TextView ?: FormattedTextBox}, lastState: EditorState | undefined) { + update(view: EditorView & { TextView?: FormattedTextBox }, lastState: EditorState | undefined) { RichTextMenu.Instance?.updateMenu(view, lastState, this.props.editorProps, view.TextView?.layoutDoc); } render() { diff --git a/src/client/views/nodes/formattedText/RichTextRules.ts b/src/client/views/nodes/formattedText/RichTextRules.ts index bf11dfe62..39f589b1e 100644 --- a/src/client/views/nodes/formattedText/RichTextRules.ts +++ b/src/client/views/nodes/formattedText/RichTextRules.ts @@ -1,4 +1,5 @@ import { ellipsis, emDash, InputRule, smartQuotes, textblockTypeInputRule } from 'prosemirror-inputrules'; +import { NodeType } from 'prosemirror-model'; import { NodeSelection, TextSelection } from 'prosemirror-state'; import { ClientUtils } from '../../../../ClientUtils'; import { Doc, DocListCast, FieldResult, StrListCast } from '../../../../fields/Doc'; @@ -6,7 +7,7 @@ import { DocData } from '../../../../fields/DocSymbols'; import { Id } from '../../../../fields/FieldSymbols'; import { List } from '../../../../fields/List'; import { NumCast, StrCast } from '../../../../fields/Types'; -import { Utils } from '../../../../Utils'; +import { emptyFunction, Utils } from '../../../../Utils'; import { Docs } from '../../../documents/Documents'; import { CollectionViewType } from '../../../documents/DocumentTypes'; import { DocUtils } from '../../../documents/DocUtils'; @@ -35,13 +36,7 @@ export class RichTextRules { wrappingInputRule(/%>$/, schema.nodes.blockquote), // 1. create numerical ordered list - wrappingInputRule( - /^1\.\s$/, - schema.nodes.ordered_list, - () => ({ mapStyle: 'decimal', bulletStyle: 1 }), - (match: any, node: any) => node.childCount + node.attrs.order === +match[1], - ((type: any) => ({ type: type, attrs: { mapStyle: 'decimal', bulletStyle: 1 } })) as any - ), + wrappingInputRule(/^1\.\s$/, schema.nodes.ordered_list, () => ({ mapStyle: 'decimal', bulletStyle: 1 }), emptyFunction, ((type: unknown) => ({ type, attrs: { mapStyle: 'decimal', bulletStyle: 1 } })) as unknown as null), // A. create alphabetical ordered list wrappingInputRule( @@ -49,9 +44,8 @@ export class RichTextRules { schema.nodes.ordered_list, // match => { () => ({ mapStyle: 'multi', bulletStyle: 1 }), - // return ({ order: +match[1] }) - (match: any, node: any) => node.childCount + node.attrs.order === +match[1], - ((type: any) => ({ type: type, attrs: { mapStyle: 'multi', bulletStyle: 1 } })) as any + emptyFunction, + ((type: NodeType) => ({ type, attrs: { mapStyle: 'multi', bulletStyle: 1 } })) as unknown as null ), // * + - create bullet list @@ -60,8 +54,8 @@ export class RichTextRules { schema.nodes.ordered_list, // match => { () => ({ mapStyle: 'bullet' }), // ({ order: +match[1] }) - (match: any, node: any) => node.childCount + node.attrs.order === +match[1], - ((type: any) => ({ type: type, attrs: { mapStyle: 'bullet' } })) as any + emptyFunction, + ((type: NodeType) => ({ type: type, attrs: { mapStyle: 'bullet' } })) as unknown as null ), // ``` create code block @@ -93,7 +87,7 @@ export class RichTextRules { const textDoc = this.Document[DocData]; const numInlines = NumCast(textDoc.inlineTextCount); textDoc.inlineTextCount = numInlines + 1; - const node = (state.doc.resolve(start) as any).nodeAfter; + const node = state.doc.resolve(start).nodeAfter; const newNode = schema.nodes.dashComment.create({ docId: doc[Id], reflow: false }); const dashDoc = schema.nodes.dashDoc.create({ width: 75, height: 35, title: 'dashDoc', docId: doc[Id], float: 'right' }); const sm = state.storedMarks || undefined; @@ -137,7 +131,7 @@ export class RichTextRules { textDocInline.proto = textDoc; // make the annotation inherit from the outer text doc so that it can resolve any nested field references, e.g., [[field]] textDoc[inlineLayoutKey] = FormattedTextBox.LayoutString(inlineFieldKey); // create a layout string for the layout key that will render the annotation text textDoc[inlineFieldKey] = ''; // set a default value for the annotation - const node = (state.doc.resolve(start) as any).nodeAfter; + const node = state.doc.resolve(start).nodeAfter; const newNode = schema.nodes.dashComment.create({ docId: textDocInline[Id], reflow: true }); const dashDoc = schema.nodes.dashDoc.create({ width: 75, height: 35, title: 'dashDoc', docId: textDocInline[Id], float: 'right' }); const sm = state.storedMarks || undefined; @@ -154,8 +148,8 @@ export class RichTextRules { // set the First-line indent node type for the selection's paragraph (assumes % was used to initiate an EnteringStyle mode) new InputRule(/(%d|d)$/, (state, match, start, end) => { if (!match[0].startsWith('%') && !this.EnteringStyle) return null; - const pos = state.doc.resolve(start) as any; - for (let depth = pos.path.length / 3 - 1; depth >= 0; depth--) { + const pos = state.doc.resolve(start); + for (let depth = pos.depth; depth >= 0; depth--) { const node = pos.node(depth); if (node.type === schema.nodes.paragraph) { const replaced = state.tr.setNodeMarkup(pos.pos - pos.parentOffset - 1, node.type, { ...node.attrs, indent: node.attrs.indent === 25 ? undefined : 25 }); @@ -169,8 +163,8 @@ export class RichTextRules { // set the Hanging indent node type for the current selection's paragraph (assumes % was used to initiate an EnteringStyle mode) new InputRule(/(%h|h)$/, (state, match, start, end) => { if (!match[0].startsWith('%') && !this.EnteringStyle) return null; - const pos = state.doc.resolve(start) as any; - for (let depth = pos.path.length / 3 - 1; depth >= 0; depth--) { + const pos = state.doc.resolve(start); + for (let depth = pos.depth; depth >= 0; depth--) { const node = pos.node(depth); if (node.type === schema.nodes.paragraph) { const replaced = state.tr.setNodeMarkup(pos.pos - pos.parentOffset - 1, node.type, { ...node.attrs, indent: node.attrs.indent === -25 ? undefined : -25 }); @@ -184,12 +178,12 @@ export class RichTextRules { // set the Quoted indent node type for the current selection's paragraph (assumes % was used to initiate an EnteringStyle mode) new InputRule(/(%q|q)$/, (state, match, start, end) => { if (!match[0].startsWith('%') && !this.EnteringStyle) return null; - const pos = state.doc.resolve(start) as any; + const pos = state.doc.resolve(start); if (state.selection instanceof NodeSelection && state.selection.node.type === schema.nodes.ordered_list) { const { node } = state.selection; return state.tr.setNodeMarkup(pos.pos, node.type, { ...node.attrs, indent: node.attrs.indent === 30 ? undefined : 30 }); } - for (let depth = pos.path.length / 3 - 1; depth >= 0; depth--) { + for (let depth = pos.depth; depth >= 0; depth--) { const node = pos.node(depth); if (node.type === schema.nodes.paragraph) { const replaced = state.tr.setNodeMarkup(pos.pos - pos.parentOffset - 1, node.type, { ...node.attrs, inset: node.attrs.inset === 30 ? undefined : 30 }); @@ -202,9 +196,9 @@ export class RichTextRules { // center justify text new InputRule(/%\^/, (state, match, start, end) => { - const resolved = state.doc.resolve(start) as any; + const resolved = state.doc.resolve(start); if (resolved?.parent.type.name === 'paragraph') { - return state.tr.deleteRange(start, end).setNodeMarkup(resolved.path[resolved.path.length - 4], schema.nodes.paragraph, { ...resolved.parent.attrs, align: 'center' }, resolved.parent.marks); + return state.tr.deleteRange(start, end).setNodeMarkup(resolved.start() - 1, schema.nodes.paragraph, { ...resolved.parent.attrs, align: 'center' }, resolved.parent.marks); } const node = resolved.nodeAfter; const sm = state.storedMarks || undefined; @@ -214,9 +208,9 @@ export class RichTextRules { // left justify text new InputRule(/%\[/, (state, match, start, end) => { - const resolved = state.doc.resolve(start) as any; + const resolved = state.doc.resolve(start); if (resolved?.parent.type.name === 'paragraph') { - return state.tr.deleteRange(start, end).setNodeMarkup(resolved.path[resolved.path.length - 4], schema.nodes.paragraph, { ...resolved.parent.attrs, align: 'left' }, resolved.parent.marks); + return state.tr.deleteRange(start, end).setNodeMarkup(resolved.start() - 1, schema.nodes.paragraph, { ...resolved.parent.attrs, align: 'left' }, resolved.parent.marks); } const node = resolved.nodeAfter; const sm = state.storedMarks || undefined; @@ -226,9 +220,9 @@ export class RichTextRules { // right justify text new InputRule(/%\]/, (state, match, start, end) => { - const resolved = state.doc.resolve(start) as any; + const resolved = state.doc.resolve(start); if (resolved?.parent.type.name === 'paragraph') { - return state.tr.deleteRange(start, end).setNodeMarkup(resolved.path[resolved.path.length - 4], schema.nodes.paragraph, { ...resolved.parent.attrs, align: 'right' }, resolved.parent.marks); + return state.tr.deleteRange(start, end).setNodeMarkup(resolved.start() - 1, schema.nodes.paragraph, { ...resolved.parent.attrs, align: 'right' }, resolved.parent.marks); } const node = resolved.nodeAfter; const sm = state.storedMarks || undefined; @@ -426,9 +420,9 @@ export class RichTextRules { if (state.selection.to === state.selection.from || !this.EnteringStyle) return null; const tag = match[0] === 't' ? 'todo' : match[0] === 'i' ? 'ignore' : match[0] === 'x' ? 'disagree' : match[0] === '!' ? 'important' : '??'; - const node = (state.doc.resolve(start) as any).nodeAfter; + const node = state.doc.resolve(start).nodeAfter; - if (node?.marks.findIndex((m: any) => m.type === schema.marks.user_tag) !== -1) return state.tr.removeMark(start, end, schema.marks.user_tag); + if (node?.marks.findIndex(m => m.type === schema.marks.user_tag) !== -1) return state.tr.removeMark(start, end, schema.marks.user_tag); return node ? state.tr .removeMark(start, end, schema.marks.user_mark) @@ -438,7 +432,7 @@ export class RichTextRules { }), new InputRule(/%\(/, (state, match, start, end) => { - const node = (state.doc.resolve(start) as any).nodeAfter; + const node = state.doc.resolve(start).nodeAfter; const sm = state.storedMarks?.slice() || []; const mark = state.schema.marks.summarizeInclusive.create(); @@ -447,7 +441,7 @@ export class RichTextRules { const content = selected.selection.content(); const replaced = node ? selected.replaceRangeWith(start, end, schema.nodes.summary.create({ visibility: true, text: content, textslice: content.toJSON() })) : state.tr; - return replaced.setSelection(new TextSelection(replaced.doc.resolve(end))).setStoredMarks([...node.marks, ...sm]); + return replaced.setSelection(new TextSelection(replaced.doc.resolve(end))).setStoredMarks([...(node?.marks ?? []), ...sm]); }), new InputRule(/%\)/, (state, match, start, end) => state.tr.deleteRange(start, end).removeStoredMark(state.schema.marks.summarizeInclusive.create())), diff --git a/src/client/views/nodes/formattedText/marks_rts.ts b/src/client/views/nodes/formattedText/marks_rts.ts index 6e1f325cf..ba8e4faed 100644 --- a/src/client/views/nodes/formattedText/marks_rts.ts +++ b/src/client/views/nodes/formattedText/marks_rts.ts @@ -34,14 +34,14 @@ export const marks: { [index: string]: MarkSpec } = { parseDOM: [ { tag: 'a[href]', - getAttrs(dom: any) { + getAttrs: dom => { return { title: dom.getAttribute('title'), }; }, }, ], - toDOM(node: any) { + toDOM: node => { const targethrefs = node.attrs.allAnchors.reduce((p: string, item: { href: string; title: string; anchorId: string }) => (p ? p + ' ' + item.href : item.href), ''); const anchorids = node.attrs.allAnchors.reduce((p: string, item: { href: string; title: string; anchorId: string }) => (p ? p + ' ' + item.anchorId : item.anchorId), ''); return ['a', { id: Utils.GenerateGuid(), class: anchorids, 'data-targethrefs': targethrefs, /* 'data-noPreview': 'true', */ 'data-linkdoc': node.attrs.linkDoc, title: node.attrs.title, style: `background: lightBlue` }, 0]; @@ -53,7 +53,7 @@ export const marks: { [index: string]: MarkSpec } = { parseDOM: [ { tag: 'div', - getAttrs(dom: any) { + getAttrs: dom => { return { noAutoLink: dom.getAttribute('data-noAutoLink'), }; @@ -80,7 +80,7 @@ export const marks: { [index: string]: MarkSpec } = { parseDOM: [ { tag: 'a[href]', - getAttrs(dom: any) { + getAttrs: dom => { return { title: dom.getAttribute('title'), noPreview: dom.getAttribute('noPreview'), @@ -88,7 +88,7 @@ export const marks: { [index: string]: MarkSpec } = { }, }, ], - toDOM(node: any) { + toDOM: node => { const targethrefs = node.attrs.allAnchors.reduce((p: string, item: { href: string; title: string; anchorId: string }) => (p ? p + ' ' + item.href : item.href), ''); const anchorids = node.attrs.allAnchors.reduce((p: string, item: { href: string; title: string; anchorId: string }) => (p ? p + ' ' + item.anchorId : item.anchorId), ''); return node.attrs.docref && node.attrs.title @@ -117,7 +117,7 @@ export const marks: { [index: string]: MarkSpec } = { parseDOM: [ { tag: 'span', - getAttrs(dom: any) { + getAttrs: dom => { return { fontSize: dom.style.fontSize ? dom.style.fontSize.toString() : '' }; }, }, @@ -131,7 +131,7 @@ export const marks: { [index: string]: MarkSpec } = { parseDOM: [ { tag: 'span', - getAttrs(dom: any) { + getAttrs: dom => { const cstyle = getComputedStyle(dom); if (cstyle.font) { if (cstyle.font.indexOf('Times New Roman') !== -1) return { fontFamily: 'Times New Roman' }; @@ -154,7 +154,7 @@ export const marks: { [index: string]: MarkSpec } = { parseDOM: [ { tag: 'span', - getAttrs(dom: any) { + getAttrs: dom => { return { color: dom.getAttribute('color') }; }, }, @@ -170,12 +170,12 @@ export const marks: { [index: string]: MarkSpec } = { parseDOM: [ { tag: 'span', - getAttrs(dom: any) { + getAttrs: dom => { return { fontHighlight: dom.getAttribute('background-color') }; }, }, ], - toDOM(node: any) { + toDOM: node => { return node.attrs.fontHighlight ? ['span', { style: 'background-color:' + node.attrs.fontHighlight }] : ['span', { style: 'background-color: transparent' }]; }, }, @@ -224,7 +224,7 @@ export const marks: { [index: string]: MarkSpec } = { attrs: { bulletType: { default: 'decimal' }, }, - toDOM(node: any) { + toDOM: node => { return [ 'span', { @@ -238,11 +238,11 @@ export const marks: { [index: string]: MarkSpec } = { parseDOM: [ { tag: 'span', - getAttrs: (p: any) => { + getAttrs: p => { if (typeof p !== 'string') { const style = getComputedStyle(p); if (style.textDecoration === 'underline') return null; - if (p.parentElement.outerHTML.indexOf('text-decoration: underline') !== -1 && p.parentElement.outerHTML.indexOf('text-decoration-style: solid') !== -1) { + if (p.parentElement?.outerHTML.indexOf('text-decoration: underline') !== -1 && p.parentElement?.outerHTML.indexOf('text-decoration-style: solid') !== -1) { return null; } } @@ -266,11 +266,11 @@ export const marks: { [index: string]: MarkSpec } = { parseDOM: [ { tag: 'span', - getAttrs: (p: any) => { + getAttrs: p => { if (typeof p !== 'string') { const style = getComputedStyle(p); if (style.textDecoration === 'underline') return null; - if (p.parentElement.outerHTML.indexOf('text-decoration: underline') !== -1 && p.parentElement.outerHTML.indexOf('text-decoration-style: dotted') !== -1) { + if (p.parentElement?.outerHTML.indexOf('text-decoration: underline') !== -1 && p.parentElement?.outerHTML.indexOf('text-decoration-style: dotted') !== -1) { return null; } } @@ -292,10 +292,10 @@ export const marks: { [index: string]: MarkSpec } = { parseDOM: [ { tag: 'span', - getAttrs: (p: any) => { + getAttrs: p => { if (typeof p !== 'string') { const style = getComputedStyle(p); - if (style.textDecoration === 'underline' || p.parentElement.outerHTML.indexOf('text-decoration-style:line') !== -1) { + if (style.textDecoration === 'underline' || p.parentElement?.outerHTML.indexOf('text-decoration-style:line') !== -1) { return null; } } @@ -317,7 +317,7 @@ export const marks: { [index: string]: MarkSpec } = { selected: { default: false }, }, parseDOM: [{ style: 'background: yellow' }], - toDOM(node: any) { + toDOM: node => { return ['span', { style: `background: ${node.attrs.selected ? 'orange' : 'yellow'}` }]; }, }, @@ -330,7 +330,7 @@ export const marks: { [index: string]: MarkSpec } = { }, excludes: 'user_mark', group: 'inline', - toDOM(node: any) { + toDOM: node => { const uid = node.attrs.userid.replace(/\./g, '').replace(/@/g, ''); const min = Math.round(node.attrs.modified / 60); const hr = Math.round(min / 60); @@ -348,7 +348,7 @@ export const marks: { [index: string]: MarkSpec } = { }, group: 'inline', inclusive: false, - toDOM(node: any) { + toDOM: node => { const uid = node.attrs.userid.replace('.', '').replace('@', ''); return ['span', { class: 'UT-' + uid + ' UT-' + node.attrs.tag }, 0]; }, diff --git a/src/client/views/nodes/formattedText/nodes_rts.ts b/src/client/views/nodes/formattedText/nodes_rts.ts index 5bf942218..02ded3103 100644 --- a/src/client/views/nodes/formattedText/nodes_rts.ts +++ b/src/client/views/nodes/formattedText/nodes_rts.ts @@ -1,6 +1,6 @@ import { DOMOutputSpec, Node, NodeSpec } from 'prosemirror-model'; import { listItem, orderedList } from 'prosemirror-schema-list'; -import { ParagraphNodeSpec, toParagraphDOM, getParagraphNodeAttrs } from './ParagraphNodeSpec'; +import { ParagraphNodeSpec, toParagraphDOM, getHeadingAttrs } from './ParagraphNodeSpec'; import { DocServer } from '../../../DocServer'; import { Doc, Field, FieldType } from '../../../../fields/Doc'; import { schema } from './schema_rts'; @@ -53,7 +53,7 @@ export const nodes: { [index: string]: NodeSpec } = { parseDOM: [ { tag: 'audiotag', - getAttrs(dom: any) { + getAttrs: dom => { return { timeCode: dom.getAttribute('data-timecode'), audioId: dom.getAttribute('data-audioid'), @@ -123,24 +123,57 @@ export const nodes: { [index: string]: NodeSpec } = { level: { default: 1 }, }, parseDOM: [ - { tag: 'h1', attrs: { level: 1 } }, - { tag: 'h2', attrs: { level: 2 } }, - { tag: 'h3', attrs: { level: 3 } }, - { tag: 'h4', attrs: { level: 4 } }, - { tag: 'h5', attrs: { level: 5 } }, - { tag: 'h6', attrs: { level: 6 } }, + { + tag: 'h1', + attrs: { level: 1 }, + getAttrs(dom) { + return getHeadingAttrs(dom); + }, + }, + { + tag: 'h2', + attrs: { level: 2 }, + getAttrs(dom) { + return getHeadingAttrs(dom); + }, + }, + { + tag: 'h3', + attrs: { level: 3 }, + getAttrs(dom) { + return getHeadingAttrs(dom); + }, + }, + { + tag: 'h4', + attrs: { level: 4 }, + getAttrs(dom) { + return getHeadingAttrs(dom); + }, + }, + { + tag: 'h5', + attrs: { level: 5 }, + getAttrs(dom) { + return getHeadingAttrs(dom); + }, + }, + { + tag: 'h6', + attrs: { level: 6 }, + getAttrs(dom) { + return getHeadingAttrs(dom); + }, + }, ], toDOM(node) { - const dom = toParagraphDOM(node) as any; - dom[0] = `h${node.attrs.level || 1}`; + const dom = toParagraphDOM(node); + if (dom instanceof Array) { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + (dom as any)[0] = `h${node.attrs.level || 1}`; // [0] is readonly so cast away to any + } return dom; }, - getAttrs(dom: any) { - const attrs = getParagraphNodeAttrs(dom) as any; - const level = Number(dom.nodeName.substring(1)) || 1; - attrs.level = level; - return attrs; - }, }, // :: NodeSpec A code listing. Disallows marks or non-text inline @@ -221,7 +254,7 @@ export const nodes: { [index: string]: NodeSpec } = { parseDOM: [ { tag: 'img[src]', - getAttrs(dom: any) { + getAttrs: dom => { return { src: dom.getAttribute('src'), title: dom.getAttribute('title'), @@ -300,7 +333,7 @@ export const nodes: { [index: string]: NodeSpec } = { parseDOM: [ { tag: 'video[src]', - getAttrs(dom: any) { + getAttrs: dom => { return { src: dom.getAttribute('src'), title: dom.getAttribute('title'), @@ -341,33 +374,31 @@ export const nodes: { [index: string]: NodeSpec } = { parseDOM: [ { tag: 'ul', - getAttrs(dom: any) { + getAttrs: dom => { return { bulletStyle: dom.getAttribute('data-bulletStyle'), mapStyle: dom.getAttribute('data-mapStyle'), fontColor: dom.style.color, - fontSize: dom.style['font-size'], - fontFamily: dom.style['font-family'], - indent: dom.style['margin-left'], + fontSize: dom.style.fontSize, + fontFamily: dom.style.fontFamily, + indent: dom.style.marginLeft, }; }, }, { style: 'list-style-type=disc', - getAttrs() { - return { mapStyle: 'bullet' }; - }, + getAttrs: () => ({ mapStyle: 'bullet' }), }, { tag: 'ol', - getAttrs(dom: any) { + getAttrs: dom => { return { bulletStyle: dom.getAttribute('data-bulletStyle'), mapStyle: dom.getAttribute('data-mapStyle'), fontColor: dom.style.color, - fontSize: dom.style['font-size'], - fontFamily: dom.style['font-family'], - indent: dom.style['margin-left'], + fontSize: dom.style.fontSize, + fontFamily: dom.style.fontFamily, + indent: dom.style.marginLeft, }; }, }, @@ -416,7 +447,7 @@ export const nodes: { [index: string]: NodeSpec } = { parseDOM: [ { tag: 'li', - getAttrs(dom: any) { + getAttrs: dom => { return { mapStyle: dom.getAttribute('data-mapStyle'), bulletStyle: dom.getAttribute('data-bulletStyle') }; }, }, diff --git a/src/client/views/pdf/GPTPopup/GPTPopup.tsx b/src/client/views/pdf/GPTPopup/GPTPopup.tsx index cb5aad32d..0920b1bd3 100644 --- a/src/client/views/pdf/GPTPopup/GPTPopup.tsx +++ b/src/client/views/pdf/GPTPopup/GPTPopup.tsx @@ -1,4 +1,3 @@ -/* eslint-disable jsx-a11y/label-has-associated-control */ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { Button, IconButton, Type } from 'browndash-components'; import { action, makeObservable, observable } from 'mobx'; @@ -150,7 +149,7 @@ export class GPTPopup extends ObservableReactComponent { } public addDoc: (doc: Doc | Doc[], sidebarKey?: string | undefined) => boolean = () => false; - public createFilteredDoc: (axes?: any) => boolean = () => false; + public createFilteredDoc: (axes?: string[]) => boolean = () => false; public addToCollection: ((doc: Doc | Doc[], annotationKey?: string | undefined) => boolean) | undefined; /** @@ -371,8 +370,8 @@ export class GPTPopup extends ObservableReactComponent {
{this.heading('GENERATED IMAGE')}
- {this.imgUrls.map(rawSrc => ( -
+ {this.imgUrls.map((rawSrc, i) => ( +
dalle generation
diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx index 1279563ef..dee0edfae 100644 --- a/src/client/views/pdf/PDFViewer.tsx +++ b/src/client/views/pdf/PDFViewer.tsx @@ -1,8 +1,8 @@ import { action, computed, IReactionDisposer, makeObservable, observable, ObservableMap, reaction, runInAction } from 'mobx'; import { observer } from 'mobx-react'; import * as Pdfjs from 'pdfjs-dist'; -import 'pdfjs-dist/web/pdf_viewer.css'; import * as PDFJSViewer from 'pdfjs-dist/web/pdf_viewer.mjs'; +import 'pdfjs-dist/webpack.mjs'; // sets the PDF workerSrc import * as React from 'react'; import { addStyleSheet, addStyleSheetRule, clearStyleSheetRules, ClientUtils, returnAll, returnFalse, returnNone, returnZero, smoothScroll } from '../../../ClientUtils'; import { CreateLinkToActiveAudio, Doc, DocListCast, Opt } from '../../../fields/Doc'; @@ -28,10 +28,8 @@ import { AnchorMenu } from './AnchorMenu'; import { Annotation } from './Annotation'; import { GPTPopup } from './GPTPopup/GPTPopup'; import './PDFViewer.scss'; - -// 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'; +// Pdfjs.GlobalWorkerOptions.workerSrc = 'https://unpkg.com/pdfjs-dist@4.4.168/build/pdf.worker.mjs'; interface IViewerProps extends FieldViewProps { pdfBox: PDFBox; @@ -62,7 +60,7 @@ export class PDFViewer extends ObservableReactComponent { } @observable _pageSizes: { width: number; height: number }[] = []; - @observable _savedAnnotations = new ObservableMap(); + @observable _savedAnnotations = new ObservableMap(); @observable _textSelecting = true; @observable _showWaiting = true; @observable Index: number = -1; @@ -214,7 +212,7 @@ export class PDFViewer extends ObservableReactComponent { this._disposers.scale = reaction( () => NumCast(this._props.layoutDoc._freeform_scale, 1), scale => { - this._pdfViewer.currentScaleValue = scale+""; + this._pdfViewer.currentScaleValue = scale + ''; }, { fireImmediately: true } ); @@ -483,7 +481,7 @@ export class PDFViewer extends ObservableReactComponent { e.stopPropagation(); if (e.ctrlKey) { const curScale = Number(this._pdfViewer.currentScaleValue); - this._pdfViewer.currentScaleValue = Math.max(1, Math.min(10, curScale - (curScale * e.deltaY) / 1000)) + ""; + this._pdfViewer.currentScaleValue = Math.max(1, Math.min(10, curScale - (curScale * e.deltaY) / 1000)) + ''; this._props.layoutDoc._freeform_scale = Number(this._pdfViewer.currentScaleValue); } } diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts index 2792f3aba..e6a95fd30 100644 --- a/src/fields/Doc.ts +++ b/src/fields/Doc.ts @@ -1,4 +1,3 @@ -/* eslint-disable @typescript-eslint/no-explicit-any */ /* eslint-disable @typescript-eslint/no-namespace */ /* eslint-disable default-param-last */ /* eslint-disable no-use-before-define */ @@ -19,7 +18,7 @@ import { import { Copy, FieldChanged, HandleUpdate, Id, Parent, ToJavascriptString, ToScriptString, ToString } from './FieldSymbols'; import { InkTool } from './InkField'; import { List } from './List'; -import { ObjectField } from './ObjectField'; +import { ObjectField, serverOpType } from './ObjectField'; import { PrefetchProxy, ProxyField } from './Proxy'; import { FieldId, RefField } from './RefField'; import { RichTextField } from './RichTextField'; @@ -28,6 +27,15 @@ import { ComputedField, ScriptField } from './ScriptField'; import { BoolCast, Cast, DocCast, FieldValue, NumCast, StrCast, ToConstructor, toList } from './Types'; import { containedFieldChangedHandler, deleteProperty, GetEffectiveAcl, getField, getter, makeEditable, makeReadOnly, setter, SharingPermissions } from './util'; +export let ObjGetRefField: (id: string, force?: boolean) => Promise; +export let ObjGetRefFields: (ids: string[]) => Promise>; + +export function SetObjGetRefField(func: (id: string, force?: boolean) => Promise) { + ObjGetRefField = func; +} +export function SetObjGetRefFields(func: (ids: string[]) => Promise>) { + ObjGetRefFields = func; +} export const LinkedTo = '-linkedTo'; export namespace Field { /** @@ -91,18 +99,19 @@ export namespace Field { }); return script; } - export function toString(field: FieldType) { + export function toString(fieldIn: unknown) { + const field = fieldIn as FieldType; if (typeof field === 'string' || typeof field === 'number' || typeof field === 'boolean') return String(field); return field?.[ToString]?.() || ''; } - export function IsField(field: any): field is FieldType; - export function IsField(field: any, includeUndefined: true): field is FieldType | undefined; - export function IsField(field: any, includeUndefined: boolean = false): field is FieldType | undefined { + export function IsField(field: unknown): field is FieldType; + export function IsField(field: unknown, includeUndefined: true): field is FieldType | undefined; + export function IsField(field: unknown, includeUndefined: boolean = false): field is FieldType | undefined { return ['string', 'number', 'boolean'].includes(typeof field) || field instanceof ObjectField || field instanceof RefField || (includeUndefined && field === undefined); } // eslint-disable-next-line @typescript-eslint/no-shadow - export function Copy(field: any) { - return field instanceof ObjectField ? ObjectField.MakeCopy(field) : field; + export function Copy(field: unknown) { + return field instanceof ObjectField ? ObjectField.MakeCopy(field) : (field as FieldType); } UndoManager.SetFieldPrinter(toString); } @@ -157,7 +166,7 @@ export const ReverseHierarchyMap: Map { key.startsWith('acl_') && (permissions[key] = ReverseHierarchyMap.get(StrCast(target[key]))!.acl); @@ -177,7 +186,7 @@ export function updateCachedAcls(doc: Doc) { } @scriptingGlobal -@Deserializable('Doc', updateCachedAcls, ['id']) +@Deserializable('Doc', (obj: unknown) => updateCachedAcls(obj as Doc), ['id']) export class Doc extends RefField { @observable public static RecordingEvent = 0; @observable public static GuestDashboard: Doc | undefined = undefined; @@ -328,12 +337,15 @@ export class Doc extends RefField { } [key: string]: FieldResult; + [key2: symbol]: unknown; @serializable(alias('fields', map(autoObject(), { afterDeserialize: afterDocDeserialize }))) - private get __fieldTuples() { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + get __fieldTuples(): any { + // __fieldTuples does not follow the index signature pattern which requires a FieldResult return value -- so this hack suppresses the error return this[FieldTuples]; } - private set __fieldTuples(value) { + set __fieldTuples(value) { // called by deserializer to set all fields in one shot this[FieldTuples] = value; Object.keys(value).forEach(key => { @@ -348,33 +360,33 @@ export class Doc extends RefField { }); } - @observable private [FieldTuples]: any = {}; - @observable private [FieldKeys]: any = {}; + @observable private [FieldTuples]: { [key: string]: FieldResult } = {}; + @observable private [FieldKeys]: { [key: string]: boolean } = {}; /// all of the raw acl's that have been set on this document. Use GetEffectiveAcl to determine the actual ACL of the doc for editing @observable public [DocAcl]: { [key: string]: symbol } = {}; @observable public [DocCss]: number = 0; // incrementer denoting a change to CSS layout @observable public [DirectLinks] = new ObservableSet(); - @observable public [AudioPlay]: any = undefined; // meant to store sound object from Howl + @observable public [AudioPlay]: unknown = undefined; // meant to store sound object from Howl @observable public [Animation]: Opt = undefined; @observable public [Highlight]: boolean = false; @observable public [Brushed]: boolean = false; - @observable public [DocViews] = new ObservableSet(); + @observable public [DocViews] = new ObservableSet(); private [Self] = this; - private [SelfProxy]: any; + private [SelfProxy]: Doc; private [UpdatingFromServer]: boolean = false; private [ForceServerWrite]: boolean = false; - private [CachedUpdates]: { [key: string]: () => void | Promise } = {}; + private [CachedUpdates]: { [key: string]: () => void | Promise } = {}; public [Initializing]: boolean = false; - public [FieldChanged] = (diff: undefined | { op: '$addToSet' | '$remFromSet' | '$set'; items: FieldType[] | undefined; length: number | undefined; hint?: any }, serverOp: any) => { + public [FieldChanged] = (diff: { op: '$addToSet' | '$remFromSet' | '$set'; items: FieldType[] | undefined; length: number | undefined; hint?: unknown } | undefined, serverOp: serverOpType) => { if (!this[UpdatingFromServer] || this[ForceServerWrite]) { DocServer.UpdateField(this[Id], serverOp); } }; public [Width] = () => NumCast(this[SelfProxy]._width); public [Height] = () => NumCast(this[SelfProxy]._height); - public [TransitionTimer]: any = undefined; + public [TransitionTimer]: NodeJS.Timeout | undefined = undefined; public [ToJavascriptString] = () => `idToDoc("${this[Self][Id]}")`; // what should go here? public [ToScriptString] = () => `idToDoc("${this[Self][Id]}")`; public [ToString] = () => `Doc(${GetEffectiveAcl(this[SelfProxy]) === AclPrivate ? '-inaccessible-' : this[SelfProxy].title})`; @@ -387,7 +399,7 @@ export class Doc extends RefField { const self = this[SelfProxy]; const templateLayoutDoc = Cast(Doc.LayoutField(self), Doc, null); if (templateLayoutDoc) { - let renderFieldKey: any; + let renderFieldKey: string = ''; const layoutField = templateLayoutDoc[StrCast(templateLayoutDoc.layout_fieldKey, 'layout')]; if (typeof layoutField === 'string') { [renderFieldKey] = layoutField.split("fieldKey={'")[1].split("'"); // layoutField.split("'")[1]; @@ -399,16 +411,17 @@ export class Doc extends RefField { return undefined; } - public async [HandleUpdate](diff: any) { - const set = diff.$set; + public async [HandleUpdate](diff: { $set: { [key: string]: FieldType } } | { $unset?: unknown }) { + const $set = '$set' in diff ? diff.$set : undefined; + const $unset = '$unset' in diff ? diff.$unset : undefined; const sameAuthor = this.author === ClientUtils.CurrentUserEmail(); const fprefix = 'fields.'; - Object.keys(set ?? {}) + Object.keys($set ?? {}) .filter(key => key.startsWith(fprefix)) .forEach(async key => { const fKey = key.substring(fprefix.length); const fn = async () => { - const value = await SerializationHelper.Deserialize(set[key]); + const value = (await SerializationHelper.Deserialize($set?.[key])) as FieldType; const prev = GetEffectiveAcl(this); this[UpdatingFromServer] = true; this[fKey] = value; @@ -429,8 +442,7 @@ export class Doc extends RefField { this[CachedUpdates][fKey] = fn; } }); - const unset = diff.$unset; - Object.keys(unset ?? {}) + Object.keys($unset ?? {}) .filter(key => key.startsWith(fprefix)) .forEach(async key => { const fKey = key.substring(7); @@ -451,12 +463,10 @@ export class Doc extends RefField { // eslint-disable-next-line no-redeclare export namespace Doc { - // eslint-disable-next-line import/no-mutable-exports export let SelectOnLoad: Doc | undefined; export function SetSelectOnLoad(doc: Doc | undefined) { SelectOnLoad = doc; } - // eslint-disable-next-line import/no-mutable-exports export let DocDragDataName: string = ''; export function SetDocDragDataName(name: string) { DocDragDataName = name; @@ -474,7 +484,7 @@ export namespace Doc { delete doc[CachedUpdates][field]; } } - export function AddCachedUpdate(doc: Doc, field: string, oldValue: any) { + export function AddCachedUpdate(doc: Doc, field: string, oldValue: FieldType) { const val = oldValue; doc[CachedUpdates][field] = () => { doc[UpdatingFromServer] = true; @@ -493,7 +503,7 @@ export namespace Doc { export function Get(doc: Doc, key: string, ignoreProto: boolean = false): FieldResult { try { - return getField(doc[Self], key, ignoreProto); + return getField(doc[Self], key, ignoreProto) as FieldResult; } catch { return doc; } @@ -558,9 +568,12 @@ export namespace Doc { export function assign(doc: Doc, fields: Partial>>, skipUndefineds: boolean = false, isInitializing = false) { isInitializing && (doc[Initializing] = true); Object.keys(fields).forEach(key => { - const value = (fields as any)[key]; + const value = (fields as { [key: string]: Opt })[key]; if (!skipUndefineds || value !== undefined) { // Do we want to filter out undefineds? + if (typeof value === 'object' && 'values' in value) { + console.log(value); + } doc[key] = value; } }); @@ -712,7 +725,7 @@ export namespace Doc { await Promise.all( Object.keys(doc).map(async key => { if (filter.includes(key)) return; - const assignKey = (val: any) => { + const assignKey = (val: Opt) => { copy[key] = val; }; const cfield = ComputedField.WithoutComputed(() => FieldValue(doc[key])); @@ -735,7 +748,7 @@ export namespace Doc { .trim() ); const results = docids && (await DocServer.GetRefFields(docids)); - const rdocs = results && Array.from(Object.keys(results)).map(rkey => DocCast(results[rkey])); + const rdocs = results && Array.from(Object.keys(results)).map(rkey => DocCast(results.get(rkey))); rdocs?.map(d => d && Doc.makeClone(d, cloneMap, linkMap, rtfs, exclusions, pruneDocs, cloneLinks, cloneTemplates)); rtfs.push({ copy, key, field: objField }); } @@ -818,11 +831,11 @@ export namespace Doc { const linkedDocs = Array.from(linkMap.values()); linkedDocs.forEach(link => Doc.AddLink?.(link, true)); rtfMap.forEach(({ copy, key, field }) => { - const replacer = (match: any, attr: string, id: string /* , offset: any, string: any */) => { + const replacer = (match: string, attr: string, id: string /* , offset: any, string: any */) => { const mapped = cloneMap.get(id); return attr + '"' + (mapped ? mapped[Id] : id) + '"'; }; - const replacer2 = (match: any, href: string, id: string /* , offset: any, string: any */) => { + const replacer2 = (match: string, href: string, id: string /* , offset: any, string: any */) => { const mapped = cloneMap.get(id); return href + (mapped ? mapped[Id] : id); }; @@ -874,7 +887,7 @@ export namespace Doc { newLayoutDoc.embedContainer = targetDoc; newLayoutDoc.resolvedDataDoc = dataDoc; newLayoutDoc.acl_Guest = SharingPermissions.Edit; - if (dataDoc[templateField] === undefined && (templateLayoutDoc[templateField] as any)?.length) { + if (dataDoc[templateField] === undefined && (templateLayoutDoc[templateField] as List)?.length) { dataDoc[templateField] = ObjectField.MakeCopy(templateLayoutDoc[templateField] as List); // ComputedField.MakeFunction(`ObjectField.MakeCopy(templateLayoutDoc["${templateField}"])`, { templateLayoutDoc: Doc.name }, { templateLayoutDoc }); } @@ -901,7 +914,7 @@ export namespace Doc { return { layout: Doc.expandTemplateLayout(childDoc, templateRoot), data: resolvedDataDoc }; } - export function FindReferences(infield: Doc | List, references: Set, system: boolean | undefined) { + export function FindReferences(infield: Doc | List, references: Set, system: boolean | undefined) { if (infield instanceof Promise) return; if (!(infield instanceof Doc)) { infield?.forEach(val => (val instanceof Doc || val instanceof List) && FindReferences(val, references, system)); @@ -976,9 +989,10 @@ export namespace Doc { } else if (cfield instanceof ComputedField) { copy[key] = cfield[Copy](); // ComputedField.MakeFunction(cfield.script.originalScript); } else if (field instanceof ObjectField) { + const docAtKey = doc[key]; copy[key] = - doc[key] instanceof Doc && key.includes('layout[') - ? new ProxyField(Doc.MakeCopy(doc[key] as any)) // copy the expanded render template + docAtKey instanceof Doc && key.includes('layout[') + ? new ProxyField(Doc.MakeCopy(docAtKey)) // copy the expanded render template : ObjectField.MakeCopy(field); } else if (field instanceof Promise) { // eslint-disable-next-line no-debugger @@ -1235,7 +1249,7 @@ export namespace Doc { } const UnhighlightWatchers: (() => void)[] = []; - let UnhighlightTimer: any; + let UnhighlightTimer: NodeJS.Timeout | undefined; export function IsUnhighlightTimerSet() { return UnhighlightTimer; } // prettier-ignore export function AddUnHighlightWatcher(watcher: () => void) { if (UnhighlightTimer) { @@ -1244,7 +1258,7 @@ export namespace Doc { } export function linkFollowUnhighlight() { clearTimeout(UnhighlightTimer); - UnhighlightTimer = 0; + UnhighlightTimer = undefined; UnhighlightWatchers.forEach(watcher => watcher()); UnhighlightWatchers.length = 0; highlightedDocs.forEach(doc => Doc.UnHighlightDoc(doc)); @@ -1258,10 +1272,7 @@ export namespace Doc { if (UnhighlightTimer) clearTimeout(UnhighlightTimer); const presTransition = Number(presentationEffect?.presentation_transition); const duration = isNaN(presTransition) ? 5000 : presTransition; - UnhighlightTimer = window.setTimeout(() => { - linkFollowUnhighlight(); - UnhighlightTimer = 0; - }, duration); + UnhighlightTimer = setTimeout(linkFollowUnhighlight, duration); } export const highlightedDocs = new ObservableSet(); @@ -1319,7 +1330,7 @@ export namespace Doc { StrCast(doc.layout_fieldKey).split('_')[1] === 'icon' && setNativeView(doc); } - export function setNativeView(doc: any) { + export function setNativeView(doc: Doc) { const prevLayout = StrCast(doc.layout_fieldKey).split('_')[1]; const deiconify = prevLayout === 'icon' && StrCast(doc.deiconifyLayout) ? 'layout_' + StrCast(doc.deiconifyLayout) : ''; prevLayout === 'icon' && (doc.deiconifyLayout = undefined); @@ -1356,15 +1367,15 @@ export namespace Doc { // filters document in a container collection: // all documents with the specified value for the specified key are included/excluded // based on the modifiers :"check", "x", undefined - export function setDocFilter(container: Opt, key: string, value: any, modifiers: 'remove' | 'match' | 'check' | 'x' | 'exists' | 'unset', toggle?: boolean, fieldPrefix?: string, append: boolean = true) { + export function setDocFilter(container: Opt, key: string, value: FieldType | undefined, modifiers: 'remove' | 'match' | 'check' | 'x' | 'exists' | 'unset', toggle?: boolean, fieldPrefix?: string, append: boolean = true) { if (!container) return; const filterField = '_' + (fieldPrefix ? fieldPrefix + '_' : '') + 'childFilters'; const childFilters = StrListCast(container[filterField]); runInAction(() => { for (let i = 0; i < childFilters.length; i++) { const fields = childFilters[i].split(FilterSep); // split key:value:modifier - if (fields[0] === key && (fields[1] === value.toString() || modifiers === 'match' || (fields[2] === 'match' && modifiers === 'remove'))) { - if (fields[2] === modifiers && modifiers && fields[1] === value.toString()) { + if (fields[0] === key && (fields[1] === value?.toString() || modifiers === 'match' || (fields[2] === 'match' && modifiers === 'remove'))) { + if (fields[2] === modifiers && modifiers && fields[1] === value?.toString()) { // eslint-disable-next-line no-param-reassign if (toggle) modifiers = 'remove'; else return; @@ -1393,7 +1404,7 @@ export namespace Doc { return undefined; } export function assignDocToField(doc: Doc, field: string, id: string) { - DocServer.GetRefField(id).then(layout => { + DocServer.GetRefField(id)?.then(layout => { layout instanceof Doc && (doc[field] = layout); }); return id; @@ -1460,7 +1471,6 @@ export namespace Doc { case DocumentType.BUTTON: return 'bolt'; case DocumentType.PRES: return 'route'; case DocumentType.SCRIPTING: return 'terminal'; - case DocumentType.IMPORT: return 'cloud-upload-alt'; case DocumentType.VID: return 'video'; case DocumentType.INK: return 'pen-nib'; case DocumentType.PDF: return 'file-pdf'; @@ -1494,7 +1504,7 @@ export namespace Doc { const doc = DocCast(await DocServer.GetRefField(json.id)); const links = await DocServer.GetRefFields(json.linkids as string[]); Array.from(Object.keys(links)) - .map(key => links[key]) + .map(key => links.get(key)) .forEach(link => link instanceof Doc && Doc.AddLink?.(link)); return doc; } @@ -1506,7 +1516,7 @@ export namespace Doc { const primitives = ['string', 'number', 'boolean']; export interface JsonConversionOpts { - data: any; + data: unknown; title?: string; appendToExisting?: { targetDoc: Doc; fieldKey?: string }; excludeEmptyObjects?: boolean; @@ -1561,7 +1571,7 @@ export namespace Doc { if (data === undefined || data === null || ![...primitives, 'object'].includes(typeof data)) { return undefined; } - let resolved: any; + let resolved: unknown; try { resolved = JSON.parse(typeof data === 'string' ? data : JSON.stringify(data)); } catch (e) { @@ -1569,7 +1579,7 @@ export namespace Doc { } let output: Opt; if (typeof resolved === 'object' && !(resolved instanceof Array)) { - output = convertObject(resolved, excludeEmptyObjects, title, appendToExisting?.targetDoc); + output = convertObject(resolved as { [key: string]: FieldType }, excludeEmptyObjects, title, appendToExisting?.targetDoc); } else { // give the proper types to the data extracted from the JSON const result = toField(resolved, excludeEmptyObjects); @@ -1590,7 +1600,7 @@ export namespace Doc { * @returns the object mapped from JSON to field values, where each mapping * might involve arbitrary recursion (since toField might itself call convertObject) */ - const convertObject = (object: any, excludeEmptyObjects: boolean, title?: string, target?: Doc): Opt => { + const convertObject = (object: { [key: string]: FieldType }, excludeEmptyObjects: boolean, title?: string, target?: Doc): Opt => { const hasEntries = Object.keys(object).length; if (hasEntries || !excludeEmptyObjects) { const resolved = target ?? new Doc(); @@ -1618,7 +1628,7 @@ export namespace Doc { * @returns the list mapped from JSON to field values, where each mapping * might involve arbitrary recursion (since toField might itself call convertList) */ - const convertList = (list: Array, excludeEmptyObjects: boolean): Opt> => { + const convertList = (list: Array, excludeEmptyObjects: boolean): Opt> => { const target = new List(); let result: Opt; // if excludeEmptyObjects is true, any qualifying conversions from toField will @@ -1633,15 +1643,15 @@ export namespace Doc { return undefined; }; - const toField = (data: any, excludeEmptyObjects: boolean, title?: string): Opt => { + const toField = (data: unknown, excludeEmptyObjects: boolean, title?: string): Opt => { if (data === null || data === undefined) { return undefined; } if (primitives.includes(typeof data)) { - return data; + return data as FieldType; } if (typeof data === 'object') { - return data instanceof Array ? convertList(data, excludeEmptyObjects) : convertObject(data, excludeEmptyObjects, title, undefined); + return data instanceof Array ? convertList(data, excludeEmptyObjects) : convertObject(data as { [key: string]: FieldType }, excludeEmptyObjects, title, undefined); } throw new Error(`How did ${data} of type ${typeof data} end up in JSON?`); }; @@ -1654,8 +1664,8 @@ export function RTFIsFragment(html: string) { export function GetHrefFromHTML(html: string): string { const parser = new DOMParser(); const parsedHtml = parser.parseFromString(html, 'text/html'); - if (parsedHtml.body.childNodes.length === 1 && parsedHtml.body.childNodes[0].childNodes.length === 1 && (parsedHtml.body.childNodes[0].childNodes[0] as any).href) { - return (parsedHtml.body.childNodes[0].childNodes[0] as any).href; + if (parsedHtml.body.childNodes.length === 1 && parsedHtml.body.childNodes[0].childNodes.length === 1 && (parsedHtml.body.childNodes[0].childNodes[0] as HTMLAnchorElement).href) { + return (parsedHtml.body.childNodes[0].childNodes[0] as HTMLAnchorElement).href; } return ''; } @@ -1675,35 +1685,35 @@ export function IdToDoc(id: string) { return DocCast(DocServer.GetCachedRefField(id)); } // eslint-disable-next-line prefer-arrow-callback -ScriptingGlobals.add(function idToDoc(id: string): any { +ScriptingGlobals.add(function idToDoc(id: string): Doc { return IdToDoc(id); }); // eslint-disable-next-line prefer-arrow-callback -ScriptingGlobals.add(function renameEmbedding(doc: any) { +ScriptingGlobals.add(function renameEmbedding(doc: Doc) { return StrCast(doc[DocData].title).replace(/\([0-9]*\)/, '') + `(${doc.proto_embeddingId})`; }); // eslint-disable-next-line prefer-arrow-callback -ScriptingGlobals.add(function getProto(doc: any) { +ScriptingGlobals.add(function getProto(doc: Doc) { return Doc.GetProto(doc); }); // eslint-disable-next-line prefer-arrow-callback -ScriptingGlobals.add(function getDocTemplate(doc?: any) { +ScriptingGlobals.add(function getDocTemplate(doc?: Doc) { return Doc.getDocTemplate(doc); }); // eslint-disable-next-line prefer-arrow-callback -ScriptingGlobals.add(function getEmbedding(doc: any) { +ScriptingGlobals.add(function getEmbedding(doc: Doc) { return Doc.MakeEmbedding(doc); }); // eslint-disable-next-line prefer-arrow-callback -ScriptingGlobals.add(function getCopy(doc: any, copyProto: any) { +ScriptingGlobals.add(function getCopy(doc: Doc, copyProto: boolean) { return doc.isTemplateDoc ? Doc.MakeDelegateWithProto(doc) : Doc.MakeCopy(doc, copyProto); }); // eslint-disable-next-line prefer-arrow-callback -ScriptingGlobals.add(function copyField(field: any) { +ScriptingGlobals.add(function copyField(field: FieldResult) { return Field.Copy(field); }); // eslint-disable-next-line prefer-arrow-callback -ScriptingGlobals.add(function docList(field: any) { +ScriptingGlobals.add(function docList(field: FieldResult) { return DocListCast(field); }); // eslint-disable-next-line prefer-arrow-callback @@ -1711,11 +1721,11 @@ ScriptingGlobals.add(function addDocToList(doc: Doc, field: string, added: Doc) return Doc.AddDocToList(doc, field, added); }); // eslint-disable-next-line prefer-arrow-callback -ScriptingGlobals.add(function setInPlace(doc: any, field: any, value: any) { +ScriptingGlobals.add(function setInPlace(doc: Doc, field: string, value: string) { return Doc.SetInPlace(doc, field, value, false); }); // eslint-disable-next-line prefer-arrow-callback -ScriptingGlobals.add(function sameDocs(doc1: any, doc2: any) { +ScriptingGlobals.add(function sameDocs(doc1: Doc, doc2: Doc) { return Doc.AreProtosEqual(doc1, doc2); }); // eslint-disable-next-line prefer-arrow-callback @@ -1723,7 +1733,7 @@ ScriptingGlobals.add(function assignDoc(doc: Doc, field: string, id: string) { return Doc.assignDocToField(doc, field, id); }); // eslint-disable-next-line prefer-arrow-callback -ScriptingGlobals.add(function docCastAsync(doc: FieldResult): any { +ScriptingGlobals.add(function docCastAsync(doc: FieldResult): FieldResult { return Cast(doc, Doc); }); // eslint-disable-next-line prefer-arrow-callback @@ -1732,7 +1742,7 @@ ScriptingGlobals.add(function activePresentationItem() { return curPres && DocListCast(curPres[Doc.LayoutFieldKey(curPres)])[NumCast(curPres._itemIndex)]; }); // eslint-disable-next-line prefer-arrow-callback -ScriptingGlobals.add(function setDocFilter(container: Doc, key: string, value: any, modifiers: 'match' | 'check' | 'x' | 'remove') { +ScriptingGlobals.add(function setDocFilter(container: Doc, key: string, value: string, modifiers: 'match' | 'check' | 'x' | 'remove') { Doc.setDocFilter(container, key, value, modifiers); }); // eslint-disable-next-line prefer-arrow-callback diff --git a/src/fields/List.ts b/src/fields/List.ts index 38c47d546..22bbcb9ab 100644 --- a/src/fields/List.ts +++ b/src/fields/List.ts @@ -2,33 +2,33 @@ import { action, computed, makeObservable, observable } from 'mobx'; import { alias, list as serializrList, serializable } from 'serializr'; import { ScriptingGlobals } from '../client/util/ScriptingGlobals'; import { Deserializable, afterDocDeserialize, autoObject } from '../client/util/SerializationHelper'; -import { Field, FieldType, StrListCast } from './Doc'; +import { Doc, Field, FieldType, ObjGetRefFields, StrListCast } from './Doc'; import { FieldTuples, Self, SelfProxy } from './DocSymbols'; import { Copy, FieldChanged, Parent, ToJavascriptString, ToScriptString, ToString } from './FieldSymbols'; -import { ObjGetRefFields, ObjectField } from './ObjectField'; +import { ObjectField } from './ObjectField'; import { ProxyField } from './Proxy'; import { RefField } from './RefField'; import { containedFieldChangedHandler, deleteProperty, getter, setter } from './util'; function toObjectField(field: FieldType) { - return field instanceof RefField ? new ProxyField(field) : field; + return field instanceof Doc ? new ProxyField(field) : field; } -function toRealField(field: FieldType) { +function toRealField(field: FieldType | undefined) { return field instanceof ProxyField ? field.value : field; } -type StoredType = T extends RefField ? ProxyField : T; +type StoredType = T extends Doc ? ProxyField : T; export const ListFieldName = 'fields'; @Deserializable('list') -class ListImpl extends ObjectField { - static listHandlers: any = { +export class ListImpl extends ObjectField { + static listHandlers = { /// Mutator methods - copyWithin() { + copyWithin: function (this: ListImpl) { throw new Error('copyWithin not supported yet'); }, - fill(value: any, start?: number, end?: number) { + fill: function (this: ListImpl, value: FieldType, start?: number, end?: number) { if (value instanceof RefField) { throw new Error('fill with RefFields not supported yet'); } @@ -36,12 +36,12 @@ class ListImpl extends ObjectField { this[SelfProxy][FieldChanged]?.(); return res; }, - pop(): any { + pop: function (this: ListImpl): FieldType { const field = toRealField(this[Self].__fieldTuples.pop()); this[SelfProxy][FieldChanged]?.(); return field; }, - push: action(function (this: ListImpl, ...itemsIn: any[]) { + push: action(function (this: ListImpl, ...itemsIn: FieldType[]) { const items = itemsIn.map(toObjectField); const list = this[Self]; @@ -58,27 +58,27 @@ class ListImpl extends ObjectField { this[SelfProxy][FieldChanged]?.({ op: '$addToSet', items, length: length + items.length }); return res; }), - reverse() { + reverse: function (this: ListImpl) { const res = this[Self].__fieldTuples.reverse(); this[SelfProxy][FieldChanged]?.(); return res; }, - shift() { + shift: function (this: ListImpl) { const res = toRealField(this[Self].__fieldTuples.shift()); this[SelfProxy][FieldChanged]?.(); return res; }, - sort(cmpFunc: any) { + sort: function (this: ListImpl, cmpFunc: (first: FieldType | undefined, second: FieldType | undefined) => number) { this[Self].__realFields; // coerce retrieving entire array - const res = this[Self].__fieldTuples.sort(cmpFunc ? (first: any, second: any) => cmpFunc(toRealField(first), toRealField(second)) : undefined); + const res = this[Self].__fieldTuples.sort(cmpFunc ? (first: FieldType, second: FieldType) => cmpFunc(toRealField(first), toRealField(second)) : undefined); this[SelfProxy][FieldChanged]?.(); return res; }, - splice: action(function (this: any, start: number, deleteCount: number, ...itemsIn: any[]) { + splice: action(function (this: ListImpl, start: number, deleteCount: number, ...itemsIn: FieldType[]) { this[Self].__realFields; // coerce retrieving entire array const items = itemsIn.map(toObjectField); const list = this[Self]; - const removed = list.__fieldTuples.filter((item: any, i: number) => i >= start && i < start + deleteCount); + const removed = list.__fieldTuples.filter((item: FieldType, i: number) => i >= start && i < start + deleteCount); for (let i = 0; i < items.length; i++) { const item = items[i]; // TODO Error checking to make sure parent doesn't already exist @@ -88,7 +88,7 @@ class ListImpl extends ObjectField { item[FieldChanged] = containedFieldChangedHandler(this, i + start, item); } } - const hintArray: { val: any; index: number }[] = []; + const hintArray: { val: FieldType; index: number }[] = []; for (let i = start; i < start + deleteCount; i++) { hintArray.push({ val: list.__fieldTuples[i], index: i }); } @@ -104,7 +104,7 @@ class ListImpl extends ObjectField { ); return res.map(toRealField); }), - unshift(...itemsIn: any[]) { + unshift: function (this: ListImpl, ...itemsIn: FieldType[]) { const items = itemsIn.map(toObjectField); const list = this[Self]; for (let i = 0; i < items.length; i++) { @@ -121,108 +121,108 @@ class ListImpl extends ObjectField { return res; }, /// Accessor methods - concat: action(function (this: any, ...items: any[]) { + concat: action(function (this: ListImpl, ...items: FieldType[]) { this[Self].__realFields; return this[Self].__fieldTuples.map(toRealField).concat(...items); }), - includes(valueToFind: any, fromIndex: number) { + includes: function (this: ListImpl, valueToFind: FieldType, fromIndex: number) { if (valueToFind instanceof RefField) { return this[Self].__realFields.includes(valueToFind, fromIndex); } return this[Self].__fieldTuples.includes(valueToFind, fromIndex); }, - indexOf(valueToFind: any, fromIndex: number) { + indexOf: function (this: ListImpl, valueToFind: FieldType, fromIndex: number) { if (valueToFind instanceof RefField) { return this[Self].__realFields.indexOf(valueToFind, fromIndex); } return this[Self].__fieldTuples.indexOf(valueToFind, fromIndex); }, - join(separator: any) { + join: function (this: ListImpl, separator: string) { this[Self].__realFields; return this[Self].__fieldTuples.map(toRealField).join(separator); }, - lastElement() { + lastElement: function (this: ListImpl) { return this[Self].__realFields.lastElement(); }, - lastIndexOf(valueToFind: any, fromIndex: number) { + lastIndexOf: function (this: ListImpl, valueToFind: FieldType, fromIndex: number) { if (valueToFind instanceof RefField) { return this[Self].__realFields.lastIndexOf(valueToFind, fromIndex); } return this[Self].__fieldTuples.lastIndexOf(valueToFind, fromIndex); }, - slice(begin: number, end: number) { + slice: function (this: ListImpl, begin: number, end: number) { this[Self].__realFields; return this[Self].__fieldTuples.slice(begin, end).map(toRealField); }, /// Iteration methods - entries() { + entries: function (this: ListImpl) { return this[Self].__realFields.entries(); }, - every(callback: any, thisArg: any) { + every: function (this: ListImpl, callback: (value: FieldType, index: number, array: FieldType[]) => unknown, thisArg: unknown) { return this[Self].__realFields.every(callback, thisArg); // TODO This is probably more efficient, but technically the callback can take the array, which would mean we would have to map the actual array anyway. // If we don't want to support the array parameter, we should use this version instead // return this[Self].__fieldTuples.every((element:any, index:number, array:any) => callback(toRealField(element), index, array), thisArg); }, - filter(callback: any, thisArg: any) { + filter: function (this: ListImpl, callback: (value: FieldType, index: number, array: FieldType[]) => FieldType[], thisArg: unknown) { return this[Self].__realFields.filter(callback, thisArg); // TODO This is probably more efficient, but technically the callback can take the array, which would mean we would have to map the actual array anyway. // If we don't want to support the array parameter, we should use this version instead // return this[Self].__fieldTuples.filter((element:any, index:number, array:any) => callback(toRealField(element), index, array), thisArg); }, - find(callback: any, thisArg: any) { + find: function (this: ListImpl, callback: (value: FieldType, index: number, obj: FieldType[]) => FieldType, thisArg: unknown) { return this[Self].__realFields.find(callback, thisArg); // TODO This is probably more efficient, but technically the callback can take the array, which would mean we would have to map the actual array anyway. // If we don't want to support the array parameter, we should use this version instead // return this[Self].__fieldTuples.find((element:any, index:number, array:any) => callback(toRealField(element), index, array), thisArg); }, - findIndex(callback: any, thisArg: any) { + findIndex: function (this: ListImpl, callback: (value: FieldType, index: number, obj: FieldType[]) => number, thisArg: unknown) { return this[Self].__realFields.findIndex(callback, thisArg); // TODO This is probably more efficient, but technically the callback can take the array, which would mean we would have to map the actual array anyway. // If we don't want to support the array parameter, we should use this version instead // return this[Self].__fieldTuples.findIndex((element:any, index:number, array:any) => callback(toRealField(element), index, array), thisArg); }, - forEach(callback: any, thisArg: any) { + forEach: function (this: ListImpl, callback: (value: FieldType, index: number, array: FieldType[]) => void, thisArg: unknown) { return this[Self].__realFields.forEach(callback, thisArg); // TODO This is probably more efficient, but technically the callback can take the array, which would mean we would have to map the actual array anyway. // If we don't want to support the array parameter, we should use this version instead // return this[Self].__fieldTuples.forEach((element:any, index:number, array:any) => callback(toRealField(element), index, array), thisArg); }, - map(callback: any, thisArg: any) { + map: function (this: ListImpl, callback: (value: FieldType, index: number, array: FieldType[]) => unknown, thisArg: unknown) { return this[Self].__realFields.map(callback, thisArg); // TODO This is probably more efficient, but technically the callback can take the array, which would mean we would have to map the actual array anyway. // If we don't want to support the array parameter, we should use this version instead // return this[Self].__fieldTuples.map((element:any, index:number, array:any) => callback(toRealField(element), index, array), thisArg); }, - reduce(callback: any, initialValue: any) { + reduce: function (this: ListImpl, callback: (previousValue: unknown, currentValue: FieldType, currentIndex: number, array: FieldType[]) => unknown, initialValue: unknown) { return this[Self].__realFields.reduce(callback, initialValue); // TODO This is probably more efficient, but technically the callback can take the array, which would mean we would have to map the actual array anyway. // If we don't want to support the array parameter, we should use this version instead // return this[Self].__fieldTuples.reduce((acc:any, element:any, index:number, array:any) => callback(acc, toRealField(element), index, array), initialValue); }, - reduceRight(callback: any, initialValue: any) { + reduceRight: function (this: ListImpl, callback: (previousValue: unknown, currentValue: FieldType, currentIndex: number, array: FieldType[]) => unknown, initialValue: unknown) { return this[Self].__realFields.reduceRight(callback, initialValue); // TODO This is probably more efficient, but technically the callback can take the array, which would mean we would have to map the actual array anyway. // If we don't want to support the array parameter, we should use this version instead // return this[Self].__fieldTuples.reduceRight((acc:any, element:any, index:number, array:any) => callback(acc, toRealField(element), index, array), initialValue); }, - some(callback: any, thisArg: any) { + some: function (this: ListImpl, callback: (value: FieldType, index: number, array: FieldType[]) => boolean, thisArg: unknown) { return this[Self].__realFields.some(callback, thisArg); // TODO This is probably more efficient, but technically the callback can take the array, which would mean we would have to map the actual array anyway. // If we don't want to support the array parameter, we should use this version instead // return this[Self].__fieldTuples.some((element:any, index:number, array:any) => callback(toRealField(element), index, array), thisArg); }, - values() { + values: function (this: ListImpl) { return this[Self].__realFields.values(); }, - [Symbol.iterator]() { + [Symbol.iterator]: function (this: ListImpl) { return this[Self].__realFields.values(); }, }; - static listGetter(target: any, prop: string | symbol, receiver: any): any { + static listGetter(target: ListImpl, prop: string | symbol, receiver: ListImpl): unknown { if (Object.prototype.hasOwnProperty.call(ListImpl.listHandlers, prop)) { - return ListImpl.listHandlers[prop]; + return (ListImpl.listHandlers as { [key: string | symbol]: unknown })[prop]; } return getter(target, prop, receiver); } @@ -251,7 +251,7 @@ class ListImpl extends ObjectField { }, }); // eslint-disable-next-line no-use-before-define - this[SelfProxy] = list as any as List; // bcz: ugh .. don't know how to convince typesecript that list is a List + this[SelfProxy] = list as unknown as List; // bcz: ugh .. don't know how to convince typesecript that list is a List if (fields) { this[SelfProxy].push(...fields); } @@ -260,18 +260,20 @@ class ListImpl extends ObjectField { } [key: number]: T | (T extends RefField ? Promise : never); + [key2: symbol]: unknown; + [key3: string]: unknown; // this requests all ProxyFields at the same time to avoid the overhead // of separate network requests and separate updates to the React dom. @computed private get __realFields() { - const unrequested = this[FieldTuples].filter(f => f instanceof ProxyField && f.needsRequesting).map(f => f as ProxyField); + const unrequested = this[FieldTuples].filter(f => f instanceof ProxyField && f.needsRequesting).map(f => f as ProxyField); // if we find any ProxyFields that don't have a current value, then // start the server request for all of them if (unrequested.length) { const batchPromise = ObjGetRefFields(unrequested.map(p => p.fieldId)); // as soon as we get the fields from the server, set all the list values in one // action to generate one React dom update. - const allSetPromise = batchPromise.then(action(pfields => unrequested.map(toReq => toReq.setValue(pfields[toReq.fieldId])))); + const allSetPromise = batchPromise.then(action(pfields => unrequested.map(toReq => toReq.setValue(pfields.get(toReq.fieldId))))); // we also have to mark all lists items with this promise so that any calls to them // will await the batch request and return the requested field value. unrequested.forEach(p => p.setExternalValuePromise(allSetPromise)); @@ -280,11 +282,11 @@ class ListImpl extends ObjectField { } @serializable(alias(ListFieldName, serializrList(autoObject(), { afterDeserialize: afterDocDeserialize }))) - private get __fieldTuples() { + get __fieldTuples() { return this[FieldTuples]; } - private set __fieldTuples(value) { + set __fieldTuples(value) { this[FieldTuples] = value; Object.keys(value).forEach(key => { const item = value[Number(key)]; @@ -297,7 +299,7 @@ class ListImpl extends ObjectField { [Copy]() { const copiedData = this[Self].__fieldTuples.map(f => (f instanceof ObjectField ? f[Copy]() : f)); - const deepCopy = new ListImpl(copiedData as any); + const deepCopy = new ListImpl(copiedData as T[]); return deepCopy; } @@ -309,19 +311,19 @@ class ListImpl extends ObjectField { private [SelfProxy]: List; // also used in utils.ts even though it won't be found using find all references [ToScriptString]() { return `new List(${this[ToJavascriptString]()})`; } // prettier-ignore - [ToJavascriptString]() { return `[${(this as any).map((field: any) => Field.toScriptString(field))}]`; } // prettier-ignore - [ToString]() { return `[${(this as any).map((field: any) => Field.toString(field))}]`; } // prettier-ignore + [ToJavascriptString]() { return `[${(this[FieldTuples]).map(field => Field.toScriptString(field))}]`; } // prettier-ignore + [ToString]() { return `[${(this[FieldTuples]).map(field => Field.toString(field))}]`; } // prettier-ignore } // declare List as a type so you can use it in type declarations, e.g., { l: List, ...} export type List = ListImpl & (T | (T extends RefField ? Promise : never))[]; -// decalre List as a value so you can invoke 'new' on it, e.g., new List() +// decalre List as a value so you can invoke 'new' on it, e.g., new List() (since List IS ListImpl, we can safely cast the 'new' return value to return List) // eslint-disable-next-line no-redeclare -export const List: { new (fields?: T[]): List } = ListImpl as any; +export const List: { new (fields?: T[]): List } = ListImpl as unknown as { new (fields?: T[]): List }; ScriptingGlobals.add('List', List); // eslint-disable-next-line prefer-arrow-callback -ScriptingGlobals.add(function compareLists(l1: any, l2: any) { +ScriptingGlobals.add(function compareLists(l1: List, l2: List) { const L1 = StrListCast(l1); const L2 = StrListCast(l2); return !L1 && !L2 ? true : L1 && L2 && L1.length === L2.length && L2.reduce((p, v) => p && L1.includes(v), true); diff --git a/src/fields/ObjectField.ts b/src/fields/ObjectField.ts index 231086262..21c4af608 100644 --- a/src/fields/ObjectField.ts +++ b/src/fields/ObjectField.ts @@ -2,13 +2,21 @@ import { ScriptingGlobals } from '../client/util/ScriptingGlobals'; import { Copy, FieldChanged, Parent, ToJavascriptString, ToScriptString, ToString } from './FieldSymbols'; import { RefField } from './RefField'; +export type serverOpType = { + $set?: { [key: string]: unknown }; // + $unset?: { [key: string]: unknown }; + $remFromSet?: { [key: string]: unknown }; + $addToSet?: { [key: string]: unknown }; + length?: number; +}; export abstract class ObjectField { // prettier-ignore public [FieldChanged]?: (diff?: { op: '$addToSet' | '$remFromSet' | '$set'; // eslint-disable-next-line no-use-before-define items: FieldType[] | undefined; length: number | undefined; - hint?: any }, serverOp?: any) => void; + hint?: unknown }, + serverOp?: serverOpType) => void; // eslint-disable-next-line no-use-before-define public [Parent]?: RefField | ObjectField; abstract [Copy](): ObjectField; @@ -22,15 +30,4 @@ export abstract class ObjectField { } export type FieldType = number | string | boolean | ObjectField | RefField; // bcz: hack for now .. must match the type definition in Doc.ts .. put here to avoid import cycles -// eslint-disable-next-line import/no-mutable-exports -export let ObjGetRefField: (id: string, force?: boolean) => Promise; -// eslint-disable-next-line import/no-mutable-exports -export let ObjGetRefFields: (ids: string[]) => Promise<{ [id: string]: RefField | undefined }>; - -export function SetObjGetRefField(func: (id: string, force?: boolean) => Promise) { - ObjGetRefField = func; -} -export function SetObjGetRefFields(func: (ids: string[]) => Promise<{ [id: string]: RefField | undefined }>) { - ObjGetRefFields = func; -} ScriptingGlobals.add(ObjectField); diff --git a/src/fields/Proxy.ts b/src/fields/Proxy.ts index 83b5672b3..48c336e60 100644 --- a/src/fields/Proxy.ts +++ b/src/fields/Proxy.ts @@ -3,18 +3,19 @@ import { primitive, serializable } from 'serializr'; import { DocServer } from '../client/DocServer'; import { scriptingGlobal } from '../client/util/ScriptingGlobals'; import { Deserializable } from '../client/util/SerializationHelper'; -import { Field, FieldWaiting, Opt } from './Doc'; +import { Doc, Field, FieldWaiting, Opt } from './Doc'; import { Copy, Id, ToJavascriptString, ToScriptString, ToString, ToValue } from './FieldSymbols'; import { ObjectField } from './ObjectField'; -import { RefField } from './RefField'; -function deserializeProxy(field: any) { +type serializedProxyType = { cache: { field: unknown; p: undefined | Promise }; fieldId: string }; + +function deserializeProxy(field: serializedProxyType) { if (!field.cache.field) { - field.cache = { field: DocServer.GetCachedRefField(field.fieldId) as any, p: undefined }; + field.cache = { field: DocServer.GetCachedRefField(field.fieldId), p: undefined }; } } -@Deserializable('proxy', deserializeProxy) -export class ProxyField extends ObjectField { +@Deserializable('proxy', (obj: unknown) => deserializeProxy(obj as serializedProxyType)) +export class ProxyField extends ObjectField { constructor(); constructor(value: T); constructor(fieldId: string); @@ -39,10 +40,10 @@ export class ProxyField extends ObjectField { } [ToJavascriptString]() { - return Field.toScriptString(this[ToValue]()?.value); + return Field.toScriptString(this[ToValue]()?.value as T); } [ToScriptString]() { - return Field.toScriptString(this[ToValue]()?.value); // not sure this is quite right since it doesn't recreate a proxy field, but better than 'invalid' ? + return Field.toScriptString(this[ToValue]()?.value as T); // not sure this is quite right since it doesn't recreate a proxy field, but better than 'invalid' ? } [ToString]() { return Field.toString(this[ToValue]()?.value); @@ -83,7 +84,7 @@ export class ProxyField extends ObjectField { return !!(!this.cache.field && !this.failed && !this._cache.p && !DocServer.GetCachedRefField(this.fieldId)); } - setExternalValuePromise(externalValuePromise: Promise) { + setExternalValuePromise(externalValuePromise: Promise) { this.cache.p = externalValuePromise.then(() => this.value) as FieldWaiting; } @action @@ -94,7 +95,7 @@ export class ProxyField extends ObjectField { } } -// eslint-disable-next-line no-redeclare +// eslint-disable-next-line no-redeclare, @typescript-eslint/no-namespace export namespace ProxyField { let useProxy = true; export function DisableProxyFields() { @@ -114,7 +115,7 @@ export namespace ProxyField { } } - export function toValue(value: any) { + export function toValue(value: { value: unknown }) { if (useProxy) { return { value: value.value }; } @@ -123,10 +124,10 @@ export namespace ProxyField { } // eslint-disable-next-line no-use-before-define -function prefetchValue(proxy: PrefetchProxy) { - return proxy.value as any; +function prefetchValue(proxy: PrefetchProxy) { + return proxy.value as Promise; } @scriptingGlobal -@Deserializable('prefetch_proxy', prefetchValue) -export class PrefetchProxy extends ProxyField {} +@Deserializable('prefetch_proxy', (obj:unknown) => prefetchValue(obj as PrefetchProxy)) +export class PrefetchProxy extends ProxyField {} diff --git a/src/fields/RefField.ts b/src/fields/RefField.ts index 1ce81368a..4ef2a6748 100644 --- a/src/fields/RefField.ts +++ b/src/fields/RefField.ts @@ -14,7 +14,7 @@ export abstract class RefField { this[Id] = this.__id; } - protected [HandleUpdate]?(diff: any): void | Promise; + protected [HandleUpdate]?(diff: unknown): void | Promise; abstract [ToJavascriptString](): string; abstract [ToScriptString](): string; diff --git a/src/fields/ScriptField.ts b/src/fields/ScriptField.ts index 8fe365ac2..582c09f29 100644 --- a/src/fields/ScriptField.ts +++ b/src/fields/ScriptField.ts @@ -1,15 +1,15 @@ import { action, makeObservable, observable } from 'mobx'; import { computedFn } from 'mobx-utils'; import { PropSchema, SKIP, createSimpleSchema, custom, map, object, primitive, serializable } from 'serializr'; -import { numberRange } from '../Utils'; +import { emptyFunction, numberRange } from '../Utils'; import { GPTCallType, gptAPICall } from '../client/apis/gpt/GPT'; import { CompileScript, CompiledScript, ScriptOptions, Transformer } from '../client/util/Scripting'; import { ScriptingGlobals, scriptingGlobal } from '../client/util/ScriptingGlobals'; import { Deserializable, autoObject } from '../client/util/SerializationHelper'; -import { Doc, Field, FieldType, FieldResult, Opt } from './Doc'; +import { Doc, Field, FieldType, FieldResult, ObjGetRefField, Opt } from './Doc'; import { Copy, FieldChanged, Id, ToJavascriptString, ToScriptString, ToString, ToValue } from './FieldSymbols'; import { List } from './List'; -import { ObjGetRefField, ObjectField } from './ObjectField'; +import { ObjectField } from './ObjectField'; import { Cast, StrCast } from './Types'; function optional(propSchema: PropSchema) { @@ -20,7 +20,7 @@ function optional(propSchema: PropSchema) { } return SKIP; }, - (jsonValue: any, context: any, oldValue: any, callback: (err: any, result: any) => void) => { + (jsonValue, context, oldValue, callback) => { if (jsonValue !== undefined) { return propSchema.deserializer(jsonValue, callback, context, oldValue); } @@ -63,7 +63,7 @@ function finalizeScript(scriptIn: ScriptField) { async function deserializeScript(scriptIn: ScriptField) { const script = scriptIn; if (script.captures) { - const captured: any = {}; + const captured: { [key: string]: undefined | string | number | boolean | Doc } = {}; (script.script.options as ScriptOptions).capturedVariables = captured; Promise.all( script.captures.map(async capture => { @@ -85,7 +85,7 @@ async function deserializeScript(scriptIn: ScriptField) { } @scriptingGlobal -@Deserializable('script', deserializeScript) +@Deserializable('script', (obj: unknown) => deserializeScript(obj as ScriptField)) export class ScriptField extends ObjectField { @serializable readonly rawscript: string | undefined; @@ -114,7 +114,7 @@ export class ScriptField extends ObjectField { const captured = script?.options?.capturedVariables; if (captured) { - this.captures = new List(Object.keys(captured).map(key => key + ':' + (captured[key] instanceof Doc ? 'ID->' + (captured[key] as Doc)[Id] : captured[key].toString()))); + this.captures = new List(Object.keys(captured).map(key => key + ':' + (captured[key] instanceof Doc ? 'ID->' + (captured[key] as Doc)[Id] : captured[key]?.toString()))); } this.rawscript = rawscript; this.setterscript = setterscript; @@ -186,7 +186,7 @@ export class ScriptField extends ObjectField { } @scriptingGlobal -@Deserializable('computed', deserializeScript) +@Deserializable('computed', (obj: unknown) => deserializeScript(obj as ComputedField)) export class ComputedField extends ScriptField { static undefined = '__undefined'; static useComputed = true; @@ -221,7 +221,7 @@ export class ComputedField extends ScriptField { _readOnly_: true, }, console.log - ).result + ).result as FieldResult )(); // prettier-ignore return this._lastComputedResult; }; @@ -239,7 +239,7 @@ export class ComputedField extends ScriptField { public static MakeInterpolatedNumber(fieldKey: string, interpolatorKey: string, doc: Doc, curTimecode: number, defaultVal: Opt) { if (!doc[`${fieldKey}_indexed`]) { - const flist = new List(numberRange(curTimecode + 1).map(() => undefined) as any as number[]); + const flist = new List(numberRange(curTimecode + 1).map(emptyFunction) as unknown as number[]); flist[curTimecode] = Cast(doc[fieldKey], 'number', null); doc[`${fieldKey}_indexed`] = flist; } @@ -249,7 +249,7 @@ export class ComputedField extends ScriptField { } public static MakeInterpolatedString(fieldKey: string, interpolatorKey: string, doc: Doc, curTimecode: number) { if (!doc[`${fieldKey}_`]) { - const flist = new List(numberRange(curTimecode + 1).map(() => undefined) as any as string[]); + const flist = new List(numberRange(curTimecode + 1).map(emptyFunction) as unknown as string[]); flist[curTimecode] = StrCast(doc[fieldKey]); doc[`${fieldKey}_indexed`] = flist; } @@ -260,7 +260,7 @@ export class ComputedField extends ScriptField { public static MakeInterpolatedDataField(fieldKey: string, interpolatorKey: string, doc: Doc, curTimecode: number) { if (doc[`${fieldKey}`] instanceof List) return undefined; if (!doc[`${fieldKey}_indexed`]) { - const flist = new List(numberRange(curTimecode + 1).map(() => undefined) as any as FieldType[]); + const flist = new List(numberRange(curTimecode + 1).map(emptyFunction) as unknown as FieldType[]); flist[curTimecode] = Field.Copy(doc[fieldKey]); doc[`${fieldKey}_indexed`] = flist; } @@ -278,7 +278,7 @@ export class ComputedField extends ScriptField { ScriptingGlobals.add( // eslint-disable-next-line prefer-arrow-callback - function setIndexVal(list: any[], index: number, value: any) { + function setIndexVal(list: FieldResult[], index: number, value: FieldType) { while (list.length <= index) list.push(undefined); list[index] = value; }, @@ -288,7 +288,7 @@ ScriptingGlobals.add( ScriptingGlobals.add( // eslint-disable-next-line prefer-arrow-callback - function getIndexVal(list: any[], index: number, defaultVal: Opt = undefined) { + function getIndexVal(list: unknown[], index: number, defaultVal: Opt = undefined) { return list?.reduce((p, x, i) => ((i <= index && x !== undefined) || p === undefined ? x : p), defaultVal); }, 'returns the value at a given index of a list', diff --git a/src/fields/util.ts b/src/fields/util.ts index a6499c3e3..69ece82a2 100644 --- a/src/fields/util.ts +++ b/src/fields/util.ts @@ -7,7 +7,7 @@ import { UndoManager } from '../client/util/UndoManager'; import { Doc, DocListCast, FieldType, FieldResult, HierarchyMapping, ReverseHierarchyMap, StrListCast, aclLevel, updateCachedAcls } from './Doc'; import { AclAdmin, AclAugment, AclEdit, AclPrivate, DirectLinks, DocAcl, DocData, DocLayout, FieldKeys, ForceServerWrite, Height, Initializing, SelfProxy, UpdatingFromServer, Width } from './DocSymbols'; import { FieldChanged, Id, Parent, ToValue } from './FieldSymbols'; -import { List } from './List'; +import { List, ListImpl } from './List'; import { ObjectField } from './ObjectField'; import { PrefetchProxy, ProxyField } from './Proxy'; import { RefField } from './RefField'; @@ -44,15 +44,23 @@ export function TraceMobx() { tracing && trace(); } -export const _propSetterCB = new Map void) | undefined>(); +export const _propSetterCB = new Map void) | undefined>(); -const _setterImpl = action((target: any, prop: string | symbol | number, valueIn: any, receiver: any): boolean => { +const _setterImpl = action((target: Doc | ListImpl, prop: string | symbol | number, valueIn: unknown, receiver: Doc | ListImpl): boolean => { + if (target instanceof ListImpl) { + if (typeof prop !== 'symbol' && +prop == prop) { + target[SelfProxy].splice(+prop, 1, valueIn as FieldType); + } else { + target[prop] = valueIn as FieldType; + } + return true; + } if (SerializationHelper.IsSerializing() || typeof prop === 'symbol') { - target[prop] = valueIn; + target[prop] = valueIn as FieldResult; return true; } - let value = valueIn?.[SelfProxy] ?? valueIn; // convert any Doc type values to Proxy's + let value = (valueIn as Doc | ListImpl)?.[SelfProxy] ?? valueIn; // convert any Doc type values to Proxy's const curValue = target.__fieldTuples[prop]; if (curValue === value || (curValue instanceof ProxyField && value instanceof RefField && curValue.fieldId === value[Id])) { @@ -60,7 +68,7 @@ const _setterImpl = action((target: any, prop: string | symbol | number, valueIn // curValue should get filled in with value if it isn't already filled in, in case we fetched the referenced field some other way return true; } - if (value instanceof RefField) { + if (value instanceof Doc) { value = new ProxyField(value); } @@ -77,7 +85,7 @@ const _setterImpl = action((target: any, prop: string | symbol | number, valueIn delete curValue[FieldChanged]; } - if (typeof prop === 'string' && _propSetterCB.has(prop)) _propSetterCB.get(prop)!(target[SelfProxy], value); + if (typeof prop === 'string' && _propSetterCB.has(prop)) _propSetterCB.get(prop)!(target[SelfProxy], value as FieldType); // eslint-disable-next-line no-use-before-define const effectiveAcl = GetEffectiveAcl(target); @@ -108,16 +116,17 @@ const _setterImpl = action((target: any, prop: string | symbol | number, valueIn (target as Doc|ObjectField)[FieldChanged]?.(undefined, { $unset: { ['fields.' + prop]: '' } }); else (target as Doc|ObjectField)[FieldChanged]?.(undefined, { $set: { ['fields.' + prop]: value instanceof ObjectField ? SerializationHelper.Serialize(value) :value}}); if (prop === 'author' || prop.toString().startsWith('acl_')) updateCachedAcls(target); - } else { + } else if (receiver instanceof Doc) { DocServer.registerDocWithCachedUpdate(receiver, prop as string, curValue); } !receiver[Initializing] && + receiver instanceof Doc && !StrListCast(receiver.undoIgnoreFields).includes(prop.toString()) && (!receiver[UpdatingFromServer] || receiver[ForceServerWrite]) && UndoManager.AddEvent( { redo: () => { - receiver[prop] = value; + receiver[prop] = value as FieldType; }, undo: () => { const wasUpdate = receiver[UpdatingFromServer]; @@ -137,7 +146,7 @@ const _setterImpl = action((target: any, prop: string | symbol | number, valueIn return true; }); -let _setter: (target: any, prop: string | symbol | number, value: any, receiver: any) => boolean = _setterImpl; +let _setter: (target: Doc | ListImpl, prop: string | symbol | number, value: FieldType | undefined, receiver: Doc | ListImpl) => boolean = _setterImpl; export function makeReadOnly() { _setter = _readOnlySetter; @@ -156,18 +165,18 @@ export function denormalizeEmail(email: string) { // return acl from cache or cache the acl and return. // eslint-disable-next-line no-use-before-define -const getEffectiveAclCache = computedFn((target: any, user?: string) => getEffectiveAcl(target, user), true); +const getEffectiveAclCache = computedFn((target: Doc | ListImpl, user?: string) => getEffectiveAcl(target, user), true); /** * Calculates the effective access right to a document for the current user. */ -export function GetEffectiveAcl(target: any, user?: string): symbol { +export function GetEffectiveAcl(target: Doc | ListImpl, user?: string): symbol { if (!target) return AclPrivate; if (target[UpdatingFromServer] || ClientUtils.CurrentUserEmail() === 'guest') return AclAdmin; return getEffectiveAclCache(target, user); // all changes received from the server must be processed as Admin. return this directly so that the acls aren't cached (UpdatingFromServer is not observable) } -export function GetPropAcl(target: any, prop: string | symbol | number) { +export function GetPropAcl(target: Doc | ListImpl, prop: string | symbol | number) { if (typeof prop === 'symbol' || target[UpdatingFromServer]) return AclAdmin; // requesting the UpdatingFromServer prop or AclSym must always go through to keep the local DB consistent if (prop && DocServer.IsPlaygroundField(prop.toString())) return AclEdit; // playground props are always editable return GetEffectiveAcl(target); @@ -182,7 +191,8 @@ export function GetCachedGroupByName(name: string) { export function SetCachedGroups(groups: string[]) { runInAction(() => cachedGroups.push(...groups)); } -function getEffectiveAcl(target: any, user?: string): symbol { +function getEffectiveAcl(target: Doc | ListImpl, user?: string): symbol { + if (target instanceof ListImpl) return AclAdmin; const targetAcls = target[DocAcl]; if (targetAcls?.acl_Me === AclAdmin || GetCachedGroupByName('Admin')) return AclAdmin; @@ -287,14 +297,14 @@ export function inheritParentAcls(parent: Doc, child: Doc, layoutOnly: boolean) * @param prop * @param propSetter */ -export function SetPropSetterCb(prop: string, propSetter: ((target: any, value: any) => void) | undefined) { +export function SetPropSetterCb(prop: string, propSetter: ((target: Doc, value: FieldType) => void) | undefined) { _propSetterCB.set(prop, propSetter); } // // target should be either a Doc or ListImpl. receiver should be a Proxy Or List. // -export function setter(target: any, inProp: string | symbol | number, value: any, receiver: any): boolean { +export function setter(target: ListImpl | Doc, inProp: string | symbol | number, value: unknown, receiver: Doc | ListImpl): boolean { if (!inProp) { console.log('WARNING: trying to set an empty property. This should be fixed. '); return false; @@ -303,12 +313,12 @@ export function setter(target: any, inProp: string | symbol | number, value: any const effectiveAcl = inProp === 'constructor' || typeof inProp === 'symbol' ? AclAdmin : GetPropAcl(target, prop); if (effectiveAcl !== AclEdit && effectiveAcl !== AclAugment && effectiveAcl !== AclAdmin) return true; // if you're trying to change an acl but don't have Admin access / you're trying to change it to something that isn't an acceptable acl, you can't - if (typeof prop === 'string' && prop.startsWith('acl_') && (effectiveAcl !== AclAdmin || ![...Object.values(SharingPermissions), undefined].includes(value))) return true; + if (typeof prop === 'string' && prop.startsWith('acl_') && (effectiveAcl !== AclAdmin || ![...Object.values(SharingPermissions), undefined].includes(value as SharingPermissions))) return true; if (typeof prop === 'string' && prop !== '__id' && prop !== '__fieldTuples' && prop.startsWith('_')) { if (!prop.startsWith('__')) prop = prop.substring(1); - if (target.__LAYOUT__) { - target.__LAYOUT__[prop] = value; + if (target.__LAYOUT__ instanceof Doc) { + target.__LAYOUT__[prop] = value as FieldResult; return true; } } @@ -317,10 +327,10 @@ export function setter(target: any, inProp: string | symbol | number, value: any return !!ScriptCast(target.__fieldTuples[prop])?.setterscript?.run({ self: target[SelfProxy], this: target[SelfProxy], value }).success; } } - return _setter(target, prop, value, receiver); + return _setter(target, prop, value as FieldType, receiver); } -function getFieldImpl(target: any, prop: string | number, proxy: any, ignoreProto: boolean = false): any { +function getFieldImpl(target: ListImpl | Doc, prop: string | number, proxy: ListImpl | Doc, ignoreProto: boolean = false): FieldType { const field = target.__fieldTuples[prop]; const value = field?.[ToValue]?.(proxy); // converts ComputedFields to values, or unpacks ProxyFields into Proxys if (value) return value.value; @@ -332,7 +342,7 @@ function getFieldImpl(target: any, prop: string | number, proxy: any, ignoreProt } return field; } -export function getter(target: any, prop: string | symbol, proxy: any): any { +export function getter(target: Doc | ListImpl, prop: string | symbol, proxy: ListImpl | Doc): unknown { // prettier-ignore switch (prop) { case 'then' : return undefined; @@ -352,19 +362,23 @@ export function getter(target: any, prop: string | symbol, proxy: any): any { } const layoutProp = prop.startsWith('_') ? prop.substring(1) : undefined; - if (layoutProp && target.__LAYOUT__) return target.__LAYOUT__[layoutProp]; + if (layoutProp && target.__LAYOUT__) return (target.__LAYOUT__ as Doc)[layoutProp]; return getFieldImpl(target, layoutProp ?? prop, proxy); } -export function getField(target: any, prop: string | number, ignoreProto: boolean = false): any { - return getFieldImpl(target, prop, target[SelfProxy], ignoreProto); +export function getField(target: ListImpl | Doc, prop: string | number, ignoreProto: boolean = false): unknown { + return getFieldImpl(target, prop, target[SelfProxy] as Doc, ignoreProto); } -export function deleteProperty(target: any, prop: string | number | symbol) { +export function deleteProperty(target: Doc | ListImpl, prop: string | number | symbol) { if (typeof prop === 'symbol') { delete target[prop]; } else { - target[SelfProxy][prop] = undefined; + if (target instanceof Doc) { + target[SelfProxy][prop] = undefined; + } else if (+prop == prop) { + target[SelfProxy].splice(+prop, 1); + } } return true; } @@ -378,39 +392,42 @@ export function deleteProperty(target: any, prop: string | number | symbol) { // were replaced. Based on this specification, an Undo event is setup that will save enough information about the ObjectField to be // able to undo and redo the partial change. // -export function containedFieldChangedHandler(container: List | Doc, prop: string | number, liveContainedField: ObjectField) { +export function containedFieldChangedHandler(container: ListImpl | Doc, prop: string | number, liveContainedField: ObjectField) { let lastValue: FieldResult = liveContainedField instanceof ObjectField ? ObjectField.MakeCopy(liveContainedField) : liveContainedField; - return (diff?: { op: '$addToSet' | '$remFromSet' | '$set'; items: FieldType[] | undefined; length: number | undefined; hint?: any } /* , dummyServerOp?: any */) => { + return (diff?: { op: '$addToSet' | '$remFromSet' | '$set'; items: (FieldType & { value?: FieldType })[] | undefined; length: number | undefined; hint?: unknown } /* , dummyServerOp?: any */) => { const serializeItems = () => ({ __type: 'list', fields: diff?.items?.map((item: FieldType) => SerializationHelper.Serialize(item)) }); // prettier-ignore const serverOp = diff?.op === '$addToSet' ? { $addToSet: { ['fields.' + prop]: serializeItems() }, length: diff.length } : diff?.op === '$remFromSet' ? { $remFromSet: { ['fields.' + prop]: serializeItems(), hint: diff.hint}, length: diff.length } - : { $set: { ['fields.' + prop]: liveContainedField ? SerializationHelper.Serialize(liveContainedField) : undefined } }; + : { $set: { ['fields.' + prop]: liveContainedField ? SerializationHelper.Serialize(liveContainedField) as FieldType : undefined } }; if (!(container instanceof Doc) || !container[UpdatingFromServer]) { - const prevValue = ObjectField.MakeCopy(lastValue as List); + const cont = container as { [key: string | number]: FieldType }; + const prevValue = ObjectField.MakeCopy(lastValue as List); lastValue = ObjectField.MakeCopy(liveContainedField); const newValue = ObjectField.MakeCopy(liveContainedField); if (diff?.op === '$addToSet') { UndoManager.AddEvent( { redo: () => { + const contList = cont[prop] as List; // console.log('redo $add: ' + prop, diff.items); // bcz: uncomment to log undo - (container as any)[prop as any]?.push(...((diff.items || [])?.map((item: any) => item.value ?? item) ?? [])); - lastValue = ObjectField.MakeCopy((container as any)[prop as any]); + contList?.push(...((diff.items || [])?.map(item => item.value ?? item) ?? [])); + lastValue = ObjectField.MakeCopy(contList); }, undo: action(() => { + const contList = cont[prop] as List; // console.log('undo $add: ' + prop, diff.items); // bcz: uncomment to log undo - diff.items?.forEach((item: any) => { + diff.items?.forEach(item => { const ind = item instanceof SchemaHeaderField // - ? (container as any)[prop as any]?.findIndex((ele: any) => ele instanceof SchemaHeaderField && ele.heading === item.heading) - : (container as any)[prop as any]?.indexOf(item.value ?? item); - ind !== undefined && ind !== -1 && (container as any)[prop as any]?.splice(ind, 1); + ? contList?.findIndex(ele => ele instanceof SchemaHeaderField && ele.heading === item.heading) + : contList?.indexOf(item.value ?? item); + ind !== undefined && ind !== -1 && (cont[prop] as List)?.splice(ind, 1); }); - lastValue = ObjectField.MakeCopy((container as any)[prop as any]); + lastValue = ObjectField.MakeCopy(contList); }), prop: 'add ' + (diff.items?.length ?? 0) + ' items to list', }, @@ -420,48 +437,53 @@ export function containedFieldChangedHandler(container: List | Doc, p UndoManager.AddEvent( { redo: action(() => { + const contList = cont[prop] as List; // console.log('redo $rem: ' + prop, diff.items); // bcz: uncomment to log undo - diff.items?.forEach((item: any) => { + diff.items?.forEach(item => { const ind = item instanceof SchemaHeaderField // - ? (container as any)[prop as any]?.findIndex((ele: any) => ele instanceof SchemaHeaderField && ele.heading === item.heading) - : (container as any)[prop as any]?.indexOf(item.value ?? item); - ind !== undefined && ind !== -1 && (container as any)[prop as any]?.splice(ind, 1); + ? contList?.findIndex(ele => ele instanceof SchemaHeaderField && ele.heading === item.heading) + : contList?.indexOf(item.value ?? item); + ind !== undefined && ind !== -1 && contList?.splice(ind, 1); }); - lastValue = ObjectField.MakeCopy((container as any)[prop as any]); + lastValue = ObjectField.MakeCopy(contList); }), undo: () => { + const contList = cont[prop] as List; + const prevList = prevValue as List; // console.log('undo $rem: ' + prop, diff.items); // bcz: uncomment to log undo - diff.items?.forEach((item: any) => { + diff.items?.forEach(item => { if (item instanceof SchemaHeaderField) { - const ind = (prevValue as List).findIndex((ele: any) => ele instanceof SchemaHeaderField && ele.heading === item.heading); - ind !== -1 && (container as any)[prop as any].findIndex((ele: any) => ele instanceof SchemaHeaderField && ele.heading === item.heading) === -1 && (container as any)[prop as any].splice(ind, 0, item); + const ind = prevList.findIndex(ele => ele instanceof SchemaHeaderField && ele.heading === item.heading); + ind !== -1 && contList.findIndex(ele => ele instanceof SchemaHeaderField && ele.heading === item.heading) === -1 && contList.splice(ind, 0, item); } else { - const ind = (prevValue as List).indexOf(item.value ?? item); - ind !== -1 && (container as any)[prop as any].indexOf(item.value ?? item) === -1 && (container as any)[prop as any].splice(ind, 0, item); + const ind = prevList.indexOf(item.value ?? item); + ind !== -1 && contList.indexOf(item.value ?? item) === -1 && (cont[prop] as List).splice(ind, 0, item); } }); - lastValue = ObjectField.MakeCopy((container as any)[prop as any]); + lastValue = ObjectField.MakeCopy(contList); }, - prop: 'remove ' + (diff.items?.length ?? 0) + ' items from list(' + ((container as any)?.title ?? '') + ':' + prop + ')', + prop: 'remove ' + (diff.items?.length ?? 0) + ' items from list(' + (cont?.title ?? '') + ':' + prop + ')', }, diff?.items ); } else { const setFieldVal = (val: FieldType | undefined) => { - container instanceof Doc ? (container[prop as string] = val) : (container[prop as number] = val as FieldType); + container instanceof Doc ? (container[prop] = val) : (container[prop as number] = val as FieldType); }; UndoManager.AddEvent( { redo: () => { // console.log('redo list: ' + prop, fieldVal()); // bcz: uncomment to log undo - setFieldVal(newValue instanceof ObjectField ? ObjectField.MakeCopy(newValue) : undefined); - lastValue = ObjectField.MakeCopy((container as any)[prop as any]); + setFieldVal(ObjectField.MakeCopy(newValue)); + const containerProp = cont[prop]; + lastValue = containerProp instanceof ObjectField && ObjectField.MakeCopy(containerProp); }, undo: () => { // console.log('undo list: ' + prop, fieldVal()); // bcz: uncomment to log undo - setFieldVal(prevValue instanceof ObjectField ? ObjectField.MakeCopy(prevValue) : undefined); - lastValue = ObjectField.MakeCopy((container as any)[prop as any]); + setFieldVal(ObjectField.MakeCopy(prevValue)); + const containerProp = cont[prop]; + lastValue = containerProp instanceof ObjectField && ObjectField.MakeCopy(containerProp); }, prop: 'set list field', }, diff --git a/src/mobile/ImageUpload.tsx b/src/mobile/ImageUpload.tsx index 7a1e35636..36c0d6a4d 100644 --- a/src/mobile/ImageUpload.tsx +++ b/src/mobile/ImageUpload.tsx @@ -1,5 +1,3 @@ -/* eslint-disable jsx-a11y/no-static-element-interactions */ -/* eslint-disable jsx-a11y/click-events-have-key-events */ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { action, observable } from 'mobx'; import { observer } from 'mobx-react'; @@ -16,6 +14,7 @@ import { listSpec } from '../fields/Schema'; import { Cast } from '../fields/Types'; import './ImageUpload.scss'; +// eslint-disable-next-line @typescript-eslint/no-var-requires const { DFLT_IMAGE_NATIVE_DIM } = require('../client/views/global/globalCssVariables.module.scss'); // prettier-ignore export interface ImageUploadProps { diff --git a/src/mobile/MobileInterface.tsx b/src/mobile/MobileInterface.tsx index d8ba89fdb..4f37c45a8 100644 --- a/src/mobile/MobileInterface.tsx +++ b/src/mobile/MobileInterface.tsx @@ -265,7 +265,6 @@ export class MobileInterface extends React.Component { this._menuListView = this._homeDoc._type_collection === 'stacking' ? true : false; Doc.ActiveTool = InkTool.None; // ink should intially be set to none Doc.UserDoc().activeMobile = this._homeDoc; // active mobile set to home - AudioBox.Enabled = true; // remove double click to avoid mobile zoom in document.removeEventListener('dblclick', this.onReactDoubleClick); diff --git a/src/pen-gestures/GestureUtils.ts b/src/pen-gestures/GestureUtils.ts index 28323d62f..bf5475042 100644 --- a/src/pen-gestures/GestureUtils.ts +++ b/src/pen-gestures/GestureUtils.ts @@ -2,14 +2,15 @@ import { Rect } from 'react-measure'; import { Gestures, PointData } from './GestureTypes'; import { NDollarRecognizer } from './ndollar'; +// eslint-disable-next-line @typescript-eslint/no-namespace export namespace GestureUtils { export class GestureEvent { readonly gesture: Gestures; readonly points: PointData[]; readonly bounds: Rect; - readonly text?: any; + readonly text?: string; - constructor(gesture: Gestures, points: PointData[], bounds: Rect, text?: any) { + constructor(gesture: Gestures, points: PointData[], bounds: Rect, text?: string) { this.gesture = gesture; this.points = points; this.bounds = bounds; diff --git a/src/server/ApiManagers/GooglePhotosManager.ts b/src/server/ApiManagers/GooglePhotosManager.ts index 5feb25fd4..0970dee81 100644 --- a/src/server/ApiManagers/GooglePhotosManager.ts +++ b/src/server/ApiManagers/GooglePhotosManager.ts @@ -139,13 +139,13 @@ // const completed: Opt[] = []; // for (const { baseUrl } of mediaItems) { // // start by getting the content size of the remote image -// const results = await DashUploadUtils.InspectImage(baseUrl); -// if (results instanceof Error) { +// const result = await DashUploadUtils.InspectImage(baseUrl); +// if (result instanceof Error) { // // if something went wrong here, we can't hope to upload it, so just move on to the next // failed++; // continue; // } -// const { contentSize, ...attributes } = results; +// const { contentSize, ...attributes } = result; // // check to see if we have uploaded a Google user content image *specifically via this route* already // // that has this exact content size // const found: Opt = await Database.Auxiliary.QueryUploadHistory(contentSize); diff --git a/src/server/ApiManagers/UploadManager.ts b/src/server/ApiManagers/UploadManager.ts index 4cb3d8baf..b2624f654 100644 --- a/src/server/ApiManagers/UploadManager.ts +++ b/src/server/ApiManagers/UploadManager.ts @@ -144,7 +144,7 @@ export default class UploadManager extends ApiManager { ids[id] = uuid.v4(); return ids[id]; }; - const mapFn = (docIn: any) => { + const mapFn = (docIn: { id: string; fields: any[] }) => { const doc = docIn; if (doc.id) { doc.id = getId(doc.id); @@ -170,10 +170,10 @@ export default class UploadManager extends ApiManager { mapFn(field); } else if (typeof field === 'string') { const re = /("(?:dataD|d)ocumentId"\s*:\s*")([\w-]*)"/g; - doc.fields[key] = (field as any).replace(re, (match: any, p1: string, p2: string) => `${p1}${getId(p2)}"`); + doc.fields[key] = field.replace(re, (match: string, p1: string, p2: string) => `${p1}${getId(p2)}"`); } else if (field.__type === 'RichTextField') { const re = /("href"\s*:\s*")(.*?)"/g; - field.Data = field.Data.replace(re, (match: any, p1: string, p2: string) => `${p1}${getId(p2)}"`); + field.Data = field.Data.replace(re, (match: string, p1: string, p2: string) => `${p1}${getId(p2)}"`); } } }; @@ -192,7 +192,7 @@ export default class UploadManager extends ApiManager { if (!f) continue; const path2 = f[0]; // what about the rest of the array? are we guaranteed only one value is set? const zip = new AdmZip(path2.filepath); - zip.getEntries().forEach((entry: any) => { + zip.getEntries().forEach(entry => { const entryName = entry.entryName.replace(/%%%/g, '/'); if (!entryName.startsWith('files/')) { return; @@ -245,7 +245,7 @@ export default class UploadManager extends ApiManager { } } SolrManager.update(); - res.send(JSON.stringify({ id, docids, linkids } || 'error')); + res.send(JSON.stringify({ id, docids, linkids }) || 'error'); } catch (e) { console.log(e); } @@ -282,8 +282,8 @@ export default class UploadManager extends ApiManager { const serverPath = serverPathToFile(Directory.images, ''); const regex = new RegExp(`${deleteFiles}.*`); fs.readdirSync(serverPath) - .filter((f: any) => regex.test(f)) - .map((f: any) => fs.unlinkSync(serverPath + f)); + .filter(f => regex.test(f)) + .map(f => fs.unlinkSync(serverPath + f)); } imageDataUri.outputFile(uri, serverPathToFile(Directory.images, InjectSize(filename, origSuffix))).then((savedName: string) => { const ext = path.extname(savedName).toLowerCase(); diff --git a/src/server/DashStats.ts b/src/server/DashStats.ts index 808d2c6f2..6b9fb8971 100644 --- a/src/server/DashStats.ts +++ b/src/server/DashStats.ts @@ -9,6 +9,7 @@ import { socketMap, timeMap, userOperations } from './SocketData'; * This includes time connected, number of operations, and * the rate of their operations */ +// eslint-disable-next-line @typescript-eslint/no-namespace export namespace DashStats { export const SAMPLING_INTERVAL = 1000; // in milliseconds (ms) - Time interval to update the frontend. export const RATE_INTERVAL = 10; // in seconds (s) - Used to calculate rate diff --git a/src/server/DashUploadUtils.ts b/src/server/DashUploadUtils.ts index 08cea1de5..5e58db103 100644 --- a/src/server/DashUploadUtils.ts +++ b/src/server/DashUploadUtils.ts @@ -1,6 +1,7 @@ import axios from 'axios'; +import { spawn, exec } from 'child_process'; import { green, red } from 'colors'; -import { ExifImage } from 'exif'; +import { ExifData, ExifImage } from 'exif'; import * as exifr from 'exifr'; import * as ffmpeg from 'fluent-ffmpeg'; import * as formidable from 'formidable'; @@ -18,13 +19,11 @@ import { Duplex, Stream } from 'stream'; import { Utils } from '../Utils'; import { createIfNotExists } from './ActionUtilities'; import { AzureManager } from './ApiManagers/AzureManager'; -import { ParsedPDF } from './PdfTypes'; import { AcceptableMedia, Upload } from './SharedMediaTypes'; import { Directory, clientPathToFile, filesDirectory, pathToDirectory, publicDirectory, serverPathToFile } from './SocketData'; import { resolvedServerUrl } from './server_Initialization'; -const { spawn } = require('child_process'); -const { exec } = require('child_process'); +// eslint-disable-next-line @typescript-eslint/no-var-requires const requestImageSize = require('../client/util/request-image-size'); export enum SizeSuffix { @@ -48,6 +47,7 @@ function usingAzure() { return process.env.USE_AZURE === 'true'; } +// eslint-disable-next-line @typescript-eslint/no-namespace export namespace DashUploadUtils { export interface Size { width: number; @@ -111,7 +111,7 @@ export namespace DashUploadUtils { // .outputOptions('-c copy') // .videoCodec("copy") .save(outputFilePath) - .on('error', (err: any) => { + .on('error', err => { console.log(err); reject(); }) @@ -130,8 +130,8 @@ export namespace DashUploadUtils { } function resolveExistingFile(name: string, pat: string, directory: Directory, mimetype?: string | null, duration?: number, rawText?: string): Upload.FileResponse { - const data = { size: 0, filepath: pat, name, type: mimetype ?? '', originalFilename: name, newFilename: path.basename(pat), mimetype: mimetype || null, hashAlgorithm: false as any }; - const file = { ...data, toJSON: () => ({ ...data, length: 0, filename: data.filepath.replace(/.*\//, ''), mtime: new Date(), mimetype: mimetype || null, toJson: () => undefined as any }) }; + const data = { size: 0, filepath: pat, name, type: mimetype ?? '', originalFilename: name, newFilename: path.basename(pat), mimetype: mimetype || null, hashAlgorithm: false as falsetype }; + const file = { ...data, toJSON: () => ({ ...data, length: 0, filename: data.filepath.replace(/.*\//, ''), mtime: new Date(), mimetype: mimetype || null }) }; return { source: file || null, result: { @@ -184,11 +184,10 @@ export namespace DashUploadUtils { const parseExifData = async (source: string) => { const image = await request.get(source, { encoding: null }); - const { /* data, */ error } = await new Promise<{ data: any; error: any }>(resolve => { + const { /* data, */ error } = await new Promise<{ data: ExifData; error: string | undefined }>(resolve => { // eslint-disable-next-line no-new new ExifImage({ image }, (exifError, data) => { - const reason = (exifError as any)?.code; - resolve({ data, error: reason }); + resolve({ data, error: exifError?.message }); }); }); return error ? { data: undefined, error } : { data: await exifr.parse(image), error }; @@ -252,11 +251,12 @@ export namespace DashUploadUtils { }; // Use the request library to parse out file level image information in the headers - const { headers } = await new Promise((resolve, reject) => { - request.head(resolvedUrl, (error, res) => (error ? reject(error) : resolve(res))); + const headerResult = await new Promise<{ headers: { [key: string]: string } }>((resolve, reject) => { + request.head(resolvedUrl, (error, res) => (error ? reject(error) : resolve(res as { headers: { [key: string]: string } }))); }).catch(e => { console.log('Error processing headers: ', e); }); + const { headers } = headerResult !== null && typeof headerResult === 'object' ? headerResult : { headers: {} as { [key: string]: string } }; try { // Compute the native width and height ofthe image with an npm module @@ -272,9 +272,9 @@ export namespace DashUploadUtils { filename, ...results, }; - } catch (e: any) { + } catch (e: unknown) { console.log(e); - return e; + return new Error(e ? e.toString?.() : 'unkown error'); } }; @@ -331,7 +331,7 @@ export namespace DashUploadUtils { )); // prettier-ignore return Jimp.read(imgBuffer) - .then(async (imgIn: any) => { + .then(async imgIn => { let img = imgIn; await Promise.all( sizes.filter(({ width }) => width).map(({ width, suffix }) => { img = img.resize(width, Jimp.AUTO).write(outputPath(suffix)); @@ -339,7 +339,7 @@ export namespace DashUploadUtils { } )); // prettier-ignore return writtenFiles; }) - .catch((e: any) => { + .catch(e => { console.log('ERROR' + e); return writtenFiles; }); @@ -432,15 +432,17 @@ export namespace DashUploadUtils { * 4) the content type of the image, i.e. image/(jpeg | png | ...) */ export const UploadImage = async (source: string, filename?: string, prefix: string = ''): Promise => { - const metadata = await InspectImage(source); - if (metadata instanceof Error) { - return { name: metadata.name, message: metadata.message }; + const result = await InspectImage(source); + if (result instanceof Error) { + return { name: result.name, message: result.message }; } - const outputFile = filename || metadata.filename || ''; + const outputFile = filename || result.filename || ''; - return UploadInspectedImage(metadata, outputFile, prefix); + return UploadInspectedImage(result, outputFile, prefix); }; + type md5 = 'md5'; + type falsetype = false; export function uploadYoutube(videoId: string, overwriteId: string): Promise { return new Promise>(res => { const name = videoId; @@ -448,6 +450,7 @@ export namespace DashUploadUtils { const finalPath = serverPathToFile(Directory.videos, filepath); if (existsSync(finalPath)) { uploadProgress.set(overwriteId, 'computing duration'); + // eslint-disable-next-line @typescript-eslint/no-explicit-any exec(`yt-dlp -o ${finalPath} "https://www.youtube.com/watch?v=${videoId}" --get-duration`, (error: any, stdout: any /* , stderr: any */) => { const time = Array.from(stdout.trim().split(':')).reverse(); const duration = (time.length > 2 ? Number(time[2]) * 1000 * 60 : 0) + (time.length > 1 ? Number(time[1]) * 60 : 0) + (time.length > 0 ? Number(time[0]) : 0); @@ -457,14 +460,17 @@ export namespace DashUploadUtils { uploadProgress.set(overwriteId, 'starting download'); const ytdlp = spawn(`yt-dlp`, ['-o', filepath, `https://www.youtube.com/watch?v=${videoId}`, '--max-filesize', '100M', '-f', 'mp4']); + // eslint-disable-next-line @typescript-eslint/no-explicit-any ytdlp.stdout.on('data', (data: any) => uploadProgress.set(overwriteId, data.toString())); let errors = ''; + // eslint-disable-next-line @typescript-eslint/no-explicit-any ytdlp.stderr.on('data', (data: any) => { uploadProgress.set(overwriteId, 'error:' + data.toString()); errors = data.toString(); }); + // eslint-disable-next-line @typescript-eslint/no-explicit-any ytdlp.on('exit', (code: any) => { if (code) { res({ @@ -484,8 +490,8 @@ export namespace DashUploadUtils { exec(`yt-dlp-o ${filepath} "https://www.youtube.com/watch?v=${videoId}" --get-duration`, (/* error: any, stdout: any, stderr: any */) => { // const time = Array.from(stdout.trim().split(':')).reverse(); // const duration = (time.length > 2 ? Number(time[2]) * 1000 * 60 : 0) + (time.length > 1 ? Number(time[1]) * 60 : 0) + (time.length > 0 ? Number(time[0]) : 0); - const data = { size: 0, filepath, name, mimetype: 'video', originalFilename: name, newFilename: name, hashAlgorithm: 'md5' as 'md5', type: 'video/mp4' }; - const file = { ...data, toJSON: () => ({ ...data, length: 0, filename: data.filepath.replace(/.*\//, ''), mtime: new Date(), toJson: () => undefined as any }) }; + const data = { size: 0, filepath, name, mimetype: 'video', originalFilename: name, newFilename: name, hashAlgorithm: 'md5' as md5, type: 'video/mp4' }; + const file = { ...data, toJSON: () => ({ ...data, length: 0, filename: data.filepath.replace(/.*\//, ''), mtime: new Date() }) }; MoveParsedFile(file, Directory.videos).then(output => res(output)); }); } @@ -517,15 +523,15 @@ export namespace DashUploadUtils { }); } const dataBuffer = readFileSync(file.filepath); - const result: ParsedPDF | any = await parse(dataBuffer).catch((e: any) => e); - if (!result.code) { + const result: parse.Result = await parse(dataBuffer).catch(e => e); + if (result) { await new Promise((resolve, reject) => { const writeStream = createWriteStream(serverPathToFile(Directory.text, textFilename)); writeStream.write(result?.text, error => (error ? reject(error) : resolve())); }); return MoveParsedFile(file, Directory.pdfs, undefined, result?.text, undefined, fileKey); } - return { source: file, result: { name: 'faile pdf pupload', message: `Could not upload (${file.originalFilename}).${result.message}` } }; + return { source: file, result: { name: 'faile pdf pupload', message: `Could not upload (${file.originalFilename}).${result}` } }; } async function UploadCsv(file: File) { @@ -563,7 +569,7 @@ export namespace DashUploadUtils { .videoCodec('copy') // this will copy the data instead of reencode it .save(vidFile.filepath.replace('.mkv', '.mp4')) .on('end', res) - .on('error', (e: any) => console.log(e)); + .on('error', console.log); }); vidFile.filepath = vidFile.filepath.replace('.mkv', '.mp4'); format = '.mp4'; @@ -571,8 +577,9 @@ export namespace DashUploadUtils { if (format.includes('quicktime')) { let abort = false; await new Promise(res => { - ffmpeg.ffprobe(vidFile.filepath, (err: any, metadata: any) => { - if (metadata.streams.some((stream: any) => stream.codec_name === 'hevc')) { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + ffmpeg.ffprobe(vidFile.filepath, (err: any, metadata: ffmpeg.FfprobeData) => { + if (metadata.streams.some(stream => stream.codec_name === 'hevc')) { abort = true; } res(); diff --git a/src/server/SharedMediaTypes.ts b/src/server/SharedMediaTypes.ts index 8ae13454e..680db9cd0 100644 --- a/src/server/SharedMediaTypes.ts +++ b/src/server/SharedMediaTypes.ts @@ -1,6 +1,7 @@ import { ExifData } from 'exif'; import { File } from 'formidable'; +// eslint-disable-next-line @typescript-eslint/no-namespace export namespace AcceptableMedia { export const gifs = ['.gif']; export const pngs = ['.png']; @@ -18,6 +19,7 @@ export enum AudioAnnoState { playing = 'playing', } +// eslint-disable-next-line @typescript-eslint/no-namespace export namespace Upload { export function isImageInformation(uploadResponse: Upload.FileInformation): uploadResponse is Upload.ImageInformation { return 'nativeWidth' in uploadResponse; @@ -36,7 +38,7 @@ export namespace Upload { duration?: number; } export interface EnrichedExifData { - data: ExifData & ExifData['gps']; + data: ExifData & ExifData['gps'] & { Orientation?: string }; error?: string; } export interface InspectionResults { diff --git a/src/server/index.ts b/src/server/index.ts index 3151c2975..3e0d86814 100644 --- a/src/server/index.ts +++ b/src/server/index.ts @@ -29,7 +29,6 @@ import initializeServer from './server_Initialization'; dotenv.config(); export const onWindows = process.platform === 'win32'; -// eslint-disable-next-line import/no-mutable-exports export let sessionAgent: AppliedSessionAgent; /** diff --git a/src/server/websocket.ts b/src/server/websocket.ts index cece8a1b7..821607df5 100644 --- a/src/server/websocket.ts +++ b/src/server/websocket.ts @@ -16,12 +16,11 @@ import YoutubeApi from './apis/youtube/youtubeApiSample'; import { initializeGuest } from './authentication/DashUserModel'; import { Database } from './database'; +// eslint-disable-next-line @typescript-eslint/no-namespace export namespace WebSocket { let CurUser: string | undefined; - // eslint-disable-next-line import/no-mutable-exports export let _socket: Socket; - // eslint-disable-next-line import/no-mutable-exports - export let _disconnect: Function; + export let _disconnect: () => void; export const clients: { [key: string]: Client } = {}; function processGesturePoints(socket: Socket, content: GestureContent) { diff --git a/webpack.config.js b/webpack.config.js index 58df9a57d..9c74bf24e 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -1,8 +1,7 @@ -/* eslint-disable node/no-unpublished-require */ +/* eslint-disable @typescript-eslint/no-var-requires */ const path = require('path'); const webpack = require('webpack'); const HtmlWebpackPlugin = require('html-webpack-plugin'); -// eslint-disable-next-line import/no-extraneous-dependencies // const ESLintPlugin = require('eslint-webpack-plugin'); // const ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin'); const { parsed } = require('dotenv').config(); -- cgit v1.2.3-70-g09d2 From 762ac2bf354e4cc2c4b15f42502da939f5061646 Mon Sep 17 00:00:00 2001 From: bobzel Date: Fri, 9 Aug 2024 16:48:18 -0400 Subject: a bunch more typing fixes. --- src/client/util/BranchingTrailManager.tsx | 14 +- src/client/util/reportManager/ReportManager.scss | 12 +- src/client/views/ContextMenu.scss | 37 ++--- src/client/views/ContextMenu.tsx | 32 ++-- src/client/views/ContextMenuItem.tsx | 180 ++++++--------------- src/client/views/DictationOverlay.tsx | 2 +- src/client/views/DocViewUtils.ts | 1 + src/client/views/DocumentButtonBar.tsx | 11 +- src/client/views/DocumentDecorations.tsx | 23 +-- src/client/views/EditableView.tsx | 26 +-- src/client/views/ExtractColors.ts | 2 +- src/client/views/FieldsDropdown.tsx | 8 +- src/client/views/GlobalKeyHandler.ts | 4 +- src/client/views/KeyphraseQueryView.scss | 8 - src/client/views/KeyphraseQueryView.tsx | 32 ---- src/client/views/MainViewModal.tsx | 2 - src/client/views/ObservableReactComponent.tsx | 14 +- src/client/views/PreviewCursor.tsx | 51 +++--- src/client/views/PropertiesButtons.tsx | 19 +-- .../views/PropertiesDocBacklinksSelector.tsx | 2 +- src/client/views/PropertiesDocContextSelector.tsx | 7 +- src/client/views/PropertiesSection.tsx | 4 +- src/client/views/PropertiesView.tsx | 102 ++++++------ src/client/views/SidebarAnnos.tsx | 10 +- src/client/views/StyleProvider.tsx | 11 +- src/client/views/TemplateMenu.tsx | 3 +- src/client/views/UndoStack.tsx | 2 - .../views/collections/CollectionCarouselView.tsx | 3 +- src/client/views/collections/CollectionMenu.tsx | 44 ++--- .../views/collections/CollectionTreeView.tsx | 4 +- src/client/views/collections/CollectionView.tsx | 12 +- src/client/views/global/globalScripts.ts | 32 ++-- src/client/views/linking/LinkMenu.tsx | 4 +- src/client/views/linking/LinkMenuGroup.tsx | 2 - src/client/views/linking/LinkMenuItem.tsx | 20 ++- src/client/views/nodes/DataVizBox/DataVizBox.tsx | 2 +- src/client/views/nodes/DocumentContentsView.tsx | 4 +- src/client/views/nodes/FunctionPlotBox.tsx | 20 +-- src/client/views/nodes/KeyValueBox.tsx | 3 +- src/client/views/nodes/KeyValuePair.tsx | 2 +- src/client/views/nodes/PDFBox.tsx | 6 +- .../views/nodes/formattedText/EquationView.tsx | 10 +- .../views/nodes/formattedText/FormattedTextBox.tsx | 6 +- 43 files changed, 333 insertions(+), 460 deletions(-) delete mode 100644 src/client/views/KeyphraseQueryView.scss delete mode 100644 src/client/views/KeyphraseQueryView.tsx (limited to 'src') diff --git a/src/client/util/BranchingTrailManager.tsx b/src/client/util/BranchingTrailManager.tsx index 119d103c5..65336812d 100644 --- a/src/client/util/BranchingTrailManager.tsx +++ b/src/client/util/BranchingTrailManager.tsx @@ -15,18 +15,18 @@ export class BranchingTrailManager extends React.Component { public static Instance: BranchingTrailManager; // stack of the history - @observable private slideHistoryStack: String[] = []; - @observable private containsSet: Set = new Set(); + @observable private slideHistoryStack: string[] = []; + @observable private containsSet: Set = new Set(); // docId to Doc map - @observable private docIdToDocMap: Map = new Map(); + @observable private docIdToDocMap: Map = new Map(); // prev pres to copmare with - @observable private prevPresId: String | null = null; - @action setPrevPres = action((newId: String | null) => { + @observable private prevPresId: string | null = null; + @action setPrevPres = action((newId: string | null) => { this.prevPresId = newId; }); - constructor(props: any) { + constructor(props: object) { super(props); makeObservable(this); if (!BranchingTrailManager.Instance) { @@ -48,7 +48,7 @@ export class BranchingTrailManager extends React.Component { // Doc.AddToMyOverlay(hi); }; - @action setSlideHistoryStack = action((newArr: String[]) => { + @action setSlideHistoryStack = action((newArr: string[]) => { this.slideHistoryStack = newArr; }); diff --git a/src/client/util/reportManager/ReportManager.scss b/src/client/util/reportManager/ReportManager.scss index d82d7fdeb..fd343ac8e 100644 --- a/src/client/util/reportManager/ReportManager.scss +++ b/src/client/util/reportManager/ReportManager.scss @@ -96,12 +96,12 @@ transition: all 0.2s ease; background: transparent; - &:hover { - // border-bottom-color: $text-gray; - } - &:focus { - // border-bottom-color: #4476f7; - } + // &:hover { + // // border-bottom-color: $text-gray; + // } + // &:focus { + // // border-bottom-color: #4476f7; + // } } // View issues diff --git a/src/client/views/ContextMenu.scss b/src/client/views/ContextMenu.scss index 232362c5c..4aaf2d03b 100644 --- a/src/client/views/ContextMenu.scss +++ b/src/client/views/ContextMenu.scss @@ -38,7 +38,12 @@ background: whitesmoke; } -.contextMenu-item { +.contextMenuItem-Selected { + background: lightgoldenrodyellow; + border-style: none; +} + +.contextMenuItem { // width: 11vw; //10vw height: 25px; //2vh display: flex; //comment out to allow search icon to be inline with search text @@ -59,7 +64,7 @@ text-transform: uppercase; padding-right: 30px; - .contextMenu-item-background { + .contextMenuItem-background { width: 100%; height: 100%; position: absolute; @@ -69,13 +74,7 @@ filter: opacity(0); } - &:hover { - .contextMenu-item-background { - filter: opacity(0.2) !important; - } - } - - .contextMenu-item-icon-background { + .contextMenuItem-icon { pointer-events: all; background-color: transparent; width: 35px; @@ -103,6 +102,8 @@ letter-spacing: 1px; text-transform: uppercase; padding-right: 30px; + align-items: center; + align-self: center; } .contextMenu-item:hover { @@ -115,11 +116,6 @@ cursor: pointer; } -.contextMenu-itemSelected { - background: lightgoldenrodyellow; - border-style: none; -} - .contextMenu-group { // width: 11vw; //10vw height: 30px; //2vh @@ -145,23 +141,24 @@ padding-left: 5px; } -.contextMenu-inlineMenu { - // border-top: solid 1px; //TODO:glr clean -} - .contextMenu-description { margin-left: 5px; text-align: left; display: inline; //need this? } -.search-icon { +.contextMenu-search { margin: 10px; + display: flex; + .contextMenu-searchIcon { + margin-right: 5px; + } } -.search { +.contextMenu-searchInput { margin-left: 10px; padding-left: 10px; border: solid black 1px; border-radius: 5px; + width: 100%; } diff --git a/src/client/views/ContextMenu.tsx b/src/client/views/ContextMenu.tsx index 05634f376..5edb5fc0d 100644 --- a/src/client/views/ContextMenu.tsx +++ b/src/client/views/ContextMenu.tsx @@ -8,7 +8,7 @@ import * as React from 'react'; import { DivHeight, DivWidth } from '../../ClientUtils'; import { SnappingManager } from '../util/SnappingManager'; import './ContextMenu.scss'; -import { ContextMenuItem, ContextMenuProps, OriginalMenuProps } from './ContextMenuItem'; +import { ContextMenuItem, ContextMenuProps } from './ContextMenuItem'; import { ObservableReactComponent } from './ObservableReactComponent'; @observer @@ -148,13 +148,13 @@ export class ContextMenu extends ObservableReactComponent<{ noexpand?: boolean } return wasOpen; }; - @computed get filteredItems(): (OriginalMenuProps | string[])[] { + @computed get filteredItems(): (ContextMenuProps | string[])[] { const searchString = this._searchString.toLowerCase().split(' '); const matches = (descriptions: string[]) => searchString.every(s => descriptions.some(desc => desc.toLowerCase().includes(s))); const flattenItems = (items: ContextMenuProps[], groupFunc: (groupName: string) => string[]) => { - let eles: (OriginalMenuProps | string[])[] = []; + let eles: (ContextMenuProps | string[])[] = []; - const leaves: OriginalMenuProps[] = []; + const leaves: ContextMenuProps[] = []; items.forEach(item => { const { description } = item; const path = groupFunc(description); @@ -165,7 +165,7 @@ export class ContextMenu extends ObservableReactComponent<{ noexpand?: boolean } eles = eles.concat(children); } } else if (matches(path)) { - leaves.push(item as OriginalMenuProps); + leaves.push(item as ContextMenuProps); } }); @@ -176,8 +176,8 @@ export class ContextMenu extends ObservableReactComponent<{ noexpand?: boolean } return flattenItems(this._items.slice(), name => [name]); } - @computed get flatItems(): OriginalMenuProps[] { - return this.filteredItems.filter(item => !Array.isArray(item)) as OriginalMenuProps[]; + @computed get flatItems(): ContextMenuProps[] { + return this.filteredItems.filter(item => !Array.isArray(item)) as ContextMenuProps[]; } @computed get menuItems() { @@ -228,21 +228,11 @@ export class ContextMenu extends ObservableReactComponent<{ noexpand?: boolean } color: SnappingManager.userColor, }}> {!this.itemsNeedSearch ? null : ( - - + + - + )} {this.menuItems} @@ -264,7 +254,7 @@ export class ContextMenu extends ObservableReactComponent<{ noexpand?: boolean } e.preventDefault(); } else if (e.key === 'Enter' || e.key === 'Tab') { const item = this.flatItems[this._selectedIndex]; - if (item) { + if (item.event) { item.event({ x: this.pageX, y: this.pageY }); } else { // if (this._searchString.startsWith(this._defaultPrefix)) { diff --git a/src/client/views/ContextMenuItem.tsx b/src/client/views/ContextMenuItem.tsx index 3b87ea58b..5b4eb704b 100644 --- a/src/client/views/ContextMenuItem.tsx +++ b/src/client/views/ContextMenuItem.tsx @@ -8,32 +8,27 @@ import { SnappingManager } from '../util/SnappingManager'; import { UndoManager } from '../util/UndoManager'; import { ObservableReactComponent } from './ObservableReactComponent'; -export interface OriginalMenuProps { +export interface ContextMenuProps { + icon: IconProp | JSX.Element; description: string; - event: (stuff?: unknown) => void; - undoable?: boolean; - noexpand?: boolean; - subitems?: ContextMenuProps[]; - icon: IconProp | JSX.Element; // maybe should be optional (icon?) - closeMenu?: () => void; -} - -export interface SubmenuProps { - description: string; - // eslint-disable-next-line no-use-before-define - subitems: ContextMenuProps[]; - noexpand?: boolean; addDivider?: boolean; - icon: IconProp; // maybe should be optional (icon?) closeMenu?: () => void; -} -export type ContextMenuProps = OriginalMenuProps | SubmenuProps; + subitems?: ContextMenuProps[]; + noexpand?: boolean; // whether to render the submenu items as a flyout from this item, or inline in place of this item + + undoable?: boolean; // whether to wrap the event callback in an UndoBatch or not + event?: (stuff?: unknown) => void; +} @observer export class ContextMenuItem extends ObservableReactComponent { - @observable private _items: Array = []; - @observable private overItem = false; + static readonly HOVER_TIMEOUT = 100; + _hoverTimeout?: NodeJS.Timeout; + _overPosY = 0; + _overPosX = 0; + @observable _items: ContextMenuProps[] = []; + @observable _overItem = false; constructor(props: ContextMenuProps & { selected?: boolean }) { super(props); @@ -41,132 +36,63 @@ export class ContextMenuItem extends ObservableReactComponent { - this._items.length = 0; - }); - if ((this._props as SubmenuProps)?.subitems) { - (this._props as SubmenuProps).subitems?.forEach(i => runInAction(() => this._items.push(i))); - } + runInAction(() => this._items.push(...(this._props.subitems ?? []))); } handleEvent = async (e: React.MouseEvent) => { - if ('event' in this._props) { + if (this._props.event) { this._props.closeMenu?.(); - const batch = this._props.undoable !== false ? UndoManager.StartBatch(`Click Menu item: ${this._props.description}`) : undefined; + const batch = this._props.undoable ? UndoManager.StartBatch(`Click Menu item: ${this._props.description}`) : undefined; await this._props.event({ x: e.clientX, y: e.clientY }); batch?.end(); } }; - currentTimeout?: NodeJS.Timeout | undefined; - static readonly timeout = 300; - _overPosY = 0; - _overPosX = 0; + setOverItem = (over: boolean) => { + this._hoverTimeout = setTimeout( action(() => { this._overItem = over; }), ContextMenuItem.HOVER_TIMEOUT ); // prettier-ignore + }; + onPointerEnter = (e: React.MouseEvent) => { - if (this.currentTimeout) { - clearTimeout(this.currentTimeout); - this.currentTimeout = undefined; - } - if (this.overItem) { - return; - } + this._hoverTimeout && clearTimeout(this._hoverTimeout); this._overPosY = e.clientY; this._overPosX = e.clientX; - this.currentTimeout = setTimeout( - action(() => { - this.overItem = true; - }), - ContextMenuItem.timeout - ); + !this._overItem && this.setOverItem(true); }; onPointerLeave = () => { - if (this.currentTimeout) { - clearTimeout(this.currentTimeout); - this.currentTimeout = undefined; - } - if (!this.overItem) { - return; - } - this.currentTimeout = setTimeout( - action(() => { - this.overItem = false; - }), - ContextMenuItem.timeout - ); + this._hoverTimeout && clearTimeout(this._hoverTimeout); + this._overItem && this.setOverItem(false); }; - isJSXElement(val: unknown): val is JSX.Element { - return React.isValidElement(val); - } + renderItem = (submenu: JSX.Element[]) => { + const alignItems = this._overPosY < window.innerHeight / 3 ? 'flex-start' : this._overPosY > (window.innerHeight * 2) / 3 ? 'flex-end' : 'center'; + const marginTop = this._overPosY < window.innerHeight / 3 ? '20px' : this._overPosY > (window.innerHeight * 2) / 3 ? '-20px' : ''; + const marginLeft = window.innerWidth - this._overPosX - 50 > 0 ? '90%' : '20%'; - render() { - if ('event' in this._props) { - return ( -
- {this._props.icon ? {this.isJSXElement(this._props.icon) ? this._props.icon : } : null} -
{this._props.description.replace(':', '')}
-
-
- ); - } - if ('subitems' in this._props) { - const where = !this.overItem ? '' : this._overPosY < window.innerHeight / 3 ? 'flex-start' : this._overPosY > (window.innerHeight * 2) / 3 ? 'flex-end' : 'center'; - const marginTop = !this.overItem ? '' : this._overPosY < window.innerHeight / 3 ? '20px' : this._overPosY > (window.innerHeight * 2) / 3 ? '-20px' : ''; + return ( +
+
+ + {React.isValidElement(this._props.icon) ? this._props.icon : this._props.icon ? : null} + +
{this._props.description}
+ {!submenu.length ? null : ( + !this._overItem ? + : ( +
+ {submenu} +
+ ) + )} +
+ ); // prettier-ignore + }; - // here - const submenu = !this.overItem ? null : ( -
0 ? '90%' : '20%', - marginTop, - background: SnappingManager.userBackgroundColor, - }}> - {this._items.map(prop => ( - - ))} -
- ); - if (!(this._props as SubmenuProps).noexpand) { - return ( -
- {this._items.map(prop => ( - - ))} -
- ); - } - return ( -
- {this._props.icon ? ( - - - - ) : null} -
- {this._props.description} - -
-
- {submenu} -
- ); - } - return null; + render() { + const submenu = this._items.map(prop => ); + return this.props.event || this._props.noexpand ? this.renderItem(submenu) :
{submenu}
; } } diff --git a/src/client/views/DictationOverlay.tsx b/src/client/views/DictationOverlay.tsx index b242acdba..e33049d3b 100644 --- a/src/client/views/DictationOverlay.tsx +++ b/src/client/views/DictationOverlay.tsx @@ -17,7 +17,7 @@ export class DictationOverlay extends React.Component { // eslint-disable-next-line react/no-unused-class-component-methods public hasActiveModal = false; - constructor(props: any) { + constructor(props: object) { super(props); makeObservable(this); DictationOverlay.Instance = this; diff --git a/src/client/views/DocViewUtils.ts b/src/client/views/DocViewUtils.ts index 1f5f29c7e..49a30aa08 100644 --- a/src/client/views/DocViewUtils.ts +++ b/src/client/views/DocViewUtils.ts @@ -6,6 +6,7 @@ import { Doc, SetActiveAudioLinker } from '../../fields/Doc'; import { DocUtils } from '../documents/DocUtils'; import { FieldViewProps } from './nodes/FieldView'; +// eslint-disable-next-line @typescript-eslint/no-namespace export namespace DocViewUtils { export const ActiveRecordings: { props: FieldViewProps; getAnchor: (addAsAnnotation: boolean) => Doc }[] = []; diff --git a/src/client/views/DocumentButtonBar.tsx b/src/client/views/DocumentButtonBar.tsx index 487868169..b778a4fb9 100644 --- a/src/client/views/DocumentButtonBar.tsx +++ b/src/client/views/DocumentButtonBar.tsx @@ -1,6 +1,3 @@ -/* eslint-disable jsx-a11y/control-has-associated-label */ -/* eslint-disable jsx-a11y/no-static-element-interactions */ -/* eslint-disable jsx-a11y/click-events-have-key-events */ import { IconLookup, IconProp } from '@fortawesome/fontawesome-svg-core'; import { faCalendarDays } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; @@ -20,7 +17,7 @@ import { DictationManager } from '../util/DictationManager'; import { DragManager } from '../util/DragManager'; import { dropActionType } from '../util/DropActionTypes'; import { SharingManager } from '../util/SharingManager'; -import { UndoManager, undoBatch } from '../util/UndoManager'; +import { UndoManager, undoable } from '../util/UndoManager'; import './DocumentButtonBar.scss'; import { ObservableReactComponent } from './ObservableReactComponent'; import { PinProps } from './PinFuncs'; @@ -33,12 +30,12 @@ import { OpenWhere } from './nodes/OpenWhere'; import { DashFieldView } from './nodes/formattedText/DashFieldView'; @observer -export class DocumentButtonBar extends ObservableReactComponent<{ views: () => (DocumentView | undefined)[]; stack?: any }> { +export class DocumentButtonBar extends ObservableReactComponent<{ views: () => (DocumentView | undefined)[]; stack?: unknown }> { private _dragRef = React.createRef(); // eslint-disable-next-line no-use-before-define public static Instance: DocumentButtonBar; - constructor(props: any) { + constructor(props: { views: () => (DocumentView | undefined)[]; stack?: unknown }) { super(props); makeObservable(this); DocumentButtonBar.Instance = this; @@ -83,7 +80,7 @@ export class DocumentButtonBar extends ObservableReactComponent<{ views: () => (
this._props.views().map(view => view?.toggleFollowLink(undefined, false)))}> + onClick={undoable(() => this._props.views().map(view => view?.toggleFollowLink(undefined, false)), 'follow link')}>
{followBtn( true, diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index 93c3e3338..68970223a 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -34,6 +34,7 @@ import { DocumentView } from './nodes/DocumentView'; import { ImageBox } from './nodes/ImageBox'; import { OpenWhere, OpenWhereMod } from './nodes/OpenWhere'; import { FormattedTextBox } from './nodes/formattedText/FormattedTextBox'; +import { IconProp } from '@fortawesome/fontawesome-svg-core'; interface DocumentDecorationsProps { PanelWidth: number; @@ -145,7 +146,7 @@ export class DocumentDecorations extends ObservableReactComponent { if (e.key === 'Enter') { e.stopPropagation(); - (e.target as any).blur(); + (e.target as HTMLElement).blur?.(); } }; @@ -239,7 +240,7 @@ export class DocumentDecorations extends ObservableReactComponent DragManager.StartWindowDrag?.(e, [DocumentView.SelectedDocs().lastElement()]) ?? false, emptyFunction, this.onMaximizeClick, false, false); e.stopPropagation(); }; - onMaximizeClick = (e: any): void => { + onMaximizeClick = (e: PointerEvent): void => { const selView = DocumentView.Selected()[0]; if (selView) { if (e.ctrlKey) { @@ -349,8 +350,10 @@ export class DocumentDecorations extends ObservableReactComponent // return false to keep getting events - this.setRotateCenter(seldocview, [this.rotCenter[0] + delta[0], this.rotCenter[1] + delta[1]]) as any as boolean, + (moveEv: PointerEvent, down: number[], delta: number[]) => { + this.setRotateCenter(seldocview, [this.rotCenter[0] + delta[0], this.rotCenter[1] + delta[1]]); + return false; + }, action(() => { this._isRotating = false; }), // upEvent action(() => { seldocview.Document._rotation_centerX = seldocview.Document._rotation_centerY = 0; }), true @@ -430,7 +433,7 @@ export class DocumentDecorations extends ObservableReactComponent this.resizeView(docView, refPt, scaleAspect, { dragHdl, ctrlKey:e.ctrlKey })); // prettier-ignore - await new Promise(res => { setTimeout(() => { res(this._interactionLock = undefined)})}); + await new Promise(res => { setTimeout(() => { res(this._interactionLock = undefined)})}); }); // prettier-ignore return false; @@ -681,10 +684,10 @@ export class DocumentDecorations extends ObservableReactComponent void), click: undefined | ((e: any) => void), title: string) => ( + const topBtn = (key: string, icon: IconProp, pointerDown: undefined | ((e: React.PointerEvent) => void), click: undefined | ((e: PointerEvent) => void), title: string) => ( {title}
} placement="top"> -
e.preventDefault()} onPointerDown={pointerDown ?? (e => setupMoveUpEvents(this, e, returnFalse, emptyFunction, clickEv => click!(clickEv)))}> - +
e.preventDefault()} onPointerDown={pointerDown ?? (e => setupMoveUpEvents(this, e, returnFalse, emptyFunction, clickEv => click?.(clickEv)))}> +
); diff --git a/src/client/views/EditableView.tsx b/src/client/views/EditableView.tsx index 684b948af..e02e39b8b 100644 --- a/src/client/views/EditableView.tsx +++ b/src/client/views/EditableView.tsx @@ -1,10 +1,7 @@ -/* eslint-disable jsx-a11y/no-static-element-interactions */ -/* eslint-disable jsx-a11y/click-events-have-key-events */ import { action, IReactionDisposer, makeObservable, observable, reaction, runInAction } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; import * as Autosuggest from 'react-autosuggest'; -import { ObjectField } from '../../fields/ObjectField'; import './EditableView.scss'; import { DocumentIconContainer } from './nodes/DocumentIcon'; import { FieldView, FieldViewProps } from './nodes/FieldView'; @@ -29,7 +26,7 @@ export interface EditableProps { /** * The contents to render when not editing */ - contents: any; + contents: string; fieldContents?: FieldViewProps; fontStyle?: string; fontSize?: number; @@ -41,8 +38,8 @@ export interface EditableProps { autosuggestProps?: { resetValue: () => void; value: string; - onChange: (e: React.ChangeEvent, { newValue }: { newValue: string }) => void; - autosuggestProps: Autosuggest.AutosuggestProps; + onChange: (e: React.FormEvent, { newValue }: { newValue: string }) => void; + autosuggestProps: Autosuggest.AutosuggestProps; }; oneLine?: boolean; // whether to display the editable view as a single input line or as a textarea allowCRs?: boolean; // can carriage returns be entered @@ -112,8 +109,8 @@ export class EditableView extends ObservableReactComponent { } onChange = (e: React.ChangeEvent) => { - const targVal = (e.target as any).value; - if (!(targVal.startsWith(':=') || targVal.startsWith('='))) { + const targVal = (e.target as HTMLSelectElement).value; + if (!(targVal?.startsWith(':=') || targVal?.startsWith('='))) { this._overlayDisposer?.(); this._overlayDisposer = undefined; } else if (!this._overlayDisposer) { @@ -230,13 +227,11 @@ export class EditableView extends ObservableReactComponent { className: 'editableView-input', onKeyDown: this.onKeyDown, autoFocus: true, - // @ts-ignore - onBlur: e => this.finalizeEdit(e.currentTarget.value, false, true, false), + onBlur: e => this.finalizeEdit((e.currentTarget as HTMLSelectElement).value, false, true, false), onPointerDown: this.stopPropagation, onClick: this.stopPropagation, onPointerUp: this.stopPropagation, value: this._props.autosuggestProps.value, - // @ts-ignore onChange: this._props.autosuggestProps.onChange, }} /> @@ -248,7 +243,6 @@ export class EditableView extends ObservableReactComponent { placeholder={this._props.placeholder} onBlur={e => this.finalizeEdit(e.currentTarget.value, false, true, false)} defaultValue={this._props.GetValue()} - // eslint-disable-next-line jsx-a11y/no-autofocus autoFocus onChange={this.onChange} onKeyDown={this.onKeyDown} @@ -264,7 +258,6 @@ export class EditableView extends ObservableReactComponent { placeholder={this._props.placeholder} onBlur={e => this.finalizeEdit(e.currentTarget.value, false, true, false)} defaultValue={this._props.GetValue()} - // eslint-disable-next-line jsx-a11y/no-autofocus autoFocus onChange={this.onChange} onKeyDown={this.onKeyDown} @@ -288,7 +281,7 @@ export class EditableView extends ObservableReactComponent { ); } setTimeout(() => this._props.autosuggestProps?.resetValue()); - return this._props.contents instanceof ObjectField ? null : ( + return (
{ fontStyle: this._props.fontStyle, fontSize: this._props.fontSize, }}> - { - // eslint-disable-next-line react/jsx-props-no-spreading - this._props.fieldContents ? : this.props.contents ? this._props.contents?.valueOf() : '' - } + {this._props.fieldContents ? : this._props.contents ? this._props.contents?.valueOf() : ''}
); diff --git a/src/client/views/ExtractColors.ts b/src/client/views/ExtractColors.ts index f6928c52a..eee1d3a04 100644 --- a/src/client/views/ExtractColors.ts +++ b/src/client/views/ExtractColors.ts @@ -126,7 +126,7 @@ export class ExtractColors { let hue = 0; let saturation = 0; - let lightness = intensity; + const lightness = intensity; if (area !== 0) { saturation = area / (1 - Math.abs(2 * intensity - 1)); diff --git a/src/client/views/FieldsDropdown.tsx b/src/client/views/FieldsDropdown.tsx index 0ea0ebd83..407031b40 100644 --- a/src/client/views/FieldsDropdown.tsx +++ b/src/client/views/FieldsDropdown.tsx @@ -29,7 +29,7 @@ interface fieldsDropdownProps { @observer export class FieldsDropdown extends ObservableReactComponent { @observable _newField = ''; - constructor(props: any) { + constructor(props: fieldsDropdownProps) { super(props); makeObservable(this); } @@ -101,13 +101,13 @@ export class FieldsDropdown extends ObservableReactComponent this._props.selectFunc((val as any as { value: string; label: string }).value)} + onChange={val => this._props.selectFunc((val as { value: string; label: string }).value)} onKeyDown={e => { if (e.key === 'Enter') { runInAction(() => { - this._props.selectFunc((this._newField = (e.nativeEvent.target as any)?.value)); + this._props.selectFunc((this._newField = (e.nativeEvent.target as HTMLSelectElement)?.value)); }); } e.stopPropagation(); diff --git a/src/client/views/GlobalKeyHandler.ts b/src/client/views/GlobalKeyHandler.ts index 7d01bbabb..a85a03aab 100644 --- a/src/client/views/GlobalKeyHandler.ts +++ b/src/client/views/GlobalKeyHandler.ts @@ -56,7 +56,7 @@ export class KeyManager { window.addEventListener('keydown', KeyManager.Instance.handle); window.removeEventListener('keyup', KeyManager.Instance.unhandle); window.addEventListener('keyup', KeyManager.Instance.unhandle); - window.addEventListener('paste', KeyManager.Instance.paste as any); + window.addEventListener('paste', KeyManager.Instance.paste); } public unhandle = action((/* e: KeyboardEvent */) => { @@ -330,7 +330,7 @@ export class KeyManager { } break; case 'c': - if ((document.activeElement as any)?.type !== 'text' && !AnchorMenu.Instance.Active && DocumentDecorations.Instance.Bounds.r - DocumentDecorations.Instance.Bounds.x > 2) { + if (!AnchorMenu.Instance.Active && DocumentDecorations.Instance.Bounds.r - DocumentDecorations.Instance.Bounds.x > 2) { const bds = DocumentDecorations.Instance.Bounds; const pt = DocumentView.Selected()[0] .screenToViewTransform() diff --git a/src/client/views/KeyphraseQueryView.scss b/src/client/views/KeyphraseQueryView.scss deleted file mode 100644 index ac715e5e7..000000000 --- a/src/client/views/KeyphraseQueryView.scss +++ /dev/null @@ -1,8 +0,0 @@ -.fading { - animation: fanOut 1s -} - -@keyframes fanOut { - from {opacity: 0;} - to {opacity: 1;} -} \ No newline at end of file diff --git a/src/client/views/KeyphraseQueryView.tsx b/src/client/views/KeyphraseQueryView.tsx deleted file mode 100644 index 81f004010..000000000 --- a/src/client/views/KeyphraseQueryView.tsx +++ /dev/null @@ -1,32 +0,0 @@ -/* eslint-disable jsx-a11y/label-has-associated-control */ -import { observer } from 'mobx-react'; -import * as React from 'react'; -import './KeyphraseQueryView.scss'; - -// tslint:disable-next-line: class-name -export interface KP_Props { - keyphrases: string; -} - -@observer -export class KeyphraseQueryView extends React.Component { - render() { - const keyterms = this.props.keyphrases.split(','); - return ( -
-
Select queries to send:
-
- {keyterms.map((kp: string) => ( - // return (

{"-" + kp}

); -

- -

- ))} -
-
- ); - } -} diff --git a/src/client/views/MainViewModal.tsx b/src/client/views/MainViewModal.tsx index a6dc5c62b..4a35805fb 100644 --- a/src/client/views/MainViewModal.tsx +++ b/src/client/views/MainViewModal.tsx @@ -1,5 +1,3 @@ -/* eslint-disable jsx-a11y/no-static-element-interactions */ -/* eslint-disable jsx-a11y/click-events-have-key-events */ /* eslint-disable react/require-default-props */ import { isDark } from 'browndash-components'; import { observer } from 'mobx-react'; diff --git a/src/client/views/ObservableReactComponent.tsx b/src/client/views/ObservableReactComponent.tsx index 34da82b6c..bb7a07f0e 100644 --- a/src/client/views/ObservableReactComponent.tsx +++ b/src/client/views/ObservableReactComponent.tsx @@ -8,27 +8,27 @@ import JsxParser from 'react-jsx-parser'; * This is an abstract class that serves as the base for a PDF-style or Marquee-style * menu. To use this class, look at PDFMenu.tsx or MarqueeOptionsMenu.tsx for an example. */ -export abstract class ObservableReactComponent extends React.Component { +export abstract class ObservableReactComponent extends React.Component { @observable _props: React.PropsWithChildren; - constructor(props: any) { + constructor(props: React.PropsWithChildren) { super(props); this._props = props; makeObservable(this); } componentDidUpdate(prevProps: Readonly): void { Object.keys(prevProps) - .filter(pkey => (prevProps as any)[pkey] !== (this.props as any)[pkey]) + .filter(pkey => (prevProps as {[key:string]: unknown})[pkey] !== (this.props as {[key:string]: unknown})[pkey]) .forEach(action(pkey => { - (this._props as any)[pkey] = (this.props as any)[pkey]; + (this._props as {[key:string]: unknown})[pkey] = (this.props as {[key:string]: unknown})[pkey]; })); // prettier-ignore } } class ObserverJsxParser1 extends JsxParser { - constructor(props: any) { + constructor(props: object) { super(props); - observer(this as any); + observer(this as typeof JsxParser); } } -export const ObserverJsxParser: typeof JsxParser = ObserverJsxParser1 as any; +export const ObserverJsxParser = ObserverJsxParser1 as typeof JsxParser; diff --git a/src/client/views/PreviewCursor.tsx b/src/client/views/PreviewCursor.tsx index 034ade50b..7e597879d 100644 --- a/src/client/views/PreviewCursor.tsx +++ b/src/client/views/PreviewCursor.tsx @@ -7,13 +7,14 @@ import { Docs, DocumentOptions } from '../documents/Documents'; import { DocUtils } from '../documents/DocUtils'; import { ImageUtils } from '../util/Import & Export/ImageUtils'; import { Transform } from '../util/Transform'; -import { UndoManager, undoBatch } from '../util/UndoManager'; +import { UndoManager, undoable } from '../util/UndoManager'; import { ObservableReactComponent } from './ObservableReactComponent'; import './PreviewCursor.scss'; import { FormattedTextBox } from './nodes/formattedText/FormattedTextBox'; +import { StrCast } from '../../fields/Types'; @observer -export class PreviewCursor extends ObservableReactComponent<{}> { +export class PreviewCursor extends ObservableReactComponent { // eslint-disable-next-line no-use-before-define static _instance: PreviewCursor; public static get Instance() { @@ -29,7 +30,7 @@ export class PreviewCursor extends ObservableReactComponent<{}> { @observable _clickPoint: number[] = []; @observable public Visible = false; public Doc: Opt; - constructor(props: any) { + constructor(props: object) { super(props); makeObservable(this); PreviewCursor._instance = this; @@ -46,7 +47,7 @@ export class PreviewCursor extends ObservableReactComponent<{}> { }); // tests for URL and makes web document - const re: any = /^https?:\/\//g; + const re = /^https?:\/\//g; const plain = e.clipboardData.getData('text/plain'); if (plain && newPoint) { // tests for youtube and makes video document @@ -64,17 +65,19 @@ export class PreviewCursor extends ObservableReactComponent<{}> { } else if (re.test(plain)) { const url = plain; if (!url.startsWith(window.location.href)) { - undoBatch(() => - this._addDocument?.( - Docs.Create.WebDocument(url, { - title: url, - _width: 500, - _height: 300, - data_useCors: true, - x: newPoint[0], - y: newPoint[1], - }) - ) + undoable( + () => + this._addDocument?.( + Docs.Create.WebDocument(url, { + title: url, + _width: 500, + _height: 300, + data_useCors: true, + x: newPoint[0], + y: newPoint[1], + }) + ), + 'paste web doc' )(); } else alert('cannot paste dash into itself'); } else if (plain.startsWith('__DashDocId(') || plain.startsWith('__DashCloneId(')) { @@ -94,11 +97,11 @@ export class PreviewCursor extends ObservableReactComponent<{}> { } // pasting in images else if (e.clipboardData.getData('text/html') !== '' && e.clipboardData.getData('text/html').includes(' { + if (newPoint && arr) { + undoable(() => { const doc = Docs.Create.ImageDocument(arr[1], { _width: 300, title: arr[1], @@ -107,7 +110,7 @@ export class PreviewCursor extends ObservableReactComponent<{}> { }); ImageUtils.ExtractImgInfo(doc); this._addDocument?.(doc); - })(); + }, 'paste image doc')(); } } else if (e.clipboardData.items.length && newPoint) { const batch = UndoManager.StartBatch('collection view drop'); @@ -196,8 +199,12 @@ export class PreviewCursor extends ObservableReactComponent<{}> { } render() { return !this._clickPoint || !this.Visible ? null : ( - // eslint-disable-next-line jsx-a11y/no-noninteractive-tabindex -
e?.focus()} style={{ color: lightOrDark(this.Doc?.backgroundColor ?? 'white'), transform: `translate(${this._clickPoint[0]}px, ${this._clickPoint[1]}px)` }}> +
e?.focus()} + style={{ color: lightOrDark(StrCast(this.Doc?.backgroundColor, 'white')), transform: `translate(${this._clickPoint[0]}px, ${this._clickPoint[1]}px)` }}> I
); diff --git a/src/client/views/PropertiesButtons.tsx b/src/client/views/PropertiesButtons.tsx index edf6df2b9..f346d4ba8 100644 --- a/src/client/views/PropertiesButtons.tsx +++ b/src/client/views/PropertiesButtons.tsx @@ -1,5 +1,3 @@ -/* eslint-disable jsx-a11y/no-static-element-interactions */ -/* eslint-disable jsx-a11y/click-events-have-key-events */ /* eslint-disable react/no-unused-class-component-methods */ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { Dropdown, DropdownType, IListItemProps, Toggle, ToggleType, Type } from 'browndash-components'; @@ -18,7 +16,7 @@ import { TfiBarChart } from 'react-icons/tfi'; import { Doc, Opt } from '../../fields/Doc'; import { DocData } from '../../fields/DocSymbols'; import { ScriptField } from '../../fields/ScriptField'; -import { BoolCast, ScriptCast } from '../../fields/Types'; +import { BoolCast, ScriptCast, StrCast } from '../../fields/Types'; import { ImageField } from '../../fields/URLField'; import { DocUtils, IsFollowLinkScript } from '../documents/DocUtils'; import { CollectionViewType, DocumentType } from '../documents/DocumentTypes'; @@ -32,7 +30,7 @@ import { OpenWhere } from './nodes/OpenWhere'; import { FormattedTextBox } from './nodes/formattedText/FormattedTextBox'; @observer -export class PropertiesButtons extends React.Component<{}, {}> { +export class PropertiesButtons extends React.Component { // eslint-disable-next-line no-use-before-define @observable public static Instance: PropertiesButtons; @@ -314,13 +312,6 @@ export class PropertiesButtons extends React.Component<{}, {}> { // ); // } - @undoBatch - handlePerspectiveChange = (e: any) => { - this.selectedDoc && (this.selectedDoc._type_collection = e.target.value); - DocumentView.Selected().forEach(docView => { - docView.layoutDoc._type_collection = e.target.value; - }); - }; @computed get onClickVal() { const linkButton = IsFollowLinkScript(this.selectedDoc.onClick); const followLoc = this.selectedDoc._followLinkLocation; @@ -452,7 +443,7 @@ export class PropertiesButtons extends React.Component<{}, {}> { else this.selectedDoc && DocUtils.makeCustomViewClicked(this.selectedDoc, undefined, 'onClick'); }; - propertyToggleBtn = (label: (on?: any) => string, property: string, tooltip: (on?: any) => string, icon: (on?: any) => any, onClick?: (dv: Opt, doc: Doc, property: string) => void, useUserDoc?: boolean) => { + propertyToggleBtn = (label: (on?: unknown) => string, property: string, tooltip: (on?: unknown) => string, icon: (on?: unknown) => unknown, onClick?: (dv: Opt, doc: Doc, property: string) => void, useUserDoc?: boolean) => { const targetDoc = useUserDoc ? Doc.UserDoc() : this.selectedLayoutDoc; const onPropToggle = (dv: Opt, doc: Doc, prop: string) => { (dv?.layoutDoc || doc)[prop] = !(dv?.layoutDoc || doc)[prop]; @@ -463,7 +454,7 @@ export class PropertiesButtons extends React.Component<{}, {}> { tooltip={tooltip(BoolCast(targetDoc[property]))} text={label(targetDoc?.[property])} color={SettingsManager.userColor} - icon={icon(targetDoc?.[property] as any)} + icon={icon(targetDoc?.[property]) as string} iconPlacement="left" align="flex-start" fillWidth @@ -484,7 +475,7 @@ export class PropertiesButtons extends React.Component<{}, {}> { const isImage = layoutField instanceof ImageField; const isMap = this.selectedDoc?.type === DocumentType.MAP; const isCollection = this.selectedDoc?.type === DocumentType.COL; - const isStacking = [CollectionViewType.Stacking, CollectionViewType.Masonry, CollectionViewType.NoteTaking].includes(this.selectedDoc?._type_collection as any); + const isStacking = [CollectionViewType.Stacking, CollectionViewType.Masonry, CollectionViewType.NoteTaking].includes(StrCast(this.selectedDoc?._type_collection) as CollectionViewType); const isFreeForm = this.selectedDoc?._type_collection === CollectionViewType.Freeform; const isTree = this.selectedDoc?._type_collection === CollectionViewType.Tree; const toggle = (ele: JSX.Element | null, style?: React.CSSProperties) => ( diff --git a/src/client/views/PropertiesDocBacklinksSelector.tsx b/src/client/views/PropertiesDocBacklinksSelector.tsx index edb55f341..e30d14eae 100644 --- a/src/client/views/PropertiesDocBacklinksSelector.tsx +++ b/src/client/views/PropertiesDocBacklinksSelector.tsx @@ -16,7 +16,7 @@ import { DocumentView } from './nodes/DocumentView'; type PropertiesDocBacklinksSelectorProps = { Document: Doc; - Stack?: any; + Stack?: string; hideTitle?: boolean; addDocTab(doc: Doc, location: OpenWhere): void; }; diff --git a/src/client/views/PropertiesDocContextSelector.tsx b/src/client/views/PropertiesDocContextSelector.tsx index 1fea36d16..f494ff16a 100644 --- a/src/client/views/PropertiesDocContextSelector.tsx +++ b/src/client/views/PropertiesDocContextSelector.tsx @@ -1,6 +1,3 @@ -/* eslint-disable jsx-a11y/no-static-element-interactions */ -/* eslint-disable jsx-a11y/click-events-have-key-events */ -/* eslint-disable jsx-a11y/anchor-is-valid */ import { computed, makeObservable } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; @@ -15,14 +12,14 @@ import { OpenWhere } from './nodes/OpenWhere'; type PropertiesDocContextSelectorProps = { DocView?: DocumentView; - Stack?: any; + Stack?: string; hideTitle?: boolean; addDocTab(doc: Doc, location: OpenWhere): void; }; @observer export class PropertiesDocContextSelector extends ObservableReactComponent { - constructor(props: any) { + constructor(props: PropertiesDocContextSelectorProps) { super(props); makeObservable(this); } diff --git a/src/client/views/PropertiesSection.tsx b/src/client/views/PropertiesSection.tsx index b9a587719..12a46c7a4 100644 --- a/src/client/views/PropertiesSection.tsx +++ b/src/client/views/PropertiesSection.tsx @@ -1,5 +1,3 @@ -/* eslint-disable jsx-a11y/no-static-element-interactions */ -/* eslint-disable jsx-a11y/click-events-have-key-events */ /* eslint-disable react/require-default-props */ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { action, computed } from 'mobx'; @@ -12,7 +10,7 @@ export interface PropertiesSectionProps { title: string; children?: JSX.Element | string | null; isOpen: boolean; - setIsOpen: (bool: boolean) => any; + setIsOpen: (bool: boolean) => void; onDoubleClick?: () => void; } diff --git a/src/client/views/PropertiesView.tsx b/src/client/views/PropertiesView.tsx index 024db82a4..5952d6641 100644 --- a/src/client/views/PropertiesView.tsx +++ b/src/client/views/PropertiesView.tsx @@ -1,7 +1,4 @@ -/* eslint-disable jsx-a11y/click-events-have-key-events */ -/* eslint-disable jsx-a11y/no-static-element-interactions */ -/* eslint-disable prettier/prettier */ -import { IconLookup } from '@fortawesome/fontawesome-svg-core'; +import { IconLookup, IconProp } from '@fortawesome/fontawesome-svg-core'; import { faAnchor, faArrowRight, faWindowMaximize } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { Checkbox, Tooltip } from '@mui/material'; @@ -12,6 +9,7 @@ import { observer } from 'mobx-react'; import * as React from 'react'; import { ColorResult, SketchPicker } from 'react-color'; import * as Icons from 'react-icons/bs'; // {BsCollectionFill, BsFillFileEarmarkImageFill} from "react-icons/bs" +import ResizeObserver from 'resize-observer-polyfill'; import { ClientUtils, returnEmptyDoclist, returnEmptyFilter, returnEmptyString, returnFalse, returnTrue, setupMoveUpEvents } from '../../ClientUtils'; import { emptyFunction } from '../../Utils'; import { Doc, Field, FieldResult, FieldType, HierarchyMapping, NumListCast, Opt, ReverseHierarchyMap, StrListCast } from '../../fields/Doc'; @@ -44,8 +42,6 @@ import { StyleProviderFuncType } from './nodes/FieldView'; import { OpenWhere } from './nodes/OpenWhere'; import { PresBox, PresEffect, PresEffectDirection } from './nodes/trails'; -const _global = (window /* browser */ || global) /* node */ as any; - interface PropertiesViewProps { width: number; height: number; @@ -59,7 +55,7 @@ export class PropertiesView extends ObservableReactComponent (!this.selectedLayoutDoc ? 0 : Math.min(NumCast(this.selectedLayoutDoc?._width), this._props.width - 20)); @@ -275,7 +271,7 @@ export class PropertiesView extends ObservableReactComponent this.transform; propertiesDocViewRef = (ref: HTMLDivElement) => { - const resizeObserver = new _global.ResizeObserver( + const resizeObserver = new ResizeObserver( action(() => { const cliRect = ref.getBoundingClientRect(); this.transform = new Transform(-cliRect.x, -cliRect.y, 1); @@ -357,7 +353,7 @@ export class PropertiesView extends ObservableReactComponent { + changePermissions = (e: React.ChangeEvent, user: string) => { const docs = DocumentView.Selected().length < 2 ? [this.selectedDoc] : DocumentView.Selected().map(dv => (this.layoutDocAcls ? dv.layoutDoc : dv.dataDoc)); SharingManager.Instance.shareFromPropertiesSidebar(user, e.currentTarget.value as SharingPermissions, docs, this.layoutDocAcls); }; @@ -456,7 +452,7 @@ export class PropertiesView extends ObservableReactComponent (u1 > u2 ? -1 : u1 === u2 ? 0 : 1); + sortUsers = (u1: string, u2: string) => (u1 > u2 ? -1 : u1 === u2 ? 0 : 1); /** * Sorting algorithm to sort groups. @@ -711,7 +707,7 @@ export class PropertiesView extends ObservableReactComponent {}, title: string) => ( + inputBox = (key: string, value: string | number | undefined, setter: (val: string) => void, title: string) => (
{title}
setter(e.target.value)} onKeyDown={e => e.stopPropagation()} />
-
this.upDownButtons('up', key)))}> +
this.upDownButtons('up', key)), + 'down btn' + )}>
-
this.upDownButtons('down', key)))}> +
this.upDownButtons('down', key)), + 'up btn' + )}>
); - inputBoxDuo = (key: string, value: any, setter: (val: string) => {}, title1: string, key2: string, value2: any, setter2: (val: string) => {}, title2: string) => ( + inputBoxDuo = (key: string, value: string | number | undefined, setter: (val: string) => void, title1: string, key2: string, value2: string | number | undefined, setter2: (val: string) => void, title2: string) => (
{this.inputBox(key, value, setter, title1)} {title2 === '' ? null : this.inputBox(key2, value2, setter2, title2)} @@ -841,7 +849,7 @@ export class PropertiesView extends ObservableReactComponent {}) => ( + regInput = (key: string, value: string | number | undefined, setter: (val: string) => void) => (
setter(e.target.value)} />
-
this.upDownButtons('up', key)))}> +
this.upDownButtons('up', key)), + 'up' + )}>
-
this.upDownButtons('down', key)))}> +
this.upDownButtons('down', key)), + 'down' + )}>
@@ -1002,7 +1022,7 @@ export class PropertiesView extends ObservableReactComponent { this.markHead = this.markHead ? '' : 'arrow'; }))} + onChange={undoable(action(() => { this.markHead = this.markHead ? '' : 'arrow'; }), "change arrow head")} />
@@ -1012,8 +1032,8 @@ export class PropertiesView extends ObservableReactComponent { this.markTail = this.markTail ? '' : 'arrow'; }) + onChange={undoable( + action(() => { this.markTail = this.markTail ? '' : 'arrow'; }) ,"change arrow tail" )} />
@@ -1044,7 +1064,8 @@ export class PropertiesView extends ObservableReactComponent { this._sliderBatch?.end(); }; - getNumber = (label: string, unit: string, min: number, max: number, number: number, setNumber: any, autorange?: number, autorangeMinVal?: number) => ( + + getNumber = (label: string, unit: string, min: number, max: number, number: number, setNumber: (val: number) => void, autorange?: number, autorangeMinVal?: number) => (
this.changeEffectDirection(direction)}> - {icon ? : null} + {icon ? : null}
); @@ -1368,7 +1389,7 @@ export class PropertiesView extends ObservableReactComponent { this.selectedLink && (this.selectedLink[prop] = !this.selectedLink[prop]); })) // prettier-ignore + undoable(action(() => { this.selectedLink && (this.selectedLink[prop] = !this.selectedLink[prop]); }), `toggle prop: ${prop}`) // prettier-ignore ); }; @@ -1385,17 +1406,17 @@ export class PropertiesView extends ObservableReactComponent any = val => val) => { + toggleAnchorProp = (e: React.PointerEvent, prop: string, anchor?: Doc, value: FieldType = true, ovalue: FieldType = false, cb: (val: FieldType) => void = val => val) => { anchor && setupMoveUpEvents( this, e, returnFalse, emptyFunction, - undoBatch(action(() => { + undoable(action(() => { anchor[prop] = anchor[prop] === value ? ovalue : value; - this.selectedDoc && cb(anchor[prop]); - })) // prettier-ignore + this.selectedDoc && cb(anchor[prop] as boolean); + }), `toggle anchor prop: ${prop}`) // prettier-ignore ); }; @@ -1433,7 +1454,7 @@ export class PropertiesView extends ObservableReactComponent { + setZoom = (number: string, change?: number) => { let scale = Number(number) / 100; if (change) scale += change; if (scale < 0.01) scale = 0.01; @@ -1530,7 +1551,6 @@ export class PropertiesView extends ObservableReactComponent

Play Target Audio

{ - // eslint-disable-next-line jsx-a11y/control-has-associated-label ); + const searchTitle = `${!this._searching ? 'Open' : 'Close'} Search Bar`; const curPage = NumCast(this.Document._layout_curPage) || 1; return !this._props.isContentActive() || this._pdfViewer?.isAnnotating ? null : ( @@ -473,14 +473,14 @@ export class PDFBox extends ViewBoxAnnotatableComponent() { specificContextMenu = (): void => { const cm = ContextMenu.Instance; const options = cm.findByDescription('Options...'); - const optionItems: ContextMenuProps[] = options && 'subitems' in options ? options.subitems : []; + const optionItems = options?.subitems ?? []; !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: ContextMenuProps[] = help && 'subitems' in help ? help.subitems : []; + const helpItems = help?.subitems ?? []; helpItems.push({ description: 'Copy path', event: () => this.pdfUrl && ClientUtils.CopyText(ClientUtils.prepend('') + this.pdfUrl.url.pathname), icon: 'expand-arrows-alt' }); !help && ContextMenu.Instance.addItem({ description: 'Help...', noexpand: true, subitems: helpItems, icon: 'asterisk' }); }; diff --git a/src/client/views/nodes/formattedText/EquationView.tsx b/src/client/views/nodes/formattedText/EquationView.tsx index 4d0e9efee..df1421a33 100644 --- a/src/client/views/nodes/formattedText/EquationView.tsx +++ b/src/client/views/nodes/formattedText/EquationView.tsx @@ -17,7 +17,7 @@ interface IEquationViewInternal { tbox: FormattedTextBox; width: number; height: number; - getPos: () => number; + getPos: () => number | undefined; setEditor: (editor: EquationEditor | undefined) => void; } @@ -47,7 +47,7 @@ export class EquationViewInternal extends React.Component className="equationView" onKeyDown={e => { if (e.key === 'Enter') { - this.props.tbox.EditorView!.dispatch(this.props.tbox.EditorView!.state.tr.setSelection(new TextSelection(this.props.tbox.EditorView!.state.doc.resolve(this.props.getPos() + 1)))); + this.props.tbox.EditorView!.dispatch(this.props.tbox.EditorView!.state.tr.setSelection(new TextSelection(this.props.tbox.EditorView!.state.doc.resolve((this.props.getPos() ?? 0) + 1)))); this.props.tbox.EditorView!.focus(); e.preventDefault(); } @@ -82,8 +82,8 @@ export class EquationView { tbox: FormattedTextBox; view: EditorView; _editor: EquationEditor | undefined; - getPos: () => number; - constructor(node: Node, view: EditorView, getPos: () => number, tbox: FormattedTextBox) { + getPos: () => number | undefined; + constructor(node: Node, view: EditorView, getPos: () => number | undefined, tbox: FormattedTextBox) { this.tbox = tbox; this.view = view; this.getPos = getPos; @@ -109,7 +109,7 @@ export class EquationView { this._editor?.mathField.focus(); } selectNode() { - this.view.dispatch(this.view.state.tr.setSelection(new TextSelection(this.view.state.doc.resolve(this.getPos())))); + this.view.dispatch(this.view.state.tr.setSelection(new TextSelection(this.view.state.doc.resolve(this.getPos() ?? 0)))); this.tbox._applyingChange = this.tbox.fieldKey; // setting focus will make prosemirror lose focus, which will cause it to change its selection to a text selection, which causes this view to get rebuilt but it's no longer node selected, so the equationview won't have focus setTimeout(() => { this._editor?.mathField.focus(); diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx index c8b25e184..478039ffa 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx +++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx @@ -875,7 +875,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent { @@ -959,7 +959,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent RTFMarkup.Instance.setOpen(true), icon: }); !help && cm.addItem({ description: 'Help...', subitems: helpItems, icon: 'eye' }); }; -- cgit v1.2.3-70-g09d2 From b84bdc5a629dfa6310b24dd5eedee2843558b73a Mon Sep 17 00:00:00 2001 From: bobzel Date: Mon, 12 Aug 2024 21:38:22 -0400 Subject: more any -> type fixes --- deploy/mobile/image.html | 16 - deploy/mobile/ink.html | 13 - src/.DS_Store | Bin 10244 -> 10244 bytes src/ClientUtils.ts | 4 - src/ServerUtils.ts | 1 + src/client/util/Scripting.ts | 2 +- src/client/util/type_decls.txt | 224 ++++++ src/client/views/EditableView.tsx | 4 +- src/client/views/GestureOverlay.tsx | 7 +- src/client/views/LightboxView.tsx | 12 +- src/client/views/MainView.tsx | 12 +- src/client/views/OverlayView.tsx | 8 +- src/client/views/PropertiesView.tsx | 8 +- src/client/views/TemplateMenu.tsx | 4 +- src/client/views/collections/CollectionMenu.tsx | 4 +- .../collections/CollectionStackedTimeline.tsx | 4 +- .../views/collections/CollectionStackingView.tsx | 5 +- .../CollectionStackingViewFieldColumn.tsx | 11 +- .../views/collections/CollectionTreeView.tsx | 7 +- src/client/views/collections/TabDocView.tsx | 14 +- src/client/views/collections/TreeView.tsx | 4 +- .../CollectionMulticolumnView.tsx | 8 +- .../CollectionMultirowView.tsx | 6 +- .../collectionMulticolumn/MulticolumnResizer.tsx | 2 +- .../collectionMulticolumn/MultirowResizer.tsx | 2 +- .../collectionSchema/CollectionSchemaView.tsx | 57 +- .../collectionSchema/SchemaColumnHeader.tsx | 4 +- .../collections/collectionSchema/SchemaRowBox.tsx | 4 +- .../collectionSchema/SchemaTableCell.tsx | 32 +- src/client/views/linking/LinkPopup.tsx | 4 +- src/client/views/newlightbox/NewLightboxView.tsx | 14 +- .../RecommendationList/RecommendationList.tsx | 7 +- src/client/views/nodes/KeyValuePair.tsx | 4 +- src/client/views/nodes/LabelBox.tsx | 5 +- src/client/views/nodes/LinkDocPreview.tsx | 7 +- .../views/nodes/MapboxMapBox/MapboxContainer.tsx | 13 +- src/client/views/nodes/trails/PresElementBox.tsx | 18 +- src/client/views/topbar/TopBar.tsx | 8 +- src/fields/Doc.ts | 4 + src/mobile/ImageUpload.scss | 139 ---- src/mobile/ImageUpload.tsx | 170 ---- src/mobile/InkControls.tsx | 0 src/mobile/MobileInkOverlay.scss | 39 - src/mobile/MobileInkOverlay.tsx | 183 ----- src/mobile/MobileInterface.scss | 445 ----------- src/mobile/MobileInterface.tsx | 871 --------------------- src/mobile/MobileMain.tsx | 26 - src/mobile/MobileMenu.scss | 271 ------- webpack.config.js | 6 +- 49 files changed, 382 insertions(+), 2331 deletions(-) delete mode 100644 deploy/mobile/image.html delete mode 100644 deploy/mobile/ink.html create mode 100644 src/client/util/type_decls.txt delete mode 100644 src/mobile/ImageUpload.scss delete mode 100644 src/mobile/ImageUpload.tsx delete mode 100644 src/mobile/InkControls.tsx delete mode 100644 src/mobile/MobileInkOverlay.scss delete mode 100644 src/mobile/MobileInkOverlay.tsx delete mode 100644 src/mobile/MobileInterface.scss delete mode 100644 src/mobile/MobileInterface.tsx delete mode 100644 src/mobile/MobileMain.tsx delete mode 100644 src/mobile/MobileMenu.scss (limited to 'src') diff --git a/deploy/mobile/image.html b/deploy/mobile/image.html deleted file mode 100644 index cca6f763b..000000000 --- a/deploy/mobile/image.html +++ /dev/null @@ -1,16 +0,0 @@ - - - - Dash Mobile - - - - - - -
- - - - \ No newline at end of file diff --git a/deploy/mobile/ink.html b/deploy/mobile/ink.html deleted file mode 100644 index 938d85794..000000000 --- a/deploy/mobile/ink.html +++ /dev/null @@ -1,13 +0,0 @@ - - - - Test view - - - - -
- - - - \ No newline at end of file diff --git a/src/.DS_Store b/src/.DS_Store index 75cff7b55..7a0b53ce0 100644 Binary files a/src/.DS_Store and b/src/.DS_Store differ diff --git a/src/ClientUtils.ts b/src/ClientUtils.ts index f9e282993..fc048b155 100644 --- a/src/ClientUtils.ts +++ b/src/ClientUtils.ts @@ -82,10 +82,6 @@ export function returnEmptyFilter() { return [] as string[]; } -export function returnEmptyDoclist() { - return [] as any[]; -} - // eslint-disable-next-line @typescript-eslint/no-namespace export namespace ClientUtils { export const CLICK_TIME = 300; diff --git a/src/ServerUtils.ts b/src/ServerUtils.ts index ade4ca35d..7e821cda2 100644 --- a/src/ServerUtils.ts +++ b/src/ServerUtils.ts @@ -2,6 +2,7 @@ import { Socket } from 'socket.io'; import { Message } from './server/Message'; import { Utils } from './Utils'; +// eslint-disable-next-line @typescript-eslint/no-namespace export namespace ServerUtils { export function Emit(socket: Socket, message: Message, args: T) { Utils.log('Emit', message.Name, args, false); diff --git a/src/client/util/Scripting.ts b/src/client/util/Scripting.ts index 133f8f2ce..b9e0943b6 100644 --- a/src/client/util/Scripting.ts +++ b/src/client/util/Scripting.ts @@ -1,7 +1,7 @@ // export const ts = (window as any).ts; // import * as typescriptlib from '!!raw-loader!../../../node_modules/typescript/lib/lib.d.ts' // import * as typescriptes5 from '!!raw-loader!../../../node_modules/typescript/lib/lib.es5.d.ts' -import * as typescriptlib from '!!raw-loader!./type_decls.d'; +import * as typescriptlib from './type_decls.d'; import * as ts from 'typescript'; import { Doc, FieldType } from '../../fields/Doc'; import { RefField } from '../../fields/RefField'; diff --git a/src/client/util/type_decls.txt b/src/client/util/type_decls.txt new file mode 100644 index 000000000..1a93bbe59 --- /dev/null +++ b/src/client/util/type_decls.txt @@ -0,0 +1,224 @@ +//@ts-ignore +declare type PropertyKey = string | number | symbol; +interface Array { + length: number; + toString(): string; + toLocaleString(): string; + pop(): T | undefined; + push(...items: T[]): number; + concat(...items: ConcatArray[]): T[]; + concat(...items: (T | ConcatArray)[]): T[]; + join(separator?: string): string; + reverse(): T[]; + shift(): T | undefined; + slice(start?: number, end?: number): T[]; + sort(compareFn?: (a: T, b: T) => number): this; + splice(start: number, deleteCount?: number): T[]; + splice(start: number, deleteCount: number, ...items: T[]): T[]; + unshift(...items: T[]): number; + indexOf(searchElement: T, fromIndex?: number): number; + lastIndexOf(searchElement: T, fromIndex?: number): number; + every(callbackfn: (value: T, index: number, array: T[]) => boolean, thisArg?: any): boolean; + some(callbackfn: (value: T, index: number, array: T[]) => boolean, thisArg?: any): boolean; + forEach(callbackfn: (value: T, index: number, array: T[]) => void, thisArg?: any): void; + map(callbackfn: (value: T, index: number, array: T[]) => U, thisArg?: any): U[]; + filter(callbackfn: (value: T, index: number, array: T[]) => value is S, thisArg?: any): S[]; + filter(callbackfn: (value: T, index: number, array: T[]) => any, thisArg?: any): T[]; + reduce(callbackfn: (previousValue: T, currentValue: T, currentIndex: number, array: T[]) => T): T; + reduce(callbackfn: (previousValue: T, currentValue: T, currentIndex: number, array: T[]) => T, initialValue: T): T; + reduce(callbackfn: (previousValue: U, currentValue: T, currentIndex: number, array: T[]) => U, initialValue: U): U; + reduceRight(callbackfn: (previousValue: T, currentValue: T, currentIndex: number, array: T[]) => T): T; + reduceRight(callbackfn: (previousValue: T, currentValue: T, currentIndex: number, array: T[]) => T, initialValue: T): T; + reduceRight(callbackfn: (previousValue: U, currentValue: T, currentIndex: number, array: T[]) => U, initialValue: U): U; + + [n: number]: T; +} + +interface Function { + apply(this: Function, thisArg: any, argArray?: any): any; + call(this: Function, thisArg: any, ...argArray: any[]): any; + bind(this: Function, thisArg: any, ...argArray: any[]): any; + toString(): string; + + prototype: any; + readonly length: number; + + // Non-standard extensions + arguments: any; + caller: Function; +} +interface Boolean { + valueOf(): boolean; +} +interface Number { + toString(radix?: number): string; + toFixed(fractionDigits?: number): string; + toExponential(fractionDigits?: number): string; + toPrecision(precision?: number): string; + valueOf(): number; +} +interface IArguments { + [index: number]: any; + length: number; + callee: Function; +} +interface RegExp { + readonly flags: string; + readonly sticky: boolean; + readonly unicode: boolean; +} +interface Date { + now() : string; +} +interface String { + codePointAt(pos: number): number | undefined; + includes(searchString: string, position?: number): boolean; + endsWith(searchString: string, endPosition?: number): boolean; + normalize(form: "NFC" | "NFD" | "NFKC" | "NFKD"): string; + normalize(form?: string): string; + repeat(count: number): string; + replace(a:any, b:any):string; // bcz: fix this + startsWith(searchString: string, position?: number): boolean; + anchor(name: string): string; + big(): string; + blink(): string; + bold(): string; + fixed(): string; + fontcolor(color: string): string; + fontsize(size: number): string; + fontsize(size: string): string; + italics(): string; + link(url: string): string; + small(): string; + strike(): string; + sub(): string; + sup(): string; +} +interface Object { + constructor: Function; + toString(): string; + toLocaleString(): string; + valueOf(): Object; + hasOwnProperty(v: PropertyKey): boolean; + isPrototypeOf(v: Object): boolean; + propertyIsEnumerable(v: PropertyKey): boolean; +} +interface ConcatArray { + readonly length: number; + readonly [n: number]: T; + join(separator?: string): string; + slice(start?: number, end?: number): T[]; +} +interface URL { + hash: string; + host: string; + hostname: string; + href: string; + readonly origin: string; + password: string; + pathname: string; + port: string; + protocol: string; + search: string; + username: string; + toJSON(): string; +} +interface PromiseLike { + then(onfulfilled?: ((value: T) => TResult1 | PromiseLike) | undefined | null, onrejected?: ((reason: any) => TResult2 | PromiseLike) | undefined | null): PromiseLike; +} +interface Promise { + then(onfulfilled?: ((value: T) => TResult1 | PromiseLike) | undefined | null, onrejected?: ((reason: any) => TResult2 | PromiseLike) | undefined | null): Promise; + catch(onrejected?: ((reason: any) => TResult | PromiseLike) | undefined | null): Promise; +} + +declare const Update: unique symbol; +declare const Self: unique symbol; +declare const SelfProxy: unique symbol; +declare const DataSym: unique symbol; +declare const HandleUpdate: unique symbol; +declare const Id: unique symbol; +declare const OnUpdate: unique symbol; +declare const Parent: unique symbol; +declare const Copy: unique symbol; +declare const ToScriptString: unique symbol; + +declare abstract class RefField { + readonly [Id]: FieldId; + + constructor(); +} + +declare type FieldId = string; + +declare abstract class ObjectField { + abstract [Copy](): ObjectField; +} + +declare abstract class URLField extends ObjectField { + readonly url: URL; + + constructor(url: string); + constructor(url: URL); +} + +declare class RichTextField extends URLField { + [Copy](): ObjectField; + constructor(data:string, text: string); +} +declare class AudioField extends URLField { [Copy](): ObjectField; } +declare class VideoField extends URLField { [Copy](): ObjectField; } +declare class ImageField extends URLField { [Copy](): ObjectField; } +declare class WebField extends URLField { [Copy](): ObjectField; } +declare class PdfField extends URLField { [Copy](): ObjectField; } + +declare const ComputedField: any; +declare const CompileScript: any; + +// @ts-ignore +declare type Extract = T extends U ? T : never; +declare type Field = number | string | boolean | ObjectField | RefField; +declare type FieldWaiting = T extends undefined ? never : Promise; +declare type FieldResult = Opt | FieldWaiting>; + +declare type Opt = T | undefined; +declare class Doc extends RefField { + constructor(); + + [key: string]: FieldResult; + // [ToScriptString](): string; +} + +declare class List extends ObjectField { + constructor(fields?: T[]); + [index: number]: T | (T extends RefField ? Promise : never); + [Copy](): ObjectField; +} + +declare class InkField extends ObjectField { + constructor(data:Array<{X:number, Y:number}>); + [Copy](): ObjectField; +} + +// @ts-ignore +declare const console: any; + +interface DocumentOptions { } + +declare const Docs: { + ImageDocument(url: string, options?: DocumentOptions): Doc; + VideoDocument(url: string, options?: DocumentOptions): Doc; + TextDocument(options?: DocumentOptions): Doc; + PdfDocument(url: string, options?: DocumentOptions): Doc; + WebDocument(url: string, options?: DocumentOptions): Doc; + HtmlDocument(html: string, options?: DocumentOptions): Doc; + MapDocument(url: string, options?: DocumentOptions): Doc; + KVPDocument(document: Doc, options?: DocumentOptions): Doc; + FreeformDocument(documents: Doc[], options?: DocumentOptions): Doc; + SchemaDocument(columns: string[], documents: Doc[], options?: DocumentOptions): Doc; + TreeDocument(documents: Doc[], options?: DocumentOptions): Doc; + StackingDocument(documents: Doc[], options?: DocumentOptions): Doc; +}; + +declare function idToDoc(id:string):any; +declare function assignDoc(doc:Doc, field:any, id:any):string; +declare function d(...args:any[]):any; diff --git a/src/client/views/EditableView.tsx b/src/client/views/EditableView.tsx index e02e39b8b..23da5a666 100644 --- a/src/client/views/EditableView.tsx +++ b/src/client/views/EditableView.tsx @@ -26,7 +26,7 @@ export interface EditableProps { /** * The contents to render when not editing */ - contents: string; + contents: JSX.Element | string; fieldContents?: FieldViewProps; fontStyle?: string; fontSize?: number; @@ -301,7 +301,7 @@ export class EditableView extends ObservableReactComponent { fontStyle: this._props.fontStyle, fontSize: this._props.fontSize, }}> - {this._props.fieldContents ? : this._props.contents ? this._props.contents?.valueOf() : ''} + {this._props.fieldContents ? : (this._props.contents ?? '')}
); diff --git a/src/client/views/GestureOverlay.tsx b/src/client/views/GestureOverlay.tsx index 804c41091..bcd4d1ee5 100644 --- a/src/client/views/GestureOverlay.tsx +++ b/src/client/views/GestureOverlay.tsx @@ -2,9 +2,9 @@ import * as fitCurve from 'fit-curve'; import { action, computed, makeObservable, observable, runInAction } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; -import { returnEmptyDoclist, returnEmptyFilter, returnEmptyString, returnFalse, setupMoveUpEvents } from '../../ClientUtils'; +import { returnEmptyFilter, returnEmptyString, returnFalse, setupMoveUpEvents } from '../../ClientUtils'; import { emptyFunction } from '../../Utils'; -import { Doc, Opt } from '../../fields/Doc'; +import { Doc, Opt, returnEmptyDoclist } from '../../fields/Doc'; import { InkData, InkField, InkTool } from '../../fields/InkField'; import { NumCast } from '../../fields/Types'; import { @@ -30,6 +30,7 @@ import { ScriptingGlobals } from '../util/ScriptingGlobals'; import { Transform } from '../util/Transform'; import './GestureOverlay.scss'; import { ObservableReactComponent } from './ObservableReactComponent'; +import { returnEmptyDocViewList } from './StyleProvider'; import { ActiveFillColor, DocumentView } from './nodes/DocumentView'; export enum ToolglassTools { @@ -466,7 +467,7 @@ export class GestureOverlay extends ObservableReactComponent { ScreenToLocalTransform={this.lightboxScreenToLocal} renderDepth={0} suppressSetHeight={!!this._doc._layout_fitWidth} - containerViewPath={returnEmptyDoclist} + containerViewPath={returnEmptyDocViewList} childFilters={returnEmptyFilter} childFiltersByRanges={returnEmptyFilter} searchFilterDocs={returnEmptyDoclist} diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index ac30c5a14..62ad0a3fb 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -8,9 +8,9 @@ import { observer } from 'mobx-react'; import * as React from 'react'; import ResizeObserver from 'resize-observer-polyfill'; import '../../../node_modules/browndash-components/dist/styles/global.min.css'; -import { ClientUtils, lightOrDark, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnTrue, returnZero, setupMoveUpEvents } from '../../ClientUtils'; +import { ClientUtils, lightOrDark, returnEmptyFilter, returnFalse, returnTrue, returnZero, setupMoveUpEvents } from '../../ClientUtils'; import { emptyFunction } from '../../Utils'; -import { Doc, DocListCast, GetDocFromUrl, Opt } from '../../fields/Doc'; +import { Doc, DocListCast, GetDocFromUrl, Opt, returnEmptyDoclist } from '../../fields/Doc'; import { DocData } from '../../fields/DocSymbols'; import { Id } from '../../fields/FieldSymbols'; import { DocCast, StrCast, toList } from '../../fields/Types'; @@ -627,7 +627,7 @@ export class MainView extends ObservableReactComponent { Document={this.headerBarDoc} addDocTab={DocumentViewInternal.addDocTabFunc} pinToPres={emptyFunction} - containerViewPath={returnEmptyDoclist} + containerViewPath={returnEmptyDocViewList} styleProvider={DefaultStyleProvider} addDocument={this.addHeaderDoc} removeDocument={this.removeHeaderDoc} @@ -662,7 +662,7 @@ export class MainView extends ObservableReactComponent { addDocument={undefined} addDocTab={DocumentViewInternal.addDocTabFunc} pinToPres={emptyFunction} - containerViewPath={returnEmptyDoclist} + containerViewPath={returnEmptyDocViewList} styleProvider={this._hideUI ? DefaultStyleProvider : undefined} isContentActive={returnTrue} removeDocument={undefined} @@ -766,7 +766,7 @@ export class MainView extends ObservableReactComponent { addDocument={undefined} addDocTab={DocumentViewInternal.addDocTabFunc} pinToPres={DocumentView.PinDoc} - containerViewPath={returnEmptyDoclist} + containerViewPath={returnEmptyDocViewList} styleProvider={this._sidebarContent.proto === Doc.MyDashboards || this._sidebarContent.proto === Doc.MyFilesystem || this._sidebarContent.proto === Doc.MyTrails ? DashboardStyleProvider : DefaultStyleProvider} removeDocument={returnFalse} ScreenToLocalTransform={this.mainContainerXf} @@ -799,7 +799,7 @@ export class MainView extends ObservableReactComponent { PanelWidth={this.leftMenuWidth} PanelHeight={this.leftMenuHeight} renderDepth={0} - containerViewPath={returnEmptyDoclist} + containerViewPath={returnEmptyDocViewList} focus={emptyFunction} styleProvider={DefaultStyleProvider} isContentActive={returnTrue} diff --git a/src/client/views/OverlayView.tsx b/src/client/views/OverlayView.tsx index 7bf10467e..5e9677b45 100644 --- a/src/client/views/OverlayView.tsx +++ b/src/client/views/OverlayView.tsx @@ -4,9 +4,9 @@ import { computedFn } from 'mobx-utils'; import * as React from 'react'; import ReactLoading from 'react-loading'; import ResizeObserver from 'resize-observer-polyfill'; -import { returnEmptyDoclist, returnEmptyFilter, returnTrue, setupMoveUpEvents } from '../../ClientUtils'; +import { returnEmptyFilter, returnTrue, setupMoveUpEvents } from '../../ClientUtils'; import { Utils, emptyFunction } from '../../Utils'; -import { Doc } from '../../fields/Doc'; +import { Doc, returnEmptyDoclist } from '../../fields/Doc'; import { Height, Width } from '../../fields/DocSymbols'; import { Id } from '../../fields/FieldSymbols'; import { NumCast, toList } from '../../fields/Types'; @@ -16,7 +16,7 @@ import { dropActionType } from '../util/DropActionTypes'; import { Transform } from '../util/Transform'; import { ObservableReactComponent } from './ObservableReactComponent'; import './OverlayView.scss'; -import { DefaultStyleProvider } from './StyleProvider'; +import { DefaultStyleProvider, returnEmptyDocViewList } from './StyleProvider'; import { DocumentView, DocumentViewInternal } from './nodes/DocumentView'; export type OverlayDisposer = () => void; @@ -226,7 +226,7 @@ export class OverlayView extends ObservableReactComponent { whenChildContentsActiveChanged={emptyFunction} focus={emptyFunction} styleProvider={DefaultStyleProvider} - containerViewPath={returnEmptyDoclist} + containerViewPath={returnEmptyDocViewList} addDocTab={DocumentViewInternal.addDocTabFunc} pinToPres={emptyFunction} childFilters={returnEmptyFilter} diff --git a/src/client/views/PropertiesView.tsx b/src/client/views/PropertiesView.tsx index 5952d6641..daa8e1720 100644 --- a/src/client/views/PropertiesView.tsx +++ b/src/client/views/PropertiesView.tsx @@ -10,9 +10,9 @@ import * as React from 'react'; import { ColorResult, SketchPicker } from 'react-color'; import * as Icons from 'react-icons/bs'; // {BsCollectionFill, BsFillFileEarmarkImageFill} from "react-icons/bs" import ResizeObserver from 'resize-observer-polyfill'; -import { ClientUtils, returnEmptyDoclist, returnEmptyFilter, returnEmptyString, returnFalse, returnTrue, setupMoveUpEvents } from '../../ClientUtils'; +import { ClientUtils, returnEmptyFilter, returnEmptyString, returnFalse, returnTrue, setupMoveUpEvents } from '../../ClientUtils'; import { emptyFunction } from '../../Utils'; -import { Doc, Field, FieldResult, FieldType, HierarchyMapping, NumListCast, Opt, ReverseHierarchyMap, StrListCast } from '../../fields/Doc'; +import { Doc, Field, FieldResult, FieldType, HierarchyMapping, NumListCast, Opt, ReverseHierarchyMap, StrListCast, returnEmptyDoclist } from '../../fields/Doc'; import { AclAdmin, DocAcl, DocData } from '../../fields/DocSymbols'; import { Id } from '../../fields/FieldSymbols'; import { InkField } from '../../fields/InkField'; @@ -36,7 +36,7 @@ import { PropertiesDocBacklinksSelector } from './PropertiesDocBacklinksSelector import { PropertiesDocContextSelector } from './PropertiesDocContextSelector'; import { PropertiesSection } from './PropertiesSection'; import './PropertiesView.scss'; -import { DefaultStyleProvider, SetFilterOpener as SetPropertiesFilterOpener } from './StyleProvider'; +import { DefaultStyleProvider, SetFilterOpener as SetPropertiesFilterOpener, returnEmptyDocViewList } from './StyleProvider'; import { DocumentView } from './nodes/DocumentView'; import { StyleProviderFuncType } from './nodes/FieldView'; import { OpenWhere } from './nodes/OpenWhere'; @@ -322,7 +322,7 @@ export class PropertiesView extends ObservableReactComponent boolean; createDropTarget: (ele: HTMLDivElement) => void; screenToLocalTransform: () => Transform; - refList: any[]; + refList: HTMLElement[]; } @observer @@ -64,7 +61,7 @@ export class CollectionStackingViewFieldColumn extends ObservableReactComponent< @observable _heading = ''; @observable _color = ''; - constructor(props: any) { + constructor(props: CSVFieldColumnProps) { super(props); makeObservable(this); this._heading = this._props.headingObject ? this._props.headingObject.heading : this._props.heading; @@ -118,7 +115,7 @@ export class CollectionStackingViewFieldColumn extends ObservableReactComponent< this._props.pivotField && drop.docs?.forEach(d => Doc.SetInPlace(d, this._props.pivotField, drop.val, false)); return true; }); - getValue = (value: string): any => { + getValue = (value: string) => { const parsed = parseInt(value); if (!isNaN(parsed)) return parsed; if (value.toLowerCase().indexOf('true') > -1) return true; @@ -212,7 +209,7 @@ export class CollectionStackingViewFieldColumn extends ObservableReactComponent<
{colors.map(col => { const palette = PastelSchemaPalette.get(col); - return
this.changeColumnColor(palette!)} />; + return
this.changeColumnColor(palette!)} />; })}
diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index 0557a9102..a60cd98ac 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -2,8 +2,8 @@ import { action, computed, IReactionDisposer, makeObservable, observable, reacti import { observer } from 'mobx-react'; import * as React from 'react'; import ResizeObserver from 'resize-observer-polyfill'; -import { DivHeight, returnAll, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnNone, returnOne, returnTrue, returnZero } from '../../../ClientUtils'; -import { Doc, DocListCast, Opt, StrListCast } from '../../../fields/Doc'; +import { DivHeight, returnAll, returnEmptyFilter, returnFalse, returnNone, returnOne, returnTrue, returnZero } from '../../../ClientUtils'; +import { Doc, DocListCast, Opt, returnEmptyDoclist, StrListCast } from '../../../fields/Doc'; import { DocData } from '../../../fields/DocSymbols'; import { Id } from '../../../fields/FieldSymbols'; import { listSpec } from '../../../fields/Schema'; @@ -25,6 +25,7 @@ import { EditableView } from '../EditableView'; import { DocumentView } from '../nodes/DocumentView'; import { FormattedTextBox } from '../nodes/formattedText/FormattedTextBox'; import { StyleProp } from '../StyleProp'; +import { returnEmptyDocViewList } from '../StyleProvider'; import { CollectionFreeFormView } from './collectionFreeForm'; import { CollectionSubView, SubCollectionViewProps } from './CollectionSubView'; import './CollectionTreeView.scss'; @@ -369,7 +370,7 @@ export class CollectionTreeView extends CollectionSubView { PanelWidth={this.PanelWidth} PanelHeight={this.PanelHeight} styleProvider={DefaultStyleProvider} - childFilters={CollectionDockingView.Instance?.childDocFilters ?? returnEmptyDoclist} - childFiltersByRanges={CollectionDockingView.Instance?.childDocRangeFilters ?? returnEmptyDoclist} + childFilters={CollectionDockingView.Instance?.childDocFilters ?? returnEmptyDocViewList} + childFiltersByRanges={CollectionDockingView.Instance?.childDocRangeFilters ?? returnEmptyDocViewList} searchFilterDocs={CollectionDockingView.Instance?.searchFilterDocs ?? returnEmptyDoclist} addDocument={undefined} removeDocument={this.remDocTab} @@ -628,7 +628,7 @@ export class TabDocView extends ObservableReactComponent { dontCenter="y" whenChildContentsActiveChanged={this.whenChildContentActiveChanges} focus={this.focusFunc} - containerViewPath={returnEmptyDoclist} + containerViewPath={returnEmptyDocViewList} pinToPres={TabDocView.PinDoc} /> {this.disableMinimap() ? null : } diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx index 54053d038..c0fe7a894 100644 --- a/src/client/views/collections/TreeView.tsx +++ b/src/client/views/collections/TreeView.tsx @@ -4,9 +4,9 @@ import { IconButton, Size } from 'browndash-components'; import { IReactionDisposer, action, computed, makeObservable, observable, reaction, runInAction } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; -import { ClientUtils, lightOrDark, return18, returnEmptyDoclist, returnEmptyFilter, returnEmptyString, returnFalse, returnTrue, returnZero, setupMoveUpEvents, simulateMouseClick } from '../../../ClientUtils'; +import { ClientUtils, lightOrDark, return18, returnEmptyFilter, returnEmptyString, returnFalse, returnTrue, returnZero, setupMoveUpEvents, simulateMouseClick } from '../../../ClientUtils'; import { emptyFunction } from '../../../Utils'; -import { Doc, DocListCast, Field, FieldResult, FieldType, Opt, StrListCast } from '../../../fields/Doc'; +import { Doc, DocListCast, Field, FieldResult, FieldType, Opt, StrListCast, returnEmptyDoclist } from '../../../fields/Doc'; import { DocData } from '../../../fields/DocSymbols'; import { Id } from '../../../fields/FieldSymbols'; import { List } from '../../../fields/List'; diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx index b8509a005..5125bdb6c 100644 --- a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx +++ b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx @@ -1,5 +1,3 @@ -/* eslint-disable jsx-a11y/no-static-element-interactions */ -/* eslint-disable jsx-a11y/click-events-have-key-events */ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { Tooltip } from '@mui/material'; import { Button, IconButton } from 'browndash-components'; @@ -14,7 +12,7 @@ import { SettingsManager } from '../../../util/SettingsManager'; import { Transform } from '../../../util/Transform'; import { undoBatch, undoable } from '../../../util/UndoManager'; import { DocumentView } from '../../nodes/DocumentView'; -import { CollectionSubView } from '../CollectionSubView'; +import { CollectionSubView, SubCollectionViewProps } from '../CollectionSubView'; import './CollectionMulticolumnView.scss'; import ResizeBar from './MulticolumnResizer'; import WidthLabel from './MulticolumnWidthLabel'; @@ -42,7 +40,7 @@ const resizerWidth = 8; export class CollectionMulticolumnView extends CollectionSubView() { @observable _startIndex = 0; - constructor(props: any) { + constructor(props: SubCollectionViewProps) { super(props); makeObservable(this); } @@ -305,7 +303,7 @@ export class CollectionMulticolumnView extends CollectionSubView() { whenChildContentsActiveChanged={this._props.whenChildContentsActiveChanged} addDocTab={this._props.addDocTab} pinToPres={this._props.pinToPres} - dontCenter={StrCast(this.layoutDoc.layout_dontCenter) as any} // 'y', 'x', 'xy' + dontCenter={StrCast(this.layoutDoc.layout_dontCenter) as 'x' | 'y' | 'xy'} /> ); }; diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx index 3fe3d5343..2833ff2f8 100644 --- a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx +++ b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx @@ -8,7 +8,7 @@ import { dropActionType } from '../../../util/DropActionTypes'; import { Transform } from '../../../util/Transform'; import { undoBatch } from '../../../util/UndoManager'; import { DocumentView } from '../../nodes/DocumentView'; -import { CollectionSubView } from '../CollectionSubView'; +import { CollectionSubView, SubCollectionViewProps } from '../CollectionSubView'; import './CollectionMultirowView.scss'; import HeightLabel from './MultirowHeightLabel'; import ResizeBar from './MultirowResizer'; @@ -33,7 +33,7 @@ const resizerHeight = 8; @observer export class CollectionMultirowView extends CollectionSubView() { - constructor(props: any) { + constructor(props: SubCollectionViewProps) { super(props); makeObservable(this); } @@ -284,7 +284,7 @@ export class CollectionMultirowView extends CollectionSubView() { whenChildContentsActiveChanged={this._props.whenChildContentsActiveChanged} addDocTab={this._props.addDocTab} pinToPres={this._props.pinToPres} - dontCenter={StrCast(this.layoutDoc.layout_dontCenter) as any} // 'y', 'x', 'xy' + dontCenter={StrCast(this.layoutDoc.layout_dontCenter) as 'y' | 'x' | 'xy'} /> ); }; diff --git a/src/client/views/collections/collectionMulticolumn/MulticolumnResizer.tsx b/src/client/views/collections/collectionMulticolumn/MulticolumnResizer.tsx index 931e2c5e0..10a6fa2e9 100644 --- a/src/client/views/collections/collectionMulticolumn/MulticolumnResizer.tsx +++ b/src/client/views/collections/collectionMulticolumn/MulticolumnResizer.tsx @@ -68,7 +68,7 @@ export default class ResizeBar extends React.Component { style={{ pointerEvents: this.props.isContentActive?.() ? 'all' : 'none', width: this.props.width, - backgroundColor: !this.props.isContentActive?.() ? '' : this.props.styleProvider?.(undefined, undefined, StyleProp.WidgetColor), + backgroundColor: !this.props.isContentActive?.() ? '' : (this.props.styleProvider?.(undefined, undefined, StyleProp.WidgetColor) as string), }}>
this.registerResizing(e)} />
diff --git a/src/client/views/collections/collectionMulticolumn/MultirowResizer.tsx b/src/client/views/collections/collectionMulticolumn/MultirowResizer.tsx index cff0a8b4c..918365700 100644 --- a/src/client/views/collections/collectionMulticolumn/MultirowResizer.tsx +++ b/src/client/views/collections/collectionMulticolumn/MultirowResizer.tsx @@ -66,7 +66,7 @@ export default class ResizeBar extends React.Component { style={{ pointerEvents: this.props.isContentActive?.() ? 'all' : 'none', height: this.props.height, - backgroundColor: !this.props.isContentActive?.() ? '' : this.props.styleProvider?.(undefined, undefined, StyleProp.WidgetColor), + backgroundColor: !this.props.isContentActive?.() ? '' : this.props.styleProvider?.(undefined, undefined, StyleProp.WidgetColor) as string, }}>
this.registerResizing(e)} />
diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx index 6bea53355..8b0639b3b 100644 --- a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx +++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx @@ -4,7 +4,7 @@ import { Popup, PopupTrigger, Type } from 'browndash-components'; import { ObservableMap, action, computed, makeObservable, observable, observe, runInAction } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; -import { returnEmptyDoclist, returnEmptyString, returnFalse, returnIgnore, returnNever, returnTrue, setupMoveUpEvents, smoothScroll } from '../../../../ClientUtils'; +import { returnEmptyString, returnFalse, returnIgnore, returnNever, returnTrue, setupMoveUpEvents, smoothScroll } from '../../../../ClientUtils'; import { emptyFunction } from '../../../../Utils'; import { Doc, DocListCast, Field, FieldType, NumListCast, Opt, StrListCast } from '../../../../fields/Doc'; import { DocData } from '../../../../fields/DocSymbols'; @@ -22,12 +22,12 @@ import { ContextMenu } from '../../ContextMenu'; import { EditableView } from '../../EditableView'; import { ObservableReactComponent } from '../../ObservableReactComponent'; import { StyleProp } from '../../StyleProp'; -import { DefaultStyleProvider } from '../../StyleProvider'; +import { DefaultStyleProvider, returnEmptyDocViewList } from '../../StyleProvider'; import { Colors } from '../../global/globalEnums'; import { DocumentView } from '../../nodes/DocumentView'; import { FieldViewProps } from '../../nodes/FieldView'; import { FocusViewOptions } from '../../nodes/FocusViewOptions'; -import { CollectionSubView } from '../CollectionSubView'; +import { CollectionSubView, SubCollectionViewProps } from '../CollectionSubView'; import './CollectionSchemaView.scss'; import { SchemaColumnHeader } from './SchemaColumnHeader'; import { SchemaRowBox } from './SchemaRowBox'; @@ -49,14 +49,14 @@ const defaultColumnKeys: string[] = ['title', 'type', 'author', 'author_date', ' @observer export class CollectionSchemaView extends CollectionSubView() { - private _keysDisposer: any; + private _keysDisposer?: () => void; private _previewRef: HTMLDivElement | null = null; private _makeNewColumn: boolean = false; private _documentOptions: DocumentOptions = new DocumentOptions(); private _tableContentRef: HTMLDivElement | null = null; private _menuTarget = React.createRef(); - constructor(props: any) { + constructor(props: SubCollectionViewProps) { super(props); makeObservable(this); } @@ -76,7 +76,7 @@ export class CollectionSchemaView extends CollectionSubView() { @observable _columnMenuIndex: number | undefined = undefined; @observable _newFieldWarning: string = ''; @observable _makeNewField: boolean = false; - @observable _newFieldDefault: any = 0; + @observable _newFieldDefault: boolean | number | string | undefined = 0; @observable _newFieldType: ColumnType = ColumnType.Number; @observable _menuValue: string = ''; @observable _filterColumnIndex: number | undefined = undefined; @@ -161,11 +161,11 @@ export class CollectionSchemaView extends CollectionSubView() { Object.entries(this._documentOptions).forEach((pair: [string, FInfo]) => this.fieldInfos.set(pair[0], pair[1])); this._keysDisposer = observe( this.dataDoc[this.fieldKey ?? 'data'] as List, - (change: any) => { + change => { switch (change.type) { case 'splice': // prettier-ignore - (change as any).added.forEach((doc: Doc) => // for each document added + change.added.filter(doc => doc instanceof Doc).map(doc => doc as Doc).forEach((doc: Doc) => // for each document added Doc.GetAllPrototypes(doc.value as Doc).forEach(proto => // for all of its prototypes (and itself) Object.keys(proto).forEach(action(key => // check if any of its keys are new, and add them !this.fieldInfos.get(key) && this.fieldInfos.set(key, new FInfo("-no description-", key === 'author')))))); @@ -270,7 +270,7 @@ export class CollectionSchemaView extends CollectionSubView() { addRow = (doc: Doc | Doc[]) => this.addDocument(doc); @undoBatch - changeColumnKey = (index: number, newKey: string, defaultVal?: any) => { + changeColumnKey = (index: number, newKey: string, defaultVal?: string | number | boolean) => { if (!this.documentKeys.includes(newKey)) { this.addNewKey(newKey, defaultVal); } @@ -281,7 +281,7 @@ export class CollectionSchemaView extends CollectionSubView() { }; @undoBatch - addColumn = (key: string, defaultVal?: any) => { + addColumn = (key: string, defaultVal?: string | number | boolean) => { if (!this.documentKeys.includes(key)) { this.addNewKey(key, defaultVal); } @@ -298,7 +298,7 @@ export class CollectionSchemaView extends CollectionSubView() { }; @action - addNewKey = (key: string, defaultVal: any) => + addNewKey = (key: string, defaultVal?: string | number | boolean) => this.childDocs.forEach(doc => { doc[DocData][key] = defaultVal; }); @@ -317,7 +317,7 @@ export class CollectionSchemaView extends CollectionSubView() { }; @action - startResize = (e: any, index: number) => { + startResize = (e: React.PointerEvent, index: number) => { this._displayColumnWidths = this.storedColumnWidths; setupMoveUpEvents(this, e, moveEv => this.resizeColumn(moveEv, index), this.finishResize, emptyFunction); }; @@ -604,7 +604,7 @@ export class CollectionSchemaView extends CollectionSubView() { }; scrollToDoc = (doc: Doc, options: FocusViewOptions) => { - const found = this._tableContentRef && Array.from(this._tableContentRef.getElementsByClassName('documentView-node')).find((node: any) => node.id === doc[Id]); + const found = this._tableContentRef && Array.from(this._tableContentRef.getElementsByClassName('documentView-node')).find(node => node.id === doc[Id]); if (found) { const rect = found.getBoundingClientRect(); const localRect = this.ScreenToLocalBoxXf().transformBounds(rect.left, rect.top, rect.width, rect.height); @@ -625,9 +625,9 @@ export class CollectionSchemaView extends CollectionSubView() { type="number" name="" id="" - value={this._newFieldDefault ?? 0} + value={Number(this._newFieldDefault ?? 0)} onPointerDown={e => e.stopPropagation()} - onChange={action((e: any) => { + onChange={action(e => { this._newFieldDefault = e.target.value; })} /> @@ -637,11 +637,9 @@ export class CollectionSchemaView extends CollectionSubView() { <> e.stopPropagation()} - onChange={action((e: any) => { + onChange={action(e => { this._newFieldDefault = e.target.checked; })} /> @@ -654,9 +652,9 @@ export class CollectionSchemaView extends CollectionSubView() { type="text" name="" id="" - value={this._newFieldDefault ?? ''} + value={this._newFieldDefault?.toString() ?? ''} onPointerDown={e => e.stopPropagation()} - onChange={action((e: any) => { + onChange={action(e => { this._newFieldDefault = e.target.value; })} /> @@ -683,7 +681,7 @@ export class CollectionSchemaView extends CollectionSubView() { }; @action - setKey = (key: string, defaultVal?: any) => { + setKey = (key: string, defaultVal?: string | number | boolean) => { if (this._makeNewColumn) { this.addColumn(key, defaultVal); } else { @@ -856,16 +854,16 @@ export class CollectionSchemaView extends CollectionSubView() { onKeysPassiveWheel = (e: WheelEvent) => { // if scrollTop is 0, then don't let wheel trigger scroll on any container (which it would since onScroll won't be triggered on this) - if (!this._oldKeysWheel.scrollTop && e.deltaY <= 0) e.preventDefault(); + if (!this._oldKeysWheel?.scrollTop && e.deltaY <= 0) e.preventDefault(); e.stopPropagation(); }; - _oldKeysWheel: any; + _oldKeysWheel: HTMLDivElement | null = null; @computed get keysDropdown() { return (
{ + onPointerDown={action(e => { e.stopPropagation(); this._makeNewField = true; })}> @@ -880,6 +878,7 @@ export class CollectionSchemaView extends CollectionSubView() { }}> {this._menuKeys.map(key => (
{ e.stopPropagation(); @@ -962,7 +961,7 @@ export class CollectionSchemaView extends CollectionSubView() { {this.renderFilterOptions}
{ + onPointerDown={action(e => { e.stopPropagation(); this.closeFilterMenu(); })}> @@ -1013,7 +1012,7 @@ export class CollectionSchemaView extends CollectionSubView() { screenToLocal = () => this.ScreenToLocalBoxXf().translate(-this.tableWidth, 0); previewWidthFunc = () => this.previewWidth; onPassiveWheel = (e: WheelEvent) => e.stopPropagation(); - _oldWheel: any; + _oldWheel: HTMLDivElement | null = null; render() { return (
this.createDashEventsTarget(ele)} onDrop={this.onExternalDrop.bind(this)} onPointerMove={e => this.onPointerMove(e)}> @@ -1112,7 +1111,7 @@ export class CollectionSchemaView extends CollectionSubView() { childFiltersByRanges={this.childDocRangeFilters} searchFilterDocs={this.searchFilterDocs} styleProvider={DefaultStyleProvider} - containerViewPath={returnEmptyDoclist} + containerViewPath={returnEmptyDocViewList} moveDocument={this._props.moveDocument} addDocument={this.addRow} removeDocument={this._props.removeDocument} @@ -1137,7 +1136,7 @@ interface CollectionSchemaViewDocProps { @observer class CollectionSchemaViewDoc extends ObservableReactComponent { - constructor(props: any) { + constructor(props: CollectionSchemaViewDocProps) { super(props); makeObservable(this); } diff --git a/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx b/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx index 6b5a34ec0..e0ed8d01e 100644 --- a/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx +++ b/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx @@ -18,8 +18,8 @@ export interface SchemaColumnHeaderProps { setSort: (field: string | undefined, desc?: boolean) => void; removeColumn: (index: number) => void; rowHeight: () => number; - resizeColumn: (e: any, index: number) => void; - dragColumn: (e: any, index: number) => boolean; + resizeColumn: (e: React.PointerEvent, index: number) => void; + dragColumn: (e: PointerEvent, index: number) => boolean; openContextMenu: (x: number, y: number, index: number) => void; setColRef: (index: number, ref: HTMLDivElement) => void; } diff --git a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx index 760089ffb..a7e0e916b 100644 --- a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx +++ b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx @@ -58,8 +58,8 @@ export class SchemaRowBox extends ViewBoxBaseComponent() { selectCell = (doc: Doc, col: number, shift: boolean, ctrl: boolean) => this.schemaView?.selectCell(doc, col, shift, ctrl); deselectCell = () => this.schemaView?.deselectAllCells(); selectedCells = () => this.schemaView?._selectedDocs; - setColumnValues = (field: any, value: any) => this.schemaView?.setColumnValues(field, value) ?? false; - setSelectedColumnValues = (field: any, value: any) => this.schemaView?.setSelectedColumnValues(field, value) ?? false; + setColumnValues = (field: string, value: string) => this.schemaView?.setColumnValues(field, value) ?? false; + setSelectedColumnValues = (field: string, value: string) => this.schemaView?.setSelectedColumnValues(field, value) ?? false; columnWidth = computedFn((index: number) => () => this.schemaView?.displayColumnWidths[index] ?? CollectionSchemaView._minColWidth); render() { return ( diff --git a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx index 5874364e0..22506cac1 100644 --- a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx +++ b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx @@ -1,4 +1,3 @@ -/* eslint-disable jsx-a11y/alt-text */ /* eslint-disable react/jsx-props-no-spreading */ /* eslint-disable no-use-before-define */ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; @@ -10,10 +9,10 @@ import * as React from 'react'; import DatePicker from 'react-datepicker'; import 'react-datepicker/dist/react-datepicker.css'; import Select from 'react-select'; -import { ClientUtils, StopEvent, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnZero } from '../../../../ClientUtils'; +import { ClientUtils, StopEvent, returnEmptyFilter, returnFalse, returnZero } from '../../../../ClientUtils'; import { emptyFunction } from '../../../../Utils'; import { DateField } from '../../../../fields/DateField'; -import { Doc, DocListCast, Field } from '../../../../fields/Doc'; +import { Doc, DocListCast, Field, returnEmptyDoclist } from '../../../../fields/Doc'; import { RichTextField } from '../../../../fields/RichTextField'; import { ColumnType } from '../../../../fields/SchemaHeaderField'; import { BoolCast, Cast, DateCast, DocCast, FieldValue, StrCast, toList } from '../../../../fields/Types'; @@ -22,7 +21,7 @@ import { FInfo, FInfoFieldType } from '../../../documents/Documents'; import { dropActionType } from '../../../util/DropActionTypes'; import { SnappingManager } from '../../../util/SnappingManager'; import { Transform } from '../../../util/Transform'; -import { undoBatch, undoable } from '../../../util/UndoManager'; +import { undoable } from '../../../util/UndoManager'; import { EditableView } from '../../EditableView'; import { ObservableReactComponent } from '../../ObservableReactComponent'; import { DefaultStyleProvider, returnEmptyDocViewList } from '../../StyleProvider'; @@ -138,7 +137,7 @@ export class SchemaTableCell extends ObservableReactComponent selectedCell(this._props) && this._props.autoFocus && r?.setIsFocused(true)} oneLine={this._props.oneLine} allowCRs={this._props.allowCRs} - contents={undefined} + contents={''} fieldContents={fieldProps} editing={selectedCell(this._props) ? undefined : false} GetValue={() => Field.toKeyValueString(fieldProps.Document, this._props.fieldKey, SnappingManager.MetaKey)} @@ -209,7 +208,7 @@ export class SchemaTableCell extends ObservableReactComponent { - constructor(props: any) { + constructor(props: SchemaTableCellProps) { super(props); makeObservable(this); } @@ -276,7 +275,7 @@ export class SchemaImageCell extends ObservableReactComponent { - constructor(props: any) { + constructor(props: SchemaTableCellProps) { super(props); makeObservable(this); } @@ -324,7 +323,7 @@ export class SchemaDateCell extends ObservableReactComponent { - constructor(props: any) { + constructor(props: SchemaTableCellProps) { super(props); makeObservable(this); } @@ -343,7 +342,7 @@ export class SchemaRTFCell extends ObservableReactComponent { - constructor(props: any) { + constructor(props: SchemaTableCellProps) { super(props); makeObservable(this); } @@ -356,18 +355,19 @@ export class SchemaBoolCell extends ObservableReactComponent | undefined) => { - if ((value?.nativeEvent as any).shiftKey) { + onChange={undoable((value: React.ChangeEvent | undefined) => { + if ((value?.nativeEvent as MouseEvent | PointerEvent).shiftKey) { this._props.setColumnValues(this._props.fieldKey.replace(/^_/, ''), (color === 'black' ? '=' : '') + (value?.target?.checked.toString() ?? '')); } else Doc.SetField(this._props.Document, this._props.fieldKey.replace(/^_/, ''), (color === 'black' ? '=' : '') + (value?.target?.checked.toString() ?? '')); - })} + }, 'set bool cell')} /> + Field.toKeyValueString(this._props.Document, this._props.fieldKey)} - SetValue={undoBatch((value: string, shiftDown?: boolean, enterKey?: boolean) => { + SetValue={undoable((value: string, shiftDown?: boolean, enterKey?: boolean) => { if (shiftDown && enterKey) { this._props.setColumnValues(this._props.fieldKey.replace(/^_/, ''), value); this._props.finishEdit?.(); @@ -376,7 +376,7 @@ export class SchemaBoolCell extends ObservableReactComponent
); @@ -384,7 +384,7 @@ export class SchemaBoolCell extends ObservableReactComponent { - constructor(props: any) { + constructor(props: SchemaTableCellProps) { super(props); makeObservable(this); } diff --git a/src/client/views/linking/LinkPopup.tsx b/src/client/views/linking/LinkPopup.tsx index 76a8396ff..9ce5f8fc9 100644 --- a/src/client/views/linking/LinkPopup.tsx +++ b/src/client/views/linking/LinkPopup.tsx @@ -1,9 +1,9 @@ /* eslint-disable react/require-default-props */ import { observer } from 'mobx-react'; import * as React from 'react'; -import { returnEmptyDoclist, returnEmptyFilter, returnFalse, returnTrue } from '../../../ClientUtils'; +import { returnEmptyFilter, returnFalse, returnTrue } from '../../../ClientUtils'; import { emptyFunction } from '../../../Utils'; -import { Doc } from '../../../fields/Doc'; +import { Doc, returnEmptyDoclist } from '../../../fields/Doc'; import { Transform } from '../../util/Transform'; import { DefaultStyleProvider, returnEmptyDocViewList } from '../StyleProvider'; import { SearchBox } from '../search/SearchBox'; diff --git a/src/client/views/newlightbox/NewLightboxView.tsx b/src/client/views/newlightbox/NewLightboxView.tsx index c86ddb745..b060fc0b6 100644 --- a/src/client/views/newlightbox/NewLightboxView.tsx +++ b/src/client/views/newlightbox/NewLightboxView.tsx @@ -1,17 +1,15 @@ -/* eslint-disable jsx-a11y/no-static-element-interactions */ -/* eslint-disable jsx-a11y/click-events-have-key-events */ import { action, computed, observable } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; -import { returnEmptyDoclist, returnEmptyFilter, returnTrue } from '../../../ClientUtils'; +import { returnEmptyFilter, returnTrue } from '../../../ClientUtils'; import { emptyFunction } from '../../../Utils'; -import { CreateLinkToActiveAudio, Doc, DocListCast, Opt } from '../../../fields/Doc'; +import { CreateLinkToActiveAudio, Doc, DocListCast, Opt, returnEmptyDoclist } from '../../../fields/Doc'; import { InkTool } from '../../../fields/InkField'; import { Cast, NumCast, StrCast, toList } from '../../../fields/Types'; import { SnappingManager } from '../../util/SnappingManager'; import { Transform } from '../../util/Transform'; import { GestureOverlay } from '../GestureOverlay'; -import { DefaultStyleProvider } from '../StyleProvider'; +import { DefaultStyleProvider, returnEmptyDocViewList } from '../StyleProvider'; import { DocumentView } from '../nodes/DocumentView'; import { OpenWhere } from '../nodes/OpenWhere'; import { ExploreView } from './ExploreView'; @@ -68,7 +66,7 @@ export class NewLightboxView extends React.Component { @action public static SetCookie(cookie: string) { if (this.LightboxDoc && cookie) { - this._docFilters = (f => (this._docFilters ? [this._docFilters.push(f) as any, this._docFilters][1] : [f]))(`cookies:${cookie}:provide`); + this._docFilters = (f => (this._docFilters ? ([this._docFilters.push(f) as unknown, this._docFilters][1] as string[]) : [f]))(`cookies:${cookie}:provide`); } } public static AddDocTab = (docsIn: Doc | Doc[], location: OpenWhere, layoutTemplate?: Doc | string) => { @@ -264,7 +262,7 @@ export class NewLightboxView extends React.Component { styleProvider={DefaultStyleProvider} ScreenToLocalTransform={this.newLightboxScreenToLocal} renderDepth={0} - containerViewPath={returnEmptyDoclist} + containerViewPath={returnEmptyDocViewList} childFilters={this.docFilters} childFiltersByRanges={returnEmptyFilter} searchFilterDocs={returnEmptyDoclist} @@ -320,7 +318,7 @@ export class NewLightboxView extends React.Component {
)}
- +
); diff --git a/src/client/views/newlightbox/RecommendationList/RecommendationList.tsx b/src/client/views/newlightbox/RecommendationList/RecommendationList.tsx index dc3339cd3..27413bac3 100644 --- a/src/client/views/newlightbox/RecommendationList/RecommendationList.tsx +++ b/src/client/views/newlightbox/RecommendationList/RecommendationList.tsx @@ -1,6 +1,4 @@ /* eslint-disable react/jsx-props-no-spreading */ -/* eslint-disable jsx-a11y/no-static-element-interactions */ -/* eslint-disable jsx-a11y/click-events-have-key-events */ /* eslint-disable guard-for-in */ import { IconButton, Size, Type } from 'browndash-components'; import * as React from 'react'; @@ -168,7 +166,8 @@ export function RecommendationList() {
{keywordsLoc && keywordsLoc.map((word, ind) => ( -
+
+ {' '} {word} )}
-
{recs && recs.map((rec: IRecommendation) => )}
+
{recs && recs.map(rec => )}
); } diff --git a/src/client/views/nodes/KeyValuePair.tsx b/src/client/views/nodes/KeyValuePair.tsx index 8e74e1ca2..85aff04c3 100644 --- a/src/client/views/nodes/KeyValuePair.tsx +++ b/src/client/views/nodes/KeyValuePair.tsx @@ -2,9 +2,9 @@ import { Tooltip } from '@mui/material'; import { action, makeObservable, observable } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; -import { returnEmptyDoclist, returnEmptyFilter, returnFalse, returnZero } from '../../../ClientUtils'; +import { returnEmptyFilter, returnFalse, returnZero } from '../../../ClientUtils'; import { emptyFunction } from '../../../Utils'; -import { Doc, Field } from '../../../fields/Doc'; +import { Doc, Field, returnEmptyDoclist } from '../../../fields/Doc'; import { DocCast } from '../../../fields/Types'; import { DocumentOptions, FInfo } from '../../documents/Documents'; import { Transform } from '../../util/Transform'; diff --git a/src/client/views/nodes/LabelBox.tsx b/src/client/views/nodes/LabelBox.tsx index d33d12603..e39caecb6 100644 --- a/src/client/views/nodes/LabelBox.tsx +++ b/src/client/views/nodes/LabelBox.tsx @@ -1,10 +1,11 @@ import { Property } from 'csstype'; -import { action, computed, makeObservable, trace } from 'mobx'; +import { action, computed, makeObservable } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; import * as textfit from 'textfit'; import { Field, FieldType } from '../../../fields/Doc'; import { BoolCast, NumCast, StrCast } from '../../../fields/Types'; +import { TraceMobx } from '../../../fields/util'; import { DocumentType } from '../../documents/DocumentTypes'; import { Docs } from '../../documents/Documents'; import { DragManager } from '../../util/DragManager'; @@ -100,7 +101,7 @@ export class LabelBox extends ViewBoxBaseComponent() { return textfitParams; }; render() { - trace(); + TraceMobx(); const boxParams = this.fitTextToBox(undefined); // this causes mobx to trigger re-render when data changes const label = this.Title.startsWith('#') ? null : this.Title; return ( diff --git a/src/client/views/nodes/LinkDocPreview.tsx b/src/client/views/nodes/LinkDocPreview.tsx index 10ff86a38..5026f52fb 100644 --- a/src/client/views/nodes/LinkDocPreview.tsx +++ b/src/client/views/nodes/LinkDocPreview.tsx @@ -4,9 +4,9 @@ import { action, computed, makeObservable, observable, runInAction } from 'mobx' import { observer } from 'mobx-react'; import * as React from 'react'; import wiki from 'wikijs'; -import { returnEmptyDoclist, returnEmptyFilter, returnEmptyString, returnFalse, returnNone, setupMoveUpEvents } from '../../../ClientUtils'; +import { returnEmptyFilter, returnEmptyString, returnFalse, returnNone, setupMoveUpEvents } from '../../../ClientUtils'; import { emptyFunction } from '../../../Utils'; -import { Doc, Opt } from '../../../fields/Doc'; +import { Doc, Opt, returnEmptyDoclist } from '../../../fields/Doc'; import { Cast, DocCast, NumCast, PromiseValue, StrCast } from '../../../fields/Types'; import { DocServer } from '../../DocServer'; import { DocumentType } from '../../documents/DocumentTypes'; @@ -17,6 +17,7 @@ import { SearchUtil } from '../../util/SearchUtil'; import { SnappingManager } from '../../util/SnappingManager'; import { Transform } from '../../util/Transform'; import { ObservableReactComponent } from '../ObservableReactComponent'; +import { returnEmptyDocViewList } from '../StyleProvider'; import { DocumentView } from './DocumentView'; import { StyleProviderFuncType } from './FieldView'; import './LinkDocPreview.scss'; @@ -286,7 +287,7 @@ export class LinkDocPreview extends ObservableReactComponent deselectPin = () => { if (this.selectedPin) { // Removes filter - Doc.setDocFilter(this.Document, 'latitude', this.selectedPin.latitude, 'remove'); - Doc.setDocFilter(this.Document, 'longitude', this.selectedPin.longitude, 'remove'); + Doc.setDocFilter(this.Document, 'latitude', NumCast(this.selectedPin.latitude), 'remove'); + Doc.setDocFilter(this.Document, 'longitude', NumCast(this.selectedPin.longitude), 'remove'); Doc.setDocFilter(this.Document, LinkedTo, `mapPin=${Field.toScriptString(DocCast(this.selectedPin))}`, 'remove'); const temp = this.selectedPin; @@ -536,8 +537,8 @@ export class MapBoxContainer extends ViewBoxAnnotatableComponent deleteSelectedPin = undoable(() => { if (this.selectedPin) { // Removes filter - Doc.setDocFilter(this.Document, 'latitude', this.selectedPin.latitude, 'remove'); - Doc.setDocFilter(this.Document, 'longitude', this.selectedPin.longitude, 'remove'); + Doc.setDocFilter(this.Document, 'latitude', NumCast(this.selectedPin.latitude), 'remove'); + Doc.setDocFilter(this.Document, 'longitude', NumCast(this.selectedPin.longitude), 'remove'); Doc.setDocFilter(this.Document, LinkedTo, `mapPin=${Field.toScriptString(DocCast(this.selectedPin))}`, 'remove'); this.removePushpin(this.selectedPin); diff --git a/src/client/views/nodes/trails/PresElementBox.tsx b/src/client/views/nodes/trails/PresElementBox.tsx index 25adfba23..a76805960 100644 --- a/src/client/views/nodes/trails/PresElementBox.tsx +++ b/src/client/views/nodes/trails/PresElementBox.tsx @@ -1,11 +1,9 @@ -/* eslint-disable jsx-a11y/no-static-element-interactions */ -/* eslint-disable jsx-a11y/click-events-have-key-events */ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { Tooltip } from '@mui/material'; import { action, computed, IReactionDisposer, makeObservable, observable, reaction, runInAction } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; -import { returnEmptyDoclist, returnFalse, returnTrue, setupMoveUpEvents } from '../../../../ClientUtils'; +import { returnFalse, returnTrue, setupMoveUpEvents } from '../../../../ClientUtils'; import { Doc, DocListCast, Opt } from '../../../../fields/Doc'; import { Id } from '../../../../fields/FieldSymbols'; import { List } from '../../../../fields/List'; @@ -23,6 +21,7 @@ import { EditableView } from '../../EditableView'; import { Colors } from '../../global/globalEnums'; import { PinDocView } from '../../PinFuncs'; import { StyleProp } from '../../StyleProp'; +import { returnEmptyDocViewList } from '../../StyleProvider'; import { DocumentView } from '../DocumentView'; import { FieldView, FieldViewProps } from '../FieldView'; import { PresBox } from './PresBox'; @@ -105,7 +104,7 @@ export class PresElementBox extends ViewBoxBaseComponent() { embedHeight = () => this.collapsedHeight + this.expandViewHeight; embedWidth = () => this._props.PanelWidth() / 2; // prettier-ignore - styleProvider = ( doc: Doc | undefined, props: Opt, property: string ): any => + styleProvider = ( doc: Doc | undefined, props: Opt, property: string ) => (property === StyleProp.Opacity ? 1 : this._props.styleProvider?.(doc, props, property)); /** * The function that is responsible for rendering a preview or not for this @@ -123,7 +122,7 @@ export class PresElementBox extends ViewBoxBaseComponent() { hideLinkButton ScreenToLocalTransform={Transform.Identity} renderDepth={this._props.renderDepth + 1} - containerViewPath={returnEmptyDoclist} + containerViewPath={returnEmptyDocViewList} childFilters={this._props.childFilters} childFiltersByRanges={this._props.childFiltersByRanges} searchFilterDocs={this._props.searchFilterDocs} @@ -144,6 +143,7 @@ export class PresElementBox extends ViewBoxBaseComponent() { const childDocs = DocListCast(this.targetDoc.data); const groupSlides = childDocs.map((doc: Doc, ind: number) => (
{ e.stopPropagation(); @@ -156,7 +156,7 @@ export class PresElementBox extends ViewBoxBaseComponent() { StrCast(doc.title)} SetValue={(value: string) => { @@ -179,7 +179,7 @@ export class PresElementBox extends ViewBoxBaseComponent() { @action headerDown = (e: React.PointerEvent) => { - const element = e.target as any; + const element = e.target as HTMLDivElement; e.stopPropagation(); e.preventDefault(); if (element && !(e.ctrlKey || e.metaKey || e.button === 2)) { @@ -580,7 +580,7 @@ export class PresElementBox extends ViewBoxBaseComponent() { className={`presItem-slide ${isCurrent ? 'active' : ''}${activeItem.runProcess ? ' testingv2' : ''}`} style={{ display: 'infline-block', - backgroundColor: this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.BackgroundColor), + backgroundColor: this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.BackgroundColor) as string, // layout_boxShadow: presBoxColor && presBoxColor !== 'white' && presBoxColor !== 'transparent' ? (isCurrent ? '0 0 0px 1.5px' + presBoxColor : undefined) : undefined, border: presBoxColor && presBoxColor !== 'white' && presBoxColor !== 'transparent' ? (isCurrent ? presBoxColor + ' solid 2.5px' : undefined) : undefined, }}> @@ -602,7 +602,7 @@ export class PresElementBox extends ViewBoxBaseComponent() { } }} onClick={e => e.stopPropagation()}>{`${this.indexInPres + 1}. `}
- StrCast(activeItem.title)} SetValue={this.onSetValue} /> + StrCast(activeItem.title)} SetValue={this.onSetValue} />
{/*
{"Movement speed"}
}>
{this.transition}
*/} {/*
{"Duration"}
}>
{this.duration}
*/} diff --git a/src/client/views/topbar/TopBar.tsx b/src/client/views/topbar/TopBar.tsx index e558e14e3..a85606bc4 100644 --- a/src/client/views/topbar/TopBar.tsx +++ b/src/client/views/topbar/TopBar.tsx @@ -5,8 +5,8 @@ import { observer } from 'mobx-react'; import * as React from 'react'; import { Flip } from 'react-awesome-reveal'; import { FaBug } from 'react-icons/fa'; -import { returnEmptyDoclist, returnEmptyFilter, returnFalse, returnTrue } from '../../../ClientUtils'; -import { Doc, DocListCast } from '../../../fields/Doc'; +import { returnEmptyFilter, returnFalse, returnTrue } from '../../../ClientUtils'; +import { Doc, DocListCast, returnEmptyDoclist } from '../../../fields/Doc'; import { AclAdmin, DashVersion } from '../../../fields/DocSymbols'; import { StrCast } from '../../../fields/Types'; import { GetEffectiveAcl } from '../../../fields/util'; @@ -33,11 +33,11 @@ import './TopBar.scss'; * and settings and help buttons. Future scope for this bar is to include the collaborators that are on the same Dashboard. */ @observer -export class TopBar extends ObservableReactComponent<{}> { +export class TopBar extends ObservableReactComponent { // eslint-disable-next-line no-use-before-define static Instance: TopBar; @observable private _flipDocumentation = 0; - constructor(props: any) { + constructor(props: object) { super(props); makeObservable(this); TopBar.Instance = this; diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts index e6a95fd30..7e7c319bf 100644 --- a/src/fields/Doc.ts +++ b/src/fields/Doc.ts @@ -1658,6 +1658,10 @@ export namespace Doc { } } +export function returnEmptyDoclist() { + return [] as Doc[]; +} + export function RTFIsFragment(html: string) { return html.indexOf('data-pm-slice') !== -1; } diff --git a/src/mobile/ImageUpload.scss b/src/mobile/ImageUpload.scss deleted file mode 100644 index e4156ee8e..000000000 --- a/src/mobile/ImageUpload.scss +++ /dev/null @@ -1,139 +0,0 @@ -@import '../client/views/global/globalCssVariables.module.scss'; - -.imgupload_cont { - display: flex; - justify-content: center; - flex-direction: column; - align-items: center; - max-width: 400px; - min-width: 400px; - - .upload_label { - font-weight: 700; - color: black; - background-color: rgba(0, 0, 0, 0); - border: solid 3px black; - margin: 10px; - font-size: 30; - height: 70px; - width: 80%; - display: flex; - font-family: sans-serif; - text-transform: uppercase; - justify-content: center; - flex-direction: column; - border-radius: 10px; - } - - .file { - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - direction: ltr; - } - - .button_file { - text-align: center; - height: 50%; - width: 50%; - background-color: paleturquoise; - color: grey; - font-size: 3em; - } - - .inputfile { - width: 0.1px; - height: 0.1px; - opacity: 0; - overflow: hidden; - position: absolute; - z-index: -1; - } - - .inputfile + label { - font-weight: 700; - color: black; - background-color: rgba(0, 0, 0, 0); - border: solid 3px black; - margin: 10px; - font-size: 30; - height: 70px; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - margin-top: 30px; - width: 80%; - display: flex; - font-family: sans-serif; - text-transform: uppercase; - justify-content: center; - flex-direction: column; - border-radius: 10px; - } - - .inputfile.active + label { - font-style: italic; - color: black; - background-color: lightgreen; - border: solid 3px darkgreen; - } - - .status { - font-size: 2em; - } -} - -.image-upload { - top: 100%; - opacity: 0; -} - -.image-upload.active { - top: 0; - position: absolute; - z-index: 999; - height: 100vh; - width: 100vw; - opacity: 1; -} - -.uploadContainer { - top: 40; - position: absolute; - z-index: 1000; - height: 20vh; - width: 80vw; - opacity: 1; -} - -.closeUpload { - position: absolute; - border-radius: 10px; - top: 3; - color: black; - font-size: 30; - right: 3; - z-index: 1002; - padding: 0px 3px; - background: rgba(0, 0, 0, 0); - transition: 0.5s ease all; - border: 0px solid; -} - -.loadingImage { - display: inline-flex; - width: max-content; -} - -.loadingSlab { - position: relative; - width: 30px; - height: 30px; - margin: 10; - border-radius: 20px; - opacity: 0.2; - background-color: black; - transition: - all 2s, - opacity 1.5s; -} diff --git a/src/mobile/ImageUpload.tsx b/src/mobile/ImageUpload.tsx deleted file mode 100644 index 36c0d6a4d..000000000 --- a/src/mobile/ImageUpload.tsx +++ /dev/null @@ -1,170 +0,0 @@ -import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { action, observable } from 'mobx'; -import { observer } from 'mobx-react'; -import * as React from 'react'; -import * as rp from 'request-promise'; -import { ClientUtils } from '../ClientUtils'; -import { DocServer } from '../client/DocServer'; -import { Networking } from '../client/Network'; -import { Docs } from '../client/documents/Documents'; -import { MainViewModal } from '../client/views/MainViewModal'; -import { Doc, Opt } from '../fields/Doc'; -import { List } from '../fields/List'; -import { listSpec } from '../fields/Schema'; -import { Cast } from '../fields/Types'; -import './ImageUpload.scss'; - -// eslint-disable-next-line @typescript-eslint/no-var-requires -const { DFLT_IMAGE_NATIVE_DIM } = require('../client/views/global/globalCssVariables.module.scss'); // prettier-ignore - -export interface ImageUploadProps { - Document: Doc; // Target document for upload (upload location) -} - -const inputRef = React.createRef(); -const defaultNativeImageDim = Number(DFLT_IMAGE_NATIVE_DIM.replace('px', '')); - -@observer -export class Uploader extends React.Component { - @observable nm: string = 'Choose files'; // Text of 'Choose Files' button - @observable process: string = ''; // Current status of upload - @observable private dialogueBoxOpacity = 1; - - onClick = async () => { - try { - // eslint-disable-next-line react/destructuring-assignment - const col = this.props.Document; - await Docs.Prototypes.initialize(); - const imgPrev = document.getElementById('img_preview'); - this.setOpacity(1, '1'); // Slab 1 - if (imgPrev && inputRef.current) { - const { files } = inputRef.current; - this.setOpacity(2, '1'); // Slab 2 - if (files && files.length !== 0) { - this.process = 'Uploading Files'; - for (let index = 0; index < files.length; ++index) { - const file = files[index]; - // eslint-disable-next-line no-await-in-loop - const res = await Networking.UploadFilesToServer({ file }); - this.setOpacity(3, '1'); // Slab 3 - // For each item that the user has selected - res.map(async ({ result }) => { - const { name } = file; - if (result instanceof Error) { - return; - } - const path = result.accessPaths.agnostic.client; - let doc = null; - // Case 1: File is a video - if (file.type === 'video/mp4') { - doc = Docs.Create.VideoDocument(path, { _nativeWidth: defaultNativeImageDim, _width: 400, title: name }); - // Case 2: File is a PDF document - } else if (file.type === 'application/pdf') { - doc = Docs.Create.PdfDocument(path, { _nativeWidth: defaultNativeImageDim, _width: 400, title: name }); - // Case 3: File is another document type (most likely Image) - } else { - doc = Docs.Create.ImageDocument(path, { _nativeWidth: defaultNativeImageDim, _width: 400, title: name }); - } - this.setOpacity(4, '1'); // Slab 4 - const docidsRes = await rp.get(ClientUtils.prepend('/getUserDocumentIds')); - if (!docidsRes) { - throw new Error('No user id returned'); - } - const field = await DocServer.GetRefField(JSON.parse(docidsRes).userDocumentId); - let pending: Opt; - if (field instanceof Doc) { - pending = col; - } - if (pending) { - const data = Cast(pending.data, listSpec(Doc)); - if (data) data.push(doc); - else pending.data = new List([doc]); - this.setOpacity(5, '1'); // Slab 5 - this.process = 'File ' + (index + 1).toString() + ' Uploaded'; - this.setOpacity(6, '1'); // Slab 6 - } - if (index + 1 === files.length) { - this.process = 'Uploads Completed'; - this.setOpacity(7, '1'); // Slab 7 - } - }); - } - // Case in which the user pressed upload and no files were selected - } else { - this.process = 'No file selected'; - } - // Three seconds after upload the menu will reset - setTimeout(this.clearUpload, 3000); - } - } catch (error) { - console.log(JSON.stringify(error)); - } - }; - - // Returns the upload interface for mobile - private get uploadInterface() { - return ( -
-
this.closeUpload()}> - -
- - - -
- Upload -
- -
-
-
-
-
-
-
-
-
-

{this.process}

-
- ); - } - - // Updates label after a files is selected (so user knows a file is uploaded) - inputLabel = async () => { - const files: FileList | null = await inputRef.current!.files; - if (files && files.length === 1) { - this.nm = files[0].name; - } else if (files && files.length > 1) { - this.nm = files.length.toString() + ' files selected'; - } - }; // Loops through load icons, and resets buttons - @action - clearUpload = () => { - for (let i = 1; i < 8; i++) { - this.setOpacity(i, '0.2'); - } - this.nm = 'Choose files'; - - if (inputRef.current) { - inputRef.current.value = ''; - } - this.process = ''; - }; - - // Clears the upload and closes the upload menu - closeUpload = () => { - this.clearUpload(); - }; - - // Handles the setting of the loading bar - setOpacity = (index: number, opacity: string) => { - const slab = document.getElementById('slab' + index); - if (slab) slab.style.opacity = opacity; - }; - - render() { - return ; - } -} diff --git a/src/mobile/InkControls.tsx b/src/mobile/InkControls.tsx deleted file mode 100644 index e69de29bb..000000000 diff --git a/src/mobile/MobileInkOverlay.scss b/src/mobile/MobileInkOverlay.scss deleted file mode 100644 index b9c1fb146..000000000 --- a/src/mobile/MobileInkOverlay.scss +++ /dev/null @@ -1,39 +0,0 @@ -.mobileInkOverlay { - border: 10px dashed red; - background-color: rgba(0, 0, 0, .05); -} - -.mobileInkOverlay-border { - // background-color: rgba(0, 255, 0, .4); - position: absolute; - pointer-events: auto; - cursor: pointer; - - &.top { - width: calc(100% + 20px); - height: 10px; - top: -10px; - left: -10px; - } - - &.left { - width: 10px; - height: calc(100% + 20px); - top: -10px; - left: -10px; - } - - &.right { - width: 10px; - height: calc(100% + 20px); - top: -10px; - right: -10px; - } - - &.bottom { - width: calc(100% + 20px); - height: 10px; - bottom: -10px; - left: -10px; - } -} \ No newline at end of file diff --git a/src/mobile/MobileInkOverlay.tsx b/src/mobile/MobileInkOverlay.tsx deleted file mode 100644 index 6babd2f39..000000000 --- a/src/mobile/MobileInkOverlay.tsx +++ /dev/null @@ -1,183 +0,0 @@ -import { action, observable } from 'mobx'; -import { observer } from 'mobx-react'; -import * as React from 'react'; -import { DocServer } from '../client/DocServer'; -import { DragManager } from '../client/util/DragManager'; -import { Doc } from '../fields/Doc'; -import { Gestures } from '../pen-gestures/GestureTypes'; -import { GestureContent, MobileDocumentUploadContent, MobileInkOverlayContent, UpdateMobileInkOverlayPositionContent } from '../server/Message'; -import './MobileInkOverlay.scss'; - -@observer -export default class MobileInkOverlay extends React.Component { - public static Instance: MobileInkOverlay; - - @observable private _scale: number = 1; - @observable private _width: number = 0; - @observable private _height: number = 0; - @observable private _x: number = -300; - @observable private _y: number = -300; - @observable private _text: string = ''; - - @observable private _offsetX: number = 0; - @observable private _offsetY: number = 0; - @observable private _isDragging: boolean = false; - private _mainCont: React.RefObject = React.createRef(); - - constructor(props: Readonly<{}>) { - super(props); - MobileInkOverlay.Instance = this; - } - - initialSize(mobileWidth: number, mobileHeight: number) { - const maxWidth = window.innerWidth - 30; - const maxHeight = window.innerHeight - 30; // -30 for padding - if (mobileWidth > maxWidth || mobileHeight > maxHeight) { - const scale = Math.min(maxWidth / mobileWidth, maxHeight / mobileHeight); - return { width: mobileWidth * scale, height: mobileHeight * scale, scale: scale }; - } - return { width: mobileWidth, height: mobileHeight, scale: 1 }; - } - - @action - initMobileInkOverlay(content: MobileInkOverlayContent) { - const { width, height, text } = content; - const scaledSize = this.initialSize(width ? width : 0, height ? height : 0); - this._width = scaledSize.width; - this._height = scaledSize.height; - this._scale = scaledSize.scale; - this._x = 300; // TODO: center on screen - this._y = 25; // TODO: center on screen - this._text = text ? text : ''; - } - - @action - updatePosition(content: UpdateMobileInkOverlayPositionContent) { - const { dx, dy, dsize } = content; - if (dx) this._x += dx; - if (dy) this._y += dy; - // TODO: scale dsize - } - - drawStroke = (content: GestureContent) => { - // TODO: figure out why strokes drawn in corner of mobile interface dont get inserted - - const { points, bounds } = content; - console.log('received points', points, bounds); - - const B = { - right: bounds.right * this._scale + this._x, - left: bounds.left * this._scale + this._x, // TODO: scale - bottom: bounds.bottom * this._scale + this._y, - top: bounds.top * this._scale + this._y, // TODO: scale - width: bounds.width * this._scale, - height: bounds.height * this._scale, - }; - - const target = document.elementFromPoint(this._x + 10, this._y + 10); - target?.dispatchEvent( - new CustomEvent('dashOnGesture', { - bubbles: true, - detail: { - points: points, - gesture: Gestures.Stroke, - bounds: B, - }, - }) - ); - }; - - uploadDocument = async (content: MobileDocumentUploadContent) => { - const { docId } = content; - const doc = await DocServer.GetRefField(docId); - - if (doc && doc instanceof Doc) { - const target = document.elementFromPoint(this._x + 10, this._y + 10); - const dragData = new DragManager.DocumentDragData([doc]); - const complete = new DragManager.DragCompleteEvent(false, dragData); - - if (target) { - console.log('dispatching upload doc!!!!', target, doc); - target.dispatchEvent( - new CustomEvent('dashOnDrop', { - bubbles: true, - detail: { - x: this._x, - y: this._y, - complete: complete, - altKey: false, - metaKey: false, - ctrlKey: false, - shiftKey: false, - embedKey: false, - }, - }) - ); - } else { - alert('TARGET IS UNDEFINED'); - } - } - }; - - @action - dragStart = (e: React.PointerEvent) => { - document.removeEventListener('pointermove', this.dragging); - document.removeEventListener('pointerup', this.dragEnd); - document.addEventListener('pointermove', this.dragging); - document.addEventListener('pointerup', this.dragEnd); - - this._isDragging = true; - this._offsetX = e.pageX - this._mainCont.current!.getBoundingClientRect().left; - this._offsetY = e.pageY - this._mainCont.current!.getBoundingClientRect().top; - - e.preventDefault(); - e.stopPropagation(); - }; - - @action - dragging = (e: PointerEvent) => { - const x = e.pageX - this._offsetX; - const y = e.pageY - this._offsetY; - - // TODO: don't allow drag over library? - this._x = Math.min(Math.max(x, 0), window.innerWidth - this._width); - this._y = Math.min(Math.max(y, 0), window.innerHeight - this._height); - - e.preventDefault(); - e.stopPropagation(); - }; - - @action - dragEnd = (e: PointerEvent) => { - document.removeEventListener('pointermove', this.dragging); - document.removeEventListener('pointerup', this.dragEnd); - - this._isDragging = false; - - e.preventDefault(); - e.stopPropagation(); - }; - - render() { - return ( -
-

{this._text}

-
-
-
-
-
- ); - } -} diff --git a/src/mobile/MobileInterface.scss b/src/mobile/MobileInterface.scss deleted file mode 100644 index 4b32c3da0..000000000 --- a/src/mobile/MobileInterface.scss +++ /dev/null @@ -1,445 +0,0 @@ -$navbar-height: 120px; -$pathbar-height: 50px; - -@media only screen and (max-device-width: 480px) { - * { - margin: 0px; - padding: 0px; - box-sizing: border-box; - font-family: sans-serif; - } -} - -body { - overflow: hidden; -} - -.mobileInterface-container { - height: 100%; - position: relative; - touch-action: none; - width: 100%; - - -webkit-touch-callout: none; - -webkit-user-select: none; - -khtml-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none; - -webkit-tap-highlight-color: rgba(0, 0, 0, 0); -} - -// Topbar of Dash Mobile -.navbar { - position: fixed; - top: 0px; - left: 0px; - width: 100vw; - height: $navbar-height; - background-color: whitesmoke; - z-index: 150; - - .cover { - position: absolute; - right: 0px; - top: 0px; - height: 120px; - width: 120px; - background-color: whitesmoke; - z-index: 200; - } - - .toggle-btn { - position: absolute; - right: 20px; - top: 30px; - height: 70px; - width: 70px; - transition: all 400ms ease-in-out 200ms; - z-index: 180; - } - - .background { - position: absolute; - right: 0px; - top: 0px; - height: 120px; - width: 120px; - //border: 1px solid black; - } - - .background.active { - background-color: lightgrey; - } - - .toggle-btn-home { - right: -200px; - } - - .header { - position: absolute; - top: 50%; - top: calc(9px + 50%); - right: 50%; - transform: translate(50%, -50%); - font-size: 40; - font-weight: 700; - text-align: center; - user-select: none; - text-transform: uppercase; - font-family: Arial, Helvetica, sans-serif; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - direction: ltr; - width: 600px; - } - - .toggle-btn span { - position: absolute; - top: 50%; - left: 50%; - transform: translate(-50%, -50%); - width: 70%; - height: 4px; - background: black; - transition: all 200ms ease; - z-index: 180; - } - - .toggle-btn span:nth-child(1) { - transition: top 200ms ease-in-out; - top: 30%; - } - - .toggle-btn span:nth-child(3) { - transition: top 200ms ease-in-out; - top: 70%; - } - - .toggle-btn.active { - transition: transform 200ms ease-in-out 200ms; - transform: rotate(135deg); - } - - .toggle-btn.active span:nth-child(1) { - top: 50%; - } - - .toggle-btn.active span:nth-child(2) { - transform: translate(-50%, -50%) rotate(90deg); - } - - .toggle-btn.active span:nth-child(3) { - top: 50%; - } -} - -.sidebar { - position: fixed; - top: 120px; - opacity: 0; - right: -100%; - width: 80%; - height: calc(80% - (120px)); - z-index: 101; - background-color: whitesmoke; - transition: all 400ms ease 50ms; - padding: 20px; - box-shadow: 0 0 5px 5px grey; - - .item { - width: 100%; - padding: 13px 12px; - border-bottom: 1px solid rgba(200, 200, 200, 0.7); - font-family: Arial, Helvetica, sans-serif; - font-style: normal; - font-weight: normal; - user-select: none; - display: inline-flex; - font-size: 35px; - text-transform: uppercase; - color: black; - } - - .ink:focus { - outline: 1px solid blue; - } - - .sidebarButtons { - top: 80px; - position: relative; - } -} - - - - - - -.blanket { - position: fixed; - top: 120px; - opacity: 0.5; - right: -100%; - width: 100%; - height: calc(100% - (120px)); - z-index: 101; - background-color: grey; - padding: 20px; -} - -.blanket.active { - position: absolute; - right: 0%; - z-index: 100; -} - -.home { - position: absolute; - top: 30px; - left: 30px; - font-size: 60; - user-select: none; - text-transform: uppercase; - font-family: Arial, Helvetica, sans-serif; - z-index: 200; -} - -.item-type { - display: inline; - text-transform: lowercase; - margin-left: 20px; - font-size: 35px; - font-style: italic; - color: rgb(28, 28, 28); -} - -.item-title { - max-width: 70%; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; -} - -.right { - margin-left: 20px; - z-index: 200; -} - -.open { - right: 20px; - font-size: 35; - position: absolute; -} - -.left { - width: 100%; - height: 100%; -} - - - -.sidebar.active { - position: absolute; - right: 0%; - opacity: 1; - z-index: 101; -} - -.back { - position: absolute; - left: 42px; - top: 0; - background: #1a1a1a; - width: 50px; - height: 100%; - display: flex; - justify-content: center; - text-align: center; - flex-direction: column; - align-items: center; - border-radius: 10px; - font-size: 25px; - user-select: none; - z-index: 100; -} - -.pathbar { - position: fixed; - top: 118px; - left: 0px; - background: #1a1a1a; - z-index: 120; - border-radius: 0px; - width: 100%; - height: 80px; - overflow: hidden; - - .pathname { - position: relative; - font-size: 25; - top: 50%; - width: 86%; - left: 12%; - color: whitesmoke; - transform: translate(0%, -50%); - z-index: 20; - font-family: sans-serif; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - direction: rtl; - text-align: left; - text-transform: uppercase; - } - - .scrollmenu { - overflow: auto; - width: 100%; - height: 100%; - white-space: nowrap; - display: inline-flex; - } - - .hidePath { - position: absolute; - height: 100%; - width: 200px; - left: 0px; - top: 0px; - background-image: linear-gradient(to right, #1a1a1a, rgba(0, 0, 0, 0)); - text-align: center; - user-select: none; - z-index: 99; - pointer-events: none; - } - - .pathbarItem { - position: relative; - display: flex; - align-items: center; - color: whitesmoke; - text-align: center; - justify-content: center; - user-select: none; - transform: translate(100px, 0px); - font-size: 30px; - padding: 10px; - text-transform: uppercase; - - .pathbarText { - font-family: sans-serif; - text-align: center; - height: 50px; - padding: 10px; - font-size: 30px; - border-radius: 10px; - text-transform: uppercase; - margin-left: 20px; - position: relative; - } - - .pathIcon { - transform: translate(0px, 0px); - position: relative; - } - } -} - - -/** -* docButton appears at the bottom of mobile document -* Buttons include: pin to presentation, download, upload, reload -*/ -.docButton { - position: relative; - width: 100px; - display: flex; - height: 100px; - font-size: 70px; - text-align: center; - border: 3px solid black; - margin: 20px; - z-index: 100; - border-radius: 100%; - justify-content: center; - flex-direction: column; - align-items: center; -} - -.docButtonContainer { - top: 80%; - position: absolute; - display: flex; - transform: translate(-50%, 0); - left: 50%; - z-index: 100; -} - -.toolbar { - left: 50%; - transform: translate(-50%); - position: absolute; - height: max-content; - top: 0px; - border-radius: 20px; - background-color: lightgrey; - opacity: 0; - transition: all 400ms ease 50ms; -} - -.toolbar.active { - display: inline-block; - width: 300px; - padding: 5px; - opacity: 1; - height: max-content; - top: -450px; -} - -.colorSelector { - position: absolute; - top: 550px; - left: 280px; - transform: translate(-50%, 0); - z-index: 100; - display: inline-flex; - width: max-content; - height: max-content; - pointer-events: all; - font-size: 80px; - user-select: none; -} - -// Menu buttons for toggling between list and icon view -.homeSwitch { - position: fixed; - top: 212; - right: 36px; - display: inline-flex; - width: max-content; - z-index: 99; - height: 70px; - - .list { - width: 70px; - height: 70px; - margin: 5; - padding: 10; - align-items: center; - text-align: center; - font-size: 50; - border-style: solid; - border-width: 3; - border-color: black; - background: whitesmoke; - align-self: center; - border-radius: 10px; - } - - .list.active { - color: darkred; - border-color: darkred; - } -} \ No newline at end of file diff --git a/src/mobile/MobileInterface.tsx b/src/mobile/MobileInterface.tsx deleted file mode 100644 index 4f37c45a8..000000000 --- a/src/mobile/MobileInterface.tsx +++ /dev/null @@ -1,871 +0,0 @@ -import { library } from '@fortawesome/fontawesome-svg-core'; -import { - faAddressCard, - faAlignLeft, - faAlignRight, - faAngleDoubleLeft, - faAngleRight, - faArrowDown, - faArrowLeft, - faArrowRight, - faArrowUp, - faArrowsAltH, - faAsterisk, - faBars, - faBell, - faBolt, - faBook, - faBrain, - faBullseye, - faCalculator, - faCamera, - faCaretDown, - faCaretLeft, - faCaretRight, - faCaretSquareDown, - faCaretSquareRight, - faCaretUp, - faCat, - faCheck, - faChevronLeft, - faChevronRight, - faClipboard, - faClone, - faCloudUploadAlt, - faCommentAlt, - faCompressArrowsAlt, - faCut, - faEdit, - faEllipsisV, - faEraser, - faExclamation, - faExpand, - faExternalLinkAlt, - faExternalLinkSquareAlt, - faEye, - faFileAlt, - faFileAudio, - faFileDownload, - faFilePdf, - faFilm, - faFilter, - faFolderOpen, - faFont, - faGlobeAsia, - faHandPointLeft, - faHighlighter, - faHome, - faImage, - faLocationArrow, - faLongArrowAltLeft, - faLongArrowAltRight, - faMicrophone, - faCircleHalfStroke, - faMinus, - faMobile, - faMousePointer, - faMusic, - faObjectGroup, - faPaintBrush, - faPalette, - faPause, - faPen, - faPenNib, - faPhone, - faPlay, - faPlus, - faPortrait, - faQuestionCircle, - faQuoteLeft, - faRedoAlt, - faReply, - faSearch, - faStamp, - faStickyNote, - faStop, - faTasks, - faTerminal, - faTh, - faThLarge, - faThumbtack, - faTimes, - faToggleOn, - faTrash, - faTrashAlt, - faTree, - faTv, - faUndoAlt, - faVideo, - faWindowClose, - faWindowMaximize, - faFile as fileSolid, -} from '@fortawesome/free-solid-svg-icons'; -import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { action, computed, observable, runInAction } from 'mobx'; -import { observer } from 'mobx-react'; -import * as React from 'react'; -import { returnEmptyDoclist, returnEmptyFilter, returnFalse, returnTrue } from '../ClientUtils'; -import { CollectionViewType, DocumentType } from '../client/documents/DocumentTypes'; -import { Docs, DocumentOptions } from '../client/documents/Documents'; -import { CurrentUserUtils } from '../client/util/CurrentUserUtils'; -import { ScriptingGlobals } from '../client/util/ScriptingGlobals'; -import { SettingsManager } from '../client/util/SettingsManager'; -import { Transform } from '../client/util/Transform'; -import { UndoManager } from '../client/util/UndoManager'; -import { DashboardView } from '../client/views/DashboardView'; -import { GestureOverlay } from '../client/views/GestureOverlay'; -import { AudioBox } from '../client/views/nodes/AudioBox'; -import { DocumentView } from '../client/views/nodes/DocumentView'; -import { RadialMenu } from '../client/views/nodes/RadialMenu'; -import { RichTextMenu } from '../client/views/nodes/formattedText/RichTextMenu'; -import { Doc, DocListCast } from '../fields/Doc'; -import { InkTool } from '../fields/InkField'; -import { List } from '../fields/List'; -import { ScriptField } from '../fields/ScriptField'; -import { Cast, FieldValue, StrCast } from '../fields/Types'; -import './AudioUpload.scss'; -import { Uploader } from './ImageUpload'; -import './ImageUpload.scss'; -import './MobileInterface.scss'; -import { emptyFunction } from '../Utils'; - -library.add( - ...[ - faTasks, - faReply, - faQuoteLeft, - faHandPointLeft, - faFolderOpen, - faAngleDoubleLeft, - faExternalLinkSquareAlt, - faMobile, - faThLarge, - faWindowClose, - faEdit, - faTrashAlt, - faPalette, - faAngleRight, - faBell, - faTrash, - faCamera, - faExpand, - faCaretDown, - faCaretLeft, - faCaretRight, - faCaretSquareDown, - faCaretSquareRight, - faArrowsAltH, - faPlus, - faMinus, - faTerminal, - faToggleOn, - fileSolid, - faExternalLinkAlt, - faLocationArrow, - faSearch, - faFileDownload, - faStop, - faCalculator, - faWindowMaximize, - faAddressCard, - faQuestionCircle, - faArrowLeft, - faArrowRight, - faArrowDown, - faArrowUp, - faBolt, - faBullseye, - faCaretUp, - faCat, - faCheck, - faChevronRight, - faClipboard, - faClone, - faCloudUploadAlt, - faCommentAlt, - faCompressArrowsAlt, - faCut, - faEllipsisV, - faEraser, - faExclamation, - faFileAlt, - faFileAudio, - faFilePdf, - faFilm, - faFilter, - faFont, - faGlobeAsia, - faHighlighter, - faLongArrowAltRight, - faMicrophone, - faCircleHalfStroke, - faMousePointer, - faMusic, - faObjectGroup, - faPause, - faPen, - faPenNib, - faPhone, - faPlay, - faPortrait, - faRedoAlt, - faStamp, - faStickyNote, - faThumbtack, - faTree, - faTv, - faUndoAlt, - faBook, - faVideo, - faAsterisk, - faBrain, - faImage, - faPaintBrush, - faTimes, - faEye, - faHome, - faLongArrowAltLeft, - faBars, - faTh, - faChevronLeft, - faAlignLeft, - faAlignRight, - ].map(m => m as any) -); - -@observer -export class MobileInterface extends React.Component { - static Instance: MobileInterface; - private _library: Doc; - private _mainDoc: any = CurrentUserUtils.setupActiveMobileMenu(Doc.UserDoc()); - @observable private _sidebarActive: boolean = false; //to toggle sidebar display - @observable private _imageUploadActive: boolean = false; //to toggle image upload - @observable private _audioUploadActive: boolean = false; - @observable private _menuListView: boolean = false; //to switch between menu view (list / icon) - @observable private _ink: boolean = false; //toggle whether ink is being dispalyed - @observable private _homeMenu: boolean = true; // to determine whether currently at home menu - @observable private dashboards: Doc | null = null; // currently selected document - @observable private _activeDoc: Doc = this._mainDoc; // doc updated as the active mobile page is updated (initially home menu) - @observable private _homeDoc: Doc = this._mainDoc; // home menu as a document - @observable private _parents: Array = []; // array of parent docs (for pathbar) - - @computed private get mainContainer() { - return Doc.UserDoc() ? FieldValue(Cast(Doc.UserDoc().activeMobile, Doc)) : Doc.GuestMobile; - } - - constructor(props: Readonly<{}>) { - super(props); - this._library = CurrentUserUtils.setupDashboards(Doc.UserDoc(), 'myDashboards'); // to access documents in Dash Web - MobileInterface.Instance = this; - } - - @action - componentDidMount() { - // if the home menu is in list view -> adjust the menu toggle appropriately - this._menuListView = this._homeDoc._type_collection === 'stacking' ? true : false; - Doc.ActiveTool = InkTool.None; // ink should intially be set to none - Doc.UserDoc().activeMobile = this._homeDoc; // active mobile set to home - - // remove double click to avoid mobile zoom in - document.removeEventListener('dblclick', this.onReactDoubleClick); - document.addEventListener('dblclick', this.onReactDoubleClick); - } - - @action - componentWillUnmount = () => { - document.removeEventListener('dblclick', this.onReactDoubleClick); - }; - - // Prevent zooming in when double tapping the screen - onReactDoubleClick = (e: MouseEvent) => { - e.stopPropagation(); - }; - - // Switch the mobile view to the given doc - @action - switchCurrentView = (doc: Doc, renderView?: () => JSX.Element, onSwitch?: () => void) => { - if (!Doc.UserDoc()) return; - if (this._activeDoc === this._homeDoc) { - this._parents.push(this._activeDoc); - this._homeMenu = false; - } - this._activeDoc = doc; - Doc.UserDoc().activeMobile = doc; - onSwitch?.(); - - // Ensures that switching to home is not registed - UndoManager.undoStack.length = 0; - UndoManager.redoStack.length = 0; - }; - - // For toggling the hamburger menu - @action - toggleSidebar = () => { - this._sidebarActive = !this._sidebarActive; - - if (this._ink) { - this.onSwitchInking(); - } - }; - /** - * Method called when 'Library' button is pressed on the home screen - */ - switchToLibrary = async () => { - this.switchCurrentView(this._library); - runInAction(() => (this._homeMenu = false)); - this.toggleSidebar(); - }; - - /** - * Back method for navigating through items - */ - @action - back = () => { - const header = document.getElementById('header') as HTMLElement; - const doc = Cast(this._parents.pop(), Doc) as Doc; // Parent document - // Case 1: Parent document is 'dashboards' - if (doc === (Cast(this._library, Doc) as Doc)) { - this.dashboards = null; - this.switchCurrentView(this._library); - // Case 2: Parent document is the 'home' menu (root node) - } else if (doc === (Cast(this._homeDoc, Doc) as Doc)) { - this._homeMenu = true; - this._parents = []; - this.dashboards = null; - this.switchCurrentView(this._homeDoc); - // Case 3: Parent document is any document - } else if (doc) { - this.dashboards = doc; - this.switchCurrentView(doc); - this._homeMenu = false; - header.textContent = String(doc.title); - } - this._ink = false; // turns ink off - }; - - /** - * Return 'Home", which implies returning to 'Home' menu buttons - */ - @action - returnHome = () => { - if (!this._homeMenu || this._sidebarActive) { - this._homeMenu = true; - this._parents = []; - this.dashboards = null; - this.switchCurrentView(this._homeDoc); - } - if (this._sidebarActive) { - this.toggleSidebar(); - } - }; - - /** - * Return to primary Dashboard in library (Dashboards Doc) - */ - @action - returnMain = () => { - this._parents = [this._homeDoc]; - this.switchCurrentView(this._library); - this._homeMenu = false; - this.dashboards = null; - }; - - /** - * Note: window.innerWidth and window.screen.width compute different values. - * window.screen.width is the display size, however window.innerWidth is the - * display resolution which computes differently. - */ - returnWidth = () => window.innerWidth; //The windows width - returnHeight = () => window.innerHeight - 300; //Calculating the windows height (-300 to account for topbar) - whitebackground = () => 'white'; - /** - * DocumentView for graphic display of all documents - */ - @computed get displayDashboards() { - return !this.mainContainer ? null : ( -
- -
- ); - } - - /** - * Handles the click functionality in the library panel. - * Navigates to the given doc and updates the sidebar. - * @param doc: doc for which the method is called - */ - handleClick = async (doc: Doc) => { - runInAction(() => { - if (doc.type !== 'collection' && this._sidebarActive) { - this._parents.push(this._activeDoc); - this.switchCurrentView(doc); - this._homeMenu = false; - this.toggleSidebar(); - } else { - this._parents.push(this._activeDoc); - this.switchCurrentView(doc); - this._homeMenu = false; - this.dashboards = doc; - } - }); - }; - - /** - * Called when an item in the library is clicked and should - * be opened (open icon on RHS of all menu items) - * @param doc doc to be opened - */ - @action - openFromSidebar = (doc: Doc) => { - this._parents.push(this._activeDoc); - this.switchCurrentView(doc); - this._homeMenu = false; - this.dashboards = doc; - this.toggleSidebar(); - }; - - // Renders the graphical pathbar - renderPathbar = () => { - const docPath = [...this._parents, this._activeDoc]; - const items = docPath.map((doc: Doc, index: any) => ( -
- {index === 0 ? null : } -
this.handlePathClick(doc, index)}> - {StrCast(doc.title)} -
-
- )); - return ( -
-
{items}
- {!this._parents.length ? null : ( -
- -
- )} -
-
- ); - }; - - // Handles when user clicks on a document in the pathbar - @action - handlePathClick = async (doc: Doc, index: number) => { - const library = await this._library; - if (doc === library) { - this.dashboards = null; - this.switchCurrentView(doc); - this._parents.length = index; - } else if (doc === this._homeDoc) { - this.returnHome(); - } else { - this.dashboards = doc; - this.switchCurrentView(doc); - this._parents.length = index; - } - }; - - // Renders the contents of the menu and sidebar - @computed get renderDefaultContent() { - if (this._homeMenu) { - return ( -
-
- - -
e.stopPropagation()}>
- -
- {this.renderPathbar()} -
- ); - } - // stores dashboards documents as 'dashboards' variable - let dashboards = Doc.MyDashboards; - if (this.dashboards) { - dashboards = this.dashboards; - } - // returns a list of navbar buttons as 'buttons' - const buttons = DocListCast(dashboards.data).map((doc: Doc, index: any) => { - if (doc.type !== 'ink') { - return ( -
-
this.handleClick(doc)}> - {' '} - {doc.title as string}{' '} -
-
this.handleClick(doc)}> - {doc.type as string} -
- this.handleClick(doc)} className="right" icon="angle-right" size="lg" style={{ display: `${doc.type === 'collection' ? 'block' : 'none'}` }} /> - this.openFromSidebar(doc)} icon="external-link-alt" size="lg" /> -
- ); - } - }); - - return ( -
-
- - -
- - - -
-
-
- {this.renderPathbar()} -
-
- {this.dashboards ? ( - <> - {buttons} -
- -
Return to dashboards
-
- - ) : ( - <> - {buttons} -
this.createNewDashboard()}> - -
Create New Dashboard
-
- - )} -
-
-
-
- ); - } - - /** - * Handles the 'Create New Dashboard' button in the menu (taken from MainView.tsx) - */ - @action - createNewDashboard = (id?: string) => { - const scens = Doc.MyDashboards; - const dashboardCount = DocListCast(scens.data).length + 1; - const freeformOptions: DocumentOptions = { - x: 0, - y: 400, - title: 'Collection ' + dashboardCount, - }; - - const freeformDoc = Doc.GuestTarget || Docs.Create.FreeformDocument([], freeformOptions); - const dashboardDoc = DashboardView.StandardCollectionDockingDocument([{ doc: freeformDoc, initialWidth: 600 }], { title: `Dashboard ${dashboardCount}` }, id, 'row'); - - const toggleComic = ScriptField.MakeScript(`toggleComicMode()`); - const cloneDashboard = ScriptField.MakeScript(`cloneDashboard()`); - dashboardDoc.contextMenuScripts = new List([toggleComic!, cloneDashboard!]); - dashboardDoc.contextMenuLabels = new List(['Toggle Comic Mode', 'New Dashboard Layout']); - - Doc.AddDocToList(scens, 'data', dashboardDoc); - }; - - // Button for switching between pen and ink mode - @action - onSwitchInking = () => { - const button = document.getElementById('inkButton') as HTMLElement; - button.style.backgroundColor = this._ink ? 'white' : 'black'; - button.style.color = this._ink ? 'black' : 'white'; - - if (!this._ink) { - Doc.ActiveTool = InkTool.Pen; - this._ink = true; - } else { - Doc.ActiveTool = InkTool.None; - this._ink = false; - } - }; - - // The static ink menu that appears at the top - @computed get inkMenu() { - return this._activeDoc._type_collection !== CollectionViewType.Docking || !this._ink ? null :
{/* */}
; - } - - // DocButton that uses UndoManager and handles the opacity change if CanUndo is true - @computed get undo() { - if (this.mainContainer && this._activeDoc.type === 'collection' && this._activeDoc !== this._homeDoc && this._activeDoc !== Doc.SharingDoc() && this._activeDoc.title !== 'WORKSPACES') { - return ( -
{ - UndoManager.Undo(); - e.stopPropagation(); - }}> - -
- ); - } else return null; - } - - // DocButton that uses UndoManager and handles the opacity change if CanRedo is true - @computed get redo() { - if (this.mainContainer && this._activeDoc.type === 'collection' && this._activeDoc !== this._homeDoc && this._activeDoc !== Doc.SharingDoc() && this._activeDoc.title !== 'WORKSPACES') { - return ( -
{ - UndoManager.Redo(); - e.stopPropagation(); - }}> - -
- ); - } else return null; - } - - // DocButton for switching into ink mode - @computed get drawInk() { - return !this.mainContainer || this._activeDoc._type_collection !== CollectionViewType.Docking ? null : ( -
- -
- ); - } - - // DocButton: Button that appears on the bottom of the screen to initiate image upload - @computed get uploadImageButton() { - if (this._activeDoc.type === DocumentType.COL && this._activeDoc !== this._homeDoc && this._activeDoc._type_collection !== CollectionViewType.Docking && this._activeDoc.title !== 'WORKSPACES') { - return ( -
- -
- ); - } else return null; - } - - // DocButton to download images on the mobile - @computed get downloadDocument() { - if (this._activeDoc.type === 'image' || this._activeDoc.type === 'pdf' || this._activeDoc.type === 'video') { - return ( -
window.open(this._activeDoc['data-path']?.toString())}> - {' '} - {/* daa-path holds the url */} - -
- ); - } else return null; - } - - // DocButton for pinning images to presentation - @computed get pinToPresentation() { - // Only making button available if it is an image - if (!(this._activeDoc.type === 'collection' || this._activeDoc.type === 'presentation')) { - return ( -
DocumentView.PinDoc(this._activeDoc, {})}> - -
- ); - } else return null; - } - - // Buttons for switching the menu between large and small icons - @computed get switchMenuView() { - return this._activeDoc.title !== this._homeDoc.title ? null : ( -
-
- -
-
- -
-
- ); - } - - // Logic for switching the menu into the icons - @action - changeToIconView = () => { - if ((this._homeDoc._type_collection = 'stacking')) { - this._menuListView = false; - this._homeDoc._type_collection = 'masonry'; - this._homeDoc.columnWidth = 300; - this._homeDoc._columnWidth = 300; - const menuButtons = DocListCast(this._homeDoc.data); - menuButtons.map(doc => { - const buttonData = DocListCast(doc.data); - buttonData[1]._nativeWidth = 0.1; - buttonData[1]._width = 0.1; - buttonData[1]._dimMagnitude = 0; - buttonData[1]._opacity = 0; - doc._nativeWidth = 400; - }); - } - }; - - // Logic for switching the menu into the stacking view - @action - changeToListView = () => { - if ((this._homeDoc._type_collection = 'masonry')) { - this._homeDoc._type_collection = 'stacking'; - this._menuListView = true; - const menuButtons = DocListCast(this._homeDoc.data); - menuButtons.map(doc => { - const buttonData = DocListCast(doc.data); - buttonData[1]._nativeWidth = 450; - buttonData[1]._dimMagnitude = 2; - buttonData[1]._opacity = 1; - doc._nativeWidth = 900; - }); - } - }; - - // For setting up the presentation document for the home menu - @action - setupDefaultPresentation = () => { - const presentation = Doc.ActivePresentation; - - if (presentation) { - this.switchCurrentView(presentation); - this._homeMenu = false; - } - }; - - // For toggling image upload pop up - @action - toggleUpload = () => (this._imageUploadActive = !this._imageUploadActive); - - // For toggling audio record and dictate pop up - @action - toggleAudio = () => (this._audioUploadActive = !this._audioUploadActive); - - // Button for toggling the upload pop up in a collection - @action - toggleUploadInCollection = () => { - const button = document.getElementById('imageButton') as HTMLElement; - button.style.backgroundColor = this._imageUploadActive ? 'white' : 'black'; - button.style.color = this._imageUploadActive ? 'black' : 'white'; - - this._imageUploadActive = !this._imageUploadActive; - }; - - // For closing the image upload pop up - @action - closeUpload = () => { - this._imageUploadActive = false; - }; - - // Returns the image upload pop up - @computed get uploadImage() { - const doc = !this._homeMenu ? this._activeDoc : (Cast(Doc.SharingDoc(), Doc) as Doc); - return ; - } - - // Radial menu can only be used if it is a colleciton and it is not a homeDoc - // (and cannot be used on Dashboard to avoid pin to presentation opening on right) - @computed get displayRadialMenu() { - return this._activeDoc.type === 'collection' && this._activeDoc !== this._homeDoc && this._activeDoc._type_collection !== CollectionViewType.Docking ? : null; - } - - onDragOver = (e: React.DragEvent) => { - e.preventDefault(); - e.stopPropagation(); - }; - - /** - * MENU BUTTON - * Switch view from mobile menu to access the mobile uploads - * Global function name: openMobileUploads() - */ - @action - switchToMobileUploads = () => { - const mobileUpload = Cast(Doc.SharingDoc(), Doc) as Doc; - this.switchCurrentView(mobileUpload); - this._homeMenu = false; - }; - - render() { - return ( -
- -
{this.uploadImage}
- {this.switchMenuView} - {this.inkMenu} - -
- -
-
- {this.pinToPresentation} - {this.downloadDocument} - {this.undo} - {this.redo} - {this.drawInk} - {this.uploadImageButton} -
- {this.displayDashboards} - {this.renderDefaultContent} -
- {this.displayRadialMenu} -
- ); - } -} - -//Global functions for mobile menu -ScriptingGlobals.add(function switchToMobileLibrary() { - return MobileInterface.Instance.switchToLibrary(); -}, 'opens the library to navigate through dashboards on Dash Mobile'); -ScriptingGlobals.add(function openMobileUploads() { - return MobileInterface.Instance.toggleUpload(); -}, 'opens the upload files menu for Dash Mobile'); -ScriptingGlobals.add(function switchToMobileUploadCollection() { - return MobileInterface.Instance.switchToMobileUploads(); -}, 'opens the mobile uploads collection on Dash Mobile'); -ScriptingGlobals.add(function openMobileAudio() { - return MobileInterface.Instance.toggleAudio(); -}, 'opens the record and dictate menu on Dash Mobile'); -ScriptingGlobals.add(function switchToMobilePresentation() { - return MobileInterface.Instance.setupDefaultPresentation(); -}, 'opens the presentation on Dash Mobile'); -ScriptingGlobals.add(function openMobileSettings() { - return SettingsManager.Instance.openMgr(); -}, 'opens settings on Dash Mobile'); - -// Other global functions for mobile -ScriptingGlobals.add( - function switchMobileView(doc: Doc, renderView?: () => JSX.Element, onSwitch?: () => void) { - return MobileInterface.Instance.switchCurrentView(doc, renderView, onSwitch); - }, - 'changes the active document displayed on the Dash Mobile', - '(doc: any)' -); diff --git a/src/mobile/MobileMain.tsx b/src/mobile/MobileMain.tsx deleted file mode 100644 index 07839b6f6..000000000 --- a/src/mobile/MobileMain.tsx +++ /dev/null @@ -1,26 +0,0 @@ -import * as React from 'react'; -import * as ReactDOM from 'react-dom'; -import { DocServer } from '../client/DocServer'; -import { Docs } from '../client/documents/Documents'; -import { CurrentUserUtils } from '../client/util/CurrentUserUtils'; -import { AssignAllExtensions } from '../extensions/Extensions'; -import { MobileInterface } from './MobileInterface'; - -AssignAllExtensions(); - -(async () => { - const info = await CurrentUserUtils.loadCurrentUser(); - DocServer.init(window.location.protocol, window.location.hostname, 4321, info.email + ' (mobile)'); - await Docs.Prototypes.initialize(); - await CurrentUserUtils.loadUserDocument(info); - document.getElementById('root')!.addEventListener( - 'wheel', - event => { - if (event.ctrlKey) { - event.preventDefault(); - } - }, - true - ); - ReactDOM.render(, document.getElementById('root')); -})(); diff --git a/src/mobile/MobileMenu.scss b/src/mobile/MobileMenu.scss deleted file mode 100644 index 7f286efc4..000000000 --- a/src/mobile/MobileMenu.scss +++ /dev/null @@ -1,271 +0,0 @@ -$navbar-height: 120px; -$pathbar-height: 50px; - -* { - margin: 0px; - padding: 0px; - box-sizing: border-box; - font-family: "Open Sans"; -} - -body { - overflow: hidden; -} - -.navbar { - position: fixed; - top: 0px; - left: 0px; - width: 100vw; - height: $navbar-height; - background-color: whitesmoke; - border-bottom: 5px solid black; -} - -.navbar .toggle-btn { - position: absolute; - right: 20px; - top: 30px; - height: 70px; - width: 70px; - transition: all 300ms ease-in-out 200ms; -} - -.navbar .header { - position: absolute; - top: 50%; - top: calc(9px + 50%); - right: 50%; - transform: translate(50%, -50%); - font-size: 40; - user-select: none; - text-transform: uppercase; - font-family: Arial, Helvetica, sans-serif; -} - -.navbar .toggle-btn span { - position: absolute; - top: 50%; - left: 50%; - transform: translate(-50%, -50%); - width: 70%; - height: 4px; - background: black; - transition: all 200ms ease; -} - -.navbar .toggle-btn span:nth-child(1) { - transition: top 200ms ease-in-out; - top: 30%; -} - -.navbar .toggle-btn span:nth-child(3) { - transition: top 200ms ease-in-out; - top: 70%; -} - -.navbar .toggle-btn.active { - transition: transform 200ms ease-in-out 200ms; - transform: rotate(135deg); -} - -.navbar .toggle-btn.active span:nth-child(1) { - top: 50%; -} - -.navbar .toggle-btn.active span:nth-child(2) { - transform: translate(-50%, -50%) rotate(90deg); -} - -.navbar .toggle-btn.active span:nth-child(3) { - top: 50%; -} -// .navbar .home { -// position: relative; -// right: 5px; -// transform: translate(50%, -50%); -// font-size: 40; -// user-select: none; -// text-transform: uppercase; -// font-family: Arial, Helvetica, sans-serif; -// z-index: 200; -// } - -.sidebar { - position: absolute; - top: 200px; - opacity: 0; - right: -100%; - width: 100%; - height: calc(100% - (200px)); - z-index: 5; - background-color: whitesmoke; - transition: all 400ms ease 50ms; - padding: 20px; - // overflow-y: auto; - // -webkit-overflow-scrolling: touch; - - // border-right: 5px solid black; -} - -.sidebar .item { - width: 100%; - padding: 13px 12px; - border-bottom: 1px solid rgba(200, 200, 200, 0.7); - font-family: Arial, Helvetica, sans-serif; - font-style: normal; - font-weight: normal; - user-select: none; - font-size: 35px; - text-transform: uppercase; - color: black; - -} - -.sidebar .ink { - width: 100%; - padding: 13px 12px; - border-bottom: 1px solid rgba(200, 200, 200, 0.7); - font-family: Arial, Helvetica, sans-serif; - font-style: normal; - font-weight: normal; - user-select: none; - font-size: 35px; - text-transform: uppercase; - color: black; -} - -.sidebar .ink:focus { - outline: 1px solid blue; -} - -.sidebar .home { - position: absolute; - top: -135px; - right: calc(50% + 80px); - transform: translate(0%, -50%); - font-size: 40; - user-select: none; - text-transform: uppercase; - font-family: Arial, Helvetica, sans-serif; - z-index: 200; -} - -.type { - display: inline; - text-transform: lowercase; - margin-left: 20px; - font-size: 35px; - font-style: italic; - color: rgb(28, 28, 28); -} - -.right { - margin-left: 20px; - z-index: 200; -} - -.left { - width: 100%; - height: 100%; -} - -.sidebar .logout { - width: 100%; - padding: 13px 12px; - border-bottom: 1px solid rgba(200, 200, 200, 0.7); - font-family: Arial, Helvetica, sans-serif; - font-style: normal; - font-weight: normal; - user-select: none; - font-size: 30px; - text-transform: uppercase; - color: black; -} - -.sidebar .settings { - width: 100%; - padding: 13px 12px; - border-bottom: 1px solid rgba(200, 200, 200, 0.7); - font-family: Arial, Helvetica, sans-serif; - font-style: normal; - font-weight: normal; - user-select: none; - font-size: 30px; - text-transform: uppercase; - color: black; -} - - -.sidebar.active { - right: 0%; - opacity: 1; -} - -.back { - position: absolute; - top: -140px; - left: 50px; - transform: translate(0%, -50%); - color: black; - font-size: 60; - user-select: none; - text-transform: uppercase; - z-index: 100; - font-family: Arial, Helvetica, sans-serif; -} - - -.pathbar { - position: absolute; - top: 118px; - background: #1a1a1a; - z-index: 20; - border-radius: 0px; - width: 100%; - height: 80px; - transition: all 400ms ease 50ms; -} - -.pathname { - position: relative; - font-size: 25; - top: 50%; - width: 90%; - left: 3%; - color: whitesmoke; - transform: translate(0%, -50%); - z-index: 20; - font-family: sans-serif; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - direction: rtl; - text-align: left; - text-transform: uppercase; -} - -.homeContainer { - position: relative; - top: 200px; - height: calc(100% - 250px); - width: 90%; - overflow: scroll; - left: 5%; - background-color: lightpink; -} - -.pinButton { - position: relative; - width: 100px; - height: 100px; - font-size: 90px; - text-align: center; - left: 50%; - transform: translate(-50%, 0); - border-style: solid; - border-radius: 50px; - border-width: medium; - background-color: pink; - z-index: 100; -} \ No newline at end of file diff --git a/webpack.config.js b/webpack.config.js index 9c74bf24e..e1afc64e5 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -53,8 +53,6 @@ module.exports = { viewer: ['./src/debug/Viewer.tsx', 'webpack-hot-middleware/client?reload=true'], repl: ['./src/debug/Repl.tsx', 'webpack-hot-middleware/client?reload=true'], test: ['./src/debug/Test.tsx', 'webpack-hot-middleware/client?reload=true'], - inkControls: ['./src/mobile/InkControls.tsx', 'webpack-hot-middleware/client?reload=true'], - mobileInterface: ['./src/client/views/Main.tsx', 'webpack-hot-middleware/client?reload=true'], }, devtool: 'source-map', output: { @@ -119,6 +117,10 @@ module.exports = { { loader: 'sass-loader' }, ], }, + { + test: /\.(txt|d)$/i, + type: 'asset/source', + }, // -------- // SCSS MODULES - all have .module. in their name and can export to .tsx -- cgit v1.2.3-70-g09d2 From 0974c8c92e48d5d278fb9bed79bc144fd79ddb1a Mon Sep 17 00:00:00 2001 From: bobzel Date: Mon, 12 Aug 2024 22:15:59 -0400 Subject: fixed typescript types module inclusion --- src/client/util/Scripting.ts | 4 +- src/client/util/type_decls.d | 224 ----------------------------------------- src/client/util/type_decls.txt | 224 ----------------------------------------- src/typings/index.d.ts | 27 ++--- src/typings/type_decls.d | 224 +++++++++++++++++++++++++++++++++++++++++ 5 files changed, 240 insertions(+), 463 deletions(-) delete mode 100644 src/client/util/type_decls.d delete mode 100644 src/client/util/type_decls.txt create mode 100644 src/typings/type_decls.d (limited to 'src') diff --git a/src/client/util/Scripting.ts b/src/client/util/Scripting.ts index b9e0943b6..c63d3d7cb 100644 --- a/src/client/util/Scripting.ts +++ b/src/client/util/Scripting.ts @@ -1,7 +1,7 @@ // export const ts = (window as any).ts; // import * as typescriptlib from '!!raw-loader!../../../node_modules/typescript/lib/lib.d.ts' // import * as typescriptes5 from '!!raw-loader!../../../node_modules/typescript/lib/lib.es5.d.ts' -import * as typescriptlib from './type_decls.d'; +import typescriptlib from 'type_decls.d'; import * as ts from 'typescript'; import { Doc, FieldType } from '../../fields/Doc'; import { RefField } from '../../fields/RefField'; @@ -248,7 +248,7 @@ export function CompileScript(script: string, options: ScriptOptions = {}): Comp const funcScript = `(function(${paramString})${reqTypes} { ${body} })`; host.writeFile('file.ts', funcScript); - if (typecheck) host.writeFile('node_modules/typescript/lib/lib.d.ts', typescriptlib.default); + if (typecheck) host.writeFile('node_modules/typescript/lib/lib.d.ts', typescriptlib); const program = ts.createProgram(['file.ts'], {}, host); const testResult = program.emit(); const outputText = host.readFile('file.js'); diff --git a/src/client/util/type_decls.d b/src/client/util/type_decls.d deleted file mode 100644 index 1a93bbe59..000000000 --- a/src/client/util/type_decls.d +++ /dev/null @@ -1,224 +0,0 @@ -//@ts-ignore -declare type PropertyKey = string | number | symbol; -interface Array { - length: number; - toString(): string; - toLocaleString(): string; - pop(): T | undefined; - push(...items: T[]): number; - concat(...items: ConcatArray[]): T[]; - concat(...items: (T | ConcatArray)[]): T[]; - join(separator?: string): string; - reverse(): T[]; - shift(): T | undefined; - slice(start?: number, end?: number): T[]; - sort(compareFn?: (a: T, b: T) => number): this; - splice(start: number, deleteCount?: number): T[]; - splice(start: number, deleteCount: number, ...items: T[]): T[]; - unshift(...items: T[]): number; - indexOf(searchElement: T, fromIndex?: number): number; - lastIndexOf(searchElement: T, fromIndex?: number): number; - every(callbackfn: (value: T, index: number, array: T[]) => boolean, thisArg?: any): boolean; - some(callbackfn: (value: T, index: number, array: T[]) => boolean, thisArg?: any): boolean; - forEach(callbackfn: (value: T, index: number, array: T[]) => void, thisArg?: any): void; - map(callbackfn: (value: T, index: number, array: T[]) => U, thisArg?: any): U[]; - filter(callbackfn: (value: T, index: number, array: T[]) => value is S, thisArg?: any): S[]; - filter(callbackfn: (value: T, index: number, array: T[]) => any, thisArg?: any): T[]; - reduce(callbackfn: (previousValue: T, currentValue: T, currentIndex: number, array: T[]) => T): T; - reduce(callbackfn: (previousValue: T, currentValue: T, currentIndex: number, array: T[]) => T, initialValue: T): T; - reduce(callbackfn: (previousValue: U, currentValue: T, currentIndex: number, array: T[]) => U, initialValue: U): U; - reduceRight(callbackfn: (previousValue: T, currentValue: T, currentIndex: number, array: T[]) => T): T; - reduceRight(callbackfn: (previousValue: T, currentValue: T, currentIndex: number, array: T[]) => T, initialValue: T): T; - reduceRight(callbackfn: (previousValue: U, currentValue: T, currentIndex: number, array: T[]) => U, initialValue: U): U; - - [n: number]: T; -} - -interface Function { - apply(this: Function, thisArg: any, argArray?: any): any; - call(this: Function, thisArg: any, ...argArray: any[]): any; - bind(this: Function, thisArg: any, ...argArray: any[]): any; - toString(): string; - - prototype: any; - readonly length: number; - - // Non-standard extensions - arguments: any; - caller: Function; -} -interface Boolean { - valueOf(): boolean; -} -interface Number { - toString(radix?: number): string; - toFixed(fractionDigits?: number): string; - toExponential(fractionDigits?: number): string; - toPrecision(precision?: number): string; - valueOf(): number; -} -interface IArguments { - [index: number]: any; - length: number; - callee: Function; -} -interface RegExp { - readonly flags: string; - readonly sticky: boolean; - readonly unicode: boolean; -} -interface Date { - now() : string; -} -interface String { - codePointAt(pos: number): number | undefined; - includes(searchString: string, position?: number): boolean; - endsWith(searchString: string, endPosition?: number): boolean; - normalize(form: "NFC" | "NFD" | "NFKC" | "NFKD"): string; - normalize(form?: string): string; - repeat(count: number): string; - replace(a:any, b:any):string; // bcz: fix this - startsWith(searchString: string, position?: number): boolean; - anchor(name: string): string; - big(): string; - blink(): string; - bold(): string; - fixed(): string; - fontcolor(color: string): string; - fontsize(size: number): string; - fontsize(size: string): string; - italics(): string; - link(url: string): string; - small(): string; - strike(): string; - sub(): string; - sup(): string; -} -interface Object { - constructor: Function; - toString(): string; - toLocaleString(): string; - valueOf(): Object; - hasOwnProperty(v: PropertyKey): boolean; - isPrototypeOf(v: Object): boolean; - propertyIsEnumerable(v: PropertyKey): boolean; -} -interface ConcatArray { - readonly length: number; - readonly [n: number]: T; - join(separator?: string): string; - slice(start?: number, end?: number): T[]; -} -interface URL { - hash: string; - host: string; - hostname: string; - href: string; - readonly origin: string; - password: string; - pathname: string; - port: string; - protocol: string; - search: string; - username: string; - toJSON(): string; -} -interface PromiseLike { - then(onfulfilled?: ((value: T) => TResult1 | PromiseLike) | undefined | null, onrejected?: ((reason: any) => TResult2 | PromiseLike) | undefined | null): PromiseLike; -} -interface Promise { - then(onfulfilled?: ((value: T) => TResult1 | PromiseLike) | undefined | null, onrejected?: ((reason: any) => TResult2 | PromiseLike) | undefined | null): Promise; - catch(onrejected?: ((reason: any) => TResult | PromiseLike) | undefined | null): Promise; -} - -declare const Update: unique symbol; -declare const Self: unique symbol; -declare const SelfProxy: unique symbol; -declare const DataSym: unique symbol; -declare const HandleUpdate: unique symbol; -declare const Id: unique symbol; -declare const OnUpdate: unique symbol; -declare const Parent: unique symbol; -declare const Copy: unique symbol; -declare const ToScriptString: unique symbol; - -declare abstract class RefField { - readonly [Id]: FieldId; - - constructor(); -} - -declare type FieldId = string; - -declare abstract class ObjectField { - abstract [Copy](): ObjectField; -} - -declare abstract class URLField extends ObjectField { - readonly url: URL; - - constructor(url: string); - constructor(url: URL); -} - -declare class RichTextField extends URLField { - [Copy](): ObjectField; - constructor(data:string, text: string); -} -declare class AudioField extends URLField { [Copy](): ObjectField; } -declare class VideoField extends URLField { [Copy](): ObjectField; } -declare class ImageField extends URLField { [Copy](): ObjectField; } -declare class WebField extends URLField { [Copy](): ObjectField; } -declare class PdfField extends URLField { [Copy](): ObjectField; } - -declare const ComputedField: any; -declare const CompileScript: any; - -// @ts-ignore -declare type Extract = T extends U ? T : never; -declare type Field = number | string | boolean | ObjectField | RefField; -declare type FieldWaiting = T extends undefined ? never : Promise; -declare type FieldResult = Opt | FieldWaiting>; - -declare type Opt = T | undefined; -declare class Doc extends RefField { - constructor(); - - [key: string]: FieldResult; - // [ToScriptString](): string; -} - -declare class List extends ObjectField { - constructor(fields?: T[]); - [index: number]: T | (T extends RefField ? Promise : never); - [Copy](): ObjectField; -} - -declare class InkField extends ObjectField { - constructor(data:Array<{X:number, Y:number}>); - [Copy](): ObjectField; -} - -// @ts-ignore -declare const console: any; - -interface DocumentOptions { } - -declare const Docs: { - ImageDocument(url: string, options?: DocumentOptions): Doc; - VideoDocument(url: string, options?: DocumentOptions): Doc; - TextDocument(options?: DocumentOptions): Doc; - PdfDocument(url: string, options?: DocumentOptions): Doc; - WebDocument(url: string, options?: DocumentOptions): Doc; - HtmlDocument(html: string, options?: DocumentOptions): Doc; - MapDocument(url: string, options?: DocumentOptions): Doc; - KVPDocument(document: Doc, options?: DocumentOptions): Doc; - FreeformDocument(documents: Doc[], options?: DocumentOptions): Doc; - SchemaDocument(columns: string[], documents: Doc[], options?: DocumentOptions): Doc; - TreeDocument(documents: Doc[], options?: DocumentOptions): Doc; - StackingDocument(documents: Doc[], options?: DocumentOptions): Doc; -}; - -declare function idToDoc(id:string):any; -declare function assignDoc(doc:Doc, field:any, id:any):string; -declare function d(...args:any[]):any; diff --git a/src/client/util/type_decls.txt b/src/client/util/type_decls.txt deleted file mode 100644 index 1a93bbe59..000000000 --- a/src/client/util/type_decls.txt +++ /dev/null @@ -1,224 +0,0 @@ -//@ts-ignore -declare type PropertyKey = string | number | symbol; -interface Array { - length: number; - toString(): string; - toLocaleString(): string; - pop(): T | undefined; - push(...items: T[]): number; - concat(...items: ConcatArray[]): T[]; - concat(...items: (T | ConcatArray)[]): T[]; - join(separator?: string): string; - reverse(): T[]; - shift(): T | undefined; - slice(start?: number, end?: number): T[]; - sort(compareFn?: (a: T, b: T) => number): this; - splice(start: number, deleteCount?: number): T[]; - splice(start: number, deleteCount: number, ...items: T[]): T[]; - unshift(...items: T[]): number; - indexOf(searchElement: T, fromIndex?: number): number; - lastIndexOf(searchElement: T, fromIndex?: number): number; - every(callbackfn: (value: T, index: number, array: T[]) => boolean, thisArg?: any): boolean; - some(callbackfn: (value: T, index: number, array: T[]) => boolean, thisArg?: any): boolean; - forEach(callbackfn: (value: T, index: number, array: T[]) => void, thisArg?: any): void; - map(callbackfn: (value: T, index: number, array: T[]) => U, thisArg?: any): U[]; - filter(callbackfn: (value: T, index: number, array: T[]) => value is S, thisArg?: any): S[]; - filter(callbackfn: (value: T, index: number, array: T[]) => any, thisArg?: any): T[]; - reduce(callbackfn: (previousValue: T, currentValue: T, currentIndex: number, array: T[]) => T): T; - reduce(callbackfn: (previousValue: T, currentValue: T, currentIndex: number, array: T[]) => T, initialValue: T): T; - reduce(callbackfn: (previousValue: U, currentValue: T, currentIndex: number, array: T[]) => U, initialValue: U): U; - reduceRight(callbackfn: (previousValue: T, currentValue: T, currentIndex: number, array: T[]) => T): T; - reduceRight(callbackfn: (previousValue: T, currentValue: T, currentIndex: number, array: T[]) => T, initialValue: T): T; - reduceRight(callbackfn: (previousValue: U, currentValue: T, currentIndex: number, array: T[]) => U, initialValue: U): U; - - [n: number]: T; -} - -interface Function { - apply(this: Function, thisArg: any, argArray?: any): any; - call(this: Function, thisArg: any, ...argArray: any[]): any; - bind(this: Function, thisArg: any, ...argArray: any[]): any; - toString(): string; - - prototype: any; - readonly length: number; - - // Non-standard extensions - arguments: any; - caller: Function; -} -interface Boolean { - valueOf(): boolean; -} -interface Number { - toString(radix?: number): string; - toFixed(fractionDigits?: number): string; - toExponential(fractionDigits?: number): string; - toPrecision(precision?: number): string; - valueOf(): number; -} -interface IArguments { - [index: number]: any; - length: number; - callee: Function; -} -interface RegExp { - readonly flags: string; - readonly sticky: boolean; - readonly unicode: boolean; -} -interface Date { - now() : string; -} -interface String { - codePointAt(pos: number): number | undefined; - includes(searchString: string, position?: number): boolean; - endsWith(searchString: string, endPosition?: number): boolean; - normalize(form: "NFC" | "NFD" | "NFKC" | "NFKD"): string; - normalize(form?: string): string; - repeat(count: number): string; - replace(a:any, b:any):string; // bcz: fix this - startsWith(searchString: string, position?: number): boolean; - anchor(name: string): string; - big(): string; - blink(): string; - bold(): string; - fixed(): string; - fontcolor(color: string): string; - fontsize(size: number): string; - fontsize(size: string): string; - italics(): string; - link(url: string): string; - small(): string; - strike(): string; - sub(): string; - sup(): string; -} -interface Object { - constructor: Function; - toString(): string; - toLocaleString(): string; - valueOf(): Object; - hasOwnProperty(v: PropertyKey): boolean; - isPrototypeOf(v: Object): boolean; - propertyIsEnumerable(v: PropertyKey): boolean; -} -interface ConcatArray { - readonly length: number; - readonly [n: number]: T; - join(separator?: string): string; - slice(start?: number, end?: number): T[]; -} -interface URL { - hash: string; - host: string; - hostname: string; - href: string; - readonly origin: string; - password: string; - pathname: string; - port: string; - protocol: string; - search: string; - username: string; - toJSON(): string; -} -interface PromiseLike { - then(onfulfilled?: ((value: T) => TResult1 | PromiseLike) | undefined | null, onrejected?: ((reason: any) => TResult2 | PromiseLike) | undefined | null): PromiseLike; -} -interface Promise { - then(onfulfilled?: ((value: T) => TResult1 | PromiseLike) | undefined | null, onrejected?: ((reason: any) => TResult2 | PromiseLike) | undefined | null): Promise; - catch(onrejected?: ((reason: any) => TResult | PromiseLike) | undefined | null): Promise; -} - -declare const Update: unique symbol; -declare const Self: unique symbol; -declare const SelfProxy: unique symbol; -declare const DataSym: unique symbol; -declare const HandleUpdate: unique symbol; -declare const Id: unique symbol; -declare const OnUpdate: unique symbol; -declare const Parent: unique symbol; -declare const Copy: unique symbol; -declare const ToScriptString: unique symbol; - -declare abstract class RefField { - readonly [Id]: FieldId; - - constructor(); -} - -declare type FieldId = string; - -declare abstract class ObjectField { - abstract [Copy](): ObjectField; -} - -declare abstract class URLField extends ObjectField { - readonly url: URL; - - constructor(url: string); - constructor(url: URL); -} - -declare class RichTextField extends URLField { - [Copy](): ObjectField; - constructor(data:string, text: string); -} -declare class AudioField extends URLField { [Copy](): ObjectField; } -declare class VideoField extends URLField { [Copy](): ObjectField; } -declare class ImageField extends URLField { [Copy](): ObjectField; } -declare class WebField extends URLField { [Copy](): ObjectField; } -declare class PdfField extends URLField { [Copy](): ObjectField; } - -declare const ComputedField: any; -declare const CompileScript: any; - -// @ts-ignore -declare type Extract = T extends U ? T : never; -declare type Field = number | string | boolean | ObjectField | RefField; -declare type FieldWaiting = T extends undefined ? never : Promise; -declare type FieldResult = Opt | FieldWaiting>; - -declare type Opt = T | undefined; -declare class Doc extends RefField { - constructor(); - - [key: string]: FieldResult; - // [ToScriptString](): string; -} - -declare class List extends ObjectField { - constructor(fields?: T[]); - [index: number]: T | (T extends RefField ? Promise : never); - [Copy](): ObjectField; -} - -declare class InkField extends ObjectField { - constructor(data:Array<{X:number, Y:number}>); - [Copy](): ObjectField; -} - -// @ts-ignore -declare const console: any; - -interface DocumentOptions { } - -declare const Docs: { - ImageDocument(url: string, options?: DocumentOptions): Doc; - VideoDocument(url: string, options?: DocumentOptions): Doc; - TextDocument(options?: DocumentOptions): Doc; - PdfDocument(url: string, options?: DocumentOptions): Doc; - WebDocument(url: string, options?: DocumentOptions): Doc; - HtmlDocument(html: string, options?: DocumentOptions): Doc; - MapDocument(url: string, options?: DocumentOptions): Doc; - KVPDocument(document: Doc, options?: DocumentOptions): Doc; - FreeformDocument(documents: Doc[], options?: DocumentOptions): Doc; - SchemaDocument(columns: string[], documents: Doc[], options?: DocumentOptions): Doc; - TreeDocument(documents: Doc[], options?: DocumentOptions): Doc; - StackingDocument(documents: Doc[], options?: DocumentOptions): Doc; -}; - -declare function idToDoc(id:string):any; -declare function assignDoc(doc:Doc, field:any, id:any):string; -declare function d(...args:any[]):any; diff --git a/src/typings/index.d.ts b/src/typings/index.d.ts index a9ebbb480..bee79a38d 100644 --- a/src/typings/index.d.ts +++ b/src/typings/index.d.ts @@ -12,13 +12,14 @@ declare module 'fit-curve'; declare module 'iink-js'; declare module 'pdfjs-dist/web/pdf_viewer'; declare module 'react-jsx-parser'; +declare module 'type_decls.d'; declare module '@react-pdf/renderer' { import * as React from 'react'; namespace ReactPDF { interface Style { - [property: string]: any; + [property: string]: unknown; } interface Styles { [key: string]: Style; @@ -32,7 +33,7 @@ declare module '@react-pdf/renderer' { keywords?: string; creator?: string; producer?: string; - onRender?: () => any; + onRender?: () => unknown; } /** @@ -213,13 +214,13 @@ declare module '@react-pdf/renderer' { src: string; loaded: boolean; loading: boolean; - data: any; - [key: string]: any; + data: unknown; + [key: string]: unknown; } - type HyphenationCallback = (words: string[], glyphString: { [key: string]: any }) => string[]; + type HyphenationCallback = (words: string[], glyphString: { [key: string]: unknown }) => string[]; const Font: { - register: (src: string, options: { family: string; [key: string]: any }) => void; + register: (src: string, options: { family: string; [key: string]: unknown }) => void; getEmojiSource: () => EmojiSource; getRegisteredFonts: () => string[]; registerEmojiSource: (emojiSource: EmojiSource) => void; @@ -252,21 +253,21 @@ declare module '@react-pdf/renderer' { }; }; - const version: any; + const version: unknown; - const PDFRenderer: any; + const PDFRenderer: unknown; const createInstance: ( element: { type: string; - props: { [key: string]: any }; + props: { [key: string]: unknown }; }, - root?: any - ) => any; + root?: unknown + ) => unknown; const pdf: (document: React.ReactElement) => { isDirty: () => boolean; - updateContainer: (document: React.ReactElement) => void; + updateContainer: (document: React.ReactElement) => void; toBuffer: () => NodeJS.ReadableStream; toBlob: () => Blob; toString: () => string; @@ -274,7 +275,7 @@ declare module '@react-pdf/renderer' { const renderToStream: (document: React.ReactElement) => NodeJS.ReadableStream; - const renderToFile: (document: React.ReactElement, filePath: string, callback?: (output: NodeJS.ReadableStream, filePath: string) => any) => Promise; + const renderToFile: (document: React.ReactElement, filePath: string, callback?: (output: NodeJS.ReadableStream, filePath: string) => unknown) => Promise; const render: typeof renderToFile; } diff --git a/src/typings/type_decls.d b/src/typings/type_decls.d new file mode 100644 index 000000000..1a93bbe59 --- /dev/null +++ b/src/typings/type_decls.d @@ -0,0 +1,224 @@ +//@ts-ignore +declare type PropertyKey = string | number | symbol; +interface Array { + length: number; + toString(): string; + toLocaleString(): string; + pop(): T | undefined; + push(...items: T[]): number; + concat(...items: ConcatArray[]): T[]; + concat(...items: (T | ConcatArray)[]): T[]; + join(separator?: string): string; + reverse(): T[]; + shift(): T | undefined; + slice(start?: number, end?: number): T[]; + sort(compareFn?: (a: T, b: T) => number): this; + splice(start: number, deleteCount?: number): T[]; + splice(start: number, deleteCount: number, ...items: T[]): T[]; + unshift(...items: T[]): number; + indexOf(searchElement: T, fromIndex?: number): number; + lastIndexOf(searchElement: T, fromIndex?: number): number; + every(callbackfn: (value: T, index: number, array: T[]) => boolean, thisArg?: any): boolean; + some(callbackfn: (value: T, index: number, array: T[]) => boolean, thisArg?: any): boolean; + forEach(callbackfn: (value: T, index: number, array: T[]) => void, thisArg?: any): void; + map(callbackfn: (value: T, index: number, array: T[]) => U, thisArg?: any): U[]; + filter(callbackfn: (value: T, index: number, array: T[]) => value is S, thisArg?: any): S[]; + filter(callbackfn: (value: T, index: number, array: T[]) => any, thisArg?: any): T[]; + reduce(callbackfn: (previousValue: T, currentValue: T, currentIndex: number, array: T[]) => T): T; + reduce(callbackfn: (previousValue: T, currentValue: T, currentIndex: number, array: T[]) => T, initialValue: T): T; + reduce(callbackfn: (previousValue: U, currentValue: T, currentIndex: number, array: T[]) => U, initialValue: U): U; + reduceRight(callbackfn: (previousValue: T, currentValue: T, currentIndex: number, array: T[]) => T): T; + reduceRight(callbackfn: (previousValue: T, currentValue: T, currentIndex: number, array: T[]) => T, initialValue: T): T; + reduceRight(callbackfn: (previousValue: U, currentValue: T, currentIndex: number, array: T[]) => U, initialValue: U): U; + + [n: number]: T; +} + +interface Function { + apply(this: Function, thisArg: any, argArray?: any): any; + call(this: Function, thisArg: any, ...argArray: any[]): any; + bind(this: Function, thisArg: any, ...argArray: any[]): any; + toString(): string; + + prototype: any; + readonly length: number; + + // Non-standard extensions + arguments: any; + caller: Function; +} +interface Boolean { + valueOf(): boolean; +} +interface Number { + toString(radix?: number): string; + toFixed(fractionDigits?: number): string; + toExponential(fractionDigits?: number): string; + toPrecision(precision?: number): string; + valueOf(): number; +} +interface IArguments { + [index: number]: any; + length: number; + callee: Function; +} +interface RegExp { + readonly flags: string; + readonly sticky: boolean; + readonly unicode: boolean; +} +interface Date { + now() : string; +} +interface String { + codePointAt(pos: number): number | undefined; + includes(searchString: string, position?: number): boolean; + endsWith(searchString: string, endPosition?: number): boolean; + normalize(form: "NFC" | "NFD" | "NFKC" | "NFKD"): string; + normalize(form?: string): string; + repeat(count: number): string; + replace(a:any, b:any):string; // bcz: fix this + startsWith(searchString: string, position?: number): boolean; + anchor(name: string): string; + big(): string; + blink(): string; + bold(): string; + fixed(): string; + fontcolor(color: string): string; + fontsize(size: number): string; + fontsize(size: string): string; + italics(): string; + link(url: string): string; + small(): string; + strike(): string; + sub(): string; + sup(): string; +} +interface Object { + constructor: Function; + toString(): string; + toLocaleString(): string; + valueOf(): Object; + hasOwnProperty(v: PropertyKey): boolean; + isPrototypeOf(v: Object): boolean; + propertyIsEnumerable(v: PropertyKey): boolean; +} +interface ConcatArray { + readonly length: number; + readonly [n: number]: T; + join(separator?: string): string; + slice(start?: number, end?: number): T[]; +} +interface URL { + hash: string; + host: string; + hostname: string; + href: string; + readonly origin: string; + password: string; + pathname: string; + port: string; + protocol: string; + search: string; + username: string; + toJSON(): string; +} +interface PromiseLike { + then(onfulfilled?: ((value: T) => TResult1 | PromiseLike) | undefined | null, onrejected?: ((reason: any) => TResult2 | PromiseLike) | undefined | null): PromiseLike; +} +interface Promise { + then(onfulfilled?: ((value: T) => TResult1 | PromiseLike) | undefined | null, onrejected?: ((reason: any) => TResult2 | PromiseLike) | undefined | null): Promise; + catch(onrejected?: ((reason: any) => TResult | PromiseLike) | undefined | null): Promise; +} + +declare const Update: unique symbol; +declare const Self: unique symbol; +declare const SelfProxy: unique symbol; +declare const DataSym: unique symbol; +declare const HandleUpdate: unique symbol; +declare const Id: unique symbol; +declare const OnUpdate: unique symbol; +declare const Parent: unique symbol; +declare const Copy: unique symbol; +declare const ToScriptString: unique symbol; + +declare abstract class RefField { + readonly [Id]: FieldId; + + constructor(); +} + +declare type FieldId = string; + +declare abstract class ObjectField { + abstract [Copy](): ObjectField; +} + +declare abstract class URLField extends ObjectField { + readonly url: URL; + + constructor(url: string); + constructor(url: URL); +} + +declare class RichTextField extends URLField { + [Copy](): ObjectField; + constructor(data:string, text: string); +} +declare class AudioField extends URLField { [Copy](): ObjectField; } +declare class VideoField extends URLField { [Copy](): ObjectField; } +declare class ImageField extends URLField { [Copy](): ObjectField; } +declare class WebField extends URLField { [Copy](): ObjectField; } +declare class PdfField extends URLField { [Copy](): ObjectField; } + +declare const ComputedField: any; +declare const CompileScript: any; + +// @ts-ignore +declare type Extract = T extends U ? T : never; +declare type Field = number | string | boolean | ObjectField | RefField; +declare type FieldWaiting = T extends undefined ? never : Promise; +declare type FieldResult = Opt | FieldWaiting>; + +declare type Opt = T | undefined; +declare class Doc extends RefField { + constructor(); + + [key: string]: FieldResult; + // [ToScriptString](): string; +} + +declare class List extends ObjectField { + constructor(fields?: T[]); + [index: number]: T | (T extends RefField ? Promise : never); + [Copy](): ObjectField; +} + +declare class InkField extends ObjectField { + constructor(data:Array<{X:number, Y:number}>); + [Copy](): ObjectField; +} + +// @ts-ignore +declare const console: any; + +interface DocumentOptions { } + +declare const Docs: { + ImageDocument(url: string, options?: DocumentOptions): Doc; + VideoDocument(url: string, options?: DocumentOptions): Doc; + TextDocument(options?: DocumentOptions): Doc; + PdfDocument(url: string, options?: DocumentOptions): Doc; + WebDocument(url: string, options?: DocumentOptions): Doc; + HtmlDocument(html: string, options?: DocumentOptions): Doc; + MapDocument(url: string, options?: DocumentOptions): Doc; + KVPDocument(document: Doc, options?: DocumentOptions): Doc; + FreeformDocument(documents: Doc[], options?: DocumentOptions): Doc; + SchemaDocument(columns: string[], documents: Doc[], options?: DocumentOptions): Doc; + TreeDocument(documents: Doc[], options?: DocumentOptions): Doc; + StackingDocument(documents: Doc[], options?: DocumentOptions): Doc; +}; + +declare function idToDoc(id:string):any; +declare function assignDoc(doc:Doc, field:any, id:any):string; +declare function d(...args:any[]):any; -- cgit v1.2.3-70-g09d2 From 5c7964173d80752200727d8340825210c2704265 Mon Sep 17 00:00:00 2001 From: bobzel Date: Tue, 13 Aug 2024 10:42:24 -0400 Subject: removed youtube query calls --- src/server/websocket.ts | 19 +------------------ 1 file changed, 1 insertion(+), 18 deletions(-) (limited to 'src') diff --git a/src/server/websocket.ts b/src/server/websocket.ts index 821607df5..4a127f099 100644 --- a/src/server/websocket.ts +++ b/src/server/websocket.ts @@ -8,7 +8,7 @@ import { logPort } from './ActionUtilities'; import { Client } from './Client'; import { DashStats } from './DashStats'; import { DocumentsCollection } from './IDatabase'; -import { Diff, GestureContent, MessageStore, MobileDocumentUploadContent, MobileInkOverlayContent, Transferable, Types, UpdateMobileInkOverlayPositionContent, YoutubeQueryInput, YoutubeQueryTypes } from './Message'; +import { Diff, GestureContent, MessageStore, MobileDocumentUploadContent, MobileInkOverlayContent, Transferable, Types, UpdateMobileInkOverlayPositionContent } from './Message'; import { Search } from './Search'; import { resolvedPorts, socketMap, timeMap, userOperations } from './SocketData'; import { GoogleCredentialsLoader } from './apis/google/CredentialsLoader'; @@ -39,22 +39,6 @@ export namespace WebSocket { socket.broadcast.emit('receiveMobileDocumentUpload', content); } - function HandleYoutubeQuery([query, callback]: [YoutubeQueryInput, (result?: any[]) => void]) { - const { ProjectCredentials } = GoogleCredentialsLoader; - switch (query.type) { - case YoutubeQueryTypes.Channels: - YoutubeApi.authorizedGetChannel(ProjectCredentials); - break; - case YoutubeQueryTypes.SearchVideo: - YoutubeApi.authorizedGetVideos(ProjectCredentials, query.userInput, callback); - break; - case YoutubeQueryTypes.VideoDetails: - YoutubeApi.authorizedGetVideoDetails(ProjectCredentials, query.videoIds, callback); - break; - default: - } - } - export async function doDelete(onlyFields = true) { const target: string[] = []; onlyFields && target.push(DocumentsCollection); @@ -448,7 +432,6 @@ export namespace WebSocket { } ServerUtils.AddServerHandler(socket, MessageStore.CreateField, CreateField); - ServerUtils.AddServerHandlerCallback(socket, MessageStore.YoutubeApiQuery, HandleYoutubeQuery); ServerUtils.AddServerHandler(socket, MessageStore.UpdateField, diff => UpdateField(socket, diff)); ServerUtils.AddServerHandler(socket, MessageStore.DeleteField, id => DeleteField(socket, id)); ServerUtils.AddServerHandler(socket, MessageStore.DeleteFields, ids => DeleteFields(socket, ids)); -- cgit v1.2.3-70-g09d2 From ef79ab121c881d3e6a2982ce2e01da40294af656 Mon Sep 17 00:00:00 2001 From: bobzel Date: Tue, 13 Aug 2024 10:44:53 -0400 Subject: from last --- src/server/Message.ts | 18 +++--------------- src/server/Search.ts | 1 + src/server/websocket.ts | 4 +--- 3 files changed, 5 insertions(+), 18 deletions(-) (limited to 'src') diff --git a/src/server/Message.ts b/src/server/Message.ts index 03150c841..8e30cd6df 100644 --- a/src/server/Message.ts +++ b/src/server/Message.ts @@ -47,19 +47,7 @@ export enum Types { export interface Transferable { readonly id: string; readonly type: Types; - readonly data?: any; -} - -export enum YoutubeQueryTypes { - Channels, - SearchVideo, - VideoDetails, -} - -export interface YoutubeQueryInput { - readonly type: YoutubeQueryTypes; - readonly userInput?: string; - readonly videoIds?: string; + readonly data?: unknown; } export interface Reference { @@ -99,6 +87,7 @@ export interface RoomMessage { readonly room: string; } +// eslint-disable-next-line @typescript-eslint/no-namespace export namespace MessageStore { export const Foo = new Message('Foo'); export const Bar = new Message('Bar'); @@ -106,7 +95,7 @@ export namespace MessageStore { export const GetField = new Message('Get Field'); // send string 'id' get Transferable back export const GetFields = new Message('Get Fields'); // send string[] of 'id' get Transferable[] back export const GetDocument = new Message('Get Document'); - export const DeleteAll = new Message('Delete All'); + export const DeleteAll = new Message('Delete All'); export const ConnectionTerminated = new Message('Connection Terminated'); export const GesturePoints = new Message('Gesture Points'); @@ -118,7 +107,6 @@ export namespace MessageStore { export const GetRefFields = new Message('Get Ref Fields'); export const UpdateField = new Message('Update Ref Field'); export const CreateField = new Message('Create Ref Field'); - export const YoutubeApiQuery = new Message('Youtube Api Query'); export const DeleteField = new Message('Delete field'); export const DeleteFields = new Message('Delete fields'); diff --git a/src/server/Search.ts b/src/server/Search.ts index b21ee853a..06af18776 100644 --- a/src/server/Search.ts +++ b/src/server/Search.ts @@ -3,6 +3,7 @@ import * as rp from 'request-promise'; const pathTo = (relative: string) => `http://localhost:8983/solr/dash/${relative}`; +// eslint-disable-next-line @typescript-eslint/no-namespace export namespace Search { export async function updateDocument(document: any) { try { diff --git a/src/server/websocket.ts b/src/server/websocket.ts index 4a127f099..905dbcf57 100644 --- a/src/server/websocket.ts +++ b/src/server/websocket.ts @@ -11,8 +11,6 @@ import { DocumentsCollection } from './IDatabase'; import { Diff, GestureContent, MessageStore, MobileDocumentUploadContent, MobileInkOverlayContent, Transferable, Types, UpdateMobileInkOverlayPositionContent } from './Message'; import { Search } from './Search'; import { resolvedPorts, socketMap, timeMap, userOperations } from './SocketData'; -import { GoogleCredentialsLoader } from './apis/google/CredentialsLoader'; -import YoutubeApi from './apis/youtube/youtubeApiSample'; import { initializeGuest } from './authentication/DashUserModel'; import { Database } from './database'; @@ -77,7 +75,7 @@ export namespace WebSocket { Database.Instance.update(newValue.id, newValue, () => socket.broadcast.emit(MessageStore.SetField.Message, newValue)); // broadcast set value to all other clients if (newValue.type === Types.Text) { // if the newValue has sring type, then it's suitable for searching -- pass it to SOLR - Search.updateDocument({ id: newValue.id, data: { set: (newValue as any).data } }); + Search.updateDocument({ id: newValue.id, data: { set: newValue.data } }); } } -- cgit v1.2.3-70-g09d2 From 4d45f8a046ce5300f0b046457a381d219eef3363 Mon Sep 17 00:00:00 2001 From: bobzel Date: Tue, 13 Aug 2024 15:14:05 -0400 Subject: cleaning up database types --- src/client/DocServer.ts | 21 +------- src/client/views/GestureOverlay.tsx | 5 -- src/fields/Doc.ts | 3 +- src/fields/ObjectField.ts | 15 ++++-- src/fields/util.ts | 20 ++++---- src/server/IDatabase.ts | 8 ++-- src/server/MemoryDatabase.ts | 6 +-- src/server/Message.ts | 66 +------------------------- src/server/apis/google/GoogleApiServerUtils.ts | 1 + src/server/database.ts | 12 +++-- src/server/server_Initialization.ts | 7 ++- 11 files changed, 44 insertions(+), 120 deletions(-) (limited to 'src') diff --git a/src/client/DocServer.ts b/src/client/DocServer.ts index 2bf3a6f9f..33fa928f2 100644 --- a/src/client/DocServer.ts +++ b/src/client/DocServer.ts @@ -8,7 +8,7 @@ import { UpdatingFromServer } from '../fields/DocSymbols'; import { FieldLoader } from '../fields/FieldLoader'; import { HandleUpdate, Id, Parent } from '../fields/FieldSymbols'; import { ObjectField, serverOpType } from '../fields/ObjectField'; -import { GestureContent, Message, MessageStore, MobileDocumentUploadContent, MobileInkOverlayContent, UpdateMobileInkOverlayPositionContent } from '../server/Message'; +import { Message, MessageStore } from '../server/Message'; import { SerializationHelper } from './util/SerializationHelper'; /** @@ -109,25 +109,6 @@ export namespace DocServer { } } - export namespace Mobile { - export function dispatchGesturePoints(content: GestureContent) { - DocServer.Emit(_socket, MessageStore.GesturePoints, content); - } - - export function dispatchOverlayTrigger(content: MobileInkOverlayContent) { - // _socket.emit("dispatchBoxTrigger"); - DocServer.Emit(_socket, MessageStore.MobileInkOverlayTrigger, content); - } - - export function dispatchOverlayPositionUpdate(content: UpdateMobileInkOverlayPositionContent) { - DocServer.Emit(_socket, MessageStore.UpdateMobileInkOverlayPosition, content); - } - - export function dispatchMobileDocumentUpload(content: MobileDocumentUploadContent) { - DocServer.Emit(_socket, MessageStore.MobileDocumentUpload, content); - } - } - const instructions = 'This page will automatically refresh after this alert is closed. Expect to reconnect after about 30 seconds.'; function alertUser(connectionTerminationReason: string) { switch (connectionTerminationReason) { diff --git a/src/client/views/GestureOverlay.tsx b/src/client/views/GestureOverlay.tsx index bcd4d1ee5..3a2738c3b 100644 --- a/src/client/views/GestureOverlay.tsx +++ b/src/client/views/GestureOverlay.tsx @@ -21,10 +21,8 @@ import { SetActiveInkColor, SetActiveInkWidth, } from './nodes/DocumentView'; -// import MobileInkOverlay from '../../mobile/MobileInkOverlay'; import { Gestures } from '../../pen-gestures/GestureTypes'; import { GestureUtils } from '../../pen-gestures/GestureUtils'; -// import { MobileInkOverlayContent } from '../../server/Message'; import { InteractionUtils } from '../util/InteractionUtils'; import { ScriptingGlobals } from '../util/ScriptingGlobals'; import { Transform } from '../util/Transform'; @@ -71,8 +69,6 @@ export class GestureOverlay extends ObservableReactComponent(); private _d1: Doc | undefined; private _inkToTextDoc: Doc | undefined; @@ -485,7 +481,6 @@ export class GestureOverlay extends ObservableReactComponent - {/* {this.showMobileInkOverlay ? : null} */} {this.elements}
void | Promise } = {}; public [Initializing]: boolean = false; - public [FieldChanged] = (diff: { op: '$addToSet' | '$remFromSet' | '$set'; items: FieldType[] | undefined; length: number | undefined; hint?: unknown } | undefined, serverOp: serverOpType) => { + public [FieldChanged] = (diff: { op: '$addToSet' | '$remFromSet' | '$set'; items: FieldType[] | undefined; length: number | undefined; hint?: { start: number; deleteCount: number } } | undefined, serverOp: serverOpType) => { if (!this[UpdatingFromServer] || this[ForceServerWrite]) { DocServer.UpdateField(this[Id], serverOp); } diff --git a/src/fields/ObjectField.ts b/src/fields/ObjectField.ts index 21c4af608..5f31208eb 100644 --- a/src/fields/ObjectField.ts +++ b/src/fields/ObjectField.ts @@ -2,11 +2,18 @@ import { ScriptingGlobals } from '../client/util/ScriptingGlobals'; import { Copy, FieldChanged, Parent, ToJavascriptString, ToScriptString, ToString } from './FieldSymbols'; import { RefField } from './RefField'; +export type serializedFieldType = { fieldId: string; heading?: string; __type: string }; +export type serializedFieldsType = { [key: string]: { fields: serializedFieldType[] } }; +export interface serializedDoctype { + readonly id: string; + readonly fields?: serializedFieldsType; +} + export type serverOpType = { - $set?: { [key: string]: unknown }; // + $set?: serializedFieldsType; // $unset?: { [key: string]: unknown }; - $remFromSet?: { [key: string]: unknown }; - $addToSet?: { [key: string]: unknown }; + $remFromSet?: { [key: string]: { fields: serializedFieldType[] } | { deleteCount: number; start: number } | undefined; hint?: { deleteCount: number; start: number } }; + $addToSet?: serializedFieldsType; length?: number; }; export abstract class ObjectField { @@ -15,7 +22,7 @@ export abstract class ObjectField { // eslint-disable-next-line no-use-before-define items: FieldType[] | undefined; length: number | undefined; - hint?: unknown }, + hint?: { deleteCount: number, start: number} }, serverOp?: serverOpType) => void; // eslint-disable-next-line no-use-before-define public [Parent]?: RefField | ObjectField; diff --git a/src/fields/util.ts b/src/fields/util.ts index 69ece82a2..a5c56607c 100644 --- a/src/fields/util.ts +++ b/src/fields/util.ts @@ -8,7 +8,7 @@ import { Doc, DocListCast, FieldType, FieldResult, HierarchyMapping, ReverseHier import { AclAdmin, AclAugment, AclEdit, AclPrivate, DirectLinks, DocAcl, DocData, DocLayout, FieldKeys, ForceServerWrite, Height, Initializing, SelfProxy, UpdatingFromServer, Width } from './DocSymbols'; import { FieldChanged, Id, Parent, ToValue } from './FieldSymbols'; import { List, ListImpl } from './List'; -import { ObjectField } from './ObjectField'; +import { ObjectField, serializedFieldType, serverOpType } from './ObjectField'; import { PrefetchProxy, ProxyField } from './Proxy'; import { RefField } from './RefField'; import { RichTextField } from './RichTextField'; @@ -112,9 +112,9 @@ const _setterImpl = action((target: Doc | ListImpl, prop: string | sy if (writeToServer) { // prettier-ignore - if (value === undefined) + if (value === undefined || value === null) (target as Doc|ObjectField)[FieldChanged]?.(undefined, { $unset: { ['fields.' + prop]: '' } }); - else (target as Doc|ObjectField)[FieldChanged]?.(undefined, { $set: { ['fields.' + prop]: value instanceof ObjectField ? SerializationHelper.Serialize(value) :value}}); + else (target as Doc|ObjectField)[FieldChanged]?.(undefined, { $set: { ['fields.' + prop]: (value instanceof ObjectField ? SerializationHelper.Serialize(value) :value) as { fields: serializedFieldType[]}}}); if (prop === 'author' || prop.toString().startsWith('acl_')) updateCachedAcls(target); } else if (receiver instanceof Doc) { DocServer.registerDocWithCachedUpdate(receiver, prop as string, curValue); @@ -393,15 +393,15 @@ export function deleteProperty(target: Doc | ListImpl, prop: string | // able to undo and redo the partial change. // export function containedFieldChangedHandler(container: ListImpl | Doc, prop: string | number, liveContainedField: ObjectField) { - let lastValue: FieldResult = liveContainedField instanceof ObjectField ? ObjectField.MakeCopy(liveContainedField) : liveContainedField; - return (diff?: { op: '$addToSet' | '$remFromSet' | '$set'; items: (FieldType & { value?: FieldType })[] | undefined; length: number | undefined; hint?: unknown } /* , dummyServerOp?: any */) => { - const serializeItems = () => ({ __type: 'list', fields: diff?.items?.map((item: FieldType) => SerializationHelper.Serialize(item)) }); + let lastValue = ObjectField.MakeCopy(liveContainedField); + return (diff?: { op: '$addToSet' | '$remFromSet' | '$set'; items: (FieldType & { value?: FieldType })[] | undefined; length: number | undefined; hint?: { start: number; deleteCount: number } } /* , dummyServerOp?: any */) => { + const serializeItems = () => ({ __type: 'list', fields: diff?.items?.map((item: FieldType) => SerializationHelper.Serialize(item) as serializedFieldType) ?? [] }); // prettier-ignore - const serverOp = diff?.op === '$addToSet' + const serverOp: serverOpType = diff?.op === '$addToSet' ? { $addToSet: { ['fields.' + prop]: serializeItems() }, length: diff.length } : diff?.op === '$remFromSet' ? { $remFromSet: { ['fields.' + prop]: serializeItems(), hint: diff.hint}, length: diff.length } - : { $set: { ['fields.' + prop]: liveContainedField ? SerializationHelper.Serialize(liveContainedField) as FieldType : undefined } }; + : { $set: { ['fields.' + prop]: SerializationHelper.Serialize(liveContainedField) as {fields: serializedFieldType[]}} }; if (!(container instanceof Doc) || !container[UpdatingFromServer]) { const cont = container as { [key: string | number]: FieldType }; @@ -477,13 +477,13 @@ export function containedFieldChangedHandler(container: ListImpl | Do // console.log('redo list: ' + prop, fieldVal()); // bcz: uncomment to log undo setFieldVal(ObjectField.MakeCopy(newValue)); const containerProp = cont[prop]; - lastValue = containerProp instanceof ObjectField && ObjectField.MakeCopy(containerProp); + if (containerProp instanceof ObjectField) lastValue = ObjectField.MakeCopy(containerProp); }, undo: () => { // console.log('undo list: ' + prop, fieldVal()); // bcz: uncomment to log undo setFieldVal(ObjectField.MakeCopy(prevValue)); const containerProp = cont[prop]; - lastValue = containerProp instanceof ObjectField && ObjectField.MakeCopy(containerProp); + if (containerProp instanceof ObjectField) lastValue = ObjectField.MakeCopy(containerProp); }, prop: 'set list field', }, diff --git a/src/server/IDatabase.ts b/src/server/IDatabase.ts index 2274792b3..481b64d4a 100644 --- a/src/server/IDatabase.ts +++ b/src/server/IDatabase.ts @@ -1,5 +1,5 @@ import * as mongodb from 'mongodb'; -import { Transferable } from './Message'; +import { serializedDoctype } from '../fields/ObjectField'; export const DocumentsCollection = 'documents'; export interface IDatabase { @@ -13,10 +13,10 @@ export interface IDatabase { dropSchema(...schemaNames: string[]): Promise; - insert(value: any, collectionName?: string): Promise; + insert(value: { _id: string }, collectionName?: string): Promise; - getDocument(id: string, fn: (result?: Transferable) => void, collectionName?: string): void; - getDocuments(ids: string[], fn: (result: Transferable[]) => void, collectionName?: string): void; + getDocument(id: string, fn: (result?: serializedDoctype) => void, collectionName?: string): void; + getDocuments(ids: string[], fn: (result: serializedDoctype[]) => void, collectionName?: string): void; getCollectionNames(): Promise; visit(ids: string[], fn: (result: any) => string[] | Promise, collectionName?: string): Promise; diff --git a/src/server/MemoryDatabase.ts b/src/server/MemoryDatabase.ts index 1432d91c4..b838cb61b 100644 --- a/src/server/MemoryDatabase.ts +++ b/src/server/MemoryDatabase.ts @@ -1,6 +1,6 @@ import * as mongodb from 'mongodb'; +import { serializedDoctype } from '../fields/ObjectField'; import { DocumentsCollection, IDatabase } from './IDatabase'; -import { Transferable } from './Message'; export class MemoryDatabase implements IDatabase { private db: { [collectionName: string]: { [id: string]: any } } = {}; @@ -81,10 +81,10 @@ export class MemoryDatabase implements IDatabase { return Promise.resolve(); } - public getDocument(id: string, fn: (result?: Transferable) => void, collectionName = DocumentsCollection): void { + public getDocument(id: string, fn: (result?: serializedDoctype) => void, collectionName = DocumentsCollection): void { fn(this.getCollection(collectionName)[id]); } - public getDocuments(ids: string[], fn: (result: Transferable[]) => void, collectionName = DocumentsCollection): void { + public getDocuments(ids: string[], fn: (result: serializedDoctype[]) => void, collectionName = DocumentsCollection): void { fn(ids.map(id => this.getCollection(collectionName)[id])); } diff --git a/src/server/Message.ts b/src/server/Message.ts index 03150c841..26b41539b 100644 --- a/src/server/Message.ts +++ b/src/server/Message.ts @@ -1,5 +1,6 @@ import * as uuid from 'uuid'; import { Point } from '../pen-gestures/ndollar'; +import { serverOpType } from '../fields/ObjectField'; function GenerateDeterministicGuid(seed: string): string { return uuid.v5(seed, uuid.v5.URL); @@ -22,52 +23,12 @@ export class Message { } } -export enum Types { - Number, - List, - Key, - Image, - Web, - Document, - Text, - Icon, - RichText, - DocumentReference, - Html, - Video, - Audio, - Ink, - PDF, - Tuple, - Boolean, - Script, - Templates, -} - -export interface Transferable { - readonly id: string; - readonly type: Types; - readonly data?: any; -} - -export enum YoutubeQueryTypes { - Channels, - SearchVideo, - VideoDetails, -} - -export interface YoutubeQueryInput { - readonly type: YoutubeQueryTypes; - readonly userInput?: string; - readonly videoIds?: string; -} - export interface Reference { readonly id: string; } export interface Diff extends Reference { - readonly diff: any; + readonly diff: serverOpType; } export interface GestureContent { @@ -77,23 +38,6 @@ export interface GestureContent { readonly color?: string; } -export interface MobileInkOverlayContent { - readonly enableOverlay: boolean; - readonly width?: number; - readonly height?: number; - readonly text?: string; -} - -export interface UpdateMobileInkOverlayPositionContent { - readonly dx?: number; - readonly dy?: number; - readonly dsize?: number; -} - -export interface MobileDocumentUploadContent { - readonly docId: string; -} - export interface RoomMessage { readonly message: string; readonly room: string; @@ -102,17 +46,11 @@ export interface RoomMessage { export namespace MessageStore { export const Foo = new Message('Foo'); export const Bar = new Message('Bar'); - export const SetField = new Message('Set Field'); // send Transferable (no reply) - export const GetField = new Message('Get Field'); // send string 'id' get Transferable back - export const GetFields = new Message('Get Fields'); // send string[] of 'id' get Transferable[] back export const GetDocument = new Message('Get Document'); export const DeleteAll = new Message('Delete All'); export const ConnectionTerminated = new Message('Connection Terminated'); export const GesturePoints = new Message('Gesture Points'); - export const MobileInkOverlayTrigger = new Message('Trigger Mobile Ink Overlay'); - export const UpdateMobileInkOverlayPosition = new Message('Update Mobile Ink Overlay Position'); - export const MobileDocumentUpload = new Message('Upload Document From Mobile'); export const GetRefField = new Message('Get Ref Field'); export const GetRefFields = new Message('Get Ref Fields'); diff --git a/src/server/apis/google/GoogleApiServerUtils.ts b/src/server/apis/google/GoogleApiServerUtils.ts index d3acc968b..47206f415 100644 --- a/src/server/apis/google/GoogleApiServerUtils.ts +++ b/src/server/apis/google/GoogleApiServerUtils.ts @@ -21,6 +21,7 @@ const scope = ['documents.readonly', 'documents', 'presentations', 'presentation * This namespace manages server side authentication for Google API queries, either * from the standard v1 APIs or the Google Photos REST API. */ +// eslint-disable-next-line @typescript-eslint/no-namespace export namespace GoogleApiServerUtils { /** * As we expand out to more Google APIs that are accessible from diff --git a/src/server/database.ts b/src/server/database.ts index ff8584cd7..a93117349 100644 --- a/src/server/database.ts +++ b/src/server/database.ts @@ -1,3 +1,4 @@ +/* eslint-disable @typescript-eslint/no-namespace */ import * as mongodb from 'mongodb'; import * as mongoose from 'mongoose'; import { Opt } from '../fields/Doc'; @@ -5,11 +6,11 @@ import { emptyFunction, Utils } from '../Utils'; import { GoogleApiServerUtils } from './apis/google/GoogleApiServerUtils'; import { DocumentsCollection, IDatabase } from './IDatabase'; import { MemoryDatabase } from './MemoryDatabase'; -import { Transferable } from './Message'; import { Upload } from './SharedMediaTypes'; +import { serializedDoctype } from '../fields/ObjectField'; export namespace Database { - export let disconnect: Function; + export let disconnect: () => void; class DocSchema implements mongodb.BSON.Document { _id!: string; @@ -84,6 +85,7 @@ export namespace Database { if (this.db) { const collection = this.db.collection(collectionName); const prom = this.currentWrites[id]; + // eslint-disable-next-line prefer-const let newProm: Promise; const run = (): Promise => new Promise(resolve => { @@ -112,6 +114,7 @@ export namespace Database { if (this.db) { const collection = this.db.collection(collectionName); const prom = this.currentWrites[id]; + // eslint-disable-next-line prefer-const let newProm: Promise; const run = (): Promise => new Promise(resolve => { @@ -196,6 +199,7 @@ export namespace Database { const id = value._id; const collection = this.db.collection(collectionName); const prom = this.currentWrites[id]; + // eslint-disable-next-line prefer-const let newProm: Promise; const run = (): Promise => new Promise(resolve => { @@ -219,7 +223,7 @@ export namespace Database { return undefined; } - public getDocument(id: string, fn: (result?: Transferable) => void, collectionName = DocumentsCollection) { + public getDocument(id: string, fn: (result?: serializedDoctype) => void, collectionName = DocumentsCollection) { if (this.db) { const collection = this.db.collection(collectionName); collection.findOne({ _id: id }).then(resultIn => { @@ -237,7 +241,7 @@ export namespace Database { } } - public async getDocuments(ids: string[], fn: (result: Transferable[]) => void, collectionName = DocumentsCollection) { + public async getDocuments(ids: string[], fn: (result: serializedDoctype[]) => void, collectionName = DocumentsCollection) { if (this.db) { const found = await this.db .collection(collectionName) diff --git a/src/server/server_Initialization.ts b/src/server/server_Initialization.ts index 9183688c6..2190e27c7 100644 --- a/src/server/server_Initialization.ts +++ b/src/server/server_Initialization.ts @@ -29,7 +29,6 @@ import { WebSocket } from './websocket'; export type RouteSetter = (server: RouteManager) => void; // export let disconnect: Function; -// eslint-disable-next-line import/no-mutable-exports export let resolvedServerUrl: string; const week = 7 * 24 * 60 * 60 * 1000; @@ -115,12 +114,12 @@ function registerEmbeddedBrowseRelativePathHandler(server: express.Express) { } function proxyServe(req: any, requrl: string, response: any) { - // eslint-disable-next-line global-require + // eslint-disable-next-line global-require, @typescript-eslint/no-var-requires const htmlBodyMemoryStream = new (require('memorystream'))(); let wasinBrFormat = false; const sendModifiedBody = () => { const header = response.headers['content-encoding']; - const refToCors = (match: any, tag: string, sym: string, href: string) => `${tag}=${sym + resolvedServerUrl}/corsProxy/${href + sym}`; + const refToCors = (match: string, tag: string, sym: string, href: string) => `${tag}=${sym + resolvedServerUrl}/corsProxy/${href + sym}`; // const relpathToCors = (match: any, href: string, offset: any, string: any) => `="${resolvedServerUrl + '/corsProxy/' + decodeURIComponent(req.originalUrl.split('/corsProxy/')[1].match(/https?:\/\/[^\/]*/)?.[0] ?? '') + '/' + href}"`; if (header) { try { @@ -238,7 +237,7 @@ function registerAuthenticationRoutes(server: express.Express) { export default async function InitializeServer(routeSetter: RouteSetter) { const isRelease = determineEnvironment(); const app = buildWithMiddleware(express()); - const compiler = webpack(config as any); + const compiler = webpack(config as webpack.Configuration); // route table managed by express. routes are tested sequentially against each of these map rules. when a match is found, the handler is called to process the request app.use(wdm(compiler, { publicPath: config.output.publicPath })); -- cgit v1.2.3-70-g09d2 From a0774ccdd2de7953b9822df2e106d7395cc0f216 Mon Sep 17 00:00:00 2001 From: bobzel Date: Tue, 13 Aug 2024 15:31:42 -0400 Subject: updated list ops on server --- src/server/websocket.ts | 244 ++++++++++++++++++------------------------------ 1 file changed, 89 insertions(+), 155 deletions(-) (limited to 'src') diff --git a/src/server/websocket.ts b/src/server/websocket.ts index 905dbcf57..f10455680 100644 --- a/src/server/websocket.ts +++ b/src/server/websocket.ts @@ -3,13 +3,14 @@ import { createServer } from 'https'; import * as _ from 'lodash'; import { networkInterfaces } from 'os'; import { Server, Socket } from 'socket.io'; +import { SecureContextOptions } from 'tls'; import { ServerUtils } from '../ServerUtils'; +import { serializedDoctype, serializedFieldsType } from '../fields/ObjectField'; import { logPort } from './ActionUtilities'; import { Client } from './Client'; import { DashStats } from './DashStats'; import { DocumentsCollection } from './IDatabase'; -import { Diff, GestureContent, MessageStore, MobileDocumentUploadContent, MobileInkOverlayContent, Transferable, Types, UpdateMobileInkOverlayPositionContent } from './Message'; -import { Search } from './Search'; +import { Diff, GestureContent, MessageStore } from './Message'; import { resolvedPorts, socketMap, timeMap, userOperations } from './SocketData'; import { initializeGuest } from './authentication/DashUserModel'; import { Database } from './database'; @@ -25,25 +26,10 @@ export namespace WebSocket { socket.broadcast.emit('receiveGesturePoints', content); } - function processOverlayTrigger(socket: Socket, content: MobileInkOverlayContent) { - socket.broadcast.emit('receiveOverlayTrigger', content); - } - - function processUpdateOverlayPosition(socket: Socket, content: UpdateMobileInkOverlayPositionContent) { - socket.broadcast.emit('receiveUpdateOverlayPosition', content); - } - - function processMobileDocumentUpload(socket: Socket, content: MobileDocumentUploadContent) { - socket.broadcast.emit('receiveMobileDocumentUpload', content); - } - export async function doDelete(onlyFields = true) { const target: string[] = []; onlyFields && target.push(DocumentsCollection); await Database.Instance.dropSchema(...target); - if (process.env.DISABLE_SEARCH !== 'true') { - await Search.clear(); - } initializeGuest(); } @@ -63,31 +49,15 @@ export namespace WebSocket { DashStats.logUserLogin(userEmail); } - function getField([id, callback]: [string, (result?: Transferable) => void]) { - Database.Instance.getDocument(id, (result?: Transferable) => callback(result)); - } - - function getFields([ids, callback]: [string[], (result: Transferable[]) => void]) { - Database.Instance.getDocuments(ids, callback); - } - - function setField(socket: Socket, newValue: Transferable) { - Database.Instance.update(newValue.id, newValue, () => socket.broadcast.emit(MessageStore.SetField.Message, newValue)); // broadcast set value to all other clients - if (newValue.type === Types.Text) { - // if the newValue has sring type, then it's suitable for searching -- pass it to SOLR - Search.updateDocument({ id: newValue.id, data: { set: newValue.data } }); - } - } - - function GetRefFieldLocal([id, callback]: [string, (result?: Transferable) => void]) { + function GetRefFieldLocal([id, callback]: [string, (result?: serializedDoctype) => void]) { return Database.Instance.getDocument(id, callback); } - function GetRefField([id, callback]: [string, (result?: Transferable) => void]) { + function GetRefField([id, callback]: [string, (result?: serializedDoctype) => void]) { process.stdout.write(`+`); GetRefFieldLocal([id, callback]); } - function GetRefFields([ids, callback]: [string[], (result?: Transferable[]) => void]) { + function GetRefFields([ids, callback]: [string[], (result?: serializedDoctype[]) => void]) { process.stdout.write(`${ids.length}…`); Database.Instance.getDocuments(ids, callback); } @@ -151,11 +121,11 @@ export namespace WebSocket { const { diff, socket } = next; if (diff.diff.$addToSet) { // eslint-disable-next-line no-use-before-define - return GetRefFieldLocal([diff.id, (result?: Transferable) => addToListField(socket, diff, result)]); // would prefer to have Mongo handle list additions direclty, but for now handle it on our own + return GetRefFieldLocal([diff.id, (result?: serializedDoctype) => addToListField(socket, diff, result)]); // would prefer to have Mongo handle list additions direclty, but for now handle it on our own } if (diff.diff.$remFromSet) { // eslint-disable-next-line no-use-before-define - return GetRefFieldLocal([diff.id, (result?: Transferable) => remFromListField(socket, diff, result)]); // would prefer to have Mongo handle list additions direclty, but for now handle it on our own + return GetRefFieldLocal([diff.id, (result?: serializedDoctype) => remFromListField(socket, diff, result)]); // would prefer to have Mongo handle list additions direclty, but for now handle it on our own } // eslint-disable-next-line no-use-before-define return SetField(socket, diff); @@ -163,37 +133,41 @@ export namespace WebSocket { return !pendingOps.get(id)!.length && pendingOps.delete(id); } - function addToListField(socket: Socket, diffIn: Diff, curListItems?: Transferable): void { + function addToListField(socket: Socket, diffIn: Diff, listDoc?: serializedDoctype): void { const diff = diffIn; diff.diff.$set = diff.diff.$addToSet; delete diff.diff.$addToSet; // convert add to set to a query of the current fields, and then a set of the composition of the new fields with the old ones - const updatefield = Array.from(Object.keys(diff.diff.$set))[0]; - const newListItems = diff.diff.$set[updatefield]?.fields; + const updatefield = Array.from(Object.keys(diff.diff.$set ?? {}))[0]; + const newListItems = diff.diff.$set?.[updatefield]?.fields; if (!newListItems) { console.log('Error: addToListField - no new list items'); return; } - const curList = (curListItems as any)?.fields?.[updatefield.replace('fields.', '')]?.fields.filter((item: any) => item !== undefined) || []; - diff.diff.$set[updatefield].fields = [...curList, ...newListItems]; // , ...newListItems.filter((newItem: any) => newItem === null || !curList.some((curItem: any) => curItem.fieldId ? curItem.fieldId === newItem.fieldId : curItem.heading ? curItem.heading === newItem.heading : curItem === newItem))]; - const sendBack = diff.diff.length !== diff.diff.$set[updatefield].fields.length; - delete diff.diff.length; - Database.Instance.update( - diff.id, - diff.diff, - () => { - if (sendBack) { - console.log('Warning: list modified during update. Composite list is being returned.'); - const { id } = socket; - (socket as any).id = ''; // bcz: HACK. this prevents the update message from going back to the client that made the change. - socket.broadcast.emit(MessageStore.UpdateField.Message, diff); - (socket as any).id = id; - } else { - socket.broadcast.emit(MessageStore.UpdateField.Message, diff); - } - dispatchNextOp(diff.id); - }, - false - ); + const listItems = listDoc?.fields?.[updatefield.replace('fields.', '')]?.fields.filter(item => item !== undefined) ?? []; + if (diff.diff.$set?.[updatefield]?.fields !== undefined) { + diff.diff.$set[updatefield]!.fields = [...listItems, ...newListItems]; // , ...newListItems.filter((newItem: any) => newItem === null || !curList.some((curItem: any) => curItem.fieldId ? curItem.fieldId === newItem.fieldId : curItem.heading ? curItem.heading === newItem.heading : curItem === newItem))]; + const sendBack = diff.diff.length !== diff.diff.$set[updatefield]!.fields?.length; + delete diff.diff.length; + Database.Instance.update( + diff.id, + diff.diff, + () => { + if (sendBack) { + console.log('Warning: list modified during update. Composite list is being returned.'); + const { id } = socket; + // eslint-disable-next-line @typescript-eslint/no-explicit-any + (socket as any).id = ''; // bcz: HACK to reference private variable. this allows the update message to go back to the client that made the change. + socket.broadcast.emit(MessageStore.UpdateField.Message, diff); + // eslint-disable-next-line @typescript-eslint/no-explicit-any + (socket as any).id = id; + } else { + socket.broadcast.emit(MessageStore.UpdateField.Message, diff); + } + dispatchNextOp(diff.id); + }, + false + ); + } } /** @@ -208,7 +182,7 @@ export namespace WebSocket { * the data * @returns the closest index with the same value or -1 if the element was not found. */ - function findClosestIndex(list: any, indexesToDelete: number[], value: any, hintIndex: number) { + function findClosestIndex(list: { fieldId: string; __type: string }[], indexesToDelete: number[], value: { fieldId: string; __type: string }, hintIndex: number) { let closestIndex = -1; for (let i = 0; i < list.length; i++) { if (list[i] === value && !indexesToDelete.includes(i)) { @@ -232,63 +206,63 @@ export namespace WebSocket { * items to delete) * @param curListItems the server's current copy of the data */ - function remFromListField(socket: Socket, diffIn: Diff, curListItems?: Transferable): void { + function remFromListField(socket: Socket, diffIn: Diff, curListItems?: serializedDoctype): void { const diff = diffIn; - diff.diff.$set = diff.diff.$remFromSet; + diff.diff.$set = diff.diff.$remFromSet as serializedFieldsType; + const hint = diff.diff.$remFromSet?.hint; delete diff.diff.$remFromSet; - const updatefield = Array.from(Object.keys(diff.diff.$set))[0]; - const remListItems = diff.diff.$set[updatefield].fields; - const curList = (curListItems as any)?.fields?.[updatefield.replace('fields.', '')]?.fields.filter((f: any) => f !== null) || []; - const { hint } = diff.diff.$set; - - if (hint) { - // indexesToRemove stores the indexes that we mark for deletion, which is later used to filter the list (delete the elements) - const indexesToRemove: number[] = []; - for (let i = 0; i < hint.deleteCount; i++) { - if (curList.length > i + hint.start && _.isEqual(curList[i + hint.start], remListItems[i])) { - indexesToRemove.push(i + hint.start); - } else { - const closestIndex = findClosestIndex(curList, indexesToRemove, remListItems[i], i + hint.start); - if (closestIndex !== -1) { - indexesToRemove.push(closestIndex); + const updatefield = Array.from(Object.keys(diff.diff.$set ?? {}))[0]; + const remListItems = diff.diff.$set[updatefield]?.fields; + if (diff.diff.$set[updatefield] !== undefined && remListItems) { + const curList = curListItems?.fields?.[updatefield.replace('fields.', '')]?.fields.filter(f => f !== null) || []; + + if (hint) { + // indexesToRemove stores the indexes that we mark for deletion, which is later used to filter the list (delete the elements) + const indexesToRemove: number[] = []; + for (let i = 0; i < hint.deleteCount; i++) { + if (curList.length > i + hint.start && _.isEqual(curList[i + hint.start], remListItems[i])) { + indexesToRemove.push(i + hint.start); } else { - console.log('Item to delete was not found - index = -1'); + const closestIndex = findClosestIndex(curList, indexesToRemove, remListItems[i], i + hint.start); + if (closestIndex !== -1) { + indexesToRemove.push(closestIndex); + } else { + console.log('Item to delete was not found - index = -1'); + } } } + diff.diff.$set[updatefield]!.fields = curList.filter((curItem, index) => !indexesToRemove.includes(index)); + } else { + // go back to the original way to delete if we didn't receive + // a hint from the client + diff.diff.$set[updatefield]!.fields = curList?.filter(curItem => !remListItems.some(remItem => (remItem.fieldId ? remItem.fieldId === curItem.fieldId : remItem.heading ? remItem.heading === curItem.heading : remItem === curItem))); } - - diff.diff.$set[updatefield].fields = curList?.filter((curItem: any, index: number) => !indexesToRemove.includes(index)); - } else { - // go back to the original way to delete if we didn't receive - // a hint from the client - diff.diff.$set[updatefield].fields = curList?.filter( - (curItem: any) => !remListItems.some((remItem: any) => (remItem.fieldId ? remItem.fieldId === curItem.fieldId : remItem.heading ? remItem.heading === curItem.heading : remItem === curItem)) + // if the client and server have different versions of the data after + // deletion, they will have different lengths and the server will + // send its version of the data to the client + const sendBack = diff.diff.length !== remListItems.length; + delete diff.diff.length; + Database.Instance.update( + diff.id, + diff.diff, + () => { + if (sendBack) { + // the two copies are different, so the server sends its copy. + console.log('SEND BACK'); + const { id } = socket; + // eslint-disable-next-line @typescript-eslint/no-explicit-any + (socket as any).id = ''; // bcz: HACK to access private variable this allows the update message to go back to the client that made the change. + socket.broadcast.emit(MessageStore.UpdateField.Message, diff); + // eslint-disable-next-line @typescript-eslint/no-explicit-any + (socket as any).id = id; + } else { + socket.broadcast.emit(MessageStore.UpdateField.Message, diff); + } + dispatchNextOp(diff.id); + }, + false ); } - - // if the client and server have different versions of the data after - // deletion, they will have different lengths and the server will - // send its version of the data to the client - const sendBack = diff.diff.length !== diff.diff.$set[updatefield].fields.length; - delete diff.diff.length; - Database.Instance.update( - diff.id, - diff.diff, - () => { - if (sendBack) { - // the two copies are different, so the server sends its copy. - console.log('SEND BACK'); - const { id } = socket; - (socket as any).id = ''; // bcz: HACK. this prevents the update message from going back to the client that made the change. - socket.broadcast.emit(MessageStore.UpdateField.Message, diff); - (socket as any).id = id; - } else { - socket.broadcast.emit(MessageStore.UpdateField.Message, diff); - } - dispatchNextOp(diff.id); - }, - false - ); } function UpdateField(socket: Socket, diff: Diff) { @@ -307,43 +281,16 @@ export namespace WebSocket { } pendingOps.set(diff.id, [{ diff, socket }]); if (diff.diff.$addToSet) { - return GetRefFieldLocal([diff.id, (result?: Transferable) => addToListField(socket, diff, result)]); // would prefer to have Mongo handle list additions direclty, but for now handle it on our own + return GetRefFieldLocal([diff.id, (result?: serializedDoctype) => addToListField(socket, diff, result)]); // would prefer to have Mongo handle list additions direclty, but for now handle it on our own } if (diff.diff.$remFromSet) { - return GetRefFieldLocal([diff.id, (result?: Transferable) => remFromListField(socket, diff, result)]); // would prefer to have Mongo handle list additions direclty, but for now handle it on our own + return GetRefFieldLocal([diff.id, (result?: serializedDoctype) => remFromListField(socket, diff, result)]); // would prefer to have Mongo handle list additions direclty, but for now handle it on our own } // eslint-disable-next-line no-use-before-define return SetField(socket, diff); } function SetField(socket: Socket, diff: Diff /* , curListItems?: Transferable */) { Database.Instance.update(diff.id, diff.diff, () => socket.broadcast.emit(MessageStore.UpdateField.Message, diff), false); - const docfield = diff.diff.$set || diff.diff.$unset; - if (docfield) { - const update: any = { id: diff.id }; - let dynfield = false; - // eslint-disable-next-line no-restricted-syntax - for (let key in docfield) { - // eslint-disable-next-line no-continue - if (!key.startsWith('fields.')) continue; - dynfield = true; - const val = docfield[key]; - key = key.substring(7); - Object.values(suffixMap).forEach(suf => { - update[key + getSuffix(suf)] = { set: null }; - }); - const term = ToSearchTerm(val); - if (term !== undefined) { - const { suffix, value } = term; - update[key + suffix] = { set: value }; - if (key.endsWith('modificationDate')) { - update['modificationDate' + suffix] = value; - } - } - } - if (dynfield) { - Search.updateDocument(update); - } - } dispatchNextOp(diff.id); } @@ -351,21 +298,15 @@ export namespace WebSocket { Database.Instance.delete({ _id: id }).then(() => { socket.broadcast.emit(MessageStore.DeleteField.Message, id); }); - - Search.deleteDocuments([id]); } function DeleteFields(socket: Socket, ids: string[]) { Database.Instance.delete({ _id: { $in: ids } }).then(() => { socket.broadcast.emit(MessageStore.DeleteFields.Message, ids); }); - Search.deleteDocuments(ids); } - function CreateField(newValue: any) { - Database.Instance.insert(newValue); - } - export async function initialize(isRelease: boolean, credentials: any) { + export async function initialize(isRelease: boolean, credentials: SecureContextOptions) { let io: Server; if (isRelease) { const { socketPort } = process.env; @@ -422,21 +363,14 @@ export namespace WebSocket { ServerUtils.Emit(socket, MessageStore.Foo, 'handshooken'); ServerUtils.AddServerHandler(socket, MessageStore.Bar, guid => barReceived(socket, guid)); - ServerUtils.AddServerHandler(socket, MessageStore.SetField, args => setField(socket, args)); - ServerUtils.AddServerHandlerCallback(socket, MessageStore.GetField, getField); - ServerUtils.AddServerHandlerCallback(socket, MessageStore.GetFields, getFields); if (isRelease) { ServerUtils.AddServerHandler(socket, MessageStore.DeleteAll, () => doDelete(false)); } - ServerUtils.AddServerHandler(socket, MessageStore.CreateField, CreateField); ServerUtils.AddServerHandler(socket, MessageStore.UpdateField, diff => UpdateField(socket, diff)); ServerUtils.AddServerHandler(socket, MessageStore.DeleteField, id => DeleteField(socket, id)); ServerUtils.AddServerHandler(socket, MessageStore.DeleteFields, ids => DeleteFields(socket, ids)); ServerUtils.AddServerHandler(socket, MessageStore.GesturePoints, content => processGesturePoints(socket, content)); - ServerUtils.AddServerHandler(socket, MessageStore.MobileInkOverlayTrigger, content => processOverlayTrigger(socket, content)); - ServerUtils.AddServerHandler(socket, MessageStore.UpdateMobileInkOverlayPosition, content => processUpdateOverlayPosition(socket, content)); - ServerUtils.AddServerHandler(socket, MessageStore.MobileDocumentUpload, content => processMobileDocumentUpload(socket, content)); ServerUtils.AddServerHandlerCallback(socket, MessageStore.GetRefField, GetRefField); ServerUtils.AddServerHandlerCallback(socket, MessageStore.GetRefFields, GetRefFields); -- cgit v1.2.3-70-g09d2 From fe91a8cd62ee1793f4a1d38c3ed4a1b451f4e3a4 Mon Sep 17 00:00:00 2001 From: bobzel Date: Tue, 13 Aug 2024 15:55:01 -0400 Subject: fix for linear views --- src/client/views/collections/collectionLinear/CollectionLinearView.tsx | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/client/views/collections/collectionLinear/CollectionLinearView.tsx b/src/client/views/collections/collectionLinear/CollectionLinearView.tsx index 3af8464c2..ceae43c04 100644 --- a/src/client/views/collections/collectionLinear/CollectionLinearView.tsx +++ b/src/client/views/collections/collectionLinear/CollectionLinearView.tsx @@ -22,6 +22,7 @@ import { DocumentLinksButton } from '../../nodes/DocumentLinksButton'; import { DocumentView } from '../../nodes/DocumentView'; import { LinkDescriptionPopup } from '../../nodes/LinkDescriptionPopup'; import { CollectionSubView, SubCollectionViewProps } from '../CollectionSubView'; +import './CollectionLinearView.scss'; /** * CollectionLinearView is the class for rendering the horizontal collection -- cgit v1.2.3-70-g09d2 From 5960fa9635c28c2b609826005cb7595ec6b9fb75 Mon Sep 17 00:00:00 2001 From: bobzel Date: Tue, 13 Aug 2024 16:31:13 -0400 Subject: fixed bugs introduced cleaning up database list ops. --- src/client/DocServer.ts | 16 ++++++++-------- src/fields/Doc.ts | 2 +- src/server/Message.ts | 2 +- src/server/websocket.ts | 7 ++++++- 4 files changed, 16 insertions(+), 11 deletions(-) (limited to 'src') diff --git a/src/client/DocServer.ts b/src/client/DocServer.ts index 33fa928f2..c644308b7 100644 --- a/src/client/DocServer.ts +++ b/src/client/DocServer.ts @@ -34,7 +34,7 @@ export namespace DocServer { throw new Error("Can't use DocServer without calling init first"); } let _UpdateField: (id: string, diff: serverOpType) => void = errorFunc; - let _CreateField: (field: Doc) => void = errorFunc; + let _CreateDocField: (field: Doc) => void = errorFunc; export function AddServerHandler(socket: Socket, message: Message, handler: (args: T) => void) { socket.on(message.Message, Utils.loggingCallback('Incoming', handler, message.Name)); @@ -132,7 +132,7 @@ export namespace DocServer { export function makeReadOnly() { if (!_isReadOnly) { _isReadOnly = true; - _CreateField = field => { + _CreateDocField = field => { _cache[field[Id]] = field; }; _UpdateField = emptyFunction; @@ -357,20 +357,20 @@ export namespace DocServer { } /** - * A wrapper around the function local variable _createField. + * A wrapper around the function local variable _CreateDocField. * This allows us to swap in different executions while comfortably * calling the same function throughout the code base (such as in Util.makeReadonly()) * @param field the [RefField] to be serialized and sent to the server to be stored in the database */ - export function CreateField(field: Doc) { + export function CreateDocField(field: Doc) { _cacheNeedsUpdate = true; - _CreateField(field); + _CreateDocField(field); } - function _CreateFieldImpl(field: Doc) { + function _CreateDocFieldImpl(field: Doc) { _cache[field[Id]] = field; const initialState = SerializationHelper.Serialize(field); - ClientUtils.CurrentUserEmail() !== 'guest' && DocServer.Emit(_socket, MessageStore.CreateField, initialState); + ClientUtils.CurrentUserEmail() !== 'guest' && DocServer.Emit(_socket, MessageStore.CreateDocField, initialState); } // NOTIFY THE SERVER OF AN UPDATE TO A DOC'S STATE @@ -462,7 +462,7 @@ export namespace DocServer { _GetCachedRefField = _GetCachedRefFieldImpl; SetObjGetRefField((_GetRefField = _GetRefFieldImpl)); SetObjGetRefFields((_GetRefFields = _GetRefFieldsImpl)); - _CreateField = _CreateFieldImpl; + _CreateDocField = _CreateDocFieldImpl; _UpdateField = _UpdateFieldImpl; /** diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts index ad7609895..2ae9dbf02 100644 --- a/src/fields/Doc.ts +++ b/src/fields/Doc.ts @@ -329,7 +329,7 @@ export class Doc extends RefField { }); this[SelfProxy] = docProxy; if (!id || forceSave) { - DocServer.CreateField(docProxy); + 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 diff --git a/src/server/Message.ts b/src/server/Message.ts index 4599708c9..b904a5ba3 100644 --- a/src/server/Message.ts +++ b/src/server/Message.ts @@ -56,7 +56,7 @@ export namespace MessageStore { export const GetRefField = new Message('Get Ref Field'); export const GetRefFields = new Message('Get Ref Fields'); export const UpdateField = new Message('Update Ref Field'); - export const CreateField = new Message('Create Ref Field'); + export const CreateDocField = new Message('Create Ref Field'); export const DeleteField = new Message('Delete field'); export const DeleteFields = new Message('Delete fields'); diff --git a/src/server/websocket.ts b/src/server/websocket.ts index f10455680..f588151a5 100644 --- a/src/server/websocket.ts +++ b/src/server/websocket.ts @@ -240,7 +240,7 @@ export namespace WebSocket { // if the client and server have different versions of the data after // deletion, they will have different lengths and the server will // send its version of the data to the client - const sendBack = diff.diff.length !== remListItems.length; + const sendBack = diff.diff.length !== diff.diff.$set[updatefield].fields.length; delete diff.diff.length; Database.Instance.update( diff.id, @@ -306,6 +306,10 @@ export namespace WebSocket { }); } + function CreateDocField(newValue: serializedDoctype) { + Database.Instance.insert(newValue); + } + export async function initialize(isRelease: boolean, credentials: SecureContextOptions) { let io: Server; if (isRelease) { @@ -367,6 +371,7 @@ export namespace WebSocket { ServerUtils.AddServerHandler(socket, MessageStore.DeleteAll, () => doDelete(false)); } + ServerUtils.AddServerHandler(socket, MessageStore.CreateDocField, CreateDocField); ServerUtils.AddServerHandler(socket, MessageStore.UpdateField, diff => UpdateField(socket, diff)); ServerUtils.AddServerHandler(socket, MessageStore.DeleteField, id => DeleteField(socket, id)); ServerUtils.AddServerHandler(socket, MessageStore.DeleteFields, ids => DeleteFields(socket, ids)); -- cgit v1.2.3-70-g09d2 From 25ea424ab2e6c32272e828b98822eb32f1fe2cab Mon Sep 17 00:00:00 2001 From: bobzel Date: Thu, 15 Aug 2024 11:14:04 -0400 Subject: cleaned up server list add/rem. --- src/ServerUtils.ts | 10 +- src/Utils.ts | 16 +- src/client/views/DocComponent.tsx | 4 +- src/client/views/StyleProvider.tsx | 3 +- src/client/views/collections/TabDocView.tsx | 10 +- src/client/views/collections/TreeView.tsx | 6 +- src/client/views/nodes/DocumentContentsView.tsx | 3 +- .../views/nodes/formattedText/FormattedTextBox.tsx | 38 ++-- src/client/views/nodes/trails/PresBox.tsx | 98 ++++---- src/client/views/nodes/trails/SlideEffect.tsx | 2 +- src/fields/ObjectField.ts | 5 +- src/fields/RichTextUtils.ts | 56 +++-- src/fields/util.ts | 4 +- src/server/database.ts | 2 +- src/server/websocket.ts | 248 +++++++-------------- 15 files changed, 201 insertions(+), 304 deletions(-) (limited to 'src') diff --git a/src/ServerUtils.ts b/src/ServerUtils.ts index 7e821cda2..904541fc7 100644 --- a/src/ServerUtils.ts +++ b/src/ServerUtils.ts @@ -9,20 +9,20 @@ export namespace ServerUtils { socket.emit(message.Message, args); } - export function AddServerHandler(socket: Socket, message: Message, handler: (args: T) => any) { + export function AddServerHandler(socket: Socket, message: Message, handler: (args: T) => void) { socket.on(message.Message, Utils.loggingCallback('Incoming', handler, message.Name)); } - export function AddServerHandlerCallback(socket: Socket, message: Message, handler: (args: [T, (res: any) => any]) => any) { - socket.on(message.Message, (arg: T, fn: (res: any) => any) => { + export function AddServerHandlerCallback(socket: Socket, message: Message, handler: (args: [T, (res: unknown) => void]) => void) { + socket.on(message.Message, (arg: T, fn: (res: unknown) => void) => { Utils.log('S receiving', message.Name, arg, true); handler([arg, Utils.loggingCallback('S sending', fn, message.Name)]); }); } - export type RoomHandler = (socket: Socket, room: string) => any; + export type RoomHandler = (socket: Socket, room: string) => void; export type UsedSockets = Socket; export type RoomMessage = 'create or join' | 'created' | 'joined'; export function AddRoomHandler(socket: Socket, message: RoomMessage, handler: RoomHandler) { - socket.on(message, (room: any) => handler(socket, room)); + socket.on(message, room => handler(socket, room)); } } diff --git a/src/Utils.ts b/src/Utils.ts index 23ae38bdb..0590c6930 100644 --- a/src/Utils.ts +++ b/src/Utils.ts @@ -1,3 +1,4 @@ +/* eslint-disable @typescript-eslint/no-namespace */ import * as uuid from 'uuid'; export function clamp(n: number, lower: number, upper: number) { @@ -23,6 +24,7 @@ export namespace Utils { export const loggingEnabled = false; export const logFilter: number | undefined = undefined; + // eslint-disable-next-line @typescript-eslint/no-explicit-any export function log(prefixIn: string, messageName: string, messageIn: any, receiving: boolean) { let prefix = prefixIn; let message = messageIn; @@ -38,8 +40,9 @@ export namespace Utils { console.log(`${prefix}: ${idString}, ${receiving ? 'receiving' : 'sending'} ${messageName} with data ${JSON.stringify(message)} `); } - export function loggingCallback(prefix: string, func: (args: any) => any, messageName: string) { - return (args: any) => { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + export function loggingCallback(prefix: string, func: (args: any) => void, messageName: string) { + return (args: unknown) => { log(prefix, messageName, args, true); func(args); }; @@ -47,7 +50,9 @@ export namespace Utils { export function TraceConsoleLog() { ['log', 'warn'].forEach(method => { + // eslint-disable-next-line @typescript-eslint/no-explicit-any const old = (console as any)[method]; + // eslint-disable-next-line @typescript-eslint/no-explicit-any (console as any)[method] = function (...args: any[]) { let stack = new Error('').stack?.split(/\n/); // Chrome includes a single "Error" line, FF doesn't. @@ -158,7 +163,7 @@ export function timenow() { const now = new Date(); let ampm = 'am'; let h = now.getHours(); - let m: any = now.getMinutes(); + let m: string | number = now.getMinutes(); if (h >= 12) { if (h > 12) h -= 12; ampm = 'pm'; @@ -201,7 +206,7 @@ export function intersectRect(r1: { left: number; top: number; width: number; he export function stringHash(s?: string) { // eslint-disable-next-line no-bitwise - return !s ? undefined : Math.abs(s.split('').reduce((a: any, b: any) => (n => n & n)((a << 5) - a + b.charCodeAt(0)), 0)); + return !s ? undefined : Math.abs(s.split('').reduce((a, b) => (n => n & n)((a << 5) - a + b.charCodeAt(0)), 0)); } export function percent2frac(percent: string) { @@ -224,8 +229,6 @@ export function emptyFunction() { return undefined; } -export const emptyPath: any[] = []; - export function unimplementedFunction() { throw new Error('This function is not implemented, but should be.'); } @@ -246,6 +249,7 @@ export function DeepCopy(source: Map, predicate?: Predicate) { export namespace JSONUtils { export function tryParse(source: string) { + // eslint-disable-next-line @typescript-eslint/no-explicit-any let results: any; try { results = JSON.parse(source); diff --git a/src/client/views/DocComponent.tsx b/src/client/views/DocComponent.tsx index e5752dcd2..e351e2dec 100644 --- a/src/client/views/DocComponent.tsx +++ b/src/client/views/DocComponent.tsx @@ -93,7 +93,7 @@ export function ViewBoxBaseComponent

() { * This is the unique data repository for a dcoument that stores the intrinsic document data */ @computed get dataDoc() { - return this.Document.isTemplateForField || this.Document.isTemplateDoc ? this._props.TemplateDataDocument ?? this.Document[DocData] : this.Document[DocData]; + return this.Document.isTemplateForField || this.Document.isTemplateDoc ? (this._props.TemplateDataDocument ?? this.Document[DocData]) : this.Document[DocData]; } /** @@ -151,7 +151,7 @@ export function ViewBoxAnnotatableComponent

() { * This is the unique data repository for a dcoument that stores the intrinsic document data */ @computed get dataDoc() { - return this.Document.isTemplateForField || this.Document.isTemplateDoc ? this._props.TemplateDataDocument ?? this.Document[DocData] : this.Document[DocData]; + return this.Document.isTemplateForField || this.Document.isTemplateDoc ? (this._props.TemplateDataDocument ?? this.Document[DocData]) : this.Document[DocData]; } /** diff --git a/src/client/views/StyleProvider.tsx b/src/client/views/StyleProvider.tsx index 2792955a0..374f8ca3a 100644 --- a/src/client/views/StyleProvider.tsx +++ b/src/client/views/StyleProvider.tsx @@ -13,7 +13,6 @@ import { Id } from '../../fields/FieldSymbols'; import { ScriptField } from '../../fields/ScriptField'; import { BoolCast, Cast, DocCast, ImageCast, NumCast, ScriptCast, StrCast } from '../../fields/Types'; import { AudioAnnoState } from '../../server/SharedMediaTypes'; -import { emptyPath } from '../../Utils'; import { CollectionViewType, DocumentType } from '../documents/DocumentTypes'; import { IsFollowLinkScript } from '../documents/DocUtils'; import { SnappingManager } from '../util/SnappingManager'; @@ -406,5 +405,5 @@ export function DashboardStyleProvider(doc: Opt, props: Opt } export function returnEmptyDocViewList() { - return emptyPath; + return [] as DocumentView[]; } diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx index f168db81b..31b6be927 100644 --- a/src/client/views/collections/TabDocView.tsx +++ b/src/client/views/collections/TabDocView.tsx @@ -7,7 +7,7 @@ import { observer } from 'mobx-react'; import * as React from 'react'; import * as ReactDOM from 'react-dom/client'; import ResizeObserver from 'resize-observer-polyfill'; -import { ClientUtils, DashColor, lightOrDark, returnFalse, returnTrue, setupMoveUpEvents, simulateMouseClick } from '../../../ClientUtils'; +import { ClientUtils, DashColor, lightOrDark, returnEmptyFilter, returnFalse, returnTrue, setupMoveUpEvents, simulateMouseClick } from '../../../ClientUtils'; import { emptyFunction } from '../../../Utils'; import { Doc, Opt, returnEmptyDoclist } from '../../../fields/Doc'; import { DocData } from '../../../fields/DocSymbols'; @@ -157,8 +157,8 @@ export class TabMinimapView extends ObservableReactComponent { PanelWidth={this.PanelWidth} PanelHeight={this.PanelHeight} styleProvider={DefaultStyleProvider} - childFilters={CollectionDockingView.Instance?.childDocFilters ?? returnEmptyDocViewList} - childFiltersByRanges={CollectionDockingView.Instance?.childDocRangeFilters ?? returnEmptyDocViewList} + childFilters={CollectionDockingView.Instance?.childDocFilters ?? returnEmptyFilter} + childFiltersByRanges={CollectionDockingView.Instance?.childDocRangeFilters ?? returnEmptyFilter} searchFilterDocs={CollectionDockingView.Instance?.searchFilterDocs ?? returnEmptyDoclist} addDocument={undefined} removeDocument={this.remDocTab} diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx index c0fe7a894..b10a521ca 100644 --- a/src/client/views/collections/TreeView.tsx +++ b/src/client/views/collections/TreeView.tsx @@ -6,7 +6,7 @@ import { observer } from 'mobx-react'; import * as React from 'react'; import { ClientUtils, lightOrDark, return18, returnEmptyFilter, returnEmptyString, returnFalse, returnTrue, returnZero, setupMoveUpEvents, simulateMouseClick } from '../../../ClientUtils'; import { emptyFunction } from '../../../Utils'; -import { Doc, DocListCast, Field, FieldResult, FieldType, Opt, StrListCast, returnEmptyDoclist } from '../../../fields/Doc'; +import { Doc, DocListCast, Field, FieldType, Opt, StrListCast, returnEmptyDoclist } from '../../../fields/Doc'; import { DocData } from '../../../fields/DocSymbols'; import { Id } from '../../../fields/FieldSymbols'; import { List } from '../../../fields/List'; @@ -249,7 +249,7 @@ export class TreeView extends ObservableReactComponent { return []; } - const runningChildren: FieldResult[] = []; + const runningChildren: Doc[] = []; childList.forEach(child => { if (child.runProcess && TreeView.GetRunningChildren.get(child)) { if (child.runProcess) { @@ -261,7 +261,7 @@ export class TreeView extends ObservableReactComponent { return runningChildren; }; - static GetRunningChildren = new Map FieldResult[]>(); + static GetRunningChildren = new Map Doc[]>(); static ToggleChildrenRun = new Map void>(); constructor(props: TreeViewProps) { super(props); diff --git a/src/client/views/nodes/DocumentContentsView.tsx b/src/client/views/nodes/DocumentContentsView.tsx index b178d6554..15baebae1 100644 --- a/src/client/views/nodes/DocumentContentsView.tsx +++ b/src/client/views/nodes/DocumentContentsView.tsx @@ -192,6 +192,7 @@ export class DocumentContentsView extends ObservableReactComponent 12 || !layoutFrame || !this.layoutDoc || GetEffectiveAcl(this.layoutDoc) === AclPrivate ? null : ( new FormattedTextBoxComment() }), + ], + }; + } private static nodeViews: (self: FormattedTextBox) => { [key: string]: NodeViewConstructor }; /** * Initialize the class with all the plugin node view components @@ -108,7 +123,6 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent; - private _keymap: KeyMap | undefined = undefined; private _rules: RichTextRules | undefined; private _forceUncollapse = true; // if the cursor doesn't move between clicks, then the selection will disappear for some reason. This flags the 2nd click as happening on a selection which allows bullet points to toggle private _break = true; @@ -128,20 +142,8 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent new FormattedTextBoxComment() }), - ], - }; + return FormattedTextBox.MakeConfig(this._rules, this._props); } public get EditorView() { @@ -1380,11 +1382,11 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent { - this._props.rootSelected?.() && RichTextMenu.Instance && (RichTextMenu.Instance.view = newView); - return new RichTextMenuPlugin({ editorProps: this._props }); + props?.rootSelected?.() && RichTextMenu.Instance && (RichTextMenu.Instance.view = newView); + return new RichTextMenuPlugin({ editorProps: props }); }), }); } diff --git a/src/client/views/nodes/trails/PresBox.tsx b/src/client/views/nodes/trails/PresBox.tsx index 0c73400a9..c403f9415 100644 --- a/src/client/views/nodes/trails/PresBox.tsx +++ b/src/client/views/nodes/trails/PresBox.tsx @@ -1,5 +1,3 @@ -/* eslint-disable jsx-a11y/no-static-element-interactions */ -/* eslint-disable jsx-a11y/click-events-have-key-events */ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { Tooltip } from '@mui/material'; import Slider from '@mui/material/Slider'; @@ -32,7 +30,7 @@ import { dropActionType } from '../../../util/DropActionTypes'; import { ScriptingGlobals } from '../../../util/ScriptingGlobals'; import { SerializationHelper } from '../../../util/SerializationHelper'; import { SnappingManager } from '../../../util/SnappingManager'; -import { undoBatch, UndoManager } from '../../../util/UndoManager'; +import { undoable, undoBatch, UndoManager } from '../../../util/UndoManager'; import { CollectionFreeFormView } from '../../collections/collectionFreeForm'; import { CollectionFreeFormPannableContents } from '../../collections/collectionFreeForm/CollectionFreeFormPannableContents'; import { CollectionView } from '../../collections/CollectionView'; @@ -191,7 +189,7 @@ export class PresBox extends ViewBoxBaseComponent() { @computed get isTreeOrStack() { - return [CollectionViewType.Tree, CollectionViewType.Stacking].includes(StrCast(this.layoutDoc._type_collection) as any); + return [CollectionViewType.Tree, CollectionViewType.Stacking].includes(StrCast(this.layoutDoc._type_collection) as CollectionViewType); } @computed get isTree() { return this.layoutDoc._type_collection === CollectionViewType.Tree; @@ -304,7 +302,7 @@ export class PresBox extends ViewBoxBaseComponent() { // 'Play on next' for audio or video therefore first navigate to the audio/video before it should be played startTempMedia = (targetDoc: Doc, activeItem: Doc) => { const duration: number = NumCast(activeItem.config_clipEnd) - NumCast(activeItem.config_clipStart); - if ([DocumentType.VID, DocumentType.AUDIO].includes(targetDoc.type as any)) { + if ([DocumentType.VID, DocumentType.AUDIO].includes(targetDoc.type as DocumentType)) { const targMedia = DocumentView.getDocumentView(targetDoc); targMedia?.ComponentView?.playFrom?.(NumCast(activeItem.config_clipStart), NumCast(activeItem.config_clipStart) + duration); } @@ -312,7 +310,7 @@ export class PresBox extends ViewBoxBaseComponent() { stopTempMedia = (targetDocField: FieldResult) => { const targetDoc = DocCast(DocCast(targetDocField).annotationOn) ?? DocCast(targetDocField); - if ([DocumentType.VID, DocumentType.AUDIO].includes(targetDoc.type as any)) { + if ([DocumentType.VID, DocumentType.AUDIO].includes(targetDoc.type as DocumentType)) { const targMedia = DocumentView.getDocumentView(targetDoc); targMedia?.ComponentView?.Pause?.(); } @@ -364,7 +362,7 @@ export class PresBox extends ViewBoxBaseComponent() { this.setIsRecording(false); this.setIsLoading(true); - const currSlideProperties: { [key: string]: any } = {}; + const currSlideProperties: { [key: string]: FieldResult } = {}; gptSlideProperties.forEach(key => { if (this.activeItem[key]) { currSlideProperties[key] = this.activeItem[key]; @@ -554,7 +552,7 @@ export class PresBox extends ViewBoxBaseComponent() { } }); static pinDataTypes(target?: Doc): dataTypes { - const targetType = target?.type as any; + const targetType = target?.type as DocumentType; const inkable = [DocumentType.INK].includes(targetType); const scrollable = [DocumentType.PDF, DocumentType.RTF, DocumentType.WEB].includes(targetType) || target?._type_collection === CollectionViewType.Stacking; const pannable = [DocumentType.IMG, DocumentType.PDF].includes(targetType) || (targetType === DocumentType.COL && target?._type_collection === CollectionViewType.Freeform); @@ -759,8 +757,8 @@ export class PresBox extends ViewBoxBaseComponent() { const doc = DocCast(DocServer.GetCachedRefField(data.id)); if (doc) { transitioned.add(doc); - const field = !data.data ? undefined : await SerializationHelper.Deserialize(data.data); - const tfield = !data.text ? undefined : await SerializationHelper.Deserialize(data.text); + const field = !data.data ? undefined : ((await SerializationHelper.Deserialize(data.data)) as FieldType); + const tfield = !data.text ? undefined : ((await SerializationHelper.Deserialize(data.text)) as FieldType); doc._dataTransition = `all ${transTime}ms`; doc.x = data.x; doc.y = data.y; @@ -858,7 +856,7 @@ export class PresBox extends ViewBoxBaseComponent() { effect: activeItem, noSelect: true, openLocation: targetDoc.type === DocumentType.PRES ? ((OpenWhere.replace + ':' + PresBox.PanelName) as OpenWhere) : OpenWhere.addLeft, - easeFunc: StrCast(activeItem.presentation_easeFunc, 'ease') as any, + easeFunc: StrCast(activeItem.presentation_easeFunc, 'ease') as 'linear' | 'ease', zoomTextSelections: BoolCast(activeItem.presentation_zoomText), playAudio: BoolCast(activeItem.presentation_playAudio), playMedia: activeItem.presentation_mediaStart === 'auto', @@ -1101,7 +1099,7 @@ export class PresBox extends ViewBoxBaseComponent() { */ @undoBatch viewChanged = action((e: React.ChangeEvent) => { - const typeCollection = (e.target as any).selectedOptions[0].value as CollectionViewType; + const typeCollection = (e.target as HTMLSelectElement).selectedOptions[0].value as CollectionViewType; this.layoutDoc.presFieldKey = this.fieldKey + (typeCollection === CollectionViewType.Tree ? '-linearized' : ''); // pivot field may be set by the user in timeline view (or some other way) -- need to reset it here [CollectionViewType.Tree || CollectionViewType.Stacking].includes(typeCollection) && (this.Document._pivotField = undefined); @@ -1111,30 +1109,8 @@ export class PresBox extends ViewBoxBaseComponent() { } }); - /** - * Called when the user changes the view type - * Either 'List' (stacking) or 'Slides' (carousel) - */ - // @undoBatch - mediaStopChanged = action((e: React.ChangeEvent) => { - const { activeItem } = this; - const stopDoc = (e.target as any).selectedOptions[0].value as string; - const stopDocIndex = Number(stopDoc[0]); - activeItem.mediaStopDoc = stopDocIndex; - if (this.childDocs[stopDocIndex - 1].mediaStopTriggerList) { - const list = DocListCast(this.childDocs[stopDocIndex - 1].mediaStopTriggerList); - list.push(activeItem); - // this.childDocs[stopDocIndex - 1].mediaStopTriggerList = list;\ - } else { - this.childDocs[stopDocIndex - 1].mediaStopTriggerList = new List(); - const list = DocListCast(this.childDocs[stopDocIndex - 1].mediaStopTriggerList); - list.push(activeItem); - // this.childDocs[stopDocIndex - 1].mediaStopTriggerList = list; - } - }); - movementName = action((activeItem: Doc) => { - if (![PresMovement.Zoom, PresMovement.Pan, PresMovement.Center, PresMovement.Jump, PresMovement.None].includes(StrCast(activeItem.presentation_movement) as any)) { + if (![PresMovement.Zoom, PresMovement.Pan, PresMovement.Center, PresMovement.Jump, PresMovement.None].includes(StrCast(activeItem.presentation_movement) as PresMovement)) { return PresMovement.Zoom; } return StrCast(activeItem.presentation_movement); @@ -1185,7 +1161,7 @@ export class PresBox extends ViewBoxBaseComponent() { * Method to get the list of selected items in the order in which they have been selected */ @computed get listOfSelected() { - return Array.from(this.selectedArray).map((doc: Doc, index: any) => { + return Array.from(this.selectedArray).map((doc, index) => { const curDoc = Cast(doc, Doc, null); const tagDoc = Cast(curDoc.presentation_targetDoc, Doc, null); if (curDoc && curDoc === this.activeItem) @@ -1193,7 +1169,7 @@ export class PresBox extends ViewBoxBaseComponent() { // eslint-disable-next-line react/no-array-index-key

- {index + 1}. {curDoc.title} + {index + 1}. {StrCast(curDoc.title)})
); @@ -1201,14 +1177,14 @@ export class PresBox extends ViewBoxBaseComponent() { return ( // eslint-disable-next-line react/no-array-index-key
- {index + 1}. {curDoc.title} + {index + 1}. {StrCast(curDoc.title)}
); if (curDoc) return ( // eslint-disable-next-line react/no-array-index-key
- {index + 1}. {curDoc.title} + {index + 1}. {StrCast(curDoc.title)}
); return null; @@ -1301,13 +1277,14 @@ export class PresBox extends ViewBoxBaseComponent() { switch (e.key) { case 'Backspace': if (this.layoutDoc.presentation_status === 'edit') { - undoBatch( + undoable( action(() => { Array.from(this.selectedArray).forEach(doc => this.removeDocument(doc)); this.clearSelectedArray(); this._eleArray.length = 0; this._dragArray.length = 0; - }) + }), + 'delete slides' )(); handled = true; } @@ -1488,7 +1465,7 @@ export class PresBox extends ViewBoxBaseComponent() { ); }; // Converts seconds to ms and updates presentation_transition - public static SetTransitionTime = (number: String, setter: (timeInMS: number) => void, change?: number) => { + public static SetTransitionTime = (number: string, setter: (timeInMS: number) => void, change?: number) => { let timeInMS = Number(number) * 1000; if (change) timeInMS += change; if (timeInMS < 100) timeInMS = 100; @@ -1497,7 +1474,7 @@ export class PresBox extends ViewBoxBaseComponent() { }; @undoBatch - updateTransitionTime = (number: String, change?: number) => { + updateTransitionTime = (number: string, change?: number) => { PresBox.SetTransitionTime( number, (timeInMS: number) => @@ -1510,7 +1487,7 @@ export class PresBox extends ViewBoxBaseComponent() { // Converts seconds to ms and updates presentation_transition @undoBatch - updateZoom = (number: String, change?: number) => { + updateZoom = (number: string, change?: number) => { let scale = Number(number) / 100; if (change) scale += change; if (scale < 0.01) scale = 0.01; @@ -1524,7 +1501,7 @@ export class PresBox extends ViewBoxBaseComponent() { * Converts seconds to ms and updates presentation_duration */ @undoBatch - updateDurationTime = (number: String, change?: number) => { + updateDurationTime = (number: string, change?: number) => { let timeInMS = Number(number) * 1000; if (change) timeInMS += change; if (timeInMS < 100) timeInMS = 100; @@ -1608,9 +1585,9 @@ export class PresBox extends ViewBoxBaseComponent() { }); }; - static _sliderBatch: any; + static _sliderBatch: UndoManager.Batch | undefined; static endBatch = () => { - PresBox._sliderBatch.end(); + PresBox._sliderBatch?.end(); document.removeEventListener('pointerup', PresBox.endBatch, true); }; public static inputter = (min: string, step: string, max: string, value: number, active: boolean, change: (val: string) => void, hmargin?: number) => ( @@ -1704,7 +1681,7 @@ export class PresBox extends ViewBoxBaseComponent() {
- {[DocumentType.AUDIO, DocumentType.VID].includes(targetType as any as DocumentType) ? null : ( + {[DocumentType.AUDIO, DocumentType.VID].includes(targetType as DocumentType) ? null : ( <>
Slide Duration
@@ -1847,7 +1824,7 @@ export class PresBox extends ViewBoxBaseComponent() { if (activeItem && this.targetDoc) { const transitionSpeed = activeItem.presentation_transition ? NumCast(activeItem.presentation_transition) / 1000 : 0.5; const zoom = NumCast(activeItem.config_zoom, 1) * 100; - const effect = StrCast(activeItem.presentation_effect) ? (StrCast(activeItem.presentation_effect) as any as PresEffect) : PresEffect.None; + const effect = StrCast(activeItem.presentation_effect) ? (StrCast(activeItem.presentation_effect) as PresEffect) : PresEffect.None; const direction = StrCast(activeItem.presentation_effectDirection) as PresEffectDirection; return ( @@ -2660,24 +2637,26 @@ export class PresBox extends ViewBoxBaseComponent() {
e.stopPropagation()} onPointerUp={e => e.stopPropagation()} onPointerDown={e => e.stopPropagation()}>
{ this.enterMinimize(); this.turnOffEdit(true); this.gotoDocument(this.itemIndex, this.activeItem); - }) + }), + 'minimze presentation' )}> Mini-player
{ this.layoutDoc.presentation_status = 'manual'; this.initializePresState(this.itemIndex); this.turnOffEdit(true); this.gotoDocument(this.itemIndex, this.activeItem); - }) + }), + 'make presentation manual' )}> Sidebar player
@@ -2773,13 +2752,13 @@ export class PresBox extends ViewBoxBaseComponent() {
{ + onClick={undoable(() => { if (this.childDocs.length) { this.layoutDoc.presentation_status = 'manual'; this.initializePresState(this.itemIndex); this.gotoDocument(this.itemIndex, this.activeItem); } - })}> + }, 'start presentation')}>
200 ? 'inline-flex' : 'none' }}>  Present
@@ -2911,11 +2890,12 @@ export class PresBox extends ViewBoxBaseComponent() { {this._props.PanelWidth() > 250 ? (
{ this.layoutDoc.presentation_status = PresStatus.Edit; clearTimeout(this._presTimer); - }) + }), + 'edit presetnation' )}> EXIT
@@ -2988,7 +2968,7 @@ export class PresBox extends ViewBoxBaseComponent() { }; sort = (treeViewMap: Map) => [...treeViewMap.entries()].sort((a: [Doc, number], b: [Doc, number]) => (a[1] > b[1] ? 1 : a[1] < b[1] ? -1 : 0)).map(kv => kv[0]); - + emptyHierarchy = []; render() { // needed to ensure that the childDocs are loaded for looking up fields this.childDocs.slice(); @@ -3086,7 +3066,7 @@ export class PresBox extends ViewBoxBaseComponent() { ScreenToLocalTransform={this.getTransform} AddToMap={this.AddToMap} RemFromMap={this.RemFromMap} - hierarchyIndex={emptyPath} + hierarchyIndex={this.emptyHierarchy} /> ) : null}
diff --git a/src/client/views/nodes/trails/SlideEffect.tsx b/src/client/views/nodes/trails/SlideEffect.tsx index 00039e3cb..a114c231f 100644 --- a/src/client/views/nodes/trails/SlideEffect.tsx +++ b/src/client/views/nodes/trails/SlideEffect.tsx @@ -103,7 +103,7 @@ export default function SpringAnimation({ doc, dir, springSettings, presEffect, api.start({ loop: infinite, delay: infinite ? 500 : 0 }); } }, [inView]); - const animatedDiv = (style: any) => ( + const animatedDiv = (style: object) => ( `${val}`) }}> {children} diff --git a/src/fields/ObjectField.ts b/src/fields/ObjectField.ts index 5f31208eb..c533cb596 100644 --- a/src/fields/ObjectField.ts +++ b/src/fields/ObjectField.ts @@ -12,9 +12,8 @@ export interface serializedDoctype { export type serverOpType = { $set?: serializedFieldsType; // $unset?: { [key: string]: unknown }; - $remFromSet?: { [key: string]: { fields: serializedFieldType[] } | { deleteCount: number; start: number } | undefined; hint?: { deleteCount: number; start: number } }; - $addToSet?: serializedFieldsType; - length?: number; + $remFromSet?: { [key: string]: { fields: serializedFieldType[] } | { deleteCount: number; start: number } | number | undefined; length: number; hint: { deleteCount: number; start: number } | undefined }; + $addToSet?: { [key: string]: { fields: serializedFieldType[] } | number | undefined; length: number }; }; export abstract class ObjectField { // prettier-ignore diff --git a/src/fields/RichTextUtils.ts b/src/fields/RichTextUtils.ts index 3763dcd2c..d1316d256 100644 --- a/src/fields/RichTextUtils.ts +++ b/src/fields/RichTextUtils.ts @@ -1,9 +1,10 @@ +/* eslint-disable @typescript-eslint/no-namespace */ /* eslint-disable no-await-in-loop */ /* eslint-disable no-use-before-define */ import { AssertionError } from 'assert'; import * as Color from 'color'; import { docs_v1 as docsV1 } from 'googleapis'; -import { Fragment, Mark, Node } from 'prosemirror-model'; +import { Fragment, Mark, Node, Schema } from 'prosemirror-model'; import { sinkListItem } from 'prosemirror-schema-list'; import { EditorState, TextSelection, Transaction } from 'prosemirror-state'; import { ClientUtils, DashColor } from '../ClientUtils'; @@ -26,7 +27,7 @@ export namespace RichTextUtils { const joiner = ''; export const Initialize = (initial?: string) => { - const content: any[] = []; + const content: object[] = []; const state = { doc: { type: 'doc', @@ -80,8 +81,10 @@ export namespace RichTextUtils { // Preserve the current state, but re-write the content to be the blocks const parsed = JSON.parse(oldState ? oldState.Data : Initialize()); parsed.doc.content = elements.map(text => { - const paragraph: any = { type: 'paragraph' }; - text.length && (paragraph.content = [{ type: 'text', marks: [], text }]); // An empty paragraph gets treated as a line break + const paragraph: object = { + type: 'paragraph', + content: text.length ? [{ type: 'text', marks: [], text }] : undefined, // An empty paragraph gets treated as a line break + }; return paragraph; }); @@ -164,7 +167,7 @@ export namespace RichTextUtils { const inlineObjectMap = await parseInlineObjects(document); const title = document.title!; const { text, paragraphs } = GoogleApiClientUtils.Docs.Utils.extractText(document); - let state = EditorState.create(new FormattedTextBox({} as any).config); + let state = EditorState.create(FormattedTextBox.MakeConfig()); const structured = parseLists(paragraphs); let position = 3; @@ -253,17 +256,20 @@ export namespace RichTextUtils { return groups; }; - const listItem = (lschema: any, runs: docsV1.Schema$TextRun[]): Node => lschema.node('list_item', null, paragraphNode(lschema, runs)); + const listItem = (lschema: Schema, runs: docsV1.Schema$TextRun[]): Node => lschema.node('list_item', null, paragraphNode(lschema, runs)); - const list = (lschema: any, items: Node[]): Node => lschema.node('ordered_list', { mapStyle: 'bullet' }, items); + const list = (lschema: Schema, items: Node[]): Node => lschema.node('ordered_list', { mapStyle: 'bullet' }, items); - const paragraphNode = (lschema: any, runs: docsV1.Schema$TextRun[]): Node => { - const children = runs.map(run => textNode(lschema, run)).filter(child => child !== undefined); + const paragraphNode = (lschema: Schema, runs: docsV1.Schema$TextRun[]): Node => { + const children = runs + .map(run => textNode(lschema, run)) + .filter(child => child !== undefined) + .map(child => child!); const fragment = children.length ? Fragment.from(children) : undefined; return lschema.node('paragraph', null, fragment); }; - const imageNode = (lschema: any, image: ImageTemplate, textNote: Doc) => { + const imageNode = (lschema: Schema, image: ImageTemplate, textNote: Doc) => { const { url: src, width, agnostic } = image; let docId: string; const guid = Utils.GenerateDeterministicGuid(agnostic); @@ -279,7 +285,7 @@ export namespace RichTextUtils { return lschema.node('image', { src, agnostic, width, docId, float: null }); }; - const textNode = (lschema: any, run: docsV1.Schema$TextRun) => { + const textNode = (lschema: Schema, run: docsV1.Schema$TextRun) => { const text = run.content!.removeTrailingNewlines(); return text.length ? lschema.text(text, styleToMarks(lschema, run.textStyle)) : undefined; }; @@ -291,29 +297,33 @@ export namespace RichTextUtils { ['fontSize', 'pFontSize'], ]); - const styleToMarks = (lschema: any, textStyle?: docsV1.Schema$TextStyle) => { + const styleToMarks = (lschema: Schema, textStyle?: docsV1.Schema$TextStyle) => { if (!textStyle) { return undefined; } const marks: Mark[] = []; Object.keys(textStyle).forEach(key => { const targeted = key as keyof docsV1.Schema$TextStyle; - const value = textStyle[targeted] as any; + const value = textStyle[targeted]; if (value) { - const attributes: any = {}; + const attributes: { [key: string]: number | string } = {}; let converted = StyleToMark.get(targeted) || targeted; - value.url && (attributes.href = value.url); - if (value.color) { - const object = value.color.rgbColor; - attributes.color = Color.rgb(['red', 'green', 'blue'].map(color => object[color] * 255 || 0)).hex(); + const urlValue = value as docsV1.Schema$Link; + urlValue.url && (attributes.href = urlValue.url); + const colValue = value as docsV1.Schema$OptionalColor; + const object = colValue.color?.rgbColor; + if (object) { + attributes.color = Color.rgb(['red', 'green', 'blue'].map(color => (object as { [key: string]: number })[color] * 255 || 0)).hex(); } - if (value.magnitude) { - attributes.fontSize = value.magnitude; + const magValue = value as docsV1.Schema$Dimension; + if (magValue.magnitude) { + attributes.fontSize = magValue.magnitude; } + const fontValue = value as docsV1.Schema$WeightedFontFamily; if (converted === 'weightedFontFamily') { - converted = ImportFontFamilyMapping.get(value.fontFamily) || 'timesNewRoman'; + converted = (fontValue.fontFamily && ImportFontFamilyMapping.get(fontValue.fontFamily)) || 'timesNewRoman'; } const mapped = lschema.marks[converted]; @@ -388,7 +398,7 @@ export namespace RichTextUtils { continue; } let converted = MarkToStyle.get(markName) || (markName as keyof docsV1.Schema$TextStyle); - let value: any = true; + let value: unknown = true; if (!converted) { // eslint-disable-next-line no-continue continue; @@ -436,7 +446,7 @@ export namespace RichTextUtils { converted = 'fontSize'; value = { magnitude: parseInt(matches[1].replace('px', '')), unit: 'PT' }; } - textStyle[converted] = value; + textStyle[converted] = value as undefined; } if (Object.keys(textStyle).length) { requests.push(EncodeStyleUpdate(information)); diff --git a/src/fields/util.ts b/src/fields/util.ts index a5c56607c..60eadcdfd 100644 --- a/src/fields/util.ts +++ b/src/fields/util.ts @@ -398,9 +398,9 @@ export function containedFieldChangedHandler(container: ListImpl | Do const serializeItems = () => ({ __type: 'list', fields: diff?.items?.map((item: FieldType) => SerializationHelper.Serialize(item) as serializedFieldType) ?? [] }); // prettier-ignore const serverOp: serverOpType = diff?.op === '$addToSet' - ? { $addToSet: { ['fields.' + prop]: serializeItems() }, length: diff.length } + ? { $addToSet: { ['fields.' + prop]: serializeItems(), length: diff.length ??0 }} : diff?.op === '$remFromSet' - ? { $remFromSet: { ['fields.' + prop]: serializeItems(), hint: diff.hint}, length: diff.length } + ? { $remFromSet: { ['fields.' + prop]: serializeItems(), hint: diff.hint, length: diff.length ?? 0 } } : { $set: { ['fields.' + prop]: SerializationHelper.Serialize(liveContainedField) as {fields: serializedFieldType[]}} }; if (!(container instanceof Doc) || !container[UpdatingFromServer]) { diff --git a/src/server/database.ts b/src/server/database.ts index a93117349..975b9eb80 100644 --- a/src/server/database.ts +++ b/src/server/database.ts @@ -32,7 +32,7 @@ export namespace Database { try { const { connection } = mongoose; disconnect = async () => - new Promise(resolve => { + new Promise(resolve => { connection.close().then(resolve); }); if (connection.readyState === ConnectionStates.disconnected) { diff --git a/src/server/websocket.ts b/src/server/websocket.ts index f588151a5..ccbcb1c5f 100644 --- a/src/server/websocket.ts +++ b/src/server/websocket.ts @@ -49,12 +49,12 @@ export namespace WebSocket { DashStats.logUserLogin(userEmail); } - function GetRefFieldLocal([id, callback]: [string, (result?: serializedDoctype) => void]) { + function GetRefFieldLocal(id: string, callback: (result?: serializedDoctype | undefined) => void) { return Database.Instance.getDocument(id, callback); } function GetRefField([id, callback]: [string, (result?: serializedDoctype) => void]) { process.stdout.write(`+`); - GetRefFieldLocal([id, callback]); + GetRefFieldLocal(id, callback); } function GetRefFields([ids, callback]: [string[], (result?: serializedDoctype[]) => void]) { @@ -62,112 +62,46 @@ export namespace WebSocket { Database.Instance.getDocuments(ids, callback); } - const suffixMap: { [type: string]: string | [string, string | ((json: any) => any)] } = { - number: '_n', - string: '_t', - boolean: '_b', - image: ['_t', 'url'], - video: ['_t', 'url'], - pdf: ['_t', 'url'], - audio: ['_t', 'url'], - web: ['_t', 'url'], - map: ['_t', 'url'], - script: ['_t', value => value.script.originalScript], - RichTextField: ['_t', value => value.Text], - date: ['_d', value => new Date(value.date).toISOString()], - proxy: ['_i', 'fieldId'], - list: [ - '_l', - list => { - const results: any[] = []; - // eslint-disable-next-line no-use-before-define - list.fields.forEach((value: any) => ToSearchTerm(value) && results.push(ToSearchTerm(value)!.value)); - return results.length ? results : null; - }, - ], - }; - - function ToSearchTerm(valIn: any): { suffix: string; value: any } | undefined { - let val = valIn; - if (val === null || val === undefined) { - return undefined; - } - const type = val.__type || typeof val; - - let suffix = suffixMap[type]; - if (!suffix) { - return undefined; - } - if (Array.isArray(suffix)) { - const accessor = suffix[1]; - if (typeof accessor === 'function') { - val = accessor(val); - } else { - val = val[accessor]; - } - [suffix] = suffix; - } - return { suffix, value: val }; - } - - function getSuffix(value: string | [string, any]): string { - return typeof value === 'string' ? value : value[0]; - } const pendingOps = new Map(); - function dispatchNextOp(id: string) { - const next = pendingOps.get(id)!.shift(); + function dispatchNextOp(id: string): unknown { + const next = pendingOps.get(id)?.shift(); + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const nextOp = (res: boolean) => dispatchNextOp(id); if (next) { const { diff, socket } = next; - if (diff.diff.$addToSet) { - // eslint-disable-next-line no-use-before-define - return GetRefFieldLocal([diff.id, (result?: serializedDoctype) => addToListField(socket, diff, result)]); // would prefer to have Mongo handle list additions direclty, but for now handle it on our own + // ideally, we'd call the Database update method for all actions, but for now we handle list insertion/removal on our own + switch (diff.diff.$addToSet ? 'add' : diff.diff.$remFromSet ? 'rem' : 'set') { + case 'add': return GetRefFieldLocal(id, (result) => addToListField(socket, diff, result, nextOp)); // prettier-ignore + case 'rem': return GetRefFieldLocal(id, (result) => remFromListField(socket, diff, result, nextOp)); // prettier-ignore + default: return Database.Instance.update(id, diff.diff, + () => nextOp(socket.broadcast.emit(MessageStore.UpdateField.Message, diff)), + false + ); // prettier-ignore } - if (diff.diff.$remFromSet) { - // eslint-disable-next-line no-use-before-define - return GetRefFieldLocal([diff.id, (result?: serializedDoctype) => remFromListField(socket, diff, result)]); // would prefer to have Mongo handle list additions direclty, but for now handle it on our own - } - // eslint-disable-next-line no-use-before-define - return SetField(socket, diff); } - return !pendingOps.get(id)!.length && pendingOps.delete(id); + return !pendingOps.get(id)?.length && pendingOps.delete(id); } - function addToListField(socket: Socket, diffIn: Diff, listDoc?: serializedDoctype): void { - const diff = diffIn; - diff.diff.$set = diff.diff.$addToSet; - delete diff.diff.$addToSet; // convert add to set to a query of the current fields, and then a set of the composition of the new fields with the old ones - const updatefield = Array.from(Object.keys(diff.diff.$set ?? {}))[0]; - const newListItems = diff.diff.$set?.[updatefield]?.fields; - if (!newListItems) { - console.log('Error: addToListField - no new list items'); - return; - } - const listItems = listDoc?.fields?.[updatefield.replace('fields.', '')]?.fields.filter(item => item !== undefined) ?? []; - if (diff.diff.$set?.[updatefield]?.fields !== undefined) { + function addToListField(socket: Socket, diff: Diff, listDoc: serializedDoctype | undefined, cb: (res: boolean) => void): void { + const $addToSet = diff.diff.$addToSet as serializedFieldsType; + const updatefield = Array.from(Object.keys($addToSet ?? {}))[0]; + const newListItems = $addToSet?.[updatefield]?.fields; + + if (newListItems) { + const length = diff.diff.$addToSet?.length; + diff.diff.$set = $addToSet; // convert add to set to a query of the current fields, and then a set of the composition of the new fields with the old ones + delete diff.diff.$addToSet; // can't pass $set to Mongo, or it will do that insetead of $addToSet + const listItems = listDoc?.fields?.[updatefield.replace('fields.', '')]?.fields.filter(item => item) ?? []; diff.diff.$set[updatefield]!.fields = [...listItems, ...newListItems]; // , ...newListItems.filter((newItem: any) => newItem === null || !curList.some((curItem: any) => curItem.fieldId ? curItem.fieldId === newItem.fieldId : curItem.heading ? curItem.heading === newItem.heading : curItem === newItem))]; - const sendBack = diff.diff.length !== diff.diff.$set[updatefield]!.fields?.length; - delete diff.diff.length; - Database.Instance.update( - diff.id, - diff.diff, - () => { - if (sendBack) { - console.log('Warning: list modified during update. Composite list is being returned.'); - const { id } = socket; - // eslint-disable-next-line @typescript-eslint/no-explicit-any - (socket as any).id = ''; // bcz: HACK to reference private variable. this allows the update message to go back to the client that made the change. - socket.broadcast.emit(MessageStore.UpdateField.Message, diff); - // eslint-disable-next-line @typescript-eslint/no-explicit-any - (socket as any).id = id; - } else { - socket.broadcast.emit(MessageStore.UpdateField.Message, diff); - } - dispatchNextOp(diff.id); - }, - false - ); - } + + // if the client's list length is not the same as what we're writing to the server, + // then we need to send the server's version back to the client so that they are in synch. + // this could happen if another client made a change before the server receives the update from the first client + const target = length !== diff.diff.$set[updatefield].fields.length ? socket : socket.broadcast; + target === socket && console.log('Warning: SEND BACK: list modified during add update. Composite list is being returned.'); + Database.Instance.update(diff.id, diff.diff, () => cb(target.emit(MessageStore.UpdateField.Message, diff)), false); + } else cb(false); } /** @@ -206,15 +140,17 @@ export namespace WebSocket { * items to delete) * @param curListItems the server's current copy of the data */ - function remFromListField(socket: Socket, diffIn: Diff, curListItems?: serializedDoctype): void { - const diff = diffIn; - diff.diff.$set = diff.diff.$remFromSet as serializedFieldsType; - const hint = diff.diff.$remFromSet?.hint; - delete diff.diff.$remFromSet; - const updatefield = Array.from(Object.keys(diff.diff.$set ?? {}))[0]; - const remListItems = diff.diff.$set[updatefield]?.fields; - if (diff.diff.$set[updatefield] !== undefined && remListItems) { - const curList = curListItems?.fields?.[updatefield.replace('fields.', '')]?.fields.filter(f => f !== null) || []; + function remFromListField(socket: Socket, diff: Diff, curListItems: serializedDoctype | undefined, cb: (res: boolean) => void): void { + const $remFromSet = diff.diff.$remFromSet as serializedFieldsType; + const updatefield = Array.from(Object.keys($remFromSet ?? {}))[0]; + const remListItems = $remFromSet?.[updatefield]?.fields; + + if (remListItems) { + const hint = diff.diff.$remFromSet?.hint; + const length = diff.diff.$remFromSet?.length; + diff.diff.$set = $remFromSet; // convert rem from set to a query of the current fields, and then a set of the old fields minus the removed ones + delete diff.diff.$remFromSet; // can't pass $set to Mongo, or it will do that insetead of $remFromSet + const curList = curListItems?.fields?.[updatefield.replace('fields.', '')]?.fields.filter(f => f) ?? []; if (hint) { // indexesToRemove stores the indexes that we mark for deletion, which is later used to filter the list (delete the elements) @@ -227,83 +163,51 @@ export namespace WebSocket { if (closestIndex !== -1) { indexesToRemove.push(closestIndex); } else { - console.log('Item to delete was not found - index = -1'); + console.log('Item to delete was not found'); } } } diff.diff.$set[updatefield]!.fields = curList.filter((curItem, index) => !indexesToRemove.includes(index)); } else { - // go back to the original way to delete if we didn't receive - // a hint from the client + // if we didn't get a hint, remove all matching items from the list diff.diff.$set[updatefield]!.fields = curList?.filter(curItem => !remListItems.some(remItem => (remItem.fieldId ? remItem.fieldId === curItem.fieldId : remItem.heading ? remItem.heading === curItem.heading : remItem === curItem))); } - // if the client and server have different versions of the data after - // deletion, they will have different lengths and the server will - // send its version of the data to the client - const sendBack = diff.diff.length !== diff.diff.$set[updatefield].fields.length; - delete diff.diff.length; - Database.Instance.update( - diff.id, - diff.diff, - () => { - if (sendBack) { - // the two copies are different, so the server sends its copy. - console.log('SEND BACK'); - const { id } = socket; - // eslint-disable-next-line @typescript-eslint/no-explicit-any - (socket as any).id = ''; // bcz: HACK to access private variable this allows the update message to go back to the client that made the change. - socket.broadcast.emit(MessageStore.UpdateField.Message, diff); - // eslint-disable-next-line @typescript-eslint/no-explicit-any - (socket as any).id = id; - } else { - socket.broadcast.emit(MessageStore.UpdateField.Message, diff); - } - dispatchNextOp(diff.id); - }, - false - ); - } + + // if the client's list length is not the same as what we're writing to the server, + // then we need to send the server's version back to the client so that they are in synch. + // this could happen if another client made a change before the server receives the update from the first client + const target = length !== diff.diff.$set[updatefield].fields.length ? socket : socket.broadcast; + target === socket && console.log('Warning: SEND BACK: list modified during remove update. Composite list is being returned.'); + Database.Instance.update(diff.id, diff.diff, () => cb(target.emit(MessageStore.UpdateField.Message, diff)), false); + } else cb(false); } function UpdateField(socket: Socket, diff: Diff) { const curUser = socketMap.get(socket); - if (!curUser) return false; - const currentUsername = curUser.split(' ')[0]; - userOperations.set(currentUsername, userOperations.get(currentUsername) !== undefined ? userOperations.get(currentUsername)! + 1 : 0); + if (curUser) { + const currentUsername = curUser.split(' ')[0]; + userOperations.set(currentUsername, userOperations.get(currentUsername) !== undefined ? userOperations.get(currentUsername)! + 1 : 0); - if (CurUser !== socketMap.get(socket)) { - CurUser = socketMap.get(socket); - console.log('Switch User: ' + CurUser); - } - if (pendingOps.has(diff.id)) { - pendingOps.get(diff.id)!.push({ diff, socket }); - return true; - } - pendingOps.set(diff.id, [{ diff, socket }]); - if (diff.diff.$addToSet) { - return GetRefFieldLocal([diff.id, (result?: serializedDoctype) => addToListField(socket, diff, result)]); // would prefer to have Mongo handle list additions direclty, but for now handle it on our own - } - if (diff.diff.$remFromSet) { - return GetRefFieldLocal([diff.id, (result?: serializedDoctype) => remFromListField(socket, diff, result)]); // would prefer to have Mongo handle list additions direclty, but for now handle it on our own + if (CurUser !== socketMap.get(socket)) { + CurUser = socketMap.get(socket); + console.log('Switch User: ' + CurUser); + } + if (pendingOps.has(diff.id)) { + pendingOps.get(diff.id)!.push({ diff, socket }); + return true; + } + pendingOps.set(diff.id, [{ diff, socket }]); + return dispatchNextOp(diff.id); } - // eslint-disable-next-line no-use-before-define - return SetField(socket, diff); - } - function SetField(socket: Socket, diff: Diff /* , curListItems?: Transferable */) { - Database.Instance.update(diff.id, diff.diff, () => socket.broadcast.emit(MessageStore.UpdateField.Message, diff), false); - dispatchNextOp(diff.id); + return false; } function DeleteField(socket: Socket, id: string) { - Database.Instance.delete({ _id: id }).then(() => { - socket.broadcast.emit(MessageStore.DeleteField.Message, id); - }); + Database.Instance.delete({ _id: id }).then(() => socket.broadcast.emit(MessageStore.DeleteField.Message, id)); } function DeleteFields(socket: Socket, ids: string[]) { - Database.Instance.delete({ _id: { $in: ids } }).then(() => { - socket.broadcast.emit(MessageStore.DeleteFields.Message, ids); - }); + Database.Instance.delete({ _id: { $in: ids } }).then(() => socket.broadcast.emit(MessageStore.DeleteFields.Message, ids)); } function CreateDocField(newValue: serializedDoctype) { @@ -343,21 +247,19 @@ export namespace WebSocket { socket.in(room).emit('message', message); }); - socket.on('ipaddr', () => { + socket.on('ipaddr', () => networkInterfaces().keys?.forEach(dev => { if (dev.family === 'IPv4' && dev.address !== '127.0.0.1') { socket.emit('ipaddr', dev.address); } - }); - }); + }) + ); - socket.on('bye', () => { - console.log('received bye'); - }); + socket.on('bye', () => console.log('received bye')); socket.on('disconnect', () => { const currentUser = socketMap.get(socket); - if (!(currentUser === undefined)) { + if (currentUser !== undefined) { const currentUsername = currentUser.split(' ')[0]; DashStats.logUserLogout(currentUsername); delete timeMap[currentUsername]; -- cgit v1.2.3-70-g09d2 From 0e975569e5686138e52bdc554b3f0391f42aeead Mon Sep 17 00:00:00 2001 From: IEatChili Date: Thu, 15 Aug 2024 14:13:02 -0400 Subject: feat: added face recogntion box --- src/client/apis/gpt/GPT.ts | 2 +- src/client/documents/DocumentTypes.ts | 1 + src/client/documents/Documents.ts | 4 + src/client/util/CurrentUserUtils.ts | 13 +- src/client/views/KeywordBox.tsx | 7 +- src/client/views/Main.tsx | 2 + .../collectionFreeForm/FaceCollectionBox.scss | 74 +++++++ .../collectionFreeForm/FaceCollectionBox.tsx | 217 +++++++++++++++++++++ .../collectionFreeForm/ImageLabelBox.tsx | 5 +- src/client/views/search/FaceRecognitionHandler.tsx | 74 +++++-- src/fields/Doc.ts | 1 + 11 files changed, 375 insertions(+), 25 deletions(-) create mode 100644 src/client/views/collections/collectionFreeForm/FaceCollectionBox.scss create mode 100644 src/client/views/collections/collectionFreeForm/FaceCollectionBox.tsx (limited to 'src') diff --git a/src/client/apis/gpt/GPT.ts b/src/client/apis/gpt/GPT.ts index 05007960d..8dd3fd6e2 100644 --- a/src/client/apis/gpt/GPT.ts +++ b/src/client/apis/gpt/GPT.ts @@ -128,7 +128,7 @@ const gptImageLabel = async (src: string): Promise => { { role: 'user', content: [ - { type: 'text', text: 'Give three to five labels to describe this image.' }, + { type: 'text', text: 'Give three labels to describe this image.' }, { type: 'image_url', image_url: { diff --git a/src/client/documents/DocumentTypes.ts b/src/client/documents/DocumentTypes.ts index a9ea889b3..b66a29ac2 100644 --- a/src/client/documents/DocumentTypes.ts +++ b/src/client/documents/DocumentTypes.ts @@ -17,6 +17,7 @@ export enum DocumentType { FONTICON = 'fonticonbox', SEARCH = 'search', // search query IMAGEGROUPER = 'imagegrouper', + FACECOLLECTION = 'facecollection', LABEL = 'label', // simple text label BUTTON = 'button', // onClick button WEBCAM = 'webcam', // webcam diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 3737aa0b5..ecea74fab 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -795,6 +795,10 @@ export namespace Docs { return InstanceFromProto(Prototypes.get(DocumentType.IMAGEGROUPER), undefined, options); } + export function FaceCollectionDocument(options: DocumentOptions = {}) { + return InstanceFromProto(Prototypes.get(DocumentType.FACECOLLECTION), undefined, options); + } + export function LoadingDocument(file: File | string, options: DocumentOptions) { return InstanceFromProto(Prototypes.get(DocumentType.LOADING), undefined, { _height: 150, _width: 200, title: typeof file === 'string' ? file : file.name, ...options }, undefined, ''); } diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts index cb3d9df62..db0de83b9 100644 --- a/src/client/util/CurrentUserUtils.ts +++ b/src/client/util/CurrentUserUtils.ts @@ -458,7 +458,8 @@ pie title Minerals in my tap water { title: "Shared", toolTip: "Shared Docs", target: Doc.MySharedDocs, ignoreClick: true, icon: "users", funcs: {badgeValue: badgeValue}}, { title: "Trails", toolTip: "Trails ⌘R", target: Doc.UserDoc(), ignoreClick: true, icon: "pres-trail", funcs: {target: getActiveDashTrails}}, { title: "User Doc", toolTip: "User Doc", target: this.setupUserDocView(doc, "myUserDocView"), ignoreClick: true, icon: "address-card",funcs: {hidden: "IsNoviceMode()"} }, - { title: "Image Grouper", toolTip: "Image Grouper", target: this.setupImageGrouper(doc, "myImageGrouper"), ignoreClick: true, icon: "folder-open", hidden: false } + { title: "Image Grouper", toolTip: "Image Grouper", target: this.setupImageGrouper(doc, "myImageGrouper"), ignoreClick: true, icon: "folder-open", hidden: false }, + { title: "Face Collection", toolTip: "Face Collection", target: this.setupFaceCollection(doc, "myFaceCollection"), ignoreClick: true, icon: "face-smile", hidden: false }, ].map(tuple => ({...tuple, scripts:{onClick: 'selectMainMenu(this)'}})); } @@ -500,6 +501,12 @@ pie title Minerals in my tap water _lockedPosition: true, _type_collection: CollectionViewType.Schema }); } + static setupFaceCollection(doc: Doc, field: string) { + return DocUtils.AssignDocField(doc, field, (opts) => Docs.Create.FaceCollectionDocument(opts), { + dontRegisterView: true, backgroundColor: "dimgray", ignoreClick: true, title: "Face Collection", isSystem: true, childDragAction: dropActionType.embed, + _lockedPosition: true, _type_collection: CollectionViewType.Schema }); + } + /// Initializes the panel of draggable tools that is opened from the left sidebar. static setupToolsBtnPanel(doc: Doc, field:string) { const allTools = DocListCast(DocCast(doc[field])?.data); @@ -702,8 +709,8 @@ pie title Minerals in my tap water { title: "Fit All", icon: "object-group", toolTip: "Fit Docs to View (double click to make sticky)",btnType: ButtonType.ToggleButton, ignoreClick:true, expertMode: false, toolType:"viewAll", funcs: {}, scripts: { onClick: '{ return showFreeform(this.toolType, _readOnly_);}', onDoubleClick: '{ return showFreeform(this.toolType, _readOnly_, true);}'}}, // Only when floating document is selected in freeform { title: "Clusters", icon: "braille", toolTip: "Show Doc Clusters", btnType: ButtonType.ToggleButton, ignoreClick: true, expertMode: false, toolType:"clusters", funcs: {}, scripts: { onClick: '{ return showFreeform(this.toolType, _readOnly_);}'}}, // Only when floating document is selected in freeform { title: "Cards", icon: "brain", toolTip: "Flashcards", btnType: ButtonType.ToggleButton, ignoreClick: true, expertMode: false, toolType:"flashcards", funcs: {}, scripts: { onClick: '{ return showFreeform(this.toolType, _readOnly_);}'}}, // Only when floating document is selected in freeform - { title: "Arrange", icon:"arrow-down-short-wide",toolTip:"Toggle Auto Arrange", btnType: ButtonType.ToggleButton, ignoreClick: true, expertMode: false, toolType:"arrange", funcs: {hidden: 'IsNoviceMode()'}, scripts: { onClick: '{ return showFreeform(this.toolType, _readOnly_);}'}}, // Only when floating document is selected in freeform - + { title: "Arrange", icon:"arrow-down-short-wide",toolTip:"Auto Arrange", btnType: ButtonType.ToggleButton, ignoreClick: true, expertMode: false, toolType:"arrange", funcs: {hidden: 'IsNoviceMode()'}, scripts: { onClick: '{ return showFreeform(this.toolType, _readOnly_);}'}}, // Only when floating document is selected in freeform + ] } static textTools():Button[] { diff --git a/src/client/views/KeywordBox.tsx b/src/client/views/KeywordBox.tsx index 68584a7fa..fc9c38a11 100644 --- a/src/client/views/KeywordBox.tsx +++ b/src/client/views/KeywordBox.tsx @@ -7,7 +7,7 @@ import { Doc, DocListCast } from '../../fields/Doc'; import { DocData } from '../../fields/DocSymbols'; import { List } from '../../fields/List'; import { NumCast, StrCast } from '../../fields/Types'; -import { emptyFunction } from '../../Utils'; +import { emptyFunction, Utils } from '../../Utils'; import { DocumentType } from '../documents/DocumentTypes'; import { DragManager } from '../util/DragManager'; import { SnappingManager } from '../util/SnappingManager'; @@ -124,7 +124,7 @@ export class KeywordItem extends ObservableReactComponent { render() { return ( -
+
{this._props.keyword} {this.props.isEditing && }
@@ -297,7 +297,7 @@ export class KeywordBox extends ObservableReactComponent {
{(keywordsList as List).map(keyword => { - return ; + return ; })}
{this._props.isEditing ? ( @@ -331,6 +331,7 @@ export class KeywordBox extends ObservableReactComponent { onClick={() => { this.submitLabel(keyword); }} + key={Utils.GenerateGuid()} /> ); })} diff --git a/src/client/views/Main.tsx b/src/client/views/Main.tsx index ada934aea..85c2b3d47 100644 --- a/src/client/views/Main.tsx +++ b/src/client/views/Main.tsx @@ -62,6 +62,7 @@ import { PresBox, PresElementBox } from './nodes/trails'; import { SearchBox } from './search/SearchBox'; import { ImageLabelBox } from './collections/collectionFreeForm/ImageLabelBox'; import { FaceRecognitionHandler } from './search/FaceRecognitionHandler'; +import { FaceCollectionBox } from './collections/collectionFreeForm/FaceCollectionBox'; dotenv.config(); @@ -135,6 +136,7 @@ FieldLoader.ServerLoadStatus = { requested: 0, retrieved: 0, message: 'cache' }; PresElementBox, SearchBox, ImageLabelBox, //Here! + FaceCollectionBox, FunctionPlotBox, InkingStroke, LinkBox, diff --git a/src/client/views/collections/collectionFreeForm/FaceCollectionBox.scss b/src/client/views/collections/collectionFreeForm/FaceCollectionBox.scss new file mode 100644 index 000000000..480d109c8 --- /dev/null +++ b/src/client/views/collections/collectionFreeForm/FaceCollectionBox.scss @@ -0,0 +1,74 @@ +.face-document-item { + background: #555555; + margin-top: 10px; + margin-bottom: 10px; + padding: 10px; + border-radius: 10px; + position: relative; + + h1 { + color: white; + font-size: 24px; + text-align: center; + } + + .face-collection-buttons { + position: absolute; + top: 10px; + right: 10px; + } + + .face-document-image-container { + display: flex; + justify-content: center; + flex-wrap: wrap; + + .image-wrapper { + position: relative; + width: 70px; + height: 70px; + margin: 10px; + display: flex; + align-items: center; // Center vertically + justify-content: center; // Center horizontally + + img { + width: 100%; + height: 100%; + object-fit: cover; // This ensures the image covers the container without stretching + border-radius: 5px; + border: 2px solid white; + transition: border-color 0.4s; + + &:hover { + border-color: orange; // Change this to your desired hover border color + } + } + + .remove-item { + position: absolute; + bottom: -5; + right: -5; + background-color: rgba(0, 0, 0, 0.5); // Optional: to add a background behind the icon for better visibility + border-radius: 30%; + width: 10px; // Adjust size as needed + height: 10px; // Adjust size as needed + display: flex; + align-items: center; + justify-content: center; + } + } + + // img { + // max-width: 60px; + // margin: 10px; + // border-radius: 5px; + // border: 2px solid white; + // transition: 0.4s; + + // &:hover { + // border-color: orange; + // } + // } + } +} diff --git a/src/client/views/collections/collectionFreeForm/FaceCollectionBox.tsx b/src/client/views/collections/collectionFreeForm/FaceCollectionBox.tsx new file mode 100644 index 000000000..1d3f88df1 --- /dev/null +++ b/src/client/views/collections/collectionFreeForm/FaceCollectionBox.tsx @@ -0,0 +1,217 @@ +import { observer } from 'mobx-react'; +import React from 'react'; +import { Docs } from '../../../documents/Documents'; +import { DocumentType } from '../../../documents/DocumentTypes'; +import { ViewBoxBaseComponent } from '../../DocComponent'; +import { FieldView, FieldViewProps } from '../../nodes/FieldView'; +import 'ldrs/ring'; +import { SnappingManager } from '../../../util/SnappingManager'; +import { action, computed, makeObservable, observable, reaction } from 'mobx'; +import { Doc, DocListCast, NumListCast } from '../../../../fields/Doc'; +import { DocData } from '../../../../fields/DocSymbols'; +import { ImageCast, StrCast } from '../../../../fields/Types'; +import { ObservableReactComponent } from '../../ObservableReactComponent'; +import './FaceCollectionBox.scss'; +import { IconButton, Size } from 'browndash-components'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { MarqueeOptionsMenu } from './MarqueeOptionsMenu'; +import { List } from '../../../../fields/List'; +import { DocumentView } from '../../nodes/DocumentView'; +import { Utils } from '../../../../Utils'; +import { DragManager } from '../../../util/DragManager'; +import * as faceapi from 'face-api.js'; +import { FaceMatcher } from 'face-api.js'; + +interface FaceDocumentProps { + faceDoc: Doc; +} + +/** + * A componenent to visually represent a Face Document. + */ +@observer +export class FaceDocumentItem extends ObservableReactComponent { + private ref: React.RefObject; + @observable _displayImages: boolean = true; + private _dropDisposer?: DragManager.DragDropDisposer; + private _inputRef = React.createRef(); + + constructor(props: any) { + super(props); + makeObservable(this); + this.ref = React.createRef(); + } + + protected createDropTarget = (ele: HTMLDivElement) => { + this._dropDisposer?.(); + ele && (this._dropDisposer = DragManager.MakeDropTarget(ele, this.onInternalDrop.bind(this), this._props.faceDoc)); + }; + + protected onInternalDrop(e: Event, de: DragManager.DropEvent): boolean { + const { docDragData } = de.complete; + if (docDragData) { + const filteredDocs = docDragData.droppedDocuments.filter(doc => doc.type === DocumentType.IMG); + filteredDocs.forEach(doc => { + // If the current Face Document has no items, and the doc has more than one face descriptor, don't let the user add the document first. + if ((this._props.faceDoc[DocData].faceDescriptors as List>).length === 0 && (doc[DocData].faces as List>).length > 1) { + alert('Cannot add a document with multiple faces as the first item!'); + } else { + // Loop through the documents' face descriptors. + // Choose the face with the smallest distance to add. + const float32Array = (this._props.faceDoc[DocData].faceDescriptors as List>).map(faceDescriptor => new Float32Array(Array.from(faceDescriptor))); + const labeledFaceDescriptor = new faceapi.LabeledFaceDescriptors(StrCast(this._props.faceDoc[DocData].label), float32Array); + const faceDescriptors: faceapi.LabeledFaceDescriptors[] = [labeledFaceDescriptor]; + + const faceMatcher = new FaceMatcher(faceDescriptors, 1); + let cur_lowest_distance = 1; + let cur_matching_face = new List(); + + (doc[DocData].faces as List>).forEach(face => { + // If the face has the current lowest distance, mark it as such + // Once that lowest distance is found, add the face descriptor to the faceDoc, and add the associated doc + const convered_32_array: Float32Array = new Float32Array(Array.from(face)); + const match = faceMatcher.matchDescriptor(convered_32_array); + + if (match.distance < cur_lowest_distance) { + cur_lowest_distance = match.distance; + cur_matching_face = face; + } + }); + + if (doc[DocData][`FACE DESCRIPTOR - ${this._props.faceDoc[DocData].label}`]) { + doc[DocData][`FACE DESCRIPTOR - ${this._props.faceDoc[DocData].label}`] = new List>([...(doc[DocData][`FACE DESCRIPTOR - ${this._props.faceDoc[DocData].label}`] as List>), cur_matching_face]); + } else { + doc[DocData][`FACE DESCRIPTOR - ${this._props.faceDoc[DocData].label}`] = new List>([cur_matching_face]); + } + + this._props.faceDoc[DocData].associatedDocs = new List([...DocListCast(this._props.faceDoc[DocData].associatedDocs), doc]); + this._props.faceDoc[DocData].faceDescriptors = new List>([...(this._props.faceDoc[DocData].faceDescriptors as List>), cur_matching_face]); + + //const match = faceMatcher.findBestMatch(cur_descriptor); + } + }); + return false; + } + return false; + } + + /** + * Toggles whether a Face Document displays its associated docs. + */ + @action + onDisplayClick() { + this._displayImages = !this._displayImages; + } + + /** + * Deletes a Face Document. + */ + @action + deleteFaceDocument = () => { + if (Doc.ActiveDashboard) { + Doc.ActiveDashboard[DocData].faceDocuments = new List(DocListCast(Doc.ActiveDashboard[DocData].faceDocuments).filter(doc => doc !== this._props.faceDoc)); + } + }; + + /** + * Deletes a document from a Face Document's associated docs list. + * @param doc + */ + @action + deleteAssociatedDoc = (doc: Doc) => { + this._props.faceDoc[DocData].faceDescriptors = new List>( + (this._props.faceDoc[DocData].faceDescriptors as List>).filter(fd => !(doc[DocData][`FACE DESCRIPTOR - ${this._props.faceDoc[DocData].label}`] as List>).includes(fd)) + ); + doc[DocData][`FACE DESCRIPTOR - ${this._props.faceDoc[DocData].label}`] = new List>(); + this._props.faceDoc[DocData].associatedDocs = new List(DocListCast(this._props.faceDoc[DocData].associatedDocs).filter(associatedDoc => associatedDoc !== doc)); + }; + + render() { + return ( +
this.createDropTarget(ele!)}> +
+ +
+
+

{StrCast(this._props.faceDoc[DocData].label)}

+
+ this.onDisplayClick()} + icon={this._displayImages ? : } + color={MarqueeOptionsMenu.Instance.userColor} + style={{ width: '19px' }} + /> + {this._displayImages ? ( +
+ {DocListCast(this._props.faceDoc[DocData].associatedDocs).map(doc => { + const [name, type] = ImageCast(doc[Doc.LayoutFieldKey(doc)]).url.href.split('.'); + return ( +
+ { + await DocumentView.showDocument(doc, { willZoomCentered: true }); + }} + style={{ maxWidth: '60px', margin: '10px' }} + src={`${name}_o.${type}`} + /> +
+ { + this.deleteAssociatedDoc(doc); + }} + icon={'x'} + style={{ width: '4px' }} + size={Size.XSMALL} + /> +
+
+ ); + })} +
+ ) : ( +
+ )} +
+ ); + } +} + +@observer +export class FaceCollectionBox extends ViewBoxBaseComponent() { + public static LayoutString(fieldKey: string) { + return FieldView.LayoutString(FaceCollectionBox, fieldKey); + } + + public static Instance: FaceCollectionBox; + + @computed get currentDocs() { + if (Doc.ActiveDashboard) { + return DocListCast(Doc.ActiveDashboard[DocData].faceDocuments); + } else { + return []; + } + } + + constructor(props: any) { + super(props); + makeObservable(this); + FaceCollectionBox.Instance = this; + } + + render() { + return ( +
+ {this.currentDocs.map(doc => { + return ; + })} +
+ ); + } +} + +Docs.Prototypes.TemplateMap.set(DocumentType.FACECOLLECTION, { + layout: { view: FaceCollectionBox, dataField: 'data' }, + options: { acl: '', _width: 400 }, +}); diff --git a/src/client/views/collections/collectionFreeForm/ImageLabelBox.tsx b/src/client/views/collections/collectionFreeForm/ImageLabelBox.tsx index af01d6cbc..421b5d0a6 100644 --- a/src/client/views/collections/collectionFreeForm/ImageLabelBox.tsx +++ b/src/client/views/collections/collectionFreeForm/ImageLabelBox.tsx @@ -179,6 +179,7 @@ export class ImageLabelBox extends ViewBoxBaseComponent() { const labels = imageInfo.labels.split('\n'); labels.forEach(label => { label = label.replace(/^\d+\.\s*|-|\*/, '').trim(); + console.log(label); imageInfo.doc[DocData][`${label}`] = true; (imageInfo.doc[DocData].data_labels as List).push(label); }); @@ -198,7 +199,7 @@ export class ImageLabelBox extends ViewBoxBaseComponent() { for (let index = 0; index < (doc[DocData].data_labels as List).length; index++) { const label = (doc[DocData].data_labels as List)[index]; const embedding = await gptGetEmbedding(label); - doc[`data_labels_embedding_${index + 1}`] = new List(embedding); + doc[DocData][`data_labels_embedding_${index + 1}`] = new List(embedding); } } @@ -209,7 +210,7 @@ export class ImageLabelBox extends ViewBoxBaseComponent() { // For each image, loop through the labels, and calculate similarity. Associate it with the // most similar one. this._selectedImages.forEach(doc => { - const embedLists = numberRange((doc[DocData].data_labels as List).length).map(n => Array.from(NumListCast(doc[`data_labels_embedding_${n + 1}`]))); + const embedLists = numberRange((doc[DocData].data_labels as List).length).map(n => Array.from(NumListCast(doc[DocData][`data_labels_embedding_${n + 1}`]))); const bestEmbedScore = (embedding: Opt) => Math.max(...embedLists.map((l, index) => (embedding && similarity(Array.from(embedding), l)!) || 0)); const {label: mostSimilarLabelCollect} = this._labelGroups.map(label => ({ label, similarityScore: bestEmbedScore(labelToEmbedding.get(label)) })) diff --git a/src/client/views/search/FaceRecognitionHandler.tsx b/src/client/views/search/FaceRecognitionHandler.tsx index fcd38c42f..ef4622ea2 100644 --- a/src/client/views/search/FaceRecognitionHandler.tsx +++ b/src/client/views/search/FaceRecognitionHandler.tsx @@ -1,14 +1,13 @@ import * as faceapi from 'face-api.js'; -import { FaceMatcher, TinyFaceDetectorOptions } from 'face-api.js'; -import { Doc, DocListCast, NumListCast } from '../../../fields/Doc'; +import { FaceMatcher } from 'face-api.js'; +import { Doc, DocListCast } from '../../../fields/Doc'; import { DocData } from '../../../fields/DocSymbols'; import { List } from '../../../fields/List'; -import { ObjectField } from '../../../fields/ObjectField'; -import { ImageCast, StrCast } from '../../../fields/Types'; -import { DocUtils } from '../../documents/DocUtils'; -import { Deserializable } from '../../util/SerializationHelper'; -import { DocumentView } from '../nodes/DocumentView'; +import { ImageCast, NumCast, StrCast } from '../../../fields/Types'; +/** + * A class that handles face recognition. + */ export class FaceRecognitionHandler { static _instance: FaceRecognitionHandler; private loadedModels: boolean = false; @@ -18,8 +17,12 @@ export class FaceRecognitionHandler { constructor() { FaceRecognitionHandler._instance = this; this.loadModels(); + this.examinedDocs = new Set(DocListCast(Doc.UserDoc()[DocData].examinedFaceDocs, [])); } + /** + * Loads the face detection models. + */ async loadModels() { const MODEL_URL = `/models`; await faceapi.loadFaceDetectionModel(MODEL_URL); @@ -32,19 +35,31 @@ export class FaceRecognitionHandler { return FaceRecognitionHandler._instance ?? new FaceRecognitionHandler(); } + /** + * When a document is added, look for matching face documents. + * @param doc The document being analyzed. + */ public async findMatches(doc: Doc) { if (this.loadedModels) { + // If the Dashboard doesn't have a list of face documents yet, initialize the list. if (!Doc.ActiveDashboard![DocData].faceDocuments) { Doc.ActiveDashboard![DocData].faceDocuments = new List(); } + // If the doc is currently already been examined, or it is being processed, stop examining the document. if (this.examinedDocs.has(doc) || this.processingDocs.has(doc)) { return; } + // Mark the document as being processed. this.processingDocs.add(doc); try { + if (!Doc.UserDoc()[DocData].faceDocNum) { + Doc.UserDoc()[DocData].faceDocNum = 0; + } + + // Get the image the document contains and analyze for faces. const [name, type] = ImageCast(doc[Doc.LayoutFieldKey(doc)]).url.href.split('.'); const imageURL = `${name}_o.${type}`; @@ -52,30 +67,51 @@ export class FaceRecognitionHandler { const fullFaceDescriptions = await faceapi.detectAllFaces(img).withFaceLandmarks().withFaceDescriptors(); + doc[DocData].faces = new List>(); + + // For each face detected, find a match. for (const fd of fullFaceDescriptions) { - const match = this.findMatch(fd.descriptor); + let match = this.findMatch(fd.descriptor); + let converted_list = new List(); + if (match) { + // If a matching Face Document has been found, add the document to the Face Document's associated docs and append the face + // descriptor to the Face Document's descriptor list. const converted_array = Array.from(fd.descriptor); - const converted_list = new List(converted_array); + converted_list = new List(converted_array); match[DocData].associatedDocs = new List([...DocListCast(match[DocData].associatedDocs), doc]); match[DocData].faceDescriptors = new List>([...(match[DocData].faceDescriptors as List>), converted_list]); } else { + // If a matching Face Document has not been found, create a new Face Document. const newFaceDocument = new Doc(); const converted_array = Array.from(fd.descriptor); - const converted_list = new List(converted_array); + converted_list = new List(converted_array); newFaceDocument[DocData].faceDescriptors = new List>(); (newFaceDocument[DocData].faceDescriptors as List>).push(converted_list); - newFaceDocument[DocData].label = `Person ${DocListCast(Doc.ActiveDashboard![DocData].faceDocuments).length + 1}`; + Doc.UserDoc()[DocData].faceDocNum = NumCast(Doc.UserDoc()[DocData].faceDocNum) + 1; + newFaceDocument[DocData].label = `Face ${Doc.UserDoc()[DocData].faceDocNum}`; newFaceDocument[DocData].associatedDocs = new List([doc]); Doc.ActiveDashboard![DocData].faceDocuments = new List([...DocListCast(Doc.ActiveDashboard![DocData].faceDocuments), newFaceDocument]); + match = newFaceDocument; } + + // Assign a field in the document of the matching Face Document. + if (doc[DocData][`FACE DESCRIPTOR - ${match[DocData].label}`]) { + doc[DocData][`FACE DESCRIPTOR - ${match[DocData].label}`] = new List>([...(doc[DocData][`FACE DESCRIPTOR - ${match[DocData].label}`] as List>), converted_list]); + } else { + doc[DocData][`FACE DESCRIPTOR - ${match[DocData].label}`] = new List>([converted_list]); + } + + doc[DocData].faces = new List>([...(doc[DocData].faces as List>), converted_list]); } + // Updates the examined docs field. this.examinedDocs.add(doc); - console.log(this.examinedDocs); - - DocListCast(Doc.ActiveDashboard![DocData].faceDocuments).forEach(doc => console.log(DocListCast(doc[DocData].associatedDocs))); + if (!Doc.UserDoc()[DocData].examinedFaceDocs) { + Doc.UserDoc()[DocData].examinedFaceDocs = new List(); + } + Doc.UserDoc()[DocData].examinedFaceDocs = new List([...DocListCast(Doc.UserDoc()[DocData].examinedFaceDocs), doc]); } catch (error) { console.error('Error processing document:', error); } finally { @@ -84,6 +120,11 @@ export class FaceRecognitionHandler { } } + /** + * Finds a matching Face Document given a descriptor + * @param cur_descriptor The current descriptor whose match is being searched for. + * @returns The most similar Face Document. + */ private findMatch(cur_descriptor: Float32Array) { if (DocListCast(Doc.ActiveDashboard![DocData].faceDocuments).length < 1) { return null; @@ -95,19 +136,20 @@ export class FaceRecognitionHandler { }); const faceMatcher = new FaceMatcher(faceDescriptors, 0.6); const match = faceMatcher.findBestMatch(cur_descriptor); - if (match.label == 'unknown') { return null; } else { for (const doc of DocListCast(Doc.ActiveDashboard![DocData].faceDocuments)) { if (doc[DocData].label === match.label) { - console.log(match.label); return doc; } } } } + /** + * Loads an image + */ private loadImage = (src: string): Promise => { return new Promise((resolve, reject) => { const img = new Image(); diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts index 4abb23404..ebd30ceba 100644 --- a/src/fields/Doc.ts +++ b/src/fields/Doc.ts @@ -265,6 +265,7 @@ export class Doc extends RefField { public static get MyDockedBtns() { return DocCast(Doc.UserDoc().myDockedBtns); } // prettier-ignore public static get MySearcher() { return DocCast(Doc.UserDoc().mySearcher); } // prettier-ignore public static get MyImageGrouper() { return DocCast(Doc.UserDoc().myImageGrouper); } //prettier-ignore + public static get MyFaceCollection() { return DocCast(Doc.UserDoc().myFaceCollection); } //prettier-ignore public static get MyHeaderBar() { return DocCast(Doc.UserDoc().myHeaderBar); } // prettier-ignore public static get MyLeftSidebarMenu() { return DocCast(Doc.UserDoc().myLeftSidebarMenu); } // prettier-ignore public static get MyLeftSidebarPanel() { return DocCast(Doc.UserDoc().myLeftSidebarPanel); } // prettier-ignore -- cgit v1.2.3-70-g09d2 From fed4bf0b7363b9d58828a7a51f037a26f287d874 Mon Sep 17 00:00:00 2001 From: bobzel Date: Thu, 15 Aug 2024 15:45:44 -0400 Subject: fixed emptyPath type --- src/ServerUtils.ts | 2 +- src/client/views/nodes/DocumentContentsView.tsx | 2 +- src/client/views/nodes/trails/PresBox.tsx | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/ServerUtils.ts b/src/ServerUtils.ts index 904541fc7..8b2d0b9f6 100644 --- a/src/ServerUtils.ts +++ b/src/ServerUtils.ts @@ -16,7 +16,7 @@ export namespace ServerUtils { export function AddServerHandlerCallback(socket: Socket, message: Message, handler: (args: [T, (res: unknown) => void]) => void) { socket.on(message.Message, (arg: T, fn: (res: unknown) => void) => { Utils.log('S receiving', message.Name, arg, true); - handler([arg, Utils.loggingCallback('S sending', fn, message.Name)]); + handler([arg, Utils.loggingCallback('Sending', fn, message.Name)]); }); } export type RoomHandler = (socket: Socket, room: string) => void; diff --git a/src/client/views/nodes/DocumentContentsView.tsx b/src/client/views/nodes/DocumentContentsView.tsx index 15baebae1..afc160297 100644 --- a/src/client/views/nodes/DocumentContentsView.tsx +++ b/src/client/views/nodes/DocumentContentsView.tsx @@ -4,7 +4,7 @@ import { observer } from 'mobx-react'; import * as React from 'react'; import * as XRegExp from 'xregexp'; import { OmitKeys } from '../../../ClientUtils'; -import { Without, emptyPath } from '../../../Utils'; +import { Without } from '../../../Utils'; import { Doc, Opt } from '../../../fields/Doc'; import { AclPrivate, DocData } from '../../../fields/DocSymbols'; import { ScriptField } from '../../../fields/ScriptField'; diff --git a/src/client/views/nodes/trails/PresBox.tsx b/src/client/views/nodes/trails/PresBox.tsx index c403f9415..cf32a0196 100644 --- a/src/client/views/nodes/trails/PresBox.tsx +++ b/src/client/views/nodes/trails/PresBox.tsx @@ -20,7 +20,7 @@ import { ObjectField } from '../../../../fields/ObjectField'; import { listSpec } from '../../../../fields/Schema'; import { ComputedField, ScriptField } from '../../../../fields/ScriptField'; import { BoolCast, Cast, DocCast, NumCast, StrCast, toList } from '../../../../fields/Types'; -import { emptyFunction, emptyPath, stringHash } from '../../../../Utils'; +import { emptyFunction, stringHash } from '../../../../Utils'; import { getSlideTransitionSuggestions, gptSlideProperties, gptTrailSlideCustomization } from '../../../apis/gpt/PresCustomization'; import { DocServer } from '../../../DocServer'; import { Docs } from '../../../documents/Documents'; -- cgit v1.2.3-70-g09d2 From 196bfbcacd554e0d5e1d437588c5719606d21025 Mon Sep 17 00:00:00 2001 From: bobzel Date: Thu, 15 Aug 2024 18:44:55 -0400 Subject: fixed lightbox typing into a one-line text box that is auto-titling --- package-lock.json | 451 +++++++++++++++++--------------------- src/client/views/LightboxView.tsx | 2 +- 2 files changed, 198 insertions(+), 255 deletions(-) (limited to 'src') diff --git a/package-lock.json b/package-lock.json index 328110401..c2a4aa964 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2620,9 +2620,9 @@ } }, "node_modules/@eslint/js": { - "version": "9.8.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.8.0.tgz", - "integrity": "sha512-MfluB7EUfxXtv3i/++oh89uzAr4PDI4nn201hsp+qaXqsjAWzinlZEHEfPgAX4doIlKvPG/i0A9dpKxOLII8yA==", + "version": "9.9.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.9.0.tgz", + "integrity": "sha512-hhetes6ZHP3BlXLxmd8K2SNgkhNSi+UcecbnwWKwpP7kyi/uC75DJ1lOOBO3xrC4jyojtGE3YxKZPHfk4yrgug==", "dev": true, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -3766,18 +3766,18 @@ } }, "node_modules/@mui/core-downloads-tracker": { - "version": "5.16.6", - "resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-5.16.6.tgz", - "integrity": "sha512-kytg6LheUG42V8H/o/Ptz3olSO5kUXW9zF0ox18VnblX6bO2yif1FPItgc3ey1t5ansb1+gbe7SatntqusQupg==", + "version": "5.16.7", + "resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-5.16.7.tgz", + "integrity": "sha512-RtsCt4Geed2/v74sbihWzzRs+HsIQCfclHeORh5Ynu2fS4icIKozcSubwuG7vtzq2uW3fOR1zITSP84TNt2GoQ==", "funding": { "type": "opencollective", "url": "https://opencollective.com/mui-org" } }, "node_modules/@mui/icons-material": { - "version": "5.16.6", - "resolved": "https://registry.npmjs.org/@mui/icons-material/-/icons-material-5.16.6.tgz", - "integrity": "sha512-ceNGjoXheH9wbIFa1JHmSc9QVjJUvh18KvHrR4/FkJCSi9HXJ+9ee1kUhCOEFfuxNF8UB6WWVrIUOUgRd70t0A==", + "version": "5.16.7", + "resolved": "https://registry.npmjs.org/@mui/icons-material/-/icons-material-5.16.7.tgz", + "integrity": "sha512-UrGwDJCXEszbDI7yV047BYU5A28eGJ79keTCP4cc74WyncuVrnurlmIRxaHL8YK+LI1Kzq+/JM52IAkNnv4u+Q==", "dependencies": { "@babel/runtime": "^7.23.9" }, @@ -3800,13 +3800,13 @@ } }, "node_modules/@mui/material": { - "version": "5.16.6", - "resolved": "https://registry.npmjs.org/@mui/material/-/material-5.16.6.tgz", - "integrity": "sha512-0LUIKBOIjiFfzzFNxXZBRAyr9UQfmTAFzbt6ziOU2FDXhorNN2o3N9/32mNJbCA8zJo2FqFU6d3dtoqUDyIEfA==", + "version": "5.16.7", + "resolved": "https://registry.npmjs.org/@mui/material/-/material-5.16.7.tgz", + "integrity": "sha512-cwwVQxBhK60OIOqZOVLFt55t01zmarKJiJUWbk0+8s/Ix5IaUzAShqlJchxsIQ4mSrWqgcKCCXKtIlG5H+/Jmg==", "dependencies": { "@babel/runtime": "^7.23.9", - "@mui/core-downloads-tracker": "^5.16.6", - "@mui/system": "^5.16.6", + "@mui/core-downloads-tracker": "^5.16.7", + "@mui/system": "^5.16.7", "@mui/types": "^7.2.15", "@mui/utils": "^5.16.6", "@popperjs/core": "^2.11.8", @@ -3901,9 +3901,9 @@ } }, "node_modules/@mui/system": { - "version": "5.16.6", - "resolved": "https://registry.npmjs.org/@mui/system/-/system-5.16.6.tgz", - "integrity": "sha512-5xgyJjBIMPw8HIaZpfbGAaFYPwImQn7Nyh+wwKWhvkoIeDosQ1ZMVrbTclefi7G8hNmqhip04duYwYpbBFnBgw==", + "version": "5.16.7", + "resolved": "https://registry.npmjs.org/@mui/system/-/system-5.16.7.tgz", + "integrity": "sha512-Jncvs/r/d/itkxh7O7opOunTqbbSSzMTHzZkNLM+FjAOg+cYAZHrPDlYe1ZGKUYORwwb2XexlWnpZp0kZ4AHuA==", "dependencies": { "@babel/runtime": "^7.23.9", "@mui/private-theming": "^5.16.6", @@ -9473,9 +9473,9 @@ "integrity": "sha512-nG96G3Wp6acyAgJqGasjODb+acrI7KltPiRxzHPXnP3NgI28bpQDRv53olbqGXbfcgF5aiiHmO3xpwEpS5Ld9g==" }, "node_modules/@types/node": { - "version": "20.14.14", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.14.14.tgz", - "integrity": "sha512-d64f00982fS9YoOgJkAMolK7MN8Iq3TDdVjchbYHdEmjth/DHowx82GnoA+tVUAN+7vxfYUgAzi+JXbKNd2SDQ==", + "version": "20.14.15", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.14.15.tgz", + "integrity": "sha512-Fz1xDMCF/B00/tYSVMlmK7hVeLh7jE5f3B7X1/hmV0MJBwE27KlS7EvD/Yp+z1lm8mVhwV5w+n8jOZG8AfTlKw==", "dependencies": { "undici-types": "~5.26.4" } @@ -9685,9 +9685,9 @@ } }, "node_modules/@types/react-transition-group": { - "version": "4.4.10", - "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.10.tgz", - "integrity": "sha512-hT/+s0VQs2ojCX823m60m5f0sL5idt9SO6Tj6Dg+rdphGPIeJbJ6CxvBYkgkGKrYeDjvIpKTR38UzmtHJOGW3Q==", + "version": "4.4.11", + "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.11.tgz", + "integrity": "sha512-RM05tAniPZ5DZPzzNFP+DmrcOdD0efDUxMy3145oljWSl3x9ZV5vhme98gTxFrj2lhXvmGNnUiuDyJgY9IKkNA==", "dependencies": { "@types/react": "*" } @@ -9859,9 +9859,9 @@ "dev": true }, "node_modules/@types/unist": { - "version": "2.0.10", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.10.tgz", - "integrity": "sha512-IfYcSBWE3hLpBg8+X2SEa8LVkJdJEkT2Ese2aaLs3ptGdVtABxndrMaxuFlQ1qdFf9Q5rDvDpxI3WwgvKFAsQA==" + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.11.tgz", + "integrity": "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==" }, "node_modules/@types/uuid": { "version": "10.0.0", @@ -10148,36 +10148,36 @@ "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==" }, "node_modules/@vue/compiler-core": { - "version": "3.4.37", - "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.4.37.tgz", - "integrity": "sha512-ZDDT/KiLKuCRXyzWecNzC5vTcubGz4LECAtfGPENpo0nrmqJHwuWtRLxk/Sb9RAKtR9iFflFycbkjkY+W/PZUQ==", + "version": "3.4.38", + "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.4.38.tgz", + "integrity": "sha512-8IQOTCWnLFqfHzOGm9+P8OPSEDukgg3Huc92qSG49if/xI2SAwLHQO2qaPQbjCWPBcQoO1WYfXfTACUrWV3c5A==", "dependencies": { "@babel/parser": "^7.24.7", - "@vue/shared": "3.4.37", - "entities": "^5.0.0", + "@vue/shared": "3.4.38", + "entities": "^4.5.0", "estree-walker": "^2.0.2", "source-map-js": "^1.2.0" } }, "node_modules/@vue/compiler-dom": { - "version": "3.4.37", - "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.4.37.tgz", - "integrity": "sha512-rIiSmL3YrntvgYV84rekAtU/xfogMUJIclUMeIKEtVBFngOL3IeZHhsH3UaFEgB5iFGpj6IW+8YuM/2Up+vVag==", + "version": "3.4.38", + "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.4.38.tgz", + "integrity": "sha512-Osc/c7ABsHXTsETLgykcOwIxFktHfGSUDkb05V61rocEfsFDcjDLH/IHJSNJP+/Sv9KeN2Lx1V6McZzlSb9EhQ==", "dependencies": { - "@vue/compiler-core": "3.4.37", - "@vue/shared": "3.4.37" + "@vue/compiler-core": "3.4.38", + "@vue/shared": "3.4.38" } }, "node_modules/@vue/compiler-sfc": { - "version": "3.4.37", - "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.4.37.tgz", - "integrity": "sha512-vCfetdas40Wk9aK/WWf8XcVESffsbNkBQwS5t13Y/PcfqKfIwJX2gF+82th6dOpnpbptNMlMjAny80li7TaCIg==", + "version": "3.4.38", + "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.4.38.tgz", + "integrity": "sha512-s5QfZ+9PzPh3T5H4hsQDJtI8x7zdJaew/dCGgqZ2630XdzaZ3AD8xGZfBqpT8oaD/p2eedd+pL8tD5vvt5ZYJQ==", "dependencies": { "@babel/parser": "^7.24.7", - "@vue/compiler-core": "3.4.37", - "@vue/compiler-dom": "3.4.37", - "@vue/compiler-ssr": "3.4.37", - "@vue/shared": "3.4.37", + "@vue/compiler-core": "3.4.38", + "@vue/compiler-dom": "3.4.38", + "@vue/compiler-ssr": "3.4.38", + "@vue/shared": "3.4.38", "estree-walker": "^2.0.2", "magic-string": "^0.30.10", "postcss": "^8.4.40", @@ -10185,18 +10185,18 @@ } }, "node_modules/@vue/compiler-ssr": { - "version": "3.4.37", - "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.4.37.tgz", - "integrity": "sha512-TyAgYBWrHlFrt4qpdACh8e9Ms6C/AZQ6A6xLJaWrCL8GCX5DxMzxyeFAEMfU/VFr4tylHm+a2NpfJpcd7+20XA==", + "version": "3.4.38", + "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.4.38.tgz", + "integrity": "sha512-YXznKFQ8dxYpAz9zLuVvfcXhc31FSPFDcqr0kyujbOwNhlmaNvL2QfIy+RZeJgSn5Fk54CWoEUeW+NVBAogGaw==", "dependencies": { - "@vue/compiler-dom": "3.4.37", - "@vue/shared": "3.4.37" + "@vue/compiler-dom": "3.4.38", + "@vue/shared": "3.4.38" } }, "node_modules/@vue/shared": { - "version": "3.4.37", - "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.4.37.tgz", - "integrity": "sha512-nIh8P2fc3DflG8+5Uw8PT/1i17ccFn0xxN/5oE9RfV5SVnd7G0XEFRwakrnNFE/jlS95fpGXDVG5zDETS26nmg==" + "version": "3.4.38", + "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.4.38.tgz", + "integrity": "sha512-q0xCiLkuWWQLzVrecPb0RMsNWyxICOjPrcrwxTUEHb1fsnvni4dcuyG7RT/Ie7VPTvnjzIaWzRMUBsrqNj/hhw==" }, "node_modules/@webassemblyjs/ast": { "version": "1.12.1", @@ -11091,9 +11091,9 @@ } }, "node_modules/axios": { - "version": "1.7.3", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.3.tgz", - "integrity": "sha512-Ar7ND9pU99eJ9GpoGQKhKf58GpUOgnzuaB7ueNQ5BMi0p+LZ5oaEnfF999fAArcTIBwXTCHAmGcHOZJaWPq9Nw==", + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.4.tgz", + "integrity": "sha512-DukmaFRnY6AzAALSH4J2M3k6PkaC+MfaAGdEERRWcC9q3/TWQwLpHR8ZRLKTdQ3aBDL64EdluRDjJqKw+BPZEw==", "dependencies": { "follow-redirects": "^1.15.6", "form-data": "^4.0.0", @@ -17145,17 +17145,6 @@ "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" } }, - "node_modules/dom-serializer/node_modules/entities": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", - "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", - "engines": { - "node": ">=0.12" - }, - "funding": { - "url": "https://github.com/fb55/entities?sponsor=1" - } - }, "node_modules/dom-walk": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/dom-walk/-/dom-walk-0.1.2.tgz", @@ -17271,9 +17260,9 @@ "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" }, "node_modules/electron-to-chromium": { - "version": "1.5.5", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.5.tgz", - "integrity": "sha512-QR7/A7ZkMS8tZuoftC/jfqNkZLQO779SSW3YuZHP4eXpj3EffGLFcB/Xu9AAZQzLccTiCV+EmUo3ha4mQ9wnlA==" + "version": "1.5.8", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.8.tgz", + "integrity": "sha512-4Nx0gP2tPNBLTrFxBMHpkQbtn2hidPVr/+/FTtcCiBYTucqc70zRyVZiOLj17Ui3wTO7SQ1/N+hkHYzJjBzt6A==" }, "node_modules/elkjs": { "version": "0.9.3", @@ -17394,9 +17383,9 @@ } }, "node_modules/entities": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-5.0.0.tgz", - "integrity": "sha512-BeJFvFRJddxobhvEdm5GqHzRV/X+ACeuw0/BuuxsCh1EUZcAIz8+kYmBp/LrQuloy6K1f3a0M7+IhmZ7QnkISA==", + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", "engines": { "node": ">=0.12" }, @@ -19509,9 +19498,9 @@ "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" }, "node_modules/express-validator": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/express-validator/-/express-validator-7.1.0.tgz", - "integrity": "sha512-ePn6NXjHRZiZkwTiU1Rl2hy6aUqmi6Cb4/s8sfUsKH7j2yYl9azSpl8xEHcOj1grzzQ+UBEoLWtE1s6FDxW++g==", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/express-validator/-/express-validator-7.2.0.tgz", + "integrity": "sha512-I2ByKD8panjtr8Y05l21Wph9xk7kk64UMyvJCl/fFM/3CTJq8isXYPLeKW/aZBCdb/LYNv63PwhY8khw8VWocA==", "dependencies": { "lodash": "^4.17.21", "validator": "~13.12.0" @@ -20330,14 +20319,6 @@ "node": ">= 12.20" } }, - "node_modules/formdata-node/node_modules/web-streams-polyfill": { - "version": "4.0.0-beta.3", - "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-4.0.0-beta.3.tgz", - "integrity": "sha512-QW95TCTaHmsYfHDybGMwO5IJIM93I/6vTRk+daHTWFPhwh+C8Cg7j7XyKrwrj8Ib6vYXe0ocYNrmzY4xAAN6ug==", - "engines": { - "node": ">= 14" - } - }, "node_modules/formidable": { "version": "3.5.1", "resolved": "https://registry.npmjs.org/formidable/-/formidable-3.5.1.tgz", @@ -20532,20 +20513,32 @@ } }, "node_modules/gaxios": { - "version": "6.7.0", - "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-6.7.0.tgz", - "integrity": "sha512-DSrkyMTfAnAm4ks9Go20QGOcXEyW/NmZhvTYBU2rb4afBB393WIMQPWPEDMl/k8xqiNN9HYq2zao3oWXsdl2Tg==", + "version": "6.7.1", + "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-6.7.1.tgz", + "integrity": "sha512-LDODD4TMYx7XXdpwxAVRAIAuB0bzv0s+ywFonY46k126qzQHT9ygyoa9tncmOiQmmDrik65UYsEkv3lbfqQ3yQ==", "dependencies": { "extend": "^3.0.2", "https-proxy-agent": "^7.0.1", "is-stream": "^2.0.0", "node-fetch": "^2.6.9", - "uuid": "^10.0.0" + "uuid": "^9.0.1" }, "engines": { "node": ">=14" } }, + "node_modules/gaxios/node_modules/uuid": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", + "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "bin": { + "uuid": "dist/bin/uuid" + } + }, "node_modules/gcp-metadata": { "version": "5.3.0", "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-5.3.0.tgz", @@ -21247,9 +21240,9 @@ } }, "node_modules/hast-util-from-parse5/node_modules/@types/unist": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.2.tgz", - "integrity": "sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ==" + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", + "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==" }, "node_modules/hast-util-is-element": { "version": "3.0.0", @@ -21300,9 +21293,9 @@ } }, "node_modules/hast-util-raw/node_modules/@types/unist": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.2.tgz", - "integrity": "sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ==" + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", + "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==" }, "node_modules/hast-util-to-jsx-runtime": { "version": "2.3.0", @@ -21331,9 +21324,9 @@ } }, "node_modules/hast-util-to-jsx-runtime/node_modules/@types/unist": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.2.tgz", - "integrity": "sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ==" + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", + "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==" }, "node_modules/hast-util-to-parse5": { "version": "8.0.0", @@ -21369,9 +21362,9 @@ } }, "node_modules/hast-util-to-text/node_modules/@types/unist": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.2.tgz", - "integrity": "sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ==" + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", + "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==" }, "node_modules/hast-util-whitespace": { "version": "3.0.0", @@ -21636,17 +21629,6 @@ "entities": "^4.4.0" } }, - "node_modules/htmlparser2/node_modules/entities": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", - "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", - "engines": { - "node": ">=0.12" - }, - "funding": { - "url": "https://github.com/fb55/entities?sponsor=1" - } - }, "node_modules/http-browserify": { "version": "1.7.0", "resolved": "https://registry.npmjs.org/http-browserify/-/http-browserify-1.7.0.tgz", @@ -21882,9 +21864,9 @@ ] }, "node_modules/ignore": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz", - "integrity": "sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==", + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", "engines": { "node": ">= 4" } @@ -23721,9 +23703,9 @@ } }, "node_modules/kruptein": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/kruptein/-/kruptein-3.0.6.tgz", - "integrity": "sha512-EQJjTwAJfQkC4NfdQdo3HXM2a9pmBm8oidzH270cYu1MbgXPNPMJuldN7OPX+qdhPO5rw4X3/iKz0BFBfkXGKA==", + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/kruptein/-/kruptein-3.0.7.tgz", + "integrity": "sha512-vTftnEjfbqFHLqxDUMQCj6gBo5lKqjV4f0JsM8rk8rM3xmvFZ2eSy4YALdaye7E+cDKnEj7eAjFR3vwh8a4PgQ==", "dependencies": { "asn1.js": "^5.4.1" }, @@ -23964,11 +23946,6 @@ "resolved": "https://registry.npmjs.org/lodash.chunk/-/lodash.chunk-4.2.0.tgz", "integrity": "sha512-ZzydJKfUHJwHa+hF5X66zLFCBrWn5GeF28OHEr4WVWtNDXlQ/IjWKPBiikqKo2ne0+v6JgCgJ0GzJp8k8bHC7w==" }, - "node_modules/lodash.clonedeep": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", - "integrity": "sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ==" - }, "node_modules/lodash.debounce": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", @@ -24232,9 +24209,9 @@ "dev": true }, "node_modules/mapbox-gl": { - "version": "3.5.2", - "resolved": "https://registry.npmjs.org/mapbox-gl/-/mapbox-gl-3.5.2.tgz", - "integrity": "sha512-KUrmDmLFKPp3MSsWGNTH5uvtYwJknV+eFJ+vxiN6hqKpzbme37z+JfYs5Mehs3CgFaIV/pUdnEV9UPUZJPuS+Q==", + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/mapbox-gl/-/mapbox-gl-3.6.0.tgz", + "integrity": "sha512-xjYHHIJDh6haYcKY+/9jh1eywwYfIOWCgT5Fowj4JriZexx/oOtg2S7BQDMZtpFyg9IN4VLCysmUWxY0pFNRWA==", "workspaces": [ "src/style-spec", "test/build/typings" @@ -24257,7 +24234,6 @@ "gl-matrix": "^3.4.3", "grid-index": "^1.1.0", "kdbush": "^4.0.2", - "lodash.clonedeep": "^4.5.0", "murmurhash-js": "^1.0.0", "pbf": "^3.2.1", "potpack": "^2.0.0", @@ -24265,7 +24241,6 @@ "rw": "^1.3.3", "serialize-to-js": "^3.1.2", "supercluster": "^8.0.1", - "tiny-lru": "^11.2.11", "tinyqueue": "^3.0.0", "tweakpane": "^4.0.4", "vt-pbf": "^3.1.3" @@ -24302,17 +24277,6 @@ "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" }, - "node_modules/markdown-it/node_modules/entities": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", - "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", - "engines": { - "node": ">=0.12" - }, - "funding": { - "url": "https://github.com/fb55/entities?sponsor=1" - } - }, "node_modules/markdown-table": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-3.0.3.tgz", @@ -24544,9 +24508,9 @@ } }, "node_modules/mdast-util-gfm-footnote/node_modules/@types/unist": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.2.tgz", - "integrity": "sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ==" + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", + "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==" }, "node_modules/mdast-util-gfm-footnote/node_modules/mdast-util-from-markdown": { "version": "2.0.1", @@ -25039,9 +25003,9 @@ } }, "node_modules/mdast-util-gfm-strikethrough/node_modules/@types/unist": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.2.tgz", - "integrity": "sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ==" + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", + "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==" }, "node_modules/mdast-util-gfm-strikethrough/node_modules/mdast-util-from-markdown": { "version": "2.0.1", @@ -25536,9 +25500,9 @@ } }, "node_modules/mdast-util-gfm-table/node_modules/@types/unist": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.2.tgz", - "integrity": "sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ==" + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", + "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==" }, "node_modules/mdast-util-gfm-table/node_modules/mdast-util-from-markdown": { "version": "2.0.1", @@ -26032,9 +25996,9 @@ } }, "node_modules/mdast-util-gfm-task-list-item/node_modules/@types/unist": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.2.tgz", - "integrity": "sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ==" + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", + "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==" }, "node_modules/mdast-util-gfm-task-list-item/node_modules/mdast-util-from-markdown": { "version": "2.0.1", @@ -26513,9 +26477,9 @@ } }, "node_modules/mdast-util-gfm/node_modules/@types/unist": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.2.tgz", - "integrity": "sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ==" + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", + "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==" }, "node_modules/mdast-util-gfm/node_modules/mdast-util-from-markdown": { "version": "2.0.1", @@ -27012,9 +26976,9 @@ } }, "node_modules/mdast-util-math/node_modules/@types/unist": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.2.tgz", - "integrity": "sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ==" + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", + "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==" }, "node_modules/mdast-util-math/node_modules/mdast-util-from-markdown": { "version": "2.0.1", @@ -27510,9 +27474,9 @@ } }, "node_modules/mdast-util-mdx-expression/node_modules/@types/unist": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.2.tgz", - "integrity": "sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ==" + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", + "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==" }, "node_modules/mdast-util-mdx-expression/node_modules/mdast-util-from-markdown": { "version": "2.0.1", @@ -28015,9 +27979,9 @@ } }, "node_modules/mdast-util-mdx-jsx/node_modules/@types/unist": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.2.tgz", - "integrity": "sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ==" + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", + "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==" }, "node_modules/mdast-util-mdx-jsx/node_modules/mdast-util-from-markdown": { "version": "2.0.1", @@ -28513,9 +28477,9 @@ } }, "node_modules/mdast-util-mdxjs-esm/node_modules/@types/unist": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.2.tgz", - "integrity": "sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ==" + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", + "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==" }, "node_modules/mdast-util-mdxjs-esm/node_modules/mdast-util-from-markdown": { "version": "2.0.1", @@ -29146,9 +29110,9 @@ } }, "node_modules/mdast-util-to-markdown/node_modules/@types/unist": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.2.tgz", - "integrity": "sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ==" + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", + "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==" }, "node_modules/mdast-util-to-markdown/node_modules/mdast-util-to-string": { "version": "4.0.0", @@ -30951,9 +30915,9 @@ } }, "node_modules/mocha": { - "version": "10.7.0", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.7.0.tgz", - "integrity": "sha512-v8/rBWr2VO5YkspYINnvu81inSz2y3ODJrhO175/Exzor1RcEZZkizgE2A+w/CAXXoESS8Kys5E62dOHGHzULA==", + "version": "10.7.3", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.7.3.tgz", + "integrity": "sha512-uQWxAu44wwiACGqjbPYmjo7Lg8sFrS3dQe7PP2FQI+woptP4vZXSMcfMyFL/e1yFEeEpV4RtyTpZROOKmxis+A==", "dev": true, "dependencies": { "ansi-colors": "^4.1.3", @@ -31143,9 +31107,9 @@ } }, "node_modules/mongoose": { - "version": "8.5.2", - "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-8.5.2.tgz", - "integrity": "sha512-GZB4rHMdYfGatV+23IpCrqFbyCOjCNOHXgWbirr92KRwTEncBrtW3kgU9vmpKjsGf7nMmnAy06SwWUv1vhDkSg==", + "version": "8.5.3", + "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-8.5.3.tgz", + "integrity": "sha512-OubSDbsAclDFGHjV82MsKyIGQWFc42Ot1l+0dhRS6U9xODM7rm/ES/WpOQd8Ds9j0Mx8QzxZtrSCnBh6o9wUqw==", "dependencies": { "bson": "^6.7.0", "kareem": "2.6.3", @@ -34265,9 +34229,9 @@ } }, "node_modules/openai": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/openai/-/openai-4.55.1.tgz", - "integrity": "sha512-FziYJcWl+SAGbt5AcRIzVzNcnKohpEMQdtzVOmHFbBp/if7x2+ACqgxF2XUbyi2PcKONPcVpmtG5h9qoDAEXwQ==", + "version": "4.55.7", + "resolved": "https://registry.npmjs.org/openai/-/openai-4.55.7.tgz", + "integrity": "sha512-I2dpHTINt0Zk+Wlns6KzkKu77MmNW3VfIIQf5qYziEUI6t7WciG1zTobfKqdPzBmZi3TTM+3DtjPumxQdcvzwA==", "dependencies": { "@types/node": "^18.11.18", "@types/node-fetch": "^2.6.4", @@ -34290,9 +34254,9 @@ } }, "node_modules/openai/node_modules/@types/node": { - "version": "18.19.43", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.43.tgz", - "integrity": "sha512-Mw/YlgXnyJdEwLoFv2dpuJaDFriX+Pc+0qOBJ57jC1H6cDxIj2xc5yUrdtArDVG0m+KV6622a4p2tenEqB3C/g==", + "version": "18.19.44", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.44.tgz", + "integrity": "sha512-ZsbGerYg72WMXUIE9fYxtvfzLEuq6q8mKERdWFnqTmOvudMxnz+CBNRoOwJ2kNpFOncrKjT1hZwxjlFgQ9qvQA==", "dependencies": { "undici-types": "~5.26.4" } @@ -34542,17 +34506,6 @@ "url": "https://github.com/inikulin/parse5?sponsor=1" } }, - "node_modules/parse5/node_modules/entities": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", - "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", - "engines": { - "node": ">=0.12" - }, - "funding": { - "url": "https://github.com/fb55/entities?sponsor=1" - } - }, "node_modules/parseley": { "version": "0.12.1", "resolved": "https://registry.npmjs.org/parseley/-/parseley-0.12.1.tgz", @@ -35110,9 +35063,9 @@ } }, "node_modules/postcss-selector-parser": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.1.tgz", - "integrity": "sha512-b4dlw/9V8A71rLIDsSwVmak9z2DuBUB7CA1/wSdelNEzqsjoSPeADTWNO09lpH49Diy3/JIZ2bSPB1dI3LJCHg==", + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz", + "integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==", "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" @@ -35331,17 +35284,17 @@ } }, "node_modules/prosemirror-transform": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/prosemirror-transform/-/prosemirror-transform-1.9.0.tgz", - "integrity": "sha512-5UXkr1LIRx3jmpXXNKDhv8OyAOeLTGuXNwdVfg8x27uASna/wQkr9p6fD3eupGOi4PLJfbezxTyi/7fSJypXHg==", + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/prosemirror-transform/-/prosemirror-transform-1.10.0.tgz", + "integrity": "sha512-9UOgFSgN6Gj2ekQH5CTDJ8Rp/fnKR2IkYfGdzzp5zQMFsS4zDllLVx/+jGcX86YlACpG7UR5fwAXiWzxqWtBTg==", "dependencies": { "prosemirror-model": "^1.21.0" } }, "node_modules/prosemirror-view": { - "version": "1.33.9", - "resolved": "https://registry.npmjs.org/prosemirror-view/-/prosemirror-view-1.33.9.tgz", - "integrity": "sha512-xV1A0Vz9cIcEnwmMhKKFAOkfIp8XmJRnaZoPqNXrPS7EK5n11Ov8V76KhR0RsfQd/SIzmWY+bg+M44A2Lx/Nnw==", + "version": "1.33.10", + "resolved": "https://registry.npmjs.org/prosemirror-view/-/prosemirror-view-1.33.10.tgz", + "integrity": "sha512-wsKg9JeQkWlkXG8DDcloI/tbB9r3CysziubigoC8wTuE6zobN/9cl8bGRk1J1XjkUp7rxGBziOSxrhoILL84hg==", "dependencies": { "prosemirror-model": "^1.20.0", "prosemirror-state": "^1.0.0", @@ -35970,9 +35923,9 @@ } }, "node_modules/react-icons": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/react-icons/-/react-icons-5.2.1.tgz", - "integrity": "sha512-zdbW5GstTzXaVKvGSyTaBalt7HSfuK5ovrzlpyiWHAFXndXTdd/1hdDHI4xBM1Mn7YriT6aqESucFl9kEXzrdw==", + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/react-icons/-/react-icons-5.3.0.tgz", + "integrity": "sha512-DnUk8aFbTyQPSkCfF8dbX6kQjXA9DktMeJqfjrg6cK9vwQVMxmcA3BfP4QoiztVmEHtwlTgLFsPuH2NskKT6eg==", "peerDependencies": { "react": "*" } @@ -36667,9 +36620,9 @@ } }, "node_modules/remark-parse/node_modules/@types/unist": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.2.tgz", - "integrity": "sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ==" + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", + "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==" }, "node_modules/remark-parse/node_modules/mdast-util-from-markdown": { "version": "2.0.1", @@ -39460,9 +39413,9 @@ "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" }, "node_modules/terser": { - "version": "5.31.5", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.31.5.tgz", - "integrity": "sha512-YPmas0L0rE1UyLL/llTWA0SiDOqIcAQYLeUj7cJYzXHlRTAnMSg9pPe4VJ5PlKvTrPQsdVFuiRiwyeNlYgwh2Q==", + "version": "5.31.6", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.31.6.tgz", + "integrity": "sha512-PQ4DAriWzKj+qgehQ7LK5bQqCFNMmlhjR2PFFLuqGCpuCAauxemVBWwWOxo3UIwWQx8+Pr61Df++r76wDmkQBg==", "dependencies": { "@jridgewell/source-map": "^0.3.3", "acorn": "^8.8.2", @@ -39627,14 +39580,6 @@ "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.3.3.tgz", "integrity": "sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==" }, - "node_modules/tiny-lru": { - "version": "11.2.11", - "resolved": "https://registry.npmjs.org/tiny-lru/-/tiny-lru-11.2.11.tgz", - "integrity": "sha512-27BIW0dIWTYYoWNnqSmoNMKe5WIbkXsc0xaCQHd3/3xT2XMuMJrzHdrO9QBFR14emBz1Bu0dOAs2sCBBrvgPQA==", - "engines": { - "node": ">=12" - } - }, "node_modules/tinycolor2": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/tinycolor2/-/tinycolor2-1.6.0.tgz", @@ -40737,9 +40682,9 @@ } }, "node_modules/unified/node_modules/@types/unist": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.2.tgz", - "integrity": "sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ==" + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", + "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==" }, "node_modules/uninstall": { "version": "0.0.0", @@ -40774,9 +40719,9 @@ } }, "node_modules/unist-util-find-after/node_modules/@types/unist": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.2.tgz", - "integrity": "sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ==" + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", + "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==" }, "node_modules/unist-util-is": { "version": "6.0.0", @@ -40791,9 +40736,9 @@ } }, "node_modules/unist-util-is/node_modules/@types/unist": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.2.tgz", - "integrity": "sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ==" + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", + "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==" }, "node_modules/unist-util-position": { "version": "5.0.0", @@ -40808,9 +40753,9 @@ } }, "node_modules/unist-util-position/node_modules/@types/unist": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.2.tgz", - "integrity": "sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ==" + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", + "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==" }, "node_modules/unist-util-remove-position": { "version": "5.0.0", @@ -40826,9 +40771,9 @@ } }, "node_modules/unist-util-remove-position/node_modules/@types/unist": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.2.tgz", - "integrity": "sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ==" + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", + "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==" }, "node_modules/unist-util-stringify-position": { "version": "3.0.3", @@ -40870,14 +40815,14 @@ } }, "node_modules/unist-util-visit-parents/node_modules/@types/unist": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.2.tgz", - "integrity": "sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ==" + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", + "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==" }, "node_modules/unist-util-visit/node_modules/@types/unist": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.2.tgz", - "integrity": "sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ==" + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", + "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==" }, "node_modules/universal-user-agent": { "version": "7.0.2", @@ -41234,9 +41179,9 @@ } }, "node_modules/vfile-location/node_modules/@types/unist": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.2.tgz", - "integrity": "sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ==" + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", + "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==" }, "node_modules/vfile-message": { "version": "4.0.2", @@ -41252,9 +41197,9 @@ } }, "node_modules/vfile-message/node_modules/@types/unist": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.2.tgz", - "integrity": "sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ==" + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", + "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==" }, "node_modules/vfile-message/node_modules/unist-util-stringify-position": { "version": "4.0.0", @@ -41269,9 +41214,9 @@ } }, "node_modules/vfile/node_modules/@types/unist": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.2.tgz", - "integrity": "sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ==" + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", + "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==" }, "node_modules/vfile/node_modules/unist-util-stringify-position": { "version": "4.0.0", @@ -41350,9 +41295,9 @@ } }, "node_modules/watchpack": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.1.tgz", - "integrity": "sha512-8wrBCMtVhqcXP2Sup1ctSkga6uc2Bx0IIvKyT7yTFier5AXHooSI+QyQQAtTb7+E0IUCCKyTFmXqdqgum2XWGg==", + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.2.tgz", + "integrity": "sha512-TnbFSbcOCcDgjZ4piURLCbJ3nJhznVh9kw6F6iokjiFPl8ONxe9A6nMDVXDiNbrSfLILs6vB07F7wLBrwPYzJw==", "dependencies": { "glob-to-regexp": "^0.4.1", "graceful-fs": "^4.1.2" @@ -41388,13 +41333,11 @@ } }, "node_modules/web-streams-polyfill": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-4.0.0.tgz", - "integrity": "sha512-0zJXHRAYEjM2tUfZ2DiSOHAa2aw1tisnnhU3ufD57R8iefL+DcdJyRBRyJpG+NUimDgbTI/lH+gAE1PAvV3Cgw==", - "optional": true, - "peer": true, + "version": "4.0.0-beta.3", + "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-4.0.0-beta.3.tgz", + "integrity": "sha512-QW95TCTaHmsYfHDybGMwO5IJIM93I/6vTRk+daHTWFPhwh+C8Cg7j7XyKrwrj8Ib6vYXe0ocYNrmzY4xAAN6ug==", "engines": { - "node": ">= 8" + "node": ">= 14" } }, "node_modules/web-worker": { diff --git a/src/client/views/LightboxView.tsx b/src/client/views/LightboxView.tsx index 334983ad0..b8b73e7dd 100644 --- a/src/client/views/LightboxView.tsx +++ b/src/client/views/LightboxView.tsx @@ -276,7 +276,7 @@ export class LightboxView extends ObservableReactComponent { }}> { this._docView = r !== null ? r : undefined; })} -- cgit v1.2.3-70-g09d2 From 325aa35c4bd5f57240ead2ec5f22ea9c4f19d522 Mon Sep 17 00:00:00 2001 From: bobzel Date: Thu, 15 Aug 2024 23:16:09 -0400 Subject: fixed dropping on multi col/row collections with margins --- .../CollectionMulticolumnView.scss | 69 +++++++++------- .../CollectionMulticolumnView.tsx | 94 +++++++++++----------- .../CollectionMultirowView.scss | 49 ++++++----- .../CollectionMultirowView.tsx | 31 +++---- src/client/views/nodes/trails/PresBox.tsx | 22 ++--- 5 files changed, 143 insertions(+), 122 deletions(-) (limited to 'src') diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.scss b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.scss index f983fd815..06d78c39e 100644 --- a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.scss +++ b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.scss @@ -1,43 +1,50 @@ -.collectionMulticolumnView_contents { - display: flex; - //overflow: hidden; // bcz: turned of to allow highlighting to appear when there is no border (e.g, for a component of the slide template) - width: 100%; +.collectionMulticolumnView_drop { height: 100%; + top: 0; + left: 0; + position: absolute; - .document-wrapper { + .collectionMulticolumnView_contents { display: flex; - flex-direction: column; + //overflow: hidden; // bcz: turned of to allow highlighting to appear when there is no border (e.g, for a component of the slide template) width: 100%; - align-items: center; - position: relative; - > .iconButton-container { - top: 0; - left: 0; - position: absolute; - } - - .contentFittingDocumentView { - margin: auto; - } + height: 100%; - .label-wrapper { + .document-wrapper { display: flex; - flex-direction: row; - justify-content: center; - height: 20px; + flex-direction: column; + width: 100%; + align-items: center; + position: relative; + > .iconButton-container { + top: 0; + left: 0; + position: absolute; + } + + .contentFittingDocumentView { + margin: auto; + } + + .label-wrapper { + display: flex; + flex-direction: row; + justify-content: center; + height: 20px; + } } - } - .multiColumnResizer { - cursor: ew-resize; - transition: 0.5s opacity ease; - display: flex; - flex-direction: column; + .multiColumnResizer { + cursor: ew-resize; + transition: 0.5s opacity ease; + display: flex; + flex-direction: column; - .multiColumnResizer-hdl { - width: 100%; - height: 100%; - transition: 0.5s background-color ease; + .multiColumnResizer-hdl { + width: 100%; + height: 100%; + transition: 0.5s background-color ease; + } } } } diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx index 5125bdb6c..c6884d866 100644 --- a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx +++ b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx @@ -17,6 +17,7 @@ import './CollectionMulticolumnView.scss'; import ResizeBar from './MulticolumnResizer'; import WidthLabel from './MulticolumnWidthLabel'; import { dropActionType } from '../../../util/DropActionTypes'; +import { SnappingManager } from '../../../util/SnappingManager'; interface WidthSpecifier { magnitude: number; @@ -211,15 +212,14 @@ export class CollectionMulticolumnView extends CollectionSubView() { return Transform.Identity(); }; - @undoBatch onInternalDrop = (e: Event, de: DragManager.DropEvent) => { let dropInd = -1; - if (de.complete.docDragData && this._mainCont) { + if (de.complete.docDragData && this._contRef.current) { let curInd = -1; de.complete.docDragData?.droppedDocuments.forEach(d => { curInd = this.childDocs.indexOf(d); }); - Array.from(this._mainCont.children).forEach((child, index) => { + Array.from(this._contRef.current.children).forEach((child, index) => { const brect = child.getBoundingClientRect(); if (brect.x < de.x && brect.x + brect.width > de.x) { if (curInd !== -1 && curInd === Math.floor(index / 2)) { @@ -317,11 +317,11 @@ export class CollectionMulticolumnView extends CollectionSubView() { this.childLayouts.forEach((layout, i) => { collector.push( // eslint-disable-next-line react/no-array-index-key - +
{this.getDisplayDoc(layout)} {this.layoutDoc._chromeHidden ? null : ( -
@@ -343,49 +343,53 @@ export class CollectionMulticolumnView extends CollectionSubView() { return collector; } + _contRef = React.createRef(); render() { return ( -
- {this.contents} - {!this._startIndex ? null : ( - -
{ - this._startIndex = Math.min(this.childLayoutPairs.length - 1, this._startIndex + this.maxShown); - })}> -
+
+ )} + {this._startIndex > this.childLayoutPairs.length - 1 || !this.maxShown ? null : ( + +
{ + this._startIndex = Math.min(this.childLayoutPairs.length - 1, this._startIndex + this.maxShown); + })}> + } color={SettingsManager.userColor} /> +
+
+ )} +
); } diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.scss b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.scss index f44eacb2a..0d49fabaa 100644 --- a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.scss +++ b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.scss @@ -1,34 +1,41 @@ -.collectionMultirowView_contents { - display: flex; - //overflow: hidden; // bcz: turned of to allow highlighting to appear when there is no border (e.g, for a component of the slide template) - width: 100%; +.collectionMultirowView_drop { height: 100%; - flex-direction: column; + top: 0; + left: 0; + position: absolute; - .document-wrapper { + .collectionMultirowView_contents { display: flex; - flex-direction: row; + //overflow: hidden; // bcz: turned of to allow highlighting to appear when there is no border (e.g, for a component of the slide template) + width: 100%; height: 100%; - align-items: center; + flex-direction: column; - .label-wrapper { + .document-wrapper { display: flex; flex-direction: row; - justify-content: center; - height: 20px; + height: 100%; + align-items: center; + + .label-wrapper { + display: flex; + flex-direction: row; + justify-content: center; + height: 20px; + } } - } - .multiRowResizer { - cursor: ns-resize; - transition: 0.5s opacity ease; - display: flex; - flex-direction: row; + .multiRowResizer { + cursor: ns-resize; + transition: 0.5s opacity ease; + display: flex; + flex-direction: row; - .multiRowResizer-hdl { - width: 100%; - height: 100%; - transition: 0.5s background-color ease; + .multiRowResizer-hdl { + width: 100%; + height: 100%; + transition: 0.5s background-color ease; + } } } } diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx index 2833ff2f8..04b85e182 100644 --- a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx +++ b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx @@ -196,12 +196,12 @@ export class CollectionMultirowView extends CollectionSubView() { @undoBatch onInternalDrop = (e: Event, de: DragManager.DropEvent) => { let dropInd = -1; - if (de.complete.docDragData && this._mainCont) { + if (de.complete.docDragData && this._contRef.current) { let curInd = -1; de.complete.docDragData?.droppedDocuments.forEach(d => { curInd = this.childDocs.indexOf(d); }); - Array.from(this._mainCont.children).forEach((child, index) => { + Array.from(this._contRef.current.children).forEach((child, index) => { const brect = child.getBoundingClientRect(); if (brect.y < de.y && brect.y + brect.height > de.y) { if (curInd !== -1 && curInd === Math.floor(index / 2)) { @@ -318,20 +318,23 @@ export class CollectionMultirowView extends CollectionSubView() { return collector; } + _contRef = React.createRef(); render() { return ( -
- {this.contents} +
+
+ {this.contents} +
); } diff --git a/src/client/views/nodes/trails/PresBox.tsx b/src/client/views/nodes/trails/PresBox.tsx index cf32a0196..7448fa898 100644 --- a/src/client/views/nodes/trails/PresBox.tsx +++ b/src/client/views/nodes/trails/PresBox.tsx @@ -2,7 +2,7 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { Tooltip } from '@mui/material'; import Slider from '@mui/material/Slider'; import { Button, Dropdown, DropdownType, IconButton, Toggle, ToggleType, Type } from 'browndash-components'; -import { action, computed, IReactionDisposer, makeObservable, observable, ObservableSet, reaction, runInAction } from 'mobx'; +import { IReactionDisposer, ObservableSet, action, computed, makeObservable, observable, reaction, runInAction } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; import { AiOutlineSend } from 'react-icons/ai'; @@ -10,7 +10,8 @@ import { BiMicrophone } from 'react-icons/bi'; import { FaArrowDown, FaArrowLeft, FaArrowRight, FaArrowUp } from 'react-icons/fa'; import ReactLoading from 'react-loading'; import ReactTextareaAutosize from 'react-textarea-autosize'; -import { lightOrDark, returnFalse, returnOne, setupMoveUpEvents, StopEvent } from '../../../../ClientUtils'; +import { StopEvent, lightOrDark, returnFalse, returnOne, setupMoveUpEvents } from '../../../../ClientUtils'; +import { emptyFunction, stringHash } from '../../../../Utils'; import { Doc, DocListCast, Field, FieldResult, FieldType, NumListCast, Opt, StrListCast } from '../../../../fields/Doc'; import { Animation, DocData, TransitionTimer } from '../../../../fields/DocSymbols'; import { Copy } from '../../../../fields/FieldSymbols'; @@ -20,24 +21,23 @@ import { ObjectField } from '../../../../fields/ObjectField'; import { listSpec } from '../../../../fields/Schema'; import { ComputedField, ScriptField } from '../../../../fields/ScriptField'; import { BoolCast, Cast, DocCast, NumCast, StrCast, toList } from '../../../../fields/Types'; -import { emptyFunction, stringHash } from '../../../../Utils'; -import { getSlideTransitionSuggestions, gptSlideProperties, gptTrailSlideCustomization } from '../../../apis/gpt/PresCustomization'; import { DocServer } from '../../../DocServer'; -import { Docs } from '../../../documents/Documents'; +import { getSlideTransitionSuggestions, gptSlideProperties, gptTrailSlideCustomization } from '../../../apis/gpt/PresCustomization'; import { CollectionViewType, DocumentType } from '../../../documents/DocumentTypes'; +import { Docs } from '../../../documents/Documents'; import { DictationManager } from '../../../util/DictationManager'; import { dropActionType } from '../../../util/DropActionTypes'; import { ScriptingGlobals } from '../../../util/ScriptingGlobals'; import { SerializationHelper } from '../../../util/SerializationHelper'; import { SnappingManager } from '../../../util/SnappingManager'; -import { undoable, undoBatch, UndoManager } from '../../../util/UndoManager'; -import { CollectionFreeFormView } from '../../collections/collectionFreeForm'; -import { CollectionFreeFormPannableContents } from '../../collections/collectionFreeForm/CollectionFreeFormPannableContents'; +import { UndoManager, undoBatch, undoable } from '../../../util/UndoManager'; +import { ViewBoxBaseComponent } from '../../DocComponent'; +import { pinDataTypes as dataTypes } from '../../PinFuncs'; import { CollectionView } from '../../collections/CollectionView'; import { TreeView } from '../../collections/TreeView'; -import { ViewBoxBaseComponent } from '../../DocComponent'; +import { CollectionFreeFormView } from '../../collections/collectionFreeForm'; +import { CollectionFreeFormPannableContents } from '../../collections/collectionFreeForm/CollectionFreeFormPannableContents'; import { Colors } from '../../global/globalEnums'; -import { pinDataTypes as dataTypes } from '../../PinFuncs'; import { DocumentView } from '../DocumentView'; import { FieldView, FieldViewProps } from '../FieldView'; import { FocusViewOptions } from '../FocusViewOptions'; @@ -47,7 +47,7 @@ import CubicBezierEditor, { EaseFuncToPoints, TIMING_DEFAULT_MAPPINGS } from './ import './PresBox.scss'; import { PresEffect, PresEffectDirection, PresMovement, PresStatus } from './PresEnums'; import SlideEffect from './SlideEffect'; -import { AnimationSettings, easeItems, effectItems, effectTimings, movementItems, presEffectDefaultTimings, springMappings, springPreviewColors, SpringSettings, SpringType } from './SpringUtils'; +import { AnimationSettings, SpringSettings, SpringType, easeItems, effectItems, effectTimings, movementItems, presEffectDefaultTimings, springMappings, springPreviewColors } from './SpringUtils'; @observer export class PresBox extends ViewBoxBaseComponent() { -- cgit v1.2.3-70-g09d2 From d0c072b36ae6b9a65f993592bc7a27719126fda9 Mon Sep 17 00:00:00 2001 From: bobzel Date: Thu, 15 Aug 2024 23:18:38 -0400 Subject: from last --- .../collections/collectionMulticolumn/CollectionMulticolumnView.tsx | 2 +- .../views/collections/collectionMulticolumn/CollectionMultirowView.tsx | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) (limited to 'src') diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx index c6884d866..c4c025ded 100644 --- a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx +++ b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx @@ -10,7 +10,7 @@ import { BoolCast, NumCast, ScriptCast, StrCast } from '../../../../fields/Types import { DragManager } from '../../../util/DragManager'; import { SettingsManager } from '../../../util/SettingsManager'; import { Transform } from '../../../util/Transform'; -import { undoBatch, undoable } from '../../../util/UndoManager'; +import { undoable } from '../../../util/UndoManager'; import { DocumentView } from '../../nodes/DocumentView'; import { CollectionSubView, SubCollectionViewProps } from '../CollectionSubView'; import './CollectionMulticolumnView.scss'; diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx index 04b85e182..bda8e91ac 100644 --- a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx +++ b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx @@ -6,7 +6,6 @@ import { BoolCast, NumCast, ScriptCast, StrCast } from '../../../../fields/Types import { DragManager } from '../../../util/DragManager'; import { dropActionType } from '../../../util/DropActionTypes'; import { Transform } from '../../../util/Transform'; -import { undoBatch } from '../../../util/UndoManager'; import { DocumentView } from '../../nodes/DocumentView'; import { CollectionSubView, SubCollectionViewProps } from '../CollectionSubView'; import './CollectionMultirowView.scss'; @@ -193,7 +192,6 @@ export class CollectionMultirowView extends CollectionSubView() { return Transform.Identity(); // type coersion, this case should never be hit }; - @undoBatch onInternalDrop = (e: Event, de: DragManager.DropEvent) => { let dropInd = -1; if (de.complete.docDragData && this._contRef.current) { -- cgit v1.2.3-70-g09d2 From b6f6acb80f57011594d39b9ce576a5e77862cb7f Mon Sep 17 00:00:00 2001 From: bobzel Date: Thu, 15 Aug 2024 23:50:01 -0400 Subject: fixed horiz alignment of items in multicolumnview --- src/client/views/collections/CollectionStackingView.tsx | 9 +++++---- .../collectionMulticolumn/CollectionMulticolumnView.tsx | 5 ++--- 2 files changed, 7 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx index 0f12c111e..3f8aee792 100644 --- a/src/client/views/collections/CollectionStackingView.tsx +++ b/src/client/views/collections/CollectionStackingView.tsx @@ -320,7 +320,7 @@ export class CollectionStackingView extends CollectionSubView this.getDocHeight(doc); const panelHeight = () => (this.isStackingView ? height() : Math.min(height(), this._props.PanelHeight())); - const panelWidth = () => (this.isStackingView ? width() : this.columnWidth); + const panelWidth = () => this.columnWidth; const stackedDocTransform = () => this.getDocTransform(doc); this._docXfs.push({ stackedDocTransform, width, height }); return count > this._renderCount ? null : ( @@ -373,9 +373,10 @@ export class CollectionStackingView extends CollectionSubView { - const { columnUnitLength } = this; - if (columnUnitLength === undefined) { + if (this.columnUnitLength === undefined) { return Transform.Identity(); // we're still waiting on promises to resolve } let offset = 0; // eslint-disable-next-line no-restricted-syntax for (const { layout: candidate } of this.childLayoutPairs) { if (candidate === layout) { - return this.ScreenToLocalBoxXf().translate(0, -offset / (this._props.NativeDimScaling?.() || 1)); + return this.ScreenToLocalBoxXf().translate(-offset / (this._props.NativeDimScaling?.() || 1), 0); } offset += this.lookupPixels(candidate) + resizerWidth; } -- cgit v1.2.3-70-g09d2 From e57584a1be9d428fb40fc789494a7ac0ac14fb84 Mon Sep 17 00:00:00 2001 From: bobzel Date: Mon, 19 Aug 2024 16:42:56 -0400 Subject: extensive fixes to DiagramBox --- src/client/documents/Documents.ts | 1 + src/client/util/CurrentUserUtils.ts | 16 +- .../collectionGrid/CollectionGridView.tsx | 6 +- src/client/views/nodes/DiagramBox.scss | 112 +++---- src/client/views/nodes/DiagramBox.tsx | 360 ++++++++------------- .../views/nodes/formattedText/FormattedTextBox.tsx | 3 +- 6 files changed, 206 insertions(+), 292 deletions(-) (limited to 'src') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index d7fdf016c..b108b73db 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -256,6 +256,7 @@ export class DocumentOptions { _layout_nativeDimEditable?: BOOLt = new BoolInfo('native dimensions can be modified using document decoration reizers', false); _layout_reflowVertical?: BOOLt = new BoolInfo('permit vertical resizing with content "reflow"'); _layout_reflowHorizontal?: BOOLt = new BoolInfo('permit horizontal resizing with content reflow'); + _layout_noSidebar?: BOOLt = new BoolInfo('whether to display the sidebar toggle button'); layout_boxShadow?: string; // box-shadow css string OR "standard" to use dash standard box shadow layout_maxShown?: NUMt = new NumInfo('maximum number of children to display at one time (see multicolumnview)'); _layout_autoHeight?: BOOLt = new BoolInfo('whether document automatically resizes vertically to display contents'); diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts index c99ce1832..311b86fa4 100644 --- a/src/client/util/CurrentUserUtils.ts +++ b/src/client/util/CurrentUserUtils.ts @@ -321,20 +321,16 @@ export class CurrentUserUtils { const rtfield = new RichTextField(JSON.stringify( {doc: {type:"doc",content:[ {type:"code_block",content:[ - {type:"text",text:"^@mermaids"}, - {type:"text",text:"\n\n"}, - {type:"text",text:"pie "}, - {type:"text",text:"title"}, - {type:"text",text:" "}, - {type:"text",text:"Minerals in my tap water"}, - {type:"text",text:"\n \"Calcium\" : "}, + {type:"text",text:`^@mermaids\n`}, + {type:"text",text:`\n pie title Minerals in my tap water`}, + {type:"text",text:`\n "Calcium" : `}, {type:"dashField",attrs:{fieldKey:"calcium",docId:"",hideKey:true,hideValue:false,editable:true}}, - {type:"text",text:"\n \"Potassium\" : "}, + {type:"text",text:`\n "Potassium" : `}, {type:"dashField",attrs:{fieldKey:"pot",docId:"",hideKey:true,hideValue:false,editable:true}}, - {type:"text",text:"\n \"Magnesium\" : 10.01"} + {type:"text",text:`\n "Magnesium" : 10.01`} ]} ]}, - selection:{type:"text",anchor:109,head:109} + selection:{type:"text",anchor:1,head:1} }), `^@mermaids pie title Minerals in my tap water diff --git a/src/client/views/collections/collectionGrid/CollectionGridView.tsx b/src/client/views/collections/collectionGrid/CollectionGridView.tsx index 2d9191dd7..61bd0241c 100644 --- a/src/client/views/collections/collectionGrid/CollectionGridView.tsx +++ b/src/client/views/collections/collectionGrid/CollectionGridView.tsx @@ -13,7 +13,7 @@ import { undoBatch } from '../../../util/UndoManager'; import { ContextMenu } from '../../ContextMenu'; import { ContextMenuProps } from '../../ContextMenuItem'; import { DocumentView } from '../../nodes/DocumentView'; -import { CollectionSubView } from '../CollectionSubView'; +import { CollectionSubView, SubCollectionViewProps } from '../CollectionSubView'; import './CollectionGridView.scss'; import Grid, { Layout } from './Grid'; @@ -26,7 +26,7 @@ export class CollectionGridView extends CollectionSubView() { @observable private _scroll: number = 0; // required to make sure the decorations box container updates on scroll private dropLocation: object = {}; // sets the drop location for external drops - constructor(props: any) { + constructor(props: SubCollectionViewProps) { super(props); makeObservable(this); } @@ -200,7 +200,7 @@ export class CollectionGridView extends CollectionSubView() { whenChildContentsActiveChanged={this._props.whenChildContentsActiveChanged} onClickScript={this.onChildClickHandler} renderDepth={this._props.renderDepth + 1} - dontCenter={StrCast(this.layoutDoc.layout_dontCenter) as any} // 'y', 'x', 'xy' + dontCenter={StrCast(this.layoutDoc.layout_dontCenter) as 'x' | 'y' | 'xy'} /> ); } diff --git a/src/client/views/nodes/DiagramBox.scss b/src/client/views/nodes/DiagramBox.scss index d2749f1ad..323638bff 100644 --- a/src/client/views/nodes/DiagramBox.scss +++ b/src/client/views/nodes/DiagramBox.scss @@ -1,3 +1,5 @@ +$searchbarHeight: 50px; + .DIYNodeBox { width: 100%; height: 100%; @@ -6,83 +8,75 @@ align-items: center; justify-content: center; - .DIYNodeBox-wrapper { - width: 100%; - height: 100%; - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - .DIYNodeBox { - /* existing code */ - - .DIYNodeBox-iframe { - height: 100%; - width: 100%; - border: none; + .DIYNodeBox { + /* existing code */ - } + .DIYNodeBox-iframe { + height: 100%; + width: 100%; + border: none; } + } - .search-bar { - display: flex; - justify-content: center; - align-items: center; - width: 100%; - padding: 10px; + .DIYNodeBox-searchbar { + display: flex; + justify-content: center; + align-items: center; + width: 100%; + height: $searchbarHeight; + padding: 10px; - input[type="text"] { - flex: 1; - margin-right: 10px; - } + input[type='text'] { + flex: 1; + margin-right: 10px; + } - button { - padding: 5px 10px; - } + button { + padding: 5px 10px; } + } - .content { + .DIYNodeBox-content { + flex: 1; + display: flex; + justify-content: center; + align-items: center; + width: 100%; + height: calc(100% - $searchbarHeight); + .diagramBox { flex: 1; display: flex; justify-content: center; align-items: center; - width:100%; - height:100%; - .diagramBox{ + width: 100%; + height: 100%; + svg { flex: 1; display: flex; justify-content: center; align-items: center; - width:100%; - height:100%; - svg{ - flex: 1; - display: flex; - justify-content: center; - align-items: center; - width:100%; - height:100%; - } + width: 100%; + height: 100%; } } + } - .loading-circle { - position: relative; - width: 50px; - height: 50px; - border-radius: 50%; - border: 3px solid #ccc; - border-top-color: #333; - animation: spin 1s infinite linear; - } + .loading-circle { + position: relative; + width: 50px; + height: 50px; + border-radius: 50%; + border: 3px solid #ccc; + border-top-color: #333; + animation: spin 1s infinite linear; + } - @keyframes spin { - 0% { - transform: rotate(0deg); - } - 100% { - transform: rotate(360deg); - } + @keyframes spin { + 0% { + transform: rotate(0deg); + } + 100% { + transform: rotate(360deg); } } -} \ No newline at end of file +} diff --git a/src/client/views/nodes/DiagramBox.tsx b/src/client/views/nodes/DiagramBox.tsx index 32969fa53..36deb2d8d 100644 --- a/src/client/views/nodes/DiagramBox.tsx +++ b/src/client/views/nodes/DiagramBox.tsx @@ -1,284 +1,198 @@ import mermaid from 'mermaid'; -import { action, makeObservable, observable, reaction } from 'mobx'; +import { action, computed, makeObservable, observable, reaction } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; import { Doc, DocListCast } from '../../../fields/Doc'; -import { List } from '../../../fields/List'; +import { DocData } from '../../../fields/DocSymbols'; import { RichTextField } from '../../../fields/RichTextField'; -import { DocCast, NumCast } from '../../../fields/Types'; +import { Cast, DocCast, NumCast } from '../../../fields/Types'; +import { Gestures } from '../../../pen-gestures/GestureTypes'; import { GPTCallType, gptAPICall } from '../../apis/gpt/GPT'; import { DocumentType } from '../../documents/DocumentTypes'; import { Docs } from '../../documents/Documents'; import { DocumentManager } from '../../util/DocumentManager'; import { LinkManager } from '../../util/LinkManager'; +import { undoable } from '../../util/UndoManager'; import { ViewBoxAnnotatableComponent } from '../DocComponent'; import { InkingStroke } from '../InkingStroke'; import './DiagramBox.scss'; import { FieldView, FieldViewProps } from './FieldView'; +import { FormattedTextBox } from './formattedText/FormattedTextBox'; @observer export class DiagramBox extends ViewBoxAnnotatableComponent() { public static LayoutString(fieldKey: string) { return FieldView.LayoutString(DiagramBox, fieldKey); } - private _ref: React.RefObject = React.createRef(); - private _dragRef = React.createRef(); + static isPointInBox = (box: Doc, pt: number[]): boolean => { + if (typeof pt[0] === 'number' && typeof box.x === 'number' && typeof box.y === 'number' && typeof pt[1] === 'number') { + return pt[0] < box.x + NumCast(box.width) && pt[0] > box.x && pt[1] > box.y && pt[1] < box.y + NumCast(box.height); + } + return false; + }; + constructor(props: FieldViewProps) { super(props); makeObservable(this); } - @observable inputValue = ''; - @observable loading = false; - @observable errorMessage = ''; - @observable mermaidCode = ''; + @observable _showCode = false; + @observable _inputValue = ''; + @observable _generating = false; + @observable _errorMessage = ''; - @action handleInputChange = (e: React.ChangeEvent) => { - this.inputValue = e.target.value; - }; - async componentDidMount() { + @computed get mermaidcode() { + return Cast(this.Document[DocData].text, RichTextField, null)?.Text ?? ''; + } + + componentDidMount() { this._props.setContentViewBox?.(this); mermaid.initialize({ securityLevel: 'loose', startOnLoad: true, flowchart: { useMaxWidth: true, htmlLabels: true, curve: 'cardinal' }, }); - this.mermaidCode = 'asdasdasd'; - const docArray: Doc[] = DocListCast(this.Document.data); - let mermaidCodeDoc = docArray.filter(doc => doc.type === 'rich text'); - mermaidCodeDoc = mermaidCodeDoc.filter(doc => (doc.text as RichTextField).Text === 'mermaidCodeTitle'); - if (mermaidCodeDoc[0]) { - if (typeof mermaidCodeDoc[0].title === 'string') { - console.log(mermaidCodeDoc[0].title); - if (mermaidCodeDoc[0].title !== '') { - this.renderMermaidAsync(mermaidCodeDoc[0].title); - } - } - } - // this will create a text doc far away where the user cant to save the mermaid code, where it will then be accessed when flipped to the diagram box side - // the code is stored in the title since it is much easier to change than in the text - else { - DocumentManager.Instance.AddViewRenderedCb(this.Document, docViewForYourCollection => { - if (docViewForYourCollection && docViewForYourCollection.ComponentView) { - if (docViewForYourCollection.ComponentView.addDocument && docViewForYourCollection.ComponentView.removeDocument) { - const newDoc = Docs.Create.TextDocument('mermaidCodeTitle', { title: '', x: 9999 + NumCast(this.layoutDoc._width), y: 9999 }); - docViewForYourCollection.ComponentView?.addDocument(newDoc); - } - } - }); - } - console.log(this.Document.title); - // this is so that ever time a new doc, text node or ink node, is created, this.createMermaidCode will run which will create a save + // when a new doc/text/ink/shape is created in the freeform view, this generates the corresponding mermaid diagram code reaction( () => DocListCast(this.Document.data), - () => this.convertDrawingToMermaidCode(), + docArray => docArray.length && this.convertDrawingToMermaidCode(docArray), { fireImmediately: true } ); } - renderMermaid = async (str: string) => { + renderMermaid = (str: string) => { try { - const { svg, bindFunctions } = await this.mermaidDiagram(str); - return { svg, bindFunctions }; + return mermaid.render('graph' + Date.now(), str); } catch (error) { - console.error('Error rendering mermaid diagram:', error); return { svg: '', bindFunctions: undefined }; } }; - mermaidDiagram = async (str: string) => mermaid.render('graph' + Date.now(), str); - async renderMermaidAsync(mermaidCode: string) { + renderMermaidAsync = async (mermaidCode: string, dashDiv: HTMLDivElement) => { try { const { svg, bindFunctions } = await this.renderMermaid(mermaidCode); - const dashDiv = document.getElementById('dashDiv' + this.Document.title); - if (dashDiv) { - dashDiv.innerHTML = svg; - if (bindFunctions) { - bindFunctions(dashDiv); - } - } + dashDiv.innerHTML = svg; + bindFunctions?.(dashDiv); } catch (error) { console.error('Error rendering Mermaid:', error); } - } - @action handleRenderClick = () => { - this.generateMermaidCode(); }; - @action async generateMermaidCode() { - console.log('Generating Mermaid Code'); - this.loading = true; - let prompt = ''; - // let docArray: Doc[] = DocListCast(this.Document.data); - // let mermaidCodeDoc = docArray.filter(doc => doc.type == 'rich text') - // mermaidCodeDoc=mermaidCodeDoc.filter(doc=>(doc.text as RichTextField).Text=='mermaidCodeTitle') - // if(mermaidCodeDoc[0]){ - // console.log(mermaidCodeDoc[0].title) - // if(typeof mermaidCodeDoc[0].title=='string'){ - // console.log(mermaidCodeDoc[0].title) - // if(mermaidCodeDoc[0].title!=""){ - // prompt="Edit this code "+this.inputValue+": "+mermaidCodeDoc[0].title - // console.log("you have to see me") - // } - // } - // } - // else{ - prompt = 'Write this in mermaid code and only give me the mermaid code: ' + this.inputValue; - console.log('there is no text save'); - // } - const res = await gptAPICall(prompt, GPTCallType.MERMAID); - this.loading = false; - if (res === 'Error connecting with API.') { - // If GPT call failed - console.error('GPT call failed'); - this.errorMessage = 'GPT call failed; please try again.'; - } else if (res !== null) { - // If GPT call succeeded, set htmlCode;;; TODO: check if valid html - if (this.isValidCode(res)) { - this.mermaidCode = res; - console.log('GPT call succeeded:' + res); - this.errorMessage = ''; - } else { - console.error('GPT call succeeded but invalid html; please try again.'); - this.errorMessage = 'GPT call succeeded but invalid html; please try again.'; - } - } - this.renderMermaidAsync.call(this, this.removeWords(this.mermaidCode)); - this.loading = false; - } - isValidCode = (html: string) => true; - removeWords(inputStrIn: string) { - const inputStr = inputStrIn.replace('```mermaid', ''); - return inputStr.replace('```', ''); - } + + setMermaidCode = undoable((res: string) => { + this.Document[DocData].text = new RichTextField( + JSON.stringify({ + doc: { + type: 'doc', + content: [ + { + type: 'code_block', + content: [ + { type: 'text', text: `^@mermaids\n` }, + { type: 'text', text: this.removeWords(res) }, + ], + }, + ], + }, + selection: { type: 'text', anchor: 1, head: 1 }, + }), + res + ); + }, 'set mermaid code'); + + generateMermaidCode = action(() => { + this._generating = true; + const prompt = 'Write this in mermaid code and only give me the mermaid code: ' + this._inputValue; + gptAPICall(prompt, GPTCallType.MERMAID).then( + action(res => { + this._generating = false; + if (res === 'Error connecting with API.') { + this._errorMessage = 'GPT call failed; please try again.'; + } + // If GPT call succeeded, set mermaid code on Doc which will trigger a rendering if _showCode is false + else if (res && this.isValidCode(res)) { + this.setMermaidCode(res); + this._errorMessage = ''; + } else { + this._errorMessage = 'GPT call succeeded but invalid html; please try again.'; + } + }) + ); + }); + isValidCode = (html: string) => (html ? true : false); + removeWords = (inputStrIn: string) => inputStrIn.replace('```mermaid', '').replace(`^@mermaids`, '').replace('```', ''); + // method to convert the drawings on collection node side the mermaid code - async convertDrawingToMermaidCode() { - let mermaidCode = ''; - let diagramExists = false; - if (this.Document.data instanceof List) { - const docArray: Doc[] = DocListCast(this.Document.data); - const rectangleArray = docArray.filter(doc => doc.title === 'rectangle' || doc.title === 'circle'); - const lineArray = docArray.filter(doc => doc.title === 'line' || doc.title === 'stroke'); - const textArray = docArray.filter(doc => doc.type === 'rich text'); - const timeoutPromise = () => - new Promise(resolve => { - setTimeout(resolve, 0); - }); - await timeoutPromise(); - const inkStrokeArray = lineArray.map(doc => DocumentManager.Instance.getDocumentView(doc, this.DocumentView?.())).filter(inkView => inkView?.ComponentView instanceof InkingStroke); - console.log(inkStrokeArray.length); - console.log(lineArray.length); - if (inkStrokeArray[0] && inkStrokeArray.length === lineArray.length) { - mermaidCode = 'graph TD;'; - const inkingStrokeArray = inkStrokeArray.map(stroke => stroke?.ComponentView); - for (let i = 0; i < rectangleArray.length; i++) { - const rectangle = rectangleArray[i]; - for (let j = 0; j < lineArray.length; j++) { - const inkScaleX = (inkingStrokeArray[j] as InkingStroke)?.inkScaledData().inkScaleX; - const inkScaleY = (inkingStrokeArray[j] as InkingStroke)?.inkScaledData().inkScaleY; - const inkStrokeXArray = (inkingStrokeArray[j] as InkingStroke) - ?.inkScaledData() - .inkData.map(coord => coord.X) - .map(doc => doc * inkScaleX); - const inkStrokeYArray = (inkingStrokeArray[j] as InkingStroke) - ?.inkScaledData() - .inkData.map(coord => coord.Y) - .map(doc => doc * inkScaleY); - console.log(inkingStrokeArray.length); - console.log(lineArray.length); - // need to minX and minY to since the inkStroke.x and.y is not relative to the doc. so I have to do some calcluations - const minX: number = Math.min(...inkStrokeXArray); - const minY: number = Math.min(...inkStrokeYArray); - const startX = inkStrokeXArray[0] - minX + (lineArray[j]?.x as number); - const startY = inkStrokeYArray[0] - minY + (lineArray[j]?.y as number); - const endX = inkStrokeXArray[inkStrokeXArray.length - 1] - minX + (lineArray[j].x as number); - const endY = inkStrokeYArray[inkStrokeYArray.length - 1] - minY + (lineArray[j].y as number); - if (this.isPointInBox(rectangle, [startX, startY])) { - for (let k = 0; k < rectangleArray.length; k++) { - const rectangle2 = rectangleArray[k]; - if (this.isPointInBox(rectangle2, [endX, endY]) && typeof rectangle.x === 'number' && typeof rectangle2.x === 'number') { - diagramExists = true; - const linkedDocs: Doc[] = LinkManager.Instance.getAllRelatedLinks(lineArray[j]).map(d => DocCast(LinkManager.getOppositeAnchor(d, lineArray[j]))); - console.log(linkedDocs.length); - if (linkedDocs.length !== 0) { - const linkedText = (linkedDocs[0].text as RichTextField).Text; - mermaidCode += Math.abs(rectangle.x) + this.getTextInBox(rectangle, textArray) + '-->|' + linkedText + '|' + Math.abs(rectangle2.x) + this.getTextInBox(rectangle2, textArray) + ';'; - } else { - mermaidCode += Math.abs(rectangle.x) + this.getTextInBox(rectangle, textArray) + '-->' + Math.abs(rectangle2.x) + this.getTextInBox(rectangle2, textArray) + ';'; - } - } + convertDrawingToMermaidCode = async (docArray: Doc[]) => { + const rectangleArray = docArray.filter(doc => doc.title === Gestures.Rectangle || doc.title === Gestures.Circle); + const lineArray = docArray.filter(doc => doc.title === Gestures.Line || doc.title === Gestures.Stroke); + const textArray = docArray.filter(doc => doc.type === DocumentType.RTF); + await new Promise(resolve => setTimeout(resolve)); + const inkStrokeArray = lineArray.map(doc => DocumentManager.Instance.getDocumentView(doc, this.DocumentView?.())).filter(inkView => inkView?.ComponentView instanceof InkingStroke); + if (inkStrokeArray[0] && inkStrokeArray.length === lineArray.length) { + let mermaidCode = `graph TD \n`; + const inkingStrokeArray = inkStrokeArray.map(stroke => stroke?.ComponentView as InkingStroke).filter(stroke => stroke); + for (const rectangle of rectangleArray) { + for (const inkStroke of inkingStrokeArray) { + const inkData = inkStroke.inkScaledData(); + const { inkScaleX, inkScaleY } = inkData; + const inkStrokeXArray = inkData.inkData.map(coord => coord.X * inkScaleX); + const inkStrokeYArray = inkData.inkData.map(coord => coord.Y * inkScaleY); + // need to minX and minY to since the inkStroke.x and.y is not relative to the doc. so I have to do some calcluations + const offX = Math.min(...inkStrokeXArray) - NumCast(inkStroke.Document.x); + const offY = Math.min(...inkStrokeYArray) - NumCast(inkStroke.Document.y); + + const startX = inkStrokeXArray[0] - offX; + const startY = inkStrokeYArray[0] - offY; + const endX = inkStrokeXArray.lastElement() - offX; + const endY = inkStrokeYArray.lastElement() - offY; + if (DiagramBox.isPointInBox(rectangle, [startX, startY])) { + for (const rectangle2 of rectangleArray) { + if (DiagramBox.isPointInBox(rectangle2, [endX, endY])) { + const linkedDocs = LinkManager.Instance.getAllRelatedLinks(inkStroke.Document).map(d => DocCast(LinkManager.getOppositeAnchor(d, inkStroke.Document))); + const linkedDocText = Cast(linkedDocs[0]?.text, RichTextField, null)?.Text; + const linkText = linkedDocText ? `|${linkedDocText}|` : ''; + mermaidCode += ' ' + Math.abs(NumCast(rectangle.x)) + this.getTextInBox(rectangle, textArray) + '-->' + linkText + Math.abs(NumCast(rectangle2.x)) + this.getTextInBox(rectangle2, textArray) + `\n`; } } } } - // this will save the text - DocumentManager.Instance.AddViewRenderedCb(this.Document, docViewForYourCollection => { - if (docViewForYourCollection && docViewForYourCollection.ComponentView) { - if (docViewForYourCollection.ComponentView.addDocument && docViewForYourCollection.ComponentView.removeDocument) { - let docs: Doc[] = DocListCast(this.Document.data); - docs = docs.filter(doc => doc.type === 'rich text'); - const mermaidCodeDoc = docs.filter(doc => (doc.text as RichTextField).Text === 'mermaidCodeTitle'); - if (mermaidCodeDoc[0]) { - if (diagramExists) { - mermaidCodeDoc[0].title = mermaidCode; - } else { - mermaidCodeDoc[0].title = ''; - } - } - } - } - }); + this.setMermaidCode(mermaidCode); } } - } - testInkingStroke = () => { - if (this.Document.data instanceof List) { - const docArray: Doc[] = DocListCast(this.Document.data); - const lineArray = docArray.filter(doc => doc.title === 'line' || doc.title === 'stroke'); - setTimeout(() => { - const inkStrokeArray = lineArray.map(doc => DocumentManager.Instance.getDocumentView(doc, this.DocumentView?.())).filter(inkView => inkView?.ComponentView instanceof InkingStroke); - console.log(inkStrokeArray); - }); - } }; - getTextInBox = (box: Doc, richTextArray: Doc[]): string => { - for (let i = 0; i < richTextArray.length; i++) { - const textDoc = richTextArray[i]; - if (typeof textDoc.x === 'number' && typeof textDoc.y === 'number' && typeof box.x === 'number' && typeof box.height === 'number' && typeof box.width === 'number' && typeof box.y === 'number') { - if (textDoc.x > box.x && textDoc.x < box.x + box.width && textDoc.y > box.y && textDoc.y < box.y + box.height) { - if (box.title === 'rectangle') { - return '(' + ((textDoc.text as RichTextField)?.Text ?? '') + ')'; - } - if (box.title === 'circle') { - return '((' + ((textDoc.text as RichTextField)?.Text ?? '') + '))'; - } - } + + getTextInBox = (box: Doc, richTextArray: Doc[]) => { + for (const textDoc of richTextArray) { + if (DiagramBox.isPointInBox(box, [NumCast(textDoc.x), NumCast(textDoc.y)])) { + switch (box.title) { + case Gestures.Rectangle: return '(' + ((textDoc.text as RichTextField)?.Text ?? '') + ')'; + case Gestures.Circle: return '((' + ((textDoc.text as RichTextField)?.Text ?? '') + '))'; + default: + } // prettier-ignore } } return '( )'; }; - isPointInBox = (box: Doc, line: number[]): boolean => { - if (typeof line[0] === 'number' && typeof box.x === 'number' && typeof box.width === 'number' && typeof box.height === 'number' && typeof box.y === 'number' && typeof line[1] === 'number') { - return line[0] < box.x + box.width && line[0] > box.x && line[1] > box.y && line[1] < box.y + box.height; - } - return false; - }; render() { return ( -
-
-
- - -
-
- {this.mermaidCode ? ( -
- ) : ( -
{this.loading ?
:
{this.errorMessage ? this.errorMessage : 'Insert prompt to generate diagram'}
}
- )} -
+
+
+ e.key === 'Enter' && this.generateMermaidCode())} onChange={action(e => (this._inputValue = e.target.value))} /> + + (this._showCode = !this._showCode))} /> +
+
+ {this._showCode ? ( + + ) : this._generating ? ( +
+ ) : ( +
r && this.renderMermaidAsync.call(this, this.removeWords(this.mermaidcode), r)}> + {this._errorMessage || 'Type a prompt to generate a diagram'} +
+ )}
); @@ -286,6 +200,14 @@ export class DiagramBox extends ViewBoxAnnotatableComponent() { } Docs.Prototypes.TemplateMap.set(DocumentType.DIAGRAM, { - layout: { view: DiagramBox, dataField: 'dadta' }, - options: { _height: 300, _layout_fitWidth: true, _layout_nativeDimEditable: true, _layout_reflowVertical: true, waitForDoubleClickToClick: 'always', systemIcon: 'BsGlobe' }, + layout: { view: DiagramBox, dataField: 'data' }, + options: { + _height: 300, // + _layout_fitWidth: true, + _layout_nativeDimEditable: true, + _layout_reflowVertical: true, + _layout_reflowHorizontal: true, + waitForDoubleClickToClick: 'always', + systemIcon: 'BsGlobe', + }, }); diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx index e21902fdd..a88bd8920 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx +++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx @@ -1464,7 +1464,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent { - this._editorView?.dispatch(tx.deleteSelection().addStoredMark(mark)); + this._editorView?.dispatch(tx.addStoredMark(mark)); }); this.tryUpdateDoc(true); // calling select() above will make isContentActive() true only after a render .. which means the selectAll() above won't write to the Document and the incomingValue will overwrite the selection with the non-updated data } else { @@ -2090,6 +2090,7 @@ Docs.Prototypes.TemplateMap.set(DocumentType.RTF, { _layout_nativeDimEditable: true, _layout_reflowVertical: true, _layout_reflowHorizontal: true, + _layout_noSidebar: true, defaultDoubleClick: 'ignore', systemIcon: 'BsFileEarmarkTextFill', }, -- cgit v1.2.3-70-g09d2 From cdb21e036ff65d63991a53798133407be1d5755f Mon Sep 17 00:00:00 2001 From: bobzel Date: Tue, 20 Aug 2024 21:30:32 -0400 Subject: fixed error handling of images too big to load. cleaned up facecollectionbox. changed metadata field naming to match conventions. --- src/client/Network.ts | 11 +-- src/client/documents/DocUtils.ts | 2 +- .../collectionFreeForm/FaceCollectionBox.tsx | 88 ++++++++------------ .../collections/collectionFreeForm/MarqueeView.tsx | 97 +++------------------- src/client/views/nodes/FaceRectangles.tsx | 3 +- src/client/views/search/FaceRecognitionHandler.tsx | 64 +++++++------- 6 files changed, 87 insertions(+), 178 deletions(-) (limited to 'src') diff --git a/src/client/Network.ts b/src/client/Network.ts index 8876d8190..17f8a6534 100644 --- a/src/client/Network.ts +++ b/src/client/Network.ts @@ -1,3 +1,4 @@ +import formidable from 'formidable'; import * as requestPromise from 'request-promise'; import { ClientUtils } from '../ClientUtils'; import { Utils } from '../Utils'; @@ -49,15 +50,9 @@ export namespace Networking { if (!fileguidpairs.length) { return []; } - const maxFileSize = 5000000; + const maxFileSize = 6000000; if (fileguidpairs.some(f => f.file.size > maxFileSize)) { - return new Promise[]>(res => { - res([{ - source: { size: 0, filepath: '', mimetype: '', originalFilename: '', newFilename: '',hashAlgorithm: false, - toJSON: () => ({ size: 0, filepath: '', mimetype: '', originalFilename: '', newFilename: '',name: '', length: 0, mtime: new Date(), type: '' }) }, - result: { name: '', message: `max file size (${maxFileSize / 1000000}MB) exceeded` } - }]) // prettier-ignore - }); + return new Promise[]>(res => res([{ source: { newFilename: '', mimetype: '' } as formidable.File, result: new Error(`max file size (${maxFileSize / 1000000}MB) exceeded`) }])); } formData.set('fileguids', fileguidpairs.map(pair => pair.guid).join(';')); formData.set('filesize', fileguidpairs.reduce((sum, pair) => sum + pair.file.size, 0).toString()); diff --git a/src/client/documents/DocUtils.ts b/src/client/documents/DocUtils.ts index a503d732b..35d835f1f 100644 --- a/src/client/documents/DocUtils.ts +++ b/src/client/documents/DocUtils.ts @@ -739,7 +739,7 @@ export namespace DocUtils { const { source: { newFilename, mimetype }, result, - } = upfiles.lastElement() ?? { source: { newFilename: '', mimetype: '' }, result: { message: 'upload failed' } }; + } = upfiles.lastElement() ?? { source: { newFilename: '', mimetype: '' }, result: new Error('upload failed') }; if (result instanceof Error) { if (overwriteDoc) { overwriteDoc.loadingError = result.message; diff --git a/src/client/views/collections/collectionFreeForm/FaceCollectionBox.tsx b/src/client/views/collections/collectionFreeForm/FaceCollectionBox.tsx index 50b91e8fe..d5a2809dc 100644 --- a/src/client/views/collections/collectionFreeForm/FaceCollectionBox.tsx +++ b/src/client/views/collections/collectionFreeForm/FaceCollectionBox.tsx @@ -11,17 +11,20 @@ import { Doc, DocListCast } from '../../../../fields/Doc'; import { DocData } from '../../../../fields/DocSymbols'; import { Id } from '../../../../fields/FieldSymbols'; import { List } from '../../../../fields/List'; -import { ImageCast, StrCast } from '../../../../fields/Types'; +import { listSpec } from '../../../../fields/Schema'; +import { Cast, ImageCast, StrCast } from '../../../../fields/Types'; import { DocumentType } from '../../../documents/DocumentTypes'; import { Docs } from '../../../documents/Documents'; import { DragManager } from '../../../util/DragManager'; import { SnappingManager } from '../../../util/SnappingManager'; +import { undoable } from '../../../util/UndoManager'; import { ViewBoxBaseComponent } from '../../DocComponent'; import { ObservableReactComponent } from '../../ObservableReactComponent'; import { DocumentView } from '../../nodes/DocumentView'; import { FieldView, FieldViewProps } from '../../nodes/FieldView'; import './FaceCollectionBox.scss'; import { MarqueeOptionsMenu } from './MarqueeOptionsMenu'; +import { FaceRecognitionHandler } from '../../search/FaceRecognitionHandler'; interface FaceDocumentProps { faceDoc: Doc; @@ -32,17 +35,15 @@ interface FaceDocumentProps { */ @observer export class FaceDocumentItem extends ObservableReactComponent { - private ref: React.RefObject; - @observable _displayImages: boolean = true; private _dropDisposer?: DragManager.DragDropDisposer; - private _inputRef = React.createRef(); constructor(props: FaceDocumentProps) { super(props); makeObservable(this); - this.ref = React.createRef(); } + @observable _displayImages: boolean = true; + protected createDropTarget = (ele: HTMLDivElement) => { this._dropDisposer?.(); ele && (this._dropDisposer = DragManager.MakeDropTarget(ele, this.onInternalDrop.bind(this), this._props.faceDoc)); @@ -54,20 +55,20 @@ export class FaceDocumentItem extends ObservableReactComponent doc.type === DocumentType.IMG); filteredDocs.forEach(doc => { // If the current Face Document has no items, and the doc has more than one face descriptor, don't let the user add the document first. - if ((this._props.faceDoc[DocData].faceDescriptors as List>).length === 0 && (doc[DocData].faces as List>).length > 1) { + if ((this._props.faceDoc[DocData].face_descriptors as List>).length === 0 && (doc[DocData][FaceRecognitionHandler.FacesField(doc)] as List>).length > 1) { alert('Cannot add a document with multiple faces as the first item!'); } else { // Loop through the documents' face descriptors. // Choose the face with the smallest distance to add. - const float32Array = (this._props.faceDoc[DocData].faceDescriptors as List>).map(faceDescriptor => new Float32Array(Array.from(faceDescriptor))); - const labeledFaceDescriptor = new faceapi.LabeledFaceDescriptors(StrCast(this._props.faceDoc[DocData].label), float32Array); + const float32Array = (this._props.faceDoc[DocData].face_descriptors as List>).map(faceDescriptor => new Float32Array(Array.from(faceDescriptor))); + const labeledFaceDescriptor = new faceapi.LabeledFaceDescriptors(StrCast(this._props.faceDoc[DocData].face_label), float32Array); const faceDescriptors: faceapi.LabeledFaceDescriptors[] = [labeledFaceDescriptor]; const faceMatcher = new FaceMatcher(faceDescriptors, 1); let cur_lowest_distance = 1; let cur_matching_face = new List(); - (doc[DocData].faces as List>).forEach(face => { + (doc[DocData][FaceRecognitionHandler.FacesField(doc)] as List>).forEach(face => { // If the face has the current lowest distance, mark it as such // Once that lowest distance is found, add the face descriptor to the faceDoc, and add the associated doc const convered_32_array: Float32Array = new Float32Array(Array.from(face)); @@ -79,16 +80,15 @@ export class FaceDocumentItem extends ObservableReactComponent>([...(doc[DocData][`FACE DESCRIPTOR - ${this._props.faceDoc[DocData].label}`] as List>), cur_matching_face]); + const faceFieldKey = FaceRecognitionHandler.FaceField(doc, this._props.faceDoc); + if (doc[DocData][faceFieldKey]) { + Cast(doc[DocData][faceFieldKey], listSpec('number'), null).push(cur_matching_face as unknown as number); // items are lists of numbers, not numbers, but type system can't handle that } else { - doc[DocData][`FACE DESCRIPTOR - ${this._props.faceDoc[DocData].label}`] = new List>([cur_matching_face]); + doc[DocData][faceFieldKey] = new List>([cur_matching_face]); } - this._props.faceDoc[DocData].associatedDocs = new List([...DocListCast(this._props.faceDoc[DocData].associatedDocs), doc]); - this._props.faceDoc[DocData].faceDescriptors = new List>([...(this._props.faceDoc[DocData].faceDescriptors as List>), cur_matching_face]); - - //const match = faceMatcher.findBestMatch(cur_descriptor); + Doc.AddDocToList(this._props.faceDoc[DocData], 'face_docList', doc); + Cast(this._props.faceDoc[DocData].face_descriptors, listSpec('number'), null).push(cur_matching_face as unknown as number); // items are lists of numbers, not numbers, but type system can't handle that } }); return false; @@ -107,12 +107,11 @@ export class FaceDocumentItem extends ObservableReactComponent { + deleteFaceDocument = undoable(() => { if (Doc.ActiveDashboard) { - Doc.ActiveDashboard[DocData].faceDocuments = new List(DocListCast(Doc.ActiveDashboard[DocData].faceDocuments).filter(doc => doc !== this._props.faceDoc)); + Doc.RemoveDocFromList(Doc.ActiveDashboard[DocData], 'faceDocuments', this._props.faceDoc); } - }; + }, 'remove face'); /** * Deletes a document from a Face Document's associated docs list. @@ -120,60 +119,44 @@ export class FaceDocumentItem extends ObservableReactComponent { - this._props.faceDoc[DocData].faceDescriptors = new List>( - (this._props.faceDoc[DocData].faceDescriptors as List>).filter(fd => !(doc[DocData][`FACE DESCRIPTOR - ${this._props.faceDoc[DocData].label}`] as List>).includes(fd)) + this._props.faceDoc[DocData].face_descriptors = new List>( + (this._props.faceDoc[DocData].face_descriptors as List>).filter(fd => !(doc[DocData][FaceRecognitionHandler.FaceField(doc, this._props.faceDoc)] as List>).includes(fd)) ); - doc[DocData][`FACE DESCRIPTOR - ${this._props.faceDoc[DocData].label}`] = new List>(); - this._props.faceDoc[DocData].associatedDocs = new List(DocListCast(this._props.faceDoc[DocData].associatedDocs).filter(associatedDoc => associatedDoc !== doc)); + doc[DocData][FaceRecognitionHandler.FaceField(doc, this._props.faceDoc)] = new List>(); + Doc.RemoveDocFromList(this._props.faceDoc[DocData], 'face_docList', doc); }; render() { return (
this.createDropTarget(ele!)}>
- +
-

{StrCast(this._props.faceDoc[DocData].label)}

+

{StrCast(this._props.faceDoc[DocData].face_label)}

this.onDisplayClick()} - icon={this._displayImages ? : } + icon={} color={MarqueeOptionsMenu.Instance.userColor} style={{ width: '19px' }} /> {this._displayImages ? (
- {DocListCast(this._props.faceDoc[DocData].associatedDocs).map(doc => { + {DocListCast(this._props.faceDoc[DocData].face_docList).map(doc => { const [name, type] = ImageCast(doc[Doc.LayoutFieldKey(doc)]).url.href.split('.'); return (
- { - await DocumentView.showDocument(doc, { willZoomCentered: true }); - }} - style={{ maxWidth: '60px', margin: '10px' }} - src={`${name}_o.${type}`} - /> + DocumentView.showDocument(doc, { willZoomCentered: true })} style={{ maxWidth: '60px', margin: '10px' }} src={`${name}_o.${type}`} />
- { - this.deleteAssociatedDoc(doc); - }} - icon={'x'} - style={{ width: '4px' }} - size={Size.XSMALL} - /> + this.deleteAssociatedDoc(doc)} icon={'x'} style={{ width: '4px' }} size={Size.XSMALL} />
); })}
- ) : ( -
- )} + ) : null}
); } @@ -190,9 +173,8 @@ export class FaceCollectionBox extends ViewBoxBaseComponent() { @computed get currentDocs() { if (Doc.ActiveDashboard) { return DocListCast(Doc.ActiveDashboard[DocData].faceDocuments); - } else { - return []; } + return []; } constructor(props: FieldViewProps) { @@ -204,9 +186,9 @@ export class FaceCollectionBox extends ViewBoxBaseComponent() { render() { return (
- {this.currentDocs.map(doc => { - return ; - })} + {this.currentDocs.map(doc => ( + + ))}
); } diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx index d7a41df64..6fee076ee 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx @@ -1,28 +1,24 @@ -/* eslint-disable jsx-a11y/no-static-element-interactions */ -import similarity from 'compute-cosine-similarity'; import { action, computed, makeObservable, observable } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; import { ClientUtils, lightOrDark, returnFalse } from '../../../../ClientUtils'; -import { intersectRect, numberRange } from '../../../../Utils'; -import { Doc, DocListCast, NumListCast, Opt } from '../../../../fields/Doc'; +import { intersectRect } from '../../../../Utils'; +import { Doc, DocListCast, Opt } from '../../../../fields/Doc'; import { AclAdmin, AclAugment, AclEdit, DocData } from '../../../../fields/DocSymbols'; import { Id } from '../../../../fields/FieldSymbols'; -import { InkData, InkField, InkTool } from '../../../../fields/InkField'; +import { InkTool } from '../../../../fields/InkField'; import { List } from '../../../../fields/List'; -import { RichTextField } from '../../../../fields/RichTextField'; -import { Cast, FieldValue, ImageCast, NumCast, StrCast } from '../../../../fields/Types'; +import { Cast, NumCast, StrCast } from '../../../../fields/Types'; import { ImageField } from '../../../../fields/URLField'; import { GetEffectiveAcl } from '../../../../fields/util'; -import { gptGetEmbedding, gptImageLabel } from '../../../apis/gpt/GPT'; -import { CognitiveServices } from '../../../cognitive_services/CognitiveServices'; import { DocUtils } from '../../../documents/DocUtils'; -import { CollectionViewType, DocumentType } from '../../../documents/DocumentTypes'; +import { DocumentType } from '../../../documents/DocumentTypes'; import { Docs, DocumentOptions } from '../../../documents/Documents'; import { SnappingManager, freeformScrollMode } from '../../../util/SnappingManager'; import { Transform } from '../../../util/Transform'; import { UndoManager, undoBatch } from '../../../util/UndoManager'; import { ContextMenu } from '../../ContextMenu'; +import { MainView } from '../../MainView'; import { ObservableReactComponent } from '../../ObservableReactComponent'; import { MarqueeViewBounds } from '../../PinFuncs'; import { PreviewCursor } from '../../PreviewCursor'; @@ -30,15 +26,10 @@ import { DocumentView } from '../../nodes/DocumentView'; import { OpenWhere } from '../../nodes/OpenWhere'; import { pasteImageBitmap } from '../../nodes/WebBoxRenderer'; import { FormattedTextBox } from '../../nodes/formattedText/FormattedTextBox'; -import { CollectionCardView } from '../CollectionCardDeckView'; import { SubCollectionViewProps } from '../CollectionSubView'; -import { CollectionFreeFormView } from './CollectionFreeFormView'; -import { ImageLabelHandler } from './ImageLabelHandler'; +import { ImageLabelBoxData } from './ImageLabelBox'; import { MarqueeOptionsMenu } from './MarqueeOptionsMenu'; import './MarqueeView.scss'; -import { MainView } from '../../MainView'; -import { ImageLabelBox, ImageLabelBoxData } from './ImageLabelBox'; -import { SearchBox } from '../../search/SearchBox'; interface MarqueeViewProps { getContainerTransform: () => Transform; @@ -68,7 +59,7 @@ export class MarqueeView extends ObservableReactComponent { - const selected = this.marqueeSelect(false); - if (e instanceof KeyboardEvent ? e.key === 'i' : true) { - const inks = selected.filter(s => s.type === DocumentType.INK); - const setDocs = selected.filter(s => s.type === DocumentType.RTF && s.color); - const sets = setDocs.map(sd => Cast(sd.data, RichTextField)?.Text as string); - const colors = setDocs.map(sd => FieldValue(sd.color) as string); - const wordToColor = new Map(); - sets.forEach((st: string, i: number) => st.split(',').forEach(word => wordToColor.set(word, colors[i]))); - const strokes: InkData[] = []; - inks.filter(i => Cast(i.data, InkField)).forEach(i => { - const d = Cast(i.data, InkField, null); - const left = Math.min(...(d?.inkData.map(pd => pd.X) ?? [0])); - const top = Math.min(...(d?.inkData.map(pd => pd.Y) ?? [0])); - strokes.push(d.inkData.map(pd => ({ X: pd.X + NumCast(i.x) - left, Y: pd.Y + NumCast(i.y) - top }))); - }); - CognitiveServices.Inking.Appliers.InterpretStrokes(strokes).then(results => { - // const wordResults = results.filter((r: any) => r.category === "inkWord"); - // for (const word of wordResults) { - // const indices: number[] = word.strokeIds; - // indices.forEach(i => { - // if (wordToColor.has(word.recognizedText.toLowerCase())) { - // inks[i].color = wordToColor.get(word.recognizedText.toLowerCase()); - // } - // else { - // for (const alt of word.alternates) { - // if (wordToColor.has(alt.recognizedString.toLowerCase())) { - // inks[i].color = wordToColor.get(alt.recognizedString.toLowerCase()); - // break; - // } - // } - // } - // }) - // } - // const wordResults = results.filter((r: any) => r.category === "inkWord"); - // for (const word of wordResults) { - // const indices: number[] = word.strokeIds; - // indices.forEach(i => { - // const otherInks: Doc[] = []; - // indices.forEach(i2 => i2 !== i && otherInks.push(inks[i2])); - // inks[i].relatedInks = new List(otherInks); - // const uniqueColors: string[] = []; - // Array.from(wordToColor.values()).forEach(c => uniqueColors.indexOf(c) === -1 && uniqueColors.push(c)); - // inks[i].alternativeColors = new List(uniqueColors); - // if (wordToColor.has(word.recognizedText.toLowerCase())) { - // inks[i].color = wordToColor.get(word.recognizedText.toLowerCase()); - // } - // else if (word.alternates) { - // for (const alt of word.alternates) { - // if (wordToColor.has(alt.recognizedString.toLowerCase())) { - // inks[i].color = wordToColor.get(alt.recognizedString.toLowerCase()); - // break; - // } - // } - // } - // }); - // } - const lines = results.filter((r: any) => r.category === 'line'); - const text = lines.map((l: any) => l.recognizedText).join('\r\n'); - this._props.addDocument?.(Docs.Create.TextDocument(text, { _width: this.Bounds.width, _height: this.Bounds.height, x: this.Bounds.left + this.Bounds.width, y: this.Bounds.top, title: text })); - }); - } - }); - @undoBatch summary = action(() => { const selected = this.marqueeSelect(false).map(d => { @@ -704,8 +630,8 @@ export class MarqueeView extends ObservableReactComponent {' '} @@ -714,7 +640,7 @@ export class MarqueeView extends ObservableReactComponent s + pt[0] + ',' + pt[1] + ' ', '')} fill="none" - stroke={lightOrDark(this._props.Document?.backgroundColor ?? 'white')} + stroke={lightOrDark((this._props.Document?.backgroundColor as string) ?? 'white')} strokeWidth="1" strokeDasharray="3" /> @@ -753,7 +679,6 @@ export class MarqueeView extends ObservableReactComponent { diff --git a/src/client/views/nodes/FaceRectangles.tsx b/src/client/views/nodes/FaceRectangles.tsx index ade4225d9..19aa90a8b 100644 --- a/src/client/views/nodes/FaceRectangles.tsx +++ b/src/client/views/nodes/FaceRectangles.tsx @@ -4,6 +4,7 @@ import { Doc, DocListCast } from '../../../fields/Doc'; import { Id } from '../../../fields/FieldSymbols'; import { Cast, NumCast } from '../../../fields/Types'; import FaceRectangle from './FaceRectangle'; +import { FaceRecognitionHandler } from '../search/FaceRecognitionHandler'; interface FaceRectanglesProps { document: Doc; @@ -19,7 +20,7 @@ export interface RectangleTemplate { @observer export class FaceRectangles extends React.Component { render() { - const faces = DocListCast(this.props.document.faces); + const faces = DocListCast(this.props.document[FaceRecognitionHandler.FacesField(this.props.document)]); const templates: RectangleTemplate[] = faces.map(faceDoc => { const rectangle = Cast(faceDoc.faceRectangle, Doc) as Doc; const style = { diff --git a/src/client/views/search/FaceRecognitionHandler.tsx b/src/client/views/search/FaceRecognitionHandler.tsx index 29ca6e797..dc271fe73 100644 --- a/src/client/views/search/FaceRecognitionHandler.tsx +++ b/src/client/views/search/FaceRecognitionHandler.tsx @@ -1,42 +1,46 @@ import * as faceapi from 'face-api.js'; import { FaceMatcher } from 'face-api.js'; +import { computed } from 'mobx'; import { Doc, DocListCast } from '../../../fields/Doc'; import { DocData } from '../../../fields/DocSymbols'; import { List } from '../../../fields/List'; +import { listSpec } from '../../../fields/Schema'; import { Cast, ImageCast, NumCast, StrCast } from '../../../fields/Types'; -import { DocumentManager } from '../../util/DocumentManager'; -import { computed } from 'mobx'; import { DocumentType } from '../../documents/DocumentTypes'; -import { listSpec } from '../../../fields/Schema'; +import { DocumentManager } from '../../util/DocumentManager'; /** * A class that handles face recognition. */ export class FaceRecognitionHandler { static _instance: FaceRecognitionHandler; - private loadedModels: boolean = false; - @computed get examinedFaceDocs() { - return DocListCast(Doc.UserDoc().examinedFaceDocs); - } - processingDocs: Set = new Set(); - pendingLoadDocs: Doc[] = []; + private _loadedModels: boolean = false; + private _processingDocs: Set = new Set(); + private _pendingLoadDocs: Doc[] = []; + + public static FaceField = (target: Doc, doc: Doc) => `${Doc.LayoutFieldKey(target)}_${doc.face_label}`; + public static FacesField = (target: Doc) => `${Doc.LayoutFieldKey(target)}_Faces`; constructor() { FaceRecognitionHandler._instance = this; - this.loadModels().then(() => this.pendingLoadDocs.forEach(this.findMatches)); + this.loadModels().then(() => this._pendingLoadDocs.forEach(this.findMatches)); DocumentManager.Instance.AddAnyViewRenderedCB(dv => FaceRecognitionHandler.Instance.findMatches(dv.Document)); } + @computed get examinedFaceDocs() { + return DocListCast(Doc.UserDoc().examinedFaceDocs); + } + /** * Loads the face detection models. */ - async loadModels() { + loadModels = async () => { const MODEL_URL = `/models`; await faceapi.loadFaceDetectionModel(MODEL_URL); await faceapi.loadFaceLandmarkModel(MODEL_URL); await faceapi.loadFaceRecognitionModel(MODEL_URL); - this.loadedModels = true; - } + this._loadedModels = true; + }; public static get Instance() { return FaceRecognitionHandler._instance ?? new FaceRecognitionHandler(); @@ -47,8 +51,8 @@ export class FaceRecognitionHandler { * @param doc The document being analyzed. */ public findMatches = async (doc: Doc) => { - if (!this.loadedModels || !Doc.ActiveDashboard) { - this.pendingLoadDocs.push(doc); + if (!this._loadedModels || !Doc.ActiveDashboard) { + this._pendingLoadDocs.push(doc); return; } @@ -59,12 +63,12 @@ export class FaceRecognitionHandler { const imgUrl = ImageCast(doc[Doc.LayoutFieldKey(doc)]); // If the doc isn't an image or currently already been examined or is being processed, stop examining the document. - if (!imgUrl || this.examinedFaceDocs.includes(doc) || this.processingDocs.has(doc)) { + if (!imgUrl || this.examinedFaceDocs.includes(doc) || this._processingDocs.has(doc)) { return; } // Mark the document as being processed. - this.processingDocs.add(doc); + this._processingDocs.add(doc); // Get the image the document contains and analyze for faces. const [name, type] = imgUrl.url.href.split('.'); @@ -74,7 +78,7 @@ export class FaceRecognitionHandler { const fullFaceDescriptions = await faceapi.detectAllFaces(img).withFaceLandmarks().withFaceDescriptors(); - doc[DocData].faces = new List>(); + doc[DocData][FaceRecognitionHandler.FacesField(doc)] = new List>(); // For each face detected, find a match. for (const fd of fullFaceDescriptions) { @@ -84,34 +88,36 @@ export class FaceRecognitionHandler { if (match) { // If a matching Face Document has been found, add the document to the Face Document's associated docs and append the face // descriptor to the Face Document's descriptor list. - Doc.AddDocToList(match, 'associatedDocs', doc); - Cast(match.faceDescriptors, listSpec('number'), null).push(converted_list as unknown as number); // items are lists of numbers, not numbers, but type system can't handle that + Doc.AddDocToList(match, 'face_docList', doc); + Cast(match.face_descriptors, listSpec('number'), null).push(converted_list as unknown as number); // items are lists of numbers, not numbers, but type system can't handle that } else { // If a matching Face Document has not been found, create a new Face Document. Doc.UserDoc().faceDocNum = NumCast(Doc.UserDoc().faceDocNum) + 1; const newFaceDocument = new Doc(); - newFaceDocument.label = `Face ${Doc.UserDoc().faceDocNum}`; - newFaceDocument.associatedDocs = new List([doc]); - newFaceDocument.faceDescriptors = new List>([converted_list]); + newFaceDocument.title = `Face ${Doc.UserDoc().faceDocNum}`; + newFaceDocument.face = ''; // just to make prettyprinting look better + newFaceDocument.face_label = `Face${Doc.UserDoc().faceDocNum}`; + newFaceDocument.face_docList = new List([doc]); + newFaceDocument.face_descriptors = new List>([converted_list]); Doc.AddDocToList(Doc.ActiveDashboard[DocData], 'faceDocuments', newFaceDocument); match = newFaceDocument; } // Assign a field in the document of the matching Face Document. - const faceDescripField = `FACE DESCRIPTOR - ${match[DocData].label}`; + const faceDescripField = FaceRecognitionHandler.FaceField(doc, match); if (doc[DocData][faceDescripField]) { Cast(doc[DocData][faceDescripField], listSpec('number'), null).push(converted_list as unknown as number); // items are lists of numbers, not numbers, but type system can't handle that } else { doc[DocData][faceDescripField] = new List>([converted_list]); } - Cast(doc[DocData].faces, listSpec('number'), null).push(converted_list as unknown as number); // items are lists of numbers, not numbers, but type system can't handle that + Cast(doc[DocData][FaceRecognitionHandler.FacesField(doc)], listSpec('number'), null).push(converted_list as unknown as number); // items are lists of numbers, not numbers, but type system can't handle that Doc.AddDocToList(Doc.UserDoc(), 'examinedFaceDocs', doc); } - this.processingDocs.delete(doc); + this._processingDocs.delete(doc); }; /** @@ -125,14 +131,14 @@ export class FaceRecognitionHandler { } const faceDescriptors: faceapi.LabeledFaceDescriptors[] = DocListCast(Doc.ActiveDashboard[DocData].faceDocuments).map(faceDocument => { - const float32Array = (faceDocument[DocData].faceDescriptors as List>).map(faceDescriptor => new Float32Array(Array.from(faceDescriptor))); - return new faceapi.LabeledFaceDescriptors(StrCast(faceDocument[DocData].label), float32Array); + const float32Array = (faceDocument[DocData].face_descriptors as List>).map(faceDescriptor => new Float32Array(Array.from(faceDescriptor))); + return new faceapi.LabeledFaceDescriptors(StrCast(faceDocument[DocData].face_label), float32Array); }); const faceMatcher = new FaceMatcher(faceDescriptors, 0.6); const match = faceMatcher.findBestMatch(cur_descriptor); if (match.label !== 'unknown') { for (const doc of DocListCast(Doc.ActiveDashboard[DocData].faceDocuments)) { - if (doc[DocData].label === match.label) { + if (doc[DocData].face_label === match.label) { return doc; } } -- cgit v1.2.3-70-g09d2 From 69e9940f4fa24fd1ab1d9715f60b27d9e1f1221a Mon Sep 17 00:00:00 2001 From: bobzel Date: Tue, 20 Aug 2024 21:34:58 -0400 Subject: from last --- src/client/views/collections/CollectionView.tsx | 3 +-- src/client/views/nodes/ImageBox.tsx | 8 +------- 2 files changed, 2 insertions(+), 9 deletions(-) (limited to 'src') diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index 66c4896c0..ab93abab6 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -17,6 +17,7 @@ import { ViewBoxAnnotatableComponent } from '../DocComponent'; import { FieldView } from '../nodes/FieldView'; import { OpenWhere } from '../nodes/OpenWhere'; import { CollectionCalendarView } from './CollectionCalendarView'; +import { CollectionCardView } from './CollectionCardDeckView'; import { CollectionCarousel3DView } from './CollectionCarousel3DView'; import { CollectionCarouselView } from './CollectionCarouselView'; import { CollectionDockingView } from './CollectionDockingView'; @@ -33,8 +34,6 @@ import { CollectionLinearView } from './collectionLinear'; import { CollectionMulticolumnView } from './collectionMulticolumn/CollectionMulticolumnView'; import { CollectionMultirowView } from './collectionMulticolumn/CollectionMultirowView'; import { CollectionSchemaView } from './collectionSchema/CollectionSchemaView'; -import { CollectionCardView } from './CollectionCardDeckView'; -import { DocData } from '../../../fields/DocSymbols'; @observer export class CollectionView extends ViewBoxAnnotatableComponent() { diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx index 7d8a4ee49..d0a7fc6ac 100644 --- a/src/client/views/nodes/ImageBox.tsx +++ b/src/client/views/nodes/ImageBox.tsx @@ -1,6 +1,5 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { Tooltip } from '@mui/material'; -import zIndex from '@mui/material/styles/zIndex'; import { Colors } from 'browndash-components'; import { action, computed, IReactionDisposer, makeObservable, observable, ObservableMap, reaction } from 'mobx'; import { observer } from 'mobx-react'; @@ -11,7 +10,6 @@ import { Doc, DocListCast, Opt } from '../../../fields/Doc'; import { DocData } from '../../../fields/DocSymbols'; import { Id } from '../../../fields/FieldSymbols'; import { InkTool } from '../../../fields/InkField'; -import { List } from '../../../fields/List'; import { ObjectField } from '../../../fields/ObjectField'; import { Cast, ImageCast, NumCast, StrCast } from '../../../fields/Types'; import { ImageField } from '../../../fields/URLField'; @@ -22,6 +20,7 @@ import { DocumentType } from '../../documents/DocumentTypes'; import { DocUtils } from '../../documents/DocUtils'; import { Networking } from '../../Network'; import { DragManager } from '../../util/DragManager'; +import { SnappingManager } from '../../util/SnappingManager'; import { undoBatch } from '../../util/UndoManager'; import { CollectionFreeFormView } from '../collections/collectionFreeForm/CollectionFreeFormView'; import { ContextMenu } from '../ContextMenu'; @@ -37,7 +36,6 @@ import { FieldView, FieldViewProps } from './FieldView'; import { FocusViewOptions } from './FocusViewOptions'; import './ImageBox.scss'; import { OpenWhere } from './OpenWhere'; -import { SnappingManager } from '../../util/SnappingManager'; export class ImageEditorData { // eslint-disable-next-line no-use-before-define @@ -176,10 +174,6 @@ export class ImageBox extends ViewBoxAnnotatableComponent() { Doc.SetNativeHeight(this.dataDoc, Doc.NativeHeight(targetDoc), this.fieldKey); } } - const layoutDoc = de.complete.docDragData?.draggedDocuments[0]; - const targetField = Doc.LayoutFieldKey(layoutDoc); - const targetDoc = layoutDoc[DocData]; - console.log(targetDoc[targetField]); added === false && e.preventDefault(); added !== undefined && e.stopPropagation(); return added; -- cgit v1.2.3-70-g09d2 From d5ae46421b34d688817e059257578906ff2f12a9 Mon Sep 17 00:00:00 2001 From: bobzel Date: Tue, 20 Aug 2024 21:46:56 -0400 Subject: fixing lint errors --- .../collectionFreeForm/MarqueeOptionsMenu.tsx | 4 ++-- .../views/collections/collectionFreeForm/MarqueeView.tsx | 16 ++++++++++------ src/server/server_Initialization.ts | 9 +++++++++ 3 files changed, 21 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/client/views/collections/collectionFreeForm/MarqueeOptionsMenu.tsx b/src/client/views/collections/collectionFreeForm/MarqueeOptionsMenu.tsx index b94a22d04..44c916ab9 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeOptionsMenu.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeOptionsMenu.tsx @@ -18,10 +18,10 @@ export class MarqueeOptionsMenu extends AntimodeMenu { public showMarquee: () => void = unimplementedFunction; public hideMarquee: () => void = unimplementedFunction; public pinWithView: (e: KeyboardEvent | React.PointerEvent | undefined) => void = unimplementedFunction; - public classifyImages: (e: React.MouseEvent | undefined) => void = unimplementedFunction; + public classifyImages: () => void = unimplementedFunction; public groupImages: () => void = unimplementedFunction; public isShown = () => this._opacity > 0; - constructor(props: any) { + constructor(props: AntimodeMenuProps) { super(props); makeObservable(this); MarqueeOptionsMenu.Instance = this; diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx index 6fee076ee..6cc75aa4b 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx @@ -156,6 +156,7 @@ export class MarqueeView extends ObservableReactComponent + // eslint-disable-next-line @typescript-eslint/no-explicit-any pasteImageBitmap((data: any, error: any) => { error && console.log(error); data && @@ -432,7 +433,7 @@ export class MarqueeView extends ObservableReactComponent { + classifyImages = action(async () => { const groupButton = DocListCast(Doc.MyLeftSidebarMenu.data).find(d => d.target === Doc.MyImageGrouper); if (groupButton) { this._selectedDocs = this.marqueeSelect(false, DocumentType.IMG); @@ -515,13 +516,14 @@ export class MarqueeView extends ObservableReactComponent { - if (this._commandExecuted || (e as any).propagationIsStopped) { + const ee = e as unknown as KeyboardEvent & { propagationIsStopped?: boolean }; + if (this._commandExecuted || ee.propagationIsStopped) { return; } if (e.key === 'Backspace' || e.key === 'Delete' || e.key === 'd' || e.key === 'h') { this._commandExecuted = true; e.stopPropagation(); - (e as any).propagationIsStopped = true; + ee.propagationIsStopped = true; this.delete(e, e.key === 'h'); e.stopPropagation(); } @@ -529,7 +531,7 @@ export class MarqueeView extends ObservableReactComponent) => { - if ((e as any).handlePan || this._props.isAnnotationOverlay) return; - (e as any).handlePan = true; + const ee = e as CustomEvent & { handlePan?: boolean }; + if (ee.handlePan || this._props.isAnnotationOverlay) return; + ee.handlePan = true; const bounds = this.MarqueeRef?.getBoundingClientRect(); if (!this._props.Document._freeform_noAutoPan && !this._props.renderDepth && bounds) { @@ -682,6 +685,7 @@ export class MarqueeView extends ObservableReactComponent { + // eslint-disable-next-line @typescript-eslint/no-explicit-any r?.addEventListener('dashDragMovePause', this.onDragMovePause as any); this.MarqueeRef = r; }} diff --git a/src/server/server_Initialization.ts b/src/server/server_Initialization.ts index 2190e27c7..8d3afc3ad 100644 --- a/src/server/server_Initialization.ts +++ b/src/server/server_Initialization.ts @@ -113,6 +113,7 @@ function registerEmbeddedBrowseRelativePathHandler(server: express.Express) { }); } +// eslint-disable-next-line @typescript-eslint/no-explicit-any function proxyServe(req: any, requrl: string, response: any) { // eslint-disable-next-line global-require, @typescript-eslint/no-var-requires const htmlBodyMemoryStream = new (require('memorystream'))(); @@ -137,8 +138,10 @@ function proxyServe(req: any, requrl: string, response: any) { response.send(header?.includes('gzip') ? zlib.gzipSync(htmlText) : htmlText); } else { req.pipe(request(requrl)) + // eslint-disable-next-line @typescript-eslint/no-explicit-any .on('error', (e: any) => console.log('requrl ', e)) .pipe(response) + // eslint-disable-next-line @typescript-eslint/no-explicit-any .on('error', (e: any) => console.log('response pipe error', e)); console.log('EMPTY body:' + req.url); } @@ -147,14 +150,17 @@ function proxyServe(req: any, requrl: string, response: any) { } } else { req.pipe(htmlBodyMemoryStream) + // eslint-disable-next-line @typescript-eslint/no-explicit-any .on('error', (e: any) => console.log('html body memorystream error', e)) .pipe(response) + // eslint-disable-next-line @typescript-eslint/no-explicit-any .on('error', (e: any) => console.log('html body memory stream response error', e)); } }; const retrieveHTTPBody = () => { // req.headers.cookie = ''; req.pipe(request(requrl)) + // eslint-disable-next-line @typescript-eslint/no-explicit-any .on('error', (e: any) => { console.log(`CORS url error: ${requrl}`, e); response.send(` @@ -163,6 +169,7 @@ function proxyServe(req: any, requrl: string, response: any) {

${e}

`); }) + // eslint-disable-next-line @typescript-eslint/no-explicit-any .on('response', (res: any) => { res.headers; const headers = Object.keys(res.headers); @@ -187,6 +194,7 @@ function proxyServe(req: any, requrl: string, response: any) { }) .on('end', sendModifiedBody) .pipe(htmlBodyMemoryStream) + // eslint-disable-next-line @typescript-eslint/no-explicit-any .on('error', (e: any) => console.log('http body pipe error', e)); }; retrieveHTTPBody(); @@ -244,6 +252,7 @@ export default async function InitializeServer(routeSetter: RouteSetter) { app.use(whm(compiler)); app.get(/^\/+$/, (req, res) => res.redirect(req.user ? '/home' : '/login')); // target urls that consist of one or more '/'s with nothing in between app.use(express.static(publicDirectory, { setHeaders: res => res.setHeader('Access-Control-Allow-Origin', '*') })); // all urls that start with dash's public directory: /files/ (e.g., /files/images, /files/audio, etc) + // eslint-disable-next-line @typescript-eslint/no-explicit-any app.use(cors({ origin: (_origin: any, callback: any) => callback(null, true) })); registerAuthenticationRoutes(app); // this adds routes to authenticate a user (login, etc) registerCorsProxy(app); // this adds a /corsProxy/ route to allow clients to get to urls that would otherwise be blocked by cors policies -- cgit v1.2.3-70-g09d2 From 19a947cbd253ff7fb9da88c27af7645219446d0a Mon Sep 17 00:00:00 2001 From: bobzel Date: Tue, 20 Aug 2024 22:02:54 -0400 Subject: from last --- .eslintrc.json | 2 +- src/client/documents/DocUtils.ts | 2 +- src/client/views/nodes/FaceRectangle.tsx | 34 ---------------------- src/client/views/nodes/FaceRectangles.tsx | 47 ------------------------------- src/server/server_Initialization.ts | 2 +- 5 files changed, 3 insertions(+), 84 deletions(-) delete mode 100644 src/client/views/nodes/FaceRectangle.tsx delete mode 100644 src/client/views/nodes/FaceRectangles.tsx (limited to 'src') diff --git a/.eslintrc.json b/.eslintrc.json index 6202561d5..d4f43f04c 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -40,6 +40,7 @@ "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", @@ -54,7 +55,6 @@ "no-unused-vars": "off", "@typescript-eslint/no-unused-vars": "error", "@typescript-eslint/no-namespace": 0, - "@typescript-eslint/no-unused-expressions": "off", "react/destructuring-assignment": 0, "no-restricted-globals": ["error", "event"], "no-param-reassign": ["error", { "props": false }], diff --git a/src/client/documents/DocUtils.ts b/src/client/documents/DocUtils.ts index 35d835f1f..0168e0a3b 100644 --- a/src/client/documents/DocUtils.ts +++ b/src/client/documents/DocUtils.ts @@ -35,7 +35,7 @@ import { TaskCompletionBox } from '../views/nodes/TaskCompletedBox'; import { DocumentType } from './DocumentTypes'; import { Docs, DocumentOptions } from './Documents'; -// eslint-disable-next-line @typescript-eslint/no-var-requires +// eslint-disable-next-line @typescript-eslint/no-var-requires, @typescript-eslint/no-require-imports const { DFLT_IMAGE_NATIVE_DIM } = require('../views/global/globalCssVariables.module.scss'); // prettier-ignore const defaultNativeImageDim = Number(DFLT_IMAGE_NATIVE_DIM.replace('px', '')); diff --git a/src/client/views/nodes/FaceRectangle.tsx b/src/client/views/nodes/FaceRectangle.tsx deleted file mode 100644 index 2b66b83fe..000000000 --- a/src/client/views/nodes/FaceRectangle.tsx +++ /dev/null @@ -1,34 +0,0 @@ -import { observable, runInAction } from 'mobx'; -import { observer } from 'mobx-react'; -import * as React from 'react'; -import { RectangleTemplate } from './FaceRectangles'; - -@observer -export default class FaceRectangle extends React.Component<{ rectangle: RectangleTemplate }> { - @observable private opacity = 0; - - componentDidMount() { - setTimeout( - () => - runInAction(() => { - this.opacity = 1; - }), - 500 - ); - } - - render() { - const { rectangle } = this.props; - return ( -
- ); - } -} diff --git a/src/client/views/nodes/FaceRectangles.tsx b/src/client/views/nodes/FaceRectangles.tsx deleted file mode 100644 index 19aa90a8b..000000000 --- a/src/client/views/nodes/FaceRectangles.tsx +++ /dev/null @@ -1,47 +0,0 @@ -import { observer } from 'mobx-react'; -import * as React from 'react'; -import { Doc, DocListCast } from '../../../fields/Doc'; -import { Id } from '../../../fields/FieldSymbols'; -import { Cast, NumCast } from '../../../fields/Types'; -import FaceRectangle from './FaceRectangle'; -import { FaceRecognitionHandler } from '../search/FaceRecognitionHandler'; - -interface FaceRectanglesProps { - document: Doc; - color: string; - backgroundColor: string; -} - -export interface RectangleTemplate { - id: string; - style: Partial; -} - -@observer -export class FaceRectangles extends React.Component { - render() { - const faces = DocListCast(this.props.document[FaceRecognitionHandler.FacesField(this.props.document)]); - const templates: RectangleTemplate[] = faces.map(faceDoc => { - const rectangle = Cast(faceDoc.faceRectangle, Doc) as Doc; - const style = { - top: NumCast(rectangle.top), - left: NumCast(rectangle.left), - width: NumCast(rectangle.width), - height: NumCast(rectangle.height), - backgroundColor: `${this.props.backgroundColor}33`, - border: `solid 2px ${this.props.color}`, - } as React.CSSProperties; - return { - id: rectangle[Id], - style: style, - }; - }); - return ( -
- {templates.map(rectangle => ( - - ))} -
- ); - } -} diff --git a/src/server/server_Initialization.ts b/src/server/server_Initialization.ts index 8d3afc3ad..97c63a93e 100644 --- a/src/server/server_Initialization.ts +++ b/src/server/server_Initialization.ts @@ -115,7 +115,7 @@ function registerEmbeddedBrowseRelativePathHandler(server: express.Express) { // eslint-disable-next-line @typescript-eslint/no-explicit-any function proxyServe(req: any, requrl: string, response: any) { - // eslint-disable-next-line global-require, @typescript-eslint/no-var-requires + // eslint-disable-next-line global-require, @typescript-eslint/no-require-imports const htmlBodyMemoryStream = new (require('memorystream'))(); let wasinBrFormat = false; const sendModifiedBody = () => { -- cgit v1.2.3-70-g09d2 From 166d40bd856b85bd4bbde9f9ffe2c1ec0fb648d5 Mon Sep 17 00:00:00 2001 From: bobzel Date: Wed, 21 Aug 2024 10:57:53 -0400 Subject: more lint fixes after update --- eslint.config.mjs | 45 ++++++++++++++++++++++++- package-lock.json | 46 ++++++++++---------------- src/ClientUtils.ts | 1 - src/ServerUtils.ts | 1 - src/client/Network.ts | 2 +- src/client/documents/DocUtils.ts | 3 +- src/client/documents/Documents.ts | 4 +-- src/client/util/DictationManager.ts | 4 --- src/client/util/DragManager.ts | 1 - src/client/util/History.ts | 1 - src/client/util/InteractionUtils.tsx | 1 - src/client/util/ScriptingGlobals.ts | 2 +- src/client/util/SearchUtil.ts | 1 - src/client/util/SerializationHelper.ts | 1 - src/client/util/UndoManager.ts | 1 - src/client/views/DocViewUtils.ts | 1 - src/pen-gestures/GestureUtils.ts | 1 - src/server/DashStats.ts | 2 +- src/server/DashUploadUtils.ts | 1 - src/server/Message.ts | 1 - src/server/Search.ts | 1 - src/server/SharedMediaTypes.ts | 2 -- src/server/apis/google/GoogleApiServerUtils.ts | 2 +- src/server/server_Initialization.ts | 9 +++++ src/server/websocket.ts | 1 - 25 files changed, 77 insertions(+), 58 deletions(-) (limited to 'src') diff --git a/eslint.config.mjs b/eslint.config.mjs index b35601abd..04655ce13 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -3,4 +3,47 @@ import pluginReactConfig from 'eslint-plugin-react/configs/recommended.js'; import globals from 'globals'; import tseslint from 'typescript-eslint'; -export default [{ languageOptions: { globals: { ...globals.browser, ...globals.node } } }, pluginJs.configs.recommended, ...tseslint.configs.recommended, pluginReactConfig]; +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', + 'prefer-template': 'off', + 'no-inner-declarations': 'off', + 'no-plusplus': 'off', + 'no-multi-assign': 'off', + 'no-underscore-dangle': 'off', + 'no-nested-ternary': 'off', + '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, + 'no-restricted-globals': ['error', 'event'], + }, + }, + pluginReactConfig, +]; diff --git a/package-lock.json b/package-lock.json index 41922228a..565463980 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2423,14 +2423,14 @@ "integrity": "sha512-30FAj7/EoJ5mwVPOWhAyCX+FPfMDrVecJAM+Iw9NRoSl4BBAQeqj4cApHHUXOVvIPgLVDsCFoz/hGD+5QQD1GQ==" }, "node_modules/@emotion/react": { - "version": "11.13.0", - "resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.13.0.tgz", - "integrity": "sha512-WkL+bw1REC2VNV1goQyfxjx1GYJkcc23CRQkXX+vZNLINyfI7o+uUn/rTGPt/xJ3bJHd5GcljgnxHf4wRw5VWQ==", + "version": "11.13.3", + "resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.13.3.tgz", + "integrity": "sha512-lIsdU6JNrmYfJ5EbUCf4xW1ovy5wKQ2CkPRM4xogziOxH1nXxBSjpC9YqbFAP7circxMfYp+6x676BqWcEiixg==", "dependencies": { "@babel/runtime": "^7.18.3", "@emotion/babel-plugin": "^11.12.0", "@emotion/cache": "^11.13.0", - "@emotion/serialize": "^1.3.0", + "@emotion/serialize": "^1.3.1", "@emotion/use-insertion-effect-with-fallbacks": "^1.1.0", "@emotion/utils": "^1.4.0", "@emotion/weak-memoize": "^0.4.0", @@ -2446,13 +2446,13 @@ } }, "node_modules/@emotion/serialize": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-1.3.0.tgz", - "integrity": "sha512-jACuBa9SlYajnpIVXB+XOXnfJHyckDfe6fOpORIM6yhBDlqGuExvDdZYHDQGoDf3bZXGv7tNr+LpLjJqiEQ6EA==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-1.3.1.tgz", + "integrity": "sha512-dEPNKzBPU+vFPGa+z3axPRn8XVDetYORmDC0wAiej+TNcOZE70ZMJa0X7JdeoM6q/nWTMZeLpN/fTnD9o8MQBA==", "dependencies": { "@emotion/hash": "^0.9.2", "@emotion/memoize": "^0.9.0", - "@emotion/unitless": "^0.9.0", + "@emotion/unitless": "^0.10.0", "@emotion/utils": "^1.4.0", "csstype": "^3.0.2" } @@ -2491,9 +2491,9 @@ "peer": true }, "node_modules/@emotion/unitless": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.9.0.tgz", - "integrity": "sha512-TP6GgNZtmtFaFcsOgExdnfxLLpRDla4Q66tnenA9CktvVSdNKDvMVuUah4QvWPIpNjrWsGg3qeGo9a43QooGZQ==" + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.10.0.tgz", + "integrity": "sha512-dFoMUuQA20zvtVTuxZww6OHoJYgrzfKM1t52mVySDJnMSEa08ruEvdYQbhvyu6soU+NeLVd3yKfTfT0NeV6qGg==" }, "node_modules/@emotion/use-insertion-effect-with-fallbacks": { "version": "1.1.0", @@ -17245,9 +17245,9 @@ "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" }, "node_modules/electron-to-chromium": { - "version": "1.5.12", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.12.tgz", - "integrity": "sha512-tIhPkdlEoCL1Y+PToq3zRNehUaKp3wBX/sr7aclAWdIWjvqAe/Im/H0SiCM4c1Q8BLPHCdoJTol+ZblflydehA==" + "version": "1.5.13", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.13.tgz", + "integrity": "sha512-lbBcvtIJ4J6sS4tb5TLp1b4LyfCdMkwStzXPyAgVgTRAsep4bvrAGaBOP7ZJtQMNJpSQ9SqG4brWOroNaQtm7Q==" }, "node_modules/elkjs": { "version": "0.9.3", @@ -20304,14 +20304,6 @@ "node": ">= 12.20" } }, - "node_modules/formdata-node/node_modules/web-streams-polyfill": { - "version": "4.0.0-beta.3", - "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-4.0.0-beta.3.tgz", - "integrity": "sha512-QW95TCTaHmsYfHDybGMwO5IJIM93I/6vTRk+daHTWFPhwh+C8Cg7j7XyKrwrj8Ib6vYXe0ocYNrmzY4xAAN6ug==", - "engines": { - "node": ">= 14" - } - }, "node_modules/formidable": { "version": "3.5.1", "resolved": "https://registry.npmjs.org/formidable/-/formidable-3.5.1.tgz", @@ -41328,13 +41320,11 @@ } }, "node_modules/web-streams-polyfill": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-4.0.0.tgz", - "integrity": "sha512-0zJXHRAYEjM2tUfZ2DiSOHAa2aw1tisnnhU3ufD57R8iefL+DcdJyRBRyJpG+NUimDgbTI/lH+gAE1PAvV3Cgw==", - "optional": true, - "peer": true, + "version": "4.0.0-beta.3", + "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-4.0.0-beta.3.tgz", + "integrity": "sha512-QW95TCTaHmsYfHDybGMwO5IJIM93I/6vTRk+daHTWFPhwh+C8Cg7j7XyKrwrj8Ib6vYXe0ocYNrmzY4xAAN6ug==", "engines": { - "node": ">= 8" + "node": ">= 14" } }, "node_modules/web-worker": { diff --git a/src/ClientUtils.ts b/src/ClientUtils.ts index fc048b155..55801df81 100644 --- a/src/ClientUtils.ts +++ b/src/ClientUtils.ts @@ -82,7 +82,6 @@ export function returnEmptyFilter() { return [] as string[]; } -// eslint-disable-next-line @typescript-eslint/no-namespace export namespace ClientUtils { export const CLICK_TIME = 300; export const DRAG_THRESHOLD = 4; diff --git a/src/ServerUtils.ts b/src/ServerUtils.ts index 8b2d0b9f6..715341ab3 100644 --- a/src/ServerUtils.ts +++ b/src/ServerUtils.ts @@ -2,7 +2,6 @@ import { Socket } from 'socket.io'; import { Message } from './server/Message'; import { Utils } from './Utils'; -// eslint-disable-next-line @typescript-eslint/no-namespace export namespace ServerUtils { export function Emit(socket: Socket, message: Message, args: T) { Utils.log('Emit', message.Name, args, false); diff --git a/src/client/Network.ts b/src/client/Network.ts index 8876d8190..6c60c4151 100644 --- a/src/client/Network.ts +++ b/src/client/Network.ts @@ -8,7 +8,7 @@ import { Upload } from '../server/SharedMediaTypes'; * mainly provides methods that the client can use to begin the process of * interacting with the server, such as fetching or uploading files. */ -// eslint-disable-next-line @typescript-eslint/no-namespace + export namespace Networking { export async function FetchFromServer(relativeRoute: string) { return (await fetch(relativeRoute)).text(); diff --git a/src/client/documents/DocUtils.ts b/src/client/documents/DocUtils.ts index a503d732b..5ee7d0f9c 100644 --- a/src/client/documents/DocUtils.ts +++ b/src/client/documents/DocUtils.ts @@ -40,7 +40,6 @@ const { DFLT_IMAGE_NATIVE_DIM } = require('../views/global/globalCssVariables.mo const defaultNativeImageDim = Number(DFLT_IMAGE_NATIVE_DIM.replace('px', '')); -// eslint-disable-next-line @typescript-eslint/no-namespace export namespace DocUtils { function matchFieldValue(doc: Doc, key: string, valueIn: unknown): boolean { let value = valueIn; @@ -467,7 +466,7 @@ export namespace DocUtils { .concat(userTypes) .concat(clickFuncs) .map(btnDoc => (btnDoc.dragFactory as Doc) || btnDoc) - .filter(doc => doc.isTemplateDoc); + .filter(d => d.isTemplateDoc); // bcz: this is hacky -- want to have different templates be applied depending on the "type" of a document. but type is not reliable and there could be other types of template searches so this should be generalized // first try to find a template that matches the specific document type (_). otherwise, fallback to a general match on !docLayoutTemplate && diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index b108b73db..41c6ce39b 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -487,9 +487,7 @@ export class DocumentOptions { export const DocOptions = new DocumentOptions(); -// eslint-disable-next-line @typescript-eslint/no-namespace export namespace Docs { - // eslint-disable-next-line @typescript-eslint/no-namespace export namespace Prototypes { type LayoutSource = { LayoutString: (key: string) => string }; type PrototypeTemplate = { @@ -647,7 +645,7 @@ export namespace Docs { * Encapsulates the factory used to create new document instances * delegated from top-level prototypes */ - // eslint-disable-next-line @typescript-eslint/no-namespace + export namespace Create { /** * This function receives the relevant document prototype and uses diff --git a/src/client/util/DictationManager.ts b/src/client/util/DictationManager.ts index 16a0df120..a0e1413b6 100644 --- a/src/client/util/DictationManager.ts +++ b/src/client/util/DictationManager.ts @@ -32,14 +32,12 @@ import { UndoManager } from './UndoManager'; * to add new commands as classes or components are constructed. */ -// eslint-disable-next-line @typescript-eslint/no-namespace export namespace DictationManager { /** * Some type maneuvering to access Webkit's built-in * speech recognizer. */ - // eslint-disable-next-line @typescript-eslint/no-namespace namespace CORE { export interface IWindow extends Window { webkitSpeechRecognition: { new (): SpeechRecognition }; @@ -48,7 +46,6 @@ export namespace DictationManager { const { webkitSpeechRecognition }: CORE.IWindow = window as unknown as CORE.IWindow; export const placeholder = 'Listening...'; - // eslint-disable-next-line @typescript-eslint/no-namespace export namespace Controls { export const Infringed = 'unable to process: dictation manager still involved in previous session'; const browser = (() => { @@ -230,7 +227,6 @@ export namespace DictationManager { }; } - // eslint-disable-next-line @typescript-eslint/no-namespace export namespace Commands { export const dictationFadeDuration = 2000; diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts index c237a75de..7db13689d 100644 --- a/src/client/util/DragManager.ts +++ b/src/client/util/DragManager.ts @@ -70,7 +70,6 @@ export function SetupDrag(_reference: React.RefObject, docFunc: () return onItemDown; } -// eslint-disable-next-line @typescript-eslint/no-namespace export namespace DragManager { export const dragClassName = 'collectionFreeFormDocumentView-container'; let dragDiv: HTMLDivElement; diff --git a/src/client/util/History.ts b/src/client/util/History.ts index 067c28c6b..0d0c056a4 100644 --- a/src/client/util/History.ts +++ b/src/client/util/History.ts @@ -10,7 +10,6 @@ import { OmitKeys, ClientUtils } from '../../ClientUtils'; import { DocServer } from '../DocServer'; import { DashboardView } from '../views/DashboardView'; -// eslint-disable-next-line @typescript-eslint/no-namespace export namespace HistoryUtil { export interface DocInitializerList { [key: string]: string | number; diff --git a/src/client/util/InteractionUtils.tsx b/src/client/util/InteractionUtils.tsx index f3ede596d..4231c2ca8 100644 --- a/src/client/util/InteractionUtils.tsx +++ b/src/client/util/InteractionUtils.tsx @@ -4,7 +4,6 @@ import { Utils } from '../../Utils'; import { Gestures } from '../../pen-gestures/GestureTypes'; import './InteractionUtils.scss'; -// eslint-disable-next-line @typescript-eslint/no-namespace export namespace InteractionUtils { export const MOUSETYPE = 'mouse'; export const TOUCHTYPE = 'touch'; diff --git a/src/client/util/ScriptingGlobals.ts b/src/client/util/ScriptingGlobals.ts index 4a1a70633..444e8fc0a 100644 --- a/src/client/util/ScriptingGlobals.ts +++ b/src/client/util/ScriptingGlobals.ts @@ -6,7 +6,7 @@ const _scriptingGlobals: { [name: string]: unknown } = {}; const _scriptingDescriptions: { [name: string]: string } = {}; const _scriptingParams: { [name: string]: string } = {}; export let scriptingGlobals: { [name: string]: unknown } = _scriptingGlobals; -// eslint-disable-next-line @typescript-eslint/no-namespace + export namespace ScriptingGlobals { export function getGlobals() { return Object.keys(_scriptingGlobals); } // prettier-ignore export function getGlobalObj() { return _scriptingGlobals; } // prettier-ignore diff --git a/src/client/util/SearchUtil.ts b/src/client/util/SearchUtil.ts index 6cad7060b..733eae5f4 100644 --- a/src/client/util/SearchUtil.ts +++ b/src/client/util/SearchUtil.ts @@ -5,7 +5,6 @@ import { StrCast } from '../../fields/Types'; import { DocumentType } from '../documents/DocumentTypes'; import { DocOptions, FInfo } from '../documents/Documents'; -// eslint-disable-next-line @typescript-eslint/no-namespace export namespace SearchUtil { export type HighlightingResult = { [id: string]: { [key: string]: string[] } }; diff --git a/src/client/util/SerializationHelper.ts b/src/client/util/SerializationHelper.ts index 0386b2455..ccb02fb79 100644 --- a/src/client/util/SerializationHelper.ts +++ b/src/client/util/SerializationHelper.ts @@ -12,7 +12,6 @@ export function afterDocDeserialize(cb: (err: unknown, val: unknown) => void, er const serializationTypes: { [name: string]: { ctor: { new (): unknown }; afterDeserialize?: (obj: unknown) => void | Promise } } = {}; const reverseMap: { [ctor: string]: string } = {}; -// eslint-disable-next-line @typescript-eslint/no-namespace export namespace SerializationHelper { export function IsSerializing() { return serializing > 0; diff --git a/src/client/util/UndoManager.ts b/src/client/util/UndoManager.ts index 5fd935370..ce0e7768b 100644 --- a/src/client/util/UndoManager.ts +++ b/src/client/util/UndoManager.ts @@ -83,7 +83,6 @@ export function undoBatch(target: any, key?: string | symbol, descriptor?: Typed return descriptor; } -// eslint-disable-next-line @typescript-eslint/no-namespace export namespace UndoManager { export interface UndoEvent { undo: () => void; diff --git a/src/client/views/DocViewUtils.ts b/src/client/views/DocViewUtils.ts index 49a30aa08..1f5f29c7e 100644 --- a/src/client/views/DocViewUtils.ts +++ b/src/client/views/DocViewUtils.ts @@ -6,7 +6,6 @@ import { Doc, SetActiveAudioLinker } from '../../fields/Doc'; import { DocUtils } from '../documents/DocUtils'; import { FieldViewProps } from './nodes/FieldView'; -// eslint-disable-next-line @typescript-eslint/no-namespace export namespace DocViewUtils { export const ActiveRecordings: { props: FieldViewProps; getAnchor: (addAsAnnotation: boolean) => Doc }[] = []; diff --git a/src/pen-gestures/GestureUtils.ts b/src/pen-gestures/GestureUtils.ts index bf5475042..c7051c87c 100644 --- a/src/pen-gestures/GestureUtils.ts +++ b/src/pen-gestures/GestureUtils.ts @@ -2,7 +2,6 @@ import { Rect } from 'react-measure'; import { Gestures, PointData } from './GestureTypes'; import { NDollarRecognizer } from './ndollar'; -// eslint-disable-next-line @typescript-eslint/no-namespace export namespace GestureUtils { export class GestureEvent { readonly gesture: Gestures; diff --git a/src/server/DashStats.ts b/src/server/DashStats.ts index 6b9fb8971..8e1d4661f 100644 --- a/src/server/DashStats.ts +++ b/src/server/DashStats.ts @@ -9,7 +9,7 @@ import { socketMap, timeMap, userOperations } from './SocketData'; * This includes time connected, number of operations, and * the rate of their operations */ -// eslint-disable-next-line @typescript-eslint/no-namespace + export namespace DashStats { export const SAMPLING_INTERVAL = 1000; // in milliseconds (ms) - Time interval to update the frontend. export const RATE_INTERVAL = 10; // in seconds (s) - Used to calculate rate diff --git a/src/server/DashUploadUtils.ts b/src/server/DashUploadUtils.ts index 5e58db103..8f012f783 100644 --- a/src/server/DashUploadUtils.ts +++ b/src/server/DashUploadUtils.ts @@ -47,7 +47,6 @@ function usingAzure() { return process.env.USE_AZURE === 'true'; } -// eslint-disable-next-line @typescript-eslint/no-namespace export namespace DashUploadUtils { export interface Size { width: number; diff --git a/src/server/Message.ts b/src/server/Message.ts index b904a5ba3..01a42fc68 100644 --- a/src/server/Message.ts +++ b/src/server/Message.ts @@ -43,7 +43,6 @@ export interface RoomMessage { readonly room: string; } -// eslint-disable-next-line @typescript-eslint/no-namespace export namespace MessageStore { export const Foo = new Message('Foo'); export const Bar = new Message('Bar'); diff --git a/src/server/Search.ts b/src/server/Search.ts index 06af18776..b21ee853a 100644 --- a/src/server/Search.ts +++ b/src/server/Search.ts @@ -3,7 +3,6 @@ import * as rp from 'request-promise'; const pathTo = (relative: string) => `http://localhost:8983/solr/dash/${relative}`; -// eslint-disable-next-line @typescript-eslint/no-namespace export namespace Search { export async function updateDocument(document: any) { try { diff --git a/src/server/SharedMediaTypes.ts b/src/server/SharedMediaTypes.ts index 680db9cd0..9aa4b120f 100644 --- a/src/server/SharedMediaTypes.ts +++ b/src/server/SharedMediaTypes.ts @@ -1,7 +1,6 @@ import { ExifData } from 'exif'; import { File } from 'formidable'; -// eslint-disable-next-line @typescript-eslint/no-namespace export namespace AcceptableMedia { export const gifs = ['.gif']; export const pngs = ['.png']; @@ -19,7 +18,6 @@ export enum AudioAnnoState { playing = 'playing', } -// eslint-disable-next-line @typescript-eslint/no-namespace export namespace Upload { export function isImageInformation(uploadResponse: Upload.FileInformation): uploadResponse is Upload.ImageInformation { return 'nativeWidth' in uploadResponse; diff --git a/src/server/apis/google/GoogleApiServerUtils.ts b/src/server/apis/google/GoogleApiServerUtils.ts index 47206f415..21c405bee 100644 --- a/src/server/apis/google/GoogleApiServerUtils.ts +++ b/src/server/apis/google/GoogleApiServerUtils.ts @@ -21,7 +21,7 @@ const scope = ['documents.readonly', 'documents', 'presentations', 'presentation * This namespace manages server side authentication for Google API queries, either * from the standard v1 APIs or the Google Photos REST API. */ -// eslint-disable-next-line @typescript-eslint/no-namespace + export namespace GoogleApiServerUtils { /** * As we expand out to more Google APIs that are accessible from diff --git a/src/server/server_Initialization.ts b/src/server/server_Initialization.ts index 2190e27c7..8d3afc3ad 100644 --- a/src/server/server_Initialization.ts +++ b/src/server/server_Initialization.ts @@ -113,6 +113,7 @@ function registerEmbeddedBrowseRelativePathHandler(server: express.Express) { }); } +// eslint-disable-next-line @typescript-eslint/no-explicit-any function proxyServe(req: any, requrl: string, response: any) { // eslint-disable-next-line global-require, @typescript-eslint/no-var-requires const htmlBodyMemoryStream = new (require('memorystream'))(); @@ -137,8 +138,10 @@ function proxyServe(req: any, requrl: string, response: any) { response.send(header?.includes('gzip') ? zlib.gzipSync(htmlText) : htmlText); } else { req.pipe(request(requrl)) + // eslint-disable-next-line @typescript-eslint/no-explicit-any .on('error', (e: any) => console.log('requrl ', e)) .pipe(response) + // eslint-disable-next-line @typescript-eslint/no-explicit-any .on('error', (e: any) => console.log('response pipe error', e)); console.log('EMPTY body:' + req.url); } @@ -147,14 +150,17 @@ function proxyServe(req: any, requrl: string, response: any) { } } else { req.pipe(htmlBodyMemoryStream) + // eslint-disable-next-line @typescript-eslint/no-explicit-any .on('error', (e: any) => console.log('html body memorystream error', e)) .pipe(response) + // eslint-disable-next-line @typescript-eslint/no-explicit-any .on('error', (e: any) => console.log('html body memory stream response error', e)); } }; const retrieveHTTPBody = () => { // req.headers.cookie = ''; req.pipe(request(requrl)) + // eslint-disable-next-line @typescript-eslint/no-explicit-any .on('error', (e: any) => { console.log(`CORS url error: ${requrl}`, e); response.send(` @@ -163,6 +169,7 @@ function proxyServe(req: any, requrl: string, response: any) {

${e}

`); }) + // eslint-disable-next-line @typescript-eslint/no-explicit-any .on('response', (res: any) => { res.headers; const headers = Object.keys(res.headers); @@ -187,6 +194,7 @@ function proxyServe(req: any, requrl: string, response: any) { }) .on('end', sendModifiedBody) .pipe(htmlBodyMemoryStream) + // eslint-disable-next-line @typescript-eslint/no-explicit-any .on('error', (e: any) => console.log('http body pipe error', e)); }; retrieveHTTPBody(); @@ -244,6 +252,7 @@ export default async function InitializeServer(routeSetter: RouteSetter) { app.use(whm(compiler)); app.get(/^\/+$/, (req, res) => res.redirect(req.user ? '/home' : '/login')); // target urls that consist of one or more '/'s with nothing in between app.use(express.static(publicDirectory, { setHeaders: res => res.setHeader('Access-Control-Allow-Origin', '*') })); // all urls that start with dash's public directory: /files/ (e.g., /files/images, /files/audio, etc) + // eslint-disable-next-line @typescript-eslint/no-explicit-any app.use(cors({ origin: (_origin: any, callback: any) => callback(null, true) })); registerAuthenticationRoutes(app); // this adds routes to authenticate a user (login, etc) registerCorsProxy(app); // this adds a /corsProxy/ route to allow clients to get to urls that would otherwise be blocked by cors policies diff --git a/src/server/websocket.ts b/src/server/websocket.ts index ccbcb1c5f..1e25a8a27 100644 --- a/src/server/websocket.ts +++ b/src/server/websocket.ts @@ -15,7 +15,6 @@ import { resolvedPorts, socketMap, timeMap, userOperations } from './SocketData' import { initializeGuest } from './authentication/DashUserModel'; import { Database } from './database'; -// eslint-disable-next-line @typescript-eslint/no-namespace export namespace WebSocket { let CurUser: string | undefined; export let _socket: Socket; -- cgit v1.2.3-70-g09d2 From 25ee9e6b3f7da67bcf94eb2affd5793c67777930 Mon Sep 17 00:00:00 2001 From: bobzel Date: Wed, 21 Aug 2024 17:04:32 -0400 Subject: cleanup of face recognition. some lint fixes. --- eslint.config.mjs | 8 + src/.DS_Store | Bin 10244 -> 10244 bytes src/client/util/CurrentUserUtils.ts | 5 - src/client/util/DocumentManager.ts | 1 - src/client/views/MainView.tsx | 2 +- src/client/views/collections/CollectionSubView.tsx | 4 +- .../collectionFreeForm/FaceCollectionBox.tsx | 121 ++++++------- src/client/views/nodes/DocumentView.tsx | 8 +- src/client/views/search/FaceRecognitionHandler.tsx | 190 +++++++++++++++------ src/fields/Doc.ts | 6 +- src/fields/RichTextUtils.ts | 4 - src/server/database.ts | 3 - src/server/server_Initialization.ts | 2 +- 13 files changed, 198 insertions(+), 156 deletions(-) (limited to 'src') diff --git a/eslint.config.mjs b/eslint.config.mjs index 04655ce13..119f2f486 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -29,6 +29,7 @@ export default [ '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', @@ -42,6 +43,13 @@ export default [ '@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-conditional-assign': 'error', + 'no-use-before-define': 'error', + 'no-explicit-any': 'error', 'no-restricted-globals': ['error', 'event'], }, }, diff --git a/src/.DS_Store b/src/.DS_Store index 7a0b53ce0..426a2ee90 100644 Binary files a/src/.DS_Store and b/src/.DS_Store differ diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts index 2962682c2..0681a21cb 100644 --- a/src/client/util/CurrentUserUtils.ts +++ b/src/client/util/CurrentUserUtils.ts @@ -95,7 +95,6 @@ export class CurrentUserUtils { }); const reqdOpts:DocumentOptions = { title: "child click editors", _height:75, isSystem: true}; - // eslint-disable-next-line no-return-assign return DocUtils.AssignOpts(tempClicks, reqdOpts, reqdClickList) ?? (doc[field] = Docs.Create.TreeDocument(reqdClickList, reqdOpts)); } @@ -120,7 +119,6 @@ export class CurrentUserUtils { }); const reqdOpts:DocumentOptions = {title: "click editor templates", _height:75, isSystem: true}; - // eslint-disable-next-line no-return-assign return DocUtils.AssignOpts(tempClicks, reqdOpts, reqdClickList) ?? (doc[field] = Docs.Create.TreeDocument(reqdClickList, reqdOpts)); } @@ -138,7 +136,6 @@ export class CurrentUserUtils { }), ... DocListCast(tempNotes?.data).filter(note => !reqdTempOpts.find(reqd => reqd.title === note.title))]; const reqdOpts:DocumentOptions = { title: "Note Layouts", _height: 75, isSystem: true }; - // eslint-disable-next-line no-return-assign return DocUtils.AssignOpts(tempNotes, reqdOpts, reqdNoteList) ?? (doc[field] = Docs.Create.TreeDocument(reqdNoteList, reqdOpts)); } static setupUserTemplates(doc: Doc, field="template_user") { @@ -146,7 +143,6 @@ export class CurrentUserUtils { const reqdUserList = DocListCast(tempUsers?.data); const reqdOpts:DocumentOptions = { title: "User Layouts", _height: 75, isSystem: true }; - // eslint-disable-next-line no-return-assign return DocUtils.AssignOpts(tempUsers, reqdOpts, reqdUserList) ?? (doc[field] = Docs.Create.TreeDocument(reqdUserList, reqdOpts)); } @@ -183,7 +179,6 @@ export class CurrentUserUtils { default: return labelBox; }})(); const allopts = {isSystem: true, onClickScriptDisable: "never", ...opts, title}; - // eslint-disable-next-line no-return-assign return DocUtils.AssignScripts( (curIcon?.iconTemplate === opts.iconTemplate ? DocUtils.AssignOpts(curIcon, allopts):undefined) ?? ((templateIconsDoc[title] = MakeTemplate(creator(allopts, templateField)))), {onClick:"deiconifyView(documentView)", onDoubleClick: "deiconifyViewToLightbox(documentView)", }); diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts index a10237fcc..83b83240e 100644 --- a/src/client/util/DocumentManager.ts +++ b/src/client/util/DocumentManager.ts @@ -17,7 +17,6 @@ export class DocumentManager { // eslint-disable-next-line no-use-before-define private static _instance: DocumentManager; public static get Instance(): DocumentManager { - // eslint-disable-next-line no-return-assign return this._instance || (this._instance = new this()); } diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index 62ad0a3fb..9f1c7da3d 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -75,7 +75,7 @@ import { AnchorMenu } from './pdf/AnchorMenu'; import { GPTPopup } from './pdf/GPTPopup/GPTPopup'; import { TopBar } from './topbar/TopBar'; -// eslint-disable-next-line @typescript-eslint/no-var-requires +// eslint-disable-next-line @typescript-eslint/no-var-requires, @typescript-eslint/no-require-imports const { LEFT_MENU_WIDTH, TOPBAR_HEIGHT } = require('./global/globalCssVariables.module.scss'); // prettier-ignore @observer diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx index a6768ab35..5782d407e 100644 --- a/src/client/views/collections/CollectionSubView.tsx +++ b/src/client/views/collections/CollectionSubView.tsx @@ -1,4 +1,4 @@ -import { action, computed, IReactionDisposer, makeObservable, observable, reaction } from 'mobx'; +import { action, computed, makeObservable, observable } from 'mobx'; import * as React from 'react'; import * as rp from 'request-promise'; import { ClientUtils, returnFalse } from '../../../ClientUtils'; @@ -9,7 +9,7 @@ import { Id } from '../../../fields/FieldSymbols'; import { List } from '../../../fields/List'; import { listSpec } from '../../../fields/Schema'; import { ScriptField } from '../../../fields/ScriptField'; -import { BoolCast, Cast, DocCast, ScriptCast, StrCast } from '../../../fields/Types'; +import { BoolCast, Cast, ScriptCast, StrCast } from '../../../fields/Types'; import { WebField } from '../../../fields/URLField'; import { GetEffectiveAcl, TraceMobx } from '../../../fields/util'; import { GestureUtils } from '../../../pen-gestures/GestureUtils'; diff --git a/src/client/views/collections/collectionFreeForm/FaceCollectionBox.tsx b/src/client/views/collections/collectionFreeForm/FaceCollectionBox.tsx index d5a2809dc..94f9a3c94 100644 --- a/src/client/views/collections/collectionFreeForm/FaceCollectionBox.tsx +++ b/src/client/views/collections/collectionFreeForm/FaceCollectionBox.tsx @@ -3,28 +3,28 @@ import { IconButton, Size } from 'browndash-components'; import * as faceapi from 'face-api.js'; import { FaceMatcher } from 'face-api.js'; import 'ldrs/ring'; -import { action, computed, makeObservable, observable } from 'mobx'; +import { action, makeObservable, observable } from 'mobx'; import { observer } from 'mobx-react'; import React from 'react'; -import { Utils } from '../../../../Utils'; -import { Doc, DocListCast } from '../../../../fields/Doc'; -import { DocData } from '../../../../fields/DocSymbols'; +import { setupMoveUpEvents } from '../../../../ClientUtils'; +import { Utils, emptyFunction } from '../../../../Utils'; +import { Doc, Opt } from '../../../../fields/Doc'; import { Id } from '../../../../fields/FieldSymbols'; import { List } from '../../../../fields/List'; -import { listSpec } from '../../../../fields/Schema'; -import { Cast, ImageCast, StrCast } from '../../../../fields/Types'; +import { ImageCast } from '../../../../fields/Types'; import { DocumentType } from '../../../documents/DocumentTypes'; import { Docs } from '../../../documents/Documents'; import { DragManager } from '../../../util/DragManager'; +import { dropActionType } from '../../../util/DropActionTypes'; import { SnappingManager } from '../../../util/SnappingManager'; import { undoable } from '../../../util/UndoManager'; import { ViewBoxBaseComponent } from '../../DocComponent'; import { ObservableReactComponent } from '../../ObservableReactComponent'; import { DocumentView } from '../../nodes/DocumentView'; import { FieldView, FieldViewProps } from '../../nodes/FieldView'; +import { FaceRecognitionHandler } from '../../search/FaceRecognitionHandler'; import './FaceCollectionBox.scss'; import { MarqueeOptionsMenu } from './MarqueeOptionsMenu'; -import { FaceRecognitionHandler } from '../../search/FaceRecognitionHandler'; interface FaceDocumentProps { faceDoc: Doc; @@ -50,49 +50,29 @@ export class FaceDocumentItem extends ObservableReactComponent doc.type === DocumentType.IMG); - filteredDocs.forEach(doc => { - // If the current Face Document has no items, and the doc has more than one face descriptor, don't let the user add the document first. - if ((this._props.faceDoc[DocData].face_descriptors as List>).length === 0 && (doc[DocData][FaceRecognitionHandler.FacesField(doc)] as List>).length > 1) { + de.complete.docDragData?.droppedDocuments + ?.filter(doc => doc.type === DocumentType.IMG) + .forEach(imgDoc => { + // If the current Face Document has no faces, and the doc has more than one face descriptor, don't let the user add the document first. Or should we just use the first face ? + if (FaceRecognitionHandler.FaceDocDescriptors(this._props.faceDoc).length === 0 && FaceRecognitionHandler.ImageDocFaceDescriptors(imgDoc).length > 1) { alert('Cannot add a document with multiple faces as the first item!'); } else { - // Loop through the documents' face descriptors. - // Choose the face with the smallest distance to add. - const float32Array = (this._props.faceDoc[DocData].face_descriptors as List>).map(faceDescriptor => new Float32Array(Array.from(faceDescriptor))); - const labeledFaceDescriptor = new faceapi.LabeledFaceDescriptors(StrCast(this._props.faceDoc[DocData].face_label), float32Array); - const faceDescriptors: faceapi.LabeledFaceDescriptors[] = [labeledFaceDescriptor]; - - const faceMatcher = new FaceMatcher(faceDescriptors, 1); - let cur_lowest_distance = 1; - let cur_matching_face = new List(); - - (doc[DocData][FaceRecognitionHandler.FacesField(doc)] as List>).forEach(face => { - // If the face has the current lowest distance, mark it as such - // Once that lowest distance is found, add the face descriptor to the faceDoc, and add the associated doc - const convered_32_array: Float32Array = new Float32Array(Array.from(face)); - const match = faceMatcher.matchDescriptor(convered_32_array); - - if (match.distance < cur_lowest_distance) { - cur_lowest_distance = match.distance; - cur_matching_face = face; - } - }); - - const faceFieldKey = FaceRecognitionHandler.FaceField(doc, this._props.faceDoc); - if (doc[DocData][faceFieldKey]) { - Cast(doc[DocData][faceFieldKey], listSpec('number'), null).push(cur_matching_face as unknown as number); // items are lists of numbers, not numbers, but type system can't handle that - } else { - doc[DocData][faceFieldKey] = new List>([cur_matching_face]); - } - - Doc.AddDocToList(this._props.faceDoc[DocData], 'face_docList', doc); - Cast(this._props.faceDoc[DocData].face_descriptors, listSpec('number'), null).push(cur_matching_face as unknown as number); // items are lists of numbers, not numbers, but type system can't handle that + // Loop through the documents' face descriptors and choose the face in the iage with the smallest distance (most similar to the face colleciton) + const faceDescriptorsAsFloat32Array = FaceRecognitionHandler.FaceDocDescriptors(this._props.faceDoc).map(fd => new Float32Array(Array.from(fd))); + const labeledFaceDescriptor = new faceapi.LabeledFaceDescriptors(FaceRecognitionHandler.FaceDocLabel(this._props.faceDoc), faceDescriptorsAsFloat32Array); + const faceMatcher = new FaceMatcher([labeledFaceDescriptor], 1); + const { face_match } = FaceRecognitionHandler.ImageDocFaceDescriptors(imgDoc).reduce( + (prev, face) => { + const match = faceMatcher.matchDescriptor(new Float32Array(Array.from(face))); + return match.distance < prev.dist ? { dist: match.distance, face_match: face } : prev; + }, + { dist: 1, face_match: new List() as Opt> } + ); + + // assign the face in the image that's closest to the face collection to be the face that's assigned to the collection + face_match && FaceRecognitionHandler.ImageDocAddFace(imgDoc, face_match, this._props.faceDoc); } }); - return false; - } return false; } @@ -108,23 +88,16 @@ export class FaceDocumentItem extends ObservableReactComponent { - if (Doc.ActiveDashboard) { - Doc.RemoveDocFromList(Doc.ActiveDashboard[DocData], 'faceDocuments', this._props.faceDoc); - } - }, 'remove face'); + FaceRecognitionHandler.DeleteFaceDoc(this._props.faceDoc); + }, 'delete face'); /** * Deletes a document from a Face Document's associated docs list. * @param doc */ - @action - deleteAssociatedDoc = (doc: Doc) => { - this._props.faceDoc[DocData].face_descriptors = new List>( - (this._props.faceDoc[DocData].face_descriptors as List>).filter(fd => !(doc[DocData][FaceRecognitionHandler.FaceField(doc, this._props.faceDoc)] as List>).includes(fd)) - ); - doc[DocData][FaceRecognitionHandler.FaceField(doc, this._props.faceDoc)] = new List>(); - Doc.RemoveDocFromList(this._props.faceDoc[DocData], 'face_docList', doc); - }; + deleteAssociatedDoc = undoable((imgDoc: Doc) => { + FaceRecognitionHandler.FaceDocRemoveImageDocFace(imgDoc, this._props.faceDoc); + }, 'remove doc from face'); render() { return ( @@ -133,7 +106,7 @@ export class FaceDocumentItem extends ObservableReactComponent
-

{StrCast(this._props.faceDoc[DocData].face_label)}

+

{FaceRecognitionHandler.FaceDocLabel(this._props.faceDoc)}

{this._displayImages ? (
- {DocListCast(this._props.faceDoc[DocData].face_docList).map(doc => { + {FaceRecognitionHandler.FaceDocFaces(this._props.faceDoc).map(doc => { const [name, type] = ImageCast(doc[Doc.LayoutFieldKey(doc)]).url.href.split('.'); return ( -
+
+ setupMoveUpEvents( + this, + e, + () => { + DragManager.StartDocumentDrag([e.target as HTMLElement], new DragManager.DocumentDragData([doc], dropActionType.embed), e.clientX, e.clientY); + return true; + }, + emptyFunction, + emptyFunction + ) + }> DocumentView.showDocument(doc, { willZoomCentered: true })} style={{ maxWidth: '60px', margin: '10px' }} src={`${name}_o.${type}`} />
this.deleteAssociatedDoc(doc)} icon={'x'} style={{ width: '4px' }} size={Size.XSMALL} /> @@ -168,25 +155,15 @@ export class FaceCollectionBox extends ViewBoxBaseComponent() { return FieldView.LayoutString(FaceCollectionBox, fieldKey); } - public static Instance: FaceCollectionBox; - - @computed get currentDocs() { - if (Doc.ActiveDashboard) { - return DocListCast(Doc.ActiveDashboard[DocData].faceDocuments); - } - return []; - } - constructor(props: FieldViewProps) { super(props); makeObservable(this); - FaceCollectionBox.Instance = this; } render() { return (
- {this.currentDocs.map(doc => ( + {FaceRecognitionHandler.FaceDocuments().map(doc => ( ))}
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index c807d99ac..5efdb3df4 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -1,5 +1,4 @@ /* eslint-disable no-use-before-define */ -/* eslint-disable react/jsx-props-no-spreading */ import { IconProp } from '@fortawesome/fontawesome-svg-core'; import { Property } from 'csstype'; import { Howl } from 'howler'; @@ -341,7 +340,6 @@ export class DocumentViewInternal extends DocComponent { if (this._props.isGroupActive?.() === GroupActive.child && !this._props.isDocumentActive?.()) return; - // eslint-disable-next-line no-use-before-define this._longPressSelector = setTimeout(() => SnappingManager.LongPress && this._props.select(false), 1000); if (!DocumentView.DownDocView) DocumentView.DownDocView = this._docView; @@ -405,7 +402,6 @@ export class DocumentViewInternal extends DocComponent() { ) ); } - // eslint-disable-next-line default-param-last + public static FocusOrOpen(docIn: Doc, optionsIn: FocusViewOptions = { willZoomCentered: true, zoomScale: 0, openLocation: OpenWhere.toggleRight }, containingDoc?: Doc) { let doc = docIn; const options = optionsIn; diff --git a/src/client/views/search/FaceRecognitionHandler.tsx b/src/client/views/search/FaceRecognitionHandler.tsx index dc271fe73..3ef6f9674 100644 --- a/src/client/views/search/FaceRecognitionHandler.tsx +++ b/src/client/views/search/FaceRecognitionHandler.tsx @@ -10,7 +10,22 @@ import { DocumentType } from '../../documents/DocumentTypes'; import { DocumentManager } from '../../util/DocumentManager'; /** - * A class that handles face recognition. + * A singleton class that handles face recognition and manages face Doc collections for each face found. + * Displaying an image doc anywhere will trigger this class to test if the image contains any faces. + * If it does, each recognized face will be compared to a global set of faces (each is a face collection Doc + * that have already been found. If the face matches a face collection Doc, then it will be added to that + * collection along with the numerical representation of the face, its face descriptor. + * + * Image Doc's that are added to one or more face collection Docs will be given these metadata fields: + * _Face - a nunerical representation of the Nth face found in the image + * _Faces - a list of all the numerical face representations found in the image (why is this needed?) + * + * Face collection Doc's are created for each person identified and are stored in the Dashboard's faceDocument's list + * + * Each Face collection Doc represents all the images found for that person. It has these fields: + * face_label - a string label for the person that was recognized (currently it's just a 'face#') + * face_descriptors - a list of all the face descriptors for different images of the person + * face_docList - a list of all image Docs that contain a face for the person */ export class FaceRecognitionHandler { static _instance: FaceRecognitionHandler; @@ -18,13 +33,90 @@ export class FaceRecognitionHandler { private _processingDocs: Set = new Set(); private _pendingLoadDocs: Doc[] = []; - public static FaceField = (target: Doc, doc: Doc) => `${Doc.LayoutFieldKey(target)}_${doc.face_label}`; - public static FacesField = (target: Doc) => `${Doc.LayoutFieldKey(target)}_Faces`; + private static imgDocFaceField = (imgDoc: Doc, faceDoc: Doc) => `${Doc.LayoutFieldKey(imgDoc)}_${FaceRecognitionHandler.FaceDocLabel(faceDoc)}`; + /** + * initializes an image with an empty list of face descriptors + * @param imgDoc image to initialize + */ + private static initImageDocFaceDescriptors = (imgDoc: Doc) => { + imgDoc[DocData][`${Doc.LayoutFieldKey(imgDoc)}_Faces`] = new List>(); + }; + /** + * returns the face descriptors for each face found on an image Doc + * @param imgDoc + * @returns list of face descriptors + */ + public static ImageDocFaceDescriptors = (imgDoc: Doc) => imgDoc[DocData][`${Doc.LayoutFieldKey(imgDoc)}_Faces`] as List>; + + /** + * Adds metadata to an image Doc describing a face found in the image + * @param imgDoc image Doc containing faces + * @param faceDescriptor descriptor for the face found + * @param faceDoc face collection Doc containing the same face + */ + public static ImageDocAddFace = (imgDoc: Doc, faceDescriptor: List, faceDoc: Doc) => { + const faceFieldKey = FaceRecognitionHandler.imgDocFaceField(imgDoc, faceDoc); + if (imgDoc[DocData][faceFieldKey]) { + Cast(imgDoc[DocData][faceFieldKey], listSpec('number'), null).push(faceDescriptor as unknown as number); // items are lists of numbers, not numbers, but type system can't handle that + } else { + imgDoc[DocData][faceFieldKey] = new List>([faceDescriptor]); + } + }; + + /** + * returns a list of all face collection Docs on the current dashboard + * @returns face collection Doc list + */ + public static FaceDocuments = () => DocListCast(Doc.ActiveDashboard?.[DocData].faceDocuments); + + public static DeleteFaceDoc = (faceDoc: Doc) => Doc.ActiveDashboard && Doc.RemoveDocFromList(Doc.ActiveDashboard[DocData], 'faceDocuments', faceDoc); + + /** + * returns the labels associated with a face collection Doc + * @param faceDoc the face collection Doc + * @returns label string + */ + public static FaceDocLabel = (faceDoc: Doc) => StrCast(faceDoc[DocData].face_label); + /** + * Returns all the face descriptors associated with a face collection Doc + * @param faceDoc a face collection Doc + * @returns face descriptors + */ + public static FaceDocDescriptors = (faceDoc: Doc) => faceDoc[DocData].face_descriptors as List>; + + /** + * Returns a list of all face image Docs associated with the face collection + * @param faceDoc a face collection Doc + * @returns image Docs + */ + public static FaceDocFaces = (faceDoc: Doc) => DocListCast(faceDoc[DocData].face_docList); + + /** + * Adds a face image to the list of faces in a face collection Doc, and updates the face collection's list of image descriptors + * @param img - image with faces to add to a face collection Doc + * @param faceDescriptor - the face descriptor for the face in the image to add + * @param faceDoc - the face collection Doc + */ + public static FaceDocAddImageDocFace = (img: Doc, faceDescriptor: List, faceDoc: Doc) => { + Doc.AddDocToList(faceDoc, 'face_docList', img); + Cast(faceDoc.face_descriptors, listSpec('number'), null).push(faceDescriptor as unknown as number); // items are lists of numbers, not numbers, but type system can't handle that + }; + + /** + * Removes a face from a face Doc collection, and updates the face collection's list of image descriptors + * @param imgDoc - image with faces to remove from the face Doc collectoin + * @param faceDoc - the face Doc collection + */ + public static FaceDocRemoveImageDocFace = (imgDoc: Doc, faceDoc: Doc) => { + imgDoc[DocData][FaceRecognitionHandler.imgDocFaceField(imgDoc, faceDoc)] = new List>(); + Doc.RemoveDocFromList(faceDoc[DocData], 'face_docList', imgDoc); + faceDoc[DocData].face_descriptors = new List>(FaceRecognitionHandler.FaceDocDescriptors(faceDoc).filter(fd => !(imgDoc[DocData][FaceRecognitionHandler.imgDocFaceField(imgDoc, faceDoc)] as List>).includes(fd))); + }; constructor() { FaceRecognitionHandler._instance = this; - this.loadModels().then(() => this._pendingLoadDocs.forEach(this.findMatches)); - DocumentManager.Instance.AddAnyViewRenderedCB(dv => FaceRecognitionHandler.Instance.findMatches(dv.Document)); + this.loadModels().then(() => this._pendingLoadDocs.forEach(this.classifyFacesInImage)); + DocumentManager.Instance.AddAnyViewRenderedCB(dv => FaceRecognitionHandler.Instance.classifyFacesInImage(dv.Document)); } @computed get examinedFaceDocs() { @@ -48,48 +140,42 @@ export class FaceRecognitionHandler { /** * When a document is added, look for matching face documents. - * @param doc The document being analyzed. + * @param imgDoc The document being analyzed. */ - public findMatches = async (doc: Doc) => { + public classifyFacesInImage = async (imgDoc: Doc) => { if (!this._loadedModels || !Doc.ActiveDashboard) { - this._pendingLoadDocs.push(doc); + this._pendingLoadDocs.push(imgDoc); return; } - if (doc.type === DocumentType.LOADING && !doc.loadingError) { - setTimeout(() => this.findMatches(doc), 1000); + if (imgDoc.type === DocumentType.LOADING && !imgDoc.loadingError) { + setTimeout(() => this.classifyFacesInImage(imgDoc), 1000); return; } - const imgUrl = ImageCast(doc[Doc.LayoutFieldKey(doc)]); + const imgUrl = ImageCast(imgDoc[Doc.LayoutFieldKey(imgDoc)]); // If the doc isn't an image or currently already been examined or is being processed, stop examining the document. - if (!imgUrl || this.examinedFaceDocs.includes(doc) || this._processingDocs.has(doc)) { + if (!imgUrl || this.examinedFaceDocs.includes(imgDoc) || this._processingDocs.has(imgDoc)) { return; } // Mark the document as being processed. - this._processingDocs.add(doc); + this._processingDocs.add(imgDoc); + FaceRecognitionHandler.initImageDocFaceDescriptors(imgDoc); // Get the image the document contains and analyze for faces. const [name, type] = imgUrl.url.href.split('.'); const imageURL = `${name}_o.${type}`; - const img = await this.loadImage(imageURL); - - const fullFaceDescriptions = await faceapi.detectAllFaces(img).withFaceLandmarks().withFaceDescriptors(); - - doc[DocData][FaceRecognitionHandler.FacesField(doc)] = new List>(); + const imgDocFaceDescriptions = await faceapi.detectAllFaces(img).withFaceLandmarks().withFaceDescriptors(); // For each face detected, find a match. - for (const fd of fullFaceDescriptions) { - let match = this.findMatch(fd.descriptor); - const converted_list = new List(Array.from(fd.descriptor)); - - if (match) { - // If a matching Face Document has been found, add the document to the Face Document's associated docs and append the face - // descriptor to the Face Document's descriptor list. - Doc.AddDocToList(match, 'face_docList', doc); - Cast(match.face_descriptors, listSpec('number'), null).push(converted_list as unknown as number); // items are lists of numbers, not numbers, but type system can't handle that + for (const fd of imgDocFaceDescriptions) { + let faceDocMatch = this.findMatchingFaceDoc(fd.descriptor); + const faceDescriptor = new List(Array.from(fd.descriptor)); + + if (faceDocMatch) { + FaceRecognitionHandler.FaceDocAddImageDocFace(imgDoc, faceDescriptor, faceDocMatch); } else { // If a matching Face Document has not been found, create a new Face Document. Doc.UserDoc().faceDocNum = NumCast(Doc.UserDoc().faceDocNum) + 1; @@ -98,53 +184,45 @@ export class FaceRecognitionHandler { newFaceDocument.title = `Face ${Doc.UserDoc().faceDocNum}`; newFaceDocument.face = ''; // just to make prettyprinting look better newFaceDocument.face_label = `Face${Doc.UserDoc().faceDocNum}`; - newFaceDocument.face_docList = new List([doc]); - newFaceDocument.face_descriptors = new List>([converted_list]); + newFaceDocument.face_docList = new List([imgDoc]); + newFaceDocument.face_descriptors = new List>([faceDescriptor]); Doc.AddDocToList(Doc.ActiveDashboard[DocData], 'faceDocuments', newFaceDocument); - match = newFaceDocument; + faceDocMatch = newFaceDocument; } // Assign a field in the document of the matching Face Document. - const faceDescripField = FaceRecognitionHandler.FaceField(doc, match); - if (doc[DocData][faceDescripField]) { - Cast(doc[DocData][faceDescripField], listSpec('number'), null).push(converted_list as unknown as number); // items are lists of numbers, not numbers, but type system can't handle that - } else { - doc[DocData][faceDescripField] = new List>([converted_list]); - } - - Cast(doc[DocData][FaceRecognitionHandler.FacesField(doc)], listSpec('number'), null).push(converted_list as unknown as number); // items are lists of numbers, not numbers, but type system can't handle that - - Doc.AddDocToList(Doc.UserDoc(), 'examinedFaceDocs', doc); + FaceRecognitionHandler.ImageDocAddFace(imgDoc, faceDescriptor, faceDocMatch); + Doc.AddDocToList(Doc.UserDoc(), 'examinedFaceDocs', imgDoc); } - this._processingDocs.delete(doc); + this._processingDocs.delete(imgDoc); }; /** - * Finds a matching Face Document given a descriptor - * @param cur_descriptor The current descriptor whose match is being searched for. - * @returns The most similar Face Document. + * Finds the most similar matching Face Document to a face descriptor + * @param faceDescriptor face descriptor number list + * @returns face Doc */ - private findMatch(cur_descriptor: Float32Array) { - if (!Doc.ActiveDashboard || DocListCast(Doc.ActiveDashboard[DocData].faceDocuments).length < 1) { - return null; + private findMatchingFaceDoc = (faceDescriptor: Float32Array) => { + if (!Doc.ActiveDashboard || FaceRecognitionHandler.FaceDocuments().length < 1) { + return undefined; } - const faceDescriptors: faceapi.LabeledFaceDescriptors[] = DocListCast(Doc.ActiveDashboard[DocData].faceDocuments).map(faceDocument => { - const float32Array = (faceDocument[DocData].face_descriptors as List>).map(faceDescriptor => new Float32Array(Array.from(faceDescriptor))); - return new faceapi.LabeledFaceDescriptors(StrCast(faceDocument[DocData].face_label), float32Array); + const faceDescriptors = FaceRecognitionHandler.FaceDocuments().map(faceDoc => { + const float32Array = FaceRecognitionHandler.FaceDocDescriptors(faceDoc).map(fd => new Float32Array(Array.from(fd))); + return new faceapi.LabeledFaceDescriptors(FaceRecognitionHandler.FaceDocLabel(faceDoc), float32Array); }); const faceMatcher = new FaceMatcher(faceDescriptors, 0.6); - const match = faceMatcher.findBestMatch(cur_descriptor); + const match = faceMatcher.findBestMatch(faceDescriptor); if (match.label !== 'unknown') { - for (const doc of DocListCast(Doc.ActiveDashboard[DocData].faceDocuments)) { - if (doc[DocData].face_label === match.label) { - return doc; + for (const faceDoc of FaceRecognitionHandler.FaceDocuments()) { + if (FaceRecognitionHandler.FaceDocLabel(faceDoc) === match.label) { + return faceDoc; } } } - return null; - } + return undefined; + }; /** * Loads an image diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts index eb6ed9757..ffb5aab79 100644 --- a/src/fields/Doc.ts +++ b/src/fields/Doc.ts @@ -1,5 +1,3 @@ -/* eslint-disable @typescript-eslint/no-namespace */ -/* eslint-disable default-param-last */ /* eslint-disable no-use-before-define */ import { action, computed, makeObservable, observable, ObservableMap, ObservableSet, runInAction } from 'mobx'; import { computedFn } from 'mobx-utils'; @@ -127,9 +125,7 @@ export type FieldResult = Opt | FieldWaiting * If no default value is given, and the returned value is not undefined, it can be safely modified. */ export function DocListCastAsync(field: FieldResult): Promise; -// eslint-disable-next-line no-redeclare export function DocListCastAsync(field: FieldResult, defaultValue: Doc[]): Promise; -// eslint-disable-next-line no-redeclare export function DocListCastAsync(field: FieldResult, defaultValue?: Doc[]) { const list = Cast(field, listSpec(Doc)); return list ? Promise.all(list).then(() => list) : Promise.resolve(defaultValue); @@ -437,7 +433,6 @@ export class Doc extends RefField { const writeMode = DocServer.getFieldWriteMode(fKey); if (fKey.startsWith('acl_') || writeMode !== DocServer.WriteMode.Playground) { delete this[CachedUpdates][fKey]; - // eslint-disable-next-line no-await-in-loop await fn(); } else { this[CachedUpdates][fKey] = fn; @@ -1576,6 +1571,7 @@ export namespace Doc { try { resolved = JSON.parse(typeof data === 'string' ? data : JSON.stringify(data)); } catch (e) { + console.error(e); return undefined; } let output: Opt; diff --git a/src/fields/RichTextUtils.ts b/src/fields/RichTextUtils.ts index d1316d256..b3534dde7 100644 --- a/src/fields/RichTextUtils.ts +++ b/src/fields/RichTextUtils.ts @@ -394,13 +394,11 @@ export namespace RichTextUtils { for (const markName of Object.keys(schema.marks)) { // eslint-disable-next-line no-cond-assign if (ignored.includes(markName) || !(mark = markMap[markName])) { - // eslint-disable-next-line no-continue continue; } let converted = MarkToStyle.get(markName) || (markName as keyof docsV1.Schema$TextStyle); let value: unknown = true; if (!converted) { - // eslint-disable-next-line no-continue continue; } // eslint-disable-next-line @typescript-eslint/no-shadow @@ -412,10 +410,8 @@ export namespace RichTextUtils { const docDelimeter = '/doc/'; const alreadyShared = '?sharing=true'; if (new RegExp(window.location.origin + docDelimeter).test(url) && !url.endsWith(alreadyShared)) { - // eslint-disable-next-line no-await-in-loop const linkDoc = await DocServer.GetRefField(url.split(docDelimeter)[1]); if (linkDoc instanceof Doc) { - // eslint-disable-next-line no-await-in-loop let exported = (await Cast(linkDoc.link_anchor_2, Doc))!; if (!exported.customLayout) { exported = Doc.MakeEmbedding(exported); diff --git a/src/server/database.ts b/src/server/database.ts index 975b9eb80..10dc540c3 100644 --- a/src/server/database.ts +++ b/src/server/database.ts @@ -1,4 +1,3 @@ -/* eslint-disable @typescript-eslint/no-namespace */ import * as mongodb from 'mongodb'; import * as mongoose from 'mongoose'; import { Opt } from '../fields/Doc'; @@ -148,9 +147,7 @@ export namespace Database { } public delete(query: any, collectionName?: string): Promise; - // eslint-disable-next-line no-dupe-class-members public delete(id: string, collectionName?: string): Promise; - // eslint-disable-next-line no-dupe-class-members public delete(idIn: any, collectionName = DocumentsCollection) { let id = idIn; if (typeof id === 'string') { diff --git a/src/server/server_Initialization.ts b/src/server/server_Initialization.ts index 97c63a93e..0cf9a6e58 100644 --- a/src/server/server_Initialization.ts +++ b/src/server/server_Initialization.ts @@ -115,7 +115,7 @@ function registerEmbeddedBrowseRelativePathHandler(server: express.Express) { // eslint-disable-next-line @typescript-eslint/no-explicit-any function proxyServe(req: any, requrl: string, response: any) { - // eslint-disable-next-line global-require, @typescript-eslint/no-require-imports + // eslint-disable-next-line global-require, @typescript-eslint/no-require-imports, @typescript-eslint/no-var-requires const htmlBodyMemoryStream = new (require('memorystream'))(); let wasinBrFormat = false; const sendModifiedBody = () => { -- cgit v1.2.3-70-g09d2 From 4091d1681437527bfb55cb79570e8b652e9b190f Mon Sep 17 00:00:00 2001 From: bobzel Date: Wed, 21 Aug 2024 17:12:35 -0400 Subject: from last --- .../views/collections/collectionFreeForm/FaceCollectionBox.tsx | 5 ++++- src/client/views/search/FaceRecognitionHandler.tsx | 1 + 2 files changed, 5 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/client/views/collections/collectionFreeForm/FaceCollectionBox.tsx b/src/client/views/collections/collectionFreeForm/FaceCollectionBox.tsx index 94f9a3c94..dd8dea41e 100644 --- a/src/client/views/collections/collectionFreeForm/FaceCollectionBox.tsx +++ b/src/client/views/collections/collectionFreeForm/FaceCollectionBox.tsx @@ -70,7 +70,10 @@ export class FaceDocumentItem extends ObservableReactComponent>([faceDescriptor]); } + FaceRecognitionHandler.FaceDocAddImageDocFace(imgDoc, faceDescriptor, faceDoc); }; /** -- cgit v1.2.3-70-g09d2 From b6275b9d630131e50727f76af44936acc0cb7d7d Mon Sep 17 00:00:00 2001 From: bobzel Date: Wed, 21 Aug 2024 17:25:01 -0400 Subject: from last --- src/client/views/search/FaceRecognitionHandler.tsx | 2 -- 1 file changed, 2 deletions(-) (limited to 'src') diff --git a/src/client/views/search/FaceRecognitionHandler.tsx b/src/client/views/search/FaceRecognitionHandler.tsx index 6494a1ed4..c446df6ff 100644 --- a/src/client/views/search/FaceRecognitionHandler.tsx +++ b/src/client/views/search/FaceRecognitionHandler.tsx @@ -61,7 +61,6 @@ export class FaceRecognitionHandler { } else { imgDoc[DocData][faceFieldKey] = new List>([faceDescriptor]); } - FaceRecognitionHandler.FaceDocAddImageDocFace(imgDoc, faceDescriptor, faceDoc); }; /** @@ -109,7 +108,6 @@ export class FaceRecognitionHandler { * @param faceDoc - the face Doc collection */ public static FaceDocRemoveImageDocFace = (imgDoc: Doc, faceDoc: Doc) => { - imgDoc[DocData][FaceRecognitionHandler.imgDocFaceField(imgDoc, faceDoc)] = new List>(); Doc.RemoveDocFromList(faceDoc[DocData], 'face_docList', imgDoc); faceDoc[DocData].face_descriptors = new List>(FaceRecognitionHandler.FaceDocDescriptors(faceDoc).filter(fd => !(imgDoc[DocData][FaceRecognitionHandler.imgDocFaceField(imgDoc, faceDoc)] as List>).includes(fd))); }; -- cgit v1.2.3-70-g09d2 From 95071fa118ee36d7365250f10756dce335dc76d9 Mon Sep 17 00:00:00 2001 From: bobzel Date: Thu, 22 Aug 2024 11:00:14 -0400 Subject: more cleanup for face collections --- src/client/views/Main.tsx | 2 +- .../collectionFreeForm/FaceCollectionBox.tsx | 62 ++++++--- src/client/views/search/FaceRecognitionHandler.tsx | 151 +++++++++++---------- 3 files changed, 121 insertions(+), 94 deletions(-) (limited to 'src') diff --git a/src/client/views/Main.tsx b/src/client/views/Main.tsx index 5a408f593..023324881 100644 --- a/src/client/views/Main.tsx +++ b/src/client/views/Main.tsx @@ -138,7 +138,7 @@ FieldLoader.ServerLoadStatus = { requested: 0, retrieved: 0, message: 'cache' }; PresBox, PresElementBox, SearchBox, - ImageLabelBox, //Here! + ImageLabelBox, FaceCollectionBox, FunctionPlotBox, InkingStroke, diff --git a/src/client/views/collections/collectionFreeForm/FaceCollectionBox.tsx b/src/client/views/collections/collectionFreeForm/FaceCollectionBox.tsx index dd8dea41e..6005da6dd 100644 --- a/src/client/views/collections/collectionFreeForm/FaceCollectionBox.tsx +++ b/src/client/views/collections/collectionFreeForm/FaceCollectionBox.tsx @@ -26,18 +26,27 @@ import { FaceRecognitionHandler } from '../../search/FaceRecognitionHandler'; import './FaceCollectionBox.scss'; import { MarqueeOptionsMenu } from './MarqueeOptionsMenu'; -interface FaceDocumentProps { +/** + * This code is used to render the sidebar collection of unique recognized faces, where each + * unique face in turn displays the set of images that correspond to the face. + */ + +interface UniqueFaceProps { faceDoc: Doc; } /** - * A componenent to visually represent a Face Document. + * React component for rendering a unique face and its collection of image Docs. + * + * This both displays a collection of images corresponding tp a unique face, and + * allows for editing the face collection by removing an image, or drag-and-dropping + * an image that was not recognized. */ @observer -export class FaceDocumentItem extends ObservableReactComponent { +export class UniqueFaceView extends ObservableReactComponent { private _dropDisposer?: DragManager.DragDropDisposer; - constructor(props: FaceDocumentProps) { + constructor(props: UniqueFaceProps) { super(props); makeObservable(this); } @@ -54,12 +63,12 @@ export class FaceDocumentItem extends ObservableReactComponent doc.type === DocumentType.IMG) .forEach(imgDoc => { // If the current Face Document has no faces, and the doc has more than one face descriptor, don't let the user add the document first. Or should we just use the first face ? - if (FaceRecognitionHandler.FaceDocDescriptors(this._props.faceDoc).length === 0 && FaceRecognitionHandler.ImageDocFaceDescriptors(imgDoc).length > 1) { + if (FaceRecognitionHandler.UniqueFaceDescriptors(this._props.faceDoc).length === 0 && FaceRecognitionHandler.ImageDocFaceDescriptors(imgDoc).length > 1) { alert('Cannot add a document with multiple faces as the first item!'); } else { // Loop through the documents' face descriptors and choose the face in the iage with the smallest distance (most similar to the face colleciton) - const faceDescriptorsAsFloat32Array = FaceRecognitionHandler.FaceDocDescriptors(this._props.faceDoc).map(fd => new Float32Array(Array.from(fd))); - const labeledFaceDescriptor = new faceapi.LabeledFaceDescriptors(FaceRecognitionHandler.FaceDocLabel(this._props.faceDoc), faceDescriptorsAsFloat32Array); + const faceDescriptorsAsFloat32Array = FaceRecognitionHandler.UniqueFaceDescriptors(this._props.faceDoc).map(fd => new Float32Array(Array.from(fd))); + const labeledFaceDescriptor = new faceapi.LabeledFaceDescriptors(FaceRecognitionHandler.UniqueFaceLabel(this._props.faceDoc), faceDescriptorsAsFloat32Array); const faceMatcher = new FaceMatcher([labeledFaceDescriptor], 1); const { face_match } = FaceRecognitionHandler.ImageDocFaceDescriptors(imgDoc).reduce( (prev, face) => { @@ -71,8 +80,8 @@ export class FaceDocumentItem extends ObservableReactComponent { - FaceRecognitionHandler.DeleteFaceDoc(this._props.faceDoc); + deleteUniqueFace = undoable(() => { + FaceRecognitionHandler.DeleteUniqueFace(this._props.faceDoc); }, 'delete face'); /** - * Deletes a document from a Face Document's associated docs list. - * @param doc + * Removes a face image Doc from a unique face's list of images. + * @param imgDoc - image Doc to remove */ - deleteAssociatedDoc = undoable((imgDoc: Doc) => { - FaceRecognitionHandler.FaceDocRemoveImageDocFace(imgDoc, this._props.faceDoc); + removeFaceImageFromUniqueFace = undoable((imgDoc: Doc) => { + FaceRecognitionHandler.ImageDocDeassociateUniqueFace(imgDoc, this._props.faceDoc); + FaceRecognitionHandler.UniqueFaceRemoveFaceImage(imgDoc, this._props.faceDoc); }, 'remove doc from face'); render() { return (
this.createDropTarget(ele!)}>
- +
-

{FaceRecognitionHandler.FaceDocLabel(this._props.faceDoc)}

+

{FaceRecognitionHandler.UniqueFaceLabel(this._props.faceDoc)}

{this._displayImages ? (
- {FaceRecognitionHandler.FaceDocFaces(this._props.faceDoc).map(doc => { + {FaceRecognitionHandler.UniqueFaceImages(this._props.faceDoc).map(doc => { const [name, type] = ImageCast(doc[Doc.LayoutFieldKey(doc)]).url.href.split('.'); return (
DocumentView.showDocument(doc, { willZoomCentered: true })} style={{ maxWidth: '60px', margin: '10px' }} src={`${name}_o.${type}`} />
- this.deleteAssociatedDoc(doc)} icon={'x'} style={{ width: '4px' }} size={Size.XSMALL} /> + this.removeFaceImageFromUniqueFace(doc)} icon={'x'} style={{ width: '4px' }} size={Size.XSMALL} />
); @@ -152,6 +162,14 @@ export class FaceDocumentItem extends ObservableReactComponent() { public static LayoutString(fieldKey: string) { @@ -166,8 +184,8 @@ export class FaceCollectionBox extends ViewBoxBaseComponent() { render() { return (
- {FaceRecognitionHandler.FaceDocuments().map(doc => ( - + {FaceRecognitionHandler.UniqueFaces().map(doc => ( + ))}
); diff --git a/src/client/views/search/FaceRecognitionHandler.tsx b/src/client/views/search/FaceRecognitionHandler.tsx index c446df6ff..c239c775c 100644 --- a/src/client/views/search/FaceRecognitionHandler.tsx +++ b/src/client/views/search/FaceRecognitionHandler.tsx @@ -1,6 +1,5 @@ import * as faceapi from 'face-api.js'; import { FaceMatcher } from 'face-api.js'; -import { computed } from 'mobx'; import { Doc, DocListCast } from '../../../fields/Doc'; import { DocData } from '../../../fields/DocSymbols'; import { List } from '../../../fields/List'; @@ -12,28 +11,27 @@ import { DocumentManager } from '../../util/DocumentManager'; /** * A singleton class that handles face recognition and manages face Doc collections for each face found. * Displaying an image doc anywhere will trigger this class to test if the image contains any faces. - * If it does, each recognized face will be compared to a global set of faces (each is a face collection Doc - * that have already been found. If the face matches a face collection Doc, then it will be added to that + * If it does, each recognized face will be compared to a stored, global set of faces (each face is represented + * as a face collection Doc). If the face matches a face collection Doc, then it will be added to that * collection along with the numerical representation of the face, its face descriptor. * * Image Doc's that are added to one or more face collection Docs will be given these metadata fields: - * _Face - a nunerical representation of the Nth face found in the image - * _Faces - a list of all the numerical face representations found in the image (why is this needed?) + * _Face - a numerical representation of the Nth face found in the image + * _Faces - a list of all the numerical face representations found in the image. (TODO: this is inelegant as it duplicates each Face) * - * Face collection Doc's are created for each person identified and are stored in the Dashboard's faceDocument's list + * unique face Doc's are created for each person identified and are stored in the Dashboard's uniqueFaces field * - * Each Face collection Doc represents all the images found for that person. It has these fields: - * face_label - a string label for the person that was recognized (currently it's just a 'face#') + * Each unique face Doc represents a unique face and collects all matching face images for that person. It has these fields: + * face_label - a string label for the person that was recognized (TODO: currently it's just a 'face#') * face_descriptors - a list of all the face descriptors for different images of the person * face_docList - a list of all image Docs that contain a face for the person */ export class FaceRecognitionHandler { static _instance: FaceRecognitionHandler; private _loadedModels: boolean = false; - private _processingDocs: Set = new Set(); private _pendingLoadDocs: Doc[] = []; - private static imgDocFaceField = (imgDoc: Doc, faceDoc: Doc) => `${Doc.LayoutFieldKey(imgDoc)}_${FaceRecognitionHandler.FaceDocLabel(faceDoc)}`; + private static imgDocFaceField = (imgDoc: Doc, faceDoc: Doc) => `${Doc.LayoutFieldKey(imgDoc)}_${FaceRecognitionHandler.UniqueFaceLabel(faceDoc)}`; /** * initializes an image with an empty list of face descriptors * @param imgDoc image to initialize @@ -49,67 +47,82 @@ export class FaceRecognitionHandler { public static ImageDocFaceDescriptors = (imgDoc: Doc) => imgDoc[DocData][`${Doc.LayoutFieldKey(imgDoc)}_Faces`] as List>; /** - * Adds metadata to an image Doc describing a face found in the image + * Adds metadata to an image Doc associating it to a unique face that corresponds to a face found in the image * @param imgDoc image Doc containing faces - * @param faceDescriptor descriptor for the face found - * @param faceDoc face collection Doc containing the same face + * @param faceDescriptor descriptor for the face + * @param faceDoc unique face */ - public static ImageDocAddFace = (imgDoc: Doc, faceDescriptor: List, faceDoc: Doc) => { + public static ImageDocAssociateUniqueFace = (imgDoc: Doc, faceDescriptor: List, faceDoc: Doc) => { const faceFieldKey = FaceRecognitionHandler.imgDocFaceField(imgDoc, faceDoc); if (imgDoc[DocData][faceFieldKey]) { Cast(imgDoc[DocData][faceFieldKey], listSpec('number'), null).push(faceDescriptor as unknown as number); // items are lists of numbers, not numbers, but type system can't handle that } else { imgDoc[DocData][faceFieldKey] = new List>([faceDescriptor]); } + Cast(imgDoc[DocData][`${Doc.LayoutFieldKey(imgDoc)}_Faces`], listSpec('number'), null).push(faceDescriptor as unknown as number); + }; + + /** + * Removes metadata from an image Doc to deassociate it from a unique face + * @param imgDoc image Doc containing faces + * @param faceDoc unique face + */ + public static ImageDocDeassociateUniqueFace = (imgDoc: Doc, faceDoc: Doc) => { + // fill in.. }; /** * returns a list of all face collection Docs on the current dashboard * @returns face collection Doc list */ - public static FaceDocuments = () => DocListCast(Doc.ActiveDashboard?.[DocData].faceDocuments); + public static UniqueFaces = () => DocListCast(Doc.ActiveDashboard?.[DocData].uniqueFaces); - public static DeleteFaceDoc = (faceDoc: Doc) => Doc.ActiveDashboard && Doc.RemoveDocFromList(Doc.ActiveDashboard[DocData], 'faceDocuments', faceDoc); + /** + * Removes a unique face from the set of recognized unique faces + * @param faceDoc unique face Doc + * @returns + */ + public static DeleteUniqueFace = (faceDoc: Doc) => Doc.ActiveDashboard && Doc.RemoveDocFromList(Doc.ActiveDashboard[DocData], 'uniqueFaces', faceDoc); /** * returns the labels associated with a face collection Doc - * @param faceDoc the face collection Doc + * @param faceDoc unique face Doc * @returns label string */ - public static FaceDocLabel = (faceDoc: Doc) => StrCast(faceDoc[DocData].face_label); + public static UniqueFaceLabel = (faceDoc: Doc) => StrCast(faceDoc[DocData].face_label); /** - * Returns all the face descriptors associated with a face collection Doc - * @param faceDoc a face collection Doc + * Returns all the face descriptors associated with a unique face Doc + * @param faceDoc unique face Doc * @returns face descriptors */ - public static FaceDocDescriptors = (faceDoc: Doc) => faceDoc[DocData].face_descriptors as List>; + public static UniqueFaceDescriptors = (faceDoc: Doc) => faceDoc[DocData].face_descriptors as List>; /** - * Returns a list of all face image Docs associated with the face collection - * @param faceDoc a face collection Doc + * Returns a list of all face image Docs associated with a unique face Doc + * @param faceDoc unique face Doc * @returns image Docs */ - public static FaceDocFaces = (faceDoc: Doc) => DocListCast(faceDoc[DocData].face_docList); + public static UniqueFaceImages = (faceDoc: Doc) => DocListCast(faceDoc[DocData].face_images); /** - * Adds a face image to the list of faces in a face collection Doc, and updates the face collection's list of image descriptors + * Adds a face image to a unique face Doc, and updates the unique face's set of face image descriptors * @param img - image with faces to add to a face collection Doc * @param faceDescriptor - the face descriptor for the face in the image to add - * @param faceDoc - the face collection Doc + * @param faceDoc - unique face Doc */ - public static FaceDocAddImageDocFace = (img: Doc, faceDescriptor: List, faceDoc: Doc) => { - Doc.AddDocToList(faceDoc, 'face_docList', img); + public static UniqueFaceAddFaceImage = (img: Doc, faceDescriptor: List, faceDoc: Doc) => { + Doc.AddDocToList(faceDoc, 'face_images', img); Cast(faceDoc.face_descriptors, listSpec('number'), null).push(faceDescriptor as unknown as number); // items are lists of numbers, not numbers, but type system can't handle that }; /** - * Removes a face from a face Doc collection, and updates the face collection's list of image descriptors - * @param imgDoc - image with faces to remove from the face Doc collectoin - * @param faceDoc - the face Doc collection + * Removes a face from a unique Face Doc, and updates the unique face's set of face image descriptors + * @param imgDoc - image with faces to remove + * @param faceDoc - unique face Doc */ - public static FaceDocRemoveImageDocFace = (imgDoc: Doc, faceDoc: Doc) => { - Doc.RemoveDocFromList(faceDoc[DocData], 'face_docList', imgDoc); - faceDoc[DocData].face_descriptors = new List>(FaceRecognitionHandler.FaceDocDescriptors(faceDoc).filter(fd => !(imgDoc[DocData][FaceRecognitionHandler.imgDocFaceField(imgDoc, faceDoc)] as List>).includes(fd))); + public static UniqueFaceRemoveFaceImage = (imgDoc: Doc, faceDoc: Doc) => { + Doc.RemoveDocFromList(faceDoc[DocData], 'face_images', imgDoc); + faceDoc[DocData].face_descriptors = new List>(FaceRecognitionHandler.UniqueFaceDescriptors(faceDoc).filter(fd => !(imgDoc[DocData][FaceRecognitionHandler.imgDocFaceField(imgDoc, faceDoc)] as List>).includes(fd))); }; constructor() { @@ -118,10 +131,6 @@ export class FaceRecognitionHandler { DocumentManager.Instance.AddAnyViewRenderedCB(dv => FaceRecognitionHandler.Instance.classifyFacesInImage(dv.Document)); } - @computed get examinedFaceDocs() { - return DocListCast(Doc.UserDoc().examinedFaceDocs); - } - /** * Loads the face detection models. */ @@ -138,7 +147,27 @@ export class FaceRecognitionHandler { } /** - * When a document is added, look for matching face documents. + * Creates a new, empty unique face Doc + * @returns a unique face Doc + */ + createUniqueFaceDoc = (dashboard: Doc) => { + const faceDocNum = NumCast(dashboard.uniqueFaces_count) + 1; + dashboard.uniqueFaces_count = faceDocNum; // TODO: improve to a better name + + const uniqueFaceDoc = new Doc(); + uniqueFaceDoc.title = `Face ${faceDocNum}`; + uniqueFaceDoc.face = ''; // just to make prettyprinting look better + uniqueFaceDoc.face_label = `Face${faceDocNum}`; + uniqueFaceDoc.face_images = new List(); + uniqueFaceDoc.face_descriptors = new List>(); + + Doc.ActiveDashboard && Doc.AddDocToList(Doc.ActiveDashboard[DocData], 'uniqueFaces', uniqueFaceDoc); + return uniqueFaceDoc; + }; + + /** + * When a document is added, this finds faces in the images and tries to + * match them to existing unique faces, otherwise new unique face(s) are created. * @param imgDoc The document being analyzed. */ public classifyFacesInImage = async (imgDoc: Doc) => { @@ -154,12 +183,11 @@ export class FaceRecognitionHandler { const imgUrl = ImageCast(imgDoc[Doc.LayoutFieldKey(imgDoc)]); // If the doc isn't an image or currently already been examined or is being processed, stop examining the document. - if (!imgUrl || this.examinedFaceDocs.includes(imgDoc) || this._processingDocs.has(imgDoc)) { + if (!imgUrl || DocListCast(Doc.MyFaceCollection.examinedFaceDocs).includes(imgDoc)) { return; } + Doc.AddDocToList(Doc.MyFaceCollection, 'examinedFaceDocs', imgDoc); - // Mark the document as being processed. - this._processingDocs.add(imgDoc); FaceRecognitionHandler.initImageDocFaceDescriptors(imgDoc); // Get the image the document contains and analyze for faces. @@ -170,31 +198,12 @@ export class FaceRecognitionHandler { // For each face detected, find a match. for (const fd of imgDocFaceDescriptions) { - let faceDocMatch = this.findMatchingFaceDoc(fd.descriptor); const faceDescriptor = new List(Array.from(fd.descriptor)); - - if (faceDocMatch) { - FaceRecognitionHandler.FaceDocAddImageDocFace(imgDoc, faceDescriptor, faceDocMatch); - } else { - // If a matching Face Document has not been found, create a new Face Document. - Doc.UserDoc().faceDocNum = NumCast(Doc.UserDoc().faceDocNum) + 1; - - const newFaceDocument = new Doc(); - newFaceDocument.title = `Face ${Doc.UserDoc().faceDocNum}`; - newFaceDocument.face = ''; // just to make prettyprinting look better - newFaceDocument.face_label = `Face${Doc.UserDoc().faceDocNum}`; - newFaceDocument.face_docList = new List([imgDoc]); - newFaceDocument.face_descriptors = new List>([faceDescriptor]); - - Doc.AddDocToList(Doc.ActiveDashboard[DocData], 'faceDocuments', newFaceDocument); - faceDocMatch = newFaceDocument; - } - - // Assign a field in the document of the matching Face Document. - FaceRecognitionHandler.ImageDocAddFace(imgDoc, faceDescriptor, faceDocMatch); - Doc.AddDocToList(Doc.UserDoc(), 'examinedFaceDocs', imgDoc); + const matchedUniqueFace = this.findMatchingFaceDoc(fd.descriptor) ?? this.createUniqueFaceDoc(Doc.ActiveDashboard); + // Add image to unique face's image collection, and assign image metadata referencing unique face + FaceRecognitionHandler.UniqueFaceAddFaceImage(imgDoc, faceDescriptor, matchedUniqueFace); + FaceRecognitionHandler.ImageDocAssociateUniqueFace(imgDoc, faceDescriptor, matchedUniqueFace); } - this._processingDocs.delete(imgDoc); }; /** @@ -203,19 +212,19 @@ export class FaceRecognitionHandler { * @returns face Doc */ private findMatchingFaceDoc = (faceDescriptor: Float32Array) => { - if (!Doc.ActiveDashboard || FaceRecognitionHandler.FaceDocuments().length < 1) { + if (!Doc.ActiveDashboard || FaceRecognitionHandler.UniqueFaces().length < 1) { return undefined; } - const faceDescriptors = FaceRecognitionHandler.FaceDocuments().map(faceDoc => { - const float32Array = FaceRecognitionHandler.FaceDocDescriptors(faceDoc).map(fd => new Float32Array(Array.from(fd))); - return new faceapi.LabeledFaceDescriptors(FaceRecognitionHandler.FaceDocLabel(faceDoc), float32Array); + const faceDescriptors = FaceRecognitionHandler.UniqueFaces().map(faceDoc => { + const float32Array = FaceRecognitionHandler.UniqueFaceDescriptors(faceDoc).map(fd => new Float32Array(Array.from(fd))); + return new faceapi.LabeledFaceDescriptors(FaceRecognitionHandler.UniqueFaceLabel(faceDoc), float32Array); }); const faceMatcher = new FaceMatcher(faceDescriptors, 0.6); const match = faceMatcher.findBestMatch(faceDescriptor); if (match.label !== 'unknown') { - for (const faceDoc of FaceRecognitionHandler.FaceDocuments()) { - if (FaceRecognitionHandler.FaceDocLabel(faceDoc) === match.label) { + for (const faceDoc of FaceRecognitionHandler.UniqueFaces()) { + if (FaceRecognitionHandler.UniqueFaceLabel(faceDoc) === match.label) { return faceDoc; } } -- cgit v1.2.3-70-g09d2 From a1f90b7c3a99aff9366a353631ea963c778b4740 Mon Sep 17 00:00:00 2001 From: bobzel Date: Thu, 22 Aug 2024 11:16:39 -0400 Subject: fixing up removing faces from unique faces --- .../collectionFreeForm/FaceCollectionBox.tsx | 2 +- src/client/views/search/FaceRecognitionHandler.tsx | 21 ++++++++++++++++----- 2 files changed, 17 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/client/views/collections/collectionFreeForm/FaceCollectionBox.tsx b/src/client/views/collections/collectionFreeForm/FaceCollectionBox.tsx index 6005da6dd..d1db19e43 100644 --- a/src/client/views/collections/collectionFreeForm/FaceCollectionBox.tsx +++ b/src/client/views/collections/collectionFreeForm/FaceCollectionBox.tsx @@ -108,8 +108,8 @@ export class UniqueFaceView extends ObservableReactComponent { * @param imgDoc - image Doc to remove */ removeFaceImageFromUniqueFace = undoable((imgDoc: Doc) => { - FaceRecognitionHandler.ImageDocDeassociateUniqueFace(imgDoc, this._props.faceDoc); FaceRecognitionHandler.UniqueFaceRemoveFaceImage(imgDoc, this._props.faceDoc); + FaceRecognitionHandler.ImageDocDisassociateUniqueFace(imgDoc, this._props.faceDoc); }, 'remove doc from face'); render() { diff --git a/src/client/views/search/FaceRecognitionHandler.tsx b/src/client/views/search/FaceRecognitionHandler.tsx index c239c775c..487c35d90 100644 --- a/src/client/views/search/FaceRecognitionHandler.tsx +++ b/src/client/views/search/FaceRecognitionHandler.tsx @@ -46,6 +46,15 @@ export class FaceRecognitionHandler { */ public static ImageDocFaceDescriptors = (imgDoc: Doc) => imgDoc[DocData][`${Doc.LayoutFieldKey(imgDoc)}_Faces`] as List>; + /** + * Adds a face descriptor for a face found in an image + * @param imgDoc image Doc with face + * @param faceDescriptor descriptor of a face + */ + public static ImageDocAddFaceDescriptor = (imgDoc: Doc, faceDescriptor: List) => { + Cast(imgDoc[DocData][`${Doc.LayoutFieldKey(imgDoc)}_Faces`], listSpec('number'), null).push(faceDescriptor as unknown as number); + }; + /** * Adds metadata to an image Doc associating it to a unique face that corresponds to a face found in the image * @param imgDoc image Doc containing faces @@ -59,7 +68,6 @@ export class FaceRecognitionHandler { } else { imgDoc[DocData][faceFieldKey] = new List>([faceDescriptor]); } - Cast(imgDoc[DocData][`${Doc.LayoutFieldKey(imgDoc)}_Faces`], listSpec('number'), null).push(faceDescriptor as unknown as number); }; /** @@ -67,10 +75,10 @@ export class FaceRecognitionHandler { * @param imgDoc image Doc containing faces * @param faceDoc unique face */ - public static ImageDocDeassociateUniqueFace = (imgDoc: Doc, faceDoc: Doc) => { - // fill in.. + public static ImageDocDisassociateUniqueFace = (imgDoc: Doc, faceDoc: Doc) => { + const faceFieldKey = FaceRecognitionHandler.imgDocFaceField(imgDoc, faceDoc); + imgDoc[DocData][faceFieldKey] = undefined; }; - /** * returns a list of all face collection Docs on the current dashboard * @returns face collection Doc list @@ -122,7 +130,8 @@ export class FaceRecognitionHandler { */ public static UniqueFaceRemoveFaceImage = (imgDoc: Doc, faceDoc: Doc) => { Doc.RemoveDocFromList(faceDoc[DocData], 'face_images', imgDoc); - faceDoc[DocData].face_descriptors = new List>(FaceRecognitionHandler.UniqueFaceDescriptors(faceDoc).filter(fd => !(imgDoc[DocData][FaceRecognitionHandler.imgDocFaceField(imgDoc, faceDoc)] as List>).includes(fd))); + // TODO: remove face descriptor from images' list of face descriptors (below doesn't work) + // faceDoc[DocData].face_descriptors = new List>(FaceRecognitionHandler.UniqueFaceDescriptors(faceDoc).filter(fd => !(imgDoc[DocData][FaceRecognitionHandler.imgDocFaceField(imgDoc, faceDoc)] as List>).includes(fd))); }; constructor() { @@ -203,6 +212,8 @@ export class FaceRecognitionHandler { // Add image to unique face's image collection, and assign image metadata referencing unique face FaceRecognitionHandler.UniqueFaceAddFaceImage(imgDoc, faceDescriptor, matchedUniqueFace); FaceRecognitionHandler.ImageDocAssociateUniqueFace(imgDoc, faceDescriptor, matchedUniqueFace); + // save the descriptor for the image's list of faces + FaceRecognitionHandler.ImageDocAddFaceDescriptor(imgDoc, faceDescriptor); } }; -- cgit v1.2.3-70-g09d2 From abac2baf512a545714379fbef3623b46e3be20a8 Mon Sep 17 00:00:00 2001 From: geireann Date: Thu, 22 Aug 2024 13:38:03 -0400 Subject: changes to face recognition to store list of face docs , not descriptors on images. --- .../collectionFreeForm/FaceCollectionBox.tsx | 2 - src/client/views/search/FaceRecognitionHandler.tsx | 61 +++++++++------------- 2 files changed, 26 insertions(+), 37 deletions(-) (limited to 'src') diff --git a/src/client/views/collections/collectionFreeForm/FaceCollectionBox.tsx b/src/client/views/collections/collectionFreeForm/FaceCollectionBox.tsx index d1db19e43..46d90db86 100644 --- a/src/client/views/collections/collectionFreeForm/FaceCollectionBox.tsx +++ b/src/client/views/collections/collectionFreeForm/FaceCollectionBox.tsx @@ -80,7 +80,6 @@ export class UniqueFaceView extends ObservableReactComponent { // assign the face in the image that's closest to the face collection to be the face that's assigned to the collection if (face_match) { - FaceRecognitionHandler.ImageDocAssociateUniqueFace(imgDoc, face_match, this._props.faceDoc); FaceRecognitionHandler.UniqueFaceAddFaceImage(imgDoc, face_match, this._props.faceDoc); } } @@ -109,7 +108,6 @@ export class UniqueFaceView extends ObservableReactComponent { */ removeFaceImageFromUniqueFace = undoable((imgDoc: Doc) => { FaceRecognitionHandler.UniqueFaceRemoveFaceImage(imgDoc, this._props.faceDoc); - FaceRecognitionHandler.ImageDocDisassociateUniqueFace(imgDoc, this._props.faceDoc); }, 'remove doc from face'); render() { diff --git a/src/client/views/search/FaceRecognitionHandler.tsx b/src/client/views/search/FaceRecognitionHandler.tsx index 487c35d90..f00c3fdf1 100644 --- a/src/client/views/search/FaceRecognitionHandler.tsx +++ b/src/client/views/search/FaceRecognitionHandler.tsx @@ -16,8 +16,7 @@ import { DocumentManager } from '../../util/DocumentManager'; * collection along with the numerical representation of the face, its face descriptor. * * Image Doc's that are added to one or more face collection Docs will be given these metadata fields: - * _Face - a numerical representation of the Nth face found in the image - * _Faces - a list of all the numerical face representations found in the image. (TODO: this is inelegant as it duplicates each Face) + * _faceDescriptors - a list of all the numerical face representations found in the image. * * unique face Doc's are created for each person identified and are stored in the Dashboard's uniqueFaces field * @@ -31,20 +30,34 @@ export class FaceRecognitionHandler { private _loadedModels: boolean = false; private _pendingLoadDocs: Doc[] = []; - private static imgDocFaceField = (imgDoc: Doc, faceDoc: Doc) => `${Doc.LayoutFieldKey(imgDoc)}_${FaceRecognitionHandler.UniqueFaceLabel(faceDoc)}`; + + /** + * return the metadata field name where unique face Docs are stored + * @param imgDoc image with faces + * @returns name of field + */ + private static ImageDocFaceField = (imgDoc: Doc) => `${Doc.LayoutFieldKey(imgDoc)}_faces`; + + /** + * Returns an array of faceDocs for each face recognized in the image + * @param imgDoc image with faces + * @returns faceDoc array + */ + private static ImageDocFaces = (imgDoc: Doc) => DocListCast(imgDoc[`${Doc.LayoutFieldKey(imgDoc)}_faces`]); + /** * initializes an image with an empty list of face descriptors * @param imgDoc image to initialize */ private static initImageDocFaceDescriptors = (imgDoc: Doc) => { - imgDoc[DocData][`${Doc.LayoutFieldKey(imgDoc)}_Faces`] = new List>(); + imgDoc[DocData][`${Doc.LayoutFieldKey(imgDoc)}_faceDescriptors`] = new List>(); }; /** * returns the face descriptors for each face found on an image Doc * @param imgDoc * @returns list of face descriptors */ - public static ImageDocFaceDescriptors = (imgDoc: Doc) => imgDoc[DocData][`${Doc.LayoutFieldKey(imgDoc)}_Faces`] as List>; + public static ImageDocFaceDescriptors = (imgDoc: Doc) => imgDoc[DocData][`${Doc.LayoutFieldKey(imgDoc)}_faceDescriptors`] as List>; /** * Adds a face descriptor for a face found in an image @@ -52,33 +65,10 @@ export class FaceRecognitionHandler { * @param faceDescriptor descriptor of a face */ public static ImageDocAddFaceDescriptor = (imgDoc: Doc, faceDescriptor: List) => { - Cast(imgDoc[DocData][`${Doc.LayoutFieldKey(imgDoc)}_Faces`], listSpec('number'), null).push(faceDescriptor as unknown as number); + Cast(imgDoc[DocData][`${Doc.LayoutFieldKey(imgDoc)}_faceDescriptors`], listSpec('number'), null).push(faceDescriptor as unknown as number); }; - /** - * Adds metadata to an image Doc associating it to a unique face that corresponds to a face found in the image - * @param imgDoc image Doc containing faces - * @param faceDescriptor descriptor for the face - * @param faceDoc unique face - */ - public static ImageDocAssociateUniqueFace = (imgDoc: Doc, faceDescriptor: List, faceDoc: Doc) => { - const faceFieldKey = FaceRecognitionHandler.imgDocFaceField(imgDoc, faceDoc); - if (imgDoc[DocData][faceFieldKey]) { - Cast(imgDoc[DocData][faceFieldKey], listSpec('number'), null).push(faceDescriptor as unknown as number); // items are lists of numbers, not numbers, but type system can't handle that - } else { - imgDoc[DocData][faceFieldKey] = new List>([faceDescriptor]); - } - }; - /** - * Removes metadata from an image Doc to deassociate it from a unique face - * @param imgDoc image Doc containing faces - * @param faceDoc unique face - */ - public static ImageDocDisassociateUniqueFace = (imgDoc: Doc, faceDoc: Doc) => { - const faceFieldKey = FaceRecognitionHandler.imgDocFaceField(imgDoc, faceDoc); - imgDoc[DocData][faceFieldKey] = undefined; - }; /** * returns a list of all face collection Docs on the current dashboard * @returns face collection Doc list @@ -121,17 +111,19 @@ export class FaceRecognitionHandler { public static UniqueFaceAddFaceImage = (img: Doc, faceDescriptor: List, faceDoc: Doc) => { Doc.AddDocToList(faceDoc, 'face_images', img); Cast(faceDoc.face_descriptors, listSpec('number'), null).push(faceDescriptor as unknown as number); // items are lists of numbers, not numbers, but type system can't handle that + Doc.AddDocToList(img[DocData], FaceRecognitionHandler.ImageDocFaceField(img), faceDoc); }; /** * Removes a face from a unique Face Doc, and updates the unique face's set of face image descriptors - * @param imgDoc - image with faces to remove + * @param img - image with faces to remove * @param faceDoc - unique face Doc */ - public static UniqueFaceRemoveFaceImage = (imgDoc: Doc, faceDoc: Doc) => { - Doc.RemoveDocFromList(faceDoc[DocData], 'face_images', imgDoc); - // TODO: remove face descriptor from images' list of face descriptors (below doesn't work) - // faceDoc[DocData].face_descriptors = new List>(FaceRecognitionHandler.UniqueFaceDescriptors(faceDoc).filter(fd => !(imgDoc[DocData][FaceRecognitionHandler.imgDocFaceField(imgDoc, faceDoc)] as List>).includes(fd))); + public static UniqueFaceRemoveFaceImage = (img: Doc, faceDoc: Doc) => { + Doc.RemoveDocFromList(faceDoc[DocData], 'face_images', img); + const descriptorsEqual = (a:List, b:List) => a === b ? true : a.length === b.length ? a.every((element, index) => element === b[index]) : false; + faceDoc[DocData].face_descriptors = new List>(FaceRecognitionHandler.UniqueFaceDescriptors(faceDoc).filter(fd => !FaceRecognitionHandler.ImageDocFaceDescriptors(img).some(desc => descriptorsEqual(fd, desc)))); + Doc.RemoveDocFromList(img[DocData], FaceRecognitionHandler.ImageDocFaceField(img), faceDoc); }; constructor() { @@ -211,7 +203,6 @@ export class FaceRecognitionHandler { const matchedUniqueFace = this.findMatchingFaceDoc(fd.descriptor) ?? this.createUniqueFaceDoc(Doc.ActiveDashboard); // Add image to unique face's image collection, and assign image metadata referencing unique face FaceRecognitionHandler.UniqueFaceAddFaceImage(imgDoc, faceDescriptor, matchedUniqueFace); - FaceRecognitionHandler.ImageDocAssociateUniqueFace(imgDoc, faceDescriptor, matchedUniqueFace); // save the descriptor for the image's list of faces FaceRecognitionHandler.ImageDocAddFaceDescriptor(imgDoc, faceDescriptor); } -- cgit v1.2.3-70-g09d2 From f18978c507dd4c9c0940a1ce17daa2e7000bccdd Mon Sep 17 00:00:00 2001 From: bobzel Date: Thu, 22 Aug 2024 15:29:45 -0400 Subject: from last --- src/client/views/search/FaceRecognitionHandler.tsx | 116 ++++++++++----------- 1 file changed, 55 insertions(+), 61 deletions(-) (limited to 'src') diff --git a/src/client/views/search/FaceRecognitionHandler.tsx b/src/client/views/search/FaceRecognitionHandler.tsx index f00c3fdf1..9b97fdfbd 100644 --- a/src/client/views/search/FaceRecognitionHandler.tsx +++ b/src/client/views/search/FaceRecognitionHandler.tsx @@ -7,6 +7,7 @@ import { listSpec } from '../../../fields/Schema'; import { Cast, ImageCast, NumCast, StrCast } from '../../../fields/Types'; import { DocumentType } from '../../documents/DocumentTypes'; import { DocumentManager } from '../../util/DocumentManager'; +import { ImageField } from '../../../fields/URLField'; /** * A singleton class that handles face recognition and manages face Doc collections for each face found. @@ -16,7 +17,8 @@ import { DocumentManager } from '../../util/DocumentManager'; * collection along with the numerical representation of the face, its face descriptor. * * Image Doc's that are added to one or more face collection Docs will be given these metadata fields: - * _faceDescriptors - a list of all the numerical face representations found in the image. + * _faceDescriptors - list of all the numerical face representations found in the image. + * _faces - list of unique face Docs corresponding to recognized faces in the image. * * unique face Doc's are created for each person identified and are stored in the Dashboard's uniqueFaces field * @@ -27,14 +29,33 @@ import { DocumentManager } from '../../util/DocumentManager'; */ export class FaceRecognitionHandler { static _instance: FaceRecognitionHandler; - private _loadedModels: boolean = false; - private _pendingLoadDocs: Doc[] = []; + private _apiModelReady = false; + private _pendingAPIModelReadyDocs: Doc[] = []; + public static get Instance() { + return FaceRecognitionHandler._instance ?? new FaceRecognitionHandler(); + } + + /** + * Loads an image + */ + private static loadImage = (imgUrl: ImageField): Promise => { + const [name, type] = imgUrl.url.href.split('.'); + const imageURL = `${name}_o.${type}`; + + return new Promise((resolve, reject) => { + const img = new Image(); + img.crossOrigin = 'anonymous'; + img.onload = () => resolve(img); + img.onerror = err => reject(err); + img.src = imageURL; + }); + }; /** * return the metadata field name where unique face Docs are stored * @param imgDoc image with faces - * @returns name of field + * @returns name of field */ private static ImageDocFaceField = (imgDoc: Doc) => `${Doc.LayoutFieldKey(imgDoc)}_faces`; @@ -68,7 +89,6 @@ export class FaceRecognitionHandler { Cast(imgDoc[DocData][`${Doc.LayoutFieldKey(imgDoc)}_faceDescriptors`], listSpec('number'), null).push(faceDescriptor as unknown as number); }; - /** * returns a list of all face collection Docs on the current dashboard * @returns face collection Doc list @@ -103,7 +123,8 @@ export class FaceRecognitionHandler { public static UniqueFaceImages = (faceDoc: Doc) => DocListCast(faceDoc[DocData].face_images); /** - * Adds a face image to a unique face Doc, and updates the unique face's set of face image descriptors + * Adds a face image to a unique face Doc, adds the unique face Doc to the images list of reognized faces, + * and updates the unique face's set of face image descriptors * @param img - image with faces to add to a face collection Doc * @param faceDescriptor - the face descriptor for the face in the image to add * @param faceDoc - unique face Doc @@ -121,37 +142,33 @@ export class FaceRecognitionHandler { */ public static UniqueFaceRemoveFaceImage = (img: Doc, faceDoc: Doc) => { Doc.RemoveDocFromList(faceDoc[DocData], 'face_images', img); - const descriptorsEqual = (a:List, b:List) => a === b ? true : a.length === b.length ? a.every((element, index) => element === b[index]) : false; + const descriptorsEqual = (a: List, b: List) => (a === b ? true : a.length === b.length ? a.every((element, index) => element === b[index]) : false); faceDoc[DocData].face_descriptors = new List>(FaceRecognitionHandler.UniqueFaceDescriptors(faceDoc).filter(fd => !FaceRecognitionHandler.ImageDocFaceDescriptors(img).some(desc => descriptorsEqual(fd, desc)))); Doc.RemoveDocFromList(img[DocData], FaceRecognitionHandler.ImageDocFaceField(img), faceDoc); }; constructor() { FaceRecognitionHandler._instance = this; - this.loadModels().then(() => this._pendingLoadDocs.forEach(this.classifyFacesInImage)); + this.loadAPIModels().then(() => this._pendingAPIModelReadyDocs.forEach(this.classifyFacesInImage)); DocumentManager.Instance.AddAnyViewRenderedCB(dv => FaceRecognitionHandler.Instance.classifyFacesInImage(dv.Document)); } /** * Loads the face detection models. */ - loadModels = async () => { + private loadAPIModels = async () => { const MODEL_URL = `/models`; await faceapi.loadFaceDetectionModel(MODEL_URL); await faceapi.loadFaceLandmarkModel(MODEL_URL); await faceapi.loadFaceRecognitionModel(MODEL_URL); - this._loadedModels = true; + this._apiModelReady = true; }; - public static get Instance() { - return FaceRecognitionHandler._instance ?? new FaceRecognitionHandler(); - } - /** * Creates a new, empty unique face Doc * @returns a unique face Doc */ - createUniqueFaceDoc = (dashboard: Doc) => { + private createUniqueFaceDoc = (dashboard: Doc) => { const faceDocNum = NumCast(dashboard.uniqueFaces_count) + 1; dashboard.uniqueFaces_count = faceDocNum; // TODO: improve to a better name @@ -171,40 +188,30 @@ export class FaceRecognitionHandler { * match them to existing unique faces, otherwise new unique face(s) are created. * @param imgDoc The document being analyzed. */ - public classifyFacesInImage = async (imgDoc: Doc) => { - if (!this._loadedModels || !Doc.ActiveDashboard) { - this._pendingLoadDocs.push(imgDoc); - return; - } - - if (imgDoc.type === DocumentType.LOADING && !imgDoc.loadingError) { + private classifyFacesInImage = async (imgDoc: Doc) => { + const activeDashboard = Doc.ActiveDashboard; + if (!this._apiModelReady || !activeDashboard) { + this._pendingAPIModelReadyDocs.push(imgDoc); + } else if (imgDoc.type === DocumentType.LOADING && !imgDoc.loadingError) { setTimeout(() => this.classifyFacesInImage(imgDoc), 1000); - return; - } - - const imgUrl = ImageCast(imgDoc[Doc.LayoutFieldKey(imgDoc)]); - // If the doc isn't an image or currently already been examined or is being processed, stop examining the document. - if (!imgUrl || DocListCast(Doc.MyFaceCollection.examinedFaceDocs).includes(imgDoc)) { - return; - } - Doc.AddDocToList(Doc.MyFaceCollection, 'examinedFaceDocs', imgDoc); - - FaceRecognitionHandler.initImageDocFaceDescriptors(imgDoc); - - // Get the image the document contains and analyze for faces. - const [name, type] = imgUrl.url.href.split('.'); - const imageURL = `${name}_o.${type}`; - const img = await this.loadImage(imageURL); - const imgDocFaceDescriptions = await faceapi.detectAllFaces(img).withFaceLandmarks().withFaceDescriptors(); - - // For each face detected, find a match. - for (const fd of imgDocFaceDescriptions) { - const faceDescriptor = new List(Array.from(fd.descriptor)); - const matchedUniqueFace = this.findMatchingFaceDoc(fd.descriptor) ?? this.createUniqueFaceDoc(Doc.ActiveDashboard); - // Add image to unique face's image collection, and assign image metadata referencing unique face - FaceRecognitionHandler.UniqueFaceAddFaceImage(imgDoc, faceDescriptor, matchedUniqueFace); - // save the descriptor for the image's list of faces - FaceRecognitionHandler.ImageDocAddFaceDescriptor(imgDoc, faceDescriptor); + } else { + const imgUrl = ImageCast(imgDoc[Doc.LayoutFieldKey(imgDoc)]); + if (imgUrl && !DocListCast(Doc.MyFaceCollection.examinedFaceDocs).includes(imgDoc)) { // only examine Docs that have an image and that haven't already been examined. + Doc.AddDocToList(Doc.MyFaceCollection, 'examinedFaceDocs', imgDoc); + FaceRecognitionHandler.initImageDocFaceDescriptors(imgDoc); + FaceRecognitionHandler.loadImage(imgUrl).then( // load image and analyze faces + img => faceapi.detectAllFaces(img).withFaceLandmarks().withFaceDescriptors() + .then(imgDocFaceDescriptions => { // For each face detected, find a match. + for (const fd of imgDocFaceDescriptions) { + const faceDescriptor = new List(Array.from(fd.descriptor)); + FaceRecognitionHandler.ImageDocAddFaceDescriptor(imgDoc, faceDescriptor); // add face descriptor to image's list of descriptors + const matchedUniqueFace = this.findMatchingFaceDoc(fd.descriptor) ?? this.createUniqueFaceDoc(activeDashboard); + FaceRecognitionHandler.UniqueFaceAddFaceImage(imgDoc, faceDescriptor, matchedUniqueFace); // add image/faceDescriptor to matched unique face + } // + return imgDocFaceDescriptions; + }) + ); + } // prettier-ignore } }; @@ -233,17 +240,4 @@ export class FaceRecognitionHandler { } return undefined; }; - - /** - * Loads an image - */ - private loadImage = (src: string): Promise => { - return new Promise((resolve, reject) => { - const img = new Image(); - img.crossOrigin = 'anonymous'; - img.onload = () => resolve(img); - img.onerror = err => reject(err); - img.src = src; - }); - }; } -- cgit v1.2.3-70-g09d2 From c9c5514c0607dcacaf8b84ef4a7730a815451d98 Mon Sep 17 00:00:00 2001 From: bobzel Date: Thu, 22 Aug 2024 15:36:41 -0400 Subject: from last --- .../collectionFreeForm/FaceCollectionBox.tsx | 2 +- src/client/views/search/FaceRecognitionHandler.tsx | 52 +++++++++++----------- 2 files changed, 27 insertions(+), 27 deletions(-) (limited to 'src') diff --git a/src/client/views/collections/collectionFreeForm/FaceCollectionBox.tsx b/src/client/views/collections/collectionFreeForm/FaceCollectionBox.tsx index 46d90db86..de7c2c027 100644 --- a/src/client/views/collections/collectionFreeForm/FaceCollectionBox.tsx +++ b/src/client/views/collections/collectionFreeForm/FaceCollectionBox.tsx @@ -75,7 +75,7 @@ export class UniqueFaceView extends ObservableReactComponent { const match = faceMatcher.matchDescriptor(new Float32Array(Array.from(face))); return match.distance < prev.dist ? { dist: match.distance, face_match: face } : prev; }, - { dist: 1, face_match: new List() as Opt> } + { dist: 1, face_match: undefined as Opt> } ); // assign the face in the image that's closest to the face collection to be the face that's assigned to the collection diff --git a/src/client/views/search/FaceRecognitionHandler.tsx b/src/client/views/search/FaceRecognitionHandler.tsx index 9b97fdfbd..f5fc12a8d 100644 --- a/src/client/views/search/FaceRecognitionHandler.tsx +++ b/src/client/views/search/FaceRecognitionHandler.tsx @@ -183,6 +183,32 @@ export class FaceRecognitionHandler { return uniqueFaceDoc; }; + /** + * Finds the most similar matching Face Document to a face descriptor + * @param faceDescriptor face descriptor number list + * @returns face Doc + */ + private findMatchingFaceDoc = (faceDescriptor: Float32Array) => { + if (!Doc.ActiveDashboard || FaceRecognitionHandler.UniqueFaces().length < 1) { + return undefined; + } + + const faceDescriptors = FaceRecognitionHandler.UniqueFaces().map(faceDoc => { + const float32Array = FaceRecognitionHandler.UniqueFaceDescriptors(faceDoc).map(fd => new Float32Array(Array.from(fd))); + return new faceapi.LabeledFaceDescriptors(FaceRecognitionHandler.UniqueFaceLabel(faceDoc), float32Array); + }); + const faceMatcher = new FaceMatcher(faceDescriptors, 0.6); + const match = faceMatcher.findBestMatch(faceDescriptor); + if (match.label !== 'unknown') { + for (const faceDoc of FaceRecognitionHandler.UniqueFaces()) { + if (FaceRecognitionHandler.UniqueFaceLabel(faceDoc) === match.label) { + return faceDoc; + } + } + } + return undefined; + }; + /** * When a document is added, this finds faces in the images and tries to * match them to existing unique faces, otherwise new unique face(s) are created. @@ -214,30 +240,4 @@ export class FaceRecognitionHandler { } // prettier-ignore } }; - - /** - * Finds the most similar matching Face Document to a face descriptor - * @param faceDescriptor face descriptor number list - * @returns face Doc - */ - private findMatchingFaceDoc = (faceDescriptor: Float32Array) => { - if (!Doc.ActiveDashboard || FaceRecognitionHandler.UniqueFaces().length < 1) { - return undefined; - } - - const faceDescriptors = FaceRecognitionHandler.UniqueFaces().map(faceDoc => { - const float32Array = FaceRecognitionHandler.UniqueFaceDescriptors(faceDoc).map(fd => new Float32Array(Array.from(fd))); - return new faceapi.LabeledFaceDescriptors(FaceRecognitionHandler.UniqueFaceLabel(faceDoc), float32Array); - }); - const faceMatcher = new FaceMatcher(faceDescriptors, 0.6); - const match = faceMatcher.findBestMatch(faceDescriptor); - if (match.label !== 'unknown') { - for (const faceDoc of FaceRecognitionHandler.UniqueFaces()) { - if (FaceRecognitionHandler.UniqueFaceLabel(faceDoc) === match.label) { - return faceDoc; - } - } - } - return undefined; - }; } -- cgit v1.2.3-70-g09d2 From efb80649dc524d152b424c8c539e4fee33450403 Mon Sep 17 00:00:00 2001 From: bobzel Date: Thu, 22 Aug 2024 15:54:00 -0400 Subject: added '@' prefix syntax to show metadata field value in keywords box --- src/client/views/KeywordBox.tsx | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/client/views/KeywordBox.tsx b/src/client/views/KeywordBox.tsx index fc9c38a11..20cb63d66 100644 --- a/src/client/views/KeywordBox.tsx +++ b/src/client/views/KeywordBox.tsx @@ -13,6 +13,7 @@ import { DragManager } from '../util/DragManager'; import { SnappingManager } from '../util/SnappingManager'; import { DocumentView } from './nodes/DocumentView'; import { ObservableReactComponent } from './ObservableReactComponent'; +import { undoable } from '../util/UndoManager'; interface KeywordItemProps { doc: Doc; @@ -123,9 +124,18 @@ export class KeywordItem extends ObservableReactComponent { }; render() { + const keyword = this._props.keyword.replace(/^@/, ''); + const metadata = this._props.keyword.startsWith('@'); return (
- {this._props.keyword} + {metadata ? ( + + {keyword}  + {this._props.doc[keyword] as string}{' '} + + ) : ( + keyword + )} {this.props.isEditing && }
); @@ -218,7 +228,7 @@ export class KeywordBox extends ObservableReactComponent { * Adds the keyword to the document. * @param keyword */ - submitLabel = (keyword: string) => { + submitLabel = undoable((keyword: string) => { // If the active Dashboard does not have a keyword collection, create it. if (Doc.ActiveDashboard && !Doc.ActiveDashboard.myKeywordCollections) { Doc.ActiveDashboard.myKeywordCollections = new List(); @@ -261,7 +271,7 @@ export class KeywordBox extends ObservableReactComponent { this._props.doc![DocData][`${submittedLabel}`] = true; this._currentInput = ''; // Clear the input box } - }; + }, 'added doc label'); @action onInputChange = (e: React.ChangeEvent) => { -- cgit v1.2.3-70-g09d2 From add4926f62b397fc6c655be31a711dd7b83b469a Mon Sep 17 00:00:00 2001 From: bobzel Date: Fri, 23 Aug 2024 00:45:10 -0400 Subject: starting to cleanup keywordsBox --- src/client/views/KeywordBox.tsx | 390 +++++++++++++++++-------------------- src/client/views/StyleProvider.tsx | 8 +- 2 files changed, 180 insertions(+), 218 deletions(-) (limited to 'src') diff --git a/src/client/views/KeywordBox.tsx b/src/client/views/KeywordBox.tsx index 20cb63d66..703299ae6 100644 --- a/src/client/views/KeywordBox.tsx +++ b/src/client/views/KeywordBox.tsx @@ -3,17 +3,17 @@ import { action, computed, makeObservable, observable, reaction } from 'mobx'; import { observer } from 'mobx-react'; import React from 'react'; import { returnFalse, setupMoveUpEvents } from '../../ClientUtils'; -import { Doc, DocListCast } from '../../fields/Doc'; +import { Utils, emptyFunction } from '../../Utils'; +import { Doc, DocListCast, StrListCast } from '../../fields/Doc'; import { DocData } from '../../fields/DocSymbols'; import { List } from '../../fields/List'; import { NumCast, StrCast } from '../../fields/Types'; -import { emptyFunction, Utils } from '../../Utils'; import { DocumentType } from '../documents/DocumentTypes'; import { DragManager } from '../util/DragManager'; +import { SelectionManager } from '../util/SelectionManager'; import { SnappingManager } from '../util/SnappingManager'; -import { DocumentView } from './nodes/DocumentView'; -import { ObservableReactComponent } from './ObservableReactComponent'; import { undoable } from '../util/UndoManager'; +import { ObservableReactComponent } from './ObservableReactComponent'; interface KeywordItemProps { doc: Doc; @@ -28,69 +28,149 @@ interface KeywordItemProps { */ @observer export class KeywordItem extends ObservableReactComponent { - constructor(props: any) { - super(props); - makeObservable(this); - this.ref = React.createRef(); + /** + * return list of all Docs that collect Docs with specified keywords + */ + public static get AllKeywordCollections() { + return DocListCast(Doc.ActiveDashboard?.myKeywordCollections); } + /** + * Find Doc that collects all Docs with given keyword + * @param keyword keyword string + * @returns keyword collection Doc or undefined + */ + public static findKeywordCollectionDoc = (keyword: String) => KeywordItem.AllKeywordCollections.find(doc => doc.title === keyword); - private ref: React.RefObject; + /** + * Creates a Doc that collects Docs with the specified keyword + * @param keyword keyword string + * @returns collection Doc + */ + public static createKeywordCollectionDoc = (keyword: string) => { + const newKeywordCol = new Doc(); + newKeywordCol.title = keyword; + newKeywordCol.collections = new List(); + newKeywordCol[DocData].docs = new List(); + // If the active Dashboard does not have a keyword collection, create it. + if (Doc.ActiveDashboard) { + if (!Doc.ActiveDashboard.myKeywordCollections) Doc.ActiveDashboard.myKeywordCollections = new List(); + Doc.AddDocToList(Doc.ActiveDashboard, 'myKeywordCollections', newKeywordCol); + } + return newKeywordCol; + }; /** - * Gets the documents that a keyword is associated with. + * Gets all Docs that have the specified keyword + * @param keyword keyword string * @returns An array of documents that contain the keyword. */ - getKeywordCollectionDocs = () => { - for (const doc of DocListCast(Doc.ActiveDashboard?.myKeywordCollections)) { - if (doc.title === this._props.keyword) { - return doc[DocData].docs; + public static allDocsWithKeyword = (keyword: string) => DocListCast(KeywordItem.findKeywordCollectionDoc(keyword)?.[DocData].docs); + + /** + * Adds a keyword to the metadata of this document + * @param keyword keyword string + */ + public static addLabelToDoc = (doc: Doc, keyword: string) => { + // If the keyword collection is not in active Dashboard, add it as a new doc, with the keyword as its title. + const keywordCollection = KeywordItem.findKeywordCollectionDoc(keyword) ?? KeywordItem.createKeywordCollectionDoc(keyword); + + // If the document is of type COLLECTION, make it a smart collection, otherwise, add the keyword to the document. + if (doc.type === DocumentType.COL) { + Doc.AddDocToList(keywordCollection[DocData], 'collections', doc); + + // Iterate through the keyword Doc collections and add a copy of the document to each collection + for (const cdoc of DocListCast(keywordCollection[DocData].docs)) { + if (!DocListCast(doc[DocData].data).find(d => Doc.AreProtosEqual(d, cdoc))) { + const newEmbedding = Doc.MakeEmbedding(cdoc); + Doc.AddDocToList(doc[DocData], 'data', newEmbedding); + Doc.SetContainer(newEmbedding, doc); + } + } + } else { + // Add this document to the keyword's collection of associated documents. + Doc.AddDocToList(keywordCollection[DocData], 'docs', doc); + + // Iterate through the keyword document's collections and add a copy of the document to each collection + for (const collection of DocListCast(keywordCollection.collections)) { + if (!DocListCast(collection[DocData].data).find(d => Doc.AreProtosEqual(d, doc))) { + const newEmbedding = Doc.MakeEmbedding(doc); + Doc.AddDocToList(collection[DocData], 'data', newEmbedding); + Doc.SetContainer(newEmbedding, collection); + } } } - return null; + + if (!doc[DocData].data_labels) doc[DocData].data_labels = new List(); + (doc[DocData].data_labels as List).push(keyword); + doc[DocData][keyword] = true; }; + public static RemoveLabel = (doc: Doc, keyword: string, keywordDoc: Doc) => { + if (doc[DocData].data_labels) { + if (doc.type === DocumentType.COL) { + Doc.RemoveDocFromList(keywordDoc[DocData], 'collections', doc); + + for (const cur_doc of KeywordItem.allDocsWithKeyword(keyword)) { + doc[DocData].data = new List(DocListCast(doc[DocData].data).filter(d => !Doc.AreProtosEqual(cur_doc, d))); + } + } else { + Doc.RemoveDocFromList(keywordDoc[DocData], 'docs', doc); + + for (const collection of DocListCast(keywordDoc.collections)) { + collection[DocData].data = new List(DocListCast(collection[DocData].data).filter(d => !Doc.AreProtosEqual(doc, d))); + } + } + } + doc[DocData].data_labels = new List((doc[DocData].data_labels as List).filter(label => label !== keyword)); + doc[DocData][keyword] = undefined; + }; + + private _ref: React.RefObject; + + constructor(props: any) { + super(props); + makeObservable(this); + this._ref = React.createRef(); + } + /** * Creates a smart collection. * @returns */ createCollection = () => { // Get the documents that contain the keyword. - const selected = DocListCast(this.getKeywordCollectionDocs()!); - const newEmbeddings = selected.map(doc => Doc.MakeEmbedding(doc)); + const newEmbeddings = KeywordItem.allDocsWithKeyword(this._props.keyword).map(doc => Doc.MakeEmbedding(doc)); // Create a new collection and set up configurations. const newCollection = ((doc: Doc) => { const docData = doc[DocData]; docData.data = new List(newEmbeddings); docData.title = this._props.keyword; + docData.data_labels = new List([this._props.keyword]); + docData[`${this._props.keyword}`] = true; + docData.showLabels = true; doc._freeform_panX = doc._freeform_panY = 0; + doc._width = 900; + doc._height = 900; + doc.layout_fitWidth = true; return doc; })(Doc.MakeCopy(Doc.UserDoc().emptyCollection as Doc, true)); - newEmbeddings.forEach(embed => (embed.embedContainer = newCollection)); - newCollection._width = 900; - newCollection._height = 900; - newCollection.layout_fitWidth = true; + newEmbeddings.forEach(embed => Doc.SetContainer(embed, newCollection)); // Add the collection to the keyword document's list of associated smart collections. - this._props.keywordDoc.collections = new List([...DocListCast(this._props.keywordDoc.collections), newCollection]); - newCollection[DocData].data_labels = new List([this._props.keyword]); - newCollection[DocData][`${this._props.keyword}`] = true; - newCollection[DocData].showLabels = true; + Doc.AddDocToList(this._props.keywordDoc, 'collections', newCollection); return newCollection; }; @action handleDragStart = (e: React.PointerEvent) => { if (this._props.isEditing) { - const clone = this.ref.current?.cloneNode(true) as HTMLElement; - if (!clone) return; - setupMoveUpEvents( this, e, () => { const dragData = new DragManager.DocumentDragData([this.createCollection()]); - DragManager.StartDocumentDrag([this.ref.current!], dragData, e.clientX, e.clientY, {}); + DragManager.StartDocumentDrag([this._ref.current!], dragData, e.clientX, e.clientY, {}); return true; }, returnFalse, @@ -100,51 +180,34 @@ export class KeywordItem extends ObservableReactComponent { } }; - @action - removeLabel = () => { - if (this._props.doc[DocData].data_labels) { - if (this._props.doc.type === DocumentType.COL) { - const filtered_collections = new List(DocListCast(this._props.keywordDoc.collections).filter(doc => doc !== this._props.doc)); - this._props.keywordDoc.collections = filtered_collections; - - for (const cur_doc of DocListCast(this.getKeywordCollectionDocs()!, [])) { - this._props.doc[DocData].data = new List(DocListCast(this._props.doc[DocData].data).filter(doc => !Doc.AreProtosEqual(cur_doc, doc))); - } - } else { - const filtered_docs = new List(DocListCast(this.getKeywordCollectionDocs()!).filter(doc => doc !== this._props.doc)); - this._props.keywordDoc[DocData].docs = filtered_docs; - - for (const collection of DocListCast(this._props.keywordDoc.collections)) { - collection[DocData].data = new List(DocListCast(collection[DocData].data).filter(doc => !Doc.AreProtosEqual(this._props.doc, doc))); - } - } - } - this._props.doc[DocData].data_labels = (this._props.doc[DocData].data_labels as List).filter(label => label !== this._props.keyword) as List; - this._props.doc![DocData][`${this._props.keyword}`] = false; - }; - render() { const keyword = this._props.keyword.replace(/^@/, ''); const metadata = this._props.keyword.startsWith('@'); return ( -
+
{metadata ? ( {keyword}  - {this._props.doc[keyword] as string}{' '} + {this._props.doc[keyword] as string} ) : ( keyword )} - {this.props.isEditing && } + {this.props.isEditing && ( + KeywordItem.RemoveLabel(this._props.doc, this._props.keyword, this._props.keywordDoc), `remove label ${this._props.keyword}`)} + icon={'X'} + style={{ width: '8px', height: '8px', marginLeft: '10px' }} + /> + )}
); } } interface KeywordBoxProps { - doc: Doc; - isEditing: boolean; + Document: Doc; } /** @@ -152,76 +215,50 @@ interface KeywordBoxProps { */ @observer export class KeywordBox extends ObservableReactComponent { - @observable _currentInput: string = ''; - private height: number = 0; - private ref: React.RefObject; - - @computed - get currentScale() { - return NumCast((this._props.doc.embedContainer as Doc)?._freeform_scale, 1); - } - - @computed - get cur_height() { - return this.ref.current?.offsetHeight ? this.ref.current?.offsetHeight : 0; - } + private _height: number = 0; + private _ref: React.RefObject; constructor(props: any) { super(props); makeObservable(this); - this.ref = React.createRef(); + this._ref = React.createRef(); reaction( () => this.cur_height, () => { - this._props.doc[DocData].keywordHeight = this.height; + this._props.Document[DocData].keywordHeight = this._height; } ); } - componentDidMount(): void { - this.height = this.ref.current?.offsetHeight ? this.ref.current?.offsetHeight : 0; - this._props.doc[DocData].keywordHeight = this.height; - } + @observable _currentInput = ''; + @observable _isEditing = !StrListCast(this._props.Document[DocData].data_labels).length; - componentDidUpdate(prevProps: Readonly): void { - this.height = this.ref.current?.offsetHeight ? this.ref.current?.offsetHeight : 0; - this._props.doc[DocData].keywordHeight = this.height; + @computed get currentScale() { + return NumCast((this._props.Document.embedContainer as Doc)?._freeform_scale, 1); } - @action - setToEditing = () => { - this._props.isEditing = true; - }; + @computed get cur_height() { + return this._ref.current?.offsetHeight ?? 0; + } - @action - setToView = () => { - this._props.isEditing = false; - }; + @computed get isEditing() { + return this._isEditing && SelectionManager.Docs().includes(this._props.Document); + } - /** - * Gets the document associated with a keyword. - * @param keyword The keyword being searched for - * @returns A Doc containing keyword information - */ - getKeywordCollection = (keyword: string) => { - // Look for the keyword document. - for (const doc of DocListCast(Doc.ActiveDashboard!.myKeywordCollections)) { - if (doc.title === keyword) { - return doc; - } - } + componentDidMount() { + this._height = this._ref.current?.offsetHeight ?? 0; + this._props.Document[DocData].keywordHeight = this._height; + } - // If not contained, create a new document and add it to the active Dashboard's keyword list. - const keywordCollection = new Doc(); - keywordCollection.title = keyword; - keywordCollection[DocData].docs = new List(); - keywordCollection.collections = new List(); - if (Doc.ActiveDashboard) { - Doc.ActiveDashboard.myKeywordCollections = new List([...DocListCast(Doc.ActiveDashboard.myKeywordCollections), keywordCollection]); - } + componentDidUpdate(prevProps: Readonly): void { + this._height = this._ref.current?.offsetHeight ?? 0; + this._props.Document[DocData].keywordHeight = this._height; + } - return keywordCollection; + @action + setToEditing = () => { + this._isEditing = true; }; /** @@ -229,94 +266,42 @@ export class KeywordBox extends ObservableReactComponent { * @param keyword */ submitLabel = undoable((keyword: string) => { - // If the active Dashboard does not have a keyword collection, create it. - if (Doc.ActiveDashboard && !Doc.ActiveDashboard.myKeywordCollections) { - Doc.ActiveDashboard.myKeywordCollections = new List(); - } - const submittedLabel = keyword.trim(); - if (submittedLabel && !this._props.doc![DocData][`${submittedLabel}`]) { - // If the keyword collection is not in active Dashboard, add it as a new doc, with the keyword as its title. - const keywordCollection = this.getKeywordCollection(submittedLabel); - - // If the document has no keywords field, create the field. - if (!this._props.doc[DocData].data_labels) { - this._props.doc[DocData].data_labels = new List(); - } - - // If the document is of type COLLECTION, make it a smart collection, otherwise, add the keyword to the document. - if (this._props.doc.type === DocumentType.COL) { - keywordCollection.collections = new List([...DocListCast(keywordCollection.collections), this._props.doc]); - - // Iterate through the keyword document's collections and add a copy of the document to each collection - for (const doc of DocListCast(keywordCollection[DocData].docs)) { - const newEmbedding = Doc.MakeEmbedding(doc); - this._props.doc[DocData].data = new List([...DocListCast(this._props.doc[DocData].data), newEmbedding]); - newEmbedding.embedContainer = this._props.doc; - } - } else { - // Add this document to the keyword's collection of associated documents. - keywordCollection[DocData].docs = new List([...DocListCast(keywordCollection[DocData].docs), this._props.doc]); - - // Iterate through the keyword document's collections and add a copy of the document to each collection - for (const collection of DocListCast(keywordCollection.collections)) { - const newEmbedding = Doc.MakeEmbedding(this._props.doc); - collection[DocData].data = new List([...DocListCast(collection.data), newEmbedding]); - newEmbedding.embedContainer = collection; - } - } - - // Push the keyword to the document's keyword list field. - (this._props.doc![DocData].data_labels! as List).push(submittedLabel); - this._props.doc![DocData][`${submittedLabel}`] = true; + if (submittedLabel && !this._props.Document[DocData][submittedLabel]) { + KeywordItem.addLabelToDoc(this._props.Document, submittedLabel); this._currentInput = ''; // Clear the input box } }, 'added doc label'); - @action - onInputChange = (e: React.ChangeEvent) => { - this._currentInput = e.target.value; - }; - render() { - const keywordsList = this._props.doc[DocData].data_labels ? this._props.doc[DocData].data_labels : new List(); - const seldoc = DocumentView.SelectedDocs().lastElement(); - if (SnappingManager.IsDragging || !(seldoc === this._props.doc) || !this._props.isEditing) { - setTimeout( - action(() => { - if ((keywordsList as List).length === 0) { - this._props.doc[DocData].showLabels = false; - } - this.setToView(); - }) - ); - } + const keywordsList = StrListCast(this._props.Document[DocData].data_labels); - return ( + return !this._props.Document.showLabels ? null : (
-
+
- {(keywordsList as List).map(keyword => { - return ; + {keywordsList.map(keyword => { + const keywordDoc = KeywordItem.findKeywordCollectionDoc(keyword); + return !keywordDoc ? null : ; })}
- {this._props.isEditing ? ( + {this.isEditing ? (
(this._currentInput = e.target.value))} onKeyDown={e => { e.key === 'Enter' ? this.submitLabel(this._currentInput) : null; e.stopPropagation(); @@ -328,45 +313,28 @@ export class KeywordBox extends ObservableReactComponent { style={{ width: '100%', borderRadius: '5px' }} />
- {Doc.ActiveDashboard?.myKeywordCollections ? ( -
- {DocListCast(Doc.ActiveDashboard?.myKeywordCollections).map(doc => { - const keyword = StrCast(doc.title); - return ( -
- ) : ( -
- )} +
+ {KeywordItem.AllKeywordCollections.map(doc => { + const keyword = StrCast(doc.title); + return ( +
- { - if ((keywordsList as List).length === 0) { - this._props.doc[DocData].showLabels = false; - } else { - this.setToView(); - } - }} - icon={'x'} - style={{ width: '4px' }} - /> + {!keywordsList.length ? null : ( // + (this._isEditing = false))} icon="x" /> + )}
- ) : ( -
- )} + ) : null}
); diff --git a/src/client/views/StyleProvider.tsx b/src/client/views/StyleProvider.tsx index 374399445..1e80e7ee5 100644 --- a/src/client/views/StyleProvider.tsx +++ b/src/client/views/StyleProvider.tsx @@ -364,13 +364,7 @@ export function DefaultStyleProvider(doc: Opt, props: Opt ); }; - const keywords = () => { - if (doc && doc![DocData].showLabels && (!doc[DocData].data_labels || (doc[DocData].data_labels as List).length === 0)){ - return () - } else if (doc && doc![DocData].data_labels && doc![DocData].showLabels) { - return () - } - } + const keywords = () => doc ? : null; return ( <> {paint()} -- cgit v1.2.3-70-g09d2 From dc7bb2ff07139c45efd3bf66ace0042b76c91ccf Mon Sep 17 00:00:00 2001 From: bobzel Date: Fri, 23 Aug 2024 11:50:49 -0400 Subject: modified keywordsBox to use tags instead data_labels. made text #tags trigger keywords box. made keywords box fit contents. --- src/client/views/DocumentButtonBar.tsx | 10 +---- src/client/views/KeywordBox.tsx | 51 ++++++++++------------ src/client/views/StyleProvider.tsx | 5 +-- .../views/nodes/formattedText/RichTextRules.ts | 3 +- 4 files changed, 30 insertions(+), 39 deletions(-) (limited to 'src') diff --git a/src/client/views/DocumentButtonBar.tsx b/src/client/views/DocumentButtonBar.tsx index d42a18e4e..eb157b9ab 100644 --- a/src/client/views/DocumentButtonBar.tsx +++ b/src/client/views/DocumentButtonBar.tsx @@ -282,15 +282,9 @@ export class DocumentButtonBar extends ObservableReactComponent<{ views: () => ( @computed get keywordButton() { - const targetDoc = this.view0?.Document; - return !targetDoc ? null : ( + return !DocumentView.Selected().length ? null : ( Open keyword menu
}> -
{ - targetDoc[DocData].showLabels = !targetDoc[DocData].showLabels; - }}> +
DocumentView.Selected().map(dv => (dv.dataDoc.showLabels = !dv.dataDoc.showLabels))}>
diff --git a/src/client/views/KeywordBox.tsx b/src/client/views/KeywordBox.tsx index 703299ae6..1460501db 100644 --- a/src/client/views/KeywordBox.tsx +++ b/src/client/views/KeywordBox.tsx @@ -18,7 +18,7 @@ import { ObservableReactComponent } from './ObservableReactComponent'; interface KeywordItemProps { doc: Doc; keyword: string; - keywordDoc: Doc; + keywordDoc?: Doc; setToEditing: () => void; isEditing: boolean; } @@ -100,29 +100,28 @@ export class KeywordItem extends ObservableReactComponent { } } - if (!doc[DocData].data_labels) doc[DocData].data_labels = new List(); - (doc[DocData].data_labels as List).push(keyword); - doc[DocData][keyword] = true; + if (!doc[DocData].tags) doc[DocData].tags = new List(); + const tagList = doc[DocData].tags as List; + if (!tagList.includes(keyword)) tagList.push(keyword); }; - public static RemoveLabel = (doc: Doc, keyword: string, keywordDoc: Doc) => { - if (doc[DocData].data_labels) { + public static RemoveLabel = (doc: Doc, keyword: string, keywordDoc?: Doc) => { + if (doc[DocData].tags) { if (doc.type === DocumentType.COL) { - Doc.RemoveDocFromList(keywordDoc[DocData], 'collections', doc); + keywordDoc && Doc.RemoveDocFromList(keywordDoc[DocData], 'collections', doc); for (const cur_doc of KeywordItem.allDocsWithKeyword(keyword)) { doc[DocData].data = new List(DocListCast(doc[DocData].data).filter(d => !Doc.AreProtosEqual(cur_doc, d))); } } else { - Doc.RemoveDocFromList(keywordDoc[DocData], 'docs', doc); + keywordDoc && Doc.RemoveDocFromList(keywordDoc[DocData], 'docs', doc); - for (const collection of DocListCast(keywordDoc.collections)) { + for (const collection of DocListCast(keywordDoc?.collections)) { collection[DocData].data = new List(DocListCast(collection[DocData].data).filter(d => !Doc.AreProtosEqual(doc, d))); } } } - doc[DocData].data_labels = new List((doc[DocData].data_labels as List).filter(label => label !== keyword)); - doc[DocData][keyword] = undefined; + doc[DocData].tags = new List((doc[DocData].tags as List).filter(label => label !== keyword)); }; private _ref: React.RefObject; @@ -146,9 +145,9 @@ export class KeywordItem extends ObservableReactComponent { const docData = doc[DocData]; docData.data = new List(newEmbeddings); docData.title = this._props.keyword; - docData.data_labels = new List([this._props.keyword]); - docData[`${this._props.keyword}`] = true; + docData.tags = new List([this._props.keyword]); docData.showLabels = true; + docData.freeform_fitContentsToBox = true; doc._freeform_panX = doc._freeform_panY = 0; doc._width = 900; doc._height = 900; @@ -158,7 +157,7 @@ export class KeywordItem extends ObservableReactComponent { newEmbeddings.forEach(embed => Doc.SetContainer(embed, newCollection)); // Add the collection to the keyword document's list of associated smart collections. - Doc.AddDocToList(this._props.keywordDoc, 'collections', newCollection); + this._props.keywordDoc && Doc.AddDocToList(this._props.keywordDoc, 'collections', newCollection); return newCollection; }; @@ -181,14 +180,15 @@ export class KeywordItem extends ObservableReactComponent { }; render() { - const keyword = this._props.keyword.replace(/^@/, ''); - const metadata = this._props.keyword.startsWith('@'); + setTimeout(() => KeywordItem.addLabelToDoc(this._props.doc, this._props.keyword)); // bcz: hack to make sure that Docs are added to their keyword Doc collection since metadata can get set anywhere without a guard triggering an add to the collection + const keyword = this._props.keyword.replace(/^#/, ''); + const metadata = keyword.startsWith('@') ? keyword.replace(/^@/, '') : ''; return (
{metadata ? ( {keyword}  - {this._props.doc[keyword] as string} + {this._props.doc[metadata] as string} ) : ( keyword @@ -232,7 +232,7 @@ export class KeywordBox extends ObservableReactComponent { } @observable _currentInput = ''; - @observable _isEditing = !StrListCast(this._props.Document[DocData].data_labels).length; + @observable _isEditing = !StrListCast(this._props.Document[DocData].tags).length; @computed get currentScale() { return NumCast((this._props.Document.embedContainer as Doc)?._freeform_scale, 1); @@ -267,14 +267,12 @@ export class KeywordBox extends ObservableReactComponent { */ submitLabel = undoable((keyword: string) => { const submittedLabel = keyword.trim(); - if (submittedLabel && !this._props.Document[DocData][submittedLabel]) { - KeywordItem.addLabelToDoc(this._props.Document, submittedLabel); - this._currentInput = ''; // Clear the input box - } + submittedLabel && KeywordItem.addLabelToDoc(this._props.Document, '#' + submittedLabel.replace(/^#/, '')); + this._currentInput = ''; // Clear the input box }, 'added doc label'); render() { - const keywordsList = StrListCast(this._props.Document[DocData].data_labels); + const keywordsList = StrListCast(this._props.Document[DocData].tags); return !this._props.Document.showLabels ? null : (
{ }}>
- {keywordsList.map(keyword => { - const keywordDoc = KeywordItem.findKeywordCollectionDoc(keyword); - return !keywordDoc ? null : ; - })} + {keywordsList.map(keyword => ( + + ))}
{this.isEditing ? (
diff --git a/src/client/views/StyleProvider.tsx b/src/client/views/StyleProvider.tsx index 1e80e7ee5..0fb4f7dd1 100644 --- a/src/client/views/StyleProvider.tsx +++ b/src/client/views/StyleProvider.tsx @@ -9,9 +9,7 @@ import { BsArrowDown, BsArrowDownUp, BsArrowUp } from 'react-icons/bs'; import { FaFilter } from 'react-icons/fa'; import { ClientUtils, DashColor, lightOrDark } from '../../ClientUtils'; import { Doc, Opt, StrListCast } from '../../fields/Doc'; -import { DocData } from '../../fields/DocSymbols'; import { Id } from '../../fields/FieldSymbols'; -import { List } from '../../fields/List'; import { ScriptField } from '../../fields/ScriptField'; import { BoolCast, Cast, DocCast, ImageCast, NumCast, ScriptCast, StrCast } from '../../fields/Types'; import { AudioAnnoState } from '../../server/SharedMediaTypes'; @@ -22,6 +20,7 @@ import { undoable, UndoManager } from '../util/UndoManager'; import { TreeSort } from './collections/TreeSort'; import { Colors } from './global/globalEnums'; import { KeywordBox } from './KeywordBox'; +import { CollectionFreeFormDocumentView } from './nodes/CollectionFreeFormDocumentView'; import { DocumentView, DocumentViewProps } from './nodes/DocumentView'; import { FieldViewProps } from './nodes/FieldView'; import { StyleProp } from './StyleProp'; @@ -364,7 +363,7 @@ export function DefaultStyleProvider(doc: Opt, props: Opt ); }; - const keywords = () => doc ? : null; + const keywords = () => doc && CollectionFreeFormDocumentView.from(props?.DocumentView?.()) ? : null; return ( <> {paint()} diff --git a/src/client/views/nodes/formattedText/RichTextRules.ts b/src/client/views/nodes/formattedText/RichTextRules.ts index 39f589b1e..79c118490 100644 --- a/src/client/views/nodes/formattedText/RichTextRules.ts +++ b/src/client/views/nodes/formattedText/RichTextRules.ts @@ -396,7 +396,7 @@ export class RichTextRules { }), // create an inline view of a tag stored under the '#' field - new InputRule(/#([a-zA-Z_-]+[a-zA-Z_\-0-9]*)\s$/, (state, match, start, end) => { + new InputRule(/#(@?[a-zA-Z_-]+[a-zA-Z_\-0-9]*)\s$/, (state, match, start, end) => { const tag = match[1]; if (!tag) return state.tr; // this.Document[DocData]['#' + tag] = '#' + tag; @@ -404,6 +404,7 @@ export class RichTextRules { if (!tags.includes(tag)) { tags.push(tag); this.Document[DocData].tags = new List(tags); + this.Document[DocData].showLabels = true; } const fieldView = state.schema.nodes.dashField.create({ fieldKey: '#' + tag }); return state.tr -- cgit v1.2.3-70-g09d2 From ac580dab29fc5867680a54b2fbfd68f9d4e2a895 Mon Sep 17 00:00:00 2001 From: bobzel Date: Fri, 23 Aug 2024 15:23:07 -0400 Subject: changed keyword items to use a doc symbol for storage instead of a field. fixed sizing of docDecoartions around keyeword box to dynaically update accurately. Aded expand/collapse button for editing keywords --- src/client/views/DocumentDecorations.tsx | 4 +- src/client/views/KeywordBox.tsx | 91 ++++++++++++-------------------- src/client/views/StyleProvider.scss | 5 +- src/client/views/StyleProvider.tsx | 2 +- src/fields/Doc.ts | 4 +- src/fields/DocSymbols.ts | 3 ++ 6 files changed, 47 insertions(+), 62 deletions(-) (limited to 'src') diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index ce1138b7a..19c4a097b 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -9,7 +9,7 @@ import { lightOrDark, returnFalse, setupMoveUpEvents } from '../../ClientUtils'; import { Utils, emptyFunction, numberValue } from '../../Utils'; import { DateField } from '../../fields/DateField'; import { Doc, DocListCast, Field, FieldType, HierarchyMapping, ReverseHierarchyMap } from '../../fields/Doc'; -import { AclAdmin, AclAugment, AclEdit, DocData } from '../../fields/DocSymbols'; +import { AclAdmin, AclAugment, AclEdit, DocData, KeywordsHeight } from '../../fields/DocSymbols'; import { Id } from '../../fields/FieldSymbols'; import { InkField } from '../../fields/InkField'; import { ScriptField } from '../../fields/ScriptField'; @@ -835,7 +835,7 @@ export class DocumentDecorations extends ObservableReactComponent DocumentView.Selected()} /> diff --git a/src/client/views/KeywordBox.tsx b/src/client/views/KeywordBox.tsx index 1460501db..841c5394b 100644 --- a/src/client/views/KeywordBox.tsx +++ b/src/client/views/KeywordBox.tsx @@ -1,19 +1,22 @@ +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { Button, Colors, IconButton } from 'browndash-components'; -import { action, computed, makeObservable, observable, reaction } from 'mobx'; +import { action, computed, makeObservable, observable } from 'mobx'; import { observer } from 'mobx-react'; import React from 'react'; +import ResizeObserver from 'resize-observer-polyfill'; import { returnFalse, setupMoveUpEvents } from '../../ClientUtils'; import { Utils, emptyFunction } from '../../Utils'; import { Doc, DocListCast, StrListCast } from '../../fields/Doc'; -import { DocData } from '../../fields/DocSymbols'; +import { DocData, KeywordsHeight } from '../../fields/DocSymbols'; import { List } from '../../fields/List'; import { NumCast, StrCast } from '../../fields/Types'; import { DocumentType } from '../documents/DocumentTypes'; import { DragManager } from '../util/DragManager'; -import { SelectionManager } from '../util/SelectionManager'; import { SnappingManager } from '../util/SnappingManager'; import { undoable } from '../util/UndoManager'; import { ObservableReactComponent } from './ObservableReactComponent'; +import { DocumentView } from './nodes/DocumentView'; +import { FontIconBox } from './nodes/FontIconBox/FontIconBox'; interface KeywordItemProps { doc: Doc; @@ -163,20 +166,18 @@ export class KeywordItem extends ObservableReactComponent { @action handleDragStart = (e: React.PointerEvent) => { - if (this._props.isEditing) { - setupMoveUpEvents( - this, - e, - () => { - const dragData = new DragManager.DocumentDragData([this.createCollection()]); - DragManager.StartDocumentDrag([this._ref.current!], dragData, e.clientX, e.clientY, {}); - return true; - }, - returnFalse, - emptyFunction - ); - e.preventDefault(); - } + setupMoveUpEvents( + this, + e, + () => { + const dragData = new DragManager.DocumentDragData([this.createCollection()]); + DragManager.StartDocumentDrag([this._ref.current!], dragData, e.clientX, e.clientY, {}); + return true; + }, + returnFalse, + emptyFunction + ); + e.preventDefault(); }; render() { @@ -197,7 +198,7 @@ export class KeywordItem extends ObservableReactComponent { KeywordItem.RemoveLabel(this._props.doc, this._props.keyword, this._props.keywordDoc), `remove label ${this._props.keyword}`)} - icon={'X'} + icon={} style={{ width: '8px', height: '8px', marginLeft: '10px' }} /> )} @@ -207,7 +208,7 @@ export class KeywordItem extends ObservableReactComponent { } interface KeywordBoxProps { - Document: Doc; + View: DocumentView; } /** @@ -215,50 +216,28 @@ interface KeywordBoxProps { */ @observer export class KeywordBox extends ObservableReactComponent { - private _height: number = 0; private _ref: React.RefObject; constructor(props: any) { super(props); makeObservable(this); this._ref = React.createRef(); - - reaction( - () => this.cur_height, - () => { - this._props.Document[DocData].keywordHeight = this._height; - } - ); } @observable _currentInput = ''; - @observable _isEditing = !StrListCast(this._props.Document[DocData].tags).length; + @observable _isEditing = !StrListCast(this._props.View.dataDoc.tags).length; @computed get currentScale() { - return NumCast((this._props.Document.embedContainer as Doc)?._freeform_scale, 1); + return NumCast((this._props.View.Document.embedContainer as Doc)?._freeform_scale, 1); } - - @computed get cur_height() { - return this._ref.current?.offsetHeight ?? 0; - } - @computed get isEditing() { - return this._isEditing && SelectionManager.Docs().includes(this._props.Document); - } - - componentDidMount() { - this._height = this._ref.current?.offsetHeight ?? 0; - this._props.Document[DocData].keywordHeight = this._height; - } - - componentDidUpdate(prevProps: Readonly): void { - this._height = this._ref.current?.offsetHeight ?? 0; - this._props.Document[DocData].keywordHeight = this._height; + return this._isEditing && DocumentView.SelectedDocs().includes(this._props.View.Document); } @action - setToEditing = () => { - this._isEditing = true; + setToEditing = (editing = true) => { + this._isEditing = editing; + editing && this._props.View.select(false); }; /** @@ -267,17 +246,17 @@ export class KeywordBox extends ObservableReactComponent { */ submitLabel = undoable((keyword: string) => { const submittedLabel = keyword.trim(); - submittedLabel && KeywordItem.addLabelToDoc(this._props.Document, '#' + submittedLabel.replace(/^#/, '')); + submittedLabel && KeywordItem.addLabelToDoc(this._props.View.Document, '#' + submittedLabel.replace(/^#/, '')); this._currentInput = ''; // Clear the input box }, 'added doc label'); render() { - const keywordsList = StrListCast(this._props.Document[DocData].tags); + const keywordsList = StrListCast(this._props.View.dataDoc.tags); - return !this._props.Document.showLabels ? null : ( + return !this._props.View.Document.showLabels ? null : (
r && new ResizeObserver(action(() => (this._props.View.Document[KeywordsHeight] = r?.getBoundingClientRect().height ?? 0))).observe(r)} style={{ transformOrigin: 'top left', maxWidth: `${100 * this.currentScale}%`, @@ -288,8 +267,11 @@ export class KeywordBox extends ObservableReactComponent { }}>
+ {!keywordsList.length ? null : ( // + this.setToEditing(!this._isEditing)} icon={} /> + )} {keywordsList.map(keyword => ( - + ))}
{this.isEditing ? ( @@ -325,11 +307,6 @@ export class KeywordBox extends ObservableReactComponent { ); })}
-
- {!keywordsList.length ? null : ( // - (this._isEditing = false))} icon="x" /> - )} -
) : null}
diff --git a/src/client/views/StyleProvider.scss b/src/client/views/StyleProvider.scss index 1d41697f5..6f6939d54 100644 --- a/src/client/views/StyleProvider.scss +++ b/src/client/views/StyleProvider.scss @@ -65,10 +65,13 @@ .keywords-list { display: flex; flex-wrap: wrap; + .iconButton-container { + min-height: unset !important; + } } .keyword { - padding: 5px 5px; + padding: 1px 5px; background-color: lightblue; border: 1px solid black; border-radius: 5px; diff --git a/src/client/views/StyleProvider.tsx b/src/client/views/StyleProvider.tsx index 0fb4f7dd1..a841ec63a 100644 --- a/src/client/views/StyleProvider.tsx +++ b/src/client/views/StyleProvider.tsx @@ -363,7 +363,7 @@ export function DefaultStyleProvider(doc: Opt, props: Opt ); }; - const keywords = () => doc && CollectionFreeFormDocumentView.from(props?.DocumentView?.()) ? : null; + const keywords = () => props?.DocumentView?.() && CollectionFreeFormDocumentView.from(props.DocumentView()) ? : null; return ( <> {paint()} diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts index ffb5aab79..f246f49e5 100644 --- a/src/fields/Doc.ts +++ b/src/fields/Doc.ts @@ -11,7 +11,7 @@ import { ClientUtils, incrementTitleCopy } from '../ClientUtils'; import { AclAdmin, AclAugment, AclEdit, AclPrivate, AclReadonly, Animation, AudioPlay, Brushed, CachedUpdates, DirectLinks, DocAcl, DocCss, DocData, DocLayout, DocViews, FieldKeys, FieldTuples, ForceServerWrite, Height, Highlight, - Initializing, Self, SelfProxy, TransitionTimer, UpdatingFromServer, Width + Initializing, KeywordsHeight, Self, SelfProxy, TransitionTimer, UpdatingFromServer, Width } from './DocSymbols'; // prettier-ignore import { Copy, FieldChanged, HandleUpdate, Id, Parent, ToJavascriptString, ToScriptString, ToString } from './FieldSymbols'; import { InkTool } from './InkField'; @@ -303,6 +303,7 @@ export class Doc extends RefField { Height, Highlight, Initializing, + KeywordsHeight, Self, SelfProxy, UpdatingFromServer, @@ -368,6 +369,7 @@ export class Doc extends RefField { @observable public [Highlight]: boolean = false; @observable public [Brushed]: boolean = false; @observable public [DocViews] = new ObservableSet(); + @observable public [KeywordsHeight]: number = 0; private [Self] = this; private [SelfProxy]: Doc; diff --git a/src/fields/DocSymbols.ts b/src/fields/DocSymbols.ts index 837fcc90e..9e091ab29 100644 --- a/src/fields/DocSymbols.ts +++ b/src/fields/DocSymbols.ts @@ -1,3 +1,5 @@ +// NOTE: These symbols must be added to Doc.ts constructor !! + // Symbols for fundamental Doc operations such as: permissions, field and proxy access and server interactions export const AclPrivate = Symbol('DocAclOwnerOnly'); export const AclReadonly = Symbol('DocAclReadOnly'); @@ -30,5 +32,6 @@ export const DocViews = Symbol('DocViews'); export const Brushed = Symbol('DocBrushed'); export const DocCss = Symbol('DocCss'); export const TransitionTimer = Symbol('DocTransitionTimer'); +export const KeywordsHeight = Symbol('DocKeywordsHeight'); export const DashVersion = 'v0.8.0'; -- cgit v1.2.3-70-g09d2 From a52cda0a098716c24b3c6aafe23d2bd9267c72d9 Mon Sep 17 00:00:00 2001 From: bobzel Date: Mon, 26 Aug 2024 10:43:43 -0400 Subject: moved KeywordsBox to TagsView. changed imagellable to use tags --- src/client/documents/Documents.ts | 8 +- src/client/views/DocumentButtonBar.tsx | 2 +- src/client/views/DocumentDecorations.tsx | 6 +- src/client/views/KeywordBox.tsx | 316 ------------------- src/client/views/StyleProvider.scss | 64 ---- src/client/views/StyleProvider.tsx | 6 +- src/client/views/TagsView.scss | 63 ++++ src/client/views/TagsView.tsx | 344 +++++++++++++++++++++ .../collectionFreeForm/ImageLabelBox.tsx | 58 ++-- src/client/views/nodes/DocumentView.tsx | 1 + .../views/nodes/formattedText/RichTextRules.ts | 2 +- src/fields/Doc.ts | 4 +- src/fields/DocSymbols.ts | 1 - 13 files changed, 447 insertions(+), 428 deletions(-) delete mode 100644 src/client/views/KeywordBox.tsx create mode 100644 src/client/views/TagsView.scss create mode 100644 src/client/views/TagsView.tsx (limited to 'src') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 6b5469cca..c0e4e961c 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -43,7 +43,7 @@ export class FInfo { description: string = ''; readOnly: boolean = false; fieldType?: FInfoFieldType; - values?: FieldType[] | Map; + values?: FieldType[]; filterable?: boolean = true; // can be used as a Filter in FilterPanel // format?: string; // format to display values (e.g, decimal places, $, etc) @@ -144,10 +144,6 @@ class ListInfo extends FInfo { fieldType? = FInfoFieldType.list; values?: List[] = []; } -class MapInfo extends FInfo { - fieldType? = FInfoFieldType.map; - values?: Map = new Map(); -} type BOOLt = BoolInfo | boolean; type NUMt = NumInfo | number; type STRt = StrInfo | string; @@ -160,7 +156,6 @@ type COLLt = CTypeInfo | CollectionViewType; type DROPt = DAInfo | dropActionType; type DATEt = DateInfo | number; type DTYPEt = DTypeInfo | string; -type MAPt = MapInfo | Map; export class DocumentOptions { // coordinate and dimensions depending on view x?: NUMt = new NumInfo('horizontal coordinate in freeform view', false); @@ -489,7 +484,6 @@ export class DocumentOptions { cardSort?: STRt = new StrInfo('way cards are sorted in deck view'); cardSort_customField?: STRt = new StrInfo('field key used for sorting cards'); cardSort_visibleSortGroups?: List; // which sorting values are being filtered (shown) - keywords?: MAPt = new MapInfo('keywords', true); } export const DocOptions = new DocumentOptions(); diff --git a/src/client/views/DocumentButtonBar.tsx b/src/client/views/DocumentButtonBar.tsx index eb157b9ab..58b7f207c 100644 --- a/src/client/views/DocumentButtonBar.tsx +++ b/src/client/views/DocumentButtonBar.tsx @@ -284,7 +284,7 @@ export class DocumentButtonBar extends ObservableReactComponent<{ views: () => ( get keywordButton() { return !DocumentView.Selected().length ? null : ( Open keyword menu
}> -
DocumentView.Selected().map(dv => (dv.dataDoc.showLabels = !dv.dataDoc.showLabels))}> +
DocumentView.Selected().map(dv => (dv.dataDoc.showTags = !dv.dataDoc.showTags))}>
diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index 19c4a097b..da35459bb 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -1,3 +1,4 @@ +import { IconProp } from '@fortawesome/fontawesome-svg-core'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { Tooltip } from '@mui/material'; import { IconButton } from 'browndash-components'; @@ -9,7 +10,7 @@ import { lightOrDark, returnFalse, setupMoveUpEvents } from '../../ClientUtils'; import { Utils, emptyFunction, numberValue } from '../../Utils'; import { DateField } from '../../fields/DateField'; import { Doc, DocListCast, Field, FieldType, HierarchyMapping, ReverseHierarchyMap } from '../../fields/Doc'; -import { AclAdmin, AclAugment, AclEdit, DocData, KeywordsHeight } from '../../fields/DocSymbols'; +import { AclAdmin, AclAugment, AclEdit, DocData } from '../../fields/DocSymbols'; import { Id } from '../../fields/FieldSymbols'; import { InkField } from '../../fields/InkField'; import { ScriptField } from '../../fields/ScriptField'; @@ -34,7 +35,6 @@ import { DocumentView } from './nodes/DocumentView'; import { ImageBox } from './nodes/ImageBox'; import { OpenWhere, OpenWhereMod } from './nodes/OpenWhere'; import { FormattedTextBox } from './nodes/formattedText/FormattedTextBox'; -import { IconProp } from '@fortawesome/fontawesome-svg-core'; interface DocumentDecorationsProps { PanelWidth: number; @@ -835,7 +835,7 @@ export class DocumentDecorations extends ObservableReactComponent DocumentView.Selected()} /> diff --git a/src/client/views/KeywordBox.tsx b/src/client/views/KeywordBox.tsx deleted file mode 100644 index 841c5394b..000000000 --- a/src/client/views/KeywordBox.tsx +++ /dev/null @@ -1,316 +0,0 @@ -import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { Button, Colors, IconButton } from 'browndash-components'; -import { action, computed, makeObservable, observable } from 'mobx'; -import { observer } from 'mobx-react'; -import React from 'react'; -import ResizeObserver from 'resize-observer-polyfill'; -import { returnFalse, setupMoveUpEvents } from '../../ClientUtils'; -import { Utils, emptyFunction } from '../../Utils'; -import { Doc, DocListCast, StrListCast } from '../../fields/Doc'; -import { DocData, KeywordsHeight } from '../../fields/DocSymbols'; -import { List } from '../../fields/List'; -import { NumCast, StrCast } from '../../fields/Types'; -import { DocumentType } from '../documents/DocumentTypes'; -import { DragManager } from '../util/DragManager'; -import { SnappingManager } from '../util/SnappingManager'; -import { undoable } from '../util/UndoManager'; -import { ObservableReactComponent } from './ObservableReactComponent'; -import { DocumentView } from './nodes/DocumentView'; -import { FontIconBox } from './nodes/FontIconBox/FontIconBox'; - -interface KeywordItemProps { - doc: Doc; - keyword: string; - keywordDoc?: Doc; - setToEditing: () => void; - isEditing: boolean; -} - -/** - * A component that handles individual keywords. - */ -@observer -export class KeywordItem extends ObservableReactComponent { - /** - * return list of all Docs that collect Docs with specified keywords - */ - public static get AllKeywordCollections() { - return DocListCast(Doc.ActiveDashboard?.myKeywordCollections); - } - /** - * Find Doc that collects all Docs with given keyword - * @param keyword keyword string - * @returns keyword collection Doc or undefined - */ - public static findKeywordCollectionDoc = (keyword: String) => KeywordItem.AllKeywordCollections.find(doc => doc.title === keyword); - - /** - * Creates a Doc that collects Docs with the specified keyword - * @param keyword keyword string - * @returns collection Doc - */ - public static createKeywordCollectionDoc = (keyword: string) => { - const newKeywordCol = new Doc(); - newKeywordCol.title = keyword; - newKeywordCol.collections = new List(); - newKeywordCol[DocData].docs = new List(); - // If the active Dashboard does not have a keyword collection, create it. - if (Doc.ActiveDashboard) { - if (!Doc.ActiveDashboard.myKeywordCollections) Doc.ActiveDashboard.myKeywordCollections = new List(); - Doc.AddDocToList(Doc.ActiveDashboard, 'myKeywordCollections', newKeywordCol); - } - - return newKeywordCol; - }; - /** - * Gets all Docs that have the specified keyword - * @param keyword keyword string - * @returns An array of documents that contain the keyword. - */ - public static allDocsWithKeyword = (keyword: string) => DocListCast(KeywordItem.findKeywordCollectionDoc(keyword)?.[DocData].docs); - - /** - * Adds a keyword to the metadata of this document - * @param keyword keyword string - */ - public static addLabelToDoc = (doc: Doc, keyword: string) => { - // If the keyword collection is not in active Dashboard, add it as a new doc, with the keyword as its title. - const keywordCollection = KeywordItem.findKeywordCollectionDoc(keyword) ?? KeywordItem.createKeywordCollectionDoc(keyword); - - // If the document is of type COLLECTION, make it a smart collection, otherwise, add the keyword to the document. - if (doc.type === DocumentType.COL) { - Doc.AddDocToList(keywordCollection[DocData], 'collections', doc); - - // Iterate through the keyword Doc collections and add a copy of the document to each collection - for (const cdoc of DocListCast(keywordCollection[DocData].docs)) { - if (!DocListCast(doc[DocData].data).find(d => Doc.AreProtosEqual(d, cdoc))) { - const newEmbedding = Doc.MakeEmbedding(cdoc); - Doc.AddDocToList(doc[DocData], 'data', newEmbedding); - Doc.SetContainer(newEmbedding, doc); - } - } - } else { - // Add this document to the keyword's collection of associated documents. - Doc.AddDocToList(keywordCollection[DocData], 'docs', doc); - - // Iterate through the keyword document's collections and add a copy of the document to each collection - for (const collection of DocListCast(keywordCollection.collections)) { - if (!DocListCast(collection[DocData].data).find(d => Doc.AreProtosEqual(d, doc))) { - const newEmbedding = Doc.MakeEmbedding(doc); - Doc.AddDocToList(collection[DocData], 'data', newEmbedding); - Doc.SetContainer(newEmbedding, collection); - } - } - } - - if (!doc[DocData].tags) doc[DocData].tags = new List(); - const tagList = doc[DocData].tags as List; - if (!tagList.includes(keyword)) tagList.push(keyword); - }; - - public static RemoveLabel = (doc: Doc, keyword: string, keywordDoc?: Doc) => { - if (doc[DocData].tags) { - if (doc.type === DocumentType.COL) { - keywordDoc && Doc.RemoveDocFromList(keywordDoc[DocData], 'collections', doc); - - for (const cur_doc of KeywordItem.allDocsWithKeyword(keyword)) { - doc[DocData].data = new List(DocListCast(doc[DocData].data).filter(d => !Doc.AreProtosEqual(cur_doc, d))); - } - } else { - keywordDoc && Doc.RemoveDocFromList(keywordDoc[DocData], 'docs', doc); - - for (const collection of DocListCast(keywordDoc?.collections)) { - collection[DocData].data = new List(DocListCast(collection[DocData].data).filter(d => !Doc.AreProtosEqual(doc, d))); - } - } - } - doc[DocData].tags = new List((doc[DocData].tags as List).filter(label => label !== keyword)); - }; - - private _ref: React.RefObject; - - constructor(props: any) { - super(props); - makeObservable(this); - this._ref = React.createRef(); - } - - /** - * Creates a smart collection. - * @returns - */ - createCollection = () => { - // Get the documents that contain the keyword. - const newEmbeddings = KeywordItem.allDocsWithKeyword(this._props.keyword).map(doc => Doc.MakeEmbedding(doc)); - - // Create a new collection and set up configurations. - const newCollection = ((doc: Doc) => { - const docData = doc[DocData]; - docData.data = new List(newEmbeddings); - docData.title = this._props.keyword; - docData.tags = new List([this._props.keyword]); - docData.showLabels = true; - docData.freeform_fitContentsToBox = true; - doc._freeform_panX = doc._freeform_panY = 0; - doc._width = 900; - doc._height = 900; - doc.layout_fitWidth = true; - return doc; - })(Doc.MakeCopy(Doc.UserDoc().emptyCollection as Doc, true)); - newEmbeddings.forEach(embed => Doc.SetContainer(embed, newCollection)); - - // Add the collection to the keyword document's list of associated smart collections. - this._props.keywordDoc && Doc.AddDocToList(this._props.keywordDoc, 'collections', newCollection); - return newCollection; - }; - - @action - handleDragStart = (e: React.PointerEvent) => { - setupMoveUpEvents( - this, - e, - () => { - const dragData = new DragManager.DocumentDragData([this.createCollection()]); - DragManager.StartDocumentDrag([this._ref.current!], dragData, e.clientX, e.clientY, {}); - return true; - }, - returnFalse, - emptyFunction - ); - e.preventDefault(); - }; - - render() { - setTimeout(() => KeywordItem.addLabelToDoc(this._props.doc, this._props.keyword)); // bcz: hack to make sure that Docs are added to their keyword Doc collection since metadata can get set anywhere without a guard triggering an add to the collection - const keyword = this._props.keyword.replace(/^#/, ''); - const metadata = keyword.startsWith('@') ? keyword.replace(/^@/, '') : ''; - return ( -
- {metadata ? ( - - {keyword}  - {this._props.doc[metadata] as string} - - ) : ( - keyword - )} - {this.props.isEditing && ( - KeywordItem.RemoveLabel(this._props.doc, this._props.keyword, this._props.keywordDoc), `remove label ${this._props.keyword}`)} - icon={} - style={{ width: '8px', height: '8px', marginLeft: '10px' }} - /> - )} -
- ); - } -} - -interface KeywordBoxProps { - View: DocumentView; -} - -/** - * A component that handles the keyword display for documents. - */ -@observer -export class KeywordBox extends ObservableReactComponent { - private _ref: React.RefObject; - - constructor(props: any) { - super(props); - makeObservable(this); - this._ref = React.createRef(); - } - - @observable _currentInput = ''; - @observable _isEditing = !StrListCast(this._props.View.dataDoc.tags).length; - - @computed get currentScale() { - return NumCast((this._props.View.Document.embedContainer as Doc)?._freeform_scale, 1); - } - @computed get isEditing() { - return this._isEditing && DocumentView.SelectedDocs().includes(this._props.View.Document); - } - - @action - setToEditing = (editing = true) => { - this._isEditing = editing; - editing && this._props.View.select(false); - }; - - /** - * Adds the keyword to the document. - * @param keyword - */ - submitLabel = undoable((keyword: string) => { - const submittedLabel = keyword.trim(); - submittedLabel && KeywordItem.addLabelToDoc(this._props.View.Document, '#' + submittedLabel.replace(/^#/, '')); - this._currentInput = ''; // Clear the input box - }, 'added doc label'); - - render() { - const keywordsList = StrListCast(this._props.View.dataDoc.tags); - - return !this._props.View.Document.showLabels ? null : ( -
r && new ResizeObserver(action(() => (this._props.View.Document[KeywordsHeight] = r?.getBoundingClientRect().height ?? 0))).observe(r)} - style={{ - transformOrigin: 'top left', - maxWidth: `${100 * this.currentScale}%`, - width: 'max-content', - transform: `scale(${1 / this.currentScale})`, - backgroundColor: this.isEditing ? Colors.LIGHT_GRAY : Colors.TRANSPARENT, - borderColor: this.isEditing ? Colors.BLACK : Colors.TRANSPARENT, - }}> -
-
- {!keywordsList.length ? null : ( // - this.setToEditing(!this._isEditing)} icon={} /> - )} - {keywordsList.map(keyword => ( - - ))} -
- {this.isEditing ? ( -
-
- (this._currentInput = e.target.value))} - onKeyDown={e => { - e.key === 'Enter' ? this.submitLabel(this._currentInput) : null; - e.stopPropagation(); - }} - type="text" - placeholder="Input keywords for document..." - aria-label="keyword-input" - className="keyword-input" - style={{ width: '100%', borderRadius: '5px' }} - /> -
-
- {KeywordItem.AllKeywordCollections.map(doc => { - const keyword = StrCast(doc.title); - return ( -
-
- ) : null} -
-
- ); - } -} diff --git a/src/client/views/StyleProvider.scss b/src/client/views/StyleProvider.scss index 6f6939d54..ce00f6101 100644 --- a/src/client/views/StyleProvider.scss +++ b/src/client/views/StyleProvider.scss @@ -53,67 +53,3 @@ .styleProvider-treeView-icon { opacity: 0; } - -.keywords-container { - display: flex; - flex-wrap: wrap; - flex-direction: column; - border: 1px solid; - border-radius: 4px; -} - -.keywords-list { - display: flex; - flex-wrap: wrap; - .iconButton-container { - min-height: unset !important; - } -} - -.keyword { - padding: 1px 5px; - background-color: lightblue; - border: 1px solid black; - border-radius: 5px; - white-space: nowrap; - display: flex; - align-items: center; -} - -.keyword-suggestions-box { - display: flex; - flex-wrap: wrap; - margin: auto; - align-self: center; - width: 90%; - border: 1px solid black; - border-radius: 2px; - margin-top: 8px; -} - -.keyword-suggestion { - cursor: pointer; - padding: 1px 1px; - margin: 2px 2px; - background-color: lightblue; - border: 1px solid black; - border-radius: 5px; - white-space: nowrap; - display: flex; - align-items: center; -} - -.keyword-editing-box { - margin-top: 8px; -} - -.keyword-input-box { - margin: auto; - align-self: center; - width: 90%; -} - -.keyword-buttons { - margin-left: auto; - width: 10%; -} diff --git a/src/client/views/StyleProvider.tsx b/src/client/views/StyleProvider.tsx index a841ec63a..e48994586 100644 --- a/src/client/views/StyleProvider.tsx +++ b/src/client/views/StyleProvider.tsx @@ -19,7 +19,7 @@ import { SnappingManager } from '../util/SnappingManager'; import { undoable, UndoManager } from '../util/UndoManager'; import { TreeSort } from './collections/TreeSort'; import { Colors } from './global/globalEnums'; -import { KeywordBox } from './KeywordBox'; +import { TagsView } from './TagsView'; import { CollectionFreeFormDocumentView } from './nodes/CollectionFreeFormDocumentView'; import { DocumentView, DocumentViewProps } from './nodes/DocumentView'; import { FieldViewProps } from './nodes/FieldView'; @@ -363,14 +363,14 @@ export function DefaultStyleProvider(doc: Opt, props: Opt ); }; - const keywords = () => props?.DocumentView?.() && CollectionFreeFormDocumentView.from(props.DocumentView()) ? : null; + const tags = () => props?.DocumentView?.() && CollectionFreeFormDocumentView.from(props.DocumentView()) ? : null; return ( <> {paint()} {lock()} {filter()} {audio()} - {keywords()} + {tags()} ); } diff --git a/src/client/views/TagsView.scss b/src/client/views/TagsView.scss new file mode 100644 index 000000000..f7365a51b --- /dev/null +++ b/src/client/views/TagsView.scss @@ -0,0 +1,63 @@ +.tagsView-container { + display: flex; + flex-wrap: wrap; + flex-direction: column; + border: 1px solid; + border-radius: 4px; +} + +.tagsView-list { + display: flex; + flex-wrap: wrap; + .iconButton-container { + min-height: unset !important; + } +} + +.tagItem { + padding: 1px 5px; + background-color: lightblue; + border: 1px solid black; + border-radius: 5px; + white-space: nowrap; + display: flex; + align-items: center; +} + +.tagsView-suggestions-box { + display: flex; + flex-wrap: wrap; + margin: auto; + align-self: center; + width: 90%; + border: 1px solid black; + border-radius: 2px; + margin-top: 8px; +} + +.tagsView-suggestion { + cursor: pointer; + padding: 1px 1px; + margin: 2px 2px; + background-color: lightblue; + border: 1px solid black; + border-radius: 5px; + white-space: nowrap; + display: flex; + align-items: center; +} + +.tagsView-editing-box { + margin-top: 8px; +} + +.tagsView-input-box { + margin: auto; + align-self: center; + width: 90%; +} + +.tagsView-buttons { + margin-left: auto; + width: 10%; +} diff --git a/src/client/views/TagsView.tsx b/src/client/views/TagsView.tsx new file mode 100644 index 000000000..dffd1e096 --- /dev/null +++ b/src/client/views/TagsView.tsx @@ -0,0 +1,344 @@ +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { Button, Colors, IconButton } from 'browndash-components'; +import { action, computed, makeObservable, observable } from 'mobx'; +import { observer } from 'mobx-react'; +import React from 'react'; +import ResizeObserver from 'resize-observer-polyfill'; +import { returnFalse, setupMoveUpEvents } from '../../ClientUtils'; +import { emptyFunction } from '../../Utils'; +import { Doc, DocListCast, Opt, StrListCast } from '../../fields/Doc'; +import { DocData } from '../../fields/DocSymbols'; +import { List } from '../../fields/List'; +import { NumCast, StrCast } from '../../fields/Types'; +import { DocumentType } from '../documents/DocumentTypes'; +import { DragManager } from '../util/DragManager'; +import { SnappingManager } from '../util/SnappingManager'; +import { undoable } from '../util/UndoManager'; +import { ObservableReactComponent } from './ObservableReactComponent'; +import './TagsView.scss'; +import { DocumentView } from './nodes/DocumentView'; + +/** + * The TagsView is a metadata input/display panel shown at the bottom of a DocumentView in a freeform collection. + * + * This panel allow sthe user to add metadata tags to a Doc, and to display those tags, or any metadata field + * in a panel of 'buttons' (TagItems) just below the DocumentView. TagItems are interactive - + * the user can drag them off in order to display a collection of all documents that share the tag value. + * + * The tags that are added using the panel are the same as the #tags that can entered in a text Doc. + * Note that tags starting with #@ display a metadata key/value pair instead of the tag itself. + * e.g., '#@author' shows the document author + * + */ + +interface TagItemProps { + doc: Doc; + tag: string; + tagDoc: Opt; + showRemoveUI: boolean; + setToEditing: () => void; +} + +/** + * Interactive component that display a single metadata tag or value. + * + * These items can be dragged and dropped to create a collection of Docs that + * share the same metadata tag / value. + */ +@observer +export class TagItem extends ObservableReactComponent { + /** + * return list of all tag Docs (ie, Doc that are collections of Docs sharing a specific tag / value) + */ + public static get AllTagCollectionDocs() { + return DocListCast(Doc.ActiveDashboard?.myTagCollections); + } + /** + * Find tag Doc that collects all Docs with given tag / value + * @param tag tag string + * @returns tag collection Doc or undefined + */ + public static findTagCollectionDoc = (tag: String) => TagItem.AllTagCollectionDocs.find(doc => doc.title === tag); + + /** + * Creates a Doc that collects Docs with the specified tag / value + * @param tag tag string + * @returns tag collection Doc + */ + public static createTagCollectionDoc = (tag: string) => { + const newTagCol = new Doc(); + newTagCol.title = tag; + newTagCol.collections = new List(); + newTagCol[DocData].docs = new List(); + // If the active Dashboard does not have a tag Doc collection, create it. + if (Doc.ActiveDashboard) { + if (!Doc.ActiveDashboard.myTagCollections) Doc.ActiveDashboard.myTagCollections = new List(); + Doc.AddDocToList(Doc.ActiveDashboard, 'myTagCollections', newTagCol); + } + + return newTagCol; + }; + /** + * Gets all Docs that have the specified tag / value + * @param tag tag string + * @returns An array of documents that contain the tag. + */ + public static allDocsWithTag = (tag: string) => DocListCast(TagItem.findTagCollectionDoc(tag)?.[DocData].docs); + + /** + * Adds a tag to the metadata of this document and adds the Doc to the corresponding tag collection Doc (or creates it) + * @param tag tag string + */ + public static addTagToDoc = (doc: Doc, tag: string) => { + // If the tag collection is not in active Dashboard, add it as a new doc, with the tag as its title. + const tagCollection = TagItem.findTagCollectionDoc(tag) ?? TagItem.createTagCollectionDoc(tag); + + // If the document is of type COLLECTION, make it a smart collection, otherwise, add the tag to the document. + if (doc.type === DocumentType.COL) { + Doc.AddDocToList(tagCollection[DocData], 'collections', doc); + + // Iterate through the tag Doc collections and add a copy of the document to each collection + for (const cdoc of DocListCast(tagCollection[DocData].docs)) { + if (!DocListCast(doc[DocData].data).find(d => Doc.AreProtosEqual(d, cdoc))) { + const newEmbedding = Doc.MakeEmbedding(cdoc); + Doc.AddDocToList(doc[DocData], 'data', newEmbedding); + Doc.SetContainer(newEmbedding, doc); + } + } + } else { + // Add this document to the tag's collection of associated documents. + Doc.AddDocToList(tagCollection[DocData], 'docs', doc); + + // Iterate through the tag document's collections and add a copy of the document to each collection + for (const collection of DocListCast(tagCollection.collections)) { + if (!DocListCast(collection[DocData].data).find(d => Doc.AreProtosEqual(d, doc))) { + const newEmbedding = Doc.MakeEmbedding(doc); + Doc.AddDocToList(collection[DocData], 'data', newEmbedding); + Doc.SetContainer(newEmbedding, collection); + } + } + } + + if (!doc[DocData].tags) doc[DocData].tags = new List(); + const tagList = doc[DocData].tags as List; + if (!tagList.includes(tag)) tagList.push(tag); + }; + + /** + * Removes a tag from a Doc and removes the Doc from the corresponding tag collection Doc + * @param doc Doc to add tag + * @param tag tag string + * @param tagDoc doc that collections the Docs with the tag + */ + public static removeTagFromDoc = (doc: Doc, tag: string, tagDoc?: Doc) => { + if (doc[DocData].tags) { + if (doc.type === DocumentType.COL) { + tagDoc && Doc.RemoveDocFromList(tagDoc[DocData], 'collections', doc); + + for (const cur_doc of TagItem.allDocsWithTag(tag)) { + doc[DocData].data = new List(DocListCast(doc[DocData].data).filter(d => !Doc.AreProtosEqual(cur_doc, d))); + } + } else { + tagDoc && Doc.RemoveDocFromList(tagDoc[DocData], 'docs', doc); + + for (const collection of DocListCast(tagDoc?.collections)) { + collection[DocData].data = new List(DocListCast(collection[DocData].data).filter(d => !Doc.AreProtosEqual(doc, d))); + } + } + } + doc[DocData].tags = new List((doc[DocData].tags as List).filter(label => label !== tag)); + }; + + private _ref: React.RefObject; + + constructor(props: any) { + super(props); + makeObservable(this); + this._ref = React.createRef(); + } + + /** + * Creates a smart collection. + * @returns + */ + createTagCollection = () => { + // Get the documents that contain the tag. + const newEmbeddings = TagItem.allDocsWithTag(this._props.tag).map(doc => Doc.MakeEmbedding(doc)); + + // Create a new collection and set up configurations. + const newCollection = ((doc: Doc) => { + const docData = doc[DocData]; + docData.data = new List(newEmbeddings); + docData.title = this._props.tag; + docData.tags = new List([this._props.tag]); + docData.showTags = true; + docData.freeform_fitContentsToBox = true; + doc._freeform_panX = doc._freeform_panY = 0; + doc._width = 900; + doc._height = 900; + doc.layout_fitWidth = true; + return doc; + })(Doc.MakeCopy(Doc.UserDoc().emptyCollection as Doc, true)); + newEmbeddings.forEach(embed => Doc.SetContainer(embed, newCollection)); + + // Add the collection to the tag document's list of associated smart collections. + this._props.tagDoc && Doc.AddDocToList(this._props.tagDoc, 'collections', newCollection); + return newCollection; + }; + + @action + handleDragStart = (e: React.PointerEvent) => { + setupMoveUpEvents( + this, + e, + () => { + const dragData = new DragManager.DocumentDragData([this.createTagCollection()]); + DragManager.StartDocumentDrag([this._ref.current!], dragData, e.clientX, e.clientY, {}); + return true; + }, + returnFalse, + emptyFunction + ); + e.preventDefault(); + }; + + render() { + setTimeout(() => TagItem.addTagToDoc(this._props.doc, this._props.tag)); // bcz: hack to make sure that Docs are added to their tag Doc collection since metadata can get set anywhere without a guard triggering an add to the collection + const tag = this._props.tag.replace(/^#/, ''); + const metadata = tag.startsWith('@') ? tag.replace(/^@/, '') : ''; + return ( +
+ {metadata ? ( + + {tag}  + {this._props.doc[metadata] as string} + + ) : ( + tag + )} + {this.props.showRemoveUI && ( + TagItem.removeTagFromDoc(this._props.doc, this._props.tag, this._props.tagDoc), `remove tag ${this._props.tag}`)} + icon={} + style={{ width: '8px', height: '8px', marginLeft: '10px' }} + /> + )} +
+ ); + } +} + +interface TagViewProps { + View: DocumentView; +} + +/** + * Displays a panel of tags that have been added to a Doc. Also allows for editing the applied tags through a dropdown UI. + */ +@observer +export class TagsView extends ObservableReactComponent { + private _ref: React.RefObject; + + constructor(props: any) { + super(props); + makeObservable(this); + this._ref = React.createRef(); + } + + @observable _currentInput = ''; + @observable _isEditing = !StrListCast(this._props.View.dataDoc.tags).length; + + @computed get currentScale() { + return NumCast((this._props.View.Document.embedContainer as Doc)?._freeform_scale, 1); + } + @computed get isEditing() { + return this._isEditing && DocumentView.SelectedDocs().includes(this._props.View.Document); + } + + @action + setToEditing = (editing = true) => { + this._isEditing = editing; + editing && this._props.View.select(false); + }; + + /** + * Adds the specified tag to the Doc. If the tag is not prefixed with '#', then a '#' prefix is added. + * Whne the tag (after the '#') begins with '@', then a metadata key/value pair is displayed instead of + * just the tag. + * @param tag tag string to add + */ + submitTag = undoable((tag: string) => { + const submittedLabel = tag.trim(); + submittedLabel && TagItem.addTagToDoc(this._props.View.Document, '#' + submittedLabel.replace(/^#/, '')); + this._currentInput = ''; // Clear the input box + }, 'added doc label'); + + /** + * When 'showTags' is set on a Doc, this displays a wrapping panel of tagItemViews corresponding to all the tags set on the Doc). + * When the dropdown is clicked, this will toggle an extended UI that allows additional tags to be added/removed. + */ + render() { + const tagsList = StrListCast(this._props.View.dataDoc.tags); + + return !this._props.View.Document.showTags ? null : ( +
r && new ResizeObserver(action(() => (this._props.View.TagPanelHeight = r?.getBoundingClientRect().height ?? 0))).observe(r)} + style={{ + transformOrigin: 'top left', + maxWidth: `${100 * this.currentScale}%`, + width: 'max-content', + transform: `scale(${1 / this.currentScale})`, + backgroundColor: this.isEditing ? Colors.LIGHT_GRAY : Colors.TRANSPARENT, + borderColor: this.isEditing ? Colors.BLACK : Colors.TRANSPARENT, + }}> +
+
+ {!tagsList.length ? null : ( // + this.setToEditing(!this._isEditing)} icon={} /> + )} + {tagsList.map(tag => ( + + ))} +
+ {this.isEditing ? ( +
+
+ (this._currentInput = e.target.value))} + onKeyDown={e => { + e.key === 'Enter' ? this.submitTag(this._currentInput) : null; + e.stopPropagation(); + }} + type="text" + placeholder="Input tags for document..." + aria-label="tagsView-input" + className="tagsView-input" + style={{ width: '100%', borderRadius: '5px' }} + /> +
+
+ {TagItem.AllTagCollectionDocs.map((doc, i) => { + const tag = StrCast(doc.title); + return ( +
+
+ ) : null} +
+
+ ); + } +} diff --git a/src/client/views/collections/collectionFreeForm/ImageLabelBox.tsx b/src/client/views/collections/collectionFreeForm/ImageLabelBox.tsx index 421b5d0a6..6eb3eb784 100644 --- a/src/client/views/collections/collectionFreeForm/ImageLabelBox.tsx +++ b/src/client/views/collections/collectionFreeForm/ImageLabelBox.tsx @@ -1,30 +1,30 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { Colors, IconButton } from 'browndash-components'; +import similarity from 'compute-cosine-similarity'; +import { ring } from 'ldrs'; +import 'ldrs/ring'; import { action, computed, makeObservable, observable, reaction } from 'mobx'; import { observer } from 'mobx-react'; import React from 'react'; +import { Utils, numberRange } from '../../../../Utils'; import { Doc, NumListCast, Opt } from '../../../../fields/Doc'; -import { Docs } from '../../../documents/Documents'; -import { DocumentType } from '../../../documents/DocumentTypes'; -import { ViewBoxBaseComponent } from '../../DocComponent'; -import { FieldView, FieldViewProps } from '../../nodes/FieldView'; -import { MarqueeOptionsMenu } from './MarqueeOptionsMenu'; -import './ImageLabelBox.scss'; -import { MainView } from '../../MainView'; -import 'ldrs/ring'; -import { ring } from 'ldrs'; -import { SnappingManager } from '../../../util/SnappingManager'; -import { ImageCast } from '../../../../fields/Types'; import { DocData } from '../../../../fields/DocSymbols'; -import { SettingsManager } from '../../../util/SettingsManager'; -import { CollectionCardView } from '../CollectionCardDeckView'; -import { gptGetEmbedding, gptImageLabel } from '../../../apis/gpt/GPT'; -import { numberRange, Utils } from '../../../../Utils'; import { List } from '../../../../fields/List'; +import { ImageCast } from '../../../../fields/Types'; +import { gptGetEmbedding, gptImageLabel } from '../../../apis/gpt/GPT'; +import { DocumentType } from '../../../documents/DocumentTypes'; +import { Docs } from '../../../documents/Documents'; import { DragManager } from '../../../util/DragManager'; -import { OpenWhere } from '../../nodes/OpenWhere'; -import similarity from 'compute-cosine-similarity'; +import { SettingsManager } from '../../../util/SettingsManager'; +import { SnappingManager } from '../../../util/SnappingManager'; +import { ViewBoxBaseComponent } from '../../DocComponent'; +import { MainView } from '../../MainView'; import { DocumentView } from '../../nodes/DocumentView'; +import { FieldView, FieldViewProps } from '../../nodes/FieldView'; +import { OpenWhere } from '../../nodes/OpenWhere'; +import { CollectionCardView } from '../CollectionCardDeckView'; +import './ImageLabelBox.scss'; +import { MarqueeOptionsMenu } from './MarqueeOptionsMenu'; export class ImageInformationItem {} @@ -139,9 +139,9 @@ export class ImageLabelBox extends ViewBoxBaseComponent() { toggleDisplayInformation = () => { this._displayImageInformation = !this._displayImageInformation; if (this._displayImageInformation) { - this._selectedImages.forEach(doc => (doc[DocData].showLabels = true)); + this._selectedImages.forEach(doc => (doc[DocData].showTags = true)); } else { - this._selectedImages.forEach(doc => (doc[DocData].showLabels = false)); + this._selectedImages.forEach(doc => (doc[DocData].showTags = false)); } }; @@ -163,7 +163,7 @@ export class ImageLabelBox extends ViewBoxBaseComponent() { // Converts the images into a Base64 format, afterwhich the information is sent to GPT to label them. const imageInfos = this._selectedImages.map(async doc => { - if (!doc[DocData].data_labels) { + if (!doc[DocData].tags) { const [name, type] = ImageCast(doc[Doc.LayoutFieldKey(doc)]).url.href.split('.'); return CollectionCardView.imageUrlToBase64(`${name}_o.${type}`).then(hrefBase64 => !hrefBase64 ? undefined : @@ -174,14 +174,14 @@ export class ImageLabelBox extends ViewBoxBaseComponent() { (await Promise.all(imageInfos)).forEach(imageInfo => { if (imageInfo) { - imageInfo.doc[DocData].data_labels = new List(); + imageInfo.doc[DocData].tags = (imageInfo.doc[DocData].tags as List) ?? new List(); const labels = imageInfo.labels.split('\n'); labels.forEach(label => { - label = label.replace(/^\d+\.\s*|-|\*/, '').trim(); + label = label.replace(/^\d+\.\s*|-|f\*/, '').trim(); console.log(label); - imageInfo.doc[DocData][`${label}`] = true; - (imageInfo.doc[DocData].data_labels as List).push(label); + imageInfo.doc[DocData][label] = true; + (imageInfo.doc[DocData].tags as List).push(label); }); } }); @@ -196,10 +196,10 @@ export class ImageLabelBox extends ViewBoxBaseComponent() { this.startLoading(); for (const doc of this._selectedImages) { - for (let index = 0; index < (doc[DocData].data_labels as List).length; index++) { - const label = (doc[DocData].data_labels as List)[index]; + for (let index = 0; index < (doc[DocData].tags as List).length; index++) { + const label = (doc[DocData].tags as List)[index]; const embedding = await gptGetEmbedding(label); - doc[DocData][`data_labels_embedding_${index + 1}`] = new List(embedding); + doc[DocData][`tags_embedding_${index + 1}`] = new List(embedding); } } @@ -210,7 +210,7 @@ export class ImageLabelBox extends ViewBoxBaseComponent() { // For each image, loop through the labels, and calculate similarity. Associate it with the // most similar one. this._selectedImages.forEach(doc => { - const embedLists = numberRange((doc[DocData].data_labels as List).length).map(n => Array.from(NumListCast(doc[DocData][`data_labels_embedding_${n + 1}`]))); + const embedLists = numberRange((doc[DocData].tags as List).length).map(n => Array.from(NumListCast(doc[DocData][`tags_embedding_${n + 1}`]))); const bestEmbedScore = (embedding: Opt) => Math.max(...embedLists.map((l, index) => (embedding && similarity(Array.from(embedding), l)!) || 0)); const {label: mostSimilarLabelCollect} = this._labelGroups.map(label => ({ label, similarityScore: bestEmbedScore(labelToEmbedding.get(label)) })) @@ -317,7 +317,7 @@ export class ImageLabelBox extends ViewBoxBaseComponent() { await DocumentView.showDocument(doc, { willZoomCentered: true }); }}>
this._props.addDocTab(doc, OpenWhere.addRightKeyvalue)}> - {(doc[DocData].data_labels as List).map(label => { + {(doc[DocData].tags as List).map(label => { return (
{label} diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 5efdb3df4..4c357cf45 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -1124,6 +1124,7 @@ export class DocumentView extends DocComponent() { @observable private _isHovering = false; @observable private _selected = false; @observable public static CurrentlyPlaying: DocumentView[] = []; // audio or video media views that are currently playing + @observable public TagPanelHeight = 0; @computed private get shouldNotScale() { return (this.layout_fitWidth && !this.nativeWidth) || this.ComponentView?.isUnstyledView?.(); diff --git a/src/client/views/nodes/formattedText/RichTextRules.ts b/src/client/views/nodes/formattedText/RichTextRules.ts index 79c118490..e0d6c7c05 100644 --- a/src/client/views/nodes/formattedText/RichTextRules.ts +++ b/src/client/views/nodes/formattedText/RichTextRules.ts @@ -404,7 +404,7 @@ export class RichTextRules { if (!tags.includes(tag)) { tags.push(tag); this.Document[DocData].tags = new List(tags); - this.Document[DocData].showLabels = true; + this.Document[DocData].showTags = true; } const fieldView = state.schema.nodes.dashField.create({ fieldKey: '#' + tag }); return state.tr diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts index f246f49e5..ffb5aab79 100644 --- a/src/fields/Doc.ts +++ b/src/fields/Doc.ts @@ -11,7 +11,7 @@ import { ClientUtils, incrementTitleCopy } from '../ClientUtils'; import { AclAdmin, AclAugment, AclEdit, AclPrivate, AclReadonly, Animation, AudioPlay, Brushed, CachedUpdates, DirectLinks, DocAcl, DocCss, DocData, DocLayout, DocViews, FieldKeys, FieldTuples, ForceServerWrite, Height, Highlight, - Initializing, KeywordsHeight, Self, SelfProxy, TransitionTimer, UpdatingFromServer, Width + Initializing, Self, SelfProxy, TransitionTimer, UpdatingFromServer, Width } from './DocSymbols'; // prettier-ignore import { Copy, FieldChanged, HandleUpdate, Id, Parent, ToJavascriptString, ToScriptString, ToString } from './FieldSymbols'; import { InkTool } from './InkField'; @@ -303,7 +303,6 @@ export class Doc extends RefField { Height, Highlight, Initializing, - KeywordsHeight, Self, SelfProxy, UpdatingFromServer, @@ -369,7 +368,6 @@ export class Doc extends RefField { @observable public [Highlight]: boolean = false; @observable public [Brushed]: boolean = false; @observable public [DocViews] = new ObservableSet(); - @observable public [KeywordsHeight]: number = 0; private [Self] = this; private [SelfProxy]: Doc; diff --git a/src/fields/DocSymbols.ts b/src/fields/DocSymbols.ts index 9e091ab29..dc18d8638 100644 --- a/src/fields/DocSymbols.ts +++ b/src/fields/DocSymbols.ts @@ -32,6 +32,5 @@ export const DocViews = Symbol('DocViews'); export const Brushed = Symbol('DocBrushed'); export const DocCss = Symbol('DocCss'); export const TransitionTimer = Symbol('DocTransitionTimer'); -export const KeywordsHeight = Symbol('DocKeywordsHeight'); export const DashVersion = 'v0.8.0'; -- cgit v1.2.3-70-g09d2 From 6bc79c5dfc5f61bf5d1b1544d399703c8006b898 Mon Sep 17 00:00:00 2001 From: bobzel Date: Mon, 26 Aug 2024 10:59:56 -0400 Subject: cleanup of myXXXstuff on dashboards --- src/client/views/DashboardView.tsx | 5 +++-- src/client/views/TagsView.tsx | 6 +----- src/fields/Doc.ts | 8 ++++---- 3 files changed, 8 insertions(+), 11 deletions(-) (limited to 'src') diff --git a/src/client/views/DashboardView.tsx b/src/client/views/DashboardView.tsx index dcc5442f0..f4fc8ee9f 100644 --- a/src/client/views/DashboardView.tsx +++ b/src/client/views/DashboardView.tsx @@ -429,7 +429,8 @@ export class DashboardView extends ObservableReactComponent { dashboardDoc.pane_count = 1; freeformDoc.embedContainer = dashboardDoc; dashboardDoc.myOverlayDocs = new List(); - dashboardDoc.myPublishedDocs = new List(); + dashboardDoc[DocData].myPublishedDocs = new List(); + dashboardDoc[DocData].myTagCollections = new List(); Doc.AddDocToList(Doc.MyDashboards, 'data', dashboardDoc); @@ -467,7 +468,7 @@ export class DashboardView extends ObservableReactComponent { }; const myCalendars = DocUtils.AssignScripts(Docs.Create.CalendarCollectionDocument([], reqdOpts)); // { treeView_ChildDoubleClick: 'openPresentation(documentView.rootDoc)' } - dashboardDoc.myCalendars = new PrefetchProxy(myCalendars); + dashboardDoc[DocData].myCalendars = new PrefetchProxy(myCalendars); } public static SetupDashboardTrails(dashboardDoc: Doc) { diff --git a/src/client/views/TagsView.tsx b/src/client/views/TagsView.tsx index dffd1e096..394162f46 100644 --- a/src/client/views/TagsView.tsx +++ b/src/client/views/TagsView.tsx @@ -70,11 +70,7 @@ export class TagItem extends ObservableReactComponent { newTagCol.title = tag; newTagCol.collections = new List(); newTagCol[DocData].docs = new List(); - // If the active Dashboard does not have a tag Doc collection, create it. - if (Doc.ActiveDashboard) { - if (!Doc.ActiveDashboard.myTagCollections) Doc.ActiveDashboard.myTagCollections = new List(); - Doc.AddDocToList(Doc.ActiveDashboard, 'myTagCollections', newTagCol); - } + Doc.ActiveDashboard && Doc.AddDocToList(Doc.ActiveDashboard, 'myTagCollections', newTagCol); return newTagCol; }; diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts index ffb5aab79..e3178f20c 100644 --- a/src/fields/Doc.ts +++ b/src/fields/Doc.ts @@ -258,16 +258,16 @@ export class Doc extends RefField { public static set ActiveDashboard(val: Opt) { Doc.UserDoc().activeDashboard = val; } // prettier-ignore public static IsInMyOverlay(doc: Doc) { return Doc.MyOverlayDocs.includes(doc); } // prettier-ignore - public static AddToMyOverlay(doc: Doc) { return Doc.ActiveDashboard?.myOverlayDocs ? Doc.AddDocToList(Doc.ActiveDashboard, 'myOverlayDocs', doc) : Doc.AddDocToList(DocCast(Doc.UserDoc().myOverlayDocs), undefined, doc); } // prettier-ignore - public static RemFromMyOverlay(doc: Doc) { return Doc.ActiveDashboard?.myOverlayDocs ? Doc.RemoveDocFromList(Doc.ActiveDashboard,'myOverlayDocs', doc) : Doc.RemoveDocFromList(DocCast(Doc.UserDoc().myOverlayDocs), undefined, doc); } // prettier-ignore + public static AddToMyOverlay(doc: Doc) { return Doc.ActiveDashboard ? Doc.AddDocToList(Doc.ActiveDashboard, 'myOverlayDocs', doc) : Doc.AddDocToList(DocCast(Doc.UserDoc().myOverlayDocs), undefined, doc); } // prettier-ignore + public static RemFromMyOverlay(doc: Doc) { return Doc.ActiveDashboard ? Doc.RemoveDocFromList(Doc.ActiveDashboard,'myOverlayDocs', doc) : Doc.RemoveDocFromList(DocCast(Doc.UserDoc().myOverlayDocs), undefined, doc); } // prettier-ignore public static AddToMyPublished(doc: Doc) { doc[DocData].title_custom = true; doc[DocData].layout_showTitle = 'title'; - Doc.ActiveDashboard?.myPublishedDocs ? Doc.AddDocToList(Doc.ActiveDashboard, 'myPublishedDocs', doc) : Doc.AddDocToList(DocCast(Doc.UserDoc().myPublishedDocs), undefined, doc); } // prettier-ignore + Doc.ActiveDashboard ? Doc.AddDocToList(Doc.ActiveDashboard, 'myPublishedDocs', doc) : Doc.AddDocToList(DocCast(Doc.UserDoc().myPublishedDocs), undefined, doc); } // prettier-ignore public static RemFromMyPublished(doc: Doc){ doc[DocData].title_custom = false; doc[DocData].layout_showTitle = undefined; - Doc.ActiveDashboard?.myPublishedDocs ? Doc.RemoveDocFromList(Doc.ActiveDashboard,'myPublishedDocs', doc) : Doc.RemoveDocFromList(DocCast(Doc.UserDoc().myPublishedDocs), undefined, doc); } // prettier-ignore + Doc.ActiveDashboard ? Doc.RemoveDocFromList(Doc.ActiveDashboard,'myPublishedDocs', doc) : Doc.RemoveDocFromList(DocCast(Doc.UserDoc().myPublishedDocs), undefined, doc); } // prettier-ignore public static IsComicStyle(doc?: Doc) { return doc && Doc.ActiveDashboard && !Doc.IsSystem(doc) && Doc.UserDoc().renderStyle === 'comic' ; } // prettier-ignore constructor(id?: FieldId, forceSave?: boolean) { -- cgit v1.2.3-70-g09d2 From cc3e1bc2c317cf34aba04e4935ae842b16ad4cae Mon Sep 17 00:00:00 2001 From: bobzel Date: Mon, 26 Aug 2024 11:22:38 -0400 Subject: cleanup of setting myXXstuff on dashboards --- src/client/views/DashboardView.tsx | 12 +++++------- .../collections/collectionFreeForm/FaceCollectionBox.tsx | 2 +- src/client/views/search/FaceRecognitionHandler.tsx | 12 ++++++------ 3 files changed, 12 insertions(+), 14 deletions(-) (limited to 'src') diff --git a/src/client/views/DashboardView.tsx b/src/client/views/DashboardView.tsx index f4fc8ee9f..4616e15e5 100644 --- a/src/client/views/DashboardView.tsx +++ b/src/client/views/DashboardView.tsx @@ -426,16 +426,14 @@ export class DashboardView extends ObservableReactComponent { const dashboardDoc = DashboardView.StandardCollectionDockingDocument([{ doc: freeformDoc, initialWidth: 600 }], { title: title }, id, 'row'); Doc.AddDocToList(Doc.MyHeaderBar, 'data', freeformDoc, undefined, undefined, true); + Doc.AddDocToList(Doc.MyDashboards, 'data', dashboardDoc); dashboardDoc.pane_count = 1; freeformDoc.embedContainer = dashboardDoc; dashboardDoc.myOverlayDocs = new List(); dashboardDoc[DocData].myPublishedDocs = new List(); dashboardDoc[DocData].myTagCollections = new List(); - - Doc.AddDocToList(Doc.MyDashboards, 'data', dashboardDoc); - - DashboardView.SetupDashboardTrails(dashboardDoc); - DashboardView.SetupDashboardCalendars(dashboardDoc); + dashboardDoc[DocData].myTrails = DashboardView.SetupDashboardTrails(dashboardDoc); + dashboardDoc[DocData].myCalendars = DashboardView.SetupDashboardCalendars(dashboardDoc); // open this new dashboard Doc.ActiveDashboard = dashboardDoc; Doc.ActivePage = 'dashboard'; @@ -468,7 +466,7 @@ export class DashboardView extends ObservableReactComponent { }; const myCalendars = DocUtils.AssignScripts(Docs.Create.CalendarCollectionDocument([], reqdOpts)); // { treeView_ChildDoubleClick: 'openPresentation(documentView.rootDoc)' } - dashboardDoc[DocData].myCalendars = new PrefetchProxy(myCalendars); + return new PrefetchProxy(myCalendars); } public static SetupDashboardTrails(dashboardDoc: Doc) { @@ -514,12 +512,12 @@ export class DashboardView extends ObservableReactComponent { layout_explainer: 'All of the trails that you have created will appear here.', }; const myTrails = DocUtils.AssignScripts(Docs.Create.TreeDocument([], reqdOpts), { treeView_ChildDoubleClick: 'openPresentation(documentView.Document)' }); - dashboardDoc.myTrails = new PrefetchProxy(myTrails); const contextMenuScripts = [reqdBtnScript.onClick]; if (Cast(myTrails.contextMenuScripts, listSpec(ScriptField), null)?.length !== contextMenuScripts.length) { myTrails.contextMenuScripts = new List(contextMenuScripts.map(script => ScriptField.MakeFunction(script)!)); } + return new PrefetchProxy(myTrails); } } diff --git a/src/client/views/collections/collectionFreeForm/FaceCollectionBox.tsx b/src/client/views/collections/collectionFreeForm/FaceCollectionBox.tsx index de7c2c027..1cc1f59dc 100644 --- a/src/client/views/collections/collectionFreeForm/FaceCollectionBox.tsx +++ b/src/client/views/collections/collectionFreeForm/FaceCollectionBox.tsx @@ -164,7 +164,7 @@ export class UniqueFaceView extends ObservableReactComponent { * This renders the sidebar collection of the unique faces that have been recognized. * * Since the collection of recognized faces is stored on the active dashboard, this class - * does not itself store any Docs, but accesses the uniqueFaces field of the current + * does not itself store any Docs, but accesses the myUniqueFaces field of the current * dashboard. Each Face collection Doc is rendered using a FaceCollectionDocView which * is not a CollectionView or even a DocumentView (but probably should be). */ diff --git a/src/client/views/search/FaceRecognitionHandler.tsx b/src/client/views/search/FaceRecognitionHandler.tsx index f5fc12a8d..a17e4c54a 100644 --- a/src/client/views/search/FaceRecognitionHandler.tsx +++ b/src/client/views/search/FaceRecognitionHandler.tsx @@ -20,7 +20,7 @@ import { ImageField } from '../../../fields/URLField'; * _faceDescriptors - list of all the numerical face representations found in the image. * _faces - list of unique face Docs corresponding to recognized faces in the image. * - * unique face Doc's are created for each person identified and are stored in the Dashboard's uniqueFaces field + * unique face Doc's are created for each person identified and are stored in the Dashboard's myUniqueFaces field * * Each unique face Doc represents a unique face and collects all matching face images for that person. It has these fields: * face_label - a string label for the person that was recognized (TODO: currently it's just a 'face#') @@ -93,14 +93,14 @@ export class FaceRecognitionHandler { * returns a list of all face collection Docs on the current dashboard * @returns face collection Doc list */ - public static UniqueFaces = () => DocListCast(Doc.ActiveDashboard?.[DocData].uniqueFaces); + public static UniqueFaces = () => DocListCast(Doc.ActiveDashboard?.[DocData].myUniqueFaces); /** * Removes a unique face from the set of recognized unique faces * @param faceDoc unique face Doc * @returns */ - public static DeleteUniqueFace = (faceDoc: Doc) => Doc.ActiveDashboard && Doc.RemoveDocFromList(Doc.ActiveDashboard[DocData], 'uniqueFaces', faceDoc); + public static DeleteUniqueFace = (faceDoc: Doc) => Doc.ActiveDashboard && Doc.RemoveDocFromList(Doc.ActiveDashboard[DocData], 'myUniqueFaces', faceDoc); /** * returns the labels associated with a face collection Doc @@ -169,8 +169,8 @@ export class FaceRecognitionHandler { * @returns a unique face Doc */ private createUniqueFaceDoc = (dashboard: Doc) => { - const faceDocNum = NumCast(dashboard.uniqueFaces_count) + 1; - dashboard.uniqueFaces_count = faceDocNum; // TODO: improve to a better name + const faceDocNum = NumCast(dashboard.myUniqueFaces_count) + 1; + dashboard.myUniqueFaces_count = faceDocNum; // TODO: improve to a better name const uniqueFaceDoc = new Doc(); uniqueFaceDoc.title = `Face ${faceDocNum}`; @@ -179,7 +179,7 @@ export class FaceRecognitionHandler { uniqueFaceDoc.face_images = new List(); uniqueFaceDoc.face_descriptors = new List>(); - Doc.ActiveDashboard && Doc.AddDocToList(Doc.ActiveDashboard[DocData], 'uniqueFaces', uniqueFaceDoc); + Doc.ActiveDashboard && Doc.AddDocToList(Doc.ActiveDashboard[DocData], 'myUniqueFaces', uniqueFaceDoc); return uniqueFaceDoc; }; -- cgit v1.2.3-70-g09d2 From 2e345c1ebd498e3f7e088e6fc3e1ca17082b23c1 Mon Sep 17 00:00:00 2001 From: bobzel Date: Mon, 26 Aug 2024 13:53:26 -0400 Subject: converted unique faces to be a Doc type similar to a collection. --- src/client/documents/DocumentTypes.ts | 1 + src/client/documents/Documents.ts | 4 + src/client/views/DashboardView.tsx | 1 + src/client/views/Main.tsx | 3 +- .../views/collections/CollectionStackingView.tsx | 3 +- src/client/views/collections/CollectionSubView.tsx | 1 + .../collectionFreeForm/FaceCollectionBox.scss | 24 ++++- .../collectionFreeForm/FaceCollectionBox.tsx | 113 +++++++++++++-------- src/client/views/search/FaceRecognitionHandler.tsx | 34 +++++-- 9 files changed, 123 insertions(+), 61 deletions(-) (limited to 'src') diff --git a/src/client/documents/DocumentTypes.ts b/src/client/documents/DocumentTypes.ts index 49df943d8..b055546fc 100644 --- a/src/client/documents/DocumentTypes.ts +++ b/src/client/documents/DocumentTypes.ts @@ -18,6 +18,7 @@ export enum DocumentType { SEARCH = 'search', // search query IMAGEGROUPER = 'imagegrouper', FACECOLLECTION = 'facecollection', + UFACE = 'uniqueface', // unique face collection doc LABEL = 'label', // simple text label BUTTON = 'button', // onClick button WEBCAM = 'webcam', // webcam diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index c0e4e961c..c2211fb80 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -795,6 +795,10 @@ export namespace Docs { return InstanceFromProto(Prototypes.get(DocumentType.FACECOLLECTION), undefined, options); } + export function UniqeFaceDocument(options: DocumentOptions = {}) { + return InstanceFromProto(Prototypes.get(DocumentType.UFACE), undefined, options); + } + export function LoadingDocument(file: File | string, options: DocumentOptions) { return InstanceFromProto(Prototypes.get(DocumentType.LOADING), undefined, { _height: 150, _width: 200, title: typeof file === 'string' ? file : file.name, ...options }, undefined, ''); } diff --git a/src/client/views/DashboardView.tsx b/src/client/views/DashboardView.tsx index 4616e15e5..33e905a54 100644 --- a/src/client/views/DashboardView.tsx +++ b/src/client/views/DashboardView.tsx @@ -432,6 +432,7 @@ export class DashboardView extends ObservableReactComponent { dashboardDoc.myOverlayDocs = new List(); dashboardDoc[DocData].myPublishedDocs = new List(); dashboardDoc[DocData].myTagCollections = new List(); + dashboardDoc[DocData].myUniqueFaces = new List(); dashboardDoc[DocData].myTrails = DashboardView.SetupDashboardTrails(dashboardDoc); dashboardDoc[DocData].myCalendars = DashboardView.SetupDashboardCalendars(dashboardDoc); // open this new dashboard diff --git a/src/client/views/Main.tsx b/src/client/views/Main.tsx index 023324881..f7cd0e925 100644 --- a/src/client/views/Main.tsx +++ b/src/client/views/Main.tsx @@ -63,7 +63,7 @@ import { PresBox, PresElementBox } from './nodes/trails'; import { SearchBox } from './search/SearchBox'; import { ImageLabelBox } from './collections/collectionFreeForm/ImageLabelBox'; import { FaceRecognitionHandler } from './search/FaceRecognitionHandler'; -import { FaceCollectionBox } from './collections/collectionFreeForm/FaceCollectionBox'; +import { FaceCollectionBox, UniqueFaceBox } from './collections/collectionFreeForm/FaceCollectionBox'; import { Node } from 'prosemirror-model'; import { EditorView } from 'prosemirror-view'; @@ -140,6 +140,7 @@ FieldLoader.ServerLoadStatus = { requested: 0, retrieved: 0, message: 'cache' }; SearchBox, ImageLabelBox, FaceCollectionBox, + UniqueFaceBox, FunctionPlotBox, InkingStroke, LinkBox, diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx index 3f8aee792..6402ef16c 100644 --- a/src/client/views/collections/CollectionStackingView.tsx +++ b/src/client/views/collections/CollectionStackingView.tsx @@ -98,7 +98,7 @@ export class CollectionStackingView extends CollectionSubView Doc | undefined; // specify a layout Doc template to use for children of the collection childHideDecorationTitle?: boolean; childHideResizeHandles?: boolean; + childHideDecorations?: boolean; childDragAction?: dropActionType; childXPadding?: number; childYPadding?: number; diff --git a/src/client/views/collections/collectionFreeForm/FaceCollectionBox.scss b/src/client/views/collections/collectionFreeForm/FaceCollectionBox.scss index 480d109c8..86120f966 100644 --- a/src/client/views/collections/collectionFreeForm/FaceCollectionBox.scss +++ b/src/client/views/collections/collectionFreeForm/FaceCollectionBox.scss @@ -1,10 +1,11 @@ .face-document-item { - background: #555555; margin-top: 10px; margin-bottom: 10px; padding: 10px; - border-radius: 10px; + border-radius: inherit; position: relative; + width: 100%; + height: 100%; h1 { color: white; @@ -14,14 +15,31 @@ .face-collection-buttons { position: absolute; - top: 10px; + top: 0px; right: 10px; } + .face-collection-toggle { + position: absolute; + top: 0px; + left: 10px; + } + .face-document-top { + position: absolute; + top: 0; + margin: auto; + width: 100%; + left: 0; + } .face-document-image-container { display: flex; justify-content: center; flex-wrap: wrap; + overflow-x: hidden; + overflow-y: auto; + position: absolute; + top: 75px; + height: calc(100% - 75px); .image-wrapper { position: relative; diff --git a/src/client/views/collections/collectionFreeForm/FaceCollectionBox.tsx b/src/client/views/collections/collectionFreeForm/FaceCollectionBox.tsx index 1cc1f59dc..6a0d51e32 100644 --- a/src/client/views/collections/collectionFreeForm/FaceCollectionBox.tsx +++ b/src/client/views/collections/collectionFreeForm/FaceCollectionBox.tsx @@ -6,23 +6,21 @@ import 'ldrs/ring'; import { action, makeObservable, observable } from 'mobx'; import { observer } from 'mobx-react'; import React from 'react'; -import { setupMoveUpEvents } from '../../../../ClientUtils'; -import { Utils, emptyFunction } from '../../../../Utils'; +import { lightOrDark, returnTrue, setupMoveUpEvents } from '../../../../ClientUtils'; +import { emptyFunction } from '../../../../Utils'; import { Doc, Opt } from '../../../../fields/Doc'; -import { Id } from '../../../../fields/FieldSymbols'; import { List } from '../../../../fields/List'; -import { ImageCast } from '../../../../fields/Types'; +import { ImageCast, StrCast } from '../../../../fields/Types'; import { DocumentType } from '../../../documents/DocumentTypes'; import { Docs } from '../../../documents/Documents'; import { DragManager } from '../../../util/DragManager'; import { dropActionType } from '../../../util/DropActionTypes'; -import { SnappingManager } from '../../../util/SnappingManager'; import { undoable } from '../../../util/UndoManager'; import { ViewBoxBaseComponent } from '../../DocComponent'; -import { ObservableReactComponent } from '../../ObservableReactComponent'; import { DocumentView } from '../../nodes/DocumentView'; import { FieldView, FieldViewProps } from '../../nodes/FieldView'; import { FaceRecognitionHandler } from '../../search/FaceRecognitionHandler'; +import { CollectionStackingView } from '../CollectionStackingView'; import './FaceCollectionBox.scss'; import { MarqueeOptionsMenu } from './MarqueeOptionsMenu'; @@ -31,31 +29,29 @@ import { MarqueeOptionsMenu } from './MarqueeOptionsMenu'; * unique face in turn displays the set of images that correspond to the face. */ -interface UniqueFaceProps { - faceDoc: Doc; -} - /** - * React component for rendering a unique face and its collection of image Docs. + * Viewer for unique face Doc collections. * * This both displays a collection of images corresponding tp a unique face, and * allows for editing the face collection by removing an image, or drag-and-dropping * an image that was not recognized. */ @observer -export class UniqueFaceView extends ObservableReactComponent { +export class UniqueFaceBox extends ViewBoxBaseComponent() { + public static LayoutString(fieldKey: string) { + return FieldView.LayoutString(UniqueFaceBox, fieldKey); + } private _dropDisposer?: DragManager.DragDropDisposer; + private _oldWheel: HTMLElement | null = null; - constructor(props: UniqueFaceProps) { + constructor(props: FieldViewProps) { super(props); makeObservable(this); } - @observable _displayImages: boolean = true; - protected createDropTarget = (ele: HTMLDivElement) => { this._dropDisposer?.(); - ele && (this._dropDisposer = DragManager.MakeDropTarget(ele, this.onInternalDrop.bind(this), this._props.faceDoc)); + ele && (this._dropDisposer = DragManager.MakeDropTarget(ele, this.onInternalDrop.bind(this), this._props.Document)); }; protected onInternalDrop(e: Event, de: DragManager.DropEvent): boolean { @@ -63,12 +59,12 @@ export class UniqueFaceView extends ObservableReactComponent { ?.filter(doc => doc.type === DocumentType.IMG) .forEach(imgDoc => { // If the current Face Document has no faces, and the doc has more than one face descriptor, don't let the user add the document first. Or should we just use the first face ? - if (FaceRecognitionHandler.UniqueFaceDescriptors(this._props.faceDoc).length === 0 && FaceRecognitionHandler.ImageDocFaceDescriptors(imgDoc).length > 1) { + if (FaceRecognitionHandler.UniqueFaceDescriptors(this._props.Document).length === 0 && FaceRecognitionHandler.ImageDocFaceDescriptors(imgDoc).length > 1) { alert('Cannot add a document with multiple faces as the first item!'); } else { // Loop through the documents' face descriptors and choose the face in the iage with the smallest distance (most similar to the face colleciton) - const faceDescriptorsAsFloat32Array = FaceRecognitionHandler.UniqueFaceDescriptors(this._props.faceDoc).map(fd => new Float32Array(Array.from(fd))); - const labeledFaceDescriptor = new faceapi.LabeledFaceDescriptors(FaceRecognitionHandler.UniqueFaceLabel(this._props.faceDoc), faceDescriptorsAsFloat32Array); + const faceDescriptorsAsFloat32Array = FaceRecognitionHandler.UniqueFaceDescriptors(this._props.Document).map(fd => new Float32Array(Array.from(fd))); + const labeledFaceDescriptor = new faceapi.LabeledFaceDescriptors(FaceRecognitionHandler.UniqueFaceLabel(this._props.Document), faceDescriptorsAsFloat32Array); const faceMatcher = new FaceMatcher([labeledFaceDescriptor], 1); const { face_match } = FaceRecognitionHandler.ImageDocFaceDescriptors(imgDoc).reduce( (prev, face) => { @@ -80,11 +76,12 @@ export class UniqueFaceView extends ObservableReactComponent { // assign the face in the image that's closest to the face collection to be the face that's assigned to the collection if (face_match) { - FaceRecognitionHandler.UniqueFaceAddFaceImage(imgDoc, face_match, this._props.faceDoc); + FaceRecognitionHandler.UniqueFaceAddFaceImage(imgDoc, face_match, this._props.Document); } } }); - return false; + e.stopPropagation(); + return true; } /** @@ -92,14 +89,15 @@ export class UniqueFaceView extends ObservableReactComponent { */ @action onDisplayClick() { - this._displayImages = !this._displayImages; + this._props.Document._displayImages = !this.props.Document._displayImages; + this._props.Document.height = this._props.Document._displayImages ? 400 : 100; } /** * Removes a unique face Doc from the colelction of unique faces. */ deleteUniqueFace = undoable(() => { - FaceRecognitionHandler.DeleteUniqueFace(this._props.faceDoc); + FaceRecognitionHandler.DeleteUniqueFace(this._props.Document); }, 'delete face'); /** @@ -107,9 +105,11 @@ export class UniqueFaceView extends ObservableReactComponent { * @param imgDoc - image Doc to remove */ removeFaceImageFromUniqueFace = undoable((imgDoc: Doc) => { - FaceRecognitionHandler.UniqueFaceRemoveFaceImage(imgDoc, this._props.faceDoc); + FaceRecognitionHandler.UniqueFaceRemoveFaceImage(imgDoc, this._props.Document); }, 'remove doc from face'); + onPassiveWheel = (e: WheelEvent) => e.stopPropagation(); + render() { return (
this.createDropTarget(ele!)}> @@ -117,23 +117,35 @@ export class UniqueFaceView extends ObservableReactComponent {
-

{FaceRecognitionHandler.UniqueFaceLabel(this._props.faceDoc)}

+

{FaceRecognitionHandler.UniqueFaceLabel(this._props.Document)}

- this.onDisplayClick()} - icon={} - color={MarqueeOptionsMenu.Instance.userColor} - style={{ width: '19px' }} - /> - {this._displayImages ? ( -
- {FaceRecognitionHandler.UniqueFaceImages(this._props.faceDoc).map(doc => { +
+ this.onDisplayClick()} + icon={} + color={MarqueeOptionsMenu.Instance.userColor} + style={{ width: '19px' }} + /> +
+ {this.props.Document._displayImages ? ( +
{ + this._oldWheel?.removeEventListener('wheel', this.onPassiveWheel); + this._oldWheel = ele; + // prevent wheel events from passively propagating up through containers and prevents containers from preventDefault which would block scrolling + ele?.addEventListener('wheel', this.onPassiveWheel, { passive: false }); + }}> + {FaceRecognitionHandler.UniqueFaceImages(this._props.Document).map((doc, i) => { const [name, type] = ImageCast(doc[Doc.LayoutFieldKey(doc)]).url.href.split('.'); return (
setupMoveUpEvents( this, @@ -165,8 +177,8 @@ export class UniqueFaceView extends ObservableReactComponent { * * Since the collection of recognized faces is stored on the active dashboard, this class * does not itself store any Docs, but accesses the myUniqueFaces field of the current - * dashboard. Each Face collection Doc is rendered using a FaceCollectionDocView which - * is not a CollectionView or even a DocumentView (but probably should be). + * dashboard. (This should probably go away as Doc type in favor of it just being a + * stacking collection of uniqueFace docs) */ @observer export class FaceCollectionBox extends ViewBoxBaseComponent() { @@ -179,18 +191,29 @@ export class FaceCollectionBox extends ViewBoxBaseComponent() { makeObservable(this); } + moveDocument = (doc: Doc | Doc[], targetCollection: Doc | undefined, addDocument: (doc: Doc | Doc[]) => boolean): boolean => !!(this._props.removeDocument?.(doc) && addDocument?.(doc)); + render() { - return ( -
- {FaceRecognitionHandler.UniqueFaces().map(doc => ( - - ))} -
+ return !Doc.ActiveDashboard ? null : ( + ); } } Docs.Prototypes.TemplateMap.set(DocumentType.FACECOLLECTION, { layout: { view: FaceCollectionBox, dataField: 'data' }, - options: { acl: '', _width: 400 }, + options: { acl: '', _width: 400, dropAction: dropActionType.embed }, +}); + +Docs.Prototypes.TemplateMap.set(DocumentType.UFACE, { + layout: { view: UniqueFaceBox, dataField: 'face_images' }, + options: { acl: '', _width: 400, _height: 400 }, }); diff --git a/src/client/views/search/FaceRecognitionHandler.tsx b/src/client/views/search/FaceRecognitionHandler.tsx index a17e4c54a..1ab084eaa 100644 --- a/src/client/views/search/FaceRecognitionHandler.tsx +++ b/src/client/views/search/FaceRecognitionHandler.tsx @@ -8,6 +8,8 @@ import { Cast, ImageCast, NumCast, StrCast } from '../../../fields/Types'; import { DocumentType } from '../../documents/DocumentTypes'; import { DocumentManager } from '../../util/DocumentManager'; import { ImageField } from '../../../fields/URLField'; +import { UniqueFaceBox } from '../collections/collectionFreeForm/FaceCollectionBox'; +import { Docs } from '../../documents/Documents'; /** * A singleton class that handles face recognition and manages face Doc collections for each face found. @@ -169,15 +171,25 @@ export class FaceRecognitionHandler { * @returns a unique face Doc */ private createUniqueFaceDoc = (dashboard: Doc) => { - const faceDocNum = NumCast(dashboard.myUniqueFaces_count) + 1; - dashboard.myUniqueFaces_count = faceDocNum; // TODO: improve to a better name - - const uniqueFaceDoc = new Doc(); - uniqueFaceDoc.title = `Face ${faceDocNum}`; - uniqueFaceDoc.face = ''; // just to make prettyprinting look better - uniqueFaceDoc.face_label = `Face${faceDocNum}`; - uniqueFaceDoc.face_images = new List(); - uniqueFaceDoc.face_descriptors = new List>(); + const faceDocNum = NumCast(dashboard[DocData].myUniqueFaces_count) + 1; + dashboard[DocData].myUniqueFaces_count = faceDocNum; // TODO: improve to a better name + + const uniqueFaceDoc = Docs.Create.UniqeFaceDocument({ + title: `Face ${faceDocNum}`, + _layout_reflowHorizontal: true, + _layout_reflowVertical: true, + _layout_nativeDimEditable: true, + _layout_borderRounding: '20px', + backgroundColor: '#555555', + _width: 400, + _height: 400, + }); + const uface = uniqueFaceDoc[DocData]; + uface.face = ''; // just to make prettyprinting look better + uface.face_label = `Face${faceDocNum}`; + uface.face_images = new List(); + uface.face_descriptors = new List>(); + Doc.SetContainer(uniqueFaceDoc, Doc.MyFaceCollection); Doc.ActiveDashboard && Doc.AddDocToList(Doc.ActiveDashboard[DocData], 'myUniqueFaces', uniqueFaceDoc); return uniqueFaceDoc; @@ -222,8 +234,8 @@ export class FaceRecognitionHandler { setTimeout(() => this.classifyFacesInImage(imgDoc), 1000); } else { const imgUrl = ImageCast(imgDoc[Doc.LayoutFieldKey(imgDoc)]); - if (imgUrl && !DocListCast(Doc.MyFaceCollection.examinedFaceDocs).includes(imgDoc)) { // only examine Docs that have an image and that haven't already been examined. - Doc.AddDocToList(Doc.MyFaceCollection, 'examinedFaceDocs', imgDoc); + if (imgUrl && !DocListCast(Doc.MyFaceCollection.examinedFaceDocs).includes(imgDoc[DocData])) { // only examine Docs that have an image and that haven't already been examined. + Doc.AddDocToList(Doc.MyFaceCollection, 'examinedFaceDocs', imgDoc[DocData]); FaceRecognitionHandler.initImageDocFaceDescriptors(imgDoc); FaceRecognitionHandler.loadImage(imgUrl).then( // load image and analyze faces img => faceapi.detectAllFaces(img).withFaceLandmarks().withFaceDescriptors() -- cgit v1.2.3-70-g09d2 From d12b43191e01e837d5a144fb19d9d3cd8eadd777 Mon Sep 17 00:00:00 2001 From: bobzel Date: Mon, 26 Aug 2024 15:17:14 -0400 Subject: from last --- src/client/documents/Documents.ts | 1 + .../collectionFreeForm/FaceCollectionBox.scss | 19 ++++--- .../collectionFreeForm/FaceCollectionBox.tsx | 60 ++++++++++++++-------- src/client/views/search/FaceRecognitionHandler.tsx | 5 +- 4 files changed, 54 insertions(+), 31 deletions(-) (limited to 'src') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index c2211fb80..ac271526f 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -362,6 +362,7 @@ export class DocumentOptions { data?: FieldType; data_useCors?: BOOLt = new BoolInfo('whether CORS protocol should be used for web page'); + _face_showImages?: BOOLt = new BoolInfo('whether to show images in uniqe face Doc'); columnHeaders?: List; // headers for stacking views schemaHeaders?: List; // headers for schema view dockingConfig?: STRt = new StrInfo('configuration of golden layout windows (applies only if doc is rendered as a CollectionDockingView)', false); diff --git a/src/client/views/collections/collectionFreeForm/FaceCollectionBox.scss b/src/client/views/collections/collectionFreeForm/FaceCollectionBox.scss index 86120f966..00297a97d 100644 --- a/src/client/views/collections/collectionFreeForm/FaceCollectionBox.scss +++ b/src/client/views/collections/collectionFreeForm/FaceCollectionBox.scss @@ -1,11 +1,10 @@ .face-document-item { - margin-top: 10px; - margin-bottom: 10px; - padding: 10px; - border-radius: inherit; - position: relative; + display: flex; + height: max-content; + flex-direction: column; + top: 0; + position: absolute; width: 100%; - height: 100%; h1 { color: white; @@ -24,11 +23,12 @@ left: 10px; } .face-document-top { - position: absolute; + position: relative; top: 0; margin: auto; width: 100%; left: 0; + height: 60px; } .face-document-image-container { @@ -37,9 +37,8 @@ flex-wrap: wrap; overflow-x: hidden; overflow-y: auto; - position: absolute; - top: 75px; - height: calc(100% - 75px); + position: relative; + padding: 10px; .image-wrapper { position: relative; diff --git a/src/client/views/collections/collectionFreeForm/FaceCollectionBox.tsx b/src/client/views/collections/collectionFreeForm/FaceCollectionBox.tsx index 6a0d51e32..33fc3c210 100644 --- a/src/client/views/collections/collectionFreeForm/FaceCollectionBox.tsx +++ b/src/client/views/collections/collectionFreeForm/FaceCollectionBox.tsx @@ -3,14 +3,14 @@ import { IconButton, Size } from 'browndash-components'; import * as faceapi from 'face-api.js'; import { FaceMatcher } from 'face-api.js'; import 'ldrs/ring'; -import { action, makeObservable, observable } from 'mobx'; +import { IReactionDisposer, action, makeObservable, observable, reaction } from 'mobx'; import { observer } from 'mobx-react'; import React from 'react'; -import { lightOrDark, returnTrue, setupMoveUpEvents } from '../../../../ClientUtils'; +import { DivHeight, lightOrDark, returnTrue, setupMoveUpEvents } from '../../../../ClientUtils'; import { emptyFunction } from '../../../../Utils'; import { Doc, Opt } from '../../../../fields/Doc'; import { List } from '../../../../fields/List'; -import { ImageCast, StrCast } from '../../../../fields/Types'; +import { ImageCast, NumCast, StrCast } from '../../../../fields/Types'; import { DocumentType } from '../../../documents/DocumentTypes'; import { Docs } from '../../../documents/Documents'; import { DragManager } from '../../../util/DragManager'; @@ -48,10 +48,29 @@ export class UniqueFaceBox extends ViewBoxBaseComponent() { super(props); makeObservable(this); } + @observable _headerRef: HTMLDivElement | null = null; + @observable _listRef: HTMLDivElement | null = null; + _disposers: { [key: string]: IReactionDisposer } = {}; + _lastHeight = 0; + observer = new ResizeObserver(() => this._props.setHeight?.((this.props.Document._face_showImages ? 20 : 0) + (!this._headerRef ? 0 : DivHeight(this._headerRef)) + (!this._listRef ? 0 : DivHeight(this._listRef)))); + + componentDidMount(): void { + this._disposers.refList = reaction( + () => ({ refList: [this._headerRef, this._listRef], autoHeight: this.layoutDoc._layout_autoHeight && !DocumentView.LightboxContains(this.DocumentView?.()) }), + ({ refList, autoHeight }) => { + this.observer.disconnect(); + if (autoHeight) refList.filter(r => r).forEach(r => this.observer.observe(r!)); + }, + { fireImmediately: true } + ); + } + componentWillUnmount(): void { + //this._disposers?.(); + } protected createDropTarget = (ele: HTMLDivElement) => { this._dropDisposer?.(); - ele && (this._dropDisposer = DragManager.MakeDropTarget(ele, this.onInternalDrop.bind(this), this._props.Document)); + ele && (this._dropDisposer = DragManager.MakeDropTarget(ele, this.onInternalDrop.bind(this), this.Document)); }; protected onInternalDrop(e: Event, de: DragManager.DropEvent): boolean { @@ -59,12 +78,12 @@ export class UniqueFaceBox extends ViewBoxBaseComponent() { ?.filter(doc => doc.type === DocumentType.IMG) .forEach(imgDoc => { // If the current Face Document has no faces, and the doc has more than one face descriptor, don't let the user add the document first. Or should we just use the first face ? - if (FaceRecognitionHandler.UniqueFaceDescriptors(this._props.Document).length === 0 && FaceRecognitionHandler.ImageDocFaceDescriptors(imgDoc).length > 1) { + if (FaceRecognitionHandler.UniqueFaceDescriptors(this.Document).length === 0 && FaceRecognitionHandler.ImageDocFaceDescriptors(imgDoc).length > 1) { alert('Cannot add a document with multiple faces as the first item!'); } else { // Loop through the documents' face descriptors and choose the face in the iage with the smallest distance (most similar to the face colleciton) - const faceDescriptorsAsFloat32Array = FaceRecognitionHandler.UniqueFaceDescriptors(this._props.Document).map(fd => new Float32Array(Array.from(fd))); - const labeledFaceDescriptor = new faceapi.LabeledFaceDescriptors(FaceRecognitionHandler.UniqueFaceLabel(this._props.Document), faceDescriptorsAsFloat32Array); + const faceDescriptorsAsFloat32Array = FaceRecognitionHandler.UniqueFaceDescriptors(this.Document).map(fd => new Float32Array(Array.from(fd))); + const labeledFaceDescriptor = new faceapi.LabeledFaceDescriptors(FaceRecognitionHandler.UniqueFaceLabel(this.Document), faceDescriptorsAsFloat32Array); const faceMatcher = new FaceMatcher([labeledFaceDescriptor], 1); const { face_match } = FaceRecognitionHandler.ImageDocFaceDescriptors(imgDoc).reduce( (prev, face) => { @@ -76,7 +95,7 @@ export class UniqueFaceBox extends ViewBoxBaseComponent() { // assign the face in the image that's closest to the face collection to be the face that's assigned to the collection if (face_match) { - FaceRecognitionHandler.UniqueFaceAddFaceImage(imgDoc, face_match, this._props.Document); + FaceRecognitionHandler.UniqueFaceAddFaceImage(imgDoc, face_match, this.Document); } } }); @@ -87,17 +106,17 @@ export class UniqueFaceBox extends ViewBoxBaseComponent() { /** * Toggles whether a Face Document displays its associated docs. */ - @action onDisplayClick() { - this._props.Document._displayImages = !this.props.Document._displayImages; - this._props.Document.height = this._props.Document._displayImages ? 400 : 100; + this.Document._face_showImages && (this._lastHeight = NumCast(this.Document.height)); + this.Document._face_showImages = !this.Document._face_showImages; + setTimeout(action(() => (!this.Document.layout_autoHeight || !this.Document._face_showImages) && (this.Document.height = this.Document._face_showImages ? this._lastHeight : 60))); } /** * Removes a unique face Doc from the colelction of unique faces. */ deleteUniqueFace = undoable(() => { - FaceRecognitionHandler.DeleteUniqueFace(this._props.Document); + FaceRecognitionHandler.DeleteUniqueFace(this.Document); }, 'delete face'); /** @@ -105,7 +124,7 @@ export class UniqueFaceBox extends ViewBoxBaseComponent() { * @param imgDoc - image Doc to remove */ removeFaceImageFromUniqueFace = undoable((imgDoc: Doc) => { - FaceRecognitionHandler.UniqueFaceRemoveFaceImage(imgDoc, this._props.Document); + FaceRecognitionHandler.UniqueFaceRemoveFaceImage(imgDoc, this.Document); }, 'remove doc from face'); onPassiveWheel = (e: WheelEvent) => e.stopPropagation(); @@ -116,31 +135,32 @@ export class UniqueFaceBox extends ViewBoxBaseComponent() {
-
-

{FaceRecognitionHandler.UniqueFaceLabel(this._props.Document)}

+
(this._headerRef = r))}> +

{FaceRecognitionHandler.UniqueFaceLabel(this.Document)}

this.onDisplayClick()} - icon={} + icon={} color={MarqueeOptionsMenu.Instance.userColor} style={{ width: '19px' }} />
- {this.props.Document._displayImages ? ( + {this.props.Document._face_showImages ? (
{ + ref={action((ele: HTMLDivElement | null) => { + this._listRef = ele; this._oldWheel?.removeEventListener('wheel', this.onPassiveWheel); this._oldWheel = ele; // prevent wheel events from passively propagating up through containers and prevents containers from preventDefault which would block scrolling ele?.addEventListener('wheel', this.onPassiveWheel, { passive: false }); - }}> - {FaceRecognitionHandler.UniqueFaceImages(this._props.Document).map((doc, i) => { + })}> + {FaceRecognitionHandler.UniqueFaceImages(this.Document).map((doc, i) => { const [name, type] = ImageCast(doc[Doc.LayoutFieldKey(doc)]).url.href.split('.'); return (
Date: Mon, 26 Aug 2024 16:46:13 -0400 Subject: added recognizeFaces for face images --- src/client/util/CurrentUserUtils.ts | 2 +- src/client/util/SettingsManager.tsx | 11 ++++++ src/client/views/StyleProvider.tsx | 2 + .../collectionFreeForm/FaceCollectionBox.scss | 11 +++++- .../collectionFreeForm/FaceCollectionBox.tsx | 45 +++++++++++++++------- src/client/views/search/FaceRecognitionHandler.tsx | 1 + 6 files changed, 55 insertions(+), 17 deletions(-) (limited to 'src') diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts index 0681a21cb..dc0c95121 100644 --- a/src/client/util/CurrentUserUtils.ts +++ b/src/client/util/CurrentUserUtils.ts @@ -497,7 +497,7 @@ pie title Minerals in my tap water static setupFaceCollection(doc: Doc, field: string) { return DocUtils.AssignDocField(doc, field, (opts) => Docs.Create.FaceCollectionDocument(opts), { - dontRegisterView: true, backgroundColor: "dimgray", ignoreClick: true, title: "Face Collection", isSystem: true, childDragAction: dropActionType.embed, + dontRegisterView: true, ignoreClick: true, title: "Face Collection", isSystem: true, childDragAction: dropActionType.embed, _lockedPosition: true, _type_collection: CollectionViewType.Schema }); } diff --git a/src/client/util/SettingsManager.tsx b/src/client/util/SettingsManager.tsx index 2d8763b63..fde8869e3 100644 --- a/src/client/util/SettingsManager.tsx +++ b/src/client/util/SettingsManager.tsx @@ -231,6 +231,17 @@ export class SettingsManager extends React.Component { size={Size.XSMALL} color={SettingsManager.userColor} /> + { + Doc.UserDoc().recognizeFaceImages = !Doc.UserDoc().recognizeFaceImages; + }} + toggleStatus={BoolCast(Doc.UserDoc().recognizeFaceImages)} + size={Size.XSMALL} + color={SettingsManager.userColor} + /> , props: Opt() { } private _dropDisposer?: DragManager.DragDropDisposer; private _oldWheel: HTMLElement | null = null; + private _disposers: { [key: string]: IReactionDisposer } = {}; + private _lastHeight = 0; constructor(props: FieldViewProps) { super(props); @@ -50,13 +52,17 @@ export class UniqueFaceBox extends ViewBoxBaseComponent() { } @observable _headerRef: HTMLDivElement | null = null; @observable _listRef: HTMLDivElement | null = null; - _disposers: { [key: string]: IReactionDisposer } = {}; - _lastHeight = 0; - observer = new ResizeObserver(() => this._props.setHeight?.((this.props.Document._face_showImages ? 20 : 0) + (!this._headerRef ? 0 : DivHeight(this._headerRef)) + (!this._listRef ? 0 : DivHeight(this._listRef)))); + observer = new ResizeObserver(a => { + this._props.setHeight?.( + (this.props.Document._face_showImages ? 20 : 0) + // + (!this._headerRef ? 0 : DivHeight(this._headerRef)) + + (!this._listRef ? 0 : DivHeight(this._listRef)) + ); + }); componentDidMount(): void { this._disposers.refList = reaction( - () => ({ refList: [this._headerRef, this._listRef], autoHeight: this.layoutDoc._layout_autoHeight && !DocumentView.LightboxContains(this.DocumentView?.()) }), + () => ({ refList: [this._headerRef, this._listRef], autoHeight: this.layoutDoc._layout_autoHeight }), ({ refList, autoHeight }) => { this.observer.disconnect(); if (autoHeight) refList.filter(r => r).forEach(r => this.observer.observe(r!)); @@ -66,7 +72,8 @@ export class UniqueFaceBox extends ViewBoxBaseComponent() { } componentWillUnmount(): void { - //this._disposers?.(); + this.observer.disconnect(); + Object.keys(this._disposers).forEach(key => this._disposers[key]()); } protected createDropTarget = (ele: HTMLDivElement) => { this._dropDisposer?.(); @@ -213,17 +220,27 @@ export class FaceCollectionBox extends ViewBoxBaseComponent() { moveDocument = (doc: Doc | Doc[], targetCollection: Doc | undefined, addDocument: (doc: Doc | Doc[]) => boolean): boolean => !!(this._props.removeDocument?.(doc) && addDocument?.(doc)); + stackingStyleProvider = (doc: Doc | undefined, props: Opt, property: string) => { + if (doc === Doc.ActiveDashboard) return this._props.styleProvider?.(this.Document, this._props, property); + return this._props.styleProvider?.(doc, this._props, property); + }; render() { return !Doc.ActiveDashboard ? null : ( - +
+
+
(Doc.UserDoc().recognizeFaceImages = !Doc.UserDoc().recognizeFaceImages))}>{`Face Recgognition is ${Doc.UserDoc().recognizeFaceImages ? 'on' : 'off'}`}
+
+ +
); } } diff --git a/src/client/views/search/FaceRecognitionHandler.tsx b/src/client/views/search/FaceRecognitionHandler.tsx index f613f78ce..7c8043219 100644 --- a/src/client/views/search/FaceRecognitionHandler.tsx +++ b/src/client/views/search/FaceRecognitionHandler.tsx @@ -230,6 +230,7 @@ export class FaceRecognitionHandler { * @param imgDoc The document being analyzed. */ private classifyFacesInImage = async (imgDoc: Doc) => { + if (!Doc.UserDoc().recognizeFaceImages) return; const activeDashboard = Doc.ActiveDashboard; if (!this._apiModelReady || !activeDashboard) { this._pendingAPIModelReadyDocs.push(imgDoc); -- cgit v1.2.3-70-g09d2 From 66daf540d581d49af5d5901963dbb95cbc2643a0 Mon Sep 17 00:00:00 2001 From: bobzel Date: Mon, 26 Aug 2024 20:19:27 -0400 Subject: from last --- src/client/views/search/FaceRecognitionHandler.tsx | 1 - 1 file changed, 1 deletion(-) (limited to 'src') diff --git a/src/client/views/search/FaceRecognitionHandler.tsx b/src/client/views/search/FaceRecognitionHandler.tsx index 7c8043219..e35f860ab 100644 --- a/src/client/views/search/FaceRecognitionHandler.tsx +++ b/src/client/views/search/FaceRecognitionHandler.tsx @@ -183,7 +183,6 @@ export class FaceRecognitionHandler { _layout_fitWidth: true, _layout_autoHeight: true, _face_showImages: true, - backgroundColor: '#555555', _width: 400, _height: 100, }); -- cgit v1.2.3-70-g09d2 From c4586cb36939561a8d0dd2dcbab4a20c51aaba5f Mon Sep 17 00:00:00 2001 From: bobzel Date: Mon, 26 Aug 2024 20:23:23 -0400 Subject: from last --- src/client/util/CurrentUserUtils.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts index dc0c95121..14fb65252 100644 --- a/src/client/util/CurrentUserUtils.ts +++ b/src/client/util/CurrentUserUtils.ts @@ -451,10 +451,10 @@ pie title Minerals in my tap water { title: "Closed", toolTip: "Recently Closed", target: this.setupRecentlyClosed(doc, "myRecentlyClosed"), ignoreClick: true, icon: "archive", hidden: true }, // this doc is hidden from the Sidebar, but it's still being used in MyFilesystem which ignores the hidden field { title: "Shared", toolTip: "Shared Docs", target: Doc.MySharedDocs, ignoreClick: true, icon: "users", funcs: {badgeValue: badgeValue}}, { title: "Trails", toolTip: "Trails ⌘R", target: Doc.UserDoc(), ignoreClick: true, icon: "pres-trail", funcs: {target: getActiveDashTrails}}, - { title: "User Doc", toolTip: "User Doc", target: this.setupUserDocView(doc, "myUserDocView"), ignoreClick: true, icon: "address-card",funcs: {hidden: "IsNoviceMode()"} }, { title: "Image Grouper", toolTip: "Image Grouper", target: this.setupImageGrouper(doc, "myImageGrouper"), ignoreClick: true, icon: "folder-open", hidden: false }, - { title: "Face Collection", toolTip: "Face Collection", target: this.setupFaceCollection(doc, "myFaceCollection"), ignoreClick: true, icon: "face-smile", hidden: false }, - ].map(tuple => ({...tuple, scripts:{onClick: 'selectMainMenu(this)'}})); + { title: "Faces", toolTip: "Unique Faces", target: this.setupFaceCollection(doc, "myFaceCollection"), ignoreClick: true, icon: "face-smile", hidden: false }, + { title: "User Doc", toolTip: "User Doc", target: this.setupUserDocView(doc, "myUserDocView"), ignoreClick: true, icon: "address-card",funcs: {hidden: "IsNoviceMode()"} }, + ].map(tuple => ({...tuple, scripts:{onClick: 'selectMainMenu(this)'}})); } /// the empty panel that is filled with whichever left menu button's panel has been selected -- cgit v1.2.3-70-g09d2 From 9a92fa403a5e2a094763d6f92ac55549aecf359c Mon Sep 17 00:00:00 2001 From: bobzel Date: Mon, 26 Aug 2024 20:38:01 -0400 Subject: cleanup of faces and tags --- src/client/views/TagsView.tsx | 4 ++++ .../collectionFreeForm/FaceCollectionBox.tsx | 17 +++++++++++++---- src/client/views/search/FaceRecognitionHandler.tsx | 5 ++--- 3 files changed, 19 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/client/views/TagsView.tsx b/src/client/views/TagsView.tsx index 394162f46..82c85ddf0 100644 --- a/src/client/views/TagsView.tsx +++ b/src/client/views/TagsView.tsx @@ -252,6 +252,10 @@ export class TagsView extends ObservableReactComponent { return this._isEditing && DocumentView.SelectedDocs().includes(this._props.View.Document); } + /** + * Shows or hides the editing UI for adding/removing Doc tags + * @param editing + */ @action setToEditing = (editing = true) => { this._isEditing = editing; diff --git a/src/client/views/collections/collectionFreeForm/FaceCollectionBox.tsx b/src/client/views/collections/collectionFreeForm/FaceCollectionBox.tsx index 7820af8aa..662436ddc 100644 --- a/src/client/views/collections/collectionFreeForm/FaceCollectionBox.tsx +++ b/src/client/views/collections/collectionFreeForm/FaceCollectionBox.tsx @@ -42,7 +42,6 @@ export class UniqueFaceBox extends ViewBoxBaseComponent() { return FieldView.LayoutString(UniqueFaceBox, fieldKey); } private _dropDisposer?: DragManager.DragDropDisposer; - private _oldWheel: HTMLElement | null = null; private _disposers: { [key: string]: IReactionDisposer } = {}; private _lastHeight = 0; @@ -50,8 +49,10 @@ export class UniqueFaceBox extends ViewBoxBaseComponent() { super(props); makeObservable(this); } + @observable _headerRef: HTMLDivElement | null = null; @observable _listRef: HTMLDivElement | null = null; + observer = new ResizeObserver(a => { this._props.setHeight?.( (this.props.Document._face_showImages ? 20 : 0) + // @@ -75,6 +76,7 @@ export class UniqueFaceBox extends ViewBoxBaseComponent() { this.observer.disconnect(); Object.keys(this._disposers).forEach(key => this._disposers[key]()); } + protected createDropTarget = (ele: HTMLDivElement) => { this._dropDisposer?.(); ele && (this._dropDisposer = DragManager.MakeDropTarget(ele, this.onInternalDrop.bind(this), this.Document)); @@ -111,7 +113,8 @@ export class UniqueFaceBox extends ViewBoxBaseComponent() { } /** - * Toggles whether a Face Document displays its associated docs. + * Toggles whether a Face Document displays its associated docs. This saves and restores the last height of the Doc since + * toggling the associated Documentss overwrites the Doc height. */ onDisplayClick() { this.Document._face_showImages && (this._lastHeight = NumCast(this.Document.height)); @@ -134,6 +137,9 @@ export class UniqueFaceBox extends ViewBoxBaseComponent() { FaceRecognitionHandler.UniqueFaceRemoveFaceImage(imgDoc, this.Document); }, 'remove doc from face'); + /** + * This stops scroll wheel events when they are used to scroll the face collection. + */ onPassiveWheel = (e: WheelEvent) => e.stopPropagation(); render() { @@ -161,9 +167,8 @@ export class UniqueFaceBox extends ViewBoxBaseComponent() { pointerEvents: this._props.isContentActive() ? undefined : 'none', }} ref={action((ele: HTMLDivElement | null) => { + this._listRef?.removeEventListener('wheel', this.onPassiveWheel); this._listRef = ele; - this._oldWheel?.removeEventListener('wheel', this.onPassiveWheel); - this._oldWheel = ele; // prevent wheel events from passively propagating up through containers and prevents containers from preventDefault which would block scrolling ele?.addEventListener('wheel', this.onPassiveWheel, { passive: false }); })}> @@ -220,6 +225,10 @@ export class FaceCollectionBox extends ViewBoxBaseComponent() { moveDocument = (doc: Doc | Doc[], targetCollection: Doc | undefined, addDocument: (doc: Doc | Doc[]) => boolean): boolean => !!(this._props.removeDocument?.(doc) && addDocument?.(doc)); + /** + * this changes style provider requests that target the dashboard to requests that target the face collection box which is what's actually being rendered. + * This is needed, for instance, to get the default background color from the face collection, not the dashboard. + */ stackingStyleProvider = (doc: Doc | undefined, props: Opt, property: string) => { if (doc === Doc.ActiveDashboard) return this._props.styleProvider?.(this.Document, this._props, property); return this._props.styleProvider?.(doc, this._props, property); diff --git a/src/client/views/search/FaceRecognitionHandler.tsx b/src/client/views/search/FaceRecognitionHandler.tsx index e35f860ab..8513ec94d 100644 --- a/src/client/views/search/FaceRecognitionHandler.tsx +++ b/src/client/views/search/FaceRecognitionHandler.tsx @@ -5,11 +5,10 @@ import { DocData } from '../../../fields/DocSymbols'; import { List } from '../../../fields/List'; import { listSpec } from '../../../fields/Schema'; import { Cast, ImageCast, NumCast, StrCast } from '../../../fields/Types'; -import { DocumentType } from '../../documents/DocumentTypes'; -import { DocumentManager } from '../../util/DocumentManager'; import { ImageField } from '../../../fields/URLField'; -import { UniqueFaceBox } from '../collections/collectionFreeForm/FaceCollectionBox'; +import { DocumentType } from '../../documents/DocumentTypes'; import { Docs } from '../../documents/Documents'; +import { DocumentManager } from '../../util/DocumentManager'; /** * A singleton class that handles face recognition and manages face Doc collections for each face found. -- cgit v1.2.3-70-g09d2 From f0d9731e1c43ee13114d42db8c4e27c94bbbf3c0 Mon Sep 17 00:00:00 2001 From: bobzel Date: Mon, 26 Aug 2024 22:25:58 -0400 Subject: made face doc labels editable --- .../views/collections/collectionFreeForm/FaceCollectionBox.scss | 6 ++++++ .../views/collections/collectionFreeForm/FaceCollectionBox.tsx | 4 +++- src/client/views/search/FaceRecognitionHandler.tsx | 9 +++++---- 3 files changed, 14 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/client/views/collections/collectionFreeForm/FaceCollectionBox.scss b/src/client/views/collections/collectionFreeForm/FaceCollectionBox.scss index a72efc948..0a001d84c 100644 --- a/src/client/views/collections/collectionFreeForm/FaceCollectionBox.scss +++ b/src/client/views/collections/collectionFreeForm/FaceCollectionBox.scss @@ -11,6 +11,12 @@ color: white; font-size: 24px; text-align: center; + .face-document-name { + text-align: center; + background: transparent; + width: 80%; + border: transparent; + } } .face-collection-buttons { diff --git a/src/client/views/collections/collectionFreeForm/FaceCollectionBox.tsx b/src/client/views/collections/collectionFreeForm/FaceCollectionBox.tsx index 662436ddc..7e47292e5 100644 --- a/src/client/views/collections/collectionFreeForm/FaceCollectionBox.tsx +++ b/src/client/views/collections/collectionFreeForm/FaceCollectionBox.tsx @@ -149,7 +149,9 @@ export class UniqueFaceBox extends ViewBoxBaseComponent() {
(this._headerRef = r))}> -

{FaceRecognitionHandler.UniqueFaceLabel(this.Document)}

+

+ FaceRecognitionHandler.SetUniqueFaceLabel(this.Document, e.currentTarget.value)} value={FaceRecognitionHandler.UniqueFaceLabel(this.Document)} /> +

StrCast(faceDoc[DocData].face_label); + public static UniqueFaceLabel = (faceDoc: Doc) => StrCast(faceDoc[DocData].face); + + public static SetUniqueFaceLabel = (faceDoc: Doc, value: string) => (faceDoc[DocData].face = value); /** * Returns all the face descriptors associated with a unique face Doc * @param faceDoc unique face Doc @@ -186,8 +188,7 @@ export class FaceRecognitionHandler { _height: 100, }); const uface = uniqueFaceDoc[DocData]; - uface.face = ''; // just to make prettyprinting look better - uface.face_label = `Face${faceDocNum}`; + uface.face = `Face${faceDocNum}`; uface.face_images = new List(); uface.face_descriptors = new List>(); Doc.SetContainer(uniqueFaceDoc, Doc.MyFaceCollection); -- cgit v1.2.3-70-g09d2 From cf38fc81b69abb084938c8f45eaf5d94caacb3a3 Mon Sep 17 00:00:00 2001 From: bobzel Date: Mon, 26 Aug 2024 22:49:10 -0400 Subject: added face rectangle annotations for faces in images --- src/client/views/search/FaceRecognitionHandler.tsx | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/client/views/search/FaceRecognitionHandler.tsx b/src/client/views/search/FaceRecognitionHandler.tsx index dee0ab99b..4e500d24e 100644 --- a/src/client/views/search/FaceRecognitionHandler.tsx +++ b/src/client/views/search/FaceRecognitionHandler.tsx @@ -243,12 +243,17 @@ export class FaceRecognitionHandler { FaceRecognitionHandler.loadImage(imgUrl).then( // load image and analyze faces img => faceapi.detectAllFaces(img).withFaceLandmarks().withFaceDescriptors() .then(imgDocFaceDescriptions => { // For each face detected, find a match. + const annos = [] as Doc[]; + const scale = NumCast(imgDoc.data_nativeWidth) / img.width; for (const fd of imgDocFaceDescriptions) { const faceDescriptor = new List(Array.from(fd.descriptor)); + annos.push(Docs.Create.FreeformDocument([], {backgroundColor: "#55555555", x: fd.alignedRect.box.left*scale, y: fd.alignedRect.box.top*scale, _width: fd.alignedRect.box.width*scale, _height: fd.alignedRect.box.height*scale})) FaceRecognitionHandler.ImageDocAddFaceDescriptor(imgDoc, faceDescriptor); // add face descriptor to image's list of descriptors const matchedUniqueFace = this.findMatchingFaceDoc(fd.descriptor) ?? this.createUniqueFaceDoc(activeDashboard); FaceRecognitionHandler.UniqueFaceAddFaceImage(imgDoc, faceDescriptor, matchedUniqueFace); // add image/faceDescriptor to matched unique face - } // + } + + imgDoc[DocData].data_annotations = new List(annos); return imgDocFaceDescriptions; }) ); -- cgit v1.2.3-70-g09d2 From ef5a8b8261052c3079f267d1d8d0804a495e3e3d Mon Sep 17 00:00:00 2001 From: bobzel Date: Mon, 26 Aug 2024 23:29:47 -0400 Subject: fixed naming of face annotations --- src/client/documents/Documents.ts | 1 + src/client/views/search/FaceRecognitionHandler.tsx | 56 ++++++++++++++-------- 2 files changed, 38 insertions(+), 19 deletions(-) (limited to 'src') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index ac271526f..235f54fe8 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -363,6 +363,7 @@ export class DocumentOptions { data?: FieldType; data_useCors?: BOOLt = new BoolInfo('whether CORS protocol should be used for web page'); _face_showImages?: BOOLt = new BoolInfo('whether to show images in uniqe face Doc'); + face?: DOCt = new DocInfo('face document'); columnHeaders?: List; // headers for stacking views schemaHeaders?: List; // headers for schema view dockingConfig?: STRt = new StrInfo('configuration of golden layout windows (applies only if doc is rendered as a CollectionDockingView)', false); diff --git a/src/client/views/search/FaceRecognitionHandler.tsx b/src/client/views/search/FaceRecognitionHandler.tsx index 4e500d24e..4906ba4b6 100644 --- a/src/client/views/search/FaceRecognitionHandler.tsx +++ b/src/client/views/search/FaceRecognitionHandler.tsx @@ -9,6 +9,7 @@ import { ImageField } from '../../../fields/URLField'; import { DocumentType } from '../../documents/DocumentTypes'; import { Docs } from '../../documents/Documents'; import { DocumentManager } from '../../util/DocumentManager'; +import { ComputedField } from '../../../fields/ScriptField'; /** * A singleton class that handles face recognition and manages face Doc collections for each face found. @@ -176,7 +177,7 @@ export class FaceRecognitionHandler { dashboard[DocData].myUniqueFaces_count = faceDocNum; // TODO: improve to a better name const uniqueFaceDoc = Docs.Create.UniqeFaceDocument({ - title: `Face ${faceDocNum}`, + title: ComputedField.MakeFunction('this.face') as unknown as string, _layout_reflowHorizontal: true, _layout_reflowVertical: true, _layout_nativeDimEditable: true, @@ -237,27 +238,44 @@ export class FaceRecognitionHandler { setTimeout(() => this.classifyFacesInImage(imgDoc), 1000); } else { const imgUrl = ImageCast(imgDoc[Doc.LayoutFieldKey(imgDoc)]); - if (imgUrl && !DocListCast(Doc.MyFaceCollection.examinedFaceDocs).includes(imgDoc[DocData])) { // only examine Docs that have an image and that haven't already been examined. + if (imgUrl && !DocListCast(Doc.MyFaceCollection.examinedFaceDocs).includes(imgDoc[DocData])) { + // only examine Docs that have an image and that haven't already been examined. Doc.AddDocToList(Doc.MyFaceCollection, 'examinedFaceDocs', imgDoc[DocData]); FaceRecognitionHandler.initImageDocFaceDescriptors(imgDoc); - FaceRecognitionHandler.loadImage(imgUrl).then( // load image and analyze faces - img => faceapi.detectAllFaces(img).withFaceLandmarks().withFaceDescriptors() - .then(imgDocFaceDescriptions => { // For each face detected, find a match. - const annos = [] as Doc[]; - const scale = NumCast(imgDoc.data_nativeWidth) / img.width; - for (const fd of imgDocFaceDescriptions) { - const faceDescriptor = new List(Array.from(fd.descriptor)); - annos.push(Docs.Create.FreeformDocument([], {backgroundColor: "#55555555", x: fd.alignedRect.box.left*scale, y: fd.alignedRect.box.top*scale, _width: fd.alignedRect.box.width*scale, _height: fd.alignedRect.box.height*scale})) - FaceRecognitionHandler.ImageDocAddFaceDescriptor(imgDoc, faceDescriptor); // add face descriptor to image's list of descriptors - const matchedUniqueFace = this.findMatchingFaceDoc(fd.descriptor) ?? this.createUniqueFaceDoc(activeDashboard); - FaceRecognitionHandler.UniqueFaceAddFaceImage(imgDoc, faceDescriptor, matchedUniqueFace); // add image/faceDescriptor to matched unique face - } + FaceRecognitionHandler.loadImage(imgUrl).then( + // load image and analyze faces + img => faceapi + .detectAllFaces(img) + .withFaceLandmarks() + .withFaceDescriptors() + .then(imgDocFaceDescriptions => { // For each face detected, find a match. + const annos = [] as Doc[]; + const scale = NumCast(imgDoc.data_nativeWidth) / img.width; + imgDocFaceDescriptions.forEach((fd, i) => { + const faceDescriptor = new List(Array.from(fd.descriptor)); + FaceRecognitionHandler.ImageDocAddFaceDescriptor(imgDoc, faceDescriptor); // add face descriptor to image's list of descriptors + const matchedUniqueFace = this.findMatchingFaceDoc(fd.descriptor) ?? this.createUniqueFaceDoc(activeDashboard); + FaceRecognitionHandler.UniqueFaceAddFaceImage(imgDoc, faceDescriptor, matchedUniqueFace); // add image/faceDescriptor to matched unique face + annos.push( + Docs.Create.FreeformDocument([], { + title: ComputedField.MakeFunction(`this.face.face`) as unknown as string, // + annotationOn: imgDoc, + face: matchedUniqueFace, + backgroundColor: '#55555555', + x: fd.alignedRect.box.left * scale, + y: fd.alignedRect.box.top * scale, + _width: fd.alignedRect.box.width * scale, + _height: fd.alignedRect.box.height * scale, + }) + ); + Doc.SetContainer(annos.lastElement(), imgDoc[DocData]); + }); - imgDoc[DocData].data_annotations = new List(annos); - return imgDocFaceDescriptions; - }) - ); - } // prettier-ignore + imgDoc[DocData].data_annotations = new List(annos); + return imgDocFaceDescriptions; + }) + ); // prettier-ignore + } } }; } -- cgit v1.2.3-70-g09d2 From 5180a22ad70cb79ff2167a3aa0a63962ec6b0319 Mon Sep 17 00:00:00 2001 From: bobzel Date: Mon, 26 Aug 2024 23:49:35 -0400 Subject: made face annotation titles editable to edit face doc. --- src/client/views/search/FaceRecognitionHandler.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/client/views/search/FaceRecognitionHandler.tsx b/src/client/views/search/FaceRecognitionHandler.tsx index 4906ba4b6..0cee7184c 100644 --- a/src/client/views/search/FaceRecognitionHandler.tsx +++ b/src/client/views/search/FaceRecognitionHandler.tsx @@ -177,7 +177,7 @@ export class FaceRecognitionHandler { dashboard[DocData].myUniqueFaces_count = faceDocNum; // TODO: improve to a better name const uniqueFaceDoc = Docs.Create.UniqeFaceDocument({ - title: ComputedField.MakeFunction('this.face') as unknown as string, + title: ComputedField.MakeFunction('this.face', undefined, undefined, 'this.face = value') as unknown as string, _layout_reflowHorizontal: true, _layout_reflowVertical: true, _layout_nativeDimEditable: true, @@ -258,9 +258,9 @@ export class FaceRecognitionHandler { FaceRecognitionHandler.UniqueFaceAddFaceImage(imgDoc, faceDescriptor, matchedUniqueFace); // add image/faceDescriptor to matched unique face annos.push( Docs.Create.FreeformDocument([], { - title: ComputedField.MakeFunction(`this.face.face`) as unknown as string, // + title: ComputedField.MakeFunction(`this.face.face`, undefined, undefined, 'this.face.face = value') as unknown as string, // annotationOn: imgDoc, - face: matchedUniqueFace, + face: matchedUniqueFace[DocData], backgroundColor: '#55555555', x: fd.alignedRect.box.left * scale, y: fd.alignedRect.box.top * scale, -- cgit v1.2.3-70-g09d2 From 248f9fdced99a36c28fb34f39b78e1267ec02486 Mon Sep 17 00:00:00 2001 From: bobzel Date: Tue, 27 Aug 2024 08:23:04 -0400 Subject: allow non-faces to be added to face collections --- .../views/collections/collectionFreeForm/FaceCollectionBox.tsx | 6 ++---- src/client/views/search/FaceRecognitionHandler.tsx | 10 ++++++---- 2 files changed, 8 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/client/views/collections/collectionFreeForm/FaceCollectionBox.tsx b/src/client/views/collections/collectionFreeForm/FaceCollectionBox.tsx index 7e47292e5..ea1c22962 100644 --- a/src/client/views/collections/collectionFreeForm/FaceCollectionBox.tsx +++ b/src/client/views/collections/collectionFreeForm/FaceCollectionBox.tsx @@ -102,10 +102,8 @@ export class UniqueFaceBox extends ViewBoxBaseComponent() { { dist: 1, face_match: undefined as Opt> } ); - // assign the face in the image that's closest to the face collection to be the face that's assigned to the collection - if (face_match) { - FaceRecognitionHandler.UniqueFaceAddFaceImage(imgDoc, face_match, this.Document); - } + // assign the face in the image that's closest to the face collection's face + FaceRecognitionHandler.UniqueFaceAddFaceImage(imgDoc, face_match, this.Document); } }); e.stopPropagation(); diff --git a/src/client/views/search/FaceRecognitionHandler.tsx b/src/client/views/search/FaceRecognitionHandler.tsx index 0cee7184c..021802061 100644 --- a/src/client/views/search/FaceRecognitionHandler.tsx +++ b/src/client/views/search/FaceRecognitionHandler.tsx @@ -1,6 +1,6 @@ import * as faceapi from 'face-api.js'; import { FaceMatcher } from 'face-api.js'; -import { Doc, DocListCast } from '../../../fields/Doc'; +import { Doc, DocListCast, Opt } from '../../../fields/Doc'; import { DocData } from '../../../fields/DocSymbols'; import { List } from '../../../fields/List'; import { listSpec } from '../../../fields/Schema'; @@ -133,10 +133,12 @@ export class FaceRecognitionHandler { * @param faceDescriptor - the face descriptor for the face in the image to add * @param faceDoc - unique face Doc */ - public static UniqueFaceAddFaceImage = (img: Doc, faceDescriptor: List, faceDoc: Doc) => { + public static UniqueFaceAddFaceImage = (img: Doc, faceDescriptor: Opt>, faceDoc: Doc) => { Doc.AddDocToList(faceDoc, 'face_images', img); - Cast(faceDoc.face_descriptors, listSpec('number'), null).push(faceDescriptor as unknown as number); // items are lists of numbers, not numbers, but type system can't handle that - Doc.AddDocToList(img[DocData], FaceRecognitionHandler.ImageDocFaceField(img), faceDoc); + if (faceDescriptor) { + Cast(faceDoc.face_descriptors, listSpec('number'), null).push(faceDescriptor as unknown as number); // items are lists of numbers, not numbers, but type system can't handle that + Doc.AddDocToList(img[DocData], FaceRecognitionHandler.ImageDocFaceField(img), faceDoc); + } }; /** -- cgit v1.2.3-70-g09d2 From cf10fbb80a022ddb141e41203b9135b6f1ed9527 Mon Sep 17 00:00:00 2001 From: bobzel Date: Tue, 27 Aug 2024 13:49:07 -0400 Subject: uniying image labels => tags. made face tags distinguishable from other tags - and drag off to place face collection. --- src/client/documents/Documents.ts | 1 + src/client/views/TagsView.scss | 4 + src/client/views/TagsView.tsx | 61 +++++++---- .../collectionFreeForm/FaceCollectionBox.tsx | 33 ++++-- .../collectionFreeForm/ImageLabelBox.tsx | 10 +- src/client/views/search/FaceRecognitionHandler.tsx | 112 +++++++-------------- src/fields/Doc.ts | 6 +- 7 files changed, 117 insertions(+), 110 deletions(-) (limited to 'src') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 235f54fe8..af181b031 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -364,6 +364,7 @@ export class DocumentOptions { data_useCors?: BOOLt = new BoolInfo('whether CORS protocol should be used for web page'); _face_showImages?: BOOLt = new BoolInfo('whether to show images in uniqe face Doc'); face?: DOCt = new DocInfo('face document'); + faceDescriptor?: List; columnHeaders?: List; // headers for stacking views schemaHeaders?: List; // headers for schema view dockingConfig?: STRt = new StrInfo('configuration of golden layout windows (applies only if doc is rendered as a CollectionDockingView)', false); diff --git a/src/client/views/TagsView.scss b/src/client/views/TagsView.scss index f7365a51b..24f9e86bc 100644 --- a/src/client/views/TagsView.scss +++ b/src/client/views/TagsView.scss @@ -24,6 +24,10 @@ align-items: center; } +.faceItem { + background-color: lightGreen; +} + .tagsView-suggestions-box { display: flex; flex-wrap: wrap; diff --git a/src/client/views/TagsView.tsx b/src/client/views/TagsView.tsx index 82c85ddf0..da1add55b 100644 --- a/src/client/views/TagsView.tsx +++ b/src/client/views/TagsView.tsx @@ -6,10 +6,10 @@ import React from 'react'; import ResizeObserver from 'resize-observer-polyfill'; import { returnFalse, setupMoveUpEvents } from '../../ClientUtils'; import { emptyFunction } from '../../Utils'; -import { Doc, DocListCast, Opt, StrListCast } from '../../fields/Doc'; +import { Doc, DocListCast, Field, Opt, StrListCast } from '../../fields/Doc'; import { DocData } from '../../fields/DocSymbols'; import { List } from '../../fields/List'; -import { NumCast, StrCast } from '../../fields/Types'; +import { DocCast, NumCast, StrCast } from '../../fields/Types'; import { DocumentType } from '../documents/DocumentTypes'; import { DragManager } from '../util/DragManager'; import { SnappingManager } from '../util/SnappingManager'; @@ -17,6 +17,7 @@ import { undoable } from '../util/UndoManager'; import { ObservableReactComponent } from './ObservableReactComponent'; import './TagsView.scss'; import { DocumentView } from './nodes/DocumentView'; +import { FaceRecognitionHandler } from './search/FaceRecognitionHandler'; /** * The TagsView is a metadata input/display panel shown at the bottom of a DocumentView in a freeform collection. @@ -158,6 +159,10 @@ export class TagItem extends ObservableReactComponent { * @returns */ createTagCollection = () => { + if (!this._props.tagDoc) { + const face = FaceRecognitionHandler.FindUniqueFaceByName(this._props.tag); + return face ? Doc.MakeEmbedding(face) : undefined; + } // Get the documents that contain the tag. const newEmbeddings = TagItem.allDocsWithTag(this._props.tag).map(doc => Doc.MakeEmbedding(doc)); @@ -188,9 +193,13 @@ export class TagItem extends ObservableReactComponent { this, e, () => { - const dragData = new DragManager.DocumentDragData([this.createTagCollection()]); - DragManager.StartDocumentDrag([this._ref.current!], dragData, e.clientX, e.clientY, {}); - return true; + const dragCollection = this.createTagCollection(); + if (dragCollection) { + const dragData = new DragManager.DocumentDragData([dragCollection]); + DragManager.StartDocumentDrag([this._ref.current!], dragData, e.clientX, e.clientY, {}); + return true; + } + return false; }, returnFalse, emptyFunction @@ -199,20 +208,20 @@ export class TagItem extends ObservableReactComponent { }; render() { - setTimeout(() => TagItem.addTagToDoc(this._props.doc, this._props.tag)); // bcz: hack to make sure that Docs are added to their tag Doc collection since metadata can get set anywhere without a guard triggering an add to the collection + this._props.tagDoc && setTimeout(() => TagItem.addTagToDoc(this._props.doc, this._props.tag)); // bcz: hack to make sure that Docs are added to their tag Doc collection since metadata can get set anywhere without a guard triggering an add to the collection const tag = this._props.tag.replace(/^#/, ''); const metadata = tag.startsWith('@') ? tag.replace(/^@/, '') : ''; return ( -
+
{metadata ? ( {tag}  - {this._props.doc[metadata] as string} + {Field.toString(this._props.doc[metadata])} ) : ( tag )} - {this.props.showRemoveUI && ( + {this.props.showRemoveUI && this._props.tagDoc && ( TagItem.removeTagFromDoc(this._props.doc, this._props.tag, this._props.tagDoc), `remove tag ${this._props.tag}`)} @@ -234,12 +243,9 @@ interface TagViewProps { */ @observer export class TagsView extends ObservableReactComponent { - private _ref: React.RefObject; - constructor(props: any) { super(props); makeObservable(this); - this._ref = React.createRef(); } @observable _currentInput = ''; @@ -268,18 +274,26 @@ export class TagsView extends ObservableReactComponent { * just the tag. * @param tag tag string to add */ - submitTag = undoable((tag: string) => { - const submittedLabel = tag.trim(); - submittedLabel && TagItem.addTagToDoc(this._props.View.Document, '#' + submittedLabel.replace(/^#/, '')); - this._currentInput = ''; // Clear the input box - }, 'added doc label'); + submitTag = undoable( + action((tag: string) => { + const submittedLabel = tag.trim(); + submittedLabel && TagItem.addTagToDoc(this._props.View.Document, '#' + submittedLabel.replace(/^#/, '')); + this._currentInput = ''; // Clear the input box + }), + 'added doc label' + ); /** * When 'showTags' is set on a Doc, this displays a wrapping panel of tagItemViews corresponding to all the tags set on the Doc). * When the dropdown is clicked, this will toggle an extended UI that allows additional tags to be added/removed. */ render() { - const tagsList = StrListCast(this._props.View.dataDoc.tags); + const tagsList = new Set(StrListCast(this._props.View.dataDoc.tags)); + const facesList = new Set( + DocListCast(this._props.View.dataDoc[Doc.LayoutFieldKey(this._props.View.Document) + '_annotations']) + .filter(d => d.face) + .map(doc => StrCast(DocCast(doc.face)?.title)) + ); return !this._props.View.Document.showTags ? null : (
{ }}>
- {!tagsList.length ? null : ( // + {!tagsList.size ? null : ( // this.setToEditing(!this._isEditing)} icon={} /> )} - {tagsList.map(tag => ( - + {Array.from(tagsList).map((tag, i) => ( + + ))} + {Array.from(facesList).map((tag, i) => ( + ))}
{this.isEditing ? ( @@ -330,7 +347,7 @@ export class TagsView extends ObservableReactComponent { color={SnappingManager.userVariantColor} tooltip="Add existing tag" onClick={() => this.submitTag(tag)} - key={i} + key={tag} /> ); })} diff --git a/src/client/views/collections/collectionFreeForm/FaceCollectionBox.tsx b/src/client/views/collections/collectionFreeForm/FaceCollectionBox.tsx index ea1c22962..c62303dc0 100644 --- a/src/client/views/collections/collectionFreeForm/FaceCollectionBox.tsx +++ b/src/client/views/collections/collectionFreeForm/FaceCollectionBox.tsx @@ -9,8 +9,9 @@ import React from 'react'; import { DivHeight, lightOrDark, returnTrue, setupMoveUpEvents } from '../../../../ClientUtils'; import { emptyFunction } from '../../../../Utils'; import { Doc, Opt } from '../../../../fields/Doc'; +import { DocData } from '../../../../fields/DocSymbols'; import { List } from '../../../../fields/List'; -import { ImageCast, NumCast, StrCast } from '../../../../fields/Types'; +import { DocCast, ImageCast, NumCast, StrCast } from '../../../../fields/Types'; import { DocumentType } from '../../../documents/DocumentTypes'; import { Docs } from '../../../documents/Documents'; import { DragManager } from '../../../util/DragManager'; @@ -87,23 +88,27 @@ export class UniqueFaceBox extends ViewBoxBaseComponent() { ?.filter(doc => doc.type === DocumentType.IMG) .forEach(imgDoc => { // If the current Face Document has no faces, and the doc has more than one face descriptor, don't let the user add the document first. Or should we just use the first face ? - if (FaceRecognitionHandler.UniqueFaceDescriptors(this.Document).length === 0 && FaceRecognitionHandler.ImageDocFaceDescriptors(imgDoc).length > 1) { + if (FaceRecognitionHandler.UniqueFaceDescriptors(this.Document).length === 0 && FaceRecognitionHandler.ImageDocFaceAnnos(imgDoc).length > 1) { alert('Cannot add a document with multiple faces as the first item!'); } else { // Loop through the documents' face descriptors and choose the face in the iage with the smallest distance (most similar to the face colleciton) const faceDescriptorsAsFloat32Array = FaceRecognitionHandler.UniqueFaceDescriptors(this.Document).map(fd => new Float32Array(Array.from(fd))); const labeledFaceDescriptor = new faceapi.LabeledFaceDescriptors(FaceRecognitionHandler.UniqueFaceLabel(this.Document), faceDescriptorsAsFloat32Array); const faceMatcher = new FaceMatcher([labeledFaceDescriptor], 1); - const { face_match } = FaceRecognitionHandler.ImageDocFaceDescriptors(imgDoc).reduce( - (prev, face) => { - const match = faceMatcher.matchDescriptor(new Float32Array(Array.from(face))); - return match.distance < prev.dist ? { dist: match.distance, face_match: face } : prev; + const { faceAnno } = FaceRecognitionHandler.ImageDocFaceAnnos(imgDoc).reduce( + (prev, faceAnno) => { + const match = faceMatcher.matchDescriptor(new Float32Array(Array.from(faceAnno.faceDescriptor as List))); + return match.distance < prev.dist ? { dist: match.distance, faceAnno } : prev; }, - { dist: 1, face_match: undefined as Opt> } + { dist: 1, faceAnno: undefined as Opt } ); // assign the face in the image that's closest to the face collection's face - FaceRecognitionHandler.UniqueFaceAddFaceImage(imgDoc, face_match, this.Document); + if (faceAnno) { + FaceRecognitionHandler.UniqueFaceRemoveFaceImage(faceAnno, DocCast(faceAnno.face)); + FaceRecognitionHandler.UniqueFaceAddFaceImage(faceAnno, this.Document); + faceAnno.face = this.Document; + } } }); e.stopPropagation(); @@ -224,7 +229,15 @@ export class FaceCollectionBox extends ViewBoxBaseComponent() { } moveDocument = (doc: Doc | Doc[], targetCollection: Doc | undefined, addDocument: (doc: Doc | Doc[]) => boolean): boolean => !!(this._props.removeDocument?.(doc) && addDocument?.(doc)); - + addDocument = (doc: Doc | Doc[], annotationKey?: string) => { + const uniqueFaceDoc = doc instanceof Doc ? doc : doc[0]; + const added = uniqueFaceDoc.type === DocumentType.UFACE; + if (added) { + Doc.SetContainer(uniqueFaceDoc, Doc.MyFaceCollection); + Doc.ActiveDashboard && Doc.AddDocToList(Doc.ActiveDashboard[DocData], 'myUniqueFaces', uniqueFaceDoc); + } + return added; + }; /** * this changes style provider requests that target the dashboard to requests that target the face collection box which is what's actually being rendered. * This is needed, for instance, to get the default background color from the face collection, not the dashboard. @@ -233,6 +246,7 @@ export class FaceCollectionBox extends ViewBoxBaseComponent() { if (doc === Doc.ActiveDashboard) return this._props.styleProvider?.(this.Document, this._props, property); return this._props.styleProvider?.(doc, this._props, property); }; + render() { return !Doc.ActiveDashboard ? null : (
@@ -245,6 +259,7 @@ export class FaceCollectionBox extends ViewBoxBaseComponent() { Document={Doc.ActiveDashboard} fieldKey="myUniqueFaces" moveDocument={this.moveDocument} + addDocument={this.addDocument} isContentActive={returnTrue} isAnyChildContentActive={returnTrue} childHideDecorations={true} diff --git a/src/client/views/collections/collectionFreeForm/ImageLabelBox.tsx b/src/client/views/collections/collectionFreeForm/ImageLabelBox.tsx index 6eb3eb784..5d3154e3c 100644 --- a/src/client/views/collections/collectionFreeForm/ImageLabelBox.tsx +++ b/src/client/views/collections/collectionFreeForm/ImageLabelBox.tsx @@ -51,7 +51,7 @@ export class ImageLabelBoxData { label = label.toUpperCase().trim(); if (label.length > 0) { if (!this._labelGroups.includes(label)) { - this._labelGroups = [...this._labelGroups, label]; + this._labelGroups = [...this._labelGroups, label.startsWith('#') ? label : '#' + label]; } } }; @@ -178,8 +178,12 @@ export class ImageLabelBox extends ViewBoxBaseComponent() { const labels = imageInfo.labels.split('\n'); labels.forEach(label => { - label = label.replace(/^\d+\.\s*|-|f\*/, '').trim(); - console.log(label); + label = + '#' + + label + .replace(/^\d+\.\s*|-|f\*/, '') + .replace(/^#/, '') + .trim(); imageInfo.doc[DocData][label] = true; (imageInfo.doc[DocData].tags as List).push(label); }); diff --git a/src/client/views/search/FaceRecognitionHandler.tsx b/src/client/views/search/FaceRecognitionHandler.tsx index 021802061..4c10307e6 100644 --- a/src/client/views/search/FaceRecognitionHandler.tsx +++ b/src/client/views/search/FaceRecognitionHandler.tsx @@ -1,15 +1,14 @@ import * as faceapi from 'face-api.js'; import { FaceMatcher } from 'face-api.js'; -import { Doc, DocListCast, Opt } from '../../../fields/Doc'; +import { Doc, DocListCast } from '../../../fields/Doc'; import { DocData } from '../../../fields/DocSymbols'; import { List } from '../../../fields/List'; -import { listSpec } from '../../../fields/Schema'; -import { Cast, ImageCast, NumCast, StrCast } from '../../../fields/Types'; +import { ComputedField } from '../../../fields/ScriptField'; +import { DocCast, ImageCast, NumCast, StrCast } from '../../../fields/Types'; import { ImageField } from '../../../fields/URLField'; import { DocumentType } from '../../documents/DocumentTypes'; import { Docs } from '../../documents/Documents'; import { DocumentManager } from '../../util/DocumentManager'; -import { ComputedField } from '../../../fields/ScriptField'; /** * A singleton class that handles face recognition and manages face Doc collections for each face found. @@ -18,16 +17,17 @@ import { ComputedField } from '../../../fields/ScriptField'; * as a face collection Doc). If the face matches a face collection Doc, then it will be added to that * collection along with the numerical representation of the face, its face descriptor. * - * Image Doc's that are added to one or more face collection Docs will be given these metadata fields: - * _faceDescriptors - list of all the numerical face representations found in the image. - * _faces - list of unique face Docs corresponding to recognized faces in the image. + * Image Doc's that are added to one or more face collection Docs will be given an annotation rectangle that + * highlights where the face is, and the annotation will have these fields: + * faceDescriptor - the numerical face representations found in the image. + * face - the unique face Docs corresponding to recognized face in the image. + * annotationOn - the image where the face was found * * unique face Doc's are created for each person identified and are stored in the Dashboard's myUniqueFaces field * * Each unique face Doc represents a unique face and collects all matching face images for that person. It has these fields: * face - a string label for the person that was recognized (TODO: currently it's just a 'face#') - * face_descriptors - a list of all the face descriptors for different images of the person - * face_docList - a list of all image Docs that contain a face for the person + * face_annos - a list of face annotations, where each anno has */ export class FaceRecognitionHandler { static _instance: FaceRecognitionHandler; @@ -54,42 +54,12 @@ export class FaceRecognitionHandler { }); }; - /** - * return the metadata field name where unique face Docs are stored - * @param imgDoc image with faces - * @returns name of field - */ - private static ImageDocFaceField = (imgDoc: Doc) => `${Doc.LayoutFieldKey(imgDoc)}_faces`; - /** * Returns an array of faceDocs for each face recognized in the image * @param imgDoc image with faces * @returns faceDoc array */ - private static ImageDocFaces = (imgDoc: Doc) => DocListCast(imgDoc[`${Doc.LayoutFieldKey(imgDoc)}_faces`]); - - /** - * initializes an image with an empty list of face descriptors - * @param imgDoc image to initialize - */ - private static initImageDocFaceDescriptors = (imgDoc: Doc) => { - imgDoc[DocData][`${Doc.LayoutFieldKey(imgDoc)}_faceDescriptors`] = new List>(); - }; - /** - * returns the face descriptors for each face found on an image Doc - * @param imgDoc - * @returns list of face descriptors - */ - public static ImageDocFaceDescriptors = (imgDoc: Doc) => imgDoc[DocData][`${Doc.LayoutFieldKey(imgDoc)}_faceDescriptors`] as List>; - - /** - * Adds a face descriptor for a face found in an image - * @param imgDoc image Doc with face - * @param faceDescriptor descriptor of a face - */ - public static ImageDocAddFaceDescriptor = (imgDoc: Doc, faceDescriptor: List) => { - Cast(imgDoc[DocData][`${Doc.LayoutFieldKey(imgDoc)}_faceDescriptors`], listSpec('number'), null).push(faceDescriptor as unknown as number); - }; + public static ImageDocFaceAnnos = (imgDoc: Doc) => DocListCast(imgDoc[`${Doc.LayoutFieldKey(imgDoc)}_annotations`]).filter(doc => doc.face); /** * returns a list of all face collection Docs on the current dashboard @@ -97,6 +67,13 @@ export class FaceRecognitionHandler { */ public static UniqueFaces = () => DocListCast(Doc.ActiveDashboard?.[DocData].myUniqueFaces); + /** + * Find a unique face from its name + * @param name name of unique face + * @returns unique face or undefined + */ + public static FindUniqueFaceByName = (name: string) => FaceRecognitionHandler.UniqueFaces().find(faceDoc => faceDoc.title === name); + /** * Removes a unique face from the set of recognized unique faces * @param faceDoc unique face Doc @@ -117,28 +94,23 @@ export class FaceRecognitionHandler { * @param faceDoc unique face Doc * @returns face descriptors */ - public static UniqueFaceDescriptors = (faceDoc: Doc) => faceDoc[DocData].face_descriptors as List>; + public static UniqueFaceDescriptors = (faceDoc: Doc) => DocListCast(faceDoc[DocData].face_annos).map(face => face.faceDescriptor as List); /** * Returns a list of all face image Docs associated with a unique face Doc * @param faceDoc unique face Doc * @returns image Docs */ - public static UniqueFaceImages = (faceDoc: Doc) => DocListCast(faceDoc[DocData].face_images); + public static UniqueFaceImages = (faceDoc: Doc) => DocListCast(faceDoc[DocData].face_annos).map(face => DocCast(face.annotationOn)); /** * Adds a face image to a unique face Doc, adds the unique face Doc to the images list of reognized faces, * and updates the unique face's set of face image descriptors * @param img - image with faces to add to a face collection Doc - * @param faceDescriptor - the face descriptor for the face in the image to add - * @param faceDoc - unique face Doc + * @param faceAnno - a face annotation */ - public static UniqueFaceAddFaceImage = (img: Doc, faceDescriptor: Opt>, faceDoc: Doc) => { - Doc.AddDocToList(faceDoc, 'face_images', img); - if (faceDescriptor) { - Cast(faceDoc.face_descriptors, listSpec('number'), null).push(faceDescriptor as unknown as number); // items are lists of numbers, not numbers, but type system can't handle that - Doc.AddDocToList(img[DocData], FaceRecognitionHandler.ImageDocFaceField(img), faceDoc); - } + public static UniqueFaceAddFaceImage = (faceAnno: Doc, faceDoc: Doc) => { + Doc.AddDocToList(faceDoc, 'face_annos', faceAnno); }; /** @@ -146,11 +118,9 @@ export class FaceRecognitionHandler { * @param img - image with faces to remove * @param faceDoc - unique face Doc */ - public static UniqueFaceRemoveFaceImage = (img: Doc, faceDoc: Doc) => { - Doc.RemoveDocFromList(faceDoc[DocData], 'face_images', img); - const descriptorsEqual = (a: List, b: List) => (a === b ? true : a.length === b.length ? a.every((element, index) => element === b[index]) : false); - faceDoc[DocData].face_descriptors = new List>(FaceRecognitionHandler.UniqueFaceDescriptors(faceDoc).filter(fd => !FaceRecognitionHandler.ImageDocFaceDescriptors(img).some(desc => descriptorsEqual(fd, desc)))); - Doc.RemoveDocFromList(img[DocData], FaceRecognitionHandler.ImageDocFaceField(img), faceDoc); + public static UniqueFaceRemoveFaceImage = (faceAnno: Doc, faceDoc: Doc) => { + Doc.RemoveDocFromList(faceDoc[DocData], 'face_annos', faceAnno); + faceAnno.face = undefined; }; constructor() { @@ -192,8 +162,7 @@ export class FaceRecognitionHandler { }); const uface = uniqueFaceDoc[DocData]; uface.face = `Face${faceDocNum}`; - uface.face_images = new List(); - uface.face_descriptors = new List>(); + uface.face_annos = new List(); Doc.SetContainer(uniqueFaceDoc, Doc.MyFaceCollection); Doc.ActiveDashboard && Doc.AddDocToList(Doc.ActiveDashboard[DocData], 'myUniqueFaces', uniqueFaceDoc); @@ -243,7 +212,6 @@ export class FaceRecognitionHandler { if (imgUrl && !DocListCast(Doc.MyFaceCollection.examinedFaceDocs).includes(imgDoc[DocData])) { // only examine Docs that have an image and that haven't already been examined. Doc.AddDocToList(Doc.MyFaceCollection, 'examinedFaceDocs', imgDoc[DocData]); - FaceRecognitionHandler.initImageDocFaceDescriptors(imgDoc); FaceRecognitionHandler.loadImage(imgUrl).then( // load image and analyze faces img => faceapi @@ -255,22 +223,20 @@ export class FaceRecognitionHandler { const scale = NumCast(imgDoc.data_nativeWidth) / img.width; imgDocFaceDescriptions.forEach((fd, i) => { const faceDescriptor = new List(Array.from(fd.descriptor)); - FaceRecognitionHandler.ImageDocAddFaceDescriptor(imgDoc, faceDescriptor); // add face descriptor to image's list of descriptors const matchedUniqueFace = this.findMatchingFaceDoc(fd.descriptor) ?? this.createUniqueFaceDoc(activeDashboard); - FaceRecognitionHandler.UniqueFaceAddFaceImage(imgDoc, faceDescriptor, matchedUniqueFace); // add image/faceDescriptor to matched unique face - annos.push( - Docs.Create.FreeformDocument([], { - title: ComputedField.MakeFunction(`this.face.face`, undefined, undefined, 'this.face.face = value') as unknown as string, // - annotationOn: imgDoc, - face: matchedUniqueFace[DocData], - backgroundColor: '#55555555', - x: fd.alignedRect.box.left * scale, - y: fd.alignedRect.box.top * scale, - _width: fd.alignedRect.box.width * scale, - _height: fd.alignedRect.box.height * scale, - }) - ); - Doc.SetContainer(annos.lastElement(), imgDoc[DocData]); + const faceAnno = Docs.Create.FreeformDocument([], { + title: ComputedField.MakeFunction(`this.face.face`, undefined, undefined, 'this.face.face = value') as unknown as string, // + annotationOn: imgDoc, + face: matchedUniqueFace[DocData], + faceDescriptor: faceDescriptor, + backgroundColor: 'transparent', + x: fd.alignedRect.box.left * scale, + y: fd.alignedRect.box.top * scale, + _width: fd.alignedRect.box.width * scale, + _height: fd.alignedRect.box.height * scale, + }) + FaceRecognitionHandler.UniqueFaceAddFaceImage(faceAnno, matchedUniqueFace); // add image/faceDescriptor to matched unique face + annos.push(faceAnno); }); imgDoc[DocData].data_annotations = new List(annos); diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts index e3178f20c..7abba7679 100644 --- a/src/fields/Doc.ts +++ b/src/fields/Doc.ts @@ -791,9 +791,9 @@ export namespace Doc { linkMap.set(link[Id], await Doc.makeClone(link, cloneMap, linkMap, rtfs, exclusions, pruneDocs, cloneLinks, cloneTemplates)); } }); - if (Doc.Get(copy, 'title', true)) copy.title = '>:' + doc.title; - // Doc.SetInPlace(copy, 'title', '>:' + doc.title, true); copy.cloneOf = doc; + const cfield = ComputedField.WithoutComputed(() => FieldValue(doc.title)); + if (Doc.Get(copy, 'title', true) && !(cfield instanceof ComputedField)) copy.title = '>:' + doc.title; cloneMap.set(doc[Id], copy); return copy; @@ -1424,7 +1424,7 @@ export namespace Doc { export function Paste(docids: string[], clone: boolean, addDocument: (doc: Doc | Doc[]) => boolean, ptx?: number, pty?: number, newPoint?: number[]) { DocServer.GetRefFields(docids).then(async fieldlist => { - const list = Array.from(Object.values(fieldlist)) + const list = Array.from(fieldlist.values()) .map(d => DocCast(d)) .filter(d => d); const docs = clone ? (await Promise.all(Doc.MakeClones(list, false, false))).map(res => res.clone) : list; -- cgit v1.2.3-70-g09d2 From b8a04a0fedf8ef3612395764a0ecd01f6824ebd1 Mon Sep 17 00:00:00 2001 From: bobzel Date: Tue, 27 Aug 2024 13:54:39 -0400 Subject: from last --- src/client/views/TagsView.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/client/views/TagsView.tsx b/src/client/views/TagsView.tsx index da1add55b..d2ca77446 100644 --- a/src/client/views/TagsView.tsx +++ b/src/client/views/TagsView.tsx @@ -309,7 +309,7 @@ export class TagsView extends ObservableReactComponent { }}>
- {!tagsList.size ? null : ( // + {!tagsList.size && !facesList.size ? null : ( // this.setToEditing(!this._isEditing)} icon={} /> )} {Array.from(tagsList).map((tag, i) => ( -- cgit v1.2.3-70-g09d2 From a566129971f1a29b1d42679befa27c63b73a7167 Mon Sep 17 00:00:00 2001 From: bobzel Date: Tue, 27 Aug 2024 17:43:27 -0400 Subject: move chat tag labels to tags_chat and updated tagsView --- src/client/views/TagsView.tsx | 32 ++++++++++++++++++++-- .../collectionFreeForm/ImageLabelBox.tsx | 15 +++++----- 2 files changed, 37 insertions(+), 10 deletions(-) (limited to 'src') diff --git a/src/client/views/TagsView.tsx b/src/client/views/TagsView.tsx index d2ca77446..89025d668 100644 --- a/src/client/views/TagsView.tsx +++ b/src/client/views/TagsView.tsx @@ -1,6 +1,6 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { Button, Colors, IconButton } from 'browndash-components'; -import { action, computed, makeObservable, observable } from 'mobx'; +import { IReactionDisposer, action, computed, makeObservable, observable, reaction } from 'mobx'; import { observer } from 'mobx-react'; import React from 'react'; import ResizeObserver from 'resize-observer-polyfill'; @@ -248,11 +248,25 @@ export class TagsView extends ObservableReactComponent { makeObservable(this); } + @observable _panelHeightDirty = 0; @observable _currentInput = ''; @observable _isEditing = !StrListCast(this._props.View.dataDoc.tags).length; + _heightDisposer: IReactionDisposer | undefined; + + componentDidMount() { + this._heightDisposer = reaction( + () => this._props.View.screenToContentsTransform(), + xf => { + this._panelHeightDirty = this._panelHeightDirty + 1; + } + ); + } + componentWillUnmount() { + this._heightDisposer?.(); + } @computed get currentScale() { - return NumCast((this._props.View.Document.embedContainer as Doc)?._freeform_scale, 1); + return NumCast(DocCast(this._props.View.Document.embedContainer)?._freeform_scale, 1); } @computed get isEditing() { return this._isEditing && DocumentView.SelectedDocs().includes(this._props.View.Document); @@ -289,11 +303,13 @@ export class TagsView extends ObservableReactComponent { */ render() { const tagsList = new Set(StrListCast(this._props.View.dataDoc.tags)); + const chatTagsList = new Set(StrListCast(this._props.View.dataDoc.tags_chat)); const facesList = new Set( DocListCast(this._props.View.dataDoc[Doc.LayoutFieldKey(this._props.View.Document) + '_annotations']) .filter(d => d.face) .map(doc => StrCast(DocCast(doc.face)?.title)) ); + this._panelHeightDirty; return !this._props.View.Document.showTags ? null : (
{ /> ); })} + {Array.from(chatTagsList).map(tag => { + return ( +
) : null} diff --git a/src/client/views/collections/collectionFreeForm/ImageLabelBox.tsx b/src/client/views/collections/collectionFreeForm/ImageLabelBox.tsx index 5d3154e3c..e419e522c 100644 --- a/src/client/views/collections/collectionFreeForm/ImageLabelBox.tsx +++ b/src/client/views/collections/collectionFreeForm/ImageLabelBox.tsx @@ -163,7 +163,7 @@ export class ImageLabelBox extends ViewBoxBaseComponent() { // Converts the images into a Base64 format, afterwhich the information is sent to GPT to label them. const imageInfos = this._selectedImages.map(async doc => { - if (!doc[DocData].tags) { + if (!doc[DocData].tags_chat) { const [name, type] = ImageCast(doc[Doc.LayoutFieldKey(doc)]).url.href.split('.'); return CollectionCardView.imageUrlToBase64(`${name}_o.${type}`).then(hrefBase64 => !hrefBase64 ? undefined : @@ -174,7 +174,7 @@ export class ImageLabelBox extends ViewBoxBaseComponent() { (await Promise.all(imageInfos)).forEach(imageInfo => { if (imageInfo) { - imageInfo.doc[DocData].tags = (imageInfo.doc[DocData].tags as List) ?? new List(); + imageInfo.doc[DocData].tags_chat = (imageInfo.doc[DocData].tags_chat as List) ?? new List(); const labels = imageInfo.labels.split('\n'); labels.forEach(label => { @@ -184,8 +184,7 @@ export class ImageLabelBox extends ViewBoxBaseComponent() { .replace(/^\d+\.\s*|-|f\*/, '') .replace(/^#/, '') .trim(); - imageInfo.doc[DocData][label] = true; - (imageInfo.doc[DocData].tags as List).push(label); + (imageInfo.doc[DocData].tags_chat as List).push(label); }); } }); @@ -200,8 +199,8 @@ export class ImageLabelBox extends ViewBoxBaseComponent() { this.startLoading(); for (const doc of this._selectedImages) { - for (let index = 0; index < (doc[DocData].tags as List).length; index++) { - const label = (doc[DocData].tags as List)[index]; + for (let index = 0; index < (doc[DocData].tags_chat as List).length; index++) { + const label = (doc[DocData].tags_chat as List)[index]; const embedding = await gptGetEmbedding(label); doc[DocData][`tags_embedding_${index + 1}`] = new List(embedding); } @@ -214,7 +213,7 @@ export class ImageLabelBox extends ViewBoxBaseComponent() { // For each image, loop through the labels, and calculate similarity. Associate it with the // most similar one. this._selectedImages.forEach(doc => { - const embedLists = numberRange((doc[DocData].tags as List).length).map(n => Array.from(NumListCast(doc[DocData][`tags_embedding_${n + 1}`]))); + const embedLists = numberRange((doc[DocData].tags_chat as List).length).map(n => Array.from(NumListCast(doc[DocData][`tags_embedding_${n + 1}`]))); const bestEmbedScore = (embedding: Opt) => Math.max(...embedLists.map((l, index) => (embedding && similarity(Array.from(embedding), l)!) || 0)); const {label: mostSimilarLabelCollect} = this._labelGroups.map(label => ({ label, similarityScore: bestEmbedScore(labelToEmbedding.get(label)) })) @@ -321,7 +320,7 @@ export class ImageLabelBox extends ViewBoxBaseComponent() { await DocumentView.showDocument(doc, { willZoomCentered: true }); }}>
this._props.addDocTab(doc, OpenWhere.addRightKeyvalue)}> - {(doc[DocData].tags as List).map(label => { + {(doc[DocData].tags_chat as List).map(label => { return (
{label} -- cgit v1.2.3-70-g09d2 From e2a1db72c103b7ed878fe876c5fb9eacc7a8c893 Mon Sep 17 00:00:00 2001 From: bobzel Date: Tue, 27 Aug 2024 19:09:31 -0400 Subject: enabled any image Doc to be added to a face Doc --- src/client/views/TagsView.tsx | 1 + .../collectionFreeForm/FaceCollectionBox.tsx | 17 +++++++++-------- src/client/views/search/FaceRecognitionHandler.tsx | 2 +- 3 files changed, 11 insertions(+), 9 deletions(-) (limited to 'src') diff --git a/src/client/views/TagsView.tsx b/src/client/views/TagsView.tsx index 89025d668..0ac015b36 100644 --- a/src/client/views/TagsView.tsx +++ b/src/client/views/TagsView.tsx @@ -306,6 +306,7 @@ export class TagsView extends ObservableReactComponent { const chatTagsList = new Set(StrListCast(this._props.View.dataDoc.tags_chat)); const facesList = new Set( DocListCast(this._props.View.dataDoc[Doc.LayoutFieldKey(this._props.View.Document) + '_annotations']) + .concat(this._props.View.Document) .filter(d => d.face) .map(doc => StrCast(DocCast(doc.face)?.title)) ); diff --git a/src/client/views/collections/collectionFreeForm/FaceCollectionBox.tsx b/src/client/views/collections/collectionFreeForm/FaceCollectionBox.tsx index c62303dc0..717081666 100644 --- a/src/client/views/collections/collectionFreeForm/FaceCollectionBox.tsx +++ b/src/client/views/collections/collectionFreeForm/FaceCollectionBox.tsx @@ -95,17 +95,18 @@ export class UniqueFaceBox extends ViewBoxBaseComponent() { const faceDescriptorsAsFloat32Array = FaceRecognitionHandler.UniqueFaceDescriptors(this.Document).map(fd => new Float32Array(Array.from(fd))); const labeledFaceDescriptor = new faceapi.LabeledFaceDescriptors(FaceRecognitionHandler.UniqueFaceLabel(this.Document), faceDescriptorsAsFloat32Array); const faceMatcher = new FaceMatcher([labeledFaceDescriptor], 1); - const { faceAnno } = FaceRecognitionHandler.ImageDocFaceAnnos(imgDoc).reduce( - (prev, faceAnno) => { - const match = faceMatcher.matchDescriptor(new Float32Array(Array.from(faceAnno.faceDescriptor as List))); - return match.distance < prev.dist ? { dist: match.distance, faceAnno } : prev; - }, - { dist: 1, faceAnno: undefined as Opt } - ); + const faceAnno = + FaceRecognitionHandler.ImageDocFaceAnnos(imgDoc).reduce( + (prev, faceAnno) => { + const match = faceMatcher.matchDescriptor(new Float32Array(Array.from(faceAnno.faceDescriptor as List))); + return match.distance < prev.dist ? { dist: match.distance, faceAnno } : prev; + }, + { dist: 1, faceAnno: undefined as Opt } + ).faceAnno ?? imgDoc; // assign the face in the image that's closest to the face collection's face if (faceAnno) { - FaceRecognitionHandler.UniqueFaceRemoveFaceImage(faceAnno, DocCast(faceAnno.face)); + faceAnno.face && FaceRecognitionHandler.UniqueFaceRemoveFaceImage(faceAnno, DocCast(faceAnno.face)); FaceRecognitionHandler.UniqueFaceAddFaceImage(faceAnno, this.Document); faceAnno.face = this.Document; } diff --git a/src/client/views/search/FaceRecognitionHandler.tsx b/src/client/views/search/FaceRecognitionHandler.tsx index 4c10307e6..4f6f5d314 100644 --- a/src/client/views/search/FaceRecognitionHandler.tsx +++ b/src/client/views/search/FaceRecognitionHandler.tsx @@ -101,7 +101,7 @@ export class FaceRecognitionHandler { * @param faceDoc unique face Doc * @returns image Docs */ - public static UniqueFaceImages = (faceDoc: Doc) => DocListCast(faceDoc[DocData].face_annos).map(face => DocCast(face.annotationOn)); + public static UniqueFaceImages = (faceDoc: Doc) => DocListCast(faceDoc[DocData].face_annos).map(face => DocCast(face.annotationOn, face)); /** * Adds a face image to a unique face Doc, adds the unique face Doc to the images list of reognized faces, -- cgit v1.2.3-70-g09d2 From 9776e4584b61d3c67622d8ea1f2338a7dfbe857d Mon Sep 17 00:00:00 2001 From: bobzel Date: Tue, 27 Aug 2024 21:57:43 -0400 Subject: fixed type --- src/client/views/pdf/Annotation.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/client/views/pdf/Annotation.tsx b/src/client/views/pdf/Annotation.tsx index 3bd42873c..1891cfd4c 100644 --- a/src/client/views/pdf/Annotation.tsx +++ b/src/client/views/pdf/Annotation.tsx @@ -13,6 +13,7 @@ import { FieldViewProps } from '../nodes/FieldView'; import { OpenWhere } from '../nodes/OpenWhere'; import { AnchorMenu } from './AnchorMenu'; import './Annotation.scss'; +import { Property } from 'csstype'; interface IRegionAnnotationProps { x: number; @@ -45,7 +46,7 @@ interface IAnnotationProps extends FieldViewProps { annoDoc: Doc; containerDataDoc: Doc; fieldKey: string; - pointerEvents?: () => Opt; + pointerEvents?: () => Opt; } @observer export class Annotation extends ObservableReactComponent { -- cgit v1.2.3-70-g09d2 From c36607691e0b7f5c04f3209a64958f5e51ddd785 Mon Sep 17 00:00:00 2001 From: bobzel Date: Fri, 30 Aug 2024 00:06:05 -0400 Subject: fixed linking text anchors to dall-e images --- src/client/views/pdf/GPTPopup/GPTPopup.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/client/views/pdf/GPTPopup/GPTPopup.tsx b/src/client/views/pdf/GPTPopup/GPTPopup.tsx index 0920b1bd3..a37e73e27 100644 --- a/src/client/views/pdf/GPTPopup/GPTPopup.tsx +++ b/src/client/views/pdf/GPTPopup/GPTPopup.tsx @@ -268,7 +268,7 @@ export class GPTPopup extends ObservableReactComponent { * Transfers the image urls to actual image docs */ private transferToImage = (source: string) => { - const textAnchor = this.imgTargetDoc; + const textAnchor = this.textAnchor ?? this.imgTargetDoc; if (!textAnchor) return; const newDoc = Docs.Create.ImageDocument(source, { x: NumCast(textAnchor.x) + NumCast(textAnchor._width) + 10, -- cgit v1.2.3-70-g09d2 From b235e116167a06b6d36e2962dd3f610839f18974 Mon Sep 17 00:00:00 2001 From: bobzel Date: Sun, 1 Sep 2024 00:11:36 -0400 Subject: updated to latest Jimp. fixed lag dropping images from filesystem by using worker threads. --- package-lock.json | 8128 ++++---------------- package.json | 9 +- src/client/Network.ts | 2 +- src/client/util/request-image-size.ts | 9 +- .../collectionGrid/CollectionGridView.tsx | 17 +- src/server/ApiManagers/UploadManager.ts | 14 +- src/server/DashUploadUtils.ts | 94 +- 7 files changed, 1447 insertions(+), 6826 deletions(-) (limited to 'src') diff --git a/package-lock.json b/package-lock.json index 1e738fcb1..4c5a5d4d4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -26,8 +26,8 @@ "@fullcalendar/daygrid": "^6.1.10", "@fullcalendar/multimonth": "^6.1.10", "@internationalized/date": "^3.5.0", - "@mui/icons-material": "^5.14.19", - "@mui/material": "^5.14.19", + "@mui/icons-material": "^6.0.1", + "@mui/material": "^6.0.1", "@octokit/core": "^6.0.1", "@react-google-maps/api": "^2.19.2", "@react-spring/web": "^9.7.3", @@ -50,10 +50,11 @@ "@types/reveal": "^4.2.0", "@types/supercluster": "^7.1.3", "@types/textfit": "^2.4.4", - "@types/web": "^0.0.157", + "@types/web": "^0.0.159", "@types/webpack-hot-middleware": "^2.25.9", "@webscopeio/react-textarea-autocomplete": "^4.9.2", "adm-zip": "^0.5.10", + "any-base": "^1.1.0", "archiver": "^7.0.1", "async": "^3.2.5", "axios": "^1.6.2", @@ -131,7 +132,7 @@ "image-size": "^1.0.2", "image-size-stream": "^1.1.0", "is-plain-obj": "^4.1.0", - "jimp": "^0.22.10", + "jimp": "^1.0.4", "jpeg-autorotate": "^9.0.0", "jquery": "^3.7.1", "js-datepicker": "^5.18.2", @@ -697,11 +698,11 @@ } }, "node_modules/@babel/generator": { - "version": "7.25.5", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.25.5.tgz", - "integrity": "sha512-abd43wyLfbWoxC6ahM8xTkqLpGB2iWBVyuKC9/srhFunCd1SDNrV1s72bBpK4hLj8KLzHBBcOblvLQZBNw9r3w==", + "version": "7.25.6", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.25.6.tgz", + "integrity": "sha512-VPC82gr1seXOpkjAAKoLhP50vx4vGNlF4msF64dSFq1P8RfB+QAuJWGHPXXPc8QyfVWwwB/TNNU4+ayZmHNbZw==", "dependencies": { - "@babel/types": "^7.25.4", + "@babel/types": "^7.25.6", "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.25", "jsesc": "^2.5.1" @@ -953,13 +954,13 @@ } }, "node_modules/@babel/helpers": { - "version": "7.25.0", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.25.0.tgz", - "integrity": "sha512-MjgLZ42aCm0oGjJj8CtSM3DB8NOOf8h2l7DCTePJs29u+v7yO/RBX9nShlKMgFnRks/Q4tBAe7Hxnov9VkGwLw==", + "version": "7.25.6", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.25.6.tgz", + "integrity": "sha512-Xg0tn4HcfTijTwfDwYlvVCl43V6h4KyVVX2aEm4qdO/PC6L2YvzLHFdmxhoeSA3eslcE6+ZVXHgWwopXYLNq4Q==", "peer": true, "dependencies": { "@babel/template": "^7.25.0", - "@babel/types": "^7.25.0" + "@babel/types": "^7.25.6" }, "engines": { "node": ">=6.9.0" @@ -980,11 +981,11 @@ } }, "node_modules/@babel/parser": { - "version": "7.25.4", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.25.4.tgz", - "integrity": "sha512-nq+eWrOgdtu3jG5Os4TQP3x3cLA8hR8TvJNjD8vnPa20WGycimcparWnLK4jJhElTK6SDyuJo1weMKO/5LpmLA==", + "version": "7.25.6", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.25.6.tgz", + "integrity": "sha512-trGdfBdbD0l1ZPmcJ83eNxB9rbEax4ALFTF7fN386TMYbeCQbyme5cOEXQhbGXKebwGaB/J52w1mrklMcbgy6Q==", "dependencies": { - "@babel/types": "^7.25.4" + "@babel/types": "^7.25.6" }, "bin": { "parser": "bin/babel-parser.js" @@ -1137,11 +1138,11 @@ } }, "node_modules/@babel/plugin-syntax-import-assertions": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.24.7.tgz", - "integrity": "sha512-Ec3NRUMoi8gskrkBe3fNmEQfxDvY8bgfQpz6jlk/41kX9eUjvpyqWU7PBP/pLAvMaSQjbMNKJmvX57jP+M6bPg==", + "version": "7.25.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.25.6.tgz", + "integrity": "sha512-aABl0jHw9bZ2karQ/uUD6XP4u0SG22SJrOHFoL6XB1R7dTovOP4TzTlsxOYC5yQ1pdscVK2JTUnF6QL3ARoAiQ==", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.24.8" }, "engines": { "node": ">=6.9.0" @@ -1151,11 +1152,11 @@ } }, "node_modules/@babel/plugin-syntax-import-attributes": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.24.7.tgz", - "integrity": "sha512-hbX+lKKeUMGihnK8nvKqmXBInriT3GVjzXKFriV3YC6APGxMbP8RZNFwy91+hocLXq90Mta+HshoB31802bb8A==", + "version": "7.25.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.25.6.tgz", + "integrity": "sha512-sXaDXaJN9SNLymBdlWFA+bjzBhFD617ZaFiY13dGt7TVslVvVgA6fkZOP7Ki3IGElC45lwHdOTrCtKZGVAWeLQ==", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.24.8" }, "engines": { "node": ">=6.9.0" @@ -2248,9 +2249,9 @@ "integrity": "sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA==" }, "node_modules/@babel/runtime": { - "version": "7.25.4", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.25.4.tgz", - "integrity": "sha512-DSgLeL/FNcpXuzav5wfYvHCGvynXkJbn3Zvc3823AEe9nPwW9IK4UoCSS5yGymmQzN0pCPvivtgS6/8U2kkm1w==", + "version": "7.25.6", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.25.6.tgz", + "integrity": "sha512-VBj9MYyDb9tuLq7yzqjgzt6Q+IBQLrGZfdjOekyEirZPHxXWoTSGUTMrpsfi58Up73d13NfYLv8HT9vmznjzhQ==", "dependencies": { "regenerator-runtime": "^0.14.0" }, @@ -2259,9 +2260,9 @@ } }, "node_modules/@babel/runtime-corejs3": { - "version": "7.25.0", - "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.25.0.tgz", - "integrity": "sha512-BOehWE7MgQ8W8Qn0CQnMtg2tHPHPulcS/5AVpFvs2KCK1ET+0WqZqPvnpRpFN81gYoFopdIEJX9Sgjw3ZBccPg==", + "version": "7.25.6", + "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.25.6.tgz", + "integrity": "sha512-Gz0Nrobx8szge6kQQ5Z5MX9L3ObqNwCQY1PSwSNzreFL7aHGxv8Fp2j3ETV6/wWdbiV+mW6OSm8oQhg3Tcsniw==", "dependencies": { "core-js-pure": "^3.30.2", "regenerator-runtime": "^0.14.0" @@ -2284,15 +2285,15 @@ } }, "node_modules/@babel/traverse": { - "version": "7.25.4", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.25.4.tgz", - "integrity": "sha512-VJ4XsrD+nOvlXyLzmLzUs/0qjFS4sK30te5yEFlvbbUNEgKaVb2BHZUpAL+ttLPQAHNrsI3zZisbfha5Cvr8vg==", + "version": "7.25.6", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.25.6.tgz", + "integrity": "sha512-9Vrcx5ZW6UwK5tvqsj0nGpp/XzqthkT0dqIc9g1AdtygFToNtTF67XzYS//dm+SAK9cp3B9R4ZO/46p63SCjlQ==", "dependencies": { "@babel/code-frame": "^7.24.7", - "@babel/generator": "^7.25.4", - "@babel/parser": "^7.25.4", + "@babel/generator": "^7.25.6", + "@babel/parser": "^7.25.6", "@babel/template": "^7.25.0", - "@babel/types": "^7.25.4", + "@babel/types": "^7.25.6", "debug": "^4.3.1", "globals": "^11.1.0" }, @@ -2309,9 +2310,9 @@ } }, "node_modules/@babel/types": { - "version": "7.25.4", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.25.4.tgz", - "integrity": "sha512-zQ1ijeeCXVEh+aNL0RlmkPkG8HUiDcU2pzQQFjtbntgAczRASFzj4H+6+bV+dy1ntKR14I/DypeuRG1uma98iQ==", + "version": "7.25.6", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.25.6.tgz", + "integrity": "sha512-/l42B1qxpG6RdfYf343Uw1vmDjeNhneUXtzhojE7pDgfpEypmRhI6j1kr17XCVv4Cgl9HdAiQY2x0GwKm7rWCw==", "dependencies": { "@babel/helper-string-parser": "^7.24.8", "@babel/helper-validator-identifier": "^7.24.7", @@ -3114,399 +3115,306 @@ "node": ">=8" } }, - "node_modules/@jimp/bmp": { - "version": "0.22.12", - "resolved": "https://registry.npmjs.org/@jimp/bmp/-/bmp-0.22.12.tgz", - "integrity": "sha512-aeI64HD0npropd+AR76MCcvvRaa+Qck6loCOS03CkkxGHN5/r336qTM5HPUdHKMDOGzqknuVPA8+kK1t03z12g==", + "node_modules/@jimp/core": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@jimp/core/-/core-1.0.4.tgz", + "integrity": "sha512-K+wDZbpdqwO0+GtMVdTEDttFAWA1R70uebcO+TTVliD88Cae1UKFxJOMTbAGFI+PJqvpZWpZn+5S6N5jLbHVXA==", "dependencies": { - "@jimp/utils": "^0.22.12", - "bmp-js": "^0.1.0" + "@jimp/file-ops": "1.0.4", + "@jimp/types": "1.0.4", + "@jimp/utils": "1.0.4", + "await-to-js": "^3.0.0", + "exif-parser": "^0.1.12", + "file-type": "^16.0.0", + "mime": "3" + } + }, + "node_modules/@jimp/core/node_modules/mime": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-3.0.0.tgz", + "integrity": "sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A==", + "bin": { + "mime": "cli.js" }, - "peerDependencies": { - "@jimp/custom": ">=0.3.5" + "engines": { + "node": ">=10.0.0" } }, - "node_modules/@jimp/core": { - "version": "0.22.12", - "resolved": "https://registry.npmjs.org/@jimp/core/-/core-0.22.12.tgz", - "integrity": "sha512-l0RR0dOPyzMKfjUW1uebzueFEDtCOj9fN6pyTYWWOM/VS4BciXQ1VVrJs8pO3kycGYZxncRKhCoygbNr8eEZQA==", + "node_modules/@jimp/diff": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@jimp/diff/-/diff-1.0.4.tgz", + "integrity": "sha512-AEsoPrZ4SiY/xFCVFwcTu3qN63gVyktL3NXHnQZoYOLcW9pvFVGsNxBa1iwk0OkK2FAR7VyuOsJtn0qmq6hUNA==", "dependencies": { - "@jimp/utils": "^0.22.12", - "any-base": "^1.1.0", - "buffer": "^5.2.0", - "exif-parser": "^0.1.12", - "file-type": "^16.5.4", - "isomorphic-fetch": "^3.0.0", - "pixelmatch": "^4.0.2", - "tinycolor2": "^1.6.0" + "@jimp/plugin-resize": "1.0.4", + "@jimp/types": "1.0.4", + "@jimp/utils": "1.0.4", + "pixelmatch": "^5.3.0" } }, - "node_modules/@jimp/custom": { - "version": "0.22.12", - "resolved": "https://registry.npmjs.org/@jimp/custom/-/custom-0.22.12.tgz", - "integrity": "sha512-xcmww1O/JFP2MrlGUMd3Q78S3Qu6W3mYTXYuIqFq33EorgYHV/HqymHfXy9GjiCJ7OI+7lWx6nYFOzU7M4rd1Q==", + "node_modules/@jimp/file-ops": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@jimp/file-ops/-/file-ops-1.0.4.tgz", + "integrity": "sha512-Epbp4brdZY6cv4jFmY8TUF6RtpIWnVFAGPr6tOTF/bI8RsXgucNbpjFQZU5M+HOAyxLED6p7o1STHFn6nGMVnA==" + }, + "node_modules/@jimp/js-bmp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@jimp/js-bmp/-/js-bmp-1.0.4.tgz", + "integrity": "sha512-p2l0xBfo+fQ/NBG93DKBC06e5xFAHRP0B4KdUINSoAXULkrBfutKd9KPBRQMAjVA8e3anLEiv1P91wYSScEvLA==", "dependencies": { - "@jimp/core": "^0.22.12" + "@jimp/core": "1.0.4", + "@jimp/types": "1.0.4", + "@jimp/utils": "1.0.4", + "bmp-ts": "^1.0.9" } }, - "node_modules/@jimp/gif": { - "version": "0.22.12", - "resolved": "https://registry.npmjs.org/@jimp/gif/-/gif-0.22.12.tgz", - "integrity": "sha512-y6BFTJgch9mbor2H234VSjd9iwAhaNf/t3US5qpYIs0TSbAvM02Fbc28IaDETj9+4YB4676sz4RcN/zwhfu1pg==", + "node_modules/@jimp/js-gif": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@jimp/js-gif/-/js-gif-1.0.4.tgz", + "integrity": "sha512-P/BH5JsR+WwkvpD+OPg+M4As+Cnzigin7QcTjda8A5nQyuTTL86qdrl5a5DbxBTXRnajCwIhb3oAQmbuD9ec/A==", "dependencies": { - "@jimp/utils": "^0.22.12", + "@jimp/core": "1.0.4", + "@jimp/types": "1.0.4", "gifwrap": "^0.10.1", - "omggif": "^1.0.9" - }, - "peerDependencies": { - "@jimp/custom": ">=0.3.5" + "omggif": "^1.0.10" } }, - "node_modules/@jimp/jpeg": { - "version": "0.22.12", - "resolved": "https://registry.npmjs.org/@jimp/jpeg/-/jpeg-0.22.12.tgz", - "integrity": "sha512-Rq26XC/uQWaQKyb/5lksCTCxXhtY01NJeBN+dQv5yNYedN0i7iYu+fXEoRsfaJ8xZzjoANH8sns7rVP4GE7d/Q==", + "node_modules/@jimp/js-jpeg": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@jimp/js-jpeg/-/js-jpeg-1.0.4.tgz", + "integrity": "sha512-BgsYW+cujySH13+8Ld5WLIvyv4VatGb1BlqP7zjS84vriX2HcgGNoyYHjnaLn1Qd5yxfU8Atewqxo0DipLlHmQ==", "dependencies": { - "@jimp/utils": "^0.22.12", + "@jimp/core": "1.0.4", + "@jimp/types": "1.0.4", "jpeg-js": "^0.4.4" - }, - "peerDependencies": { - "@jimp/custom": ">=0.3.5" + } + }, + "node_modules/@jimp/js-png": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@jimp/js-png/-/js-png-1.0.4.tgz", + "integrity": "sha512-B8AeNGbPFd/wZzIKy9qZXvJ44yDDSQSDsU0OrCiNZCP70S5raWa93LehOYqEdr+brwO7+FiwI7nbCAUB/zgcPQ==", + "dependencies": { + "@jimp/core": "1.0.4", + "@jimp/types": "1.0.4", + "pngjs": "^7.0.0" + } + }, + "node_modules/@jimp/js-tiff": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@jimp/js-tiff/-/js-tiff-1.0.4.tgz", + "integrity": "sha512-K/A/Ej6C0bgUP7nD0vH3hc2ftfib7oAdRPN1HLpyyJJc4eatfLcoY1BlDgLiOwEfv8LEzhRB8+0uMwM6ZrvjcQ==", + "dependencies": { + "@jimp/core": "1.0.4", + "@jimp/types": "1.0.4", + "utif2": "^4.1.0" } }, "node_modules/@jimp/plugin-blit": { - "version": "0.22.12", - "resolved": "https://registry.npmjs.org/@jimp/plugin-blit/-/plugin-blit-0.22.12.tgz", - "integrity": "sha512-xslz2ZoFZOPLY8EZ4dC29m168BtDx95D6K80TzgUi8gqT7LY6CsajWO0FAxDwHz6h0eomHMfyGX0stspBrTKnQ==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@jimp/plugin-blit/-/plugin-blit-1.0.4.tgz", + "integrity": "sha512-u3HIa6VmKShNJ3/RPIJizecEFgRPwLVo0vyjtE/hx7L2TfbNxaWShUBUqEVL192Luk7D9SIBl998ujn37lO4DQ==", "dependencies": { - "@jimp/utils": "^0.22.12" - }, - "peerDependencies": { - "@jimp/custom": ">=0.3.5" + "@jimp/types": "1.0.4", + "@jimp/utils": "1.0.4", + "zod": "^3.22.4" } }, "node_modules/@jimp/plugin-blur": { - "version": "0.22.12", - "resolved": "https://registry.npmjs.org/@jimp/plugin-blur/-/plugin-blur-0.22.12.tgz", - "integrity": "sha512-S0vJADTuh1Q9F+cXAwFPlrKWzDj2F9t/9JAbUvaaDuivpyWuImEKXVz5PUZw2NbpuSHjwssbTpOZ8F13iJX4uw==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@jimp/plugin-blur/-/plugin-blur-1.0.4.tgz", + "integrity": "sha512-hgNPUvlgyoRGIYFZ5u2Ptd2f3b1m2+KeDJ1RXnWshz01oc/vr0UyRZRzmhKn0S8Ic+3UYa3mAsIBp7GLsXyK5g==", "dependencies": { - "@jimp/utils": "^0.22.12" - }, - "peerDependencies": { - "@jimp/custom": ">=0.3.5" + "@jimp/types": "1.0.4" } }, "node_modules/@jimp/plugin-circle": { - "version": "0.22.12", - "resolved": "https://registry.npmjs.org/@jimp/plugin-circle/-/plugin-circle-0.22.12.tgz", - "integrity": "sha512-SWVXx1yiuj5jZtMijqUfvVOJBwOifFn0918ou4ftoHgegc5aHWW5dZbYPjvC9fLpvz7oSlptNl2Sxr1zwofjTg==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@jimp/plugin-circle/-/plugin-circle-1.0.4.tgz", + "integrity": "sha512-C4lBEnCYBahq4qefYyAH/mkIsWzytsERcwR17V6x4+UxmD0vW1aEMAKrPvEEsTM7O84zUgCrYuh7+Uuvf+00lw==", "dependencies": { - "@jimp/utils": "^0.22.12" - }, - "peerDependencies": { - "@jimp/custom": ">=0.3.5" + "@jimp/types": "1.0.4", + "zod": "^3.22.4" } }, "node_modules/@jimp/plugin-color": { - "version": "0.22.12", - "resolved": "https://registry.npmjs.org/@jimp/plugin-color/-/plugin-color-0.22.12.tgz", - "integrity": "sha512-xImhTE5BpS8xa+mAN6j4sMRWaUgUDLoaGHhJhpC+r7SKKErYDR0WQV4yCE4gP+N0gozD0F3Ka1LUSaMXrn7ZIA==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@jimp/plugin-color/-/plugin-color-1.0.4.tgz", + "integrity": "sha512-og/KO6pRncUt2ovQK+J/UseLerfjmv4IBS4Byb5KrQ1O7P5l+wvb537EMuixHOzW9G7CI7OyuzjOSEvW1LOJOQ==", "dependencies": { - "@jimp/utils": "^0.22.12", - "tinycolor2": "^1.6.0" - }, - "peerDependencies": { - "@jimp/custom": ">=0.3.5" + "@jimp/core": "1.0.4", + "@jimp/types": "1.0.4", + "@jimp/utils": "1.0.4", + "tinycolor2": "^1.6.0", + "zod": "^3.22.4" } }, "node_modules/@jimp/plugin-contain": { - "version": "0.22.12", - "resolved": "https://registry.npmjs.org/@jimp/plugin-contain/-/plugin-contain-0.22.12.tgz", - "integrity": "sha512-Eo3DmfixJw3N79lWk8q/0SDYbqmKt1xSTJ69yy8XLYQj9svoBbyRpSnHR+n9hOw5pKXytHwUW6nU4u1wegHNoQ==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@jimp/plugin-contain/-/plugin-contain-1.0.4.tgz", + "integrity": "sha512-5cjPOIW6W/tiVG1CU64rSsR5MJ/x2tGk6Z1erJqI+7oQDtrP9iSI1HGdhrenIegdtgsxQ8xcr3DoaEvmOkwwdA==", "dependencies": { - "@jimp/utils": "^0.22.12" - }, - "peerDependencies": { - "@jimp/custom": ">=0.3.5", - "@jimp/plugin-blit": ">=0.3.5", - "@jimp/plugin-resize": ">=0.3.5", - "@jimp/plugin-scale": ">=0.3.5" + "@jimp/core": "1.0.4", + "@jimp/plugin-blit": "1.0.4", + "@jimp/plugin-resize": "1.0.4", + "@jimp/types": "1.0.4", + "@jimp/utils": "1.0.4", + "zod": "^3.22.4" } }, "node_modules/@jimp/plugin-cover": { - "version": "0.22.12", - "resolved": "https://registry.npmjs.org/@jimp/plugin-cover/-/plugin-cover-0.22.12.tgz", - "integrity": "sha512-z0w/1xH/v/knZkpTNx+E8a7fnasQ2wHG5ze6y5oL2dhH1UufNua8gLQXlv8/W56+4nJ1brhSd233HBJCo01BXA==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@jimp/plugin-cover/-/plugin-cover-1.0.4.tgz", + "integrity": "sha512-9gYQsSxJ1wvzurS9d0BBVFLb6Y6soc02NL5YA/kdaydfmpUn2M/DbIuVR+G5oaWUvL0kriTyCVLw7Pk26rqxpA==", "dependencies": { - "@jimp/utils": "^0.22.12" - }, - "peerDependencies": { - "@jimp/custom": ">=0.3.5", - "@jimp/plugin-crop": ">=0.3.5", - "@jimp/plugin-resize": ">=0.3.5", - "@jimp/plugin-scale": ">=0.3.5" + "@jimp/core": "1.0.4", + "@jimp/plugin-crop": "1.0.4", + "@jimp/plugin-resize": "1.0.4", + "@jimp/types": "1.0.4", + "zod": "^3.22.4" } }, "node_modules/@jimp/plugin-crop": { - "version": "0.22.12", - "resolved": "https://registry.npmjs.org/@jimp/plugin-crop/-/plugin-crop-0.22.12.tgz", - "integrity": "sha512-FNuUN0OVzRCozx8XSgP9MyLGMxNHHJMFt+LJuFjn1mu3k0VQxrzqbN06yIl46TVejhyAhcq5gLzqmSCHvlcBVw==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@jimp/plugin-crop/-/plugin-crop-1.0.4.tgz", + "integrity": "sha512-FAxSqeeFNvmcEiQ6aHmxGZCtfj+atQAg5Xs8AJMOpVYe36mVLXlaQgl+TDGZl0CroURtVfigtiEVLizAtmF4pQ==", "dependencies": { - "@jimp/utils": "^0.22.12" - }, - "peerDependencies": { - "@jimp/custom": ">=0.3.5" + "@jimp/core": "1.0.4", + "@jimp/types": "1.0.4", + "@jimp/utils": "1.0.4", + "zod": "^3.22.4" } }, "node_modules/@jimp/plugin-displace": { - "version": "0.22.12", - "resolved": "https://registry.npmjs.org/@jimp/plugin-displace/-/plugin-displace-0.22.12.tgz", - "integrity": "sha512-qpRM8JRicxfK6aPPqKZA6+GzBwUIitiHaZw0QrJ64Ygd3+AsTc7BXr+37k2x7QcyCvmKXY4haUrSIsBug4S3CA==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@jimp/plugin-displace/-/plugin-displace-1.0.4.tgz", + "integrity": "sha512-MXy2E+iwpQV4Iug3+9rYhUCFjJjw/aXn9ShwZSIUKlNuF2NWlZeI2QwbYR0sEFHHbovOMIVuA2FLzgmGM66XfQ==", "dependencies": { - "@jimp/utils": "^0.22.12" - }, - "peerDependencies": { - "@jimp/custom": ">=0.3.5" + "@jimp/types": "1.0.4", + "@jimp/utils": "1.0.4", + "zod": "^3.22.4" } }, "node_modules/@jimp/plugin-dither": { - "version": "0.22.12", - "resolved": "https://registry.npmjs.org/@jimp/plugin-dither/-/plugin-dither-0.22.12.tgz", - "integrity": "sha512-jYgGdSdSKl1UUEanX8A85v4+QUm+PE8vHFwlamaKk89s+PXQe7eVE3eNeSZX4inCq63EHL7cX580dMqkoC3ZLw==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@jimp/plugin-dither/-/plugin-dither-1.0.4.tgz", + "integrity": "sha512-MdSmPE1l3sxtGoSVV7WLx5cMLk1KT3x+WXjivL19OBBPTLVbgPYdcOe7ikLM0ZoLbsw6PpvbGNfPY1LxDU7JzA==", "dependencies": { - "@jimp/utils": "^0.22.12" - }, - "peerDependencies": { - "@jimp/custom": ">=0.3.5" + "@jimp/types": "1.0.4" } }, "node_modules/@jimp/plugin-fisheye": { - "version": "0.22.12", - "resolved": "https://registry.npmjs.org/@jimp/plugin-fisheye/-/plugin-fisheye-0.22.12.tgz", - "integrity": "sha512-LGuUTsFg+fOp6KBKrmLkX4LfyCy8IIsROwoUvsUPKzutSqMJnsm3JGDW2eOmWIS/jJpPaeaishjlxvczjgII+Q==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@jimp/plugin-fisheye/-/plugin-fisheye-1.0.4.tgz", + "integrity": "sha512-iSeiU1WzhZBi1qfLWUiMNG7Ft1AP6ZFvfR8fpr9X+ipJ+uvofBQ2SzHUxmhxcI/PGcZTdXUkUxT20LiM9h3ksQ==", "dependencies": { - "@jimp/utils": "^0.22.12" - }, - "peerDependencies": { - "@jimp/custom": ">=0.3.5" + "@jimp/types": "1.0.4", + "@jimp/utils": "1.0.4", + "zod": "^3.22.4" } }, "node_modules/@jimp/plugin-flip": { - "version": "0.22.12", - "resolved": "https://registry.npmjs.org/@jimp/plugin-flip/-/plugin-flip-0.22.12.tgz", - "integrity": "sha512-m251Rop7GN8W0Yo/rF9LWk6kNclngyjIJs/VXHToGQ6EGveOSTSQaX2Isi9f9lCDLxt+inBIb7nlaLLxnvHX8Q==", - "dependencies": { - "@jimp/utils": "^0.22.12" - }, - "peerDependencies": { - "@jimp/custom": ">=0.3.5", - "@jimp/plugin-rotate": ">=0.3.5" - } - }, - "node_modules/@jimp/plugin-gaussian": { - "version": "0.22.12", - "resolved": "https://registry.npmjs.org/@jimp/plugin-gaussian/-/plugin-gaussian-0.22.12.tgz", - "integrity": "sha512-sBfbzoOmJ6FczfG2PquiK84NtVGeScw97JsCC3rpQv1PHVWyW+uqWFF53+n3c8Y0P2HWlUjflEla2h/vWShvhg==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@jimp/plugin-flip/-/plugin-flip-1.0.4.tgz", + "integrity": "sha512-0YoLAOtvAonHgOST7jyt36Dv0262FQZGbAvevI8TYbcU6BPPSuONBQRw04iSmakk0XdeJ5TfP+I/Z3qZSn48FQ==", "dependencies": { - "@jimp/utils": "^0.22.12" - }, - "peerDependencies": { - "@jimp/custom": ">=0.3.5" + "@jimp/types": "1.0.4", + "zod": "^3.22.4" } }, - "node_modules/@jimp/plugin-invert": { - "version": "0.22.12", - "resolved": "https://registry.npmjs.org/@jimp/plugin-invert/-/plugin-invert-0.22.12.tgz", - "integrity": "sha512-N+6rwxdB+7OCR6PYijaA/iizXXodpxOGvT/smd/lxeXsZ/empHmFFFJ/FaXcYh19Tm04dGDaXcNF/dN5nm6+xQ==", + "node_modules/@jimp/plugin-hash": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@jimp/plugin-hash/-/plugin-hash-1.0.4.tgz", + "integrity": "sha512-FgL3jX5dIDtVJ5WUVzAcSy740Jk2p/6rB0Vg40TkETfEYnhHfltRGkpvv5a1kxD0icte23eICNU1lL5hw27lJw==", "dependencies": { - "@jimp/utils": "^0.22.12" - }, - "peerDependencies": { - "@jimp/custom": ">=0.3.5" + "@jimp/core": "1.0.4", + "@jimp/js-bmp": "1.0.4", + "@jimp/js-jpeg": "1.0.4", + "@jimp/js-png": "1.0.4", + "@jimp/js-tiff": "1.0.4", + "@jimp/plugin-color": "1.0.4", + "@jimp/plugin-resize": "1.0.4", + "@jimp/types": "1.0.4", + "@jimp/utils": "1.0.4", + "@types/any-base": "^1.1.3" } }, "node_modules/@jimp/plugin-mask": { - "version": "0.22.12", - "resolved": "https://registry.npmjs.org/@jimp/plugin-mask/-/plugin-mask-0.22.12.tgz", - "integrity": "sha512-4AWZg+DomtpUA099jRV8IEZUfn1wLv6+nem4NRJC7L/82vxzLCgXKTxvNvBcNmJjT9yS1LAAmiJGdWKXG63/NA==", - "dependencies": { - "@jimp/utils": "^0.22.12" - }, - "peerDependencies": { - "@jimp/custom": ">=0.3.5" - } - }, - "node_modules/@jimp/plugin-normalize": { - "version": "0.22.12", - "resolved": "https://registry.npmjs.org/@jimp/plugin-normalize/-/plugin-normalize-0.22.12.tgz", - "integrity": "sha512-0So0rexQivnWgnhacX4cfkM2223YdExnJTTy6d06WbkfZk5alHUx8MM3yEzwoCN0ErO7oyqEWRnEkGC+As1FtA==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@jimp/plugin-mask/-/plugin-mask-1.0.4.tgz", + "integrity": "sha512-E9Z3aitK1coWpCXy0qycBPnfcxTbg3azygdMOZdj9Nbjnf+rh0Jz+JtG4HKJjCw9SLOgvCNjKY71JkubdyoRhg==", "dependencies": { - "@jimp/utils": "^0.22.12" - }, - "peerDependencies": { - "@jimp/custom": ">=0.3.5" + "@jimp/types": "1.0.4", + "zod": "^3.22.4" } }, "node_modules/@jimp/plugin-print": { - "version": "0.22.12", - "resolved": "https://registry.npmjs.org/@jimp/plugin-print/-/plugin-print-0.22.12.tgz", - "integrity": "sha512-c7TnhHlxm87DJeSnwr/XOLjJU/whoiKYY7r21SbuJ5nuH+7a78EW1teOaj5gEr2wYEd7QtkFqGlmyGXY/YclyQ==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@jimp/plugin-print/-/plugin-print-1.0.4.tgz", + "integrity": "sha512-eTTTfZe7GgIZifLrQgt7EsWK/JKLm2Lm1Upro3wVKHJ8gfBtq5Fu+GxCeER+1bA7a5b9IGZSO3diRNqOpXs6bw==", "dependencies": { - "@jimp/utils": "^0.22.12", - "load-bmfont": "^1.4.1" - }, - "peerDependencies": { - "@jimp/custom": ">=0.3.5", - "@jimp/plugin-blit": ">=0.3.5" + "@jimp/core": "1.0.4", + "@jimp/js-jpeg": "1.0.4", + "@jimp/js-png": "1.0.4", + "@jimp/plugin-blit": "1.0.4", + "@jimp/types": "1.0.4", + "parse-bmfont-ascii": "^1.0.6", + "parse-bmfont-binary": "^1.0.6", + "parse-bmfont-xml": "^1.1.6", + "zod": "^3.22.4" } }, "node_modules/@jimp/plugin-resize": { - "version": "0.22.12", - "resolved": "https://registry.npmjs.org/@jimp/plugin-resize/-/plugin-resize-0.22.12.tgz", - "integrity": "sha512-3NyTPlPbTnGKDIbaBgQ3HbE6wXbAlFfxHVERmrbqAi8R3r6fQPxpCauA8UVDnieg5eo04D0T8nnnNIX//i/sXg==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@jimp/plugin-resize/-/plugin-resize-1.0.4.tgz", + "integrity": "sha512-iOOMCe3rSBKB6AhDBKJFZIjnqL1j6IB/SxdQsW8H5oCevuz4OPROxPBIdNDXxeyGBwqqppXbcnsL+sX7NUI7KQ==", "dependencies": { - "@jimp/utils": "^0.22.12" - }, - "peerDependencies": { - "@jimp/custom": ">=0.3.5" + "@jimp/core": "1.0.4", + "@jimp/types": "1.0.4", + "zod": "^3.22.4" } }, "node_modules/@jimp/plugin-rotate": { - "version": "0.22.12", - "resolved": "https://registry.npmjs.org/@jimp/plugin-rotate/-/plugin-rotate-0.22.12.tgz", - "integrity": "sha512-9YNEt7BPAFfTls2FGfKBVgwwLUuKqy+E8bDGGEsOqHtbuhbshVGxN2WMZaD4gh5IDWvR+emmmPPWGgaYNYt1gA==", - "dependencies": { - "@jimp/utils": "^0.22.12" - }, - "peerDependencies": { - "@jimp/custom": ">=0.3.5", - "@jimp/plugin-blit": ">=0.3.5", - "@jimp/plugin-crop": ">=0.3.5", - "@jimp/plugin-resize": ">=0.3.5" - } - }, - "node_modules/@jimp/plugin-scale": { - "version": "0.22.12", - "resolved": "https://registry.npmjs.org/@jimp/plugin-scale/-/plugin-scale-0.22.12.tgz", - "integrity": "sha512-dghs92qM6MhHj0HrV2qAwKPMklQtjNpoYgAB94ysYpsXslhRTiPisueSIELRwZGEr0J0VUxpUY7HgJwlSIgGZw==", - "dependencies": { - "@jimp/utils": "^0.22.12" - }, - "peerDependencies": { - "@jimp/custom": ">=0.3.5", - "@jimp/plugin-resize": ">=0.3.5" - } - }, - "node_modules/@jimp/plugin-shadow": { - "version": "0.22.12", - "resolved": "https://registry.npmjs.org/@jimp/plugin-shadow/-/plugin-shadow-0.22.12.tgz", - "integrity": "sha512-FX8mTJuCt7/3zXVoeD/qHlm4YH2bVqBuWQHXSuBK054e7wFRnRnbSLPUqAwSeYP3lWqpuQzJtgiiBxV3+WWwTg==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@jimp/plugin-rotate/-/plugin-rotate-1.0.4.tgz", + "integrity": "sha512-QjY2DYFZj+m+I6F8aWDGAT/YHfpkP8AF9/qW4zi3Lq3WpBAeOqf9cvcHBjFv3hN72JQlneC5dRWE1h/QfygRxQ==", "dependencies": { - "@jimp/utils": "^0.22.12" - }, - "peerDependencies": { - "@jimp/custom": ">=0.3.5", - "@jimp/plugin-blur": ">=0.3.5", - "@jimp/plugin-resize": ">=0.3.5" + "@jimp/core": "1.0.4", + "@jimp/plugin-crop": "1.0.4", + "@jimp/plugin-resize": "1.0.4", + "@jimp/types": "1.0.4", + "@jimp/utils": "1.0.4", + "zod": "^3.22.4" } }, "node_modules/@jimp/plugin-threshold": { - "version": "0.22.12", - "resolved": "https://registry.npmjs.org/@jimp/plugin-threshold/-/plugin-threshold-0.22.12.tgz", - "integrity": "sha512-4x5GrQr1a/9L0paBC/MZZJjjgjxLYrqSmWd+e+QfAEPvmRxdRoQ5uKEuNgXnm9/weHQBTnQBQsOY2iFja+XGAw==", - "dependencies": { - "@jimp/utils": "^0.22.12" - }, - "peerDependencies": { - "@jimp/custom": ">=0.3.5", - "@jimp/plugin-color": ">=0.8.0", - "@jimp/plugin-resize": ">=0.8.0" - } - }, - "node_modules/@jimp/plugins": { - "version": "0.22.12", - "resolved": "https://registry.npmjs.org/@jimp/plugins/-/plugins-0.22.12.tgz", - "integrity": "sha512-yBJ8vQrDkBbTgQZLty9k4+KtUQdRjsIDJSPjuI21YdVeqZxYywifHl4/XWILoTZsjTUASQcGoH0TuC0N7xm3ww==", - "dependencies": { - "@jimp/plugin-blit": "^0.22.12", - "@jimp/plugin-blur": "^0.22.12", - "@jimp/plugin-circle": "^0.22.12", - "@jimp/plugin-color": "^0.22.12", - "@jimp/plugin-contain": "^0.22.12", - "@jimp/plugin-cover": "^0.22.12", - "@jimp/plugin-crop": "^0.22.12", - "@jimp/plugin-displace": "^0.22.12", - "@jimp/plugin-dither": "^0.22.12", - "@jimp/plugin-fisheye": "^0.22.12", - "@jimp/plugin-flip": "^0.22.12", - "@jimp/plugin-gaussian": "^0.22.12", - "@jimp/plugin-invert": "^0.22.12", - "@jimp/plugin-mask": "^0.22.12", - "@jimp/plugin-normalize": "^0.22.12", - "@jimp/plugin-print": "^0.22.12", - "@jimp/plugin-resize": "^0.22.12", - "@jimp/plugin-rotate": "^0.22.12", - "@jimp/plugin-scale": "^0.22.12", - "@jimp/plugin-shadow": "^0.22.12", - "@jimp/plugin-threshold": "^0.22.12", - "timm": "^1.6.1" - }, - "peerDependencies": { - "@jimp/custom": ">=0.3.5" - } - }, - "node_modules/@jimp/png": { - "version": "0.22.12", - "resolved": "https://registry.npmjs.org/@jimp/png/-/png-0.22.12.tgz", - "integrity": "sha512-Mrp6dr3UTn+aLK8ty/dSKELz+Otdz1v4aAXzV5q53UDD2rbB5joKVJ/ChY310B+eRzNxIovbUF1KVrUsYdE8Hg==", - "dependencies": { - "@jimp/utils": "^0.22.12", - "pngjs": "^6.0.0" - }, - "peerDependencies": { - "@jimp/custom": ">=0.3.5" - } - }, - "node_modules/@jimp/tiff": { - "version": "0.22.12", - "resolved": "https://registry.npmjs.org/@jimp/tiff/-/tiff-0.22.12.tgz", - "integrity": "sha512-E1LtMh4RyJsoCAfAkBRVSYyZDTtLq9p9LUiiYP0vPtXyxX4BiYBUYihTLSBlCQg5nF2e4OpQg7SPrLdJ66u7jg==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@jimp/plugin-threshold/-/plugin-threshold-1.0.4.tgz", + "integrity": "sha512-wF//3Kg5nOcqBIx7p+fI/8x5T4FDzAXjTL+B8acNJIYNRJR0eceErgFvSl+lAA8xKMyVHbXtrzbUK7+p1Cdptw==", "dependencies": { - "utif2": "^4.0.1" - }, - "peerDependencies": { - "@jimp/custom": ">=0.3.5" + "@jimp/core": "1.0.4", + "@jimp/plugin-color": "1.0.4", + "@jimp/plugin-hash": "1.0.4", + "@jimp/types": "1.0.4", + "@jimp/utils": "1.0.4", + "zod": "^3.22.4" } }, "node_modules/@jimp/types": { - "version": "0.22.12", - "resolved": "https://registry.npmjs.org/@jimp/types/-/types-0.22.12.tgz", - "integrity": "sha512-wwKYzRdElE1MBXFREvCto5s699izFHNVvALUv79GXNbsOVqlwlOxlWJ8DuyOGIXoLP4JW/m30YyuTtfUJgMRMA==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@jimp/types/-/types-1.0.4.tgz", + "integrity": "sha512-sKM5R5kEm2VyfU68vYfEDoDtlmHMZ+pJTvYxa62SA5WEFKeO2ATBsybk5a8bJV1LDL1FXwKgXR6wsO4kx4RfQw==", "dependencies": { - "@jimp/bmp": "^0.22.12", - "@jimp/gif": "^0.22.12", - "@jimp/jpeg": "^0.22.12", - "@jimp/png": "^0.22.12", - "@jimp/tiff": "^0.22.12", - "timm": "^1.6.1" - }, - "peerDependencies": { - "@jimp/custom": ">=0.3.5" + "zod": "^3.22.4" } }, "node_modules/@jimp/utils": { - "version": "0.22.12", - "resolved": "https://registry.npmjs.org/@jimp/utils/-/utils-0.22.12.tgz", - "integrity": "sha512-yJ5cWUknGnilBq97ZXOyOS0HhsHOyAyjHwYfHxGbSyMTohgQI6sVyE8KPgDwH8HHW/nMKXk8TrSwAE71zt716Q==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@jimp/utils/-/utils-1.0.4.tgz", + "integrity": "sha512-aqsJKDleM54v0s9rW+swc0SJHb/O4sy2I56ng+9UC7uhF+P6JRjvMVyqEprQ1fKBaCN/Ff0Bu0YUzEXwUtpH/g==", "dependencies": { - "regenerator-runtime": "^0.13.3" + "@jimp/types": "1.0.4", + "tinycolor2": "^1.6.0" } }, - "node_modules/@jimp/utils/node_modules/regenerator-runtime": { - "version": "0.13.11", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", - "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==" - }, "node_modules/@jridgewell/gen-mapping": { "version": "0.3.5", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", @@ -3799,6 +3707,45 @@ "langium": "3.0.0" } }, + "node_modules/@module-federation/runtime": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/@module-federation/runtime/-/runtime-0.5.1.tgz", + "integrity": "sha512-xgiMUWwGLWDrvZc9JibuEbXIbhXg6z2oUkemogSvQ4LKvrl/n0kbqP1Blk669mXzyWbqtSp6PpvNdwaE1aN5xQ==", + "optional": true, + "peer": true, + "dependencies": { + "@module-federation/sdk": "0.5.1" + } + }, + "node_modules/@module-federation/runtime-tools": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/@module-federation/runtime-tools/-/runtime-tools-0.5.1.tgz", + "integrity": "sha512-nfBedkoZ3/SWyO0hnmaxuz0R0iGPSikHZOAZ0N/dVSQaIzlffUo35B5nlC2wgWIc0JdMZfkwkjZRrnuuDIJbzg==", + "optional": true, + "peer": true, + "dependencies": { + "@module-federation/runtime": "0.5.1", + "@module-federation/webpack-bundler-runtime": "0.5.1" + } + }, + "node_modules/@module-federation/sdk": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/@module-federation/sdk/-/sdk-0.5.1.tgz", + "integrity": "sha512-exvchtjNURJJkpqjQ3/opdbfeT2wPKvrbnGnyRkrwW5o3FH1LaST1tkiNviT6OXTexGaVc2DahbdniQHVtQ7pA==", + "optional": true, + "peer": true + }, + "node_modules/@module-federation/webpack-bundler-runtime": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/@module-federation/webpack-bundler-runtime/-/webpack-bundler-runtime-0.5.1.tgz", + "integrity": "sha512-mMhRFH0k2VjwHt3Jol9JkUsmI/4XlrAoBG3E0o7HoyoPYv1UFOWyqAflfANcUPgbYpvqmyLzDcO+3IT36LXnrA==", + "optional": true, + "peer": true, + "dependencies": { + "@module-federation/runtime": "0.5.1", + "@module-federation/sdk": "0.5.1" + } + }, "node_modules/@mongodb-js/saslprep": { "version": "1.1.8", "resolved": "https://registry.npmjs.org/@mongodb-js/saslprep/-/saslprep-1.1.8.tgz", @@ -3808,32 +3755,32 @@ } }, "node_modules/@mui/core-downloads-tracker": { - "version": "5.16.7", - "resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-5.16.7.tgz", - "integrity": "sha512-RtsCt4Geed2/v74sbihWzzRs+HsIQCfclHeORh5Ynu2fS4icIKozcSubwuG7vtzq2uW3fOR1zITSP84TNt2GoQ==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-6.0.1.tgz", + "integrity": "sha512-TmKkCTwgtwvlFTF1tZzG4lYbi7v6NGweEJwFBZoIWZrkF1OLa0xu4umifmIyd+bVIScsEj//E2AD6bOJbPMOOQ==", "funding": { "type": "opencollective", "url": "https://opencollective.com/mui-org" } }, "node_modules/@mui/icons-material": { - "version": "5.16.7", - "resolved": "https://registry.npmjs.org/@mui/icons-material/-/icons-material-5.16.7.tgz", - "integrity": "sha512-UrGwDJCXEszbDI7yV047BYU5A28eGJ79keTCP4cc74WyncuVrnurlmIRxaHL8YK+LI1Kzq+/JM52IAkNnv4u+Q==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/@mui/icons-material/-/icons-material-6.0.1.tgz", + "integrity": "sha512-CsgaF65jA3H1YzpDg6H2nFH/UHueVlmpEtPim7xF9VbjYnmnblG3aX0GflBahH96Pg0schrFWyRySlgbVAh5Kw==", "dependencies": { - "@babel/runtime": "^7.23.9" + "@babel/runtime": "^7.25.0" }, "engines": { - "node": ">=12.0.0" + "node": ">=14.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/mui-org" }, "peerDependencies": { - "@mui/material": "^5.0.0", - "@types/react": "^17.0.0 || ^18.0.0", - "react": "^17.0.0 || ^18.0.0" + "@mui/material": "^6.0.1", + "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0", + "react": "^17.0.0 || ^18.0.0 || ^19.0.0" }, "peerDependenciesMeta": { "@types/react": { @@ -3842,25 +3789,25 @@ } }, "node_modules/@mui/material": { - "version": "5.16.7", - "resolved": "https://registry.npmjs.org/@mui/material/-/material-5.16.7.tgz", - "integrity": "sha512-cwwVQxBhK60OIOqZOVLFt55t01zmarKJiJUWbk0+8s/Ix5IaUzAShqlJchxsIQ4mSrWqgcKCCXKtIlG5H+/Jmg==", - "dependencies": { - "@babel/runtime": "^7.23.9", - "@mui/core-downloads-tracker": "^5.16.7", - "@mui/system": "^5.16.7", - "@mui/types": "^7.2.15", - "@mui/utils": "^5.16.6", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/@mui/material/-/material-6.0.1.tgz", + "integrity": "sha512-gOJS0RKYs9lRACaTluXPNopxFpIBhWVmhf09lHpqpPlR6bujXhuiTE2Q8puensdz3Qm2JGzl1VjccYHieV1g8A==", + "dependencies": { + "@babel/runtime": "^7.25.0", + "@mui/core-downloads-tracker": "^6.0.1", + "@mui/system": "^6.0.1", + "@mui/types": "^7.2.16", + "@mui/utils": "^6.0.1", "@popperjs/core": "^2.11.8", - "@types/react-transition-group": "^4.4.10", - "clsx": "^2.1.0", + "@types/react-transition-group": "^4.4.11", + "clsx": "^2.1.1", "csstype": "^3.1.3", "prop-types": "^15.8.1", "react-is": "^18.3.1", "react-transition-group": "^4.4.5" }, "engines": { - "node": ">=12.0.0" + "node": ">=14.0.0" }, "funding": { "type": "opencollective", @@ -3869,9 +3816,10 @@ "peerDependencies": { "@emotion/react": "^11.5.0", "@emotion/styled": "^11.3.0", - "@types/react": "^17.0.0 || ^18.0.0", - "react": "^17.0.0 || ^18.0.0", - "react-dom": "^17.0.0 || ^18.0.0" + "@mui/material-pigment-css": "^6.0.1", + "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0", + "react": "^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0" }, "peerDependenciesMeta": { "@emotion/react": { @@ -3880,30 +3828,33 @@ "@emotion/styled": { "optional": true }, + "@mui/material-pigment-css": { + "optional": true + }, "@types/react": { "optional": true } } }, "node_modules/@mui/private-theming": { - "version": "5.16.6", - "resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-5.16.6.tgz", - "integrity": "sha512-rAk+Rh8Clg7Cd7shZhyt2HGTTE5wYKNSJ5sspf28Fqm/PZ69Er9o6KX25g03/FG2dfpg5GCwZh/xOojiTfm3hw==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-6.0.1.tgz", + "integrity": "sha512-jQCJml1OwIrhqN5tTk5Lpqx2RZKQnShE8lMlvAkuO7Ft+xaHkP8J3iHpEk3/Pzue34DfBQtK00jcaplgM47mBA==", "dependencies": { - "@babel/runtime": "^7.23.9", - "@mui/utils": "^5.16.6", + "@babel/runtime": "^7.25.0", + "@mui/utils": "^6.0.1", "prop-types": "^15.8.1" }, "engines": { - "node": ">=12.0.0" + "node": ">=14.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/mui-org" }, "peerDependencies": { - "@types/react": "^17.0.0 || ^18.0.0", - "react": "^17.0.0 || ^18.0.0" + "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0", + "react": "^17.0.0 || ^18.0.0 || ^19.0.0" }, "peerDependenciesMeta": { "@types/react": { @@ -3912,17 +3863,17 @@ } }, "node_modules/@mui/styled-engine": { - "version": "5.16.6", - "resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-5.16.6.tgz", - "integrity": "sha512-zaThmS67ZmtHSWToTiHslbI8jwrmITcN93LQaR2lKArbvS7Z3iLkwRoiikNWutx9MBs8Q6okKvbZq1RQYB3v7g==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-6.0.1.tgz", + "integrity": "sha512-7ZOnUhIak2vosDgMlBE/oLrsvvF3O8QKmTFpP6bhZkHjPu4dv0DbF1vC7gzgkOqiMaT0/NgRQCFW9zh38pIvsg==", "dependencies": { - "@babel/runtime": "^7.23.9", - "@emotion/cache": "^11.11.0", + "@babel/runtime": "^7.25.0", + "@emotion/cache": "^11.13.1", "csstype": "^3.1.3", "prop-types": "^15.8.1" }, "engines": { - "node": ">=12.0.0" + "node": ">=14.0.0" }, "funding": { "type": "opencollective", @@ -3931,7 +3882,7 @@ "peerDependencies": { "@emotion/react": "^11.4.1", "@emotion/styled": "^11.3.0", - "react": "^17.0.0 || ^18.0.0" + "react": "^17.0.0 || ^18.0.0 || ^19.0.0" }, "peerDependenciesMeta": { "@emotion/react": { @@ -3943,21 +3894,21 @@ } }, "node_modules/@mui/system": { - "version": "5.16.7", - "resolved": "https://registry.npmjs.org/@mui/system/-/system-5.16.7.tgz", - "integrity": "sha512-Jncvs/r/d/itkxh7O7opOunTqbbSSzMTHzZkNLM+FjAOg+cYAZHrPDlYe1ZGKUYORwwb2XexlWnpZp0kZ4AHuA==", - "dependencies": { - "@babel/runtime": "^7.23.9", - "@mui/private-theming": "^5.16.6", - "@mui/styled-engine": "^5.16.6", - "@mui/types": "^7.2.15", - "@mui/utils": "^5.16.6", - "clsx": "^2.1.0", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/@mui/system/-/system-6.0.1.tgz", + "integrity": "sha512-RdWyCMi+GkAekOnpMKhy51lyzid4F6Vj96vekp3AExkFY21JWg2+KVBqcAgJOROJ3RiaeDJf98n0yrixlCvuEw==", + "dependencies": { + "@babel/runtime": "^7.25.0", + "@mui/private-theming": "^6.0.1", + "@mui/styled-engine": "^6.0.1", + "@mui/types": "^7.2.16", + "@mui/utils": "^6.0.1", + "clsx": "^2.1.1", "csstype": "^3.1.3", "prop-types": "^15.8.1" }, "engines": { - "node": ">=12.0.0" + "node": ">=14.0.0" }, "funding": { "type": "opencollective", @@ -3966,8 +3917,8 @@ "peerDependencies": { "@emotion/react": "^11.5.0", "@emotion/styled": "^11.3.0", - "@types/react": "^17.0.0 || ^18.0.0", - "react": "^17.0.0 || ^18.0.0" + "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0", + "react": "^17.0.0 || ^18.0.0 || ^19.0.0" }, "peerDependenciesMeta": { "@emotion/react": { @@ -3982,11 +3933,11 @@ } }, "node_modules/@mui/types": { - "version": "7.2.15", - "resolved": "https://registry.npmjs.org/@mui/types/-/types-7.2.15.tgz", - "integrity": "sha512-nbo7yPhtKJkdf9kcVOF8JZHPZTmqXjJ/tI0bdWgHg5tp9AnIN4Y7f7wm9T+0SyGYJk76+GYZ8Q5XaTYAsUHN0Q==", + "version": "7.2.16", + "resolved": "https://registry.npmjs.org/@mui/types/-/types-7.2.16.tgz", + "integrity": "sha512-qI8TV3M7ShITEEc8Ih15A2vLzZGLhD+/UPNwck/hcls2gwg7dyRjNGXcQYHKLB5Q7PuTRfrTkAoPa2VV1s67Ag==", "peerDependencies": { - "@types/react": "^17.0.0 || ^18.0.0" + "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0" }, "peerDependenciesMeta": { "@types/react": { @@ -3995,27 +3946,27 @@ } }, "node_modules/@mui/utils": { - "version": "5.16.6", - "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-5.16.6.tgz", - "integrity": "sha512-tWiQqlhxAt3KENNiSRL+DIn9H5xNVK6Jjf70x3PnfQPz1MPBdh7yyIcAyVBT9xiw7hP3SomRhPR7hzBMBCjqEA==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-6.0.1.tgz", + "integrity": "sha512-YmQYb2tY5nJactHltTrKA15TZfbd1R003a2xYHxUuycTv9n83rsIwHkypOxM4x7+c+Pc8xfCuE9EfLT3B3n40Q==", "dependencies": { - "@babel/runtime": "^7.23.9", - "@mui/types": "^7.2.15", + "@babel/runtime": "^7.25.0", + "@mui/types": "^7.2.16", "@types/prop-types": "^15.7.12", "clsx": "^2.1.1", "prop-types": "^15.8.1", "react-is": "^18.3.1" }, "engines": { - "node": ">=12.0.0" + "node": ">=14.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/mui-org" }, "peerDependencies": { - "@types/react": "^17.0.0 || ^18.0.0", - "react": "^17.0.0 || ^18.0.0" + "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0", + "react": "^17.0.0 || ^18.0.0 || ^19.0.0" }, "peerDependenciesMeta": { "@types/react": { @@ -7110,6 +7061,175 @@ "unicode-trie": "^0.3.0" } }, + "node_modules/@rspack/binding": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@rspack/binding/-/binding-1.0.0.tgz", + "integrity": "sha512-eLyqSEM1h/exJYn98k+9MRktP8AYDB13x5oVn8hoxVucuhk0TubFqQSX8h9SQcZp1O3j/Z8eWWwOaNPe3JU40Q==", + "optional": true, + "peer": true, + "optionalDependencies": { + "@rspack/binding-darwin-arm64": "1.0.0", + "@rspack/binding-darwin-x64": "1.0.0", + "@rspack/binding-linux-arm64-gnu": "1.0.0", + "@rspack/binding-linux-arm64-musl": "1.0.0", + "@rspack/binding-linux-x64-gnu": "1.0.0", + "@rspack/binding-linux-x64-musl": "1.0.0", + "@rspack/binding-win32-arm64-msvc": "1.0.0", + "@rspack/binding-win32-ia32-msvc": "1.0.0", + "@rspack/binding-win32-x64-msvc": "1.0.0" + } + }, + "node_modules/@rspack/binding-darwin-arm64": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@rspack/binding-darwin-arm64/-/binding-darwin-arm64-1.0.0.tgz", + "integrity": "sha512-ZHQk9YK+swlTG48kJTgzFUW9T26KjhLXRok5la7t2AMoiuHyhGHHgC5iQfPJLZ62XzcJ/rfqs2rwakl97151jQ==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "darwin" + ], + "peer": true + }, + "node_modules/@rspack/binding-darwin-x64": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@rspack/binding-darwin-x64/-/binding-darwin-x64-1.0.0.tgz", + "integrity": "sha512-qhTXm9wUhv2lBjsqqfCu59RchH1/2jursdPAmTqGc7zMReZdZvtJs2Ri6Ma1M48BLLu+7fS4fbL8Rw1g78TOOQ==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "darwin" + ], + "peer": true + }, + "node_modules/@rspack/binding-linux-arm64-gnu": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@rspack/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.0.tgz", + "integrity": "sha512-yKnlsWgvydJRxDBGGKC+cyDeoSzIvOzuVqCloy5oAFAGOMXMY6bznxrkE6/olGZncdeLEpnJzZmXSuF1dYc8ow==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "peer": true + }, + "node_modules/@rspack/binding-linux-arm64-musl": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@rspack/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.0.tgz", + "integrity": "sha512-dKFmlqlF4FELT/AX02hSwX8aRawjH5zAliQzYnvgrqcEyCKE60vKacGJQ3ZeRyru6dh5MlbUNW4H1+TDT+cDVA==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "peer": true + }, + "node_modules/@rspack/binding-linux-x64-gnu": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@rspack/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.0.tgz", + "integrity": "sha512-fRk9i8aE4FiwW7+LkNyw+5vfFzJ8BZ2seAL9V5U2iwYwYibzFJsukg3h3Uh+IsGm30/7+ZRENtGwybQiMruL4g==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "peer": true + }, + "node_modules/@rspack/binding-linux-x64-musl": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@rspack/binding-linux-x64-musl/-/binding-linux-x64-musl-1.0.0.tgz", + "integrity": "sha512-qcTJC8o3KvLwsnrJJcuBjfzSrjEbACMiCB4RtbFNecXDtI+Nputx1CO1SlUrINC25/44ILketf0/hsdBQHk60g==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "peer": true + }, + "node_modules/@rspack/binding-win32-arm64-msvc": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@rspack/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.0.tgz", + "integrity": "sha512-gqtakP0Yl2aj+Q/Giwgt31hz8eOZpo2s+sJlkMJGVdIF4dejB31a8vbj/VNGeSN1tDRiLI4cyqa5eQU//t26aQ==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "win32" + ], + "peer": true + }, + "node_modules/@rspack/binding-win32-ia32-msvc": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@rspack/binding-win32-ia32-msvc/-/binding-win32-ia32-msvc-1.0.0.tgz", + "integrity": "sha512-nLfGu5DjdzwawzZ7zK69vZX5aL1Gt9+Ovfz4RlngDq/D5ZzqCnNWw93cqKADgFRWS4qK9vOD9RXNNnkyWB2SEw==", + "cpu": [ + "ia32" + ], + "optional": true, + "os": [ + "win32" + ], + "peer": true + }, + "node_modules/@rspack/binding-win32-x64-msvc": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@rspack/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.0.0.tgz", + "integrity": "sha512-H9PqjgtZMw5aP+eXdFo7bgSP/Ycwn3oW81uI9qFqOOQ90W+o3T9ItghHBf2/ksc5GHibd208EwOBNxbKwjZDSQ==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "win32" + ], + "peer": true + }, + "node_modules/@rspack/core": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@rspack/core/-/core-1.0.0.tgz", + "integrity": "sha512-F4RA9uOLLvD1oTKa96Gcly+Sro1qaqPNENadFyiPwepa7DrwexQa/ym6CQKbvKMOYGKlVSFDPUmgFAirz35ETg==", + "optional": true, + "peer": true, + "dependencies": { + "@module-federation/runtime-tools": "0.5.1", + "@rspack/binding": "1.0.0", + "@rspack/lite-tapable": "1.0.0", + "caniuse-lite": "^1.0.30001616" + }, + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "@swc/helpers": ">=0.5.1" + }, + "peerDependenciesMeta": { + "@swc/helpers": { + "optional": true + } + } + }, + "node_modules/@rspack/lite-tapable": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@rspack/lite-tapable/-/lite-tapable-1.0.0.tgz", + "integrity": "sha512-7MZf4lburSUZoEenwazwUDKHhqyfnLCGnQ/tKcUtztfmVzfjZfRn/EaiT0AKkYGnL2U8AGsw89oUeVyvaOLVCw==", + "optional": true, + "peer": true, + "engines": { + "node": ">=16.0.0" + } + }, "node_modules/@sec-ant/readable-stream": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/@sec-ant/readable-stream/-/readable-stream-0.4.1.tgz", @@ -8827,6 +8947,11 @@ "integrity": "sha512-fpdH+ZtlO0kqjTOqRaBdsEmvpRNOayI8k4EVkEtitL5l6wducDOXk0rgQgfZqWf/ZX9DzXrHf257S5i9xTcISQ==", "dev": true }, + "node_modules/@types/any-base": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@types/any-base/-/any-base-1.1.3.tgz", + "integrity": "sha512-B7RTBD7jVYxm754XDdw6UozY3ZyyBv4iF4QQSjCzeLV4avDy8JBwCuI5SN4mz27ENI6K1NtKZwQ7zcqgH2h2Mw==" + }, "node_modules/@types/archiver": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/@types/archiver/-/archiver-6.0.2.tgz", @@ -8893,9 +9018,9 @@ "dev": true }, "node_modules/@types/chai": { - "version": "4.3.18", - "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.3.18.tgz", - "integrity": "sha512-2UfJzigyNa8kYTKn7o4hNMPphkxtu4WTJyobK3m4FBpyj7EK5xgtPcOtxLm7Dznk/Qxr0QXn+gQbkg7mCZKdfg==", + "version": "4.3.19", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.3.19.tgz", + "integrity": "sha512-2hHHvQBVE2FiSK4eN0Br6snX9MtolHaTo/batnLjlGRhoQzlCL61iVpxoqO7SfFyOw+P/pwv+0zNHzKoGWz9Cw==", "dev": true }, "node_modules/@types/color": { @@ -9309,9 +9434,9 @@ "integrity": "sha512-IGKtSn0Lonfx3HdK6KMcfd5GUc1xdeLtjW1n7ZSA5Tmn1n2gj878q6IC0s4MbF9KtBpXIRqjRQxBzi2kF4WvGw==" }, "node_modules/@types/fluent-ffmpeg": { - "version": "2.1.25", - "resolved": "https://registry.npmjs.org/@types/fluent-ffmpeg/-/fluent-ffmpeg-2.1.25.tgz", - "integrity": "sha512-a9/Jtv/RVaCG4lUwWIcuClWE5eXJFoFS/oHOecOv/RS8n+lQdJzcJVmDlxA8Xbk4B82YpO88Dijcoljb6sYTcA==", + "version": "2.1.26", + "resolved": "https://registry.npmjs.org/@types/fluent-ffmpeg/-/fluent-ffmpeg-2.1.26.tgz", + "integrity": "sha512-0JVF3wdQG+pN0ImwWD0bNgJiKF2OHg/7CDBHw5UIbRTvlnkgGHK6V5doE54ltvhud4o31/dEiHm23CAlxFiUQg==", "dependencies": { "@types/node": "*" } @@ -9481,6 +9606,14 @@ "@types/geojson": "*" } }, + "node_modules/@types/mdast": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-4.0.4.tgz", + "integrity": "sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==", + "dependencies": { + "@types/unist": "*" + } + }, "node_modules/@types/mime": { "version": "1.3.5", "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz", @@ -9505,9 +9638,9 @@ "integrity": "sha512-nG96G3Wp6acyAgJqGasjODb+acrI7KltPiRxzHPXnP3NgI28bpQDRv53olbqGXbfcgF5aiiHmO3xpwEpS5Ld9g==" }, "node_modules/@types/node": { - "version": "22.5.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.5.0.tgz", - "integrity": "sha512-DkFrJOe+rfdHTqqMg0bSNlGlQ85hSoh2TPzZyhHsXnMtligRWpxUySiyw8FY14ITt24HVCiQPWxS3KO/QlGmWg==", + "version": "22.5.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.5.1.tgz", + "integrity": "sha512-KkHsxej0j9IW1KKOOAA/XBA0z08UFSrRQHErzEfA3Vgq57eXIMYboIlHJuYIfd+lwCQjtKqUu3UnmKbtUc9yRw==", "dependencies": { "undici-types": "~6.19.2" } @@ -9628,8 +9761,7 @@ "node_modules/@types/qs": { "version": "6.9.15", "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.15.tgz", - "integrity": "sha512-uXHQKES6DQKKCLh441Xv/dwxOq1TVS3JPUMlEqoEglvlhR6Mxnlew/Xq/LRVHpLyk7iK3zODe1qYHIMltO7XGg==", - "dev": true + "integrity": "sha512-uXHQKES6DQKKCLh441Xv/dwxOq1TVS3JPUMlEqoEglvlhR6Mxnlew/Xq/LRVHpLyk7iK3zODe1qYHIMltO7XGg==" }, "node_modules/@types/range-parser": { "version": "1.2.7", @@ -9647,9 +9779,9 @@ } }, "node_modules/@types/react": { - "version": "18.3.4", - "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.4.tgz", - "integrity": "sha512-J7W30FTdfCxDDjmfRM+/JqLHBIyl7xUIp9kwK637FGmY7+mkSFSe6L4jpZzhj5QMfLssSDP4/i75AKkrdC7/Jw==", + "version": "18.3.5", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.5.tgz", + "integrity": "sha512-WeqMfGJLGuLCqHGYRGHxnKrXcTitc6L/nBUWfWPcTarG3t9PsquqUMuVeXZeca+mglY4Vo5GZjCi0A3Or2lnxA==", "dependencies": { "@types/prop-types": "*", "csstype": "^3.0.2" @@ -9890,9 +10022,9 @@ "dev": true }, "node_modules/@types/unist": { - "version": "2.0.11", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.11.tgz", - "integrity": "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==" + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", + "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==" }, "node_modules/@types/uuid": { "version": "10.0.0", @@ -9907,9 +10039,9 @@ "dev": true }, "node_modules/@types/web": { - "version": "0.0.157", - "resolved": "https://registry.npmjs.org/@types/web/-/web-0.0.157.tgz", - "integrity": "sha512-erqzRlWBxaV7qI0g5rIkHRRxQ3kKmqqhokqgnSy3UEQYIl+5qNCU7DwdPaOke3ZHRXmbrjpGgSc4bjM4ItSDnw==" + "version": "0.0.159", + "resolved": "https://registry.npmjs.org/@types/web/-/web-0.0.159.tgz", + "integrity": "sha512-BHPaU+yHqHOrua8iFksPmgLCXEt1LE/2sPB+MPTRuxDFm4z6gBgmDiXUCGleyHiOLT6R+fklgR99hq/iFGVO1w==" }, "node_modules/@types/webgl-ext": { "version": "0.0.30", @@ -10538,9 +10670,9 @@ } }, "node_modules/adm-zip": { - "version": "0.5.15", - "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.5.15.tgz", - "integrity": "sha512-jYPWSeOA8EFoZnucrKCNihqBjoEGQSU4HKgHYQgKNEQ0pQF9a/DYuo/+fAxY76k4qe75LUlLWpAM1QWcBMTOKw==", + "version": "0.5.16", + "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.5.16.tgz", + "integrity": "sha512-TGw5yVi4saajsSEgz25grObGHEUaDrniwvA2qwSC060KfqGPdglhvPMA2lPIoxs3PQIItj2iag35fONcQqgUaQ==", "engines": { "node": ">=12.0" } @@ -11036,6 +11168,14 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/await-to-js": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/await-to-js/-/await-to-js-3.0.0.tgz", + "integrity": "sha512-zJAaP9zxTcvTHRlejau3ZOY4V7SRpiByf3/dxx2uyKxxor19tpmpV2QRsTKikckwhaPmr2dVpxxMr7jOCYVp5g==", + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/aws-sign2": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", @@ -11045,14 +11185,14 @@ } }, "node_modules/aws4": { - "version": "1.13.1", - "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.13.1.tgz", - "integrity": "sha512-u5w79Rd7SU4JaIlA/zFqG+gOiuq25q5VLyZ8E+ijJeILuTxVzZgp2CaGw/UTw6pXYN9XMO9yiqj/nEHmhTG5CA==" + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.13.2.tgz", + "integrity": "sha512-lHe62zvbTB5eEABUVi/AwVh0ZKY9rMMDhmm+eeyuuUQbQ3+J+fONVQOZyj+DdrvD4BY33uYniyRJ4UJIaSKAfw==" }, "node_modules/axios": { - "version": "1.7.5", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.5.tgz", - "integrity": "sha512-fZu86yCo+svH3uqJ/yTdQ0QHpQu5oL+/QE+QPSv6BZSkDAoky9vytxp7u5qk83OJFS3kEBcesWni9WTZAv3tSw==", + "version": "1.7.7", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.7.tgz", + "integrity": "sha512-S4kL7XrjgBmvdGut0sN3yJxqYzrDOnivkBiN0OFs6hLiUam3UPvswUo0kqGyhqUZGEOytHyumEdXsAkgCOUf3Q==", "dependencies": { "follow-redirects": "^1.15.6", "form-data": "^4.0.0", @@ -11339,10 +11479,10 @@ "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==" }, - "node_modules/bmp-js": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/bmp-js/-/bmp-js-0.1.0.tgz", - "integrity": "sha512-vHdS19CnY3hwiNdkaqk93DvjVLfbEcI8mys4UjuWrlX1haDmroo8o4xCzh4wD6DGV6HxRCyauwhHRqMTfERtjw==" + "node_modules/bmp-ts": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/bmp-ts/-/bmp-ts-1.0.9.tgz", + "integrity": "sha512-cTEHk2jLrPyi+12M3dhpEbnnPOsaZuq7C45ylbbQIiWgDFZq4UVYPEY5mlqjvsj/6gJv9qX5sa+ebDzLXT28Vw==" }, "node_modules/bn.js": { "version": "4.12.0", @@ -11467,6 +11607,116 @@ "integrity": "sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg==", "peer": true }, + "node_modules/browndash-components/node_modules/@mui/core-downloads-tracker": { + "version": "5.16.7", + "resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-5.16.7.tgz", + "integrity": "sha512-RtsCt4Geed2/v74sbihWzzRs+HsIQCfclHeORh5Ynu2fS4icIKozcSubwuG7vtzq2uW3fOR1zITSP84TNt2GoQ==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + } + }, + "node_modules/browndash-components/node_modules/@mui/material": { + "version": "5.16.7", + "resolved": "https://registry.npmjs.org/@mui/material/-/material-5.16.7.tgz", + "integrity": "sha512-cwwVQxBhK60OIOqZOVLFt55t01zmarKJiJUWbk0+8s/Ix5IaUzAShqlJchxsIQ4mSrWqgcKCCXKtIlG5H+/Jmg==", + "dependencies": { + "@babel/runtime": "^7.23.9", + "@mui/core-downloads-tracker": "^5.16.7", + "@mui/system": "^5.16.7", + "@mui/types": "^7.2.15", + "@mui/utils": "^5.16.6", + "@popperjs/core": "^2.11.8", + "@types/react-transition-group": "^4.4.10", + "clsx": "^2.1.0", + "csstype": "^3.1.3", + "prop-types": "^15.8.1", + "react-is": "^18.3.1", + "react-transition-group": "^4.4.5" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@emotion/react": "^11.5.0", + "@emotion/styled": "^11.3.0", + "@types/react": "^17.0.0 || ^18.0.0", + "react": "^17.0.0 || ^18.0.0", + "react-dom": "^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@emotion/react": { + "optional": true + }, + "@emotion/styled": { + "optional": true + }, + "@types/react": { + "optional": true + } + } + }, + "node_modules/browndash-components/node_modules/@mui/private-theming": { + "version": "5.16.6", + "resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-5.16.6.tgz", + "integrity": "sha512-rAk+Rh8Clg7Cd7shZhyt2HGTTE5wYKNSJ5sspf28Fqm/PZ69Er9o6KX25g03/FG2dfpg5GCwZh/xOojiTfm3hw==", + "dependencies": { + "@babel/runtime": "^7.23.9", + "@mui/utils": "^5.16.6", + "prop-types": "^15.8.1" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@types/react": "^17.0.0 || ^18.0.0", + "react": "^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/browndash-components/node_modules/@mui/styled-engine": { + "version": "5.16.6", + "resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-5.16.6.tgz", + "integrity": "sha512-zaThmS67ZmtHSWToTiHslbI8jwrmITcN93LQaR2lKArbvS7Z3iLkwRoiikNWutx9MBs8Q6okKvbZq1RQYB3v7g==", + "dependencies": { + "@babel/runtime": "^7.23.9", + "@emotion/cache": "^11.11.0", + "csstype": "^3.1.3", + "prop-types": "^15.8.1" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@emotion/react": "^11.4.1", + "@emotion/styled": "^11.3.0", + "react": "^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@emotion/react": { + "optional": true + }, + "@emotion/styled": { + "optional": true + } + } + }, "node_modules/browndash-components/node_modules/@mui/styled-engine-sc": { "version": "5.14.12", "resolved": "https://registry.npmjs.org/@mui/styled-engine-sc/-/styled-engine-sc-5.14.12.tgz", @@ -11493,6 +11743,74 @@ } } }, + "node_modules/browndash-components/node_modules/@mui/system": { + "version": "5.16.7", + "resolved": "https://registry.npmjs.org/@mui/system/-/system-5.16.7.tgz", + "integrity": "sha512-Jncvs/r/d/itkxh7O7opOunTqbbSSzMTHzZkNLM+FjAOg+cYAZHrPDlYe1ZGKUYORwwb2XexlWnpZp0kZ4AHuA==", + "dependencies": { + "@babel/runtime": "^7.23.9", + "@mui/private-theming": "^5.16.6", + "@mui/styled-engine": "^5.16.6", + "@mui/types": "^7.2.15", + "@mui/utils": "^5.16.6", + "clsx": "^2.1.0", + "csstype": "^3.1.3", + "prop-types": "^15.8.1" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@emotion/react": "^11.5.0", + "@emotion/styled": "^11.3.0", + "@types/react": "^17.0.0 || ^18.0.0", + "react": "^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@emotion/react": { + "optional": true + }, + "@emotion/styled": { + "optional": true + }, + "@types/react": { + "optional": true + } + } + }, + "node_modules/browndash-components/node_modules/@mui/utils": { + "version": "5.16.6", + "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-5.16.6.tgz", + "integrity": "sha512-tWiQqlhxAt3KENNiSRL+DIn9H5xNVK6Jjf70x3PnfQPz1MPBdh7yyIcAyVBT9xiw7hP3SomRhPR7hzBMBCjqEA==", + "dependencies": { + "@babel/runtime": "^7.23.9", + "@mui/types": "^7.2.15", + "@types/prop-types": "^15.7.12", + "clsx": "^2.1.1", + "prop-types": "^15.8.1", + "react-is": "^18.3.1" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@types/react": "^17.0.0 || ^18.0.0", + "react": "^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, "node_modules/browndash-components/node_modules/npm": { "version": "9.9.3", "resolved": "https://registry.npmjs.org/npm/-/npm-9.9.3.tgz", @@ -14610,9 +14928,9 @@ } }, "node_modules/buffer": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", - "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", "funding": [ { "type": "github", @@ -14629,7 +14947,7 @@ ], "dependencies": { "base64-js": "^1.3.1", - "ieee754": "^1.1.13" + "ieee754": "^1.2.1" } }, "node_modules/buffer-crc32": { @@ -14640,14 +14958,6 @@ "node": ">=8.0.0" } }, - "node_modules/buffer-equal": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/buffer-equal/-/buffer-equal-0.0.1.tgz", - "integrity": "sha512-RgSV6InVQ9ODPdLWJ5UAqBqJBOg370Nz6ZQtRzpt6nUjc8v0St97uJ4PYC6NztqIScrAXafKM3mZPMygSe1ggA==", - "engines": { - "node": ">=0.4.0" - } - }, "node_modules/buffer-equal-constant-time": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", @@ -14802,9 +15112,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001653", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001653.tgz", - "integrity": "sha512-XGWQVB8wFQ2+9NZwZ10GxTYC5hk0Fa+q8cSkr0tgvMhYhMHP/QC+WTgrePMDBWiWc/pV+1ik82Al20XOK25Gcw==", + "version": "1.0.30001655", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001655.tgz", + "integrity": "sha512-jRGVy3iSGO5Uutn2owlb5gR6qsGngTw9ZTb4ali9f3glshcNmJ2noam4Mo9zia5P9Dk3jNNydy7vQjuE5dQmfg==", "funding": [ { "type": "opencollective", @@ -14848,14 +15158,6 @@ "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/centra": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/centra/-/centra-2.7.0.tgz", - "integrity": "sha512-PbFMgMSrmgx6uxCdm57RUos9Tc3fclMvhLSATYN39XsDV29B89zZ3KA89jmY0vwSGazyU+uerqwa6t+KaodPcg==", - "dependencies": { - "follow-redirects": "^1.15.6" - } - }, "node_modules/chai": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/chai/-/chai-5.1.1.tgz", @@ -16995,11 +17297,6 @@ "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" } }, - "node_modules/dom-walk": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/dom-walk/-/dom-walk-0.1.2.tgz", - "integrity": "sha512-6QvTW9mrGeIegrFXdtQi9pk7O/nSK6lSdXW2eqUspN5LWD7UTji2Fqw5V2YLjBpHEoU9Xl/eUWNpDeZvoyOv2w==" - }, "node_modules/domelementtype": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", @@ -17424,9 +17721,9 @@ "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==" }, "node_modules/escalade": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz", - "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", "engines": { "node": ">=6" } @@ -19252,15 +19549,6 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/global": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/global/-/global-4.4.0.tgz", - "integrity": "sha512-wv/LAoHdRE3BeTGz53FAamhGlPLhlssK45usmGFThIi4XqnBmjKQ16u+RNbP7WvigRZDxUsM0J3gcQ5yicaL0w==", - "dependencies": { - "min-document": "^2.19.0", - "process": "^0.11.10" - } - }, "node_modules/global-modules": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-1.0.0.tgz", @@ -19654,11 +19942,6 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/hast-util-from-parse5/node_modules/@types/unist": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", - "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==" - }, "node_modules/hast-util-is-element": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/hast-util-is-element/-/hast-util-is-element-3.0.0.tgz", @@ -19707,11 +19990,6 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/hast-util-raw/node_modules/@types/unist": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", - "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==" - }, "node_modules/hast-util-to-jsx-runtime": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/hast-util-to-jsx-runtime/-/hast-util-to-jsx-runtime-2.3.0.tgz", @@ -19738,11 +20016,6 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/hast-util-to-jsx-runtime/node_modules/@types/unist": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", - "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==" - }, "node_modules/hast-util-to-parse5": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/hast-util-to-parse5/-/hast-util-to-parse5-8.0.0.tgz", @@ -19776,11 +20049,6 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/hast-util-to-text/node_modules/@types/unist": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", - "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==" - }, "node_modules/hast-util-whitespace": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/hast-util-whitespace/-/hast-util-whitespace-3.0.0.tgz", @@ -21056,11 +21324,6 @@ "node": ">=8" } }, - "node_modules/is-function": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-function/-/is-function-1.0.2.tgz", - "integrity": "sha512-lw7DUp0aWXYg+CBCN+JKkcE0Q2RayZnSvnZBlwgxHBQhqt5pZNVy4Ri7H9GmmXkdu7LUthszM+Tor1u/2iBcpQ==" - }, "node_modules/is-generator-function": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.10.tgz", @@ -21414,15 +21677,6 @@ "node": ">=0.10.0" } }, - "node_modules/isomorphic-fetch": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/isomorphic-fetch/-/isomorphic-fetch-3.0.0.tgz", - "integrity": "sha512-qvUtwJ3j6qwsF3jLxkZ72qCgjMysPzDfeV240JHiGZsANBYd+EEuu35v7dfrJ9Up0Ak07D7GGSkGhCHTqg/5wA==", - "dependencies": { - "node-fetch": "^2.6.1", - "whatwg-fetch": "^3.4.1" - } - }, "node_modules/isstream": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", @@ -21581,21 +21835,38 @@ } }, "node_modules/jimp": { - "version": "0.22.12", - "resolved": "https://registry.npmjs.org/jimp/-/jimp-0.22.12.tgz", - "integrity": "sha512-R5jZaYDnfkxKJy1dwLpj/7cvyjxiclxU3F4TrI/J4j2rS0niq6YDUMoPn5hs8GDpO+OZGo7Ky057CRtWesyhfg==", - "dependencies": { - "@jimp/custom": "^0.22.12", - "@jimp/plugins": "^0.22.12", - "@jimp/types": "^0.22.12", - "regenerator-runtime": "^0.13.3" + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/jimp/-/jimp-1.0.4.tgz", + "integrity": "sha512-J1zLB9LCEMznSoh277vJuiIzTxlurJxrC1Wv9aRKtbLtRZEwxEU5iHmN300Hzc62BUCyGziVHx6g7kfTp84j0A==", + "dependencies": { + "@jimp/core": "1.0.4", + "@jimp/diff": "1.0.4", + "@jimp/js-bmp": "1.0.4", + "@jimp/js-gif": "1.0.4", + "@jimp/js-jpeg": "1.0.4", + "@jimp/js-png": "1.0.4", + "@jimp/js-tiff": "1.0.4", + "@jimp/plugin-blit": "1.0.4", + "@jimp/plugin-blur": "1.0.4", + "@jimp/plugin-circle": "1.0.4", + "@jimp/plugin-color": "1.0.4", + "@jimp/plugin-contain": "1.0.4", + "@jimp/plugin-cover": "1.0.4", + "@jimp/plugin-crop": "1.0.4", + "@jimp/plugin-displace": "1.0.4", + "@jimp/plugin-dither": "1.0.4", + "@jimp/plugin-fisheye": "1.0.4", + "@jimp/plugin-flip": "1.0.4", + "@jimp/plugin-hash": "1.0.4", + "@jimp/plugin-mask": "1.0.4", + "@jimp/plugin-print": "1.0.4", + "@jimp/plugin-resize": "1.0.4", + "@jimp/plugin-rotate": "1.0.4", + "@jimp/plugin-threshold": "1.0.4", + "@jimp/types": "1.0.4", + "@jimp/utils": "1.0.4" } }, - "node_modules/jimp/node_modules/regenerator-runtime": { - "version": "0.13.11", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", - "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==" - }, "node_modules/jpeg-autorotate": { "version": "9.0.0", "resolved": "https://registry.npmjs.org/jpeg-autorotate/-/jpeg-autorotate-9.0.0.tgz", @@ -22176,21 +22447,6 @@ "uc.micro": "^2.0.0" } }, - "node_modules/load-bmfont": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/load-bmfont/-/load-bmfont-1.4.2.tgz", - "integrity": "sha512-qElWkmjW9Oq1F9EI5Gt7aD9zcdHb9spJCW1L/dmPf7KzCCEJxq8nhHz5eCgI9aMf7vrG/wyaCqdsI+Iy9ZTlog==", - "dependencies": { - "buffer-equal": "0.0.1", - "mime": "^1.3.4", - "parse-bmfont-ascii": "^1.0.3", - "parse-bmfont-binary": "^1.0.5", - "parse-bmfont-xml": "^1.1.4", - "phin": "^3.7.1", - "xhr": "^2.0.1", - "xtend": "^4.0.0" - } - }, "node_modules/loader-runner": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz", @@ -22656,14 +22912,6 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/mdast-util-find-and-replace/node_modules/@types/mdast": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-4.0.4.tgz", - "integrity": "sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==", - "dependencies": { - "@types/unist": "*" - } - }, "node_modules/mdast-util-find-and-replace/node_modules/escape-string-regexp": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", @@ -22675,6 +22923,29 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/mdast-util-from-markdown": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mdast-util-from-markdown/-/mdast-util-from-markdown-2.0.1.tgz", + "integrity": "sha512-aJEUyzZ6TzlsX2s5B4Of7lN7EQtAxvtradMMglCQDyaTFgse6CmtmdJ15ElnVRlCg1vpNyVtbem0PWzlNieZsA==", + "dependencies": { + "@types/mdast": "^4.0.0", + "@types/unist": "^3.0.0", + "decode-named-character-reference": "^1.0.0", + "devlop": "^1.0.0", + "mdast-util-to-string": "^4.0.0", + "micromark": "^4.0.0", + "micromark-util-decode-numeric-character-reference": "^2.0.0", + "micromark-util-decode-string": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0", + "unist-util-stringify-position": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, "node_modules/mdast-util-gfm": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/mdast-util-gfm/-/mdast-util-gfm-3.0.0.tgz", @@ -22709,4523 +22980,136 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/mdast-util-gfm-autolink-literal/node_modules/@types/mdast": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-4.0.4.tgz", - "integrity": "sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==", - "dependencies": { - "@types/unist": "*" - } - }, - "node_modules/mdast-util-gfm-autolink-literal/node_modules/micromark-util-character": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.0.tgz", - "integrity": "sha512-KvOVV+X1yLBfs9dCBSopq/+G1PcgT3lAK07mC4BzXi5E7ahzMAF8oIupDDJ6mievI6F+lAATkbQQlQixJfT3aQ==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/mdast-util-gfm-autolink-literal/node_modules/micromark-util-symbol": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", - "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ] - }, - "node_modules/mdast-util-gfm-autolink-literal/node_modules/micromark-util-types": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-2.0.0.tgz", - "integrity": "sha512-oNh6S2WMHWRZrmutsRmDDfkzKtxF+bc2VxLC9dvtrDIRFln627VsFP6fLMgTryGDljgLPjkrzQSDcPrjPyDJ5w==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ] - }, - "node_modules/mdast-util-gfm-footnote": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/mdast-util-gfm-footnote/-/mdast-util-gfm-footnote-2.0.0.tgz", - "integrity": "sha512-5jOT2boTSVkMnQ7LTrd6n/18kqwjmuYqo7JUPe+tRCY6O7dAuTFMtTPauYYrMPpox9hlN0uOx/FL8XvEfG9/mQ==", - "dependencies": { - "@types/mdast": "^4.0.0", - "devlop": "^1.1.0", - "mdast-util-from-markdown": "^2.0.0", - "mdast-util-to-markdown": "^2.0.0", - "micromark-util-normalize-identifier": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/mdast-util-gfm-footnote/node_modules/@types/mdast": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-4.0.4.tgz", - "integrity": "sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==", - "dependencies": { - "@types/unist": "*" - } - }, - "node_modules/mdast-util-gfm-footnote/node_modules/@types/unist": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", - "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==" - }, - "node_modules/mdast-util-gfm-footnote/node_modules/mdast-util-from-markdown": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/mdast-util-from-markdown/-/mdast-util-from-markdown-2.0.1.tgz", - "integrity": "sha512-aJEUyzZ6TzlsX2s5B4Of7lN7EQtAxvtradMMglCQDyaTFgse6CmtmdJ15ElnVRlCg1vpNyVtbem0PWzlNieZsA==", - "dependencies": { - "@types/mdast": "^4.0.0", - "@types/unist": "^3.0.0", - "decode-named-character-reference": "^1.0.0", - "devlop": "^1.0.0", - "mdast-util-to-string": "^4.0.0", - "micromark": "^4.0.0", - "micromark-util-decode-numeric-character-reference": "^2.0.0", - "micromark-util-decode-string": "^2.0.0", - "micromark-util-normalize-identifier": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0", - "unist-util-stringify-position": "^4.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/mdast-util-gfm-footnote/node_modules/mdast-util-to-string": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-4.0.0.tgz", - "integrity": "sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg==", - "dependencies": { - "@types/mdast": "^4.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/mdast-util-gfm-footnote/node_modules/micromark": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/micromark/-/micromark-4.0.0.tgz", - "integrity": "sha512-o/sd0nMof8kYff+TqcDx3VSrgBTcZpSvYcAHIfHhv5VAuNmisCxjhx6YmxS8PFEpb9z5WKWKPdzf0jM23ro3RQ==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "@types/debug": "^4.0.0", - "debug": "^4.0.0", - "decode-named-character-reference": "^1.0.0", - "devlop": "^1.0.0", - "micromark-core-commonmark": "^2.0.0", - "micromark-factory-space": "^2.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-chunked": "^2.0.0", - "micromark-util-combine-extensions": "^2.0.0", - "micromark-util-decode-numeric-character-reference": "^2.0.0", - "micromark-util-encode": "^2.0.0", - "micromark-util-normalize-identifier": "^2.0.0", - "micromark-util-resolve-all": "^2.0.0", - "micromark-util-sanitize-uri": "^2.0.0", - "micromark-util-subtokenize": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/mdast-util-gfm-footnote/node_modules/micromark-core-commonmark": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-core-commonmark/-/micromark-core-commonmark-2.0.1.tgz", - "integrity": "sha512-CUQyKr1e///ZODyD1U3xit6zXwy1a8q2a1S1HKtIlmgvurrEpaw/Y9y6KSIbF8P59cn/NjzHyO+Q2fAyYLQrAA==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "decode-named-character-reference": "^1.0.0", - "devlop": "^1.0.0", - "micromark-factory-destination": "^2.0.0", - "micromark-factory-label": "^2.0.0", - "micromark-factory-space": "^2.0.0", - "micromark-factory-title": "^2.0.0", - "micromark-factory-whitespace": "^2.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-chunked": "^2.0.0", - "micromark-util-classify-character": "^2.0.0", - "micromark-util-html-tag-name": "^2.0.0", - "micromark-util-normalize-identifier": "^2.0.0", - "micromark-util-resolve-all": "^2.0.0", - "micromark-util-subtokenize": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/mdast-util-gfm-footnote/node_modules/micromark-factory-destination": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-factory-destination/-/micromark-factory-destination-2.0.0.tgz", - "integrity": "sha512-j9DGrQLm/Uhl2tCzcbLhy5kXsgkHUrjJHg4fFAeoMRwJmJerT9aw4FEhIbZStWN8A3qMwOp1uzHr4UL8AInxtA==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-util-character": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/mdast-util-gfm-footnote/node_modules/micromark-factory-label": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-factory-label/-/micromark-factory-label-2.0.0.tgz", - "integrity": "sha512-RR3i96ohZGde//4WSe/dJsxOX6vxIg9TimLAS3i4EhBAFx8Sm5SmqVfR8E87DPSR31nEAjZfbt91OMZWcNgdZw==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "devlop": "^1.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/mdast-util-gfm-footnote/node_modules/micromark-factory-space": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.0.tgz", - "integrity": "sha512-TKr+LIDX2pkBJXFLzpyPyljzYK3MtmllMUMODTQJIUfDGncESaqB90db9IAUcz4AZAJFdd8U9zOp9ty1458rxg==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-util-character": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/mdast-util-gfm-footnote/node_modules/micromark-factory-title": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-factory-title/-/micromark-factory-title-2.0.0.tgz", - "integrity": "sha512-jY8CSxmpWLOxS+t8W+FG3Xigc0RDQA9bKMY/EwILvsesiRniiVMejYTE4wumNc2f4UbAa4WsHqe3J1QS1sli+A==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-factory-space": "^2.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/mdast-util-gfm-footnote/node_modules/micromark-factory-whitespace": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-factory-whitespace/-/micromark-factory-whitespace-2.0.0.tgz", - "integrity": "sha512-28kbwaBjc5yAI1XadbdPYHX/eDnqaUFVikLwrO7FDnKG7lpgxnvk/XGRhX/PN0mOZ+dBSZ+LgunHS+6tYQAzhA==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-factory-space": "^2.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/mdast-util-gfm-footnote/node_modules/micromark-util-character": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.0.tgz", - "integrity": "sha512-KvOVV+X1yLBfs9dCBSopq/+G1PcgT3lAK07mC4BzXi5E7ahzMAF8oIupDDJ6mievI6F+lAATkbQQlQixJfT3aQ==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/mdast-util-gfm-footnote/node_modules/micromark-util-chunked": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-chunked/-/micromark-util-chunked-2.0.0.tgz", - "integrity": "sha512-anK8SWmNphkXdaKgz5hJvGa7l00qmcaUQoMYsBwDlSKFKjc6gjGXPDw3FNL3Nbwq5L8gE+RCbGqTw49FK5Qyvg==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-util-symbol": "^2.0.0" - } - }, - "node_modules/mdast-util-gfm-footnote/node_modules/micromark-util-classify-character": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-classify-character/-/micromark-util-classify-character-2.0.0.tgz", - "integrity": "sha512-S0ze2R9GH+fu41FA7pbSqNWObo/kzwf8rN/+IGlW/4tC6oACOs8B++bh+i9bVyNnwCcuksbFwsBme5OCKXCwIw==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-util-character": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/mdast-util-gfm-footnote/node_modules/micromark-util-combine-extensions": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-combine-extensions/-/micromark-util-combine-extensions-2.0.0.tgz", - "integrity": "sha512-vZZio48k7ON0fVS3CUgFatWHoKbbLTK/rT7pzpJ4Bjp5JjkZeasRfrS9wsBdDJK2cJLHMckXZdzPSSr1B8a4oQ==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-util-chunked": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/mdast-util-gfm-footnote/node_modules/micromark-util-decode-numeric-character-reference": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-decode-numeric-character-reference/-/micromark-util-decode-numeric-character-reference-2.0.1.tgz", - "integrity": "sha512-bmkNc7z8Wn6kgjZmVHOX3SowGmVdhYS7yBpMnuMnPzDq/6xwVA604DuOXMZTO1lvq01g+Adfa0pE2UKGlxL1XQ==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-util-symbol": "^2.0.0" - } - }, - "node_modules/mdast-util-gfm-footnote/node_modules/micromark-util-decode-string": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-decode-string/-/micromark-util-decode-string-2.0.0.tgz", - "integrity": "sha512-r4Sc6leeUTn3P6gk20aFMj2ntPwn6qpDZqWvYmAG6NgvFTIlj4WtrAudLi65qYoaGdXYViXYw2pkmn7QnIFasA==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "decode-named-character-reference": "^1.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-decode-numeric-character-reference": "^2.0.0", - "micromark-util-symbol": "^2.0.0" - } - }, - "node_modules/mdast-util-gfm-footnote/node_modules/micromark-util-encode": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-encode/-/micromark-util-encode-2.0.0.tgz", - "integrity": "sha512-pS+ROfCXAGLWCOc8egcBvT0kf27GoWMqtdarNfDcjb6YLuV5cM3ioG45Ys2qOVqeqSbjaKg72vU+Wby3eddPsA==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ] - }, - "node_modules/mdast-util-gfm-footnote/node_modules/micromark-util-html-tag-name": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-html-tag-name/-/micromark-util-html-tag-name-2.0.0.tgz", - "integrity": "sha512-xNn4Pqkj2puRhKdKTm8t1YHC/BAjx6CEwRFXntTaRf/x16aqka6ouVoutm+QdkISTlT7e2zU7U4ZdlDLJd2Mcw==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ] - }, - "node_modules/mdast-util-gfm-footnote/node_modules/micromark-util-normalize-identifier": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-normalize-identifier/-/micromark-util-normalize-identifier-2.0.0.tgz", - "integrity": "sha512-2xhYT0sfo85FMrUPtHcPo2rrp1lwbDEEzpx7jiH2xXJLqBuy4H0GgXk5ToU8IEwoROtXuL8ND0ttVa4rNqYK3w==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-util-symbol": "^2.0.0" - } - }, - "node_modules/mdast-util-gfm-footnote/node_modules/micromark-util-resolve-all": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-resolve-all/-/micromark-util-resolve-all-2.0.0.tgz", - "integrity": "sha512-6KU6qO7DZ7GJkaCgwBNtplXCvGkJToU86ybBAUdavvgsCiG8lSSvYxr9MhwmQ+udpzywHsl4RpGJsYWG1pDOcA==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/mdast-util-gfm-footnote/node_modules/micromark-util-sanitize-uri": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-2.0.0.tgz", - "integrity": "sha512-WhYv5UEcZrbAtlsnPuChHUAsu/iBPOVaEVsntLBIdpibO0ddy8OzavZz3iL2xVvBZOpolujSliP65Kq0/7KIYw==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-util-character": "^2.0.0", - "micromark-util-encode": "^2.0.0", - "micromark-util-symbol": "^2.0.0" - } - }, - "node_modules/mdast-util-gfm-footnote/node_modules/micromark-util-subtokenize": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-subtokenize/-/micromark-util-subtokenize-2.0.1.tgz", - "integrity": "sha512-jZNtiFl/1aY73yS3UGQkutD0UbhTt68qnRpw2Pifmz5wV9h8gOVsN70v+Lq/f1rKaU/W8pxRe8y8Q9FX1AOe1Q==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "devlop": "^1.0.0", - "micromark-util-chunked": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/mdast-util-gfm-footnote/node_modules/micromark-util-symbol": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", - "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ] - }, - "node_modules/mdast-util-gfm-footnote/node_modules/micromark-util-types": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-2.0.0.tgz", - "integrity": "sha512-oNh6S2WMHWRZrmutsRmDDfkzKtxF+bc2VxLC9dvtrDIRFln627VsFP6fLMgTryGDljgLPjkrzQSDcPrjPyDJ5w==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ] - }, - "node_modules/mdast-util-gfm-footnote/node_modules/unist-util-stringify-position": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-4.0.0.tgz", - "integrity": "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==", - "dependencies": { - "@types/unist": "^3.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/mdast-util-gfm-strikethrough": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/mdast-util-gfm-strikethrough/-/mdast-util-gfm-strikethrough-2.0.0.tgz", - "integrity": "sha512-mKKb915TF+OC5ptj5bJ7WFRPdYtuHv0yTRxK2tJvi+BDqbkiG7h7u/9SI89nRAYcmap2xHQL9D+QG/6wSrTtXg==", - "dependencies": { - "@types/mdast": "^4.0.0", - "mdast-util-from-markdown": "^2.0.0", - "mdast-util-to-markdown": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/mdast-util-gfm-strikethrough/node_modules/@types/mdast": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-4.0.4.tgz", - "integrity": "sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==", - "dependencies": { - "@types/unist": "*" - } - }, - "node_modules/mdast-util-gfm-strikethrough/node_modules/@types/unist": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", - "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==" - }, - "node_modules/mdast-util-gfm-strikethrough/node_modules/mdast-util-from-markdown": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/mdast-util-from-markdown/-/mdast-util-from-markdown-2.0.1.tgz", - "integrity": "sha512-aJEUyzZ6TzlsX2s5B4Of7lN7EQtAxvtradMMglCQDyaTFgse6CmtmdJ15ElnVRlCg1vpNyVtbem0PWzlNieZsA==", - "dependencies": { - "@types/mdast": "^4.0.0", - "@types/unist": "^3.0.0", - "decode-named-character-reference": "^1.0.0", - "devlop": "^1.0.0", - "mdast-util-to-string": "^4.0.0", - "micromark": "^4.0.0", - "micromark-util-decode-numeric-character-reference": "^2.0.0", - "micromark-util-decode-string": "^2.0.0", - "micromark-util-normalize-identifier": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0", - "unist-util-stringify-position": "^4.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/mdast-util-gfm-strikethrough/node_modules/mdast-util-to-string": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-4.0.0.tgz", - "integrity": "sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg==", - "dependencies": { - "@types/mdast": "^4.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/mdast-util-gfm-strikethrough/node_modules/micromark": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/micromark/-/micromark-4.0.0.tgz", - "integrity": "sha512-o/sd0nMof8kYff+TqcDx3VSrgBTcZpSvYcAHIfHhv5VAuNmisCxjhx6YmxS8PFEpb9z5WKWKPdzf0jM23ro3RQ==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "@types/debug": "^4.0.0", - "debug": "^4.0.0", - "decode-named-character-reference": "^1.0.0", - "devlop": "^1.0.0", - "micromark-core-commonmark": "^2.0.0", - "micromark-factory-space": "^2.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-chunked": "^2.0.0", - "micromark-util-combine-extensions": "^2.0.0", - "micromark-util-decode-numeric-character-reference": "^2.0.0", - "micromark-util-encode": "^2.0.0", - "micromark-util-normalize-identifier": "^2.0.0", - "micromark-util-resolve-all": "^2.0.0", - "micromark-util-sanitize-uri": "^2.0.0", - "micromark-util-subtokenize": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/mdast-util-gfm-strikethrough/node_modules/micromark-core-commonmark": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-core-commonmark/-/micromark-core-commonmark-2.0.1.tgz", - "integrity": "sha512-CUQyKr1e///ZODyD1U3xit6zXwy1a8q2a1S1HKtIlmgvurrEpaw/Y9y6KSIbF8P59cn/NjzHyO+Q2fAyYLQrAA==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "decode-named-character-reference": "^1.0.0", - "devlop": "^1.0.0", - "micromark-factory-destination": "^2.0.0", - "micromark-factory-label": "^2.0.0", - "micromark-factory-space": "^2.0.0", - "micromark-factory-title": "^2.0.0", - "micromark-factory-whitespace": "^2.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-chunked": "^2.0.0", - "micromark-util-classify-character": "^2.0.0", - "micromark-util-html-tag-name": "^2.0.0", - "micromark-util-normalize-identifier": "^2.0.0", - "micromark-util-resolve-all": "^2.0.0", - "micromark-util-subtokenize": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/mdast-util-gfm-strikethrough/node_modules/micromark-factory-destination": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-factory-destination/-/micromark-factory-destination-2.0.0.tgz", - "integrity": "sha512-j9DGrQLm/Uhl2tCzcbLhy5kXsgkHUrjJHg4fFAeoMRwJmJerT9aw4FEhIbZStWN8A3qMwOp1uzHr4UL8AInxtA==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-util-character": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/mdast-util-gfm-strikethrough/node_modules/micromark-factory-label": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-factory-label/-/micromark-factory-label-2.0.0.tgz", - "integrity": "sha512-RR3i96ohZGde//4WSe/dJsxOX6vxIg9TimLAS3i4EhBAFx8Sm5SmqVfR8E87DPSR31nEAjZfbt91OMZWcNgdZw==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "devlop": "^1.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/mdast-util-gfm-strikethrough/node_modules/micromark-factory-space": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.0.tgz", - "integrity": "sha512-TKr+LIDX2pkBJXFLzpyPyljzYK3MtmllMUMODTQJIUfDGncESaqB90db9IAUcz4AZAJFdd8U9zOp9ty1458rxg==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-util-character": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/mdast-util-gfm-strikethrough/node_modules/micromark-factory-title": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-factory-title/-/micromark-factory-title-2.0.0.tgz", - "integrity": "sha512-jY8CSxmpWLOxS+t8W+FG3Xigc0RDQA9bKMY/EwILvsesiRniiVMejYTE4wumNc2f4UbAa4WsHqe3J1QS1sli+A==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-factory-space": "^2.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/mdast-util-gfm-strikethrough/node_modules/micromark-factory-whitespace": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-factory-whitespace/-/micromark-factory-whitespace-2.0.0.tgz", - "integrity": "sha512-28kbwaBjc5yAI1XadbdPYHX/eDnqaUFVikLwrO7FDnKG7lpgxnvk/XGRhX/PN0mOZ+dBSZ+LgunHS+6tYQAzhA==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-factory-space": "^2.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/mdast-util-gfm-strikethrough/node_modules/micromark-util-character": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.0.tgz", - "integrity": "sha512-KvOVV+X1yLBfs9dCBSopq/+G1PcgT3lAK07mC4BzXi5E7ahzMAF8oIupDDJ6mievI6F+lAATkbQQlQixJfT3aQ==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/mdast-util-gfm-strikethrough/node_modules/micromark-util-chunked": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-chunked/-/micromark-util-chunked-2.0.0.tgz", - "integrity": "sha512-anK8SWmNphkXdaKgz5hJvGa7l00qmcaUQoMYsBwDlSKFKjc6gjGXPDw3FNL3Nbwq5L8gE+RCbGqTw49FK5Qyvg==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-util-symbol": "^2.0.0" - } - }, - "node_modules/mdast-util-gfm-strikethrough/node_modules/micromark-util-classify-character": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-classify-character/-/micromark-util-classify-character-2.0.0.tgz", - "integrity": "sha512-S0ze2R9GH+fu41FA7pbSqNWObo/kzwf8rN/+IGlW/4tC6oACOs8B++bh+i9bVyNnwCcuksbFwsBme5OCKXCwIw==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-util-character": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/mdast-util-gfm-strikethrough/node_modules/micromark-util-combine-extensions": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-combine-extensions/-/micromark-util-combine-extensions-2.0.0.tgz", - "integrity": "sha512-vZZio48k7ON0fVS3CUgFatWHoKbbLTK/rT7pzpJ4Bjp5JjkZeasRfrS9wsBdDJK2cJLHMckXZdzPSSr1B8a4oQ==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-util-chunked": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/mdast-util-gfm-strikethrough/node_modules/micromark-util-decode-numeric-character-reference": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-decode-numeric-character-reference/-/micromark-util-decode-numeric-character-reference-2.0.1.tgz", - "integrity": "sha512-bmkNc7z8Wn6kgjZmVHOX3SowGmVdhYS7yBpMnuMnPzDq/6xwVA604DuOXMZTO1lvq01g+Adfa0pE2UKGlxL1XQ==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-util-symbol": "^2.0.0" - } - }, - "node_modules/mdast-util-gfm-strikethrough/node_modules/micromark-util-decode-string": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-decode-string/-/micromark-util-decode-string-2.0.0.tgz", - "integrity": "sha512-r4Sc6leeUTn3P6gk20aFMj2ntPwn6qpDZqWvYmAG6NgvFTIlj4WtrAudLi65qYoaGdXYViXYw2pkmn7QnIFasA==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "decode-named-character-reference": "^1.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-decode-numeric-character-reference": "^2.0.0", - "micromark-util-symbol": "^2.0.0" - } - }, - "node_modules/mdast-util-gfm-strikethrough/node_modules/micromark-util-encode": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-encode/-/micromark-util-encode-2.0.0.tgz", - "integrity": "sha512-pS+ROfCXAGLWCOc8egcBvT0kf27GoWMqtdarNfDcjb6YLuV5cM3ioG45Ys2qOVqeqSbjaKg72vU+Wby3eddPsA==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ] - }, - "node_modules/mdast-util-gfm-strikethrough/node_modules/micromark-util-html-tag-name": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-html-tag-name/-/micromark-util-html-tag-name-2.0.0.tgz", - "integrity": "sha512-xNn4Pqkj2puRhKdKTm8t1YHC/BAjx6CEwRFXntTaRf/x16aqka6ouVoutm+QdkISTlT7e2zU7U4ZdlDLJd2Mcw==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ] - }, - "node_modules/mdast-util-gfm-strikethrough/node_modules/micromark-util-normalize-identifier": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-normalize-identifier/-/micromark-util-normalize-identifier-2.0.0.tgz", - "integrity": "sha512-2xhYT0sfo85FMrUPtHcPo2rrp1lwbDEEzpx7jiH2xXJLqBuy4H0GgXk5ToU8IEwoROtXuL8ND0ttVa4rNqYK3w==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-util-symbol": "^2.0.0" - } - }, - "node_modules/mdast-util-gfm-strikethrough/node_modules/micromark-util-resolve-all": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-resolve-all/-/micromark-util-resolve-all-2.0.0.tgz", - "integrity": "sha512-6KU6qO7DZ7GJkaCgwBNtplXCvGkJToU86ybBAUdavvgsCiG8lSSvYxr9MhwmQ+udpzywHsl4RpGJsYWG1pDOcA==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/mdast-util-gfm-strikethrough/node_modules/micromark-util-sanitize-uri": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-2.0.0.tgz", - "integrity": "sha512-WhYv5UEcZrbAtlsnPuChHUAsu/iBPOVaEVsntLBIdpibO0ddy8OzavZz3iL2xVvBZOpolujSliP65Kq0/7KIYw==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-util-character": "^2.0.0", - "micromark-util-encode": "^2.0.0", - "micromark-util-symbol": "^2.0.0" - } - }, - "node_modules/mdast-util-gfm-strikethrough/node_modules/micromark-util-subtokenize": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-subtokenize/-/micromark-util-subtokenize-2.0.1.tgz", - "integrity": "sha512-jZNtiFl/1aY73yS3UGQkutD0UbhTt68qnRpw2Pifmz5wV9h8gOVsN70v+Lq/f1rKaU/W8pxRe8y8Q9FX1AOe1Q==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "devlop": "^1.0.0", - "micromark-util-chunked": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/mdast-util-gfm-strikethrough/node_modules/micromark-util-symbol": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", - "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ] - }, - "node_modules/mdast-util-gfm-strikethrough/node_modules/micromark-util-types": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-2.0.0.tgz", - "integrity": "sha512-oNh6S2WMHWRZrmutsRmDDfkzKtxF+bc2VxLC9dvtrDIRFln627VsFP6fLMgTryGDljgLPjkrzQSDcPrjPyDJ5w==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ] - }, - "node_modules/mdast-util-gfm-strikethrough/node_modules/unist-util-stringify-position": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-4.0.0.tgz", - "integrity": "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==", - "dependencies": { - "@types/unist": "^3.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/mdast-util-gfm-table": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/mdast-util-gfm-table/-/mdast-util-gfm-table-2.0.0.tgz", - "integrity": "sha512-78UEvebzz/rJIxLvE7ZtDd/vIQ0RHv+3Mh5DR96p7cS7HsBhYIICDBCu8csTNWNO6tBWfqXPWekRuj2FNOGOZg==", - "dependencies": { - "@types/mdast": "^4.0.0", - "devlop": "^1.0.0", - "markdown-table": "^3.0.0", - "mdast-util-from-markdown": "^2.0.0", - "mdast-util-to-markdown": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/mdast-util-gfm-table/node_modules/@types/mdast": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-4.0.4.tgz", - "integrity": "sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==", - "dependencies": { - "@types/unist": "*" - } - }, - "node_modules/mdast-util-gfm-table/node_modules/@types/unist": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", - "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==" - }, - "node_modules/mdast-util-gfm-table/node_modules/mdast-util-from-markdown": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/mdast-util-from-markdown/-/mdast-util-from-markdown-2.0.1.tgz", - "integrity": "sha512-aJEUyzZ6TzlsX2s5B4Of7lN7EQtAxvtradMMglCQDyaTFgse6CmtmdJ15ElnVRlCg1vpNyVtbem0PWzlNieZsA==", - "dependencies": { - "@types/mdast": "^4.0.0", - "@types/unist": "^3.0.0", - "decode-named-character-reference": "^1.0.0", - "devlop": "^1.0.0", - "mdast-util-to-string": "^4.0.0", - "micromark": "^4.0.0", - "micromark-util-decode-numeric-character-reference": "^2.0.0", - "micromark-util-decode-string": "^2.0.0", - "micromark-util-normalize-identifier": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0", - "unist-util-stringify-position": "^4.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/mdast-util-gfm-table/node_modules/mdast-util-to-string": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-4.0.0.tgz", - "integrity": "sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg==", - "dependencies": { - "@types/mdast": "^4.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/mdast-util-gfm-table/node_modules/micromark": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/micromark/-/micromark-4.0.0.tgz", - "integrity": "sha512-o/sd0nMof8kYff+TqcDx3VSrgBTcZpSvYcAHIfHhv5VAuNmisCxjhx6YmxS8PFEpb9z5WKWKPdzf0jM23ro3RQ==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "@types/debug": "^4.0.0", - "debug": "^4.0.0", - "decode-named-character-reference": "^1.0.0", - "devlop": "^1.0.0", - "micromark-core-commonmark": "^2.0.0", - "micromark-factory-space": "^2.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-chunked": "^2.0.0", - "micromark-util-combine-extensions": "^2.0.0", - "micromark-util-decode-numeric-character-reference": "^2.0.0", - "micromark-util-encode": "^2.0.0", - "micromark-util-normalize-identifier": "^2.0.0", - "micromark-util-resolve-all": "^2.0.0", - "micromark-util-sanitize-uri": "^2.0.0", - "micromark-util-subtokenize": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/mdast-util-gfm-table/node_modules/micromark-core-commonmark": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-core-commonmark/-/micromark-core-commonmark-2.0.1.tgz", - "integrity": "sha512-CUQyKr1e///ZODyD1U3xit6zXwy1a8q2a1S1HKtIlmgvurrEpaw/Y9y6KSIbF8P59cn/NjzHyO+Q2fAyYLQrAA==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "decode-named-character-reference": "^1.0.0", - "devlop": "^1.0.0", - "micromark-factory-destination": "^2.0.0", - "micromark-factory-label": "^2.0.0", - "micromark-factory-space": "^2.0.0", - "micromark-factory-title": "^2.0.0", - "micromark-factory-whitespace": "^2.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-chunked": "^2.0.0", - "micromark-util-classify-character": "^2.0.0", - "micromark-util-html-tag-name": "^2.0.0", - "micromark-util-normalize-identifier": "^2.0.0", - "micromark-util-resolve-all": "^2.0.0", - "micromark-util-subtokenize": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/mdast-util-gfm-table/node_modules/micromark-factory-destination": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-factory-destination/-/micromark-factory-destination-2.0.0.tgz", - "integrity": "sha512-j9DGrQLm/Uhl2tCzcbLhy5kXsgkHUrjJHg4fFAeoMRwJmJerT9aw4FEhIbZStWN8A3qMwOp1uzHr4UL8AInxtA==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-util-character": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/mdast-util-gfm-table/node_modules/micromark-factory-label": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-factory-label/-/micromark-factory-label-2.0.0.tgz", - "integrity": "sha512-RR3i96ohZGde//4WSe/dJsxOX6vxIg9TimLAS3i4EhBAFx8Sm5SmqVfR8E87DPSR31nEAjZfbt91OMZWcNgdZw==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "devlop": "^1.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/mdast-util-gfm-table/node_modules/micromark-factory-space": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.0.tgz", - "integrity": "sha512-TKr+LIDX2pkBJXFLzpyPyljzYK3MtmllMUMODTQJIUfDGncESaqB90db9IAUcz4AZAJFdd8U9zOp9ty1458rxg==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-util-character": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/mdast-util-gfm-table/node_modules/micromark-factory-title": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-factory-title/-/micromark-factory-title-2.0.0.tgz", - "integrity": "sha512-jY8CSxmpWLOxS+t8W+FG3Xigc0RDQA9bKMY/EwILvsesiRniiVMejYTE4wumNc2f4UbAa4WsHqe3J1QS1sli+A==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-factory-space": "^2.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/mdast-util-gfm-table/node_modules/micromark-factory-whitespace": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-factory-whitespace/-/micromark-factory-whitespace-2.0.0.tgz", - "integrity": "sha512-28kbwaBjc5yAI1XadbdPYHX/eDnqaUFVikLwrO7FDnKG7lpgxnvk/XGRhX/PN0mOZ+dBSZ+LgunHS+6tYQAzhA==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-factory-space": "^2.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/mdast-util-gfm-table/node_modules/micromark-util-character": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.0.tgz", - "integrity": "sha512-KvOVV+X1yLBfs9dCBSopq/+G1PcgT3lAK07mC4BzXi5E7ahzMAF8oIupDDJ6mievI6F+lAATkbQQlQixJfT3aQ==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/mdast-util-gfm-table/node_modules/micromark-util-chunked": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-chunked/-/micromark-util-chunked-2.0.0.tgz", - "integrity": "sha512-anK8SWmNphkXdaKgz5hJvGa7l00qmcaUQoMYsBwDlSKFKjc6gjGXPDw3FNL3Nbwq5L8gE+RCbGqTw49FK5Qyvg==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-util-symbol": "^2.0.0" - } - }, - "node_modules/mdast-util-gfm-table/node_modules/micromark-util-classify-character": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-classify-character/-/micromark-util-classify-character-2.0.0.tgz", - "integrity": "sha512-S0ze2R9GH+fu41FA7pbSqNWObo/kzwf8rN/+IGlW/4tC6oACOs8B++bh+i9bVyNnwCcuksbFwsBme5OCKXCwIw==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-util-character": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/mdast-util-gfm-table/node_modules/micromark-util-combine-extensions": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-combine-extensions/-/micromark-util-combine-extensions-2.0.0.tgz", - "integrity": "sha512-vZZio48k7ON0fVS3CUgFatWHoKbbLTK/rT7pzpJ4Bjp5JjkZeasRfrS9wsBdDJK2cJLHMckXZdzPSSr1B8a4oQ==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-util-chunked": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/mdast-util-gfm-table/node_modules/micromark-util-decode-numeric-character-reference": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-decode-numeric-character-reference/-/micromark-util-decode-numeric-character-reference-2.0.1.tgz", - "integrity": "sha512-bmkNc7z8Wn6kgjZmVHOX3SowGmVdhYS7yBpMnuMnPzDq/6xwVA604DuOXMZTO1lvq01g+Adfa0pE2UKGlxL1XQ==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-util-symbol": "^2.0.0" - } - }, - "node_modules/mdast-util-gfm-table/node_modules/micromark-util-decode-string": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-decode-string/-/micromark-util-decode-string-2.0.0.tgz", - "integrity": "sha512-r4Sc6leeUTn3P6gk20aFMj2ntPwn6qpDZqWvYmAG6NgvFTIlj4WtrAudLi65qYoaGdXYViXYw2pkmn7QnIFasA==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "decode-named-character-reference": "^1.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-decode-numeric-character-reference": "^2.0.0", - "micromark-util-symbol": "^2.0.0" - } - }, - "node_modules/mdast-util-gfm-table/node_modules/micromark-util-encode": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-encode/-/micromark-util-encode-2.0.0.tgz", - "integrity": "sha512-pS+ROfCXAGLWCOc8egcBvT0kf27GoWMqtdarNfDcjb6YLuV5cM3ioG45Ys2qOVqeqSbjaKg72vU+Wby3eddPsA==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ] - }, - "node_modules/mdast-util-gfm-table/node_modules/micromark-util-html-tag-name": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-html-tag-name/-/micromark-util-html-tag-name-2.0.0.tgz", - "integrity": "sha512-xNn4Pqkj2puRhKdKTm8t1YHC/BAjx6CEwRFXntTaRf/x16aqka6ouVoutm+QdkISTlT7e2zU7U4ZdlDLJd2Mcw==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ] - }, - "node_modules/mdast-util-gfm-table/node_modules/micromark-util-normalize-identifier": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-normalize-identifier/-/micromark-util-normalize-identifier-2.0.0.tgz", - "integrity": "sha512-2xhYT0sfo85FMrUPtHcPo2rrp1lwbDEEzpx7jiH2xXJLqBuy4H0GgXk5ToU8IEwoROtXuL8ND0ttVa4rNqYK3w==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-util-symbol": "^2.0.0" - } - }, - "node_modules/mdast-util-gfm-table/node_modules/micromark-util-resolve-all": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-resolve-all/-/micromark-util-resolve-all-2.0.0.tgz", - "integrity": "sha512-6KU6qO7DZ7GJkaCgwBNtplXCvGkJToU86ybBAUdavvgsCiG8lSSvYxr9MhwmQ+udpzywHsl4RpGJsYWG1pDOcA==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/mdast-util-gfm-table/node_modules/micromark-util-sanitize-uri": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-2.0.0.tgz", - "integrity": "sha512-WhYv5UEcZrbAtlsnPuChHUAsu/iBPOVaEVsntLBIdpibO0ddy8OzavZz3iL2xVvBZOpolujSliP65Kq0/7KIYw==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-util-character": "^2.0.0", - "micromark-util-encode": "^2.0.0", - "micromark-util-symbol": "^2.0.0" - } - }, - "node_modules/mdast-util-gfm-table/node_modules/micromark-util-subtokenize": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-subtokenize/-/micromark-util-subtokenize-2.0.1.tgz", - "integrity": "sha512-jZNtiFl/1aY73yS3UGQkutD0UbhTt68qnRpw2Pifmz5wV9h8gOVsN70v+Lq/f1rKaU/W8pxRe8y8Q9FX1AOe1Q==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "devlop": "^1.0.0", - "micromark-util-chunked": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/mdast-util-gfm-table/node_modules/micromark-util-symbol": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", - "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ] - }, - "node_modules/mdast-util-gfm-table/node_modules/micromark-util-types": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-2.0.0.tgz", - "integrity": "sha512-oNh6S2WMHWRZrmutsRmDDfkzKtxF+bc2VxLC9dvtrDIRFln627VsFP6fLMgTryGDljgLPjkrzQSDcPrjPyDJ5w==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ] - }, - "node_modules/mdast-util-gfm-table/node_modules/unist-util-stringify-position": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-4.0.0.tgz", - "integrity": "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==", - "dependencies": { - "@types/unist": "^3.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/mdast-util-gfm-task-list-item": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/mdast-util-gfm-task-list-item/-/mdast-util-gfm-task-list-item-2.0.0.tgz", - "integrity": "sha512-IrtvNvjxC1o06taBAVJznEnkiHxLFTzgonUdy8hzFVeDun0uTjxxrRGVaNFqkU1wJR3RBPEfsxmU6jDWPofrTQ==", - "dependencies": { - "@types/mdast": "^4.0.0", - "devlop": "^1.0.0", - "mdast-util-from-markdown": "^2.0.0", - "mdast-util-to-markdown": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/mdast-util-gfm-task-list-item/node_modules/@types/mdast": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-4.0.4.tgz", - "integrity": "sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==", - "dependencies": { - "@types/unist": "*" - } - }, - "node_modules/mdast-util-gfm-task-list-item/node_modules/@types/unist": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", - "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==" - }, - "node_modules/mdast-util-gfm-task-list-item/node_modules/mdast-util-from-markdown": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/mdast-util-from-markdown/-/mdast-util-from-markdown-2.0.1.tgz", - "integrity": "sha512-aJEUyzZ6TzlsX2s5B4Of7lN7EQtAxvtradMMglCQDyaTFgse6CmtmdJ15ElnVRlCg1vpNyVtbem0PWzlNieZsA==", - "dependencies": { - "@types/mdast": "^4.0.0", - "@types/unist": "^3.0.0", - "decode-named-character-reference": "^1.0.0", - "devlop": "^1.0.0", - "mdast-util-to-string": "^4.0.0", - "micromark": "^4.0.0", - "micromark-util-decode-numeric-character-reference": "^2.0.0", - "micromark-util-decode-string": "^2.0.0", - "micromark-util-normalize-identifier": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0", - "unist-util-stringify-position": "^4.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/mdast-util-gfm-task-list-item/node_modules/mdast-util-to-string": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-4.0.0.tgz", - "integrity": "sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg==", - "dependencies": { - "@types/mdast": "^4.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/mdast-util-gfm-task-list-item/node_modules/micromark": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/micromark/-/micromark-4.0.0.tgz", - "integrity": "sha512-o/sd0nMof8kYff+TqcDx3VSrgBTcZpSvYcAHIfHhv5VAuNmisCxjhx6YmxS8PFEpb9z5WKWKPdzf0jM23ro3RQ==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "@types/debug": "^4.0.0", - "debug": "^4.0.0", - "decode-named-character-reference": "^1.0.0", - "devlop": "^1.0.0", - "micromark-core-commonmark": "^2.0.0", - "micromark-factory-space": "^2.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-chunked": "^2.0.0", - "micromark-util-combine-extensions": "^2.0.0", - "micromark-util-decode-numeric-character-reference": "^2.0.0", - "micromark-util-encode": "^2.0.0", - "micromark-util-normalize-identifier": "^2.0.0", - "micromark-util-resolve-all": "^2.0.0", - "micromark-util-sanitize-uri": "^2.0.0", - "micromark-util-subtokenize": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/mdast-util-gfm-task-list-item/node_modules/micromark-core-commonmark": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-core-commonmark/-/micromark-core-commonmark-2.0.1.tgz", - "integrity": "sha512-CUQyKr1e///ZODyD1U3xit6zXwy1a8q2a1S1HKtIlmgvurrEpaw/Y9y6KSIbF8P59cn/NjzHyO+Q2fAyYLQrAA==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "decode-named-character-reference": "^1.0.0", - "devlop": "^1.0.0", - "micromark-factory-destination": "^2.0.0", - "micromark-factory-label": "^2.0.0", - "micromark-factory-space": "^2.0.0", - "micromark-factory-title": "^2.0.0", - "micromark-factory-whitespace": "^2.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-chunked": "^2.0.0", - "micromark-util-classify-character": "^2.0.0", - "micromark-util-html-tag-name": "^2.0.0", - "micromark-util-normalize-identifier": "^2.0.0", - "micromark-util-resolve-all": "^2.0.0", - "micromark-util-subtokenize": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/mdast-util-gfm-task-list-item/node_modules/micromark-factory-destination": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-factory-destination/-/micromark-factory-destination-2.0.0.tgz", - "integrity": "sha512-j9DGrQLm/Uhl2tCzcbLhy5kXsgkHUrjJHg4fFAeoMRwJmJerT9aw4FEhIbZStWN8A3qMwOp1uzHr4UL8AInxtA==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-util-character": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/mdast-util-gfm-task-list-item/node_modules/micromark-factory-label": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-factory-label/-/micromark-factory-label-2.0.0.tgz", - "integrity": "sha512-RR3i96ohZGde//4WSe/dJsxOX6vxIg9TimLAS3i4EhBAFx8Sm5SmqVfR8E87DPSR31nEAjZfbt91OMZWcNgdZw==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "devlop": "^1.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/mdast-util-gfm-task-list-item/node_modules/micromark-factory-space": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.0.tgz", - "integrity": "sha512-TKr+LIDX2pkBJXFLzpyPyljzYK3MtmllMUMODTQJIUfDGncESaqB90db9IAUcz4AZAJFdd8U9zOp9ty1458rxg==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-util-character": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/mdast-util-gfm-task-list-item/node_modules/micromark-factory-title": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-factory-title/-/micromark-factory-title-2.0.0.tgz", - "integrity": "sha512-jY8CSxmpWLOxS+t8W+FG3Xigc0RDQA9bKMY/EwILvsesiRniiVMejYTE4wumNc2f4UbAa4WsHqe3J1QS1sli+A==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-factory-space": "^2.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/mdast-util-gfm-task-list-item/node_modules/micromark-factory-whitespace": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-factory-whitespace/-/micromark-factory-whitespace-2.0.0.tgz", - "integrity": "sha512-28kbwaBjc5yAI1XadbdPYHX/eDnqaUFVikLwrO7FDnKG7lpgxnvk/XGRhX/PN0mOZ+dBSZ+LgunHS+6tYQAzhA==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-factory-space": "^2.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/mdast-util-gfm-task-list-item/node_modules/micromark-util-character": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.0.tgz", - "integrity": "sha512-KvOVV+X1yLBfs9dCBSopq/+G1PcgT3lAK07mC4BzXi5E7ahzMAF8oIupDDJ6mievI6F+lAATkbQQlQixJfT3aQ==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/mdast-util-gfm-task-list-item/node_modules/micromark-util-chunked": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-chunked/-/micromark-util-chunked-2.0.0.tgz", - "integrity": "sha512-anK8SWmNphkXdaKgz5hJvGa7l00qmcaUQoMYsBwDlSKFKjc6gjGXPDw3FNL3Nbwq5L8gE+RCbGqTw49FK5Qyvg==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-util-symbol": "^2.0.0" - } - }, - "node_modules/mdast-util-gfm-task-list-item/node_modules/micromark-util-classify-character": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-classify-character/-/micromark-util-classify-character-2.0.0.tgz", - "integrity": "sha512-S0ze2R9GH+fu41FA7pbSqNWObo/kzwf8rN/+IGlW/4tC6oACOs8B++bh+i9bVyNnwCcuksbFwsBme5OCKXCwIw==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-util-character": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/mdast-util-gfm-task-list-item/node_modules/micromark-util-combine-extensions": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-combine-extensions/-/micromark-util-combine-extensions-2.0.0.tgz", - "integrity": "sha512-vZZio48k7ON0fVS3CUgFatWHoKbbLTK/rT7pzpJ4Bjp5JjkZeasRfrS9wsBdDJK2cJLHMckXZdzPSSr1B8a4oQ==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-util-chunked": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/mdast-util-gfm-task-list-item/node_modules/micromark-util-decode-numeric-character-reference": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-decode-numeric-character-reference/-/micromark-util-decode-numeric-character-reference-2.0.1.tgz", - "integrity": "sha512-bmkNc7z8Wn6kgjZmVHOX3SowGmVdhYS7yBpMnuMnPzDq/6xwVA604DuOXMZTO1lvq01g+Adfa0pE2UKGlxL1XQ==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-util-symbol": "^2.0.0" - } - }, - "node_modules/mdast-util-gfm-task-list-item/node_modules/micromark-util-decode-string": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-decode-string/-/micromark-util-decode-string-2.0.0.tgz", - "integrity": "sha512-r4Sc6leeUTn3P6gk20aFMj2ntPwn6qpDZqWvYmAG6NgvFTIlj4WtrAudLi65qYoaGdXYViXYw2pkmn7QnIFasA==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "decode-named-character-reference": "^1.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-decode-numeric-character-reference": "^2.0.0", - "micromark-util-symbol": "^2.0.0" - } - }, - "node_modules/mdast-util-gfm-task-list-item/node_modules/micromark-util-encode": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-encode/-/micromark-util-encode-2.0.0.tgz", - "integrity": "sha512-pS+ROfCXAGLWCOc8egcBvT0kf27GoWMqtdarNfDcjb6YLuV5cM3ioG45Ys2qOVqeqSbjaKg72vU+Wby3eddPsA==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ] - }, - "node_modules/mdast-util-gfm-task-list-item/node_modules/micromark-util-html-tag-name": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-html-tag-name/-/micromark-util-html-tag-name-2.0.0.tgz", - "integrity": "sha512-xNn4Pqkj2puRhKdKTm8t1YHC/BAjx6CEwRFXntTaRf/x16aqka6ouVoutm+QdkISTlT7e2zU7U4ZdlDLJd2Mcw==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ] - }, - "node_modules/mdast-util-gfm-task-list-item/node_modules/micromark-util-normalize-identifier": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-normalize-identifier/-/micromark-util-normalize-identifier-2.0.0.tgz", - "integrity": "sha512-2xhYT0sfo85FMrUPtHcPo2rrp1lwbDEEzpx7jiH2xXJLqBuy4H0GgXk5ToU8IEwoROtXuL8ND0ttVa4rNqYK3w==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-util-symbol": "^2.0.0" - } - }, - "node_modules/mdast-util-gfm-task-list-item/node_modules/micromark-util-resolve-all": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-resolve-all/-/micromark-util-resolve-all-2.0.0.tgz", - "integrity": "sha512-6KU6qO7DZ7GJkaCgwBNtplXCvGkJToU86ybBAUdavvgsCiG8lSSvYxr9MhwmQ+udpzywHsl4RpGJsYWG1pDOcA==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/mdast-util-gfm-task-list-item/node_modules/micromark-util-sanitize-uri": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-2.0.0.tgz", - "integrity": "sha512-WhYv5UEcZrbAtlsnPuChHUAsu/iBPOVaEVsntLBIdpibO0ddy8OzavZz3iL2xVvBZOpolujSliP65Kq0/7KIYw==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-util-character": "^2.0.0", - "micromark-util-encode": "^2.0.0", - "micromark-util-symbol": "^2.0.0" - } - }, - "node_modules/mdast-util-gfm-task-list-item/node_modules/micromark-util-subtokenize": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-subtokenize/-/micromark-util-subtokenize-2.0.1.tgz", - "integrity": "sha512-jZNtiFl/1aY73yS3UGQkutD0UbhTt68qnRpw2Pifmz5wV9h8gOVsN70v+Lq/f1rKaU/W8pxRe8y8Q9FX1AOe1Q==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "devlop": "^1.0.0", - "micromark-util-chunked": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/mdast-util-gfm-task-list-item/node_modules/micromark-util-symbol": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", - "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ] - }, - "node_modules/mdast-util-gfm-task-list-item/node_modules/micromark-util-types": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-2.0.0.tgz", - "integrity": "sha512-oNh6S2WMHWRZrmutsRmDDfkzKtxF+bc2VxLC9dvtrDIRFln627VsFP6fLMgTryGDljgLPjkrzQSDcPrjPyDJ5w==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ] - }, - "node_modules/mdast-util-gfm-task-list-item/node_modules/unist-util-stringify-position": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-4.0.0.tgz", - "integrity": "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==", - "dependencies": { - "@types/unist": "^3.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/mdast-util-gfm/node_modules/@types/mdast": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-4.0.4.tgz", - "integrity": "sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==", - "dependencies": { - "@types/unist": "*" - } - }, - "node_modules/mdast-util-gfm/node_modules/@types/unist": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", - "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==" - }, - "node_modules/mdast-util-gfm/node_modules/mdast-util-from-markdown": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/mdast-util-from-markdown/-/mdast-util-from-markdown-2.0.1.tgz", - "integrity": "sha512-aJEUyzZ6TzlsX2s5B4Of7lN7EQtAxvtradMMglCQDyaTFgse6CmtmdJ15ElnVRlCg1vpNyVtbem0PWzlNieZsA==", - "dependencies": { - "@types/mdast": "^4.0.0", - "@types/unist": "^3.0.0", - "decode-named-character-reference": "^1.0.0", - "devlop": "^1.0.0", - "mdast-util-to-string": "^4.0.0", - "micromark": "^4.0.0", - "micromark-util-decode-numeric-character-reference": "^2.0.0", - "micromark-util-decode-string": "^2.0.0", - "micromark-util-normalize-identifier": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0", - "unist-util-stringify-position": "^4.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/mdast-util-gfm/node_modules/mdast-util-to-string": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-4.0.0.tgz", - "integrity": "sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg==", - "dependencies": { - "@types/mdast": "^4.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/mdast-util-gfm/node_modules/micromark": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/micromark/-/micromark-4.0.0.tgz", - "integrity": "sha512-o/sd0nMof8kYff+TqcDx3VSrgBTcZpSvYcAHIfHhv5VAuNmisCxjhx6YmxS8PFEpb9z5WKWKPdzf0jM23ro3RQ==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "@types/debug": "^4.0.0", - "debug": "^4.0.0", - "decode-named-character-reference": "^1.0.0", - "devlop": "^1.0.0", - "micromark-core-commonmark": "^2.0.0", - "micromark-factory-space": "^2.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-chunked": "^2.0.0", - "micromark-util-combine-extensions": "^2.0.0", - "micromark-util-decode-numeric-character-reference": "^2.0.0", - "micromark-util-encode": "^2.0.0", - "micromark-util-normalize-identifier": "^2.0.0", - "micromark-util-resolve-all": "^2.0.0", - "micromark-util-sanitize-uri": "^2.0.0", - "micromark-util-subtokenize": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/mdast-util-gfm/node_modules/micromark-core-commonmark": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-core-commonmark/-/micromark-core-commonmark-2.0.1.tgz", - "integrity": "sha512-CUQyKr1e///ZODyD1U3xit6zXwy1a8q2a1S1HKtIlmgvurrEpaw/Y9y6KSIbF8P59cn/NjzHyO+Q2fAyYLQrAA==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "decode-named-character-reference": "^1.0.0", - "devlop": "^1.0.0", - "micromark-factory-destination": "^2.0.0", - "micromark-factory-label": "^2.0.0", - "micromark-factory-space": "^2.0.0", - "micromark-factory-title": "^2.0.0", - "micromark-factory-whitespace": "^2.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-chunked": "^2.0.0", - "micromark-util-classify-character": "^2.0.0", - "micromark-util-html-tag-name": "^2.0.0", - "micromark-util-normalize-identifier": "^2.0.0", - "micromark-util-resolve-all": "^2.0.0", - "micromark-util-subtokenize": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/mdast-util-gfm/node_modules/micromark-factory-destination": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-factory-destination/-/micromark-factory-destination-2.0.0.tgz", - "integrity": "sha512-j9DGrQLm/Uhl2tCzcbLhy5kXsgkHUrjJHg4fFAeoMRwJmJerT9aw4FEhIbZStWN8A3qMwOp1uzHr4UL8AInxtA==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-util-character": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/mdast-util-gfm/node_modules/micromark-factory-label": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-factory-label/-/micromark-factory-label-2.0.0.tgz", - "integrity": "sha512-RR3i96ohZGde//4WSe/dJsxOX6vxIg9TimLAS3i4EhBAFx8Sm5SmqVfR8E87DPSR31nEAjZfbt91OMZWcNgdZw==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "devlop": "^1.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/mdast-util-gfm/node_modules/micromark-factory-space": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.0.tgz", - "integrity": "sha512-TKr+LIDX2pkBJXFLzpyPyljzYK3MtmllMUMODTQJIUfDGncESaqB90db9IAUcz4AZAJFdd8U9zOp9ty1458rxg==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-util-character": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/mdast-util-gfm/node_modules/micromark-factory-title": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-factory-title/-/micromark-factory-title-2.0.0.tgz", - "integrity": "sha512-jY8CSxmpWLOxS+t8W+FG3Xigc0RDQA9bKMY/EwILvsesiRniiVMejYTE4wumNc2f4UbAa4WsHqe3J1QS1sli+A==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-factory-space": "^2.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/mdast-util-gfm/node_modules/micromark-factory-whitespace": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-factory-whitespace/-/micromark-factory-whitespace-2.0.0.tgz", - "integrity": "sha512-28kbwaBjc5yAI1XadbdPYHX/eDnqaUFVikLwrO7FDnKG7lpgxnvk/XGRhX/PN0mOZ+dBSZ+LgunHS+6tYQAzhA==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-factory-space": "^2.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/mdast-util-gfm/node_modules/micromark-util-character": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.0.tgz", - "integrity": "sha512-KvOVV+X1yLBfs9dCBSopq/+G1PcgT3lAK07mC4BzXi5E7ahzMAF8oIupDDJ6mievI6F+lAATkbQQlQixJfT3aQ==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/mdast-util-gfm/node_modules/micromark-util-chunked": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-chunked/-/micromark-util-chunked-2.0.0.tgz", - "integrity": "sha512-anK8SWmNphkXdaKgz5hJvGa7l00qmcaUQoMYsBwDlSKFKjc6gjGXPDw3FNL3Nbwq5L8gE+RCbGqTw49FK5Qyvg==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-util-symbol": "^2.0.0" - } - }, - "node_modules/mdast-util-gfm/node_modules/micromark-util-classify-character": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-classify-character/-/micromark-util-classify-character-2.0.0.tgz", - "integrity": "sha512-S0ze2R9GH+fu41FA7pbSqNWObo/kzwf8rN/+IGlW/4tC6oACOs8B++bh+i9bVyNnwCcuksbFwsBme5OCKXCwIw==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-util-character": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/mdast-util-gfm/node_modules/micromark-util-combine-extensions": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-combine-extensions/-/micromark-util-combine-extensions-2.0.0.tgz", - "integrity": "sha512-vZZio48k7ON0fVS3CUgFatWHoKbbLTK/rT7pzpJ4Bjp5JjkZeasRfrS9wsBdDJK2cJLHMckXZdzPSSr1B8a4oQ==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-util-chunked": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/mdast-util-gfm/node_modules/micromark-util-decode-numeric-character-reference": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-decode-numeric-character-reference/-/micromark-util-decode-numeric-character-reference-2.0.1.tgz", - "integrity": "sha512-bmkNc7z8Wn6kgjZmVHOX3SowGmVdhYS7yBpMnuMnPzDq/6xwVA604DuOXMZTO1lvq01g+Adfa0pE2UKGlxL1XQ==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-util-symbol": "^2.0.0" - } - }, - "node_modules/mdast-util-gfm/node_modules/micromark-util-decode-string": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-decode-string/-/micromark-util-decode-string-2.0.0.tgz", - "integrity": "sha512-r4Sc6leeUTn3P6gk20aFMj2ntPwn6qpDZqWvYmAG6NgvFTIlj4WtrAudLi65qYoaGdXYViXYw2pkmn7QnIFasA==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "decode-named-character-reference": "^1.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-decode-numeric-character-reference": "^2.0.0", - "micromark-util-symbol": "^2.0.0" - } - }, - "node_modules/mdast-util-gfm/node_modules/micromark-util-encode": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-encode/-/micromark-util-encode-2.0.0.tgz", - "integrity": "sha512-pS+ROfCXAGLWCOc8egcBvT0kf27GoWMqtdarNfDcjb6YLuV5cM3ioG45Ys2qOVqeqSbjaKg72vU+Wby3eddPsA==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ] - }, - "node_modules/mdast-util-gfm/node_modules/micromark-util-html-tag-name": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-html-tag-name/-/micromark-util-html-tag-name-2.0.0.tgz", - "integrity": "sha512-xNn4Pqkj2puRhKdKTm8t1YHC/BAjx6CEwRFXntTaRf/x16aqka6ouVoutm+QdkISTlT7e2zU7U4ZdlDLJd2Mcw==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ] - }, - "node_modules/mdast-util-gfm/node_modules/micromark-util-normalize-identifier": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-normalize-identifier/-/micromark-util-normalize-identifier-2.0.0.tgz", - "integrity": "sha512-2xhYT0sfo85FMrUPtHcPo2rrp1lwbDEEzpx7jiH2xXJLqBuy4H0GgXk5ToU8IEwoROtXuL8ND0ttVa4rNqYK3w==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-util-symbol": "^2.0.0" - } - }, - "node_modules/mdast-util-gfm/node_modules/micromark-util-resolve-all": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-resolve-all/-/micromark-util-resolve-all-2.0.0.tgz", - "integrity": "sha512-6KU6qO7DZ7GJkaCgwBNtplXCvGkJToU86ybBAUdavvgsCiG8lSSvYxr9MhwmQ+udpzywHsl4RpGJsYWG1pDOcA==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/mdast-util-gfm/node_modules/micromark-util-sanitize-uri": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-2.0.0.tgz", - "integrity": "sha512-WhYv5UEcZrbAtlsnPuChHUAsu/iBPOVaEVsntLBIdpibO0ddy8OzavZz3iL2xVvBZOpolujSliP65Kq0/7KIYw==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-util-character": "^2.0.0", - "micromark-util-encode": "^2.0.0", - "micromark-util-symbol": "^2.0.0" - } - }, - "node_modules/mdast-util-gfm/node_modules/micromark-util-subtokenize": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-subtokenize/-/micromark-util-subtokenize-2.0.1.tgz", - "integrity": "sha512-jZNtiFl/1aY73yS3UGQkutD0UbhTt68qnRpw2Pifmz5wV9h8gOVsN70v+Lq/f1rKaU/W8pxRe8y8Q9FX1AOe1Q==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "devlop": "^1.0.0", - "micromark-util-chunked": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/mdast-util-gfm/node_modules/micromark-util-symbol": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", - "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ] - }, - "node_modules/mdast-util-gfm/node_modules/micromark-util-types": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-2.0.0.tgz", - "integrity": "sha512-oNh6S2WMHWRZrmutsRmDDfkzKtxF+bc2VxLC9dvtrDIRFln627VsFP6fLMgTryGDljgLPjkrzQSDcPrjPyDJ5w==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ] - }, - "node_modules/mdast-util-gfm/node_modules/unist-util-stringify-position": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-4.0.0.tgz", - "integrity": "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==", - "dependencies": { - "@types/unist": "^3.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/mdast-util-math": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/mdast-util-math/-/mdast-util-math-3.0.0.tgz", - "integrity": "sha512-Tl9GBNeG/AhJnQM221bJR2HPvLOSnLE/T9cJI9tlc6zwQk2nPk/4f0cHkOdEixQPC/j8UtKDdITswvLAy1OZ1w==", - "dependencies": { - "@types/hast": "^3.0.0", - "@types/mdast": "^4.0.0", - "devlop": "^1.0.0", - "longest-streak": "^3.0.0", - "mdast-util-from-markdown": "^2.0.0", - "mdast-util-to-markdown": "^2.1.0", - "unist-util-remove-position": "^5.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/mdast-util-math/node_modules/@types/mdast": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-4.0.4.tgz", - "integrity": "sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==", - "dependencies": { - "@types/unist": "*" - } - }, - "node_modules/mdast-util-math/node_modules/@types/unist": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", - "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==" - }, - "node_modules/mdast-util-math/node_modules/mdast-util-from-markdown": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/mdast-util-from-markdown/-/mdast-util-from-markdown-2.0.1.tgz", - "integrity": "sha512-aJEUyzZ6TzlsX2s5B4Of7lN7EQtAxvtradMMglCQDyaTFgse6CmtmdJ15ElnVRlCg1vpNyVtbem0PWzlNieZsA==", - "dependencies": { - "@types/mdast": "^4.0.0", - "@types/unist": "^3.0.0", - "decode-named-character-reference": "^1.0.0", - "devlop": "^1.0.0", - "mdast-util-to-string": "^4.0.0", - "micromark": "^4.0.0", - "micromark-util-decode-numeric-character-reference": "^2.0.0", - "micromark-util-decode-string": "^2.0.0", - "micromark-util-normalize-identifier": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0", - "unist-util-stringify-position": "^4.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/mdast-util-math/node_modules/mdast-util-to-string": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-4.0.0.tgz", - "integrity": "sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg==", - "dependencies": { - "@types/mdast": "^4.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/mdast-util-math/node_modules/micromark": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/micromark/-/micromark-4.0.0.tgz", - "integrity": "sha512-o/sd0nMof8kYff+TqcDx3VSrgBTcZpSvYcAHIfHhv5VAuNmisCxjhx6YmxS8PFEpb9z5WKWKPdzf0jM23ro3RQ==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "@types/debug": "^4.0.0", - "debug": "^4.0.0", - "decode-named-character-reference": "^1.0.0", - "devlop": "^1.0.0", - "micromark-core-commonmark": "^2.0.0", - "micromark-factory-space": "^2.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-chunked": "^2.0.0", - "micromark-util-combine-extensions": "^2.0.0", - "micromark-util-decode-numeric-character-reference": "^2.0.0", - "micromark-util-encode": "^2.0.0", - "micromark-util-normalize-identifier": "^2.0.0", - "micromark-util-resolve-all": "^2.0.0", - "micromark-util-sanitize-uri": "^2.0.0", - "micromark-util-subtokenize": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/mdast-util-math/node_modules/micromark-core-commonmark": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-core-commonmark/-/micromark-core-commonmark-2.0.1.tgz", - "integrity": "sha512-CUQyKr1e///ZODyD1U3xit6zXwy1a8q2a1S1HKtIlmgvurrEpaw/Y9y6KSIbF8P59cn/NjzHyO+Q2fAyYLQrAA==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "decode-named-character-reference": "^1.0.0", - "devlop": "^1.0.0", - "micromark-factory-destination": "^2.0.0", - "micromark-factory-label": "^2.0.0", - "micromark-factory-space": "^2.0.0", - "micromark-factory-title": "^2.0.0", - "micromark-factory-whitespace": "^2.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-chunked": "^2.0.0", - "micromark-util-classify-character": "^2.0.0", - "micromark-util-html-tag-name": "^2.0.0", - "micromark-util-normalize-identifier": "^2.0.0", - "micromark-util-resolve-all": "^2.0.0", - "micromark-util-subtokenize": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/mdast-util-math/node_modules/micromark-factory-destination": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-factory-destination/-/micromark-factory-destination-2.0.0.tgz", - "integrity": "sha512-j9DGrQLm/Uhl2tCzcbLhy5kXsgkHUrjJHg4fFAeoMRwJmJerT9aw4FEhIbZStWN8A3qMwOp1uzHr4UL8AInxtA==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-util-character": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/mdast-util-math/node_modules/micromark-factory-label": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-factory-label/-/micromark-factory-label-2.0.0.tgz", - "integrity": "sha512-RR3i96ohZGde//4WSe/dJsxOX6vxIg9TimLAS3i4EhBAFx8Sm5SmqVfR8E87DPSR31nEAjZfbt91OMZWcNgdZw==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "devlop": "^1.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/mdast-util-math/node_modules/micromark-factory-space": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.0.tgz", - "integrity": "sha512-TKr+LIDX2pkBJXFLzpyPyljzYK3MtmllMUMODTQJIUfDGncESaqB90db9IAUcz4AZAJFdd8U9zOp9ty1458rxg==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-util-character": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/mdast-util-math/node_modules/micromark-factory-title": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-factory-title/-/micromark-factory-title-2.0.0.tgz", - "integrity": "sha512-jY8CSxmpWLOxS+t8W+FG3Xigc0RDQA9bKMY/EwILvsesiRniiVMejYTE4wumNc2f4UbAa4WsHqe3J1QS1sli+A==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-factory-space": "^2.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/mdast-util-math/node_modules/micromark-factory-whitespace": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-factory-whitespace/-/micromark-factory-whitespace-2.0.0.tgz", - "integrity": "sha512-28kbwaBjc5yAI1XadbdPYHX/eDnqaUFVikLwrO7FDnKG7lpgxnvk/XGRhX/PN0mOZ+dBSZ+LgunHS+6tYQAzhA==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-factory-space": "^2.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/mdast-util-math/node_modules/micromark-util-character": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.0.tgz", - "integrity": "sha512-KvOVV+X1yLBfs9dCBSopq/+G1PcgT3lAK07mC4BzXi5E7ahzMAF8oIupDDJ6mievI6F+lAATkbQQlQixJfT3aQ==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/mdast-util-math/node_modules/micromark-util-chunked": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-chunked/-/micromark-util-chunked-2.0.0.tgz", - "integrity": "sha512-anK8SWmNphkXdaKgz5hJvGa7l00qmcaUQoMYsBwDlSKFKjc6gjGXPDw3FNL3Nbwq5L8gE+RCbGqTw49FK5Qyvg==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-util-symbol": "^2.0.0" - } - }, - "node_modules/mdast-util-math/node_modules/micromark-util-classify-character": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-classify-character/-/micromark-util-classify-character-2.0.0.tgz", - "integrity": "sha512-S0ze2R9GH+fu41FA7pbSqNWObo/kzwf8rN/+IGlW/4tC6oACOs8B++bh+i9bVyNnwCcuksbFwsBme5OCKXCwIw==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-util-character": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/mdast-util-math/node_modules/micromark-util-combine-extensions": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-combine-extensions/-/micromark-util-combine-extensions-2.0.0.tgz", - "integrity": "sha512-vZZio48k7ON0fVS3CUgFatWHoKbbLTK/rT7pzpJ4Bjp5JjkZeasRfrS9wsBdDJK2cJLHMckXZdzPSSr1B8a4oQ==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-util-chunked": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/mdast-util-math/node_modules/micromark-util-decode-numeric-character-reference": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-decode-numeric-character-reference/-/micromark-util-decode-numeric-character-reference-2.0.1.tgz", - "integrity": "sha512-bmkNc7z8Wn6kgjZmVHOX3SowGmVdhYS7yBpMnuMnPzDq/6xwVA604DuOXMZTO1lvq01g+Adfa0pE2UKGlxL1XQ==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-util-symbol": "^2.0.0" - } - }, - "node_modules/mdast-util-math/node_modules/micromark-util-decode-string": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-decode-string/-/micromark-util-decode-string-2.0.0.tgz", - "integrity": "sha512-r4Sc6leeUTn3P6gk20aFMj2ntPwn6qpDZqWvYmAG6NgvFTIlj4WtrAudLi65qYoaGdXYViXYw2pkmn7QnIFasA==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "decode-named-character-reference": "^1.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-decode-numeric-character-reference": "^2.0.0", - "micromark-util-symbol": "^2.0.0" - } - }, - "node_modules/mdast-util-math/node_modules/micromark-util-encode": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-encode/-/micromark-util-encode-2.0.0.tgz", - "integrity": "sha512-pS+ROfCXAGLWCOc8egcBvT0kf27GoWMqtdarNfDcjb6YLuV5cM3ioG45Ys2qOVqeqSbjaKg72vU+Wby3eddPsA==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ] - }, - "node_modules/mdast-util-math/node_modules/micromark-util-html-tag-name": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-html-tag-name/-/micromark-util-html-tag-name-2.0.0.tgz", - "integrity": "sha512-xNn4Pqkj2puRhKdKTm8t1YHC/BAjx6CEwRFXntTaRf/x16aqka6ouVoutm+QdkISTlT7e2zU7U4ZdlDLJd2Mcw==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ] - }, - "node_modules/mdast-util-math/node_modules/micromark-util-normalize-identifier": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-normalize-identifier/-/micromark-util-normalize-identifier-2.0.0.tgz", - "integrity": "sha512-2xhYT0sfo85FMrUPtHcPo2rrp1lwbDEEzpx7jiH2xXJLqBuy4H0GgXk5ToU8IEwoROtXuL8ND0ttVa4rNqYK3w==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-util-symbol": "^2.0.0" - } - }, - "node_modules/mdast-util-math/node_modules/micromark-util-resolve-all": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-resolve-all/-/micromark-util-resolve-all-2.0.0.tgz", - "integrity": "sha512-6KU6qO7DZ7GJkaCgwBNtplXCvGkJToU86ybBAUdavvgsCiG8lSSvYxr9MhwmQ+udpzywHsl4RpGJsYWG1pDOcA==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/mdast-util-math/node_modules/micromark-util-sanitize-uri": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-2.0.0.tgz", - "integrity": "sha512-WhYv5UEcZrbAtlsnPuChHUAsu/iBPOVaEVsntLBIdpibO0ddy8OzavZz3iL2xVvBZOpolujSliP65Kq0/7KIYw==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-util-character": "^2.0.0", - "micromark-util-encode": "^2.0.0", - "micromark-util-symbol": "^2.0.0" - } - }, - "node_modules/mdast-util-math/node_modules/micromark-util-subtokenize": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-subtokenize/-/micromark-util-subtokenize-2.0.1.tgz", - "integrity": "sha512-jZNtiFl/1aY73yS3UGQkutD0UbhTt68qnRpw2Pifmz5wV9h8gOVsN70v+Lq/f1rKaU/W8pxRe8y8Q9FX1AOe1Q==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "devlop": "^1.0.0", - "micromark-util-chunked": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/mdast-util-math/node_modules/micromark-util-symbol": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", - "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ] - }, - "node_modules/mdast-util-math/node_modules/micromark-util-types": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-2.0.0.tgz", - "integrity": "sha512-oNh6S2WMHWRZrmutsRmDDfkzKtxF+bc2VxLC9dvtrDIRFln627VsFP6fLMgTryGDljgLPjkrzQSDcPrjPyDJ5w==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ] - }, - "node_modules/mdast-util-math/node_modules/unist-util-stringify-position": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-4.0.0.tgz", - "integrity": "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==", - "dependencies": { - "@types/unist": "^3.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/mdast-util-mdx-expression": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/mdast-util-mdx-expression/-/mdast-util-mdx-expression-2.0.0.tgz", - "integrity": "sha512-fGCu8eWdKUKNu5mohVGkhBXCXGnOTLuFqOvGMvdikr+J1w7lDJgxThOKpwRWzzbyXAU2hhSwsmssOY4yTokluw==", - "dependencies": { - "@types/estree-jsx": "^1.0.0", - "@types/hast": "^3.0.0", - "@types/mdast": "^4.0.0", - "devlop": "^1.0.0", - "mdast-util-from-markdown": "^2.0.0", - "mdast-util-to-markdown": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/mdast-util-mdx-expression/node_modules/@types/mdast": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-4.0.4.tgz", - "integrity": "sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==", - "dependencies": { - "@types/unist": "*" - } - }, - "node_modules/mdast-util-mdx-expression/node_modules/@types/unist": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", - "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==" - }, - "node_modules/mdast-util-mdx-expression/node_modules/mdast-util-from-markdown": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/mdast-util-from-markdown/-/mdast-util-from-markdown-2.0.1.tgz", - "integrity": "sha512-aJEUyzZ6TzlsX2s5B4Of7lN7EQtAxvtradMMglCQDyaTFgse6CmtmdJ15ElnVRlCg1vpNyVtbem0PWzlNieZsA==", - "dependencies": { - "@types/mdast": "^4.0.0", - "@types/unist": "^3.0.0", - "decode-named-character-reference": "^1.0.0", - "devlop": "^1.0.0", - "mdast-util-to-string": "^4.0.0", - "micromark": "^4.0.0", - "micromark-util-decode-numeric-character-reference": "^2.0.0", - "micromark-util-decode-string": "^2.0.0", - "micromark-util-normalize-identifier": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0", - "unist-util-stringify-position": "^4.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/mdast-util-mdx-expression/node_modules/mdast-util-to-string": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-4.0.0.tgz", - "integrity": "sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg==", - "dependencies": { - "@types/mdast": "^4.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/mdast-util-mdx-expression/node_modules/micromark": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/micromark/-/micromark-4.0.0.tgz", - "integrity": "sha512-o/sd0nMof8kYff+TqcDx3VSrgBTcZpSvYcAHIfHhv5VAuNmisCxjhx6YmxS8PFEpb9z5WKWKPdzf0jM23ro3RQ==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "@types/debug": "^4.0.0", - "debug": "^4.0.0", - "decode-named-character-reference": "^1.0.0", - "devlop": "^1.0.0", - "micromark-core-commonmark": "^2.0.0", - "micromark-factory-space": "^2.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-chunked": "^2.0.0", - "micromark-util-combine-extensions": "^2.0.0", - "micromark-util-decode-numeric-character-reference": "^2.0.0", - "micromark-util-encode": "^2.0.0", - "micromark-util-normalize-identifier": "^2.0.0", - "micromark-util-resolve-all": "^2.0.0", - "micromark-util-sanitize-uri": "^2.0.0", - "micromark-util-subtokenize": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/mdast-util-mdx-expression/node_modules/micromark-core-commonmark": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-core-commonmark/-/micromark-core-commonmark-2.0.1.tgz", - "integrity": "sha512-CUQyKr1e///ZODyD1U3xit6zXwy1a8q2a1S1HKtIlmgvurrEpaw/Y9y6KSIbF8P59cn/NjzHyO+Q2fAyYLQrAA==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "decode-named-character-reference": "^1.0.0", - "devlop": "^1.0.0", - "micromark-factory-destination": "^2.0.0", - "micromark-factory-label": "^2.0.0", - "micromark-factory-space": "^2.0.0", - "micromark-factory-title": "^2.0.0", - "micromark-factory-whitespace": "^2.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-chunked": "^2.0.0", - "micromark-util-classify-character": "^2.0.0", - "micromark-util-html-tag-name": "^2.0.0", - "micromark-util-normalize-identifier": "^2.0.0", - "micromark-util-resolve-all": "^2.0.0", - "micromark-util-subtokenize": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/mdast-util-mdx-expression/node_modules/micromark-factory-destination": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-factory-destination/-/micromark-factory-destination-2.0.0.tgz", - "integrity": "sha512-j9DGrQLm/Uhl2tCzcbLhy5kXsgkHUrjJHg4fFAeoMRwJmJerT9aw4FEhIbZStWN8A3qMwOp1uzHr4UL8AInxtA==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-util-character": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/mdast-util-mdx-expression/node_modules/micromark-factory-label": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-factory-label/-/micromark-factory-label-2.0.0.tgz", - "integrity": "sha512-RR3i96ohZGde//4WSe/dJsxOX6vxIg9TimLAS3i4EhBAFx8Sm5SmqVfR8E87DPSR31nEAjZfbt91OMZWcNgdZw==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "devlop": "^1.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/mdast-util-mdx-expression/node_modules/micromark-factory-space": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.0.tgz", - "integrity": "sha512-TKr+LIDX2pkBJXFLzpyPyljzYK3MtmllMUMODTQJIUfDGncESaqB90db9IAUcz4AZAJFdd8U9zOp9ty1458rxg==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-util-character": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/mdast-util-mdx-expression/node_modules/micromark-factory-title": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-factory-title/-/micromark-factory-title-2.0.0.tgz", - "integrity": "sha512-jY8CSxmpWLOxS+t8W+FG3Xigc0RDQA9bKMY/EwILvsesiRniiVMejYTE4wumNc2f4UbAa4WsHqe3J1QS1sli+A==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-factory-space": "^2.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/mdast-util-mdx-expression/node_modules/micromark-factory-whitespace": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-factory-whitespace/-/micromark-factory-whitespace-2.0.0.tgz", - "integrity": "sha512-28kbwaBjc5yAI1XadbdPYHX/eDnqaUFVikLwrO7FDnKG7lpgxnvk/XGRhX/PN0mOZ+dBSZ+LgunHS+6tYQAzhA==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-factory-space": "^2.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/mdast-util-mdx-expression/node_modules/micromark-util-character": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.0.tgz", - "integrity": "sha512-KvOVV+X1yLBfs9dCBSopq/+G1PcgT3lAK07mC4BzXi5E7ahzMAF8oIupDDJ6mievI6F+lAATkbQQlQixJfT3aQ==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/mdast-util-mdx-expression/node_modules/micromark-util-chunked": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-chunked/-/micromark-util-chunked-2.0.0.tgz", - "integrity": "sha512-anK8SWmNphkXdaKgz5hJvGa7l00qmcaUQoMYsBwDlSKFKjc6gjGXPDw3FNL3Nbwq5L8gE+RCbGqTw49FK5Qyvg==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-util-symbol": "^2.0.0" - } - }, - "node_modules/mdast-util-mdx-expression/node_modules/micromark-util-classify-character": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-classify-character/-/micromark-util-classify-character-2.0.0.tgz", - "integrity": "sha512-S0ze2R9GH+fu41FA7pbSqNWObo/kzwf8rN/+IGlW/4tC6oACOs8B++bh+i9bVyNnwCcuksbFwsBme5OCKXCwIw==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-util-character": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/mdast-util-mdx-expression/node_modules/micromark-util-combine-extensions": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-combine-extensions/-/micromark-util-combine-extensions-2.0.0.tgz", - "integrity": "sha512-vZZio48k7ON0fVS3CUgFatWHoKbbLTK/rT7pzpJ4Bjp5JjkZeasRfrS9wsBdDJK2cJLHMckXZdzPSSr1B8a4oQ==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-util-chunked": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/mdast-util-mdx-expression/node_modules/micromark-util-decode-numeric-character-reference": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-decode-numeric-character-reference/-/micromark-util-decode-numeric-character-reference-2.0.1.tgz", - "integrity": "sha512-bmkNc7z8Wn6kgjZmVHOX3SowGmVdhYS7yBpMnuMnPzDq/6xwVA604DuOXMZTO1lvq01g+Adfa0pE2UKGlxL1XQ==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-util-symbol": "^2.0.0" - } - }, - "node_modules/mdast-util-mdx-expression/node_modules/micromark-util-decode-string": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-decode-string/-/micromark-util-decode-string-2.0.0.tgz", - "integrity": "sha512-r4Sc6leeUTn3P6gk20aFMj2ntPwn6qpDZqWvYmAG6NgvFTIlj4WtrAudLi65qYoaGdXYViXYw2pkmn7QnIFasA==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "decode-named-character-reference": "^1.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-decode-numeric-character-reference": "^2.0.0", - "micromark-util-symbol": "^2.0.0" - } - }, - "node_modules/mdast-util-mdx-expression/node_modules/micromark-util-encode": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-encode/-/micromark-util-encode-2.0.0.tgz", - "integrity": "sha512-pS+ROfCXAGLWCOc8egcBvT0kf27GoWMqtdarNfDcjb6YLuV5cM3ioG45Ys2qOVqeqSbjaKg72vU+Wby3eddPsA==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ] - }, - "node_modules/mdast-util-mdx-expression/node_modules/micromark-util-html-tag-name": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-html-tag-name/-/micromark-util-html-tag-name-2.0.0.tgz", - "integrity": "sha512-xNn4Pqkj2puRhKdKTm8t1YHC/BAjx6CEwRFXntTaRf/x16aqka6ouVoutm+QdkISTlT7e2zU7U4ZdlDLJd2Mcw==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ] - }, - "node_modules/mdast-util-mdx-expression/node_modules/micromark-util-normalize-identifier": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-normalize-identifier/-/micromark-util-normalize-identifier-2.0.0.tgz", - "integrity": "sha512-2xhYT0sfo85FMrUPtHcPo2rrp1lwbDEEzpx7jiH2xXJLqBuy4H0GgXk5ToU8IEwoROtXuL8ND0ttVa4rNqYK3w==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-util-symbol": "^2.0.0" - } - }, - "node_modules/mdast-util-mdx-expression/node_modules/micromark-util-resolve-all": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-resolve-all/-/micromark-util-resolve-all-2.0.0.tgz", - "integrity": "sha512-6KU6qO7DZ7GJkaCgwBNtplXCvGkJToU86ybBAUdavvgsCiG8lSSvYxr9MhwmQ+udpzywHsl4RpGJsYWG1pDOcA==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/mdast-util-mdx-expression/node_modules/micromark-util-sanitize-uri": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-2.0.0.tgz", - "integrity": "sha512-WhYv5UEcZrbAtlsnPuChHUAsu/iBPOVaEVsntLBIdpibO0ddy8OzavZz3iL2xVvBZOpolujSliP65Kq0/7KIYw==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-util-character": "^2.0.0", - "micromark-util-encode": "^2.0.0", - "micromark-util-symbol": "^2.0.0" - } - }, - "node_modules/mdast-util-mdx-expression/node_modules/micromark-util-subtokenize": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-subtokenize/-/micromark-util-subtokenize-2.0.1.tgz", - "integrity": "sha512-jZNtiFl/1aY73yS3UGQkutD0UbhTt68qnRpw2Pifmz5wV9h8gOVsN70v+Lq/f1rKaU/W8pxRe8y8Q9FX1AOe1Q==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "devlop": "^1.0.0", - "micromark-util-chunked": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/mdast-util-mdx-expression/node_modules/micromark-util-symbol": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", - "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ] - }, - "node_modules/mdast-util-mdx-expression/node_modules/micromark-util-types": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-2.0.0.tgz", - "integrity": "sha512-oNh6S2WMHWRZrmutsRmDDfkzKtxF+bc2VxLC9dvtrDIRFln627VsFP6fLMgTryGDljgLPjkrzQSDcPrjPyDJ5w==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ] - }, - "node_modules/mdast-util-mdx-expression/node_modules/unist-util-stringify-position": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-4.0.0.tgz", - "integrity": "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==", - "dependencies": { - "@types/unist": "^3.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/mdast-util-mdx-jsx": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/mdast-util-mdx-jsx/-/mdast-util-mdx-jsx-3.1.2.tgz", - "integrity": "sha512-eKMQDeywY2wlHc97k5eD8VC+9ASMjN8ItEZQNGwJ6E0XWKiW/Z0V5/H8pvoXUf+y+Mj0VIgeRRbujBmFn4FTyA==", - "dependencies": { - "@types/estree-jsx": "^1.0.0", - "@types/hast": "^3.0.0", - "@types/mdast": "^4.0.0", - "@types/unist": "^3.0.0", - "ccount": "^2.0.0", - "devlop": "^1.1.0", - "mdast-util-from-markdown": "^2.0.0", - "mdast-util-to-markdown": "^2.0.0", - "parse-entities": "^4.0.0", - "stringify-entities": "^4.0.0", - "unist-util-remove-position": "^5.0.0", - "unist-util-stringify-position": "^4.0.0", - "vfile-message": "^4.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/mdast-util-mdx-jsx/node_modules/@types/mdast": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-4.0.4.tgz", - "integrity": "sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==", - "dependencies": { - "@types/unist": "*" - } - }, - "node_modules/mdast-util-mdx-jsx/node_modules/@types/unist": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", - "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==" - }, - "node_modules/mdast-util-mdx-jsx/node_modules/mdast-util-from-markdown": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/mdast-util-from-markdown/-/mdast-util-from-markdown-2.0.1.tgz", - "integrity": "sha512-aJEUyzZ6TzlsX2s5B4Of7lN7EQtAxvtradMMglCQDyaTFgse6CmtmdJ15ElnVRlCg1vpNyVtbem0PWzlNieZsA==", - "dependencies": { - "@types/mdast": "^4.0.0", - "@types/unist": "^3.0.0", - "decode-named-character-reference": "^1.0.0", - "devlop": "^1.0.0", - "mdast-util-to-string": "^4.0.0", - "micromark": "^4.0.0", - "micromark-util-decode-numeric-character-reference": "^2.0.0", - "micromark-util-decode-string": "^2.0.0", - "micromark-util-normalize-identifier": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0", - "unist-util-stringify-position": "^4.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/mdast-util-mdx-jsx/node_modules/mdast-util-to-string": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-4.0.0.tgz", - "integrity": "sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg==", - "dependencies": { - "@types/mdast": "^4.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/mdast-util-mdx-jsx/node_modules/micromark": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/micromark/-/micromark-4.0.0.tgz", - "integrity": "sha512-o/sd0nMof8kYff+TqcDx3VSrgBTcZpSvYcAHIfHhv5VAuNmisCxjhx6YmxS8PFEpb9z5WKWKPdzf0jM23ro3RQ==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "@types/debug": "^4.0.0", - "debug": "^4.0.0", - "decode-named-character-reference": "^1.0.0", - "devlop": "^1.0.0", - "micromark-core-commonmark": "^2.0.0", - "micromark-factory-space": "^2.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-chunked": "^2.0.0", - "micromark-util-combine-extensions": "^2.0.0", - "micromark-util-decode-numeric-character-reference": "^2.0.0", - "micromark-util-encode": "^2.0.0", - "micromark-util-normalize-identifier": "^2.0.0", - "micromark-util-resolve-all": "^2.0.0", - "micromark-util-sanitize-uri": "^2.0.0", - "micromark-util-subtokenize": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/mdast-util-mdx-jsx/node_modules/micromark-core-commonmark": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-core-commonmark/-/micromark-core-commonmark-2.0.1.tgz", - "integrity": "sha512-CUQyKr1e///ZODyD1U3xit6zXwy1a8q2a1S1HKtIlmgvurrEpaw/Y9y6KSIbF8P59cn/NjzHyO+Q2fAyYLQrAA==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "decode-named-character-reference": "^1.0.0", - "devlop": "^1.0.0", - "micromark-factory-destination": "^2.0.0", - "micromark-factory-label": "^2.0.0", - "micromark-factory-space": "^2.0.0", - "micromark-factory-title": "^2.0.0", - "micromark-factory-whitespace": "^2.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-chunked": "^2.0.0", - "micromark-util-classify-character": "^2.0.0", - "micromark-util-html-tag-name": "^2.0.0", - "micromark-util-normalize-identifier": "^2.0.0", - "micromark-util-resolve-all": "^2.0.0", - "micromark-util-subtokenize": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/mdast-util-mdx-jsx/node_modules/micromark-factory-destination": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-factory-destination/-/micromark-factory-destination-2.0.0.tgz", - "integrity": "sha512-j9DGrQLm/Uhl2tCzcbLhy5kXsgkHUrjJHg4fFAeoMRwJmJerT9aw4FEhIbZStWN8A3qMwOp1uzHr4UL8AInxtA==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-util-character": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/mdast-util-mdx-jsx/node_modules/micromark-factory-label": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-factory-label/-/micromark-factory-label-2.0.0.tgz", - "integrity": "sha512-RR3i96ohZGde//4WSe/dJsxOX6vxIg9TimLAS3i4EhBAFx8Sm5SmqVfR8E87DPSR31nEAjZfbt91OMZWcNgdZw==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "devlop": "^1.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/mdast-util-mdx-jsx/node_modules/micromark-factory-space": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.0.tgz", - "integrity": "sha512-TKr+LIDX2pkBJXFLzpyPyljzYK3MtmllMUMODTQJIUfDGncESaqB90db9IAUcz4AZAJFdd8U9zOp9ty1458rxg==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-util-character": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/mdast-util-mdx-jsx/node_modules/micromark-factory-title": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-factory-title/-/micromark-factory-title-2.0.0.tgz", - "integrity": "sha512-jY8CSxmpWLOxS+t8W+FG3Xigc0RDQA9bKMY/EwILvsesiRniiVMejYTE4wumNc2f4UbAa4WsHqe3J1QS1sli+A==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-factory-space": "^2.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/mdast-util-mdx-jsx/node_modules/micromark-factory-whitespace": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-factory-whitespace/-/micromark-factory-whitespace-2.0.0.tgz", - "integrity": "sha512-28kbwaBjc5yAI1XadbdPYHX/eDnqaUFVikLwrO7FDnKG7lpgxnvk/XGRhX/PN0mOZ+dBSZ+LgunHS+6tYQAzhA==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-factory-space": "^2.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/mdast-util-mdx-jsx/node_modules/micromark-util-character": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.0.tgz", - "integrity": "sha512-KvOVV+X1yLBfs9dCBSopq/+G1PcgT3lAK07mC4BzXi5E7ahzMAF8oIupDDJ6mievI6F+lAATkbQQlQixJfT3aQ==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/mdast-util-mdx-jsx/node_modules/micromark-util-chunked": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-chunked/-/micromark-util-chunked-2.0.0.tgz", - "integrity": "sha512-anK8SWmNphkXdaKgz5hJvGa7l00qmcaUQoMYsBwDlSKFKjc6gjGXPDw3FNL3Nbwq5L8gE+RCbGqTw49FK5Qyvg==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-util-symbol": "^2.0.0" - } - }, - "node_modules/mdast-util-mdx-jsx/node_modules/micromark-util-classify-character": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-classify-character/-/micromark-util-classify-character-2.0.0.tgz", - "integrity": "sha512-S0ze2R9GH+fu41FA7pbSqNWObo/kzwf8rN/+IGlW/4tC6oACOs8B++bh+i9bVyNnwCcuksbFwsBme5OCKXCwIw==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-util-character": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/mdast-util-mdx-jsx/node_modules/micromark-util-combine-extensions": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-combine-extensions/-/micromark-util-combine-extensions-2.0.0.tgz", - "integrity": "sha512-vZZio48k7ON0fVS3CUgFatWHoKbbLTK/rT7pzpJ4Bjp5JjkZeasRfrS9wsBdDJK2cJLHMckXZdzPSSr1B8a4oQ==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-util-chunked": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/mdast-util-mdx-jsx/node_modules/micromark-util-decode-numeric-character-reference": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-decode-numeric-character-reference/-/micromark-util-decode-numeric-character-reference-2.0.1.tgz", - "integrity": "sha512-bmkNc7z8Wn6kgjZmVHOX3SowGmVdhYS7yBpMnuMnPzDq/6xwVA604DuOXMZTO1lvq01g+Adfa0pE2UKGlxL1XQ==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-util-symbol": "^2.0.0" - } - }, - "node_modules/mdast-util-mdx-jsx/node_modules/micromark-util-decode-string": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-decode-string/-/micromark-util-decode-string-2.0.0.tgz", - "integrity": "sha512-r4Sc6leeUTn3P6gk20aFMj2ntPwn6qpDZqWvYmAG6NgvFTIlj4WtrAudLi65qYoaGdXYViXYw2pkmn7QnIFasA==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "decode-named-character-reference": "^1.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-decode-numeric-character-reference": "^2.0.0", - "micromark-util-symbol": "^2.0.0" - } - }, - "node_modules/mdast-util-mdx-jsx/node_modules/micromark-util-encode": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-encode/-/micromark-util-encode-2.0.0.tgz", - "integrity": "sha512-pS+ROfCXAGLWCOc8egcBvT0kf27GoWMqtdarNfDcjb6YLuV5cM3ioG45Ys2qOVqeqSbjaKg72vU+Wby3eddPsA==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ] - }, - "node_modules/mdast-util-mdx-jsx/node_modules/micromark-util-html-tag-name": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-html-tag-name/-/micromark-util-html-tag-name-2.0.0.tgz", - "integrity": "sha512-xNn4Pqkj2puRhKdKTm8t1YHC/BAjx6CEwRFXntTaRf/x16aqka6ouVoutm+QdkISTlT7e2zU7U4ZdlDLJd2Mcw==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ] - }, - "node_modules/mdast-util-mdx-jsx/node_modules/micromark-util-normalize-identifier": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-normalize-identifier/-/micromark-util-normalize-identifier-2.0.0.tgz", - "integrity": "sha512-2xhYT0sfo85FMrUPtHcPo2rrp1lwbDEEzpx7jiH2xXJLqBuy4H0GgXk5ToU8IEwoROtXuL8ND0ttVa4rNqYK3w==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-util-symbol": "^2.0.0" - } - }, - "node_modules/mdast-util-mdx-jsx/node_modules/micromark-util-resolve-all": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-resolve-all/-/micromark-util-resolve-all-2.0.0.tgz", - "integrity": "sha512-6KU6qO7DZ7GJkaCgwBNtplXCvGkJToU86ybBAUdavvgsCiG8lSSvYxr9MhwmQ+udpzywHsl4RpGJsYWG1pDOcA==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/mdast-util-mdx-jsx/node_modules/micromark-util-sanitize-uri": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-2.0.0.tgz", - "integrity": "sha512-WhYv5UEcZrbAtlsnPuChHUAsu/iBPOVaEVsntLBIdpibO0ddy8OzavZz3iL2xVvBZOpolujSliP65Kq0/7KIYw==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-util-character": "^2.0.0", - "micromark-util-encode": "^2.0.0", - "micromark-util-symbol": "^2.0.0" - } - }, - "node_modules/mdast-util-mdx-jsx/node_modules/micromark-util-subtokenize": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-subtokenize/-/micromark-util-subtokenize-2.0.1.tgz", - "integrity": "sha512-jZNtiFl/1aY73yS3UGQkutD0UbhTt68qnRpw2Pifmz5wV9h8gOVsN70v+Lq/f1rKaU/W8pxRe8y8Q9FX1AOe1Q==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "devlop": "^1.0.0", - "micromark-util-chunked": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/mdast-util-mdx-jsx/node_modules/micromark-util-symbol": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", - "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ] - }, - "node_modules/mdast-util-mdx-jsx/node_modules/micromark-util-types": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-2.0.0.tgz", - "integrity": "sha512-oNh6S2WMHWRZrmutsRmDDfkzKtxF+bc2VxLC9dvtrDIRFln627VsFP6fLMgTryGDljgLPjkrzQSDcPrjPyDJ5w==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ] - }, - "node_modules/mdast-util-mdx-jsx/node_modules/unist-util-stringify-position": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-4.0.0.tgz", - "integrity": "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==", - "dependencies": { - "@types/unist": "^3.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/mdast-util-mdxjs-esm": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/mdast-util-mdxjs-esm/-/mdast-util-mdxjs-esm-2.0.1.tgz", - "integrity": "sha512-EcmOpxsZ96CvlP03NghtH1EsLtr0n9Tm4lPUJUBccV9RwUOneqSycg19n5HGzCf+10LozMRSObtVr3ee1WoHtg==", - "dependencies": { - "@types/estree-jsx": "^1.0.0", - "@types/hast": "^3.0.0", - "@types/mdast": "^4.0.0", - "devlop": "^1.0.0", - "mdast-util-from-markdown": "^2.0.0", - "mdast-util-to-markdown": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/mdast-util-mdxjs-esm/node_modules/@types/mdast": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-4.0.4.tgz", - "integrity": "sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==", - "dependencies": { - "@types/unist": "*" - } - }, - "node_modules/mdast-util-mdxjs-esm/node_modules/@types/unist": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", - "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==" - }, - "node_modules/mdast-util-mdxjs-esm/node_modules/mdast-util-from-markdown": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/mdast-util-from-markdown/-/mdast-util-from-markdown-2.0.1.tgz", - "integrity": "sha512-aJEUyzZ6TzlsX2s5B4Of7lN7EQtAxvtradMMglCQDyaTFgse6CmtmdJ15ElnVRlCg1vpNyVtbem0PWzlNieZsA==", - "dependencies": { - "@types/mdast": "^4.0.0", - "@types/unist": "^3.0.0", - "decode-named-character-reference": "^1.0.0", - "devlop": "^1.0.0", - "mdast-util-to-string": "^4.0.0", - "micromark": "^4.0.0", - "micromark-util-decode-numeric-character-reference": "^2.0.0", - "micromark-util-decode-string": "^2.0.0", - "micromark-util-normalize-identifier": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0", - "unist-util-stringify-position": "^4.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/mdast-util-mdxjs-esm/node_modules/mdast-util-to-string": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-4.0.0.tgz", - "integrity": "sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg==", - "dependencies": { - "@types/mdast": "^4.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/mdast-util-mdxjs-esm/node_modules/micromark": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/micromark/-/micromark-4.0.0.tgz", - "integrity": "sha512-o/sd0nMof8kYff+TqcDx3VSrgBTcZpSvYcAHIfHhv5VAuNmisCxjhx6YmxS8PFEpb9z5WKWKPdzf0jM23ro3RQ==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "@types/debug": "^4.0.0", - "debug": "^4.0.0", - "decode-named-character-reference": "^1.0.0", - "devlop": "^1.0.0", - "micromark-core-commonmark": "^2.0.0", - "micromark-factory-space": "^2.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-chunked": "^2.0.0", - "micromark-util-combine-extensions": "^2.0.0", - "micromark-util-decode-numeric-character-reference": "^2.0.0", - "micromark-util-encode": "^2.0.0", - "micromark-util-normalize-identifier": "^2.0.0", - "micromark-util-resolve-all": "^2.0.0", - "micromark-util-sanitize-uri": "^2.0.0", - "micromark-util-subtokenize": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/mdast-util-mdxjs-esm/node_modules/micromark-core-commonmark": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-core-commonmark/-/micromark-core-commonmark-2.0.1.tgz", - "integrity": "sha512-CUQyKr1e///ZODyD1U3xit6zXwy1a8q2a1S1HKtIlmgvurrEpaw/Y9y6KSIbF8P59cn/NjzHyO+Q2fAyYLQrAA==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "decode-named-character-reference": "^1.0.0", - "devlop": "^1.0.0", - "micromark-factory-destination": "^2.0.0", - "micromark-factory-label": "^2.0.0", - "micromark-factory-space": "^2.0.0", - "micromark-factory-title": "^2.0.0", - "micromark-factory-whitespace": "^2.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-chunked": "^2.0.0", - "micromark-util-classify-character": "^2.0.0", - "micromark-util-html-tag-name": "^2.0.0", - "micromark-util-normalize-identifier": "^2.0.0", - "micromark-util-resolve-all": "^2.0.0", - "micromark-util-subtokenize": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/mdast-util-mdxjs-esm/node_modules/micromark-factory-destination": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-factory-destination/-/micromark-factory-destination-2.0.0.tgz", - "integrity": "sha512-j9DGrQLm/Uhl2tCzcbLhy5kXsgkHUrjJHg4fFAeoMRwJmJerT9aw4FEhIbZStWN8A3qMwOp1uzHr4UL8AInxtA==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-util-character": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/mdast-util-mdxjs-esm/node_modules/micromark-factory-label": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-factory-label/-/micromark-factory-label-2.0.0.tgz", - "integrity": "sha512-RR3i96ohZGde//4WSe/dJsxOX6vxIg9TimLAS3i4EhBAFx8Sm5SmqVfR8E87DPSR31nEAjZfbt91OMZWcNgdZw==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "devlop": "^1.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/mdast-util-mdxjs-esm/node_modules/micromark-factory-space": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.0.tgz", - "integrity": "sha512-TKr+LIDX2pkBJXFLzpyPyljzYK3MtmllMUMODTQJIUfDGncESaqB90db9IAUcz4AZAJFdd8U9zOp9ty1458rxg==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-util-character": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/mdast-util-mdxjs-esm/node_modules/micromark-factory-title": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-factory-title/-/micromark-factory-title-2.0.0.tgz", - "integrity": "sha512-jY8CSxmpWLOxS+t8W+FG3Xigc0RDQA9bKMY/EwILvsesiRniiVMejYTE4wumNc2f4UbAa4WsHqe3J1QS1sli+A==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-factory-space": "^2.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/mdast-util-mdxjs-esm/node_modules/micromark-factory-whitespace": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-factory-whitespace/-/micromark-factory-whitespace-2.0.0.tgz", - "integrity": "sha512-28kbwaBjc5yAI1XadbdPYHX/eDnqaUFVikLwrO7FDnKG7lpgxnvk/XGRhX/PN0mOZ+dBSZ+LgunHS+6tYQAzhA==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-factory-space": "^2.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/mdast-util-mdxjs-esm/node_modules/micromark-util-character": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.0.tgz", - "integrity": "sha512-KvOVV+X1yLBfs9dCBSopq/+G1PcgT3lAK07mC4BzXi5E7ahzMAF8oIupDDJ6mievI6F+lAATkbQQlQixJfT3aQ==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/mdast-util-mdxjs-esm/node_modules/micromark-util-chunked": { + "node_modules/mdast-util-gfm-footnote": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-chunked/-/micromark-util-chunked-2.0.0.tgz", - "integrity": "sha512-anK8SWmNphkXdaKgz5hJvGa7l00qmcaUQoMYsBwDlSKFKjc6gjGXPDw3FNL3Nbwq5L8gE+RCbGqTw49FK5Qyvg==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], + "resolved": "https://registry.npmjs.org/mdast-util-gfm-footnote/-/mdast-util-gfm-footnote-2.0.0.tgz", + "integrity": "sha512-5jOT2boTSVkMnQ7LTrd6n/18kqwjmuYqo7JUPe+tRCY6O7dAuTFMtTPauYYrMPpox9hlN0uOx/FL8XvEfG9/mQ==", "dependencies": { - "micromark-util-symbol": "^2.0.0" + "@types/mdast": "^4.0.0", + "devlop": "^1.1.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/mdast-util-mdxjs-esm/node_modules/micromark-util-classify-character": { + "node_modules/mdast-util-gfm-strikethrough": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-classify-character/-/micromark-util-classify-character-2.0.0.tgz", - "integrity": "sha512-S0ze2R9GH+fu41FA7pbSqNWObo/kzwf8rN/+IGlW/4tC6oACOs8B++bh+i9bVyNnwCcuksbFwsBme5OCKXCwIw==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], + "resolved": "https://registry.npmjs.org/mdast-util-gfm-strikethrough/-/mdast-util-gfm-strikethrough-2.0.0.tgz", + "integrity": "sha512-mKKb915TF+OC5ptj5bJ7WFRPdYtuHv0yTRxK2tJvi+BDqbkiG7h7u/9SI89nRAYcmap2xHQL9D+QG/6wSrTtXg==", "dependencies": { - "micromark-util-character": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" + "@types/mdast": "^4.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/mdast-util-mdxjs-esm/node_modules/micromark-util-combine-extensions": { + "node_modules/mdast-util-gfm-table": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-combine-extensions/-/micromark-util-combine-extensions-2.0.0.tgz", - "integrity": "sha512-vZZio48k7ON0fVS3CUgFatWHoKbbLTK/rT7pzpJ4Bjp5JjkZeasRfrS9wsBdDJK2cJLHMckXZdzPSSr1B8a4oQ==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-util-chunked": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/mdast-util-mdxjs-esm/node_modules/micromark-util-decode-numeric-character-reference": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-decode-numeric-character-reference/-/micromark-util-decode-numeric-character-reference-2.0.1.tgz", - "integrity": "sha512-bmkNc7z8Wn6kgjZmVHOX3SowGmVdhYS7yBpMnuMnPzDq/6xwVA604DuOXMZTO1lvq01g+Adfa0pE2UKGlxL1XQ==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], + "resolved": "https://registry.npmjs.org/mdast-util-gfm-table/-/mdast-util-gfm-table-2.0.0.tgz", + "integrity": "sha512-78UEvebzz/rJIxLvE7ZtDd/vIQ0RHv+3Mh5DR96p7cS7HsBhYIICDBCu8csTNWNO6tBWfqXPWekRuj2FNOGOZg==", "dependencies": { - "micromark-util-symbol": "^2.0.0" + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "markdown-table": "^3.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/mdast-util-mdxjs-esm/node_modules/micromark-util-decode-string": { + "node_modules/mdast-util-gfm-task-list-item": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-decode-string/-/micromark-util-decode-string-2.0.0.tgz", - "integrity": "sha512-r4Sc6leeUTn3P6gk20aFMj2ntPwn6qpDZqWvYmAG6NgvFTIlj4WtrAudLi65qYoaGdXYViXYw2pkmn7QnIFasA==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], + "resolved": "https://registry.npmjs.org/mdast-util-gfm-task-list-item/-/mdast-util-gfm-task-list-item-2.0.0.tgz", + "integrity": "sha512-IrtvNvjxC1o06taBAVJznEnkiHxLFTzgonUdy8hzFVeDun0uTjxxrRGVaNFqkU1wJR3RBPEfsxmU6jDWPofrTQ==", "dependencies": { - "decode-named-character-reference": "^1.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-decode-numeric-character-reference": "^2.0.0", - "micromark-util-symbol": "^2.0.0" + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/mdast-util-mdxjs-esm/node_modules/micromark-util-encode": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-encode/-/micromark-util-encode-2.0.0.tgz", - "integrity": "sha512-pS+ROfCXAGLWCOc8egcBvT0kf27GoWMqtdarNfDcjb6YLuV5cM3ioG45Ys2qOVqeqSbjaKg72vU+Wby3eddPsA==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ] - }, - "node_modules/mdast-util-mdxjs-esm/node_modules/micromark-util-html-tag-name": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-html-tag-name/-/micromark-util-html-tag-name-2.0.0.tgz", - "integrity": "sha512-xNn4Pqkj2puRhKdKTm8t1YHC/BAjx6CEwRFXntTaRf/x16aqka6ouVoutm+QdkISTlT7e2zU7U4ZdlDLJd2Mcw==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ] - }, - "node_modules/mdast-util-mdxjs-esm/node_modules/micromark-util-normalize-identifier": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-normalize-identifier/-/micromark-util-normalize-identifier-2.0.0.tgz", - "integrity": "sha512-2xhYT0sfo85FMrUPtHcPo2rrp1lwbDEEzpx7jiH2xXJLqBuy4H0GgXk5ToU8IEwoROtXuL8ND0ttVa4rNqYK3w==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], + "node_modules/mdast-util-math": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-math/-/mdast-util-math-3.0.0.tgz", + "integrity": "sha512-Tl9GBNeG/AhJnQM221bJR2HPvLOSnLE/T9cJI9tlc6zwQk2nPk/4f0cHkOdEixQPC/j8UtKDdITswvLAy1OZ1w==", "dependencies": { - "micromark-util-symbol": "^2.0.0" + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "longest-streak": "^3.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.1.0", + "unist-util-remove-position": "^5.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/mdast-util-mdxjs-esm/node_modules/micromark-util-resolve-all": { + "node_modules/mdast-util-mdx-expression": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-resolve-all/-/micromark-util-resolve-all-2.0.0.tgz", - "integrity": "sha512-6KU6qO7DZ7GJkaCgwBNtplXCvGkJToU86ybBAUdavvgsCiG8lSSvYxr9MhwmQ+udpzywHsl4RpGJsYWG1pDOcA==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], + "resolved": "https://registry.npmjs.org/mdast-util-mdx-expression/-/mdast-util-mdx-expression-2.0.0.tgz", + "integrity": "sha512-fGCu8eWdKUKNu5mohVGkhBXCXGnOTLuFqOvGMvdikr+J1w7lDJgxThOKpwRWzzbyXAU2hhSwsmssOY4yTokluw==", "dependencies": { - "micromark-util-types": "^2.0.0" + "@types/estree-jsx": "^1.0.0", + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/mdast-util-mdxjs-esm/node_modules/micromark-util-sanitize-uri": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-2.0.0.tgz", - "integrity": "sha512-WhYv5UEcZrbAtlsnPuChHUAsu/iBPOVaEVsntLBIdpibO0ddy8OzavZz3iL2xVvBZOpolujSliP65Kq0/7KIYw==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], + "node_modules/mdast-util-mdx-jsx": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/mdast-util-mdx-jsx/-/mdast-util-mdx-jsx-3.1.3.tgz", + "integrity": "sha512-bfOjvNt+1AcbPLTFMFWY149nJz0OjmewJs3LQQ5pIyVGxP4CdOqNVJL6kTaM5c68p8q82Xv3nCyFfUnuEcH3UQ==", "dependencies": { - "micromark-util-character": "^2.0.0", - "micromark-util-encode": "^2.0.0", - "micromark-util-symbol": "^2.0.0" + "@types/estree-jsx": "^1.0.0", + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "@types/unist": "^3.0.0", + "ccount": "^2.0.0", + "devlop": "^1.1.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0", + "parse-entities": "^4.0.0", + "stringify-entities": "^4.0.0", + "unist-util-stringify-position": "^4.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/mdast-util-mdxjs-esm/node_modules/micromark-util-subtokenize": { + "node_modules/mdast-util-mdxjs-esm": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-subtokenize/-/micromark-util-subtokenize-2.0.1.tgz", - "integrity": "sha512-jZNtiFl/1aY73yS3UGQkutD0UbhTt68qnRpw2Pifmz5wV9h8gOVsN70v+Lq/f1rKaU/W8pxRe8y8Q9FX1AOe1Q==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], + "resolved": "https://registry.npmjs.org/mdast-util-mdxjs-esm/-/mdast-util-mdxjs-esm-2.0.1.tgz", + "integrity": "sha512-EcmOpxsZ96CvlP03NghtH1EsLtr0n9Tm4lPUJUBccV9RwUOneqSycg19n5HGzCf+10LozMRSObtVr3ee1WoHtg==", "dependencies": { + "@types/estree-jsx": "^1.0.0", + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", "devlop": "^1.0.0", - "micromark-util-chunked": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/mdast-util-mdxjs-esm/node_modules/micromark-util-symbol": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", - "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ] - }, - "node_modules/mdast-util-mdxjs-esm/node_modules/micromark-util-types": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-2.0.0.tgz", - "integrity": "sha512-oNh6S2WMHWRZrmutsRmDDfkzKtxF+bc2VxLC9dvtrDIRFln627VsFP6fLMgTryGDljgLPjkrzQSDcPrjPyDJ5w==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ] - }, - "node_modules/mdast-util-mdxjs-esm/node_modules/unist-util-stringify-position": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-4.0.0.tgz", - "integrity": "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==", - "dependencies": { - "@types/unist": "^3.0.0" + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" }, "funding": { "type": "opencollective", @@ -27245,14 +23129,6 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/mdast-util-phrasing/node_modules/@types/mdast": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-4.0.4.tgz", - "integrity": "sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==", - "dependencies": { - "@types/unist": "*" - } - }, "node_modules/mdast-util-to-hast": { "version": "13.2.0", "resolved": "https://registry.npmjs.org/mdast-util-to-hast/-/mdast-util-to-hast-13.2.0.tgz", @@ -27271,99 +23147,7 @@ "funding": { "type": "opencollective", "url": "https://opencollective.com/unified" - } - }, - "node_modules/mdast-util-to-hast/node_modules/@types/mdast": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-4.0.4.tgz", - "integrity": "sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==", - "dependencies": { - "@types/unist": "*" - } - }, - "node_modules/mdast-util-to-hast/node_modules/micromark-util-character": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.0.tgz", - "integrity": "sha512-KvOVV+X1yLBfs9dCBSopq/+G1PcgT3lAK07mC4BzXi5E7ahzMAF8oIupDDJ6mievI6F+lAATkbQQlQixJfT3aQ==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/mdast-util-to-hast/node_modules/micromark-util-encode": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-encode/-/micromark-util-encode-2.0.0.tgz", - "integrity": "sha512-pS+ROfCXAGLWCOc8egcBvT0kf27GoWMqtdarNfDcjb6YLuV5cM3ioG45Ys2qOVqeqSbjaKg72vU+Wby3eddPsA==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ] - }, - "node_modules/mdast-util-to-hast/node_modules/micromark-util-sanitize-uri": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-2.0.0.tgz", - "integrity": "sha512-WhYv5UEcZrbAtlsnPuChHUAsu/iBPOVaEVsntLBIdpibO0ddy8OzavZz3iL2xVvBZOpolujSliP65Kq0/7KIYw==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-util-character": "^2.0.0", - "micromark-util-encode": "^2.0.0", - "micromark-util-symbol": "^2.0.0" - } - }, - "node_modules/mdast-util-to-hast/node_modules/micromark-util-symbol": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", - "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ] - }, - "node_modules/mdast-util-to-hast/node_modules/micromark-util-types": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-2.0.0.tgz", - "integrity": "sha512-oNh6S2WMHWRZrmutsRmDDfkzKtxF+bc2VxLC9dvtrDIRFln627VsFP6fLMgTryGDljgLPjkrzQSDcPrjPyDJ5w==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ] + } }, "node_modules/mdast-util-to-markdown": { "version": "2.1.0", @@ -27384,20 +23168,7 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/mdast-util-to-markdown/node_modules/@types/mdast": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-4.0.4.tgz", - "integrity": "sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==", - "dependencies": { - "@types/unist": "*" - } - }, - "node_modules/mdast-util-to-markdown/node_modules/@types/unist": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", - "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==" - }, - "node_modules/mdast-util-to-markdown/node_modules/mdast-util-to-string": { + "node_modules/mdast-util-to-string": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-4.0.0.tgz", "integrity": "sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg==", @@ -27409,94 +23180,6 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/mdast-util-to-markdown/node_modules/micromark-util-character": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.0.tgz", - "integrity": "sha512-KvOVV+X1yLBfs9dCBSopq/+G1PcgT3lAK07mC4BzXi5E7ahzMAF8oIupDDJ6mievI6F+lAATkbQQlQixJfT3aQ==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/mdast-util-to-markdown/node_modules/micromark-util-decode-numeric-character-reference": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-decode-numeric-character-reference/-/micromark-util-decode-numeric-character-reference-2.0.1.tgz", - "integrity": "sha512-bmkNc7z8Wn6kgjZmVHOX3SowGmVdhYS7yBpMnuMnPzDq/6xwVA604DuOXMZTO1lvq01g+Adfa0pE2UKGlxL1XQ==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-util-symbol": "^2.0.0" - } - }, - "node_modules/mdast-util-to-markdown/node_modules/micromark-util-decode-string": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-decode-string/-/micromark-util-decode-string-2.0.0.tgz", - "integrity": "sha512-r4Sc6leeUTn3P6gk20aFMj2ntPwn6qpDZqWvYmAG6NgvFTIlj4WtrAudLi65qYoaGdXYViXYw2pkmn7QnIFasA==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "decode-named-character-reference": "^1.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-decode-numeric-character-reference": "^2.0.0", - "micromark-util-symbol": "^2.0.0" - } - }, - "node_modules/mdast-util-to-markdown/node_modules/micromark-util-symbol": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", - "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ] - }, - "node_modules/mdast-util-to-markdown/node_modules/micromark-util-types": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-2.0.0.tgz", - "integrity": "sha512-oNh6S2WMHWRZrmutsRmDDfkzKtxF+bc2VxLC9dvtrDIRFln627VsFP6fLMgTryGDljgLPjkrzQSDcPrjPyDJ5w==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ] - }, "node_modules/mdurl": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-2.0.0.tgz", @@ -27612,78 +23295,10 @@ "resolved": "https://registry.npmjs.org/mhchemparser/-/mhchemparser-4.2.1.tgz", "integrity": "sha512-kYmyrCirqJf3zZ9t/0wGgRZ4/ZJw//VwaRVGA75C4nhE60vtnIzhl9J9ndkX/h6hxSN7pjg/cE0VxbnNM+bnDQ==" }, - "node_modules/micromark-extension-gfm": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/micromark-extension-gfm/-/micromark-extension-gfm-3.0.0.tgz", - "integrity": "sha512-vsKArQsicm7t0z2GugkCKtZehqUm31oeGBV/KVSorWSy8ZlNAv7ytjFhvaryUiCUJYqs+NoE6AFhpQvBTM6Q4w==", - "dependencies": { - "micromark-extension-gfm-autolink-literal": "^2.0.0", - "micromark-extension-gfm-footnote": "^2.0.0", - "micromark-extension-gfm-strikethrough": "^2.0.0", - "micromark-extension-gfm-table": "^2.0.0", - "micromark-extension-gfm-tagfilter": "^2.0.0", - "micromark-extension-gfm-task-list-item": "^2.0.0", - "micromark-util-combine-extensions": "^2.0.0", - "micromark-util-types": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/micromark-extension-gfm-autolink-literal": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/micromark-extension-gfm-autolink-literal/-/micromark-extension-gfm-autolink-literal-2.1.0.tgz", - "integrity": "sha512-oOg7knzhicgQ3t4QCjCWgTmfNhvQbDDnJeVu9v81r7NltNCVmhPy1fJRX27pISafdjL+SVc4d3l48Gb6pbRypw==", - "dependencies": { - "micromark-util-character": "^2.0.0", - "micromark-util-sanitize-uri": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/micromark-extension-gfm-autolink-literal/node_modules/micromark-util-character": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.0.tgz", - "integrity": "sha512-KvOVV+X1yLBfs9dCBSopq/+G1PcgT3lAK07mC4BzXi5E7ahzMAF8oIupDDJ6mievI6F+lAATkbQQlQixJfT3aQ==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/micromark-extension-gfm-autolink-literal/node_modules/micromark-util-encode": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-encode/-/micromark-util-encode-2.0.0.tgz", - "integrity": "sha512-pS+ROfCXAGLWCOc8egcBvT0kf27GoWMqtdarNfDcjb6YLuV5cM3ioG45Ys2qOVqeqSbjaKg72vU+Wby3eddPsA==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ] - }, - "node_modules/micromark-extension-gfm-autolink-literal/node_modules/micromark-util-sanitize-uri": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-2.0.0.tgz", - "integrity": "sha512-WhYv5UEcZrbAtlsnPuChHUAsu/iBPOVaEVsntLBIdpibO0ddy8OzavZz3iL2xVvBZOpolujSliP65Kq0/7KIYw==", + "node_modules/micromark": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/micromark/-/micromark-4.0.0.tgz", + "integrity": "sha512-o/sd0nMof8kYff+TqcDx3VSrgBTcZpSvYcAHIfHhv5VAuNmisCxjhx6YmxS8PFEpb9z5WKWKPdzf0jM23ro3RQ==", "funding": [ { "type": "GitHub Sponsors", @@ -27695,61 +23310,26 @@ } ], "dependencies": { - "micromark-util-character": "^2.0.0", - "micromark-util-encode": "^2.0.0", - "micromark-util-symbol": "^2.0.0" - } - }, - "node_modules/micromark-extension-gfm-autolink-literal/node_modules/micromark-util-symbol": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", - "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ] - }, - "node_modules/micromark-extension-gfm-autolink-literal/node_modules/micromark-util-types": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-2.0.0.tgz", - "integrity": "sha512-oNh6S2WMHWRZrmutsRmDDfkzKtxF+bc2VxLC9dvtrDIRFln627VsFP6fLMgTryGDljgLPjkrzQSDcPrjPyDJ5w==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ] - }, - "node_modules/micromark-extension-gfm-footnote": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/micromark-extension-gfm-footnote/-/micromark-extension-gfm-footnote-2.1.0.tgz", - "integrity": "sha512-/yPhxI1ntnDNsiHtzLKYnE3vf9JZ6cAisqVDauhp4CEHxlb4uoOTxOCJ+9s51bIB8U1N1FJ1RXOKTIlD5B/gqw==", - "dependencies": { + "@types/debug": "^4.0.0", + "debug": "^4.0.0", + "decode-named-character-reference": "^1.0.0", "devlop": "^1.0.0", "micromark-core-commonmark": "^2.0.0", "micromark-factory-space": "^2.0.0", "micromark-util-character": "^2.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-combine-extensions": "^2.0.0", + "micromark-util-decode-numeric-character-reference": "^2.0.0", + "micromark-util-encode": "^2.0.0", "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-resolve-all": "^2.0.0", "micromark-util-sanitize-uri": "^2.0.0", + "micromark-util-subtokenize": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" } }, - "node_modules/micromark-extension-gfm-footnote/node_modules/micromark-core-commonmark": { + "node_modules/micromark-core-commonmark": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/micromark-core-commonmark/-/micromark-core-commonmark-2.0.1.tgz", "integrity": "sha512-CUQyKr1e///ZODyD1U3xit6zXwy1a8q2a1S1HKtIlmgvurrEpaw/Y9y6KSIbF8P59cn/NjzHyO+Q2fAyYLQrAA==", @@ -27782,149 +23362,142 @@ "micromark-util-types": "^2.0.0" } }, - "node_modules/micromark-extension-gfm-footnote/node_modules/micromark-factory-destination": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-factory-destination/-/micromark-factory-destination-2.0.0.tgz", - "integrity": "sha512-j9DGrQLm/Uhl2tCzcbLhy5kXsgkHUrjJHg4fFAeoMRwJmJerT9aw4FEhIbZStWN8A3qMwOp1uzHr4UL8AInxtA==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], + "node_modules/micromark-extension-gfm": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm/-/micromark-extension-gfm-3.0.0.tgz", + "integrity": "sha512-vsKArQsicm7t0z2GugkCKtZehqUm31oeGBV/KVSorWSy8ZlNAv7ytjFhvaryUiCUJYqs+NoE6AFhpQvBTM6Q4w==", + "dependencies": { + "micromark-extension-gfm-autolink-literal": "^2.0.0", + "micromark-extension-gfm-footnote": "^2.0.0", + "micromark-extension-gfm-strikethrough": "^2.0.0", + "micromark-extension-gfm-table": "^2.0.0", + "micromark-extension-gfm-tagfilter": "^2.0.0", + "micromark-extension-gfm-task-list-item": "^2.0.0", + "micromark-util-combine-extensions": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-autolink-literal": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-autolink-literal/-/micromark-extension-gfm-autolink-literal-2.1.0.tgz", + "integrity": "sha512-oOg7knzhicgQ3t4QCjCWgTmfNhvQbDDnJeVu9v81r7NltNCVmhPy1fJRX27pISafdjL+SVc4d3l48Gb6pbRypw==", "dependencies": { "micromark-util-character": "^2.0.0", + "micromark-util-sanitize-uri": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/micromark-extension-gfm-footnote/node_modules/micromark-factory-label": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-factory-label/-/micromark-factory-label-2.0.0.tgz", - "integrity": "sha512-RR3i96ohZGde//4WSe/dJsxOX6vxIg9TimLAS3i4EhBAFx8Sm5SmqVfR8E87DPSR31nEAjZfbt91OMZWcNgdZw==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], + "node_modules/micromark-extension-gfm-footnote": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-footnote/-/micromark-extension-gfm-footnote-2.1.0.tgz", + "integrity": "sha512-/yPhxI1ntnDNsiHtzLKYnE3vf9JZ6cAisqVDauhp4CEHxlb4uoOTxOCJ+9s51bIB8U1N1FJ1RXOKTIlD5B/gqw==", "dependencies": { "devlop": "^1.0.0", + "micromark-core-commonmark": "^2.0.0", + "micromark-factory-space": "^2.0.0", "micromark-util-character": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-sanitize-uri": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/micromark-extension-gfm-footnote/node_modules/micromark-factory-space": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.0.tgz", - "integrity": "sha512-TKr+LIDX2pkBJXFLzpyPyljzYK3MtmllMUMODTQJIUfDGncESaqB90db9IAUcz4AZAJFdd8U9zOp9ty1458rxg==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], + "node_modules/micromark-extension-gfm-strikethrough": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-strikethrough/-/micromark-extension-gfm-strikethrough-2.1.0.tgz", + "integrity": "sha512-ADVjpOOkjz1hhkZLlBiYA9cR2Anf8F4HqZUO6e5eDcPQd0Txw5fxLzzxnEkSkfnD0wziSGiv7sYhk/ktvbf1uw==", "dependencies": { - "micromark-util-character": "^2.0.0", + "devlop": "^1.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-classify-character": "^2.0.0", + "micromark-util-resolve-all": "^2.0.0", + "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/micromark-extension-gfm-footnote/node_modules/micromark-factory-title": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-factory-title/-/micromark-factory-title-2.0.0.tgz", - "integrity": "sha512-jY8CSxmpWLOxS+t8W+FG3Xigc0RDQA9bKMY/EwILvsesiRniiVMejYTE4wumNc2f4UbAa4WsHqe3J1QS1sli+A==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], + "node_modules/micromark-extension-gfm-table": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-table/-/micromark-extension-gfm-table-2.1.0.tgz", + "integrity": "sha512-Ub2ncQv+fwD70/l4ou27b4YzfNaCJOvyX4HxXU15m7mpYY+rjuWzsLIPZHJL253Z643RpbcP1oeIJlQ/SKW67g==", "dependencies": { + "devlop": "^1.0.0", "micromark-factory-space": "^2.0.0", "micromark-util-character": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/micromark-extension-gfm-footnote/node_modules/micromark-factory-whitespace": { + "node_modules/micromark-extension-gfm-tagfilter": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-factory-whitespace/-/micromark-factory-whitespace-2.0.0.tgz", - "integrity": "sha512-28kbwaBjc5yAI1XadbdPYHX/eDnqaUFVikLwrO7FDnKG7lpgxnvk/XGRhX/PN0mOZ+dBSZ+LgunHS+6tYQAzhA==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-tagfilter/-/micromark-extension-gfm-tagfilter-2.0.0.tgz", + "integrity": "sha512-xHlTOmuCSotIA8TW1mDIM6X2O1SiX5P9IuDtqGonFhEK0qgRI4yeC6vMxEV2dgyr2TiD+2PQ10o+cOhdVAcwfg==", "dependencies": { - "micromark-factory-space": "^2.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/micromark-extension-gfm-footnote/node_modules/micromark-util-character": { + "node_modules/micromark-extension-gfm-task-list-item": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.0.tgz", - "integrity": "sha512-KvOVV+X1yLBfs9dCBSopq/+G1PcgT3lAK07mC4BzXi5E7ahzMAF8oIupDDJ6mievI6F+lAATkbQQlQixJfT3aQ==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-task-list-item/-/micromark-extension-gfm-task-list-item-2.1.0.tgz", + "integrity": "sha512-qIBZhqxqI6fjLDYFTBIa4eivDMnP+OZqsNwmQ3xNLE4Cxwc+zfQEfbs6tzAo2Hjq+bh6q5F+Z8/cksrLFYWQQw==", "dependencies": { + "devlop": "^1.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/micromark-extension-gfm-footnote/node_modules/micromark-util-chunked": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-chunked/-/micromark-util-chunked-2.0.0.tgz", - "integrity": "sha512-anK8SWmNphkXdaKgz5hJvGa7l00qmcaUQoMYsBwDlSKFKjc6gjGXPDw3FNL3Nbwq5L8gE+RCbGqTw49FK5Qyvg==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], + "node_modules/micromark-extension-math": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/micromark-extension-math/-/micromark-extension-math-3.1.0.tgz", + "integrity": "sha512-lvEqd+fHjATVs+2v/8kg9i5Q0AP2k85H0WUOwpIVvUML8BapsMvh1XAogmQjOCsLpoKRCVQqEkQBB3NhVBcsOg==", "dependencies": { - "micromark-util-symbol": "^2.0.0" + "@types/katex": "^0.16.0", + "devlop": "^1.0.0", + "katex": "^0.16.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/micromark-extension-gfm-footnote/node_modules/micromark-util-classify-character": { + "node_modules/micromark-factory-destination": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-classify-character/-/micromark-util-classify-character-2.0.0.tgz", - "integrity": "sha512-S0ze2R9GH+fu41FA7pbSqNWObo/kzwf8rN/+IGlW/4tC6oACOs8B++bh+i9bVyNnwCcuksbFwsBme5OCKXCwIw==", + "resolved": "https://registry.npmjs.org/micromark-factory-destination/-/micromark-factory-destination-2.0.0.tgz", + "integrity": "sha512-j9DGrQLm/Uhl2tCzcbLhy5kXsgkHUrjJHg4fFAeoMRwJmJerT9aw4FEhIbZStWN8A3qMwOp1uzHr4UL8AInxtA==", "funding": [ { "type": "GitHub Sponsors", @@ -27941,40 +23514,10 @@ "micromark-util-types": "^2.0.0" } }, - "node_modules/micromark-extension-gfm-footnote/node_modules/micromark-util-encode": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-encode/-/micromark-util-encode-2.0.0.tgz", - "integrity": "sha512-pS+ROfCXAGLWCOc8egcBvT0kf27GoWMqtdarNfDcjb6YLuV5cM3ioG45Ys2qOVqeqSbjaKg72vU+Wby3eddPsA==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ] - }, - "node_modules/micromark-extension-gfm-footnote/node_modules/micromark-util-html-tag-name": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-html-tag-name/-/micromark-util-html-tag-name-2.0.0.tgz", - "integrity": "sha512-xNn4Pqkj2puRhKdKTm8t1YHC/BAjx6CEwRFXntTaRf/x16aqka6ouVoutm+QdkISTlT7e2zU7U4ZdlDLJd2Mcw==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ] - }, - "node_modules/micromark-extension-gfm-footnote/node_modules/micromark-util-normalize-identifier": { + "node_modules/micromark-factory-label": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-normalize-identifier/-/micromark-util-normalize-identifier-2.0.0.tgz", - "integrity": "sha512-2xhYT0sfo85FMrUPtHcPo2rrp1lwbDEEzpx7jiH2xXJLqBuy4H0GgXk5ToU8IEwoROtXuL8ND0ttVa4rNqYK3w==", + "resolved": "https://registry.npmjs.org/micromark-factory-label/-/micromark-factory-label-2.0.0.tgz", + "integrity": "sha512-RR3i96ohZGde//4WSe/dJsxOX6vxIg9TimLAS3i4EhBAFx8Sm5SmqVfR8E87DPSR31nEAjZfbt91OMZWcNgdZw==", "funding": [ { "type": "GitHub Sponsors", @@ -27986,13 +23529,16 @@ } ], "dependencies": { - "micromark-util-symbol": "^2.0.0" + "devlop": "^1.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" } }, - "node_modules/micromark-extension-gfm-footnote/node_modules/micromark-util-resolve-all": { + "node_modules/micromark-factory-space": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-resolve-all/-/micromark-util-resolve-all-2.0.0.tgz", - "integrity": "sha512-6KU6qO7DZ7GJkaCgwBNtplXCvGkJToU86ybBAUdavvgsCiG8lSSvYxr9MhwmQ+udpzywHsl4RpGJsYWG1pDOcA==", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.0.tgz", + "integrity": "sha512-TKr+LIDX2pkBJXFLzpyPyljzYK3MtmllMUMODTQJIUfDGncESaqB90db9IAUcz4AZAJFdd8U9zOp9ty1458rxg==", "funding": [ { "type": "GitHub Sponsors", @@ -28004,13 +23550,14 @@ } ], "dependencies": { + "micromark-util-character": "^2.0.0", "micromark-util-types": "^2.0.0" } }, - "node_modules/micromark-extension-gfm-footnote/node_modules/micromark-util-sanitize-uri": { + "node_modules/micromark-factory-title": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-2.0.0.tgz", - "integrity": "sha512-WhYv5UEcZrbAtlsnPuChHUAsu/iBPOVaEVsntLBIdpibO0ddy8OzavZz3iL2xVvBZOpolujSliP65Kq0/7KIYw==", + "resolved": "https://registry.npmjs.org/micromark-factory-title/-/micromark-factory-title-2.0.0.tgz", + "integrity": "sha512-jY8CSxmpWLOxS+t8W+FG3Xigc0RDQA9bKMY/EwILvsesiRniiVMejYTE4wumNc2f4UbAa4WsHqe3J1QS1sli+A==", "funding": [ { "type": "GitHub Sponsors", @@ -28022,51 +23569,16 @@ } ], "dependencies": { + "micromark-factory-space": "^2.0.0", "micromark-util-character": "^2.0.0", - "micromark-util-encode": "^2.0.0", - "micromark-util-symbol": "^2.0.0" - } - }, - "node_modules/micromark-extension-gfm-footnote/node_modules/micromark-util-subtokenize": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-subtokenize/-/micromark-util-subtokenize-2.0.1.tgz", - "integrity": "sha512-jZNtiFl/1aY73yS3UGQkutD0UbhTt68qnRpw2Pifmz5wV9h8gOVsN70v+Lq/f1rKaU/W8pxRe8y8Q9FX1AOe1Q==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "devlop": "^1.0.0", - "micromark-util-chunked": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0" } }, - "node_modules/micromark-extension-gfm-footnote/node_modules/micromark-util-symbol": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", - "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ] - }, - "node_modules/micromark-extension-gfm-footnote/node_modules/micromark-util-types": { + "node_modules/micromark-factory-whitespace": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-2.0.0.tgz", - "integrity": "sha512-oNh6S2WMHWRZrmutsRmDDfkzKtxF+bc2VxLC9dvtrDIRFln627VsFP6fLMgTryGDljgLPjkrzQSDcPrjPyDJ5w==", + "resolved": "https://registry.npmjs.org/micromark-factory-whitespace/-/micromark-factory-whitespace-2.0.0.tgz", + "integrity": "sha512-28kbwaBjc5yAI1XadbdPYHX/eDnqaUFVikLwrO7FDnKG7lpgxnvk/XGRhX/PN0mOZ+dBSZ+LgunHS+6tYQAzhA==", "funding": [ { "type": "GitHub Sponsors", @@ -28076,26 +23588,15 @@ "type": "OpenCollective", "url": "https://opencollective.com/unified" } - ] - }, - "node_modules/micromark-extension-gfm-strikethrough": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/micromark-extension-gfm-strikethrough/-/micromark-extension-gfm-strikethrough-2.1.0.tgz", - "integrity": "sha512-ADVjpOOkjz1hhkZLlBiYA9cR2Anf8F4HqZUO6e5eDcPQd0Txw5fxLzzxnEkSkfnD0wziSGiv7sYhk/ktvbf1uw==", + ], "dependencies": { - "devlop": "^1.0.0", - "micromark-util-chunked": "^2.0.0", - "micromark-util-classify-character": "^2.0.0", - "micromark-util-resolve-all": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" } }, - "node_modules/micromark-extension-gfm-strikethrough/node_modules/micromark-util-character": { + "node_modules/micromark-util-character": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.0.tgz", "integrity": "sha512-KvOVV+X1yLBfs9dCBSopq/+G1PcgT3lAK07mC4BzXi5E7ahzMAF8oIupDDJ6mievI6F+lAATkbQQlQixJfT3aQ==", @@ -28114,7 +23615,7 @@ "micromark-util-types": "^2.0.0" } }, - "node_modules/micromark-extension-gfm-strikethrough/node_modules/micromark-util-chunked": { + "node_modules/micromark-util-chunked": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/micromark-util-chunked/-/micromark-util-chunked-2.0.0.tgz", "integrity": "sha512-anK8SWmNphkXdaKgz5hJvGa7l00qmcaUQoMYsBwDlSKFKjc6gjGXPDw3FNL3Nbwq5L8gE+RCbGqTw49FK5Qyvg==", @@ -28132,7 +23633,7 @@ "micromark-util-symbol": "^2.0.0" } }, - "node_modules/micromark-extension-gfm-strikethrough/node_modules/micromark-util-classify-character": { + "node_modules/micromark-util-classify-character": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/micromark-util-classify-character/-/micromark-util-classify-character-2.0.0.tgz", "integrity": "sha512-S0ze2R9GH+fu41FA7pbSqNWObo/kzwf8rN/+IGlW/4tC6oACOs8B++bh+i9bVyNnwCcuksbFwsBme5OCKXCwIw==", @@ -28152,74 +23653,10 @@ "micromark-util-types": "^2.0.0" } }, - "node_modules/micromark-extension-gfm-strikethrough/node_modules/micromark-util-resolve-all": { + "node_modules/micromark-util-combine-extensions": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-resolve-all/-/micromark-util-resolve-all-2.0.0.tgz", - "integrity": "sha512-6KU6qO7DZ7GJkaCgwBNtplXCvGkJToU86ybBAUdavvgsCiG8lSSvYxr9MhwmQ+udpzywHsl4RpGJsYWG1pDOcA==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/micromark-extension-gfm-strikethrough/node_modules/micromark-util-symbol": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", - "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ] - }, - "node_modules/micromark-extension-gfm-strikethrough/node_modules/micromark-util-types": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-2.0.0.tgz", - "integrity": "sha512-oNh6S2WMHWRZrmutsRmDDfkzKtxF+bc2VxLC9dvtrDIRFln627VsFP6fLMgTryGDljgLPjkrzQSDcPrjPyDJ5w==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ] - }, - "node_modules/micromark-extension-gfm-table": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/micromark-extension-gfm-table/-/micromark-extension-gfm-table-2.1.0.tgz", - "integrity": "sha512-Ub2ncQv+fwD70/l4ou27b4YzfNaCJOvyX4HxXU15m7mpYY+rjuWzsLIPZHJL253Z643RpbcP1oeIJlQ/SKW67g==", - "dependencies": { - "devlop": "^1.0.0", - "micromark-factory-space": "^2.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/micromark-extension-gfm-table/node_modules/micromark-factory-space": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.0.tgz", - "integrity": "sha512-TKr+LIDX2pkBJXFLzpyPyljzYK3MtmllMUMODTQJIUfDGncESaqB90db9IAUcz4AZAJFdd8U9zOp9ty1458rxg==", + "resolved": "https://registry.npmjs.org/micromark-util-combine-extensions/-/micromark-util-combine-extensions-2.0.0.tgz", + "integrity": "sha512-vZZio48k7ON0fVS3CUgFatWHoKbbLTK/rT7pzpJ4Bjp5JjkZeasRfrS9wsBdDJK2cJLHMckXZdzPSSr1B8a4oQ==", "funding": [ { "type": "GitHub Sponsors", @@ -28231,14 +23668,14 @@ } ], "dependencies": { - "micromark-util-character": "^2.0.0", + "micromark-util-chunked": "^2.0.0", "micromark-util-types": "^2.0.0" } }, - "node_modules/micromark-extension-gfm-table/node_modules/micromark-util-character": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.0.tgz", - "integrity": "sha512-KvOVV+X1yLBfs9dCBSopq/+G1PcgT3lAK07mC4BzXi5E7ahzMAF8oIupDDJ6mievI6F+lAATkbQQlQixJfT3aQ==", + "node_modules/micromark-util-decode-numeric-character-reference": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-decode-numeric-character-reference/-/micromark-util-decode-numeric-character-reference-2.0.1.tgz", + "integrity": "sha512-bmkNc7z8Wn6kgjZmVHOX3SowGmVdhYS7yBpMnuMnPzDq/6xwVA604DuOXMZTO1lvq01g+Adfa0pE2UKGlxL1XQ==", "funding": [ { "type": "GitHub Sponsors", @@ -28250,87 +23687,13 @@ } ], "dependencies": { - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/micromark-extension-gfm-table/node_modules/micromark-util-symbol": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", - "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ] - }, - "node_modules/micromark-extension-gfm-table/node_modules/micromark-util-types": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-2.0.0.tgz", - "integrity": "sha512-oNh6S2WMHWRZrmutsRmDDfkzKtxF+bc2VxLC9dvtrDIRFln627VsFP6fLMgTryGDljgLPjkrzQSDcPrjPyDJ5w==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ] - }, - "node_modules/micromark-extension-gfm-tagfilter": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-extension-gfm-tagfilter/-/micromark-extension-gfm-tagfilter-2.0.0.tgz", - "integrity": "sha512-xHlTOmuCSotIA8TW1mDIM6X2O1SiX5P9IuDtqGonFhEK0qgRI4yeC6vMxEV2dgyr2TiD+2PQ10o+cOhdVAcwfg==", - "dependencies": { - "micromark-util-types": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/micromark-extension-gfm-tagfilter/node_modules/micromark-util-types": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-2.0.0.tgz", - "integrity": "sha512-oNh6S2WMHWRZrmutsRmDDfkzKtxF+bc2VxLC9dvtrDIRFln627VsFP6fLMgTryGDljgLPjkrzQSDcPrjPyDJ5w==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ] - }, - "node_modules/micromark-extension-gfm-task-list-item": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/micromark-extension-gfm-task-list-item/-/micromark-extension-gfm-task-list-item-2.1.0.tgz", - "integrity": "sha512-qIBZhqxqI6fjLDYFTBIa4eivDMnP+OZqsNwmQ3xNLE4Cxwc+zfQEfbs6tzAo2Hjq+bh6q5F+Z8/cksrLFYWQQw==", - "dependencies": { - "devlop": "^1.0.0", - "micromark-factory-space": "^2.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "micromark-util-symbol": "^2.0.0" } }, - "node_modules/micromark-extension-gfm-task-list-item/node_modules/micromark-factory-space": { + "node_modules/micromark-util-decode-string": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.0.tgz", - "integrity": "sha512-TKr+LIDX2pkBJXFLzpyPyljzYK3MtmllMUMODTQJIUfDGncESaqB90db9IAUcz4AZAJFdd8U9zOp9ty1458rxg==", + "resolved": "https://registry.npmjs.org/micromark-util-decode-string/-/micromark-util-decode-string-2.0.0.tgz", + "integrity": "sha512-r4Sc6leeUTn3P6gk20aFMj2ntPwn6qpDZqWvYmAG6NgvFTIlj4WtrAudLi65qYoaGdXYViXYw2pkmn7QnIFasA==", "funding": [ { "type": "GitHub Sponsors", @@ -28342,33 +23705,16 @@ } ], "dependencies": { + "decode-named-character-reference": "^1.0.0", "micromark-util-character": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/micromark-extension-gfm-task-list-item/node_modules/micromark-util-character": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.0.tgz", - "integrity": "sha512-KvOVV+X1yLBfs9dCBSopq/+G1PcgT3lAK07mC4BzXi5E7ahzMAF8oIupDDJ6mievI6F+lAATkbQQlQixJfT3aQ==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" + "micromark-util-decode-numeric-character-reference": "^2.0.0", + "micromark-util-symbol": "^2.0.0" } }, - "node_modules/micromark-extension-gfm-task-list-item/node_modules/micromark-util-symbol": { + "node_modules/micromark-util-encode": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", - "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==", + "resolved": "https://registry.npmjs.org/micromark-util-encode/-/micromark-util-encode-2.0.0.tgz", + "integrity": "sha512-pS+ROfCXAGLWCOc8egcBvT0kf27GoWMqtdarNfDcjb6YLuV5cM3ioG45Ys2qOVqeqSbjaKg72vU+Wby3eddPsA==", "funding": [ { "type": "GitHub Sponsors", @@ -28380,10 +23726,10 @@ } ] }, - "node_modules/micromark-extension-gfm-task-list-item/node_modules/micromark-util-types": { + "node_modules/micromark-util-html-tag-name": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-2.0.0.tgz", - "integrity": "sha512-oNh6S2WMHWRZrmutsRmDDfkzKtxF+bc2VxLC9dvtrDIRFln627VsFP6fLMgTryGDljgLPjkrzQSDcPrjPyDJ5w==", + "resolved": "https://registry.npmjs.org/micromark-util-html-tag-name/-/micromark-util-html-tag-name-2.0.0.tgz", + "integrity": "sha512-xNn4Pqkj2puRhKdKTm8t1YHC/BAjx6CEwRFXntTaRf/x16aqka6ouVoutm+QdkISTlT7e2zU7U4ZdlDLJd2Mcw==", "funding": [ { "type": "GitHub Sponsors", @@ -28395,10 +23741,10 @@ } ] }, - "node_modules/micromark-extension-gfm/node_modules/micromark-util-chunked": { + "node_modules/micromark-util-normalize-identifier": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-chunked/-/micromark-util-chunked-2.0.0.tgz", - "integrity": "sha512-anK8SWmNphkXdaKgz5hJvGa7l00qmcaUQoMYsBwDlSKFKjc6gjGXPDw3FNL3Nbwq5L8gE+RCbGqTw49FK5Qyvg==", + "resolved": "https://registry.npmjs.org/micromark-util-normalize-identifier/-/micromark-util-normalize-identifier-2.0.0.tgz", + "integrity": "sha512-2xhYT0sfo85FMrUPtHcPo2rrp1lwbDEEzpx7jiH2xXJLqBuy4H0GgXk5ToU8IEwoROtXuL8ND0ttVa4rNqYK3w==", "funding": [ { "type": "GitHub Sponsors", @@ -28413,10 +23759,10 @@ "micromark-util-symbol": "^2.0.0" } }, - "node_modules/micromark-extension-gfm/node_modules/micromark-util-combine-extensions": { + "node_modules/micromark-util-resolve-all": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-combine-extensions/-/micromark-util-combine-extensions-2.0.0.tgz", - "integrity": "sha512-vZZio48k7ON0fVS3CUgFatWHoKbbLTK/rT7pzpJ4Bjp5JjkZeasRfrS9wsBdDJK2cJLHMckXZdzPSSr1B8a4oQ==", + "resolved": "https://registry.npmjs.org/micromark-util-resolve-all/-/micromark-util-resolve-all-2.0.0.tgz", + "integrity": "sha512-6KU6qO7DZ7GJkaCgwBNtplXCvGkJToU86ybBAUdavvgsCiG8lSSvYxr9MhwmQ+udpzywHsl4RpGJsYWG1pDOcA==", "funding": [ { "type": "GitHub Sponsors", @@ -28428,62 +23774,13 @@ } ], "dependencies": { - "micromark-util-chunked": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/micromark-extension-gfm/node_modules/micromark-util-symbol": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", - "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ] - }, - "node_modules/micromark-extension-gfm/node_modules/micromark-util-types": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-2.0.0.tgz", - "integrity": "sha512-oNh6S2WMHWRZrmutsRmDDfkzKtxF+bc2VxLC9dvtrDIRFln627VsFP6fLMgTryGDljgLPjkrzQSDcPrjPyDJ5w==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ] - }, - "node_modules/micromark-extension-math": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/micromark-extension-math/-/micromark-extension-math-3.1.0.tgz", - "integrity": "sha512-lvEqd+fHjATVs+2v/8kg9i5Q0AP2k85H0WUOwpIVvUML8BapsMvh1XAogmQjOCsLpoKRCVQqEkQBB3NhVBcsOg==", - "dependencies": { - "@types/katex": "^0.16.0", - "devlop": "^1.0.0", - "katex": "^0.16.0", - "micromark-factory-space": "^2.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" } }, - "node_modules/micromark-extension-math/node_modules/micromark-factory-space": { + "node_modules/micromark-util-sanitize-uri": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.0.tgz", - "integrity": "sha512-TKr+LIDX2pkBJXFLzpyPyljzYK3MtmllMUMODTQJIUfDGncESaqB90db9IAUcz4AZAJFdd8U9zOp9ty1458rxg==", + "resolved": "https://registry.npmjs.org/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-2.0.0.tgz", + "integrity": "sha512-WhYv5UEcZrbAtlsnPuChHUAsu/iBPOVaEVsntLBIdpibO0ddy8OzavZz3iL2xVvBZOpolujSliP65Kq0/7KIYw==", "funding": [ { "type": "GitHub Sponsors", @@ -28496,13 +23793,14 @@ ], "dependencies": { "micromark-util-character": "^2.0.0", - "micromark-util-types": "^2.0.0" + "micromark-util-encode": "^2.0.0", + "micromark-util-symbol": "^2.0.0" } }, - "node_modules/micromark-extension-math/node_modules/micromark-util-character": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.0.tgz", - "integrity": "sha512-KvOVV+X1yLBfs9dCBSopq/+G1PcgT3lAK07mC4BzXi5E7ahzMAF8oIupDDJ6mievI6F+lAATkbQQlQixJfT3aQ==", + "node_modules/micromark-util-subtokenize": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-subtokenize/-/micromark-util-subtokenize-2.0.1.tgz", + "integrity": "sha512-jZNtiFl/1aY73yS3UGQkutD0UbhTt68qnRpw2Pifmz5wV9h8gOVsN70v+Lq/f1rKaU/W8pxRe8y8Q9FX1AOe1Q==", "funding": [ { "type": "GitHub Sponsors", @@ -28514,11 +23812,13 @@ } ], "dependencies": { + "devlop": "^1.0.0", + "micromark-util-chunked": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0" } }, - "node_modules/micromark-extension-math/node_modules/micromark-util-symbol": { + "node_modules/micromark-util-symbol": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==", @@ -28533,7 +23833,7 @@ } ] }, - "node_modules/micromark-extension-math/node_modules/micromark-util-types": { + "node_modules/micromark-util-types": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-2.0.0.tgz", "integrity": "sha512-oNh6S2WMHWRZrmutsRmDDfkzKtxF+bc2VxLC9dvtrDIRFln627VsFP6fLMgTryGDljgLPjkrzQSDcPrjPyDJ5w==", @@ -28610,14 +23910,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/min-document": { - "version": "2.19.0", - "resolved": "https://registry.npmjs.org/min-document/-/min-document-2.19.0.tgz", - "integrity": "sha512-9Wy1B3m3f66bPPmU5hdA4DR4PB2OfDU/+GS3yAB7IQozE3tqXaVv2zOjgla7MEGSRv95+ILmOuvhLkOK6wJtCQ==", - "dependencies": { - "dom-walk": "^0.1.0" - } - }, "node_modules/minimalistic-assert": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", @@ -28960,13 +24252,13 @@ } }, "node_modules/mongoose": { - "version": "8.5.4", - "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-8.5.4.tgz", - "integrity": "sha512-nG3eehhWf9l1q80WuHvp5DV+4xDNFpDWLE5ZgcFD5tslUV2USJ56ogun8gaZ62MKAocJnoStjAdno08b8U57hg==", + "version": "8.6.0", + "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-8.6.0.tgz", + "integrity": "sha512-p6VSbYKvD4ZIabqo8C0kS5eKX1Xpji+opTAIJ9wyuPJ8Y/FblgXSMnFRXnB40bYZLKPQT089K5KU8+bqIXtFdw==", "dependencies": { "bson": "^6.7.0", "kareem": "2.6.3", - "mongodb": "6.7.0", + "mongodb": "6.8.0", "mpath": "0.9.0", "mquery": "5.0.0", "ms": "2.1.3", @@ -28980,51 +24272,6 @@ "url": "https://opencollective.com/mongoose" } }, - "node_modules/mongoose/node_modules/mongodb": { - "version": "6.7.0", - "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-6.7.0.tgz", - "integrity": "sha512-TMKyHdtMcO0fYBNORiYdmM25ijsHs+Njs963r4Tro4OQZzqYigAzYQouwWRg4OIaiLRUEGUh/1UAcH5lxdSLIA==", - "dependencies": { - "@mongodb-js/saslprep": "^1.1.5", - "bson": "^6.7.0", - "mongodb-connection-string-url": "^3.0.0" - }, - "engines": { - "node": ">=16.20.1" - }, - "peerDependencies": { - "@aws-sdk/credential-providers": "^3.188.0", - "@mongodb-js/zstd": "^1.1.0", - "gcp-metadata": "^5.2.0", - "kerberos": "^2.0.1", - "mongodb-client-encryption": ">=6.0.0 <7", - "snappy": "^7.2.2", - "socks": "^2.7.1" - }, - "peerDependenciesMeta": { - "@aws-sdk/credential-providers": { - "optional": true - }, - "@mongodb-js/zstd": { - "optional": true - }, - "gcp-metadata": { - "optional": true - }, - "kerberos": { - "optional": true - }, - "mongodb-client-encryption": { - "optional": true - }, - "snappy": { - "optional": true - }, - "socks": { - "optional": true - } - } - }, "node_modules/mongoose/node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", @@ -29393,9 +24640,9 @@ } }, "node_modules/npm": { - "version": "10.8.2", - "resolved": "https://registry.npmjs.org/npm/-/npm-10.8.2.tgz", - "integrity": "sha512-x/AIjFIKRllrhcb48dqUNAAZl0ig9+qMuN91RpZo3Cb2+zuibfh+KISl6+kVVyktDz230JKc208UkQwwMqyB+w==", + "version": "10.8.3", + "resolved": "https://registry.npmjs.org/npm/-/npm-10.8.3.tgz", + "integrity": "sha512-0IQlyAYvVtQ7uOhDFYZCGK8kkut2nh8cpAdA9E6FvRSJaTgtZRZgNjlC5ZCct//L73ygrpY93CxXpRJDtNqPVg==", "bundleDependencies": [ "@isaacs/string-locale-compare", "@npmcli/arborist", @@ -29486,13 +24733,13 @@ "@sigstore/tuf": "^2.3.4", "abbrev": "^2.0.0", "archy": "~1.0.0", - "cacache": "^18.0.3", + "cacache": "^18.0.4", "chalk": "^5.3.0", "ci-info": "^4.0.0", "cli-columns": "^4.0.0", "fastest-levenshtein": "^1.0.16", "fs-minipass": "^3.0.3", - "glob": "^10.4.2", + "glob": "^10.4.5", "graceful-fs": "^4.2.11", "hosted-git-info": "^7.0.2", "ini": "^4.1.3", @@ -29501,7 +24748,7 @@ "json-parse-even-better-errors": "^3.0.2", "libnpmaccess": "^8.0.6", "libnpmdiff": "^6.1.4", - "libnpmexec": "^8.1.3", + "libnpmexec": "^8.1.4", "libnpmfund": "^5.0.12", "libnpmhook": "^10.0.5", "libnpmorg": "^6.0.6", @@ -29515,12 +24762,12 @@ "minipass": "^7.1.1", "minipass-pipeline": "^1.2.4", "ms": "^2.1.2", - "node-gyp": "^10.1.0", + "node-gyp": "^10.2.0", "nopt": "^7.2.1", "normalize-package-data": "^6.0.2", "npm-audit-report": "^5.0.0", "npm-install-checks": "^6.3.0", - "npm-package-arg": "^11.0.2", + "npm-package-arg": "^11.0.3", "npm-pick-manifest": "^9.1.0", "npm-profile": "^10.0.0", "npm-registry-fetch": "^17.1.0", @@ -29531,7 +24778,7 @@ "proc-log": "^4.2.0", "qrcode-terminal": "^0.12.0", "read": "^3.0.1", - "semver": "^7.6.2", + "semver": "^7.6.3", "spdx-expression-parse": "^4.0.0", "ssri": "^10.0.6", "supports-color": "^9.4.0", @@ -30060,7 +25307,7 @@ } }, "node_modules/npm/node_modules/cacache": { - "version": "18.0.3", + "version": "18.0.4", "inBundle": true, "license": "ISC", "dependencies": { @@ -30213,7 +25460,7 @@ } }, "node_modules/npm/node_modules/debug": { - "version": "4.3.5", + "version": "4.3.6", "inBundle": true, "license": "MIT", "dependencies": { @@ -30287,7 +25534,7 @@ } }, "node_modules/npm/node_modules/foreground-child": { - "version": "3.2.1", + "version": "3.3.0", "inBundle": true, "license": "ISC", "dependencies": { @@ -30313,7 +25560,7 @@ } }, "node_modules/npm/node_modules/glob": { - "version": "10.4.2", + "version": "10.4.5", "inBundle": true, "license": "ISC", "dependencies": { @@ -30327,9 +25574,6 @@ "bin": { "glob": "dist/esm/bin.mjs" }, - "engines": { - "node": ">=16 || 14 >=14.18" - }, "funding": { "url": "https://github.com/sponsors/isaacs" } @@ -30496,15 +25740,12 @@ "license": "ISC" }, "node_modules/npm/node_modules/jackspeak": { - "version": "3.4.0", + "version": "3.4.3", "inBundle": true, "license": "BlueOak-1.0.0", "dependencies": { "@isaacs/cliui": "^8.0.2" }, - "engines": { - "node": ">=14" - }, "funding": { "url": "https://github.com/sponsors/isaacs" }, @@ -30582,7 +25823,7 @@ } }, "node_modules/npm/node_modules/libnpmexec": { - "version": "8.1.3", + "version": "8.1.4", "inBundle": true, "license": "ISC", "dependencies": { @@ -30707,12 +25948,9 @@ } }, "node_modules/npm/node_modules/lru-cache": { - "version": "10.2.2", + "version": "10.4.3", "inBundle": true, - "license": "ISC", - "engines": { - "node": "14 || >=16.14" - } + "license": "ISC" }, "node_modules/npm/node_modules/make-fetch-happen": { "version": "13.0.1", @@ -30907,7 +26145,7 @@ } }, "node_modules/npm/node_modules/node-gyp": { - "version": "10.1.0", + "version": "10.2.0", "inBundle": true, "license": "MIT", "dependencies": { @@ -30917,9 +26155,9 @@ "graceful-fs": "^4.2.6", "make-fetch-happen": "^13.0.0", "nopt": "^7.0.0", - "proc-log": "^3.0.0", + "proc-log": "^4.1.0", "semver": "^7.3.5", - "tar": "^6.1.2", + "tar": "^6.2.1", "which": "^4.0.0" }, "bin": { @@ -30929,14 +26167,6 @@ "node": "^16.14.0 || >=18.0.0" } }, - "node_modules/npm/node_modules/node-gyp/node_modules/proc-log": { - "version": "3.0.0", - "inBundle": true, - "license": "ISC", - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, "node_modules/npm/node_modules/nopt": { "version": "7.2.1", "inBundle": true, @@ -31003,7 +26233,7 @@ } }, "node_modules/npm/node_modules/npm-package-arg": { - "version": "11.0.2", + "version": "11.0.3", "inBundle": true, "license": "ISC", "dependencies": { @@ -31165,7 +26395,7 @@ } }, "node_modules/npm/node_modules/postcss-selector-parser": { - "version": "6.1.0", + "version": "6.1.2", "inBundle": true, "license": "MIT", "dependencies": { @@ -31289,7 +26519,7 @@ "optional": true }, "node_modules/npm/node_modules/semver": { - "version": "7.6.2", + "version": "7.6.3", "inBundle": true, "license": "ISC", "bin": { @@ -32043,17 +27273,19 @@ } }, "node_modules/openai": { - "version": "4.56.0", - "resolved": "https://registry.npmjs.org/openai/-/openai-4.56.0.tgz", - "integrity": "sha512-zcag97+3bG890MNNa0DQD9dGmmTWL8unJdNkulZzWRXrl+QeD+YkBI4H58rJcwErxqGK6a0jVPZ4ReJjhDGcmw==", + "version": "4.57.0", + "resolved": "https://registry.npmjs.org/openai/-/openai-4.57.0.tgz", + "integrity": "sha512-JnwBSIYqiZ3jYjB5f2in8hQ0PRA092c6m+/6dYB0MzK0BEbn+0dioxZsPLBm5idJbg9xzLNOiGVm2OSuhZ+BdQ==", "dependencies": { "@types/node": "^18.11.18", "@types/node-fetch": "^2.6.4", + "@types/qs": "^6.9.7", "abort-controller": "^3.0.0", "agentkeepalive": "^4.2.1", "form-data-encoder": "1.7.2", "formdata-node": "^4.3.2", - "node-fetch": "^2.6.7" + "node-fetch": "^2.6.7", + "qs": "^6.10.3" }, "bin": { "openai": "bin/cli" @@ -32068,9 +27300,9 @@ } }, "node_modules/openai/node_modules/@types/node": { - "version": "18.19.46", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.46.tgz", - "integrity": "sha512-vnRgMS7W6cKa1/0G3/DTtQYpVrZ8c0Xm6UkLaVFrb9jtcVC3okokW09Ki1Qdrj9ISokszD69nY4WDLRlvHlhAA==", + "version": "18.19.47", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.47.tgz", + "integrity": "sha512-1f7dB3BL/bpd9tnDJrrHb66Y+cVrhxSOTGorRNdHwYTUlTay3HuTDPKo9a/4vX9pMQkhYBcAbL4jQdNlhCFP9A==", "dependencies": { "undici-types": "~5.26.4" } @@ -32275,10 +27507,10 @@ "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/parse-headers": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/parse-headers/-/parse-headers-2.0.5.tgz", - "integrity": "sha512-ft3iAoLOB/MlwbNXgzy43SWGP6sQki2jQvAyBg/zDFAgr9bfNWZIUj42Kw2eJIl8kEi4PbgE6U1Zau/HwI75HA==" + "node_modules/parse-entities/node_modules/@types/unist": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.11.tgz", + "integrity": "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==" }, "node_modules/parse-json": { "version": "5.2.0", @@ -32617,17 +27849,6 @@ "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", "integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==" }, - "node_modules/phin": { - "version": "3.7.1", - "resolved": "https://registry.npmjs.org/phin/-/phin-3.7.1.tgz", - "integrity": "sha512-GEazpTWwTZaEQ9RhL7Nyz0WwqilbqgLahDM3D0hxWwmVDI52nXEybHqiN6/elwpkJBhcuj+WbBu+QfT0uhPGfQ==", - "dependencies": { - "centra": "^2.7.0" - }, - "engines": { - "node": ">= 8" - } - }, "node_modules/picocolors": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz", @@ -32655,22 +27876,22 @@ "integrity": "sha512-6Rtbp7criZRwedlvWbUYxqlqJoAlMvYHo2UcRWq79xZ54vZcaNHpVBOcWkX3ErT2aUA69tv+uiv4zKJbhD/Wgg==" }, "node_modules/pixelmatch": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/pixelmatch/-/pixelmatch-4.0.2.tgz", - "integrity": "sha512-J8B6xqiO37sU/gkcMglv6h5Jbd9xNER7aHzpfRdNmV4IbQBzBpe4l9XmbG+xPF/znacgu2jfEw+wHffaq/YkXA==", + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/pixelmatch/-/pixelmatch-5.3.0.tgz", + "integrity": "sha512-o8mkY4E/+LNUf6LzX96ht6k6CEDi65k9G2rjMtBe9Oo+VPKSvl+0GKHuH/AlG+GA5LPG/i5hrekkxUc3s2HU+Q==", "dependencies": { - "pngjs": "^3.0.0" + "pngjs": "^6.0.0" }, "bin": { "pixelmatch": "bin/pixelmatch" } }, "node_modules/pixelmatch/node_modules/pngjs": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/pngjs/-/pngjs-3.4.0.tgz", - "integrity": "sha512-NCrCHhWmnQklfH4MtJMRjZ2a8c80qXeMlQMv2uVp9ISJMTt562SbGd6n2oq0PaPgKm7Z6pL9E2UlLIhC+SHL3w==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/pngjs/-/pngjs-6.0.0.tgz", + "integrity": "sha512-TRzzuFRRmEoSW/p1KVAmiOgPco2Irlah+bGFCeNfJXxxYGwSw7YwAOAcd7X28K/m5bjBWKsC29KyoMfHbypayg==", "engines": { - "node": ">=4.0.0" + "node": ">=12.13.0" } }, "node_modules/pkg-dir": { @@ -32761,11 +27982,11 @@ } }, "node_modules/pngjs": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/pngjs/-/pngjs-6.0.0.tgz", - "integrity": "sha512-TRzzuFRRmEoSW/p1KVAmiOgPco2Irlah+bGFCeNfJXxxYGwSw7YwAOAcd7X28K/m5bjBWKsC29KyoMfHbypayg==", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/pngjs/-/pngjs-7.0.0.tgz", + "integrity": "sha512-LKWqWJRhstyYo9pGvgor/ivk2w94eSjE3RGVuzLGlr3NmD8bf7RcYGze1mNdEHRP6TRP6rMuDHk5t44hnTRyow==", "engines": { - "node": ">=12.13.0" + "node": ">=14.19.0" } }, "node_modules/point-in-polygon": { @@ -32810,9 +28031,9 @@ } }, "node_modules/postcss": { - "version": "8.4.41", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.41.tgz", - "integrity": "sha512-TesUflQ0WKZqAvg52PWL6kHgLKP6xB6heTOdoYM0Wt2UHyxNa4K25EZZMgKns3BH1RLVbZCREPpLY0rhnNoHVQ==", + "version": "8.4.42", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.42.tgz", + "integrity": "sha512-hywKUQB9Ra4dR1mGhldy5Aj1X3MWDSIA1cEi+Uy0CjheLvP6Ual5RlwMCh8i/X121yEDLDIKBsrCQ8ba3FDMfQ==", "funding": [ { "type": "opencollective", @@ -34062,29 +29283,6 @@ "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, - "node_modules/readable-stream/node_modules/buffer": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", - "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "dependencies": { - "base64-js": "^1.3.1", - "ieee754": "^1.2.1" - } - }, "node_modules/readable-web-to-node-stream": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/readable-web-to-node-stream/-/readable-web-to-node-stream-3.0.2.tgz", @@ -34165,723 +29363,226 @@ "engines": { "node": ">=14" }, - "peerDependencies": { - "react": "^16.0.0 || ^17.0.0 || ^18.0.0", - "react-dom": "^16.0.0 || ^17.0.0 || ^18.0.0" - } - }, - "node_modules/recharts-scale": { - "version": "0.4.5", - "resolved": "https://registry.npmjs.org/recharts-scale/-/recharts-scale-0.4.5.tgz", - "integrity": "sha512-kivNFO+0OcUNu7jQquLXAxz1FIwZj8nrj+YkOKc5694NbjCvcT6aSZiIzNzd2Kul4o4rTto8QVR9lMNtxD4G1w==", - "dependencies": { - "decimal.js-light": "^2.4.1" - } - }, - "node_modules/recharts/node_modules/react-is": { - "version": "16.13.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" - }, - "node_modules/rechoir": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", - "integrity": "sha512-HFM8rkZ+i3zrV+4LQjwQ0W+ez98pApMGM3HUrN04j3CqzPOzl9nmP15Y8YXNm8QHGv/eacOVEjqhmWpkRV0NAw==", - "dependencies": { - "resolve": "^1.1.6" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/reduce-flatten": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/reduce-flatten/-/reduce-flatten-1.0.1.tgz", - "integrity": "sha512-j5WfFJfc9CoXv/WbwVLHq74i/hdTUpy+iNC534LxczMRP67vJeK3V9JOdnL0N1cIRbn9mYhE2yVjvvKXDxvNXQ==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/reflect.getprototypeof": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.6.tgz", - "integrity": "sha512-fmfw4XgoDke3kdI6h4xcUz1dG8uaiv5q9gcEwLS4Pnth2kxT+GZ7YehS1JTMGBQmtV7Y4GFGbs2re2NqhdozUg==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.1", - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.4", - "globalthis": "^1.0.3", - "which-builtin-type": "^1.1.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/regenerate": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", - "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==" - }, - "node_modules/regenerate-unicode-properties": { - "version": "10.1.1", - "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.1.1.tgz", - "integrity": "sha512-X007RyZLsCJVVrjgEFVpLUTZwyOZk3oiL75ZcuYjlIWd6rNJtOjkBwQc5AsRrpbKVkxN6sklw/k/9m2jJYOf8Q==", - "dependencies": { - "regenerate": "^1.4.2" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/regenerator-runtime": { - "version": "0.14.1", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", - "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==" - }, - "node_modules/regenerator-transform": { - "version": "0.15.2", - "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.15.2.tgz", - "integrity": "sha512-hfMp2BoF0qOk3uc5V20ALGDS2ddjQaLrdl7xrGXvAIow7qeWRM2VA2HuCHkUKk9slq3VwEwLNK3DFBqDfPGYtg==", - "dependencies": { - "@babel/runtime": "^7.8.4" - } - }, - "node_modules/regexp.prototype.flags": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.2.tgz", - "integrity": "sha512-NcDiDkTLuPR+++OCKB0nWafEmhg/Da8aUPLPMQbK+bxKKCm1/S5he+AqYa4PlMCVBalb4/yxIRub6qkEx5yJbw==", - "dependencies": { - "call-bind": "^1.0.6", - "define-properties": "^1.2.1", - "es-errors": "^1.3.0", - "set-function-name": "^2.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/regexpu-core": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-5.3.2.tgz", - "integrity": "sha512-RAM5FlZz+Lhmo7db9L298p2vHP5ZywrVXmVXpmAD9GuL5MPH6t9ROw1iA/wfHkQ76Qe7AaPF0nGuim96/IrQMQ==", - "dependencies": { - "@babel/regjsgen": "^0.8.0", - "regenerate": "^1.4.2", - "regenerate-unicode-properties": "^10.1.0", - "regjsparser": "^0.9.1", - "unicode-match-property-ecmascript": "^2.0.0", - "unicode-match-property-value-ecmascript": "^2.1.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/regjsparser": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.9.1.tgz", - "integrity": "sha512-dQUtn90WanSNl+7mQKcXAgZxvUe7Z0SqXlgzv0za4LwiUhyzBC58yQO3liFoUgu8GiJVInAhJjkj1N0EtQ5nkQ==", - "dependencies": { - "jsesc": "~0.5.0" - }, - "bin": { - "regjsparser": "bin/parser" - } - }, - "node_modules/regjsparser/node_modules/jsesc": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", - "integrity": "sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==", - "bin": { - "jsesc": "bin/jsesc" - } - }, - "node_modules/rehype-katex": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/rehype-katex/-/rehype-katex-7.0.1.tgz", - "integrity": "sha512-OiM2wrZ/wuhKkigASodFoo8wimG3H12LWQaH8qSPVJn9apWKFSH3YOCtbKpBorTVw/eI7cuT21XBbvwEswbIOA==", - "dependencies": { - "@types/hast": "^3.0.0", - "@types/katex": "^0.16.0", - "hast-util-from-html-isomorphic": "^2.0.0", - "hast-util-to-text": "^4.0.0", - "katex": "^0.16.0", - "unist-util-visit-parents": "^6.0.0", - "vfile": "^6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/rehype-raw": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/rehype-raw/-/rehype-raw-7.0.0.tgz", - "integrity": "sha512-/aE8hCfKlQeA8LmyeyQvQF3eBiLRGNlfBJEvWH7ivp9sBqs7TNqBL5X3v157rM4IFETqDnIOO+z5M/biZbo9Ww==", - "dependencies": { - "@types/hast": "^3.0.0", - "hast-util-raw": "^9.0.0", - "vfile": "^6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/relateurl": { - "version": "0.2.7", - "resolved": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz", - "integrity": "sha512-G08Dxvm4iDN3MLM0EsP62EDV9IuhXPR6blNz6Utcp7zyV3tr4HVNINt6MpaRWbxoOHT3Q7YN2P+jaHX8vUbgog==", - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/remark-gfm": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/remark-gfm/-/remark-gfm-4.0.0.tgz", - "integrity": "sha512-U92vJgBPkbw4Zfu/IiW2oTZLSL3Zpv+uI7My2eq8JxKgqraFdU8YUGicEJCEgSbeaG+QDFqIcwwfMTOEelPxuA==", - "dependencies": { - "@types/mdast": "^4.0.0", - "mdast-util-gfm": "^3.0.0", - "micromark-extension-gfm": "^3.0.0", - "remark-parse": "^11.0.0", - "remark-stringify": "^11.0.0", - "unified": "^11.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/remark-gfm/node_modules/@types/mdast": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-4.0.4.tgz", - "integrity": "sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==", - "dependencies": { - "@types/unist": "*" - } - }, - "node_modules/remark-math": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/remark-math/-/remark-math-6.0.0.tgz", - "integrity": "sha512-MMqgnP74Igy+S3WwnhQ7kqGlEerTETXMvJhrUzDikVZ2/uogJCb+WHUg97hK9/jcfc0dkD73s3LN8zU49cTEtA==", - "dependencies": { - "@types/mdast": "^4.0.0", - "mdast-util-math": "^3.0.0", - "micromark-extension-math": "^3.0.0", - "unified": "^11.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/remark-math/node_modules/@types/mdast": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-4.0.4.tgz", - "integrity": "sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==", - "dependencies": { - "@types/unist": "*" - } - }, - "node_modules/remark-parse": { - "version": "11.0.0", - "resolved": "https://registry.npmjs.org/remark-parse/-/remark-parse-11.0.0.tgz", - "integrity": "sha512-FCxlKLNGknS5ba/1lmpYijMUzX2esxW5xQqjWxw2eHFfS2MSdaHVINFmhjo+qN1WhZhNimq0dZATN9pH0IDrpA==", - "dependencies": { - "@types/mdast": "^4.0.0", - "mdast-util-from-markdown": "^2.0.0", - "micromark-util-types": "^2.0.0", - "unified": "^11.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/remark-parse/node_modules/@types/mdast": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-4.0.4.tgz", - "integrity": "sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==", - "dependencies": { - "@types/unist": "*" - } - }, - "node_modules/remark-parse/node_modules/@types/unist": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", - "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==" - }, - "node_modules/remark-parse/node_modules/mdast-util-from-markdown": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/mdast-util-from-markdown/-/mdast-util-from-markdown-2.0.1.tgz", - "integrity": "sha512-aJEUyzZ6TzlsX2s5B4Of7lN7EQtAxvtradMMglCQDyaTFgse6CmtmdJ15ElnVRlCg1vpNyVtbem0PWzlNieZsA==", - "dependencies": { - "@types/mdast": "^4.0.0", - "@types/unist": "^3.0.0", - "decode-named-character-reference": "^1.0.0", - "devlop": "^1.0.0", - "mdast-util-to-string": "^4.0.0", - "micromark": "^4.0.0", - "micromark-util-decode-numeric-character-reference": "^2.0.0", - "micromark-util-decode-string": "^2.0.0", - "micromark-util-normalize-identifier": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0", - "unist-util-stringify-position": "^4.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/remark-parse/node_modules/mdast-util-to-string": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-4.0.0.tgz", - "integrity": "sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg==", - "dependencies": { - "@types/mdast": "^4.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/remark-parse/node_modules/micromark": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/micromark/-/micromark-4.0.0.tgz", - "integrity": "sha512-o/sd0nMof8kYff+TqcDx3VSrgBTcZpSvYcAHIfHhv5VAuNmisCxjhx6YmxS8PFEpb9z5WKWKPdzf0jM23ro3RQ==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "@types/debug": "^4.0.0", - "debug": "^4.0.0", - "decode-named-character-reference": "^1.0.0", - "devlop": "^1.0.0", - "micromark-core-commonmark": "^2.0.0", - "micromark-factory-space": "^2.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-chunked": "^2.0.0", - "micromark-util-combine-extensions": "^2.0.0", - "micromark-util-decode-numeric-character-reference": "^2.0.0", - "micromark-util-encode": "^2.0.0", - "micromark-util-normalize-identifier": "^2.0.0", - "micromark-util-resolve-all": "^2.0.0", - "micromark-util-sanitize-uri": "^2.0.0", - "micromark-util-subtokenize": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/remark-parse/node_modules/micromark-core-commonmark": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-core-commonmark/-/micromark-core-commonmark-2.0.1.tgz", - "integrity": "sha512-CUQyKr1e///ZODyD1U3xit6zXwy1a8q2a1S1HKtIlmgvurrEpaw/Y9y6KSIbF8P59cn/NjzHyO+Q2fAyYLQrAA==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "decode-named-character-reference": "^1.0.0", - "devlop": "^1.0.0", - "micromark-factory-destination": "^2.0.0", - "micromark-factory-label": "^2.0.0", - "micromark-factory-space": "^2.0.0", - "micromark-factory-title": "^2.0.0", - "micromark-factory-whitespace": "^2.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-chunked": "^2.0.0", - "micromark-util-classify-character": "^2.0.0", - "micromark-util-html-tag-name": "^2.0.0", - "micromark-util-normalize-identifier": "^2.0.0", - "micromark-util-resolve-all": "^2.0.0", - "micromark-util-subtokenize": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/remark-parse/node_modules/micromark-factory-destination": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-factory-destination/-/micromark-factory-destination-2.0.0.tgz", - "integrity": "sha512-j9DGrQLm/Uhl2tCzcbLhy5kXsgkHUrjJHg4fFAeoMRwJmJerT9aw4FEhIbZStWN8A3qMwOp1uzHr4UL8AInxtA==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-util-character": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/remark-parse/node_modules/micromark-factory-label": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-factory-label/-/micromark-factory-label-2.0.0.tgz", - "integrity": "sha512-RR3i96ohZGde//4WSe/dJsxOX6vxIg9TimLAS3i4EhBAFx8Sm5SmqVfR8E87DPSR31nEAjZfbt91OMZWcNgdZw==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "devlop": "^1.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/remark-parse/node_modules/micromark-factory-space": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.0.tgz", - "integrity": "sha512-TKr+LIDX2pkBJXFLzpyPyljzYK3MtmllMUMODTQJIUfDGncESaqB90db9IAUcz4AZAJFdd8U9zOp9ty1458rxg==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-util-character": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/remark-parse/node_modules/micromark-factory-title": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-factory-title/-/micromark-factory-title-2.0.0.tgz", - "integrity": "sha512-jY8CSxmpWLOxS+t8W+FG3Xigc0RDQA9bKMY/EwILvsesiRniiVMejYTE4wumNc2f4UbAa4WsHqe3J1QS1sli+A==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-factory-space": "^2.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" + "peerDependencies": { + "react": "^16.0.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.0.0 || ^17.0.0 || ^18.0.0" } }, - "node_modules/remark-parse/node_modules/micromark-factory-whitespace": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-factory-whitespace/-/micromark-factory-whitespace-2.0.0.tgz", - "integrity": "sha512-28kbwaBjc5yAI1XadbdPYHX/eDnqaUFVikLwrO7FDnKG7lpgxnvk/XGRhX/PN0mOZ+dBSZ+LgunHS+6tYQAzhA==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], + "node_modules/recharts-scale": { + "version": "0.4.5", + "resolved": "https://registry.npmjs.org/recharts-scale/-/recharts-scale-0.4.5.tgz", + "integrity": "sha512-kivNFO+0OcUNu7jQquLXAxz1FIwZj8nrj+YkOKc5694NbjCvcT6aSZiIzNzd2Kul4o4rTto8QVR9lMNtxD4G1w==", "dependencies": { - "micromark-factory-space": "^2.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" + "decimal.js-light": "^2.4.1" } }, - "node_modules/remark-parse/node_modules/micromark-util-character": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.0.tgz", - "integrity": "sha512-KvOVV+X1yLBfs9dCBSopq/+G1PcgT3lAK07mC4BzXi5E7ahzMAF8oIupDDJ6mievI6F+lAATkbQQlQixJfT3aQ==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], + "node_modules/recharts/node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" + }, + "node_modules/rechoir": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", + "integrity": "sha512-HFM8rkZ+i3zrV+4LQjwQ0W+ez98pApMGM3HUrN04j3CqzPOzl9nmP15Y8YXNm8QHGv/eacOVEjqhmWpkRV0NAw==", "dependencies": { - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" + "resolve": "^1.1.6" + }, + "engines": { + "node": ">= 0.10" } }, - "node_modules/remark-parse/node_modules/micromark-util-chunked": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-chunked/-/micromark-util-chunked-2.0.0.tgz", - "integrity": "sha512-anK8SWmNphkXdaKgz5hJvGa7l00qmcaUQoMYsBwDlSKFKjc6gjGXPDw3FNL3Nbwq5L8gE+RCbGqTw49FK5Qyvg==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], + "node_modules/reduce-flatten": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/reduce-flatten/-/reduce-flatten-1.0.1.tgz", + "integrity": "sha512-j5WfFJfc9CoXv/WbwVLHq74i/hdTUpy+iNC534LxczMRP67vJeK3V9JOdnL0N1cIRbn9mYhE2yVjvvKXDxvNXQ==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/reflect.getprototypeof": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.6.tgz", + "integrity": "sha512-fmfw4XgoDke3kdI6h4xcUz1dG8uaiv5q9gcEwLS4Pnth2kxT+GZ7YehS1JTMGBQmtV7Y4GFGbs2re2NqhdozUg==", + "dev": true, "dependencies": { - "micromark-util-symbol": "^2.0.0" + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.1", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4", + "globalthis": "^1.0.3", + "which-builtin-type": "^1.1.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/remark-parse/node_modules/micromark-util-classify-character": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-classify-character/-/micromark-util-classify-character-2.0.0.tgz", - "integrity": "sha512-S0ze2R9GH+fu41FA7pbSqNWObo/kzwf8rN/+IGlW/4tC6oACOs8B++bh+i9bVyNnwCcuksbFwsBme5OCKXCwIw==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], + "node_modules/regenerate": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", + "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==" + }, + "node_modules/regenerate-unicode-properties": { + "version": "10.1.1", + "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.1.1.tgz", + "integrity": "sha512-X007RyZLsCJVVrjgEFVpLUTZwyOZk3oiL75ZcuYjlIWd6rNJtOjkBwQc5AsRrpbKVkxN6sklw/k/9m2jJYOf8Q==", "dependencies": { - "micromark-util-character": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" + "regenerate": "^1.4.2" + }, + "engines": { + "node": ">=4" } }, - "node_modules/remark-parse/node_modules/micromark-util-combine-extensions": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-combine-extensions/-/micromark-util-combine-extensions-2.0.0.tgz", - "integrity": "sha512-vZZio48k7ON0fVS3CUgFatWHoKbbLTK/rT7pzpJ4Bjp5JjkZeasRfrS9wsBdDJK2cJLHMckXZdzPSSr1B8a4oQ==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], + "node_modules/regenerator-runtime": { + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", + "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==" + }, + "node_modules/regenerator-transform": { + "version": "0.15.2", + "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.15.2.tgz", + "integrity": "sha512-hfMp2BoF0qOk3uc5V20ALGDS2ddjQaLrdl7xrGXvAIow7qeWRM2VA2HuCHkUKk9slq3VwEwLNK3DFBqDfPGYtg==", "dependencies": { - "micromark-util-chunked": "^2.0.0", - "micromark-util-types": "^2.0.0" + "@babel/runtime": "^7.8.4" } }, - "node_modules/remark-parse/node_modules/micromark-util-decode-numeric-character-reference": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-decode-numeric-character-reference/-/micromark-util-decode-numeric-character-reference-2.0.1.tgz", - "integrity": "sha512-bmkNc7z8Wn6kgjZmVHOX3SowGmVdhYS7yBpMnuMnPzDq/6xwVA604DuOXMZTO1lvq01g+Adfa0pE2UKGlxL1XQ==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], + "node_modules/regexp.prototype.flags": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.2.tgz", + "integrity": "sha512-NcDiDkTLuPR+++OCKB0nWafEmhg/Da8aUPLPMQbK+bxKKCm1/S5he+AqYa4PlMCVBalb4/yxIRub6qkEx5yJbw==", "dependencies": { - "micromark-util-symbol": "^2.0.0" + "call-bind": "^1.0.6", + "define-properties": "^1.2.1", + "es-errors": "^1.3.0", + "set-function-name": "^2.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/remark-parse/node_modules/micromark-util-decode-string": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-decode-string/-/micromark-util-decode-string-2.0.0.tgz", - "integrity": "sha512-r4Sc6leeUTn3P6gk20aFMj2ntPwn6qpDZqWvYmAG6NgvFTIlj4WtrAudLi65qYoaGdXYViXYw2pkmn7QnIFasA==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], + "node_modules/regexpu-core": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-5.3.2.tgz", + "integrity": "sha512-RAM5FlZz+Lhmo7db9L298p2vHP5ZywrVXmVXpmAD9GuL5MPH6t9ROw1iA/wfHkQ76Qe7AaPF0nGuim96/IrQMQ==", "dependencies": { - "decode-named-character-reference": "^1.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-decode-numeric-character-reference": "^2.0.0", - "micromark-util-symbol": "^2.0.0" + "@babel/regjsgen": "^0.8.0", + "regenerate": "^1.4.2", + "regenerate-unicode-properties": "^10.1.0", + "regjsparser": "^0.9.1", + "unicode-match-property-ecmascript": "^2.0.0", + "unicode-match-property-value-ecmascript": "^2.1.0" + }, + "engines": { + "node": ">=4" } }, - "node_modules/remark-parse/node_modules/micromark-util-encode": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-encode/-/micromark-util-encode-2.0.0.tgz", - "integrity": "sha512-pS+ROfCXAGLWCOc8egcBvT0kf27GoWMqtdarNfDcjb6YLuV5cM3ioG45Ys2qOVqeqSbjaKg72vU+Wby3eddPsA==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ] + "node_modules/regjsparser": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.9.1.tgz", + "integrity": "sha512-dQUtn90WanSNl+7mQKcXAgZxvUe7Z0SqXlgzv0za4LwiUhyzBC58yQO3liFoUgu8GiJVInAhJjkj1N0EtQ5nkQ==", + "dependencies": { + "jsesc": "~0.5.0" + }, + "bin": { + "regjsparser": "bin/parser" + } }, - "node_modules/remark-parse/node_modules/micromark-util-html-tag-name": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-html-tag-name/-/micromark-util-html-tag-name-2.0.0.tgz", - "integrity": "sha512-xNn4Pqkj2puRhKdKTm8t1YHC/BAjx6CEwRFXntTaRf/x16aqka6ouVoutm+QdkISTlT7e2zU7U4ZdlDLJd2Mcw==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ] + "node_modules/regjsparser/node_modules/jsesc": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", + "integrity": "sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==", + "bin": { + "jsesc": "bin/jsesc" + } }, - "node_modules/remark-parse/node_modules/micromark-util-normalize-identifier": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-normalize-identifier/-/micromark-util-normalize-identifier-2.0.0.tgz", - "integrity": "sha512-2xhYT0sfo85FMrUPtHcPo2rrp1lwbDEEzpx7jiH2xXJLqBuy4H0GgXk5ToU8IEwoROtXuL8ND0ttVa4rNqYK3w==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], + "node_modules/rehype-katex": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/rehype-katex/-/rehype-katex-7.0.1.tgz", + "integrity": "sha512-OiM2wrZ/wuhKkigASodFoo8wimG3H12LWQaH8qSPVJn9apWKFSH3YOCtbKpBorTVw/eI7cuT21XBbvwEswbIOA==", "dependencies": { - "micromark-util-symbol": "^2.0.0" + "@types/hast": "^3.0.0", + "@types/katex": "^0.16.0", + "hast-util-from-html-isomorphic": "^2.0.0", + "hast-util-to-text": "^4.0.0", + "katex": "^0.16.0", + "unist-util-visit-parents": "^6.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/remark-parse/node_modules/micromark-util-resolve-all": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-resolve-all/-/micromark-util-resolve-all-2.0.0.tgz", - "integrity": "sha512-6KU6qO7DZ7GJkaCgwBNtplXCvGkJToU86ybBAUdavvgsCiG8lSSvYxr9MhwmQ+udpzywHsl4RpGJsYWG1pDOcA==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], + "node_modules/rehype-raw": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/rehype-raw/-/rehype-raw-7.0.0.tgz", + "integrity": "sha512-/aE8hCfKlQeA8LmyeyQvQF3eBiLRGNlfBJEvWH7ivp9sBqs7TNqBL5X3v157rM4IFETqDnIOO+z5M/biZbo9Ww==", "dependencies": { - "micromark-util-types": "^2.0.0" + "@types/hast": "^3.0.0", + "hast-util-raw": "^9.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/remark-parse/node_modules/micromark-util-sanitize-uri": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-2.0.0.tgz", - "integrity": "sha512-WhYv5UEcZrbAtlsnPuChHUAsu/iBPOVaEVsntLBIdpibO0ddy8OzavZz3iL2xVvBZOpolujSliP65Kq0/7KIYw==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-util-character": "^2.0.0", - "micromark-util-encode": "^2.0.0", - "micromark-util-symbol": "^2.0.0" + "node_modules/relateurl": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz", + "integrity": "sha512-G08Dxvm4iDN3MLM0EsP62EDV9IuhXPR6blNz6Utcp7zyV3tr4HVNINt6MpaRWbxoOHT3Q7YN2P+jaHX8vUbgog==", + "engines": { + "node": ">= 0.10" } }, - "node_modules/remark-parse/node_modules/micromark-util-subtokenize": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-subtokenize/-/micromark-util-subtokenize-2.0.1.tgz", - "integrity": "sha512-jZNtiFl/1aY73yS3UGQkutD0UbhTt68qnRpw2Pifmz5wV9h8gOVsN70v+Lq/f1rKaU/W8pxRe8y8Q9FX1AOe1Q==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], + "node_modules/remark-gfm": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/remark-gfm/-/remark-gfm-4.0.0.tgz", + "integrity": "sha512-U92vJgBPkbw4Zfu/IiW2oTZLSL3Zpv+uI7My2eq8JxKgqraFdU8YUGicEJCEgSbeaG+QDFqIcwwfMTOEelPxuA==", "dependencies": { - "devlop": "^1.0.0", - "micromark-util-chunked": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" + "@types/mdast": "^4.0.0", + "mdast-util-gfm": "^3.0.0", + "micromark-extension-gfm": "^3.0.0", + "remark-parse": "^11.0.0", + "remark-stringify": "^11.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/remark-parse/node_modules/micromark-util-symbol": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", - "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ] - }, - "node_modules/remark-parse/node_modules/micromark-util-types": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-2.0.0.tgz", - "integrity": "sha512-oNh6S2WMHWRZrmutsRmDDfkzKtxF+bc2VxLC9dvtrDIRFln627VsFP6fLMgTryGDljgLPjkrzQSDcPrjPyDJ5w==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ] + "node_modules/remark-math": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/remark-math/-/remark-math-6.0.0.tgz", + "integrity": "sha512-MMqgnP74Igy+S3WwnhQ7kqGlEerTETXMvJhrUzDikVZ2/uogJCb+WHUg97hK9/jcfc0dkD73s3LN8zU49cTEtA==", + "dependencies": { + "@types/mdast": "^4.0.0", + "mdast-util-math": "^3.0.0", + "micromark-extension-math": "^3.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } }, - "node_modules/remark-parse/node_modules/unist-util-stringify-position": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-4.0.0.tgz", - "integrity": "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==", + "node_modules/remark-parse": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/remark-parse/-/remark-parse-11.0.0.tgz", + "integrity": "sha512-FCxlKLNGknS5ba/1lmpYijMUzX2esxW5xQqjWxw2eHFfS2MSdaHVINFmhjo+qN1WhZhNimq0dZATN9pH0IDrpA==", "dependencies": { - "@types/unist": "^3.0.0" + "@types/mdast": "^4.0.0", + "mdast-util-from-markdown": "^2.0.0", + "micromark-util-types": "^2.0.0", + "unified": "^11.0.0" }, "funding": { "type": "opencollective", @@ -34904,14 +29605,6 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/remark-rehype/node_modules/@types/mdast": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-4.0.4.tgz", - "integrity": "sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==", - "dependencies": { - "@types/unist": "*" - } - }, "node_modules/remark-stringify": { "version": "11.0.0", "resolved": "https://registry.npmjs.org/remark-stringify/-/remark-stringify-11.0.0.tgz", @@ -34926,14 +29619,6 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/remark-stringify/node_modules/@types/mdast": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-4.0.4.tgz", - "integrity": "sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==", - "dependencies": { - "@types/unist": "*" - } - }, "node_modules/renderkid": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/renderkid/-/renderkid-3.0.0.tgz", @@ -36502,9 +31187,9 @@ "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" }, "node_modules/streamx": { - "version": "2.19.0", - "resolved": "https://registry.npmjs.org/streamx/-/streamx-2.19.0.tgz", - "integrity": "sha512-5z6CNR4gtkPbwlxyEqoDGDmWIzoNJqCBt4Eac1ICP9YaIT08ct712cFj0u1rx4F8luAuL+3Qc+RFIdI4OX00kg==", + "version": "2.20.0", + "resolved": "https://registry.npmjs.org/streamx/-/streamx-2.20.0.tgz", + "integrity": "sha512-ZGd1LhDeGFucr1CUCTBOS58ZhEendd0ttpGT3usTvosS4ntIwKN9LJFp+OeCSprsCPL14BXVRZlHGRY1V9PVzQ==", "dependencies": { "fast-fifo": "^1.3.2", "queue-tick": "^1.0.1", @@ -36827,17 +31512,17 @@ } }, "node_modules/style-to-object": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/style-to-object/-/style-to-object-1.0.6.tgz", - "integrity": "sha512-khxq+Qm3xEyZfKd/y9L3oIWQimxuc4STrQKtQn8aSDRHb8mFgpukgX1hdzfrMEW6JCjyJ8p89x+IUMVnCBI1PA==", + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/style-to-object/-/style-to-object-1.0.7.tgz", + "integrity": "sha512-uSjr59G5u6fbxUfKbb8GcqMGT3Xs9v5IbPkjb0S16GyOeBLAzSRK0CixBv5YrYvzO6TDLzIS6QCn78tkqWngPw==", "dependencies": { "inline-style-parser": "0.2.3" } }, "node_modules/styled-components": { - "version": "6.1.12", - "resolved": "https://registry.npmjs.org/styled-components/-/styled-components-6.1.12.tgz", - "integrity": "sha512-n/O4PzRPhbYI0k1vKKayfti3C/IGcPf+DqcrOB7O/ab9x4u/zjqraneT5N45+sIe87cxrCApXM8Bna7NYxwoTA==", + "version": "6.1.13", + "resolved": "https://registry.npmjs.org/styled-components/-/styled-components-6.1.13.tgz", + "integrity": "sha512-M0+N2xSnAtwcVAQeFEsGWFFxXDftHUD7XrKla06QbpUMmbmtFBMMTcKWvFXtWxuD5qQkB8iU5gk6QASlx2ZRMw==", "dependencies": { "@emotion/is-prop-valid": "1.2.2", "@emotion/unitless": "0.8.1", @@ -37171,11 +31856,6 @@ "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==", "dev": true }, - "node_modules/timm": { - "version": "1.7.1", - "resolved": "https://registry.npmjs.org/timm/-/timm-1.7.1.tgz", - "integrity": "sha512-IjZc9KIotudix8bMaBW6QvMuq64BrJWFs1+4V0lXwWGQZwH+LnX87doAYhem4caOEusRP9/g6jVDQmZ8XOk1nw==" - }, "node_modules/tiny-inflate": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/tiny-inflate/-/tiny-inflate-1.0.3.tgz", @@ -37962,9 +32642,9 @@ } }, "node_modules/type-fest": { - "version": "4.25.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.25.0.tgz", - "integrity": "sha512-bRkIGlXsnGBRBQRAY56UXBm//9qH4bmJfFvq83gSz41N282df+fjy8ofcEgc1sM8geNt5cl6mC2g9Fht1cs8Aw==", + "version": "4.26.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.26.0.tgz", + "integrity": "sha512-OduNjVJsFbifKb57UqZ2EMP1i4u64Xwow3NYXUtBbD4vIwJdQd4+xl8YDou1dlm4DVrtwT/7Ky8z8WyCULVfxw==", "engines": { "node": ">=16" }, @@ -38240,11 +32920,6 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/unified/node_modules/@types/unist": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", - "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==" - }, "node_modules/uninstall": { "version": "0.0.0", "resolved": "https://registry.npmjs.org/uninstall/-/uninstall-0.0.0.tgz", @@ -38277,11 +32952,6 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/unist-util-find-after/node_modules/@types/unist": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", - "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==" - }, "node_modules/unist-util-is": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-6.0.0.tgz", @@ -38294,11 +32964,6 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/unist-util-is/node_modules/@types/unist": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", - "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==" - }, "node_modules/unist-util-position": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/unist-util-position/-/unist-util-position-5.0.0.tgz", @@ -38311,11 +32976,6 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/unist-util-position/node_modules/@types/unist": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", - "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==" - }, "node_modules/unist-util-remove-position": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/unist-util-remove-position/-/unist-util-remove-position-5.0.0.tgz", @@ -38329,10 +32989,17 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/unist-util-remove-position/node_modules/@types/unist": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", - "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==" + "node_modules/unist-util-stringify-position": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-4.0.0.tgz", + "integrity": "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } }, "node_modules/unist-util-visit": { "version": "5.0.0", @@ -38361,16 +33028,6 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/unist-util-visit-parents/node_modules/@types/unist": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", - "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==" - }, - "node_modules/unist-util-visit/node_modules/@types/unist": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", - "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==" - }, "node_modules/universal-user-agent": { "version": "7.0.2", "resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-7.0.2.tgz", @@ -38676,12 +33333,11 @@ } }, "node_modules/vfile": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/vfile/-/vfile-6.0.2.tgz", - "integrity": "sha512-zND7NlS8rJYb/sPqkb13ZvbbUoExdbi4w3SfRrMq6R3FvnLQmmfpajJNITuuYm6AZ5uao9vy4BAos3EXBPf2rg==", + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/vfile/-/vfile-6.0.3.tgz", + "integrity": "sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==", "dependencies": { "@types/unist": "^3.0.0", - "unist-util-stringify-position": "^4.0.0", "vfile-message": "^4.0.0" }, "funding": { @@ -38702,11 +33358,6 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/vfile-location/node_modules/@types/unist": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", - "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==" - }, "node_modules/vfile-message": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-4.0.2.tgz", @@ -38720,40 +33371,6 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/vfile-message/node_modules/@types/unist": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", - "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==" - }, - "node_modules/vfile-message/node_modules/unist-util-stringify-position": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-4.0.0.tgz", - "integrity": "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==", - "dependencies": { - "@types/unist": "^3.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/vfile/node_modules/@types/unist": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", - "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==" - }, - "node_modules/vfile/node_modules/unist-util-stringify-position": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-4.0.0.tgz", - "integrity": "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==", - "dependencies": { - "@types/unist": "^3.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, "node_modules/victory-vendor": { "version": "36.9.2", "resolved": "https://registry.npmjs.org/victory-vendor/-/victory-vendor-36.9.2.tgz", @@ -39277,11 +33894,6 @@ "node": ">=0.10.0" } }, - "node_modules/whatwg-fetch": { - "version": "3.6.20", - "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-3.6.20.tgz", - "integrity": "sha512-EqhiFU6daOA8kpjOWTL0olhVOF3i7OrFzSYiGsEMB8GcXS+RrzauAERX65xMeNWVqxA6HXH2m69Z9LaKKdisfg==" - }, "node_modules/whatwg-mimetype": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-4.0.0.tgz", @@ -39647,17 +34259,6 @@ } } }, - "node_modules/xhr": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/xhr/-/xhr-2.6.0.tgz", - "integrity": "sha512-/eCGLb5rxjx5e3mF1A7s+pLlR6CGyqWN91fv1JgER5mVWg1MZmlhBvy9kjcsOdRk8RrIujotWyJamfyrp+WIcA==", - "dependencies": { - "global": "~4.4.0", - "is-function": "^1.0.1", - "parse-headers": "^2.0.0", - "xtend": "^4.0.0" - } - }, "node_modules/xml-name-validator": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-5.0.0.tgz", @@ -39731,6 +34332,7 @@ "version": "4.0.2", "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "dev": true, "engines": { "node": ">=0.4" } @@ -39856,6 +34458,14 @@ "node": ">= 14" } }, + "node_modules/zod": { + "version": "3.23.8", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.23.8.tgz", + "integrity": "sha512-XBx9AXhXktjUqnepgTiE5flcKIYWi/rme0Eaj+5Y0lftuGBq+jyRu/md4WnuxqgP1ubdpNCsYEYPxrzVHD8d6g==", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + }, "node_modules/zwitch": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/zwitch/-/zwitch-2.0.4.tgz", diff --git a/package.json b/package.json index 81ee9972a..11c299f7d 100644 --- a/package.json +++ b/package.json @@ -105,8 +105,8 @@ "@fullcalendar/daygrid": "^6.1.10", "@fullcalendar/multimonth": "^6.1.10", "@internationalized/date": "^3.5.0", - "@mui/icons-material": "^5.14.19", - "@mui/material": "^5.14.19", + "@mui/icons-material": "^6.0.1", + "@mui/material": "^6.0.1", "@octokit/core": "^6.0.1", "@react-google-maps/api": "^2.19.2", "@react-spring/web": "^9.7.3", @@ -129,10 +129,11 @@ "@types/reveal": "^4.2.0", "@types/supercluster": "^7.1.3", "@types/textfit": "^2.4.4", - "@types/web": "^0.0.157", + "@types/web": "^0.0.159", "@types/webpack-hot-middleware": "^2.25.9", "@webscopeio/react-textarea-autocomplete": "^4.9.2", "adm-zip": "^0.5.10", + "any-base": "^1.1.0", "archiver": "^7.0.1", "async": "^3.2.5", "axios": "^1.6.2", @@ -210,7 +211,7 @@ "image-size": "^1.0.2", "image-size-stream": "^1.1.0", "is-plain-obj": "^4.1.0", - "jimp": "^0.22.10", + "jimp": "^1.0.4", "jpeg-autorotate": "^9.0.0", "jquery": "^3.7.1", "js-datepicker": "^5.18.2", diff --git a/src/client/Network.ts b/src/client/Network.ts index 204fcf0ac..9afdc844f 100644 --- a/src/client/Network.ts +++ b/src/client/Network.ts @@ -50,7 +50,7 @@ export namespace Networking { if (!fileguidpairs.length) { return []; } - const maxFileSize = 6000000; + const maxFileSize = 50000000; if (fileguidpairs.some(f => f.file.size > maxFileSize)) { return new Promise[]>(res => res([{ source: { newFilename: '', mimetype: '' } as formidable.File, result: new Error(`max file size (${maxFileSize / 1000000}MB) exceeded`) }])); } diff --git a/src/client/util/request-image-size.ts b/src/client/util/request-image-size.ts index 7a2ecd486..c619192ed 100644 --- a/src/client/util/request-image-size.ts +++ b/src/client/util/request-image-size.ts @@ -35,7 +35,11 @@ module.exports = function requestImageSize(url: string) { res.on('data', chunk => { buffer = Buffer.concat([buffer, chunk]); + }); + + res.on('error', reject); + res.on('end', () => { try { size = imageSize(buffer); if (size) { @@ -46,11 +50,6 @@ module.exports = function requestImageSize(url: string) { /* empty */ console.log('Error: ', err); } - }); - - res.on('error', reject); - - res.on('end', () => { if (!size) { reject(new Error('Image has no size')); return; diff --git a/src/client/views/collections/collectionGrid/CollectionGridView.tsx b/src/client/views/collections/collectionGrid/CollectionGridView.tsx index 61bd0241c..5c41fee37 100644 --- a/src/client/views/collections/collectionGrid/CollectionGridView.tsx +++ b/src/client/views/collections/collectionGrid/CollectionGridView.tsx @@ -9,7 +9,7 @@ import { emptyFunction } from '../../../../Utils'; import { Docs } from '../../../documents/Documents'; import { DragManager } from '../../../util/DragManager'; import { Transform } from '../../../util/Transform'; -import { undoBatch } from '../../../util/UndoManager'; +import { undoable, undoBatch } from '../../../util/UndoManager'; import { ContextMenu } from '../../ContextMenu'; import { ContextMenuProps } from '../../ContextMenuItem'; import { DocumentView } from '../../nodes/DocumentView'; @@ -221,13 +221,13 @@ export class CollectionGridView extends CollectionSubView() { }); if (this.Document.gridStartCompaction) { - undoBatch(() => { + undoable(() => { this.Document.gridCompaction = this.Document.gridStartCompaction; this.setLayoutList(savedLayouts); - })(); + }, 'start grid compaction')(); this.Document.gridStartCompaction = undefined; } else { - undoBatch(() => this.setLayoutList(savedLayouts))(); + undoable(() => this.setLayoutList(savedLayouts), 'start grid compaction')(); } } }; @@ -315,9 +315,9 @@ export class CollectionGridView extends CollectionSubView() { e, returnFalse, action(() => { - undoBatch(() => { + undoable(() => { this.Document.gridRowHeight = this._rowHeight; - })(); + }, 'changing row height')(); this._rowHeight = undefined; }), emptyFunction, @@ -360,13 +360,14 @@ export class CollectionGridView extends CollectionSubView() { returnFalse, (clickEv: PointerEvent, doubleTap?: boolean) => { if (doubleTap && !clickEv.button) { - undoBatch( + undoable( action(() => { const text = Docs.Create.TextDocument('', { _width: 150, _height: 50 }); Doc.SetSelectOnLoad(text); // track the new text box so we can give it a prop that tells it to focus itself when it's displayed Doc.AddDocToList(this.Document, this._props.fieldKey, text); this.setLayoutList(this.addLayoutItem(this.savedLayoutList, this.makeLayoutItem(text, this.screenToCell(clickEv.clientX, clickEv.clientY)))); - }) + }), + 'create grid text' )(); } }, diff --git a/src/server/ApiManagers/UploadManager.ts b/src/server/ApiManagers/UploadManager.ts index b2624f654..8ab27130b 100644 --- a/src/server/ApiManagers/UploadManager.ts +++ b/src/server/ApiManagers/UploadManager.ts @@ -3,7 +3,7 @@ import * as formidable from 'formidable'; import * as fs from 'fs'; import { createReadStream, createWriteStream, unlink } from 'fs'; import * as imageDataUri from 'image-data-uri'; -import Jimp from 'jimp'; +import { Jimp } from 'jimp'; import * as path from 'path'; import * as uuid from 'uuid'; import { retrocycle } from '../../decycler/decycler'; @@ -11,7 +11,7 @@ import { DashVersion } from '../../fields/DocSymbols'; import { DashUploadUtils, InjectSize, SizeSuffix } from '../DashUploadUtils'; import { Method, _success } from '../RouteManager'; import { AcceptableMedia, Upload } from '../SharedMediaTypes'; -import { clientPathToFile, Directory, pathToDirectory, publicDirectory, serverPathToFile } from '../SocketData'; +import { Directory, clientPathToFile, pathToDirectory, publicDirectory, serverPathToFile } from '../SocketData'; import { Database } from '../database'; import ApiManager, { Registration } from './ApiManager'; import { SolrManager } from './SearchManager'; @@ -203,12 +203,11 @@ export default class UploadManager extends ApiManager { try { zip.extractEntryTo(entry.entryName, publicDirectory, true, false); createReadStream(pathname).pipe(createWriteStream(targetname)); - Jimp.read(pathname).then(imgIn => { - let img = imgIn; + Jimp.read(pathname).then(img => { DashUploadUtils.imageResampleSizes(extension).forEach(({ width, suffix }) => { const outputPath = InjectSize(targetname, suffix); if (!width) createReadStream(pathname).pipe(createWriteStream(outputPath)); - else img = img.resize(width, Jimp.AUTO).write(outputPath); + else img.resize({ w: width }).write(outputPath as `${string}.${string}`); }); unlink(pathname, () => {}); }); @@ -288,13 +287,12 @@ export default class UploadManager extends ApiManager { imageDataUri.outputFile(uri, serverPathToFile(Directory.images, InjectSize(filename, origSuffix))).then((savedName: string) => { const ext = path.extname(savedName).toLowerCase(); if (AcceptableMedia.imageFormats.includes(ext)) { - Jimp.read(savedName).then(imgIn => { - let img = imgIn; + Jimp.read(savedName).then(img => { (!origSuffix ? [{ width: 400, suffix: SizeSuffix.Medium }] : Object.values(DashUploadUtils.Sizes)) // .forEach(({ width, suffix }) => { const outputPath = serverPathToFile(Directory.images, InjectSize(filename, suffix) + ext); if (!width) createReadStream(savedName).pipe(createWriteStream(outputPath)); - else img = img.resize(width, Jimp.AUTO).write(outputPath); + else img.resize({ w: width }).write(outputPath as `${string}.${string}`); }); }); } diff --git a/src/server/DashUploadUtils.ts b/src/server/DashUploadUtils.ts index 8f012f783..5cf86b2ae 100644 --- a/src/server/DashUploadUtils.ts +++ b/src/server/DashUploadUtils.ts @@ -1,5 +1,5 @@ import axios from 'axios'; -import { spawn, exec } from 'child_process'; +import { exec, spawn } from 'child_process'; import { green, red } from 'colors'; import { ExifData, ExifImage } from 'exif'; import * as exifr from 'exifr'; @@ -7,9 +7,8 @@ import * as ffmpeg from 'fluent-ffmpeg'; import * as formidable from 'formidable'; import { File } from 'formidable'; import * as fs from 'fs'; -import { createReadStream, createWriteStream, existsSync, readFileSync, rename, unlinkSync, writeFile } from 'fs'; -import Jimp from 'jimp'; -import * as autorotate from 'jpeg-autorotate'; +import { createReadStream, createWriteStream, existsSync, readFileSync, rename, unlinkSync, writeFile } from 'fs'; // import { Jimp } from "@jimp/core"; +import { Jimp } from 'jimp'; import * as md5File from 'md5-file'; import * as path from 'path'; import { basename } from 'path'; @@ -23,6 +22,38 @@ import { AcceptableMedia, Upload } from './SharedMediaTypes'; import { Directory, clientPathToFile, filesDirectory, pathToDirectory, publicDirectory, serverPathToFile } from './SocketData'; import { resolvedServerUrl } from './server_Initialization'; +import { Worker, isMainThread, parentPort } from 'worker_threads'; + +// Create an array to store worker threads +const workerThreads: Worker[] = []; +if (isMainThread) { + // Main thread code + // Create worker threads -- just one right to do image resampling + workerThreads.push(new Worker(__filename)); +} else { + // Worker thread code - Listens for messages from the main thread + parentPort?.on('message', message => workerResampleImage(message.task)); + async function workerResampleImage(task: string) { + const [sourcePath, outputFileName, outputDirectory, unlinkSource] = task.split('::'); + const sizes = DashUploadUtils.imageResampleSizes(path.extname(sourcePath)); + const imgBuffer = await fs.readFileSync(sourcePath); + const outputPath = (suffix: SizeSuffix) => { + const writtenFile = InjectSize(outputFileName, suffix); + return path.resolve(outputDirectory, writtenFile); + }; + await Jimp.fromBuffer(imgBuffer) + .then(img => sizes.filter(({ width }) => width).map(({ width, suffix }) => img.resize({ w: width }).write(outputPath(suffix) as `${string}.${string}`))) + .catch(e => { + console.log('ERROR' + e); + }); + if (unlinkSource === 'true') { + unlinkSync(sourcePath); + } + + // … operations to be performed to execute the task + } +} + // eslint-disable-next-line @typescript-eslint/no-var-requires const requestImageSize = require('../client/util/request-image-size'); @@ -277,15 +308,6 @@ export namespace DashUploadUtils { } }; - async function correctRotation(imgSourcePath: string) { - const buffer = fs.readFileSync(imgSourcePath); - try { - return (await autorotate.rotate(buffer, { quality: 30 })).buffer; - } catch (e) { - return buffer; - } - } - /** * define the resizers to use * @param ext the extension @@ -310,38 +332,29 @@ export namespace DashUploadUtils { * @param outputDirectory the directory to output to, usually Directory.Images * @returns a map with suffixes as keys and resized filenames as values. */ - export async function outputResizedImages(imgSourcePath: string, outputFileName: string, outputDirectory: string) { + export async function outputResizedImages(imgSourcePath: string, outputFileName: string, outputDirectory: string, unlinkSource: boolean) { const writtenFiles: { [suffix: string]: string } = {}; - const sizes = imageResampleSizes(path.extname(outputFileName)); - const imgBuffer = await correctRotation(imgSourcePath); - const imgReadStream = new Duplex(); - imgReadStream.push(imgBuffer); - imgReadStream.push(null); const outputPath = (suffix: SizeSuffix) => { writtenFiles[suffix] = InjectSize(outputFileName, suffix); return path.resolve(outputDirectory, writtenFiles[suffix]); }; + + const sizes = imageResampleSizes(path.extname(outputFileName)); + const imgBuffer = fs.readFileSync(imgSourcePath); + const imgReadStream = new Duplex(); + imgReadStream.push(imgBuffer); + imgReadStream.push(null); await Promise.all( - sizes.filter(({ width }) => !width).map(({ suffix }) => - new Promise(res => { - imgReadStream.pipe(createWriteStream(outputPath(suffix))).on('close', res); - }) + sizes.map(({ suffix }) => + new Promise(res => + imgReadStream.pipe(createWriteStream(outputPath(suffix))).on('close', res) + ) )); // prettier-ignore - return Jimp.read(imgBuffer) - .then(async imgIn => { - let img = imgIn; - await Promise.all( sizes.filter(({ width }) => width).map(({ width, suffix }) => { - img = img.resize(width, Jimp.AUTO).write(outputPath(suffix)); - return img; - } )); // prettier-ignore - return writtenFiles; - }) - .catch(e => { - console.log('ERROR' + e); - return writtenFiles; - }); + // Send a message to worker thread to resample image + workerThreads[0].postMessage({ task: imgSourcePath + '::' + outputFileName + '::' + outputDirectory + '::' + unlinkSource }); + return writtenFiles; } /** @@ -387,8 +400,9 @@ export namespace DashUploadUtils { writtenFiles = {}; } } else { + const unlinkSrcWhenFinished = isLocal().test(source) && cleanUp; try { - writtenFiles = await outputResizedImages(metadata.source, resolved, pathToDirectory(Directory.images)); + writtenFiles = await outputResizedImages(metadata.source, resolved, pathToDirectory(Directory.images), unlinkSrcWhenFinished); } catch (e) { // input is a blob or other, try reading it to create a metadata source file. const reqSource = request(metadata.source); @@ -400,16 +414,14 @@ export namespace DashUploadUtils { .on('close', () => res()) .on('error', () => rej()); }); - writtenFiles = await outputResizedImages(readSource, resolved, pathToDirectory(Directory.images)); + writtenFiles = await outputResizedImages(readSource, resolved, pathToDirectory(Directory.images), unlinkSrcWhenFinished); fs.unlink(readSource, err => console.log("Couldn't unlink temporary image file:" + readSource, err)); } } Array.from(Object.keys(writtenFiles)).forEach(suffix => { information.accessPaths[suffix] = getAccessPaths(images, writtenFiles[suffix]); }); - if (isLocal().test(source) && cleanUp) { - unlinkSync(source); - } + return information; }; -- cgit v1.2.3-70-g09d2 From a958577d4c27b276aa37484e3f895e196138b17c Mon Sep 17 00:00:00 2001 From: bobzel Date: Sun, 1 Sep 2024 12:55:59 -0400 Subject: consolidated image resampling. fixed importing zipped workspace. --- src/client/views/PropertiesButtons.tsx | 20 --- .../collectionFreeForm/CollectionFreeFormView.tsx | 2 +- .../collections/collectionFreeForm/MarqueeView.tsx | 4 +- src/client/views/nodes/PDFBox.tsx | 4 - src/server/ApiManagers/SearchManager.ts | 200 --------------------- src/server/ApiManagers/UploadManager.ts | 49 ++--- src/server/DashUploadUtils.ts | 74 ++++---- src/server/index.ts | 2 - 8 files changed, 56 insertions(+), 299 deletions(-) delete mode 100644 src/server/ApiManagers/SearchManager.ts (limited to 'src') diff --git a/src/client/views/PropertiesButtons.tsx b/src/client/views/PropertiesButtons.tsx index f346d4ba8..f96a4a255 100644 --- a/src/client/views/PropertiesButtons.tsx +++ b/src/client/views/PropertiesButtons.tsx @@ -246,26 +246,6 @@ export class PropertiesButtons extends React.Component { // ); // } - // @computed get freezeThumb() { - // return this.propertyToggleBtn( - // 'FreezeThumb', - // '_thumb-frozen', - // on => `${on ? 'Freeze' : 'Unfreeze'} thumbnail`, - // on => 'snowflake', - // (dv, doc) => { - // if (doc['thumb-frozen']) doc['thumb-frozen'] = undefined; - // else { - // document.body.focus(); // so that we can access the clipboard without an error - // setTimeout(() => - // pasteImageBitmap((data_url: any, error: any) => { - // error && console.log(error); - // data_url && Utils.convertDataUri(data_url, doc[Id] + '-thumb-frozen', true).then(returnedfilename => (doc['thumb-frozen'] = new ImageField(returnedfilename))); - // }) - // ); - // } - // } - // ); - // } @computed get snapButton() { // THESE ARE NOT COMING return this.propertyToggleBtn( diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index c4cf8dee7..dbf781e63 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -1811,7 +1811,7 @@ export class CollectionFreeFormView extends CollectionSubView { error && console.log(error); data && - ClientUtils.convertDataUri(data, this._props.Document[Id] + '-thumb-frozen').then(returnedfilename => { - this._props.Document['thumb-frozen'] = new ImageField(returnedfilename); + ClientUtils.convertDataUri(data, this._props.Document[Id] + '_icon_' + new Date().getTime()).then(returnedfilename => { + this._props.Document[DocData].icon = new ImageField(returnedfilename); }); }) ); diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx index b17275a1e..cb0b0d71f 100644 --- a/src/client/views/nodes/PDFBox.tsx +++ b/src/client/views/nodes/PDFBox.tsx @@ -56,10 +56,6 @@ export class PDFBox extends ViewBoxAnnotatableComponent() { @computed get pdfUrl() { return Cast(this.dataDoc[this._props.fieldKey], PdfField); } - @computed get pdfThumb() { - return ImageCast(this.layoutDoc['thumb-frozen'], ImageCast(this.layoutDoc.thumb))?.url; - } - constructor(props: FieldViewProps) { super(props); makeObservable(this); diff --git a/src/server/ApiManagers/SearchManager.ts b/src/server/ApiManagers/SearchManager.ts deleted file mode 100644 index 684b49eaf..000000000 --- a/src/server/ApiManagers/SearchManager.ts +++ /dev/null @@ -1,200 +0,0 @@ -/* eslint-disable no-use-before-define */ -import { exec } from 'child_process'; -import { cyan, green, red, yellow } from 'colors'; -import { logExecution } from '../ActionUtilities'; -import { Method } from '../RouteManager'; -import RouteSubscriber from '../RouteSubscriber'; -import { Search } from '../Search'; -import { Database } from '../database'; -import ApiManager, { Registration } from './ApiManager'; - -export class SearchManager extends ApiManager { - protected initialize(register: Registration): void { - register({ - method: Method.GET, - subscription: new RouteSubscriber('solr').add('action'), - secureHandler: async ({ req, res }) => { - const { action } = req.params; - switch (action) { - case 'start': - case 'stop': - { - const status = req.params.action === 'start'; - SolrManager.SetRunning(status); - } - break; - case 'update': - await SolrManager.update(); - break; - default: - console.log(yellow(`${action} is an unknown solr operation.`)); - } - res.redirect('/home'); - }, - }); - - register({ - method: Method.GET, - subscription: '/dashsearch', - secureHandler: async ({ req, res }) => { - const solrQuery: any = {}; - ['q', 'fq', 'start', 'rows', 'sort', 'hl.maxAnalyzedChars', 'hl', 'hl.fl'].forEach(key => { - solrQuery[key] = req.query[key]; - }); - if (solrQuery.q === undefined) { - res.send([]); - return; - } - const results = await Search.search(solrQuery); - res.send(results); - }, - }); - } -} - -export namespace SolrManager { - export function SetRunning(status: boolean) { - const args = status ? 'start' : 'stop -p 8983'; - console.log(`solr management: trying to ${args}`); - exec(`solr ${args}`, { cwd: './solr-8.3.1/bin' }, (error, stdout, stderr) => { - if (error) { - console.log(red(`solr management error: unable to ${args} server`)); - console.log(red(error.message)); - } - console.log(cyan(stdout)); - console.log(yellow(stderr)); - }); - if (status) { - console.log(cyan('Start script is executing: please allow 15 seconds for solr to start on port 8983.')); - } - } - - export async function update() { - console.log(green('Beginning update...')); - await logExecution({ - startMessage: 'Clearing existing Solr information...', - endMessage: 'Solr information successfully cleared', - action: Search.clear, - color: cyan, - }); - const cursor = await logExecution({ - startMessage: 'Connecting to and querying for all documents from database...', - endMessage: ({ result, error }) => { - const success = error === null && result !== undefined; - if (!success) { - console.log(red('Unable to connect to the database.')); - process.exit(0); - } - return 'Connection successful and query complete'; - }, - action: () => Database.Instance.query({}), - color: yellow, - }); - const updates: any[] = []; - let numDocs = 0; - function updateDoc(doc: any) { - numDocs++; - if (numDocs % 50 === 0) { - console.log(`Batch of 50 complete, total of ${numDocs}`); - } - if (doc.__type !== 'Doc') { - return; - } - const { fields } = doc; - if (!fields) { - return; - } - const update2: any = { id: doc._id }; - let dynfield = false; - fields.forEach((key: any) => { - const value = fields[key]; - const term = ToSearchTerm(value); - if (term !== undefined) { - const { suffix, value: tvalue } = term; - if (key.endsWith('modificationDate')) { - update2['modificationDate' + suffix] = tvalue; - } - update2[key + suffix] = value; - dynfield = true; - } - }); - if (dynfield) { - updates.push(update2); - } - } - await cursor?.forEach(updateDoc); - const result = await logExecution({ - startMessage: `Dispatching updates for ${updates.length} documents`, - endMessage: 'Dispatched updates complete', - action: () => Search.updateDocuments(updates), - color: cyan, - }); - try { - if (result) { - const { status } = JSON.parse(result).responseHeader; - console.log(status ? red(`Failed with status code (${status})`) : green('Success!')); - } else { - console.log(red('Solr is likely not running!')); - } - } catch (e) { - console.log(red('Error:')); - console.log(e); - console.log('\n'); - } - await cursor?.close(); - } - - const suffixMap: { [type: string]: string | [string, string | ((json: any) => any)] } = { - number: '_n', - string: '_t', - boolean: '_b', - image: ['_t', 'url'], - video: ['_t', 'url'], - pdf: ['_t', 'url'], - audio: ['_t', 'url'], - web: ['_t', 'url'], - map: ['_t', 'url'], - date: ['_d', value => new Date(value.date).toISOString()], - proxy: ['_i', 'fieldId'], - prefetch_proxy: ['_i', 'fieldId'], - list: [ - '_l', - list => { - const results = []; - // eslint-disable-next-line no-restricted-syntax - for (const value of list.fields) { - const term = ToSearchTerm(value); - if (term) { - results.push(term.value); - } - } - return results.length ? results : null; - }, - ], - }; - - function ToSearchTerm(valIn: any): { suffix: string; value: any } | undefined { - let val = valIn; - if (val === null || val === undefined) { - return undefined; - } - const type = val.__type || typeof val; - let suffix = suffixMap[type]; - if (!suffix) { - return undefined; - } - - if (Array.isArray(suffix)) { - const accessor = suffix[1]; - if (typeof accessor === 'function') { - val = accessor(val); - } else { - val = val[accessor]; - } - // eslint-disable-next-line prefer-destructuring - suffix = suffix[0]; - } - - return { suffix, value: val }; - } -} diff --git a/src/server/ApiManagers/UploadManager.ts b/src/server/ApiManagers/UploadManager.ts index 8ab27130b..868373474 100644 --- a/src/server/ApiManagers/UploadManager.ts +++ b/src/server/ApiManagers/UploadManager.ts @@ -1,20 +1,18 @@ import * as AdmZip from 'adm-zip'; import * as formidable from 'formidable'; import * as fs from 'fs'; -import { createReadStream, createWriteStream, unlink } from 'fs'; +import { unlink } from 'fs'; import * as imageDataUri from 'image-data-uri'; -import { Jimp } from 'jimp'; import * as path from 'path'; import * as uuid from 'uuid'; import { retrocycle } from '../../decycler/decycler'; import { DashVersion } from '../../fields/DocSymbols'; -import { DashUploadUtils, InjectSize, SizeSuffix } from '../DashUploadUtils'; +import { DashUploadUtils, InjectSize, SizeSuffix, workerResample } from '../DashUploadUtils'; import { Method, _success } from '../RouteManager'; import { AcceptableMedia, Upload } from '../SharedMediaTypes'; import { Directory, clientPathToFile, pathToDirectory, publicDirectory, serverPathToFile } from '../SocketData'; import { Database } from '../database'; import ApiManager, { Registration } from './ApiManager'; -import { SolrManager } from './SearchManager'; export default class UploadManager extends ApiManager { protected initialize(register: Registration): void { @@ -185,7 +183,7 @@ export default class UploadManager extends ApiManager { let linkids: string[] = []; try { // eslint-disable-next-line no-restricted-syntax - for (const name in Object.keys(files)) { + for (const name in files) { if (Object.prototype.hasOwnProperty.call(files, name)) { const f = files[name]; // eslint-disable-next-line no-continue @@ -194,25 +192,17 @@ export default class UploadManager extends ApiManager { const zip = new AdmZip(path2.filepath); zip.getEntries().forEach(entry => { const entryName = entry.entryName.replace(/%%%/g, '/'); - if (!entryName.startsWith('files/')) { - return; - } - const extension = path.extname(entryName); - const pathname = publicDirectory + '/' + entry.entryName; - const targetname = publicDirectory + '/' + entryName; - try { - zip.extractEntryTo(entry.entryName, publicDirectory, true, false); - createReadStream(pathname).pipe(createWriteStream(targetname)); - Jimp.read(pathname).then(img => { - DashUploadUtils.imageResampleSizes(extension).forEach(({ width, suffix }) => { - const outputPath = InjectSize(targetname, suffix); - if (!width) createReadStream(pathname).pipe(createWriteStream(outputPath)); - else img.resize({ w: width }).write(outputPath as `${string}.${string}`); - }); - unlink(pathname, () => {}); - }); - } catch (e) { - console.log(e); + if (entryName.startsWith('files/')) { + const pathname = publicDirectory + '/' + entry.entryName; + const targetname = publicDirectory + '/' + entryName; + try { + zip.extractEntryTo(entry.entryName, publicDirectory, true, false); + const extension = path.extname(targetname).toLowerCase(); + const basefilename = targetname.substring(0, targetname.length - extension.length); + workerResample(pathname, basefilename.replace(/_o$/, '') + extension, SizeSuffix.Original, true); + } catch (e) { + console.log(e); + } } }); const json = zip.getEntry('docs.json'); @@ -243,7 +233,6 @@ export default class UploadManager extends ApiManager { unlink(path2.filepath, () => {}); } } - SolrManager.update(); res.send(JSON.stringify({ id, docids, linkids }) || 'error'); } catch (e) { console.log(e); @@ -286,15 +275,9 @@ export default class UploadManager extends ApiManager { } imageDataUri.outputFile(uri, serverPathToFile(Directory.images, InjectSize(filename, origSuffix))).then((savedName: string) => { const ext = path.extname(savedName).toLowerCase(); + const outputPath = serverPathToFile(Directory.images, filename + ext); if (AcceptableMedia.imageFormats.includes(ext)) { - Jimp.read(savedName).then(img => { - (!origSuffix ? [{ width: 400, suffix: SizeSuffix.Medium }] : Object.values(DashUploadUtils.Sizes)) // - .forEach(({ width, suffix }) => { - const outputPath = serverPathToFile(Directory.images, InjectSize(filename, suffix) + ext); - if (!width) createReadStream(savedName).pipe(createWriteStream(outputPath)); - else img.resize({ w: width }).write(outputPath as `${string}.${string}`); - }); - }); + workerResample(savedName, outputPath, origSuffix, false); } res.send(clientPathToFile(Directory.images, filename + ext)); }); diff --git a/src/server/DashUploadUtils.ts b/src/server/DashUploadUtils.ts index 5cf86b2ae..1e55a885a 100644 --- a/src/server/DashUploadUtils.ts +++ b/src/server/DashUploadUtils.ts @@ -7,7 +7,7 @@ import * as ffmpeg from 'fluent-ffmpeg'; import * as formidable from 'formidable'; import { File } from 'formidable'; import * as fs from 'fs'; -import { createReadStream, createWriteStream, existsSync, readFileSync, rename, unlinkSync, writeFile } from 'fs'; // import { Jimp } from "@jimp/core"; +import { createReadStream, createWriteStream, existsSync, readFileSync, rename, unlinkSync, writeFile } from 'fs'; import { Jimp } from 'jimp'; import * as md5File from 'md5-file'; import * as path from 'path'; @@ -25,32 +25,38 @@ import { resolvedServerUrl } from './server_Initialization'; import { Worker, isMainThread, parentPort } from 'worker_threads'; // Create an array to store worker threads -const workerThreads: Worker[] = []; +enum workertasks { + JIMP = 'jimp', +} +const JimpWorker: Worker | undefined = isMainThread ? new Worker(__filename) : undefined; +export const workerResample = (imgSourcePath: string, outputPath: string, origSuffix: SizeSuffix, unlinkSource: boolean) => { + JimpWorker?.postMessage({ task: workertasks.JIMP, imgSourcePath, outputPath, origSuffix, unlinkSource }); +}; + if (isMainThread) { - // Main thread code - // Create worker threads -- just one right to do image resampling - workerThreads.push(new Worker(__filename)); + // main thread code if needed ... } else { // Worker thread code - Listens for messages from the main thread - parentPort?.on('message', message => workerResampleImage(message.task)); - async function workerResampleImage(task: string) { - const [sourcePath, outputFileName, outputDirectory, unlinkSource] = task.split('::'); - const sizes = DashUploadUtils.imageResampleSizes(path.extname(sourcePath)); - const imgBuffer = await fs.readFileSync(sourcePath); - const outputPath = (suffix: SizeSuffix) => { - const writtenFile = InjectSize(outputFileName, suffix); - return path.resolve(outputDirectory, writtenFile); - }; - await Jimp.fromBuffer(imgBuffer) - .then(img => sizes.filter(({ width }) => width).map(({ width, suffix }) => img.resize({ w: width }).write(outputPath(suffix) as `${string}.${string}`))) - .catch(e => { - console.log('ERROR' + e); - }); - if (unlinkSource === 'true') { - unlinkSync(sourcePath); + parentPort?.on('message', message => { + switch (message.task) { + case workertasks.JIMP: + return workerResampleImage(message); + default: } - - // … operations to be performed to execute the task + }); + + async function workerResampleImage(message: { imgSourcePath: string; outputPath: string; origSuffix: string; unlinkSource: boolean }) { + const { imgSourcePath, outputPath, origSuffix, unlinkSource } = message; + const sizes = !origSuffix ? [{ width: 400, suffix: SizeSuffix.Medium }] : DashUploadUtils.imageResampleSizes(path.extname(imgSourcePath)); + // prettier-ignore + Jimp.read(imgSourcePath) + .then(img => + sizes.forEach(({ width, suffix }) => + img.resize({ w: width || img.bitmap.width }) + .write(InjectSize(outputPath, suffix) as `${string}.${string}`) + )) + .catch(e => console.log('Error Jimp:', e)) + .finally(() => unlinkSource && unlinkSync(imgSourcePath)); } } @@ -332,28 +338,22 @@ export namespace DashUploadUtils { * @param outputDirectory the directory to output to, usually Directory.Images * @returns a map with suffixes as keys and resized filenames as values. */ - export async function outputResizedImages(imgSourcePath: string, outputFileName: string, outputDirectory: string, unlinkSource: boolean) { + export async function outputResizedImages(imgSourcePath: string, outputFileName: string, unlinkSource: boolean) { const writtenFiles: { [suffix: string]: string } = {}; - - const outputPath = (suffix: SizeSuffix) => { - writtenFiles[suffix] = InjectSize(outputFileName, suffix); - return path.resolve(outputDirectory, writtenFiles[suffix]); - }; - + const outputPath = path.resolve(pathToDirectory(Directory.images), outputFileName); const sizes = imageResampleSizes(path.extname(outputFileName)); - const imgBuffer = fs.readFileSync(imgSourcePath); + const imgReadStream = new Duplex(); - imgReadStream.push(imgBuffer); + imgReadStream.push(fs.readFileSync(imgSourcePath)); imgReadStream.push(null); await Promise.all( sizes.map(({ suffix }) => new Promise(res => - imgReadStream.pipe(createWriteStream(outputPath(suffix))).on('close', res) + imgReadStream.pipe(createWriteStream(writtenFiles[suffix] = InjectSize(outputPath, suffix))).on('close', res) ) )); // prettier-ignore - // Send a message to worker thread to resample image - workerThreads[0].postMessage({ task: imgSourcePath + '::' + outputFileName + '::' + outputDirectory + '::' + unlinkSource }); + workerResample(imgSourcePath, outputPath, SizeSuffix.Original, unlinkSource); return writtenFiles; } @@ -402,7 +402,7 @@ export namespace DashUploadUtils { } else { const unlinkSrcWhenFinished = isLocal().test(source) && cleanUp; try { - writtenFiles = await outputResizedImages(metadata.source, resolved, pathToDirectory(Directory.images), unlinkSrcWhenFinished); + writtenFiles = await outputResizedImages(metadata.source, resolved, unlinkSrcWhenFinished); } catch (e) { // input is a blob or other, try reading it to create a metadata source file. const reqSource = request(metadata.source); @@ -414,7 +414,7 @@ export namespace DashUploadUtils { .on('close', () => res()) .on('error', () => rej()); }); - writtenFiles = await outputResizedImages(readSource, resolved, pathToDirectory(Directory.images), unlinkSrcWhenFinished); + writtenFiles = await outputResizedImages(readSource, resolved, unlinkSrcWhenFinished); fs.unlink(readSource, err => console.log("Couldn't unlink temporary image file:" + readSource, err)); } } diff --git a/src/server/index.ts b/src/server/index.ts index 3e0d86814..88dbd232d 100644 --- a/src/server/index.ts +++ b/src/server/index.ts @@ -8,7 +8,6 @@ import DataVizManager from './ApiManagers/DataVizManager'; import DeleteManager from './ApiManagers/DeleteManager'; import DownloadManager from './ApiManagers/DownloadManager'; import GeneralGoogleManager from './ApiManagers/GeneralGoogleManager'; -import { SearchManager } from './ApiManagers/SearchManager'; import SessionManager from './ApiManagers/SessionManager'; import UploadManager from './ApiManagers/UploadManager'; import UserManager from './ApiManagers/UserManager'; @@ -67,7 +66,6 @@ function routeSetter({ addSupervisedRoute, logRegistrationOutcome }: RouteManage new UserManager(), new UploadManager(), new DownloadManager(), - new SearchManager(), new DeleteManager(), new UtilManager(), new GeneralGoogleManager(), -- cgit v1.2.3-70-g09d2