diff --git a/AnnotationCard/35572061-1354-450a-8dd7-2a7ef3e2342d.json b/AnnotationCard/35572061-1354-450a-8dd7-2a7ef3e2342d.json new file mode 100644 index 0000000..e70fe1a --- /dev/null +++ b/AnnotationCard/35572061-1354-450a-8dd7-2a7ef3e2342d.json @@ -0,0 +1,28 @@ +{ + "data": { + "type": "card", + "attributes": { + "documentUrl": null, + "documentTitle": null, + "annotations": [], + "pageNumber": null, + "position": null, + "annotationType": null, + "color": null, + "createdAt": null, + "annotationData": null, + "cardInfo": { + "name": null, + "summary": null, + "cardThumbnailURL": null, + "notes": null + } + }, + "meta": { + "adoptsFrom": { + "module": "../annotation-2f9c8aa5-a258-4390-839d-fc965f5e915e/annotation/annotation", + "name": "AnnotationCard" + } + } + } +} diff --git a/CardListing/1a427887-81aa-45ff-9296-a3671cacaef2.json b/CardListing/1a427887-81aa-45ff-9296-a3671cacaef2.json new file mode 100644 index 0000000..361e35f --- /dev/null +++ b/CardListing/1a427887-81aa-45ff-9296-a3671cacaef2.json @@ -0,0 +1,74 @@ +{ + "data": { + "meta": { + "adoptsFrom": { + "name": "CardListing", + "module": "https://realms-staging.stack.cards/catalog/catalog-app/listing/listing" + } + }, + "type": "card", + "attributes": { + "name": "Document Annotation Title", + "images": [], + "summary": "A comprehensive annotation card definition for PDFs, enabling users to view, create, and manage annotations such as highlights, notes, drawings, and comments on individual document pages. The primary purpose is to facilitate rich, interactive PDF annotation within a card-based interface, supporting functionalities like page navigation, zooming, drawing with variable colors and thickness, and annotation data export. It integrates with PDF.js for rendering pages and text layers, allowing precise text highlighting and annotation overlay. The component provides tools for drawing annotations directly on PDFs, managing annotation states, and displaying associated notes. It is designed for both embedded and isolated (standalone) contexts, with styles optimized for a professional, modern UI, including toolbar controls, annotation overlays, and notes panel, thus enabling dynamic, user-friendly PDF annotation workflows.", + "cardInfo": { + "name": null, + "notes": null, + "summary": null, + "cardThumbnailURL": null + } + }, + "relationships": { + "tags": { + "links": { + "self": null + } + }, + "specs.0": { + "links": { + "self": "../Spec/1a32aa1a-433a-4cdc-8f9f-404b1965136e" + } + }, + "skills": { + "links": { + "self": null + } + }, + "license": { + "links": { + "self": "https://realms-staging.stack.cards/catalog/License/4c5a023b-a72c-4f90-930b-da60a1de5b2d" + } + }, + "publisher": { + "links": { + "self": null + } + }, + "examples.0": { + "links": { + "self": "../AnnotationCard/35572061-1354-450a-8dd7-2a7ef3e2342d" + } + }, + "examples.1": { + "links": { + "self": "../annotation-2f9c8aa5-a258-4390-839d-fc965f5e915e/annotation/AnnotationCard/dsa-textbook-annotations" + } + }, + "categories.0": { + "links": { + "self": "https://realms-staging.stack.cards/catalog/Category/content-creation" + } + }, + "cardInfo.theme": { + "links": { + "self": null + } + }, + "cardInfo.cardThumbnail": { + "links": { + "self": null + } + } + } + } +} \ No newline at end of file diff --git a/Spec/1a32aa1a-433a-4cdc-8f9f-404b1965136e.json b/Spec/1a32aa1a-433a-4cdc-8f9f-404b1965136e.json new file mode 100644 index 0000000..51f30e0 --- /dev/null +++ b/Spec/1a32aa1a-433a-4cdc-8f9f-404b1965136e.json @@ -0,0 +1,45 @@ +{ + "data": { + "meta": { + "adoptsFrom": { + "name": "Spec", + "module": "https://cardstack.com/base/spec" + } + }, + "type": "card", + "attributes": { + "ref": { + "name": "AnnotationCard", + "module": "../annotation-2f9c8aa5-a258-4390-839d-fc965f5e915e/annotation/annotation" + }, + "readMe": "Sure, here's the usage documentation for the AnnotationCard spec:\n\n## Summary\nThe AnnotationCard spec is a card component that allows users to annotate PDF documents with various types of annotations such as highlights, notes, drawings, and comments. It provides a rich set of features for interacting with the PDF, managing annotations, and customizing the appearance of the card.\n\n## Import\n```javascript\nimport { AnnotationCard } from 'https://realms-staging.stack.cards/chuan16/catalog-listing-test-11/annotation-2f9c8aa5-a258-4390-839d-fc965f5e915e/annotation/annotation';\n```\n\n## Usage as a Field\nTo use the AnnotationCard as a field within a consuming card or field, you can define it as follows:\n\n```javascript\n@field annotationCard = contains(AnnotationCard);\n```\n\nThis will add an AnnotationCard field to your card or field definition, which can be used to display and interact with the PDF annotation features.\n\n## Template Usage\nWithin your consuming card or field template, you can use the AnnotationCard like this:\n\n```handlebars\n\n```\n\nThe `@model` argument should be bound to the `annotationCard` field defined in your card or field.\n\nThe AnnotationCard spec provides a rich set of features and customization options, including:\n\n- Annotation types (highlights, notes, drawings, comments)\n- Annotation management (create, update, delete)\n- PDF viewer with zoom, pan, and page navigation\n- Toolbar for selecting annotation tools and settings\n- Sidebar for viewing and managing annotations\n- Exporting and clearing annotations\n- Error handling and retry functionality\n\nRefer to the Boxel Development Guide for more information on how to use and configure the AnnotationCard spec.", + "cardInfo": { + "name": null, + "notes": null, + "summary": null, + "cardThumbnailURL": null + }, + "specType": "card", + "cardTitle": "Document Annotation", + "cardDescription": null, + "containedExamples": [] + }, + "relationships": { + "cardInfo.theme": { + "links": { + "self": null + } + }, + "linkedExamples": { + "links": { + "self": null + } + }, + "cardInfo.cardThumbnail": { + "links": { + "self": null + } + } + } + } +} \ No newline at end of file diff --git a/annotation-2f9c8aa5-a258-4390-839d-fc965f5e915e/annotation/AnnotationCard/dsa-textbook-annotations.json b/annotation-2f9c8aa5-a258-4390-839d-fc965f5e915e/annotation/AnnotationCard/dsa-textbook-annotations.json new file mode 100644 index 0000000..10110e5 --- /dev/null +++ b/annotation-2f9c8aa5-a258-4390-839d-fc965f5e915e/annotation/AnnotationCard/dsa-textbook-annotations.json @@ -0,0 +1,39 @@ +{ + "data": { + "meta": { + "adoptsFrom": { + "name": "AnnotationCard", + "module": "../annotation" + } + }, + "type": "card", + "attributes": { + "color": "#ffeb3b", + "cardInfo": { + "notes": null, + "name": null, + "summary": null, + "cardThumbnailURL": null + }, + "position": "chapter-5-section-2", + "createdAt": "2025-10-28T03:13:20.600Z", + "pageNumber": 14, + "annotations": [ + "Binary search trees maintain sorted order for efficient searching", + "Time complexity of BST operations is O(log n) in balanced trees", + "AVL trees automatically rebalance to maintain optimal height" + ], + "documentUrl": "https://files.catbox.moe/qccrg6.pdf", + "documentTitle": "Data Structures & Algorithms Textbook", + "annotationData": "[{\"id\":\"drawing_1757570200181_d73fkmukw\",\"type\":\"drawing\",\"paths\":[{\"points\":[{\"x\":0.3374307712586988,\"y\":0.09173236040491389},{\"x\":0.3374307712586988,\"y\":0.09173236040491389},{\"x\":0.33911144352760636,\"y\":0.09173236040491389},{\"x\":0.34415346033432903,\"y\":0.09054471194885688},{\"x\":0.35423749394777443,\"y\":0.08935706349279988},{\"x\":0.3592795107544971,\"y\":0.08935706349279988},{\"x\":0.36768287209903494,\"y\":0.08935706349279988},{\"x\":0.3777669057124803,\"y\":0.08935706349279988},{\"x\":0.3962543006704635,\"y\":0.08935706349279988},{\"x\":0.4046576620150013,\"y\":0.09173236040491389},{\"x\":0.4197837124351694,\"y\":0.09767060268519893},{\"x\":0.43490976285533745,\"y\":0.10598414187759798},{\"x\":0.45171648554441307,\"y\":0.11548532952605403},{\"x\":0.47020388050239625,\"y\":0.12736181408662411},{\"x\":0.5172627040318081,\"y\":0.15467772857593529},{\"x\":0.5458341326032367,\"y\":0.16892951004861936},{\"x\":0.5760862334435728,\"y\":0.18436893997736045},{\"x\":0.5945736284015559,\"y\":0.19505777608187352},{\"x\":0.6130610233595392,\"y\":0.20218366681821556},{\"x\":0.6315484183175223,\"y\":0.2104972060106146},{\"x\":0.6500358132755055,\"y\":0.21643544829089964},{\"x\":0.6735652250402114,\"y\":0.22356133902724168},{\"x\":0.6954139645360097,\"y\":0.22949958130752673},{\"x\":0.717262704031808,\"y\":0.23306252667569774},{\"x\":0.7374307712586988,\"y\":0.23543782358781176},{\"x\":0.755918166216682,\"y\":0.23543782358781176},{\"x\":0.7760862334435727,\"y\":0.23543782358781176},{\"x\":0.7912122838637408,\"y\":0.23425017513175475},{\"x\":0.8080190065528164,\"y\":0.2271242843954127},{\"x\":0.8197837124351693,\"y\":0.21999839365907067},{\"x\":0.8315484183175224,\"y\":0.2093095575545576},{\"x\":0.8500358132755055,\"y\":0.18080599460918942},{\"x\":0.8533971578133206,\"y\":0.16536656468044833},{\"x\":0.8550778300822282,\"y\":0.15349008011987827},{\"x\":0.8550778300822282,\"y\":0.14517654092747923},{\"x\":0.8550778300822282,\"y\":0.1380506501911372},{\"x\":0.8550778300822282,\"y\":0.13211240791085213},{\"x\":0.8533971578133206,\"y\":0.1261741656305671},{\"x\":0.8466744687376904,\"y\":0.11786062643816805},{\"x\":0.8416324519309677,\"y\":0.11548532952605403},{\"x\":0.8382711073931526,\"y\":0.11429768106999703},{\"x\":0.8315484183175224,\"y\":0.11311003261394002},{\"x\":0.8265064015107997,\"y\":0.11311003261394002},{\"x\":0.8197837124351693,\"y\":0.11192238415788301},{\"x\":0.8113803510906316,\"y\":0.11192238415788301},{\"x\":0.8029769897460938,\"y\":0.11192238415788301}],\"color\":\"#ffeb3b\",\"thickness\":0.0033613445378151263}],\"pageNumber\":16,\"createdAt\":\"2025-09-11T05:56:40.181Z\",\"color\":\"#ffeb3b\"},{\"id\":\"drawing_1757570201797_i551jv161\",\"type\":\"drawing\",\"paths\":[{\"points\":[{\"x\":0.6718845527713039,\"y\":0.10598414187759798},{\"x\":0.6718845527713039,\"y\":0.10598414187759798},{\"x\":0.6702038805023963,\"y\":0.10717179033365498},{\"x\":0.6668425359645811,\"y\":0.109547087245769},{\"x\":0.6601198468889509,\"y\":0.11548532952605403},{\"x\":0.6500358132755055,\"y\":0.12379886871845308},{\"x\":0.636590435124245,\"y\":0.13567535327902316},{\"x\":0.6214643847040769,\"y\":0.14755183783959322},{\"x\":0.6080190065528165,\"y\":0.1594283224001633},{\"x\":0.57104421663685,\"y\":0.19030718225764548},{\"x\":0.5508761494099593,\"y\":0.20574661218638657},{\"x\":0.5374307712586988,\"y\":0.21762309674695665},{\"x\":0.5239853931074383,\"y\":0.2271242843954127},{\"x\":0.49877530907382484,\"y\":0.24731430814838182},{\"x\":0.49037194772928705,\"y\":0.25206490197260983},{\"x\":0.4853299309225643,\"y\":0.25562784734078087},{\"x\":0.4819685863847492,\"y\":0.2580031442528949},{\"x\":0.4786072418469341,\"y\":0.2615660896210659},{\"x\":0.475245897309119,\"y\":0.26275373807712293},{\"x\":0.4735652250402114,\"y\":0.26394138653317994},{\"x\":0.4735652250402114,\"y\":0.26512903498923696},{\"x\":0.47020388050239625,\"y\":0.26631668344529397},{\"x\":0.46684253596458114,\"y\":0.26987962881346494},{\"x\":0.46180051915785847,\"y\":0.27581787109375},{\"x\":0.44499379646878284,\"y\":0.2936325979346051},{\"x\":0.436590435124245,\"y\":0.3007584886709472},{\"x\":0.4298677460486148,\"y\":0.3090720278633462},{\"x\":0.4231450569729845,\"y\":0.31501027014363125},{\"x\":0.4181030401662618,\"y\":0.31976086396785924},{\"x\":0.4147416956284467,\"y\":0.3245114577920873}],\"color\":\"#ffeb3b\",\"thickness\":0.0033613445378151263}],\"pageNumber\":16,\"createdAt\":\"2025-09-11T05:56:41.797Z\",\"color\":\"#ffeb3b\"},{\"id\":\"drawing_1757570203474_6qjpbthb1\",\"type\":\"drawing\",\"paths\":[{\"points\":[{\"x\":0.23490976285533743,\"y\":0.47555873626201567},{\"x\":0.23659043512424502,\"y\":0.47555873626201567},{\"x\":0.23827110739315258,\"y\":0.47555873626201567},{\"x\":0.24499379646878283,\"y\":0.47555873626201567},{\"x\":0.2685232082334887,\"y\":0.4791216816301867},{\"x\":0.30381732588054755,\"y\":0.4850599239104717},{\"x\":0.4500358132755055,\"y\":0.5052499476634409},{\"x\":0.5054979981494551,\"y\":0.5111881899437258},{\"x\":0.5744055611746651,\"y\":0.5183140806800679},{\"x\":0.6315484183175223,\"y\":0.5218770260482389},{\"x\":0.6836492586536568,\"y\":0.523064674504296},{\"x\":0.7424727880654215,\"y\":0.524252322960353},{\"x\":0.7844895947881105,\"y\":0.52543997141641},{\"x\":0.8298677460486148,\"y\":0.52543997141641},{\"x\":0.8466744687376904,\"y\":0.52543997141641},{\"x\":0.8584391746200434,\"y\":0.52543997141641},{\"x\":0.8685232082334887,\"y\":0.52543997141641},{\"x\":0.875245897309119,\"y\":0.52543997141641},{\"x\":0.8786072418469341,\"y\":0.52543997141641}],\"color\":\"#ffeb3b\",\"thickness\":0.0033613445378151263}],\"pageNumber\":16,\"createdAt\":\"2025-09-11T05:56:43.474Z\",\"color\":\"#ffeb3b\"},{\"id\":\"highlight_1757570206626_azaes4fmo\",\"type\":\"highlight\",\"text\":\"for a number and so you can assume unless otherwise stated that\\nn translates to an integer that has the same number of bits as a WORD on a\\n32 bit machine, similarly l is a pseudo-name for a list where a list is a resizeable\\narray (e.g. a vector).\\nThe last major point of reference is that we always explicitly end a language\\nconstruct. For instance if we wish to close the scope of a for loop we will\\nexplicitly state end for rather than leaving the interpretation of when scopes\\nare closed to the reader. While implicit scope closure works well in simple code,\\nin complex cases it can lead to ambiguity.\\nThe pseudocode style that we use within this book is rather straightforward.\\nAll algorithms start with a simple algorithm signature, e.g.\\n1) algorithm AlgorithmName(arg1, arg2, ..., argN )\\n2) ...\\nn) end AlgorithmName\\nImmediately after the algorithm signature we list any Pre or Post condi-\\ntions.\\n1) algorithm AlgorithmName(n)\\n2) Pre: n is the value to compute the factorial of\\n3) n ≥ 0\\n4) Post: the factorial of n has been computed\\n5) // ...\\nn) end AlgorithmName\\nThe example above describes an algorithm by the name of AlgorithmName,\",\"bounds\":[{\"x\":0.31359608113264836,\"y\":0.2932175842430133,\"width\":0.473867413176208,\"height\":0.013495982118004008},{\"x\":0.20979754023191308,\"y\":0.30849337181399383,\"width\":0.009310554055606617,\"height\":0.011825851476673843},{\"x\":0.20979754023191308,\"y\":0.3074136946943197,\"width\":0.009310554055606617,\"height\":0.013495982118004008},{\"x\":0.2197884824095654,\"y\":0.30849337181399383,\"width\":0.004655264205291491,\"height\":0.011825851476673843},{\"x\":0.2197884824095654,\"y\":0.3074136946943197,\"width\":0.004655264205291491,\"height\":0.013495982118004008},{\"x\":0.22599550134995405,\"y\":0.30849337181399383,\"width\":0.5614180364528624,\"height\":0.011825851476673843},{\"x\":0.22599550134995405,\"y\":0.3074136946943197,\"width\":0.5614180364528624,\"height\":0.013495982118004008},{\"x\":0.20979754023191308,\"y\":0.3226978909091542,\"width\":0.17969837349002102,\"height\":0.011825887720828385},{\"x\":0.20979754023191308,\"y\":0.32161821378948,\"width\":0.17969837349002102,\"height\":0.013496018362158552},{\"x\":0.3893955390994288,\"y\":0.3226978909091542,\"width\":0.004655238560267857,\"height\":0.011825887720828385},{\"x\":0.3893955390994288,\"y\":0.32161821378948,\"width\":0.004655238560267857,\"height\":0.013496018362158552},{\"x\":0.3943969341887145,\"y\":0.3226978909091542,\"width\":0.003724221622242647,\"height\":0.011825887720828385},{\"x\":0.3943969341887145,\"y\":0.32161821378948,\"width\":0.003724221622242647,\"height\":0.013496018362158552},{\"x\":0.39939838056804755,\"y\":0.3226978909091542,\"width\":0.004655289850315126,\"height\":0.011825887720828385},{\"x\":0.39939838056804755,\"y\":0.32161821378948,\"width\":0.004655289850315126,\"height\":0.013496018362158552},{\"x\":0.40459077979336266,\"y\":0.3226978909091542,\"width\":0.3827883936777836,\"height\":0.011825887720828385},{\"x\":0.40459077979336266,\"y\":0.32161821378948,\"width\":0.3827883936777836,\"height\":0.013496018362158552},{\"x\":0.20979754023191308,\"y\":0.3368940013604606,\"width\":0.15271596187303046,\"height\":0.011825887720828385},{\"x\":0.20979754023191308,\"y\":0.33581432424078644,\"width\":0.15271596187303046,\"height\":0.013496018362158552},{\"x\":0.23488827232553178,\"y\":0.351090111811767,\"width\":0.5525581936876313,\"height\":0.011825887720828385},{\"x\":0.23488827232553178,\"y\":0.35001043469209286,\"width\":0.5525581936876313,\"height\":0.013496018362158552},{\"x\":0.20979754023191308,\"y\":0.3652946671510819,\"width\":0.07270243668756565,\"height\":0.011825887720828385},{\"x\":0.20979754023191308,\"y\":0.3642149900314077,\"width\":0.07270243668756565,\"height\":0.013496018362158552},{\"x\":0.2824913858365612,\"y\":0.3652946671510819,\"width\":0.004655289850315126,\"height\":0.011825887720828385},{\"x\":0.2824913858365612,\"y\":0.3642149900314077,\"width\":0.004655289850315126,\"height\":0.013496018362158552},{\"x\":0.29689886269449184,\"y\":0.3652946671510819,\"width\":0.35903592149750524,\"height\":0.011825887720828385},{\"x\":0.29689886269449184,\"y\":0.3642149900314077,\"width\":0.35903592149750524,\"height\":0.013496018362158552},{\"x\":0.6559993070714614,\"y\":0.3652946671510819,\"width\":0.004655289850315126,\"height\":0.011825887720828385},{\"x\":0.6559993070714614,\"y\":0.3642149900314077,\"width\":0.004655289850315126,\"height\":0.013496018362158552},{\"x\":0.6638894089129792,\"y\":0.3652946671510819,\"width\":0.023450373801864495,\"height\":0.011825887720828385},{\"x\":0.6638894089129792,\"y\":0.3642149900314077,\"width\":0.023450373801864495,\"height\":0.013496018362158552},{\"x\":0.6872970581054687,\"y\":0.3652946671510819,\"width\":0.004655289850315126,\"height\":0.011825887720828385},{\"x\":0.6872970581054687,\"y\":0.3642149900314077,\"width\":0.004655289850315126,\"height\":0.013496018362158552},{\"x\":0.6952945613059677,\"y\":0.3652946671510819,\"width\":0.09214882730435925,\"height\":0.011825887720828385},{\"x\":0.6952945613059677,\"y\":0.3642149900314077,\"width\":0.09214882730435925,\"height\":0.013496018362158552},{\"x\":0.20979754023191308,\"y\":0.3794907776023883,\"width\":0.1086890981978729,\"height\":0.011825887720828385},{\"x\":0.20979754023191308,\"y\":0.37841110048271415,\"width\":0.1086890981978729,\"height\":0.013496018362158552},{\"x\":0.3183966756868763,\"y\":0.3794907776023883,\"width\":0.004655238560267857,\"height\":0.011825887720828385},{\"x\":0.3183966756868763,\"y\":0.37841110048271415,\"width\":0.004655238560267857,\"height\":0.013496018362158552},{\"x\":0.3246991966952797,\"y\":0.3794907776023883,\"width\":0.060886261242778364,\"height\":0.011825887720828385},{\"x\":0.3246991966952797,\"y\":0.37841110048271415,\"width\":0.060886261242778364,\"height\":0.013496018362158552},{\"x\":0.3855996652811515,\"y\":0.3794907776023883,\"width\":0.004655289850315126,\"height\":0.011825887720828385},{\"x\":0.3855996652811515,\"y\":0.37841110048271415,\"width\":0.004655289850315126,\"height\":0.013496018362158552},{\"x\":0.3918902869985885,\"y\":0.3794907776023883,\"width\":0.3955122747341124,\"height\":0.011825887720828385},{\"x\":0.3918902869985885,\"y\":0.37841110048271415,\"width\":0.3955122747341124,\"height\":0.013496018362158552},{\"x\":0.20979754023191308,\"y\":0.39369533294170317,\"width\":0.5776641076352416,\"height\":0.011825851476673843},{\"x\":0.20979754023191308,\"y\":0.392615655822029,\"width\":0.5776641076352416,\"height\":0.013495982118004008},{\"x\":0.20979754023191308,\"y\":0.4078914433930096,\"width\":0.3067084817325368,\"height\":0.011825851476673843},{\"x\":0.20979754023191308,\"y\":0.40681176627333543,\"width\":0.3067084817325368,\"height\":0.013495982118004008},{\"x\":0.23488827232553178,\"y\":0.4220959624881699,\"width\":0.5525691697577468,\"height\":0.011825887720828385},{\"x\":0.23488827232553178,\"y\":0.4210162853684958,\"width\":0.5525691697577468,\"height\":0.013496018362158552},{\"x\":0.20979754023191308,\"y\":0.4362920729394763,\"width\":0.43357641396402313,\"height\":0.011825887720828385},{\"x\":0.20979754023191308,\"y\":0.4352123958198022,\"width\":0.43357641396402313,\"height\":0.013496018362158552},{\"x\":0.20979754023191308,\"y\":0.457497694146888,\"width\":0.014886115579044118,\"height\":0.011825851476673843},{\"x\":0.20979754023191308,\"y\":0.45641801702721385,\"width\":0.014886115579044118,\"height\":0.013495982118004008},{\"x\":0.22459892465286896,\"y\":0.457497694146888,\"width\":0.004655264205291491,\"height\":0.011825851476673843},{\"x\":0.22459892465286896,\"y\":0.45641801702721385,\"width\":0.004655264205291491,\"height\":0.013495982118004008},{\"x\":0.23019718202222295,\"y\":0.457497694146888,\"width\":0.0817542837447479,\"height\":0.011825851476673843},{\"x\":0.23019718202222295,\"y\":0.45641801702721385,\"width\":0.0817542837447479,\"height\":0.013495982118004008},{\"x\":0.3119986526104582,\"y\":0.457497694146888,\"width\":0.004655289850315126,\"height\":0.011825851476673843},{\"x\":0.3119986526104582,\"y\":0.45641801702721385,\"width\":0.004655289850315126,\"height\":0.013495982118004008},{\"x\":0.31748950862083114,\"y\":0.457497694146888,\"width\":0.12376862854516807,\"height\":0.011825851476673843},{\"x\":0.31748950862083114,\"y\":0.45641801702721385,\"width\":0.12376862854516807,\"height\":0.013495982118004008},{\"x\":0.44129583535074185,\"y\":0.457497694146888,\"width\":0.02486577394629727,\"height\":0.011825851476673843},{\"x\":0.44129583535074185,\"y\":0.45641801702721385,\"width\":0.02486577394629727,\"height\":0.013495982118004008},{\"x\":0.46679237429835213,\"y\":0.457497694146888,\"width\":0.013029826188287815,\"height\":0.011825851476673843},{\"x\":0.46679237429835213,\"y\":0.45641801702721385,\"width\":0.013029826188287815,\"height\":0.013495982118004008},{\"x\":0.4797913238781841,\"y\":0.457497694146888,\"width\":0.004655289850315126,\"height\":0.011825851476673843},{\"x\":0.4797913238781841,\"y\":0.45641801702721385,\"width\":0.004655289850315126,\"height\":0.013495982118004008},{\"x\":0.48538958124753806,\"y\":0.457497694146888,\"width\":0.02486577394629727,\"height\":0.011825851476673843},{\"x\":0.48538958124753806,\"y\":0.45641801702721385,\"width\":0.02486577394629727,\"height\":0.013495982118004008},{\"x\":0.510790669417181,\"y\":0.457497694146888,\"width\":0.03719620905002626,\"height\":0.011825851476673843},{\"x\":0.510790669417181,\"y\":0.45641801702721385,\"width\":0.03719620905002626,\"height\":0.013495982118004008},{\"x\":0.5479970338965664,\"y\":0.457497694146888,\"width\":0.004655238560267857,\"height\":0.011825851476673843},{\"x\":0.5479970338965664,\"y\":0.45641801702721385,\"width\":0.004655238560267857,\"height\":0.013495982118004008},{\"x\":0.5535952912659204,\"y\":0.457497694146888,\"width\":0.03891037371980042,\"height\":0.011825851476673843},{\"x\":0.5535952912659204,\"y\":0.45641801702721385,\"width\":0.03891037371980042,\"height\":0.013495982118004008},{\"x\":0.5924966379374015,\"y\":0.457497694146888,\"width\":0.004655289850315126,\"height\":0.011825851476673843},{\"x\":0.5924966379374015,\"y\":0.45641801702721385,\"width\":0.004655289850315126,\"height\":0.013495982118004008},{\"x\":0.5943945748465401,\"y\":0.457497694146888,\"width\":0.005574356207326681,\"height\":0.011825851476673843},{\"x\":0.5943945748465401,\"y\":0.45641801702721385,\"width\":0.005574356207326681,\"height\":0.013495982118004008},{\"x\":0.20979754023191308,\"y\":0.4716938045981944,\"width\":0.034424597475709036,\"height\":0.011825851476673843},{\"x\":0.20979754023191308,\"y\":0.47061412747852027,\"width\":0.034424597475709036,\"height\":0.013495982118004008},{\"x\":0.20979754023191308,\"y\":0.4858899150495008,\"width\":0.0158172607421875,\"height\":0.011825851476673843},{\"x\":0.20979754023191308,\"y\":0.4848102379298267,\"width\":0.0158172607421875,\"height\":0.013495982118004008},{\"x\":0.2255896688509388,\"y\":0.4858899150495008,\"width\":0.004655264205291491,\"height\":0.011825851476673843},{\"x\":0.2255896688509388,\"y\":0.4848102379298267,\"width\":0.004655264205291491,\"height\":0.013495982118004008},{\"x\":0.2310924241522781,\"y\":0.4858899150495008,\"width\":0.03022709694229254,\"height\":0.011825851476673843},{\"x\":0.2310924241522781,\"y\":0.4848102379298267,\"width\":0.03022709694229254,\"height\":0.013495982118004008},{\"x\":0.2613994309882156,\"y\":0.4858899150495008,\"width\":0.004655264205291491,\"height\":0.011825851476673843},{\"x\":0.2613994309882156,\"y\":0.4848102379298267,\"width\":0.004655264205291491,\"height\":0.013495982118004008},{\"x\":0.26689026135356486,\"y\":0.4858899150495008,\"width\":0.11725630559841124,\"height\":0.011825851476673843},{\"x\":0.26689026135356486,\"y\":0.4848102379298267,\"width\":0.11725630559841124,\"height\":0.013495982118004008},{\"x\":0.23488827232553178,\"y\":0.5212916104640644,\"width\":0.3994384765625,\"height\":0.011825887720828385},{\"x\":0.23488827232553178,\"y\":0.5202119695885448,\"width\":0.3994384765625,\"height\":0.013495945873849466},{\"x\":0.6342985906520812,\"y\":0.5212916104640644,\"width\":0.004655238560267857,\"height\":0.011825887720828385},{\"x\":0.6342985906520812,\"y\":0.5202119695885448,\"width\":0.004655238560267857,\"height\":0.013495945873849466},{\"x\":0.6409950192235098,\"y\":0.5212916104640644,\"width\":0.029930922564338235,\"height\":0.011825887720828385},{\"x\":0.6409950192235098,\"y\":0.5202119695885448,\"width\":0.029930922564338235,\"height\":0.013495945873849466},{\"x\":0.6709916443383994,\"y\":0.5212916104640644,\"width\":0.004655289850315126,\"height\":0.011825887720828385},{\"x\":0.6709916443383994,\"y\":0.5202119695885448,\"width\":0.004655289850315126,\"height\":0.013495945873849466},{\"x\":0.6774971200638459,\"y\":0.5212916104640644,\"width\":0.014933045972295169,\"height\":0.011825887720828385},{\"x\":0.6774971200638459,\"y\":0.5202119695885448,\"width\":0.014933045972295169,\"height\":0.013495945873849466},{\"x\":0.6923939552627691,\"y\":0.5212916104640644,\"width\":0.004655289850315126,\"height\":0.011825887720828385},{\"x\":0.6923939552627691,\"y\":0.5202119695885448,\"width\":0.004655289850315126,\"height\":0.013495945873849466},{\"x\":0.6988994309882156,\"y\":0.5212916104640644,\"width\":0.03733987247242647,\"height\":0.011825887720828385},{\"x\":0.6988994309882156,\"y\":0.5202119695885448,\"width\":0.03733987247242647,\"height\":0.013495945873849466},{\"x\":0.7362967483135833,\"y\":0.5212916104640644,\"width\":0.004655289850315126,\"height\":0.011825887720828385},{\"x\":0.7362967483135833,\"y\":0.5202119695885448,\"width\":0.004655289850315126,\"height\":0.013495945873849466},{\"x\":0.7427902734580161,\"y\":0.5212916104640644,\"width\":0.04466121897977941,\"height\":0.011825887720828385},{\"x\":0.7427902734580161,\"y\":0.5202119695885448,\"width\":0.04466121897977941,\"height\":0.013495945873849466},{\"x\":0.20979754023191308,\"y\":0.5354961295592247,\"width\":0.0400994308856355,\"height\":0.011825887720828385},{\"x\":0.20979754023191308,\"y\":0.5344164886837051,\"width\":0.0400994308856355,\"height\":0.013496018362158552},{\"x\":0.20979754023191308,\"y\":0.5566933058786279,\"width\":0.014886115579044118,\"height\":0.011825887720828385},{\"x\":0.20979754023191308,\"y\":0.5556136650031083,\"width\":0.014886115579044118,\"height\":0.013495945873849466},{\"x\":0.22459892465286896,\"y\":0.5566933058786279,\"width\":0.004655264205291491,\"height\":0.011825887720828385},{\"x\":0.22459892465286896,\"y\":0.5556136650031083,\"width\":0.004655264205291491,\"height\":0.013495945873849466},{\"x\":0.23019718202222295,\"y\":0.5566933058786279,\"width\":0.0817542837447479,\"height\":0.011825887720828385},{\"x\":0.23019718202222295,\"y\":0.5556136650031083,\"width\":0.0817542837447479,\"height\":0.013495945873849466},{\"x\":0.3119986526104582,\"y\":0.5566933058786279,\"width\":0.004655289850315126,\"height\":0.011825887720828385},{\"x\":0.3119986526104582,\"y\":0.5556136650031083,\"width\":0.004655289850315126,\"height\":0.013495945873849466},{\"x\":0.31748950862083114,\"y\":0.5566933058786279,\"width\":0.12376862854516807,\"height\":0.011825887720828385},{\"x\":0.31748950862083114,\"y\":0.5556136650031083,\"width\":0.12376862854516807,\"height\":0.013495945873849466},{\"x\":0.44129583535074185,\"y\":0.5566933058786279,\"width\":0.009310528410582983,\"height\":0.011825887720828385},{\"x\":0.44129583535074185,\"y\":0.5556136650031083,\"width\":0.009310528410582983,\"height\":0.013495945873849466},{\"x\":0.45139417888737526,\"y\":0.5566933058786279,\"width\":0.005574407497373949,\"height\":0.011825887720828385},{\"x\":0.45139417888737526,\"y\":0.5556136650031083,\"width\":0.005574407497373949,\"height\":0.013495945873849466},{\"x\":0.20979754023191308,\"y\":0.5708894163299343,\"width\":0.014886115579044118,\"height\":0.011825887720828385},{\"x\":0.20979754023191308,\"y\":0.5698097754544147,\"width\":0.014886115579044118,\"height\":0.013495945873849466},{\"x\":0.22459892465286896,\"y\":0.5708894163299343,\"width\":0.004655264205291491,\"height\":0.011825887720828385},{\"x\":0.22459892465286896,\"y\":0.5698097754544147,\"width\":0.004655264205291491,\"height\":0.013495945873849466},{\"x\":0.25479850448480174,\"y\":0.5708894163299343,\"width\":0.03527093454569328,\"height\":0.011825887720828385},{\"x\":0.25479850448480174,\"y\":0.5698097754544147,\"width\":0.03527093454569328,\"height\":0.013495945873849466},{\"x\":0.29009500711905856,\"y\":0.5708894163299343,\"width\":0.004655264205291491,\"height\":0.011825887720828385},{\"x\":0.29009500711905856,\"y\":0.5698097754544147,\"width\":0.004655264205291491,\"height\":0.013495945873849466},{\"x\":0.30119604543477546,\"y\":0.5708894163299343,\"width\":0.009310528410582983,\"height\":0.011825887720828385},{\"x\":0.30119604543477546,\"y\":0.5698097754544147,\"width\":0.009310528410582983,\"height\":0.013495945873849466},{\"x\":0.3112943889714089,\"y\":0.5708894163299343,\"width\":0.004655289850315126,\"height\":0.011825887720828385},{\"x\":0.3112943889714089,\"y\":0.5698097754544147,\"width\":0.004655289850315126,\"height\":0.013495945873849466},{\"x\":0.31689264634076286,\"y\":0.5708894163299343,\"width\":0.285250469816833,\"height\":0.011825887720828385},{\"x\":0.31689264634076286,\"y\":0.5698097754544147,\"width\":0.285250469816833,\"height\":0.013495945873849466},{\"x\":0.20979754023191308,\"y\":0.5850940079134037,\"width\":0.014886115579044118,\"height\":0.011825815232519299},{\"x\":0.20979754023191308,\"y\":0.5840142945495751,\"width\":0.014886115579044118,\"height\":0.013496018362158552},{\"x\":0.22459892465286896,\"y\":0.5850940079134037,\"width\":0.004655264205291491,\"height\":0.011825815232519299},{\"x\":0.22459892465286896,\"y\":0.5840142945495751,\"width\":0.004655264205291491,\"height\":0.013496018362158552},{\"x\":0.2994891126616662,\"y\":0.5850940079134037,\"width\":0.009310528410582983,\"height\":0.011825815232519299},{\"x\":0.2994891126616662,\"y\":0.5840142945495751,\"width\":0.009310528410582983,\"height\":0.013496018362158552},{\"x\":0.3094919541302849,\"y\":0.5850940079134037,\"width\":0.004655289850315126,\"height\":0.011825815232519299},{\"x\":0.3094919541302849,\"y\":0.5840142945495751,\"width\":0.004655289850315126,\"height\":0.013496018362158552},{\"x\":0.3141949950146074,\"y\":0.5850940079134037,\"width\":0.009191176470588236,\"height\":0.011825815232519299},{\"x\":0.3141949950146074,\"y\":0.5840142945495751,\"width\":0.009191176470588236,\"height\":0.013496018362158552},{\"x\":0.32719394459443935,\"y\":0.5850940079134037,\"width\":0.004655238560267857,\"height\":0.011825815232519299},{\"x\":0.32719394459443935,\"y\":0.5840142945495751,\"width\":0.004655238560267857,\"height\":0.013496018362158552},{\"x\":0.33178953282973345,\"y\":0.5850940079134037,\"width\":0.009310528410582983,\"height\":0.011825815232519299},{\"x\":0.33178953282973345,\"y\":0.5840142945495751,\"width\":0.009310528410582983,\"height\":0.013496018362158552},{\"x\":0.20979754023191308,\"y\":0.5992901183647101,\"width\":0.014886115579044118,\"height\":0.011825815232519299},{\"x\":0.20979754023191308,\"y\":0.5982104050008814,\"width\":0.014886115579044118,\"height\":0.013496018362158552},{\"x\":0.22459892465286896,\"y\":0.5992901183647101,\"width\":0.004655264205291491,\"height\":0.011825815232519299},{\"x\":0.22459892465286896,\"y\":0.5982104050008814,\"width\":0.004655264205291491,\"height\":0.013496018362158552},{\"x\":0.25479850448480174,\"y\":0.5992901183647101,\"width\":0.042693527606355045,\"height\":0.011825815232519299},{\"x\":0.25479850448480174,\"y\":0.5982104050008814,\"width\":0.042693527606355045,\"height\":0.013496018362158552},{\"x\":0.29749567368451285,\"y\":0.5992901183647101,\"width\":0.004655289850315126,\"height\":0.011825815232519299},{\"x\":0.29749567368451285,\"y\":0.5982104050008814,\"width\":0.004655289850315126,\"height\":0.013496018362158552},{\"x\":0.30309393105386684,\"y\":0.5992901183647101,\"width\":0.10794703379398635,\"height\":0.011825815232519299},{\"x\":0.30309393105386684,\"y\":0.5982104050008814,\"width\":0.10794703379398635,\"height\":0.013496018362158552},{\"x\":0.41098880286978073,\"y\":0.5992901183647101,\"width\":0.004655289850315126,\"height\":0.011825815232519299},{\"x\":0.41098880286978073,\"y\":0.5982104050008814,\"width\":0.004655289850315126,\"height\":0.013496018362158552},{\"x\":0.4165990108201484,\"y\":0.5992901183647101,\"width\":0.009310528410582983,\"height\":0.011825815232519299},{\"x\":0.4165990108201484,\"y\":0.5982104050008814,\"width\":0.009310528410582983,\"height\":0.013496018362158552},{\"x\":0.4266973543567818,\"y\":0.5992901183647101,\"width\":0.004655289850315126,\"height\":0.011825815232519299},{\"x\":0.4266973543567818,\"y\":0.5982104050008814,\"width\":0.004655289850315126,\"height\":0.013496018362158552},{\"x\":0.4322956117261358,\"y\":0.5992901183647101,\"width\":0.141021728515625,\"height\":0.011825815232519299},{\"x\":0.4322956117261358,\"y\":0.5982104050008814,\"width\":0.141021728515625,\"height\":0.013496018362158552},{\"x\":0.20979754023191308,\"y\":0.6134946374598704,\"width\":0.014886115579044118,\"height\":0.011825887720828385},{\"x\":0.20979754023191308,\"y\":0.6124149240960418,\"width\":0.014886115579044118,\"height\":0.013496018362158552},{\"x\":0.22459892465286896,\"y\":0.6134946374598704,\"width\":0.004655264205291491,\"height\":0.011825887720828385},{\"x\":0.22459892465286896,\"y\":0.6124149240960418,\"width\":0.004655264205291491,\"height\":0.013496018362158552},{\"x\":0.25479850448480174,\"y\":0.6134946374598704,\"width\":0.03628201524750525,\"height\":0.011825887720828385},{\"x\":0.25479850448480174,\"y\":0.6124149240960418,\"width\":0.03628201524750525,\"height\":0.013496018362158552},{\"x\":0.20979754023191308,\"y\":0.6276907479111768,\"width\":0.0158172607421875,\"height\":0.011825887720828385},{\"x\":0.20979754023191308,\"y\":0.6266110345473482,\"width\":0.0158172607421875,\"height\":0.013496018362158552},{\"x\":0.2255896688509388,\"y\":0.6276907479111768,\"width\":0.004655264205291491,\"height\":0.011825887720828385},{\"x\":0.2255896688509388,\"y\":0.6266110345473482,\"width\":0.004655264205291491,\"height\":0.013496018362158552},{\"x\":0.2310924241522781,\"y\":0.6276907479111768,\"width\":0.03022709694229254,\"height\":0.011825887720828385},{\"x\":0.2310924241522781,\"y\":0.6266110345473482,\"width\":0.03022709694229254,\"height\":0.013496018362158552},{\"x\":0.2613994309882156,\"y\":0.6276907479111768,\"width\":0.004655264205291491,\"height\":0.011825887720828385},{\"x\":0.2613994309882156,\"y\":0.6266110345473482,\"width\":0.004655264205291491,\"height\":0.013496018362158552},{\"x\":0.26689026135356486,\"y\":0.6276907479111768,\"width\":0.11725630559841124,\"height\":0.011825887720828385},{\"x\":0.26689026135356486,\"y\":0.6266110345473482,\"width\":0.11725630559841124,\"height\":0.013496018362158552},{\"x\":0.23488827232553178,\"y\":0.6630924433257405,\"width\":0.4274803353958771,\"height\":0.011825887720828385},{\"x\":0.23488827232553178,\"y\":0.6620128024502209,\"width\":0.4274803353958771,\"height\":0.013495945873849466},{\"x\":0.6622898774988512,\"y\":0.6630924433257405,\"width\":0.004655289850315126,\"height\":0.011825887720828385},{\"x\":0.6622898774988512,\"y\":0.6620128024502209,\"width\":0.004655289850315126,\"height\":0.013495945873849466},{\"x\":0.6677926840902376,\"y\":0.6630924433257405,\"width\":0.11497746315323004,\"height\":0.011825887720828385},{\"x\":0.6677926840902376,\"y\":0.6620128024502209,\"width\":0.11497746315323004,\"height\":0.013495945873849466},{\"x\":0.7827897400415245,\"y\":0.6630924433257405,\"width\":0.004655289850315126,\"height\":0.011825887720828385},{\"x\":0.7827897400415245,\"y\":0.6620128024502209,\"width\":0.004655289850315126,\"height\":0.013495945873849466}],\"color\":\"#e91e63\",\"pageNumber\":16,\"createdAt\":\"2025-09-11T05:56:46.626Z\"},{\"id\":\"drawing_1757570296777_xl9038l1b\",\"type\":\"drawing\",\"paths\":[{\"points\":[{\"x\":0.6987753090738248,\"y\":0.30982779097387175},{\"x\":0.6987753090738248,\"y\":0.30982779097387175},{\"x\":0.7038173258805476,\"y\":0.31339073634204273},{\"x\":0.7122206872250854,\"y\":0.3193289786223278},{\"x\":0.7223047208385307,\"y\":0.32407957244655583},{\"x\":0.7407921157965139,\"y\":0.33239311163895485},{\"x\":0.7575988384855895,\"y\":0.34070665083135393},{\"x\":0.767682872099035,\"y\":0.34426959619952496},{\"x\":0.7844895947881105,\"y\":0.34902019002375295},{\"x\":0.8029769897460938,\"y\":0.352583135391924},{\"x\":0.8214643847040769,\"y\":0.354958432304038},{\"x\":0.8399517796620601,\"y\":0.356146080760095},{\"x\":0.875245897309119,\"y\":0.354958432304038},{\"x\":0.8903719477292871,\"y\":0.35020783847980996},{\"x\":0.9004559813427324,\"y\":0.3395190023752969},{\"x\":0.9071786704183626,\"y\":0.32526722090261284},{\"x\":0.9088593426872702,\"y\":0.31339073634204273},{\"x\":0.9105400149561778,\"y\":0.30745249406175773},{\"x\":0.9105400149561778,\"y\":0.29082541567695963},{\"x\":0.9088593426872702,\"y\":0.28251187648456055},{\"x\":0.9038173258805475,\"y\":0.27776128266033256},{\"x\":0.8903719477292871,\"y\":0.27419833729216153},{\"x\":0.8802879141158416,\"y\":0.27419833729216153},{\"x\":0.8668425359645812,\"y\":0.2730106888361045},{\"x\":0.851716485544413,\"y\":0.2730106888361045},{\"x\":0.8281870737797072,\"y\":0.27657363420427555},{\"x\":0.6399517796620602,\"y\":0.352583135391924},{\"x\":0.6265064015107996,\"y\":0.35852137767220904},{\"x\":0.6181030401662618,\"y\":0.36327197149643703},{\"x\":0.6113803510906316,\"y\":0.36683491686460806},{\"x\":0.6046576620150013,\"y\":0.3703978622327791},{\"x\":0.5996156452082786,\"y\":0.3727731591448931},{\"x\":0.597934972939371,\"y\":0.37396080760095013},{\"x\":0.5945736284015559,\"y\":0.37514845605700714},{\"x\":0.5928929561326484,\"y\":0.37514845605700714},{\"x\":0.5912122838637408,\"y\":0.37633610451306415},{\"x\":0.5912122838637408,\"y\":0.37633610451306415},{\"x\":0.5878509393259257,\"y\":0.37633610451306415},{\"x\":0.5844895947881106,\"y\":0.37633610451306415}],\"color\":\"#ffeb3b\",\"thickness\":0.0033613445378151263}],\"pageNumber\":17,\"createdAt\":\"2025-09-11T05:58:16.777Z\",\"color\":\"#ffeb3b\"},{\"id\":\"drawing_1757570297831_ze0qj2m7u\",\"type\":\"drawing\",\"paths\":[{\"points\":[{\"x\":0.20801900655281644,\"y\":0.186312351543943},{\"x\":0.209699678821724,\"y\":0.186312351543943},{\"x\":0.209699678821724,\"y\":0.1875},{\"x\":0.21306102335953914,\"y\":0.188687648456057},{\"x\":0.2197837124351694,\"y\":0.19106294536817103},{\"x\":0.2281870737797072,\"y\":0.19581353919239905},{\"x\":0.23995177966206013,\"y\":0.20175178147268408},{\"x\":0.2500358132755055,\"y\":0.20769002375296913},{\"x\":0.263481191426766,\"y\":0.21481591448931117},{\"x\":0.3004559813427324,\"y\":0.23381828978622327},{\"x\":0.32566606537634585,\"y\":0.24688242280285036},{\"x\":0.3458341326032366,\"y\":0.2563836104513064},{\"x\":0.36096018302340466,\"y\":0.2623218527315915},{\"x\":0.37440556117466517,\"y\":0.26707244655581946},{\"x\":0.3962543006704635,\"y\":0.2718230403800475},{\"x\":0.4080190065528164,\"y\":0.27419833729216153},{\"x\":0.4197837124351694,\"y\":0.27419833729216153},{\"x\":0.4298677460486148,\"y\":0.27538598574821854},{\"x\":0.4399517796620601,\"y\":0.27419833729216153},{\"x\":0.44835514100659796,\"y\":0.2706353919239905},{\"x\":0.45171648554441307,\"y\":0.26350950118764843},{\"x\":0.4550778300822282,\"y\":0.24925771971496438},{\"x\":0.45675850235113574,\"y\":0.23500593824228028},{\"x\":0.45675850235113574,\"y\":0.22669239904988123},{\"x\":0.3912122838637408,\"y\":0.18037410926365796},{\"x\":0.3727248889057576,\"y\":0.18156175771971497},{\"x\":0.34751480487214415,\"y\":0.186312351543943},{\"x\":0.32230472083853073,\"y\":0.19462589073634204},{\"x\":0.29373329226710215,\"y\":0.20650237529691212},{\"x\":0.23659043512424502,\"y\":0.23975653206650832},{\"x\":0.2147416956284467,\"y\":0.2551959619952494},{\"x\":0.19457362840155593,\"y\":0.2706353919239905},{\"x\":0.17272488890575763,\"y\":0.2872624703087886},{\"x\":0.15759883848558956,\"y\":0.29913895486935865},{\"x\":0.1407921157965139,\"y\":0.3122030878859858},{\"x\":0.1323887544519761,\"y\":0.3193289786223278},{\"x\":0.12734673764525342,\"y\":0.32407957244655583},{\"x\":0.12230472083853072,\"y\":0.32645486935866985},{\"x\":0.12062404856962317,\"y\":0.3288301662707839},{\"x\":0.1189433763007156,\"y\":0.3288301662707839},{\"x\":0.1189433763007156,\"y\":0.33001781472684083}],\"color\":\"#ffeb3b\",\"thickness\":0.0033613445378151263}],\"pageNumber\":17,\"createdAt\":\"2025-09-11T05:58:17.831Z\",\"color\":\"#ffeb3b\"},{\"id\":\"drawing_1757570298862_ggnfrq5sg\",\"type\":\"drawing\",\"paths\":[{\"points\":[{\"x\":0.22986774604861476,\"y\":0.37752375296912116},{\"x\":0.22986774604861476,\"y\":0.37752375296912116},{\"x\":0.23154841831752232,\"y\":0.3787114014251782},{\"x\":0.23154841831752232,\"y\":0.3787114014251782},{\"x\":0.23322909058642988,\"y\":0.37989904988123513},{\"x\":0.2786072418469341,\"y\":0.41315320665083133},{\"x\":0.2853299309225643,\"y\":0.41552850356294535},{\"x\":0.2886912754603795,\"y\":0.41671615201900236},{\"x\":0.3004559813427324,\"y\":0.4179038004750594},{\"x\":0.30381732588054755,\"y\":0.4179038004750594},{\"x\":0.30717867041836266,\"y\":0.4179038004750594},{\"x\":0.31222068722508534,\"y\":0.41552850356294535},{\"x\":0.31726270403180806,\"y\":0.40840261282660334},{\"x\":0.3206240485696232,\"y\":0.39890142517814725},{\"x\":0.32230472083853073,\"y\":0.3882125890736342},{\"x\":0.3239853931074383,\"y\":0.37396080760095013},{\"x\":0.3239853931074383,\"y\":0.354958432304038},{\"x\":0.3239853931074383,\"y\":0.345457244655582},{\"x\":0.3239853931074383,\"y\":0.3371437054631829},{\"x\":0.32230472083853073,\"y\":0.33239311163895485},{\"x\":0.31726270403180806,\"y\":0.32764251781472686},{\"x\":0.3088593426872702,\"y\":0.3228919239904988},{\"x\":0.30381732588054755,\"y\":0.3228919239904988},{\"x\":0.2987753090738248,\"y\":0.3228919239904988},{\"x\":0.29373329226710215,\"y\":0.3228919239904988},{\"x\":0.2870106031914719,\"y\":0.32407957244655583},{\"x\":0.2685232082334887,\"y\":0.33239311163895485},{\"x\":0.2601198468889509,\"y\":0.3395190023752969},{\"x\":0.2500358132755055,\"y\":0.34902019002375295},{\"x\":0.23827110739315258,\"y\":0.36089667458432306},{\"x\":0.22650640151079962,\"y\":0.3727731591448931},{\"x\":0.21306102335953914,\"y\":0.3870249406175772},{\"x\":0.1861702670570181,\"y\":0.41434085510688834},{\"x\":0.17608623344357274,\"y\":0.42384204275534443},{\"x\":0.16768287209903493,\"y\":0.43215558194774345},{\"x\":0.15759883848558956,\"y\":0.44284441805225655},{\"x\":0.14919547714105175,\"y\":0.45115795724465557},{\"x\":0.1407921157965139,\"y\":0.45947149643705465},{\"x\":0.13070808218306854,\"y\":0.46778503562945367},{\"x\":0.12734673764525342,\"y\":0.4713479809976247}],\"color\":\"#ffeb3b\",\"thickness\":0.0033613445378151263}],\"pageNumber\":17,\"createdAt\":\"2025-09-11T05:58:18.862Z\",\"color\":\"#ffeb3b\"},{\"id\":\"highlight_1757570300380_t69zgza6y\",\"type\":\"highlight\",\"text\":\"tuitively map relationships between data structures rather\\nthan trying to work out a few values on paper and the rest in your head. We\\nsuggest you put everything on paper irrespective of how trivial some variables\\nand calculations may be so that you always have a point of reference.\\nWhen dealing with recursive algorithm traces we recommend you do the\\nsame as the above, but also have a table that records function calls and who\\nthey return to. This approach is a far cleaner way than drawing out an elaborate\\nmap of function calls with arrows to one another, which gets large quickly and\\nsimply makes things more complex to follow. Track everything in a simple and\\nsystematic way to make your time studying the implementations far easier.\\n1.5 Book outline\\nWe have split this book into two parts:\\nPart 1: Provides discussion and pseudo-implementations of common and uncom-\\nmon data structures; and\\nPart 2: Provides algorithms of varying purposes from sorting to string operations.\\nThe reader doesn’t have to read the book sequentially from beginning to\\nend: chapters can be read independently from one another. We suggest that\\nin part 1 you read each chapter in its entirety, but in part 2 you can get away\\nwith just reading the section of a chapter that describes the algorithm you are\\ninterested in.\\nEach of the chapters on data structures present initially the algorithms con-\",\"bounds\":[{\"x\":0.3412160793272387,\"y\":0.2762126061808752,\"width\":0.44626177619485297,\"height\":0.013495982118004008},{\"x\":0.20979754023191308,\"y\":0.29149683863986414,\"width\":0.5776920094209559,\"height\":0.011825851476673843},{\"x\":0.20979754023191308,\"y\":0.29041716152019004,\"width\":0.5776920094209559,\"height\":0.013495982118004008},{\"x\":0.20979754023191308,\"y\":0.30569294909117056,\"width\":0.5776841107536764,\"height\":0.011825851476673843},{\"x\":0.20979754023191308,\"y\":0.30461327197149646,\"width\":0.5776841107536764,\"height\":0.013495982118004008},{\"x\":0.20979754023191308,\"y\":0.3198974681863309,\"width\":0.5096699177717963,\"height\":0.011825887720828385},{\"x\":0.20979754023191308,\"y\":0.31881779106665675,\"width\":0.5096699177717963,\"height\":0.013496018362158552},{\"x\":0.23488827232553178,\"y\":0.33409357863763733,\"width\":0.5525503976004464,\"height\":0.011825887720828385},{\"x\":0.23488827232553178,\"y\":0.3330139015179632,\"width\":0.5525503976004464,\"height\":0.013496018362158552},{\"x\":0.20979754023191308,\"y\":0.3482981339769522,\"width\":0.577669339220063,\"height\":0.011825887720828385},{\"x\":0.20979754023191308,\"y\":0.34721845685727803,\"width\":0.577669339220063,\"height\":0.013496018362158552},{\"x\":0.20979754023191308,\"y\":0.3624942444282586,\"width\":0.5773846794577205,\"height\":0.011825887720828385},{\"x\":0.20979754023191308,\"y\":0.36141456730858446,\"width\":0.5773846794577205,\"height\":0.013496018362158552},{\"x\":0.20979754023191308,\"y\":0.37669035487956504,\"width\":0.5776862649356618,\"height\":0.011825887720828385},{\"x\":0.20979754023191308,\"y\":0.3756106777598909,\"width\":0.5776862649356618,\"height\":0.013496018362158552},{\"x\":0.20979754023191308,\"y\":0.3908949102188799,\"width\":0.5773778065913866,\"height\":0.011825851476673843},{\"x\":0.20979754023191308,\"y\":0.38981523309920574,\"width\":0.5773778065913866,\"height\":0.013495982118004008},{\"x\":0.20979754023191308,\"y\":0.4050910206701863,\"width\":0.5517693014705882,\"height\":0.011825851476673843},{\"x\":0.20979754023191308,\"y\":0.40401134355051216,\"width\":0.5517693014705882,\"height\":0.013495982118004008},{\"x\":0.20979754023191308,\"y\":0.43969139407196406,\"width\":0.03465512059315914,\"height\":0.01703025835993171},{\"x\":0.20979754023191308,\"y\":0.4380718602703756,\"width\":0.03465512059315914,\"height\":0.019434260642443586},{\"x\":0.24438977922712055,\"y\":0.43969139407196406,\"width\":0.006696428571428571,\"height\":0.01703025835993171},{\"x\":0.24438977922712055,\"y\":0.4380718602703756,\"width\":0.006696428571428571,\"height\":0.019434260642443586},{\"x\":0.2714978001698726,\"y\":0.43969139407196406,\"width\":0.1521651837004333,\"height\":0.01703025835993171},{\"x\":0.2714978001698726,\"y\":0.4380718602703756,\"width\":0.1521651837004333,\"height\":0.019434260642443586},{\"x\":0.20979754023191308,\"y\":0.46979593381179485,\"width\":0.28636777220653886,\"height\":0.011825887720828385},{\"x\":0.20979754023191308,\"y\":0.4687162204479661,\"width\":0.28636777220653886,\"height\":0.013496018362158552},{\"x\":0.19229850448480174,\"y\":0.493894744655582,\"width\":0.5951769916951155,\"height\":0.011825815232519299},{\"x\":0.19229850448480174,\"y\":0.49281503129175325,\"width\":0.5951769916951155,\"height\":0.013496018362158552},{\"x\":0.2515994929465927,\"y\":0.5080908551068883,\"width\":0.18538279813878678,\"height\":0.011825815232519299},{\"x\":0.2515994929465927,\"y\":0.5070111417430597,\"width\":0.18538279813878678,\"height\":0.013496018362158552},{\"x\":0.19229850448480174,\"y\":0.5308906754518631,\"width\":0.5951731962316177,\"height\":0.011825815232519299},{\"x\":0.19229850448480174,\"y\":0.5298109620880345,\"width\":0.5951731962316177,\"height\":0.013496018362158552},{\"x\":0.23488827232553178,\"y\":0.5549894138073411,\"width\":0.5525517311416754,\"height\":0.011825887720828385},{\"x\":0.23488827232553178,\"y\":0.5539097729318215,\"width\":0.5525517311416754,\"height\":0.013496018362158552},{\"x\":0.20979754023191308,\"y\":0.5691940053908106,\"width\":0.44576708368894435,\"height\":0.011825887720828385},{\"x\":0.20979754023191308,\"y\":0.5681142920269819,\"width\":0.44576708368894435,\"height\":0.013496018362158552},{\"x\":0.6554979468594079,\"y\":0.5691940053908106,\"width\":0.004655289850315126,\"height\":0.011825887720828385},{\"x\":0.6554979468594079,\"y\":0.5681142920269819,\"width\":0.004655289850315126,\"height\":0.013496018362158552},{\"x\":0.6665990108201484,\"y\":0.5691940053908106,\"width\":0.12080909023765757,\"height\":0.011825887720828385},{\"x\":0.6665990108201484,\"y\":0.5681142920269819,\"width\":0.12080909023765757,\"height\":0.013496018362158552},{\"x\":0.20979754023191308,\"y\":0.583390115842117,\"width\":0.5777005235688025,\"height\":0.011825887720828385},{\"x\":0.20979754023191308,\"y\":0.5823104024782882,\"width\":0.5777005235688025,\"height\":0.013496018362158552},{\"x\":0.20979754023191308,\"y\":0.5975946349372773,\"width\":0.5776641076352416,\"height\":0.011825887720828385},{\"x\":0.20979754023191308,\"y\":0.5965149940617577,\"width\":0.5776641076352416,\"height\":0.013495945873849466},{\"x\":0.20979754023191308,\"y\":0.6117907453885837,\"width\":0.09548468068868173,\"height\":0.011825887720828385},{\"x\":0.20979754023191308,\"y\":0.6107111045130641,\"width\":0.09548468068868173,\"height\":0.013495945873849466},{\"x\":0.23488827232553178,\"y\":0.6259953369720531,\"width\":0.5525452685957195,\"height\":0.011825815232519299},{\"x\":0.23488827232553178,\"y\":0.6249156236082245,\"width\":0.5525452685957195,\"height\":0.013496018362158552}],\"color\":\"#ffeb3b\",\"pageNumber\":17,\"createdAt\":\"2025-09-11T05:58:20.380Z\"},{\"id\":\"drawing_1757570318167_cc060pn9x\",\"type\":\"drawing\",\"paths\":[{\"points\":[{\"x\":0.5928929561326484,\"y\":0.4023564082709741},{\"x\":0.5945736284015559,\"y\":0.4035440567270311},{\"x\":0.5996156452082786,\"y\":0.40591935363914505},{\"x\":0.609699678821724,\"y\":0.4118575959194301},{\"x\":0.6248257292418921,\"y\":0.4213587835678862},{\"x\":0.6449937964687829,\"y\":0.43323526812845625},{\"x\":0.7004559813427325,\"y\":0.4605511826177674},{\"x\":0.7223047208385307,\"y\":0.4688647218101665},{\"x\":0.7407921157965139,\"y\":0.47361531563439446},{\"x\":0.7643215275612198,\"y\":0.4795535579146795},{\"x\":0.7844895947881105,\"y\":0.48074120637073653},{\"x\":0.8012963174771862,\"y\":0.48192885482679354},{\"x\":0.8214643847040769,\"y\":0.4795535579146795},{\"x\":0.8332290905864299,\"y\":0.47242766717833745},{\"x\":0.8416324519309677,\"y\":0.4605511826177674},{\"x\":0.8433131241998753,\"y\":0.44986234651325435},{\"x\":0.8449937964687828,\"y\":0.4415488073208553},{\"x\":0.8449937964687828,\"y\":0.43323526812845625},{\"x\":0.8433131241998753,\"y\":0.42254643202394315},{\"x\":0.8231450569729845,\"y\":0.4047317051830881},{\"x\":0.8046576620150013,\"y\":0.40116875981491706},{\"x\":0.7811282502502954,\"y\":0.40116875981491706},{\"x\":0.755918166216682,\"y\":0.4035440567270311},{\"x\":0.7273467376452534,\"y\":0.4118575959194301},{\"x\":0.6937332922671021,\"y\":0.42373408048000016},{\"x\":0.663481191426766,\"y\":0.4367982134966273},{\"x\":0.6416324519309677,\"y\":0.44748704960114033},{\"x\":0.6029769897460937,\"y\":0.46767707335410946},{\"x\":0.5928929561326484,\"y\":0.47361531563439446},{\"x\":0.5794475779813879,\"y\":0.48074120637073653},{\"x\":0.57104421663685,\"y\":0.4866794486510216},{\"x\":0.5609601830234047,\"y\":0.4926176909313066}],\"color\":\"#ffeb3b\",\"thickness\":0.0033613445378151263}],\"pageNumber\":18,\"createdAt\":\"2025-09-11T05:58:38.167Z\",\"color\":\"#ffeb3b\"},{\"id\":\"drawing_1757570320263_qkstrel4k\",\"type\":\"drawing\",\"paths\":[{\"points\":[{\"x\":0.3323887544519761,\"y\":0.3382233916438957},{\"x\":0.3323887544519761,\"y\":0.3382233916438957},{\"x\":0.3323887544519761,\"y\":0.33941104009995265},{\"x\":0.3323887544519761,\"y\":0.3441616339241807},{\"x\":0.3323887544519761,\"y\":0.3524751731165798},{\"x\":0.3323887544519761,\"y\":0.36435165767714983},{\"x\":0.3323887544519761,\"y\":0.3797910876058909},{\"x\":0.3323887544519761,\"y\":0.392855220622518},{\"x\":0.3323887544519761,\"y\":0.40591935363914505},{\"x\":0.3323887544519761,\"y\":0.4213587835678862},{\"x\":0.3323887544519761,\"y\":0.43204761967239924},{\"x\":0.3323887544519761,\"y\":0.43917351040874125},{\"x\":0.3323887544519761,\"y\":0.44867469805719734},{\"x\":0.3323887544519761,\"y\":0.4522376434253684},{\"x\":0.3323887544519761,\"y\":0.4581758857056534},{\"x\":0.3323887544519761,\"y\":0.4593635341617104},{\"x\":0.3307080821830685,\"y\":0.4605511826177674},{\"x\":0.32902740991416096,\"y\":0.4605511826177674},{\"x\":0.3239853931074383,\"y\":0.4617388310738244},{\"x\":0.31726270403180806,\"y\":0.4593635341617104},{\"x\":0.30381732588054755,\"y\":0.4534252918814254},{\"x\":0.2870106031914719,\"y\":0.4415488073208553},{\"x\":0.26684253596458113,\"y\":0.4272970258481712},{\"x\":0.2416324519309677,\"y\":0.4106699474633731},{\"x\":0.22146438470407695,\"y\":0.396418165990689},{\"x\":0.20465766201500132,\"y\":0.385729329886176},{\"x\":0.18112825025029544,\"y\":0.3714775484134919},{\"x\":0.1643215275612198,\"y\":0.3631640092210928},{\"x\":0.15255682167886686,\"y\":0.35722576694080777},{\"x\":0.1424727880654215,\"y\":0.3536628215726368},{\"x\":0.13575009898979123,\"y\":0.35128752466052277},{\"x\":0.1239853931074383,\"y\":0.3465369308362947},{\"x\":0.11054001495617778,\"y\":0.3453492823802377},{\"x\":0.10717867041836265,\"y\":0.3453492823802377},{\"x\":0.10213665361163997,\"y\":0.3465369308362947},{\"x\":0.09877530907382484,\"y\":0.34891222774840874},{\"x\":0.09709463680491728,\"y\":0.35128752466052277},{\"x\":0.09541396453600971,\"y\":0.3536628215726368},{\"x\":0.09373329226710216,\"y\":0.35603811848475075},{\"x\":0.09373329226710216,\"y\":0.3584134153968648},{\"x\":0.09205261999819458,\"y\":0.3596010638529218},{\"x\":0.09205261999819458,\"y\":0.3619763607650358},{\"x\":0.09205261999819458,\"y\":0.3631640092210928},{\"x\":0.09205261999819458,\"y\":0.36435165767714983},{\"x\":0.09205261999819458,\"y\":0.36672695458926385},{\"x\":0.09373329226710216,\"y\":0.3702898999574349},{\"x\":0.09709463680491728,\"y\":0.3774157906937769}],\"color\":\"#ffeb3b\",\"thickness\":0.013445378151260505}],\"pageNumber\":18,\"createdAt\":\"2025-09-11T05:58:40.263Z\",\"color\":\"#ffeb3b\"},{\"id\":\"drawing_1757570321280_5lxv54h0d\",\"type\":\"drawing\",\"paths\":[{\"points\":[{\"x\":0.7004559813427325,\"y\":0.2610262420001902},{\"x\":0.7004559813427325,\"y\":0.2610262420001902},{\"x\":0.6987753090738248,\"y\":0.2622138904562472},{\"x\":0.6954139645360097,\"y\":0.2634015389123042},{\"x\":0.690371947729287,\"y\":0.26696448428047526},{\"x\":0.675245897309119,\"y\":0.2776533203849883},{\"x\":0.6584391746200433,\"y\":0.28952980494555836},{\"x\":0.6349097628553374,\"y\":0.3049692348742995},{\"x\":0.6113803510906316,\"y\":0.3204086648030406},{\"x\":0.5744055611746651,\"y\":0.3417863370120667},{\"x\":0.5273467376452534,\"y\":0.36672695458926385},{\"x\":0.48364925865365677,\"y\":0.394042869078575},{\"x\":0.4298677460486148,\"y\":0.4261093773921142},{\"x\":0.3727248889057576,\"y\":0.46530177644199544},{\"x\":0.31726270403180806,\"y\":0.5092447693161047},{\"x\":0.26180051915785846,\"y\":0.556750707558385},{\"x\":0.22650640151079962,\"y\":0.5900048643279812},{\"x\":0.19961564520827862,\"y\":0.6196960757294063},{\"x\":0.18953161159483325,\"y\":0.6327602087460334},{\"x\":0.17440556117466519,\"y\":0.6493872871308315}],\"color\":\"#ffeb3b\",\"thickness\":0.013445378151260505}],\"pageNumber\":18,\"createdAt\":\"2025-09-11T05:58:41.280Z\",\"color\":\"#ffeb3b\"},{\"id\":\"drawing_1757570404272_xelu5xya0\",\"type\":\"drawing\",\"paths\":[{\"points\":[{\"x\":0.5458341326032367,\"y\":0.377955629253614},{\"x\":0.5491954771410518,\"y\":0.377955629253614},{\"x\":0.57104421663685,\"y\":0.381518574621785},{\"x\":0.6113803510906316,\"y\":0.3945827076384121},{\"x\":0.636590435124245,\"y\":0.4040838952868681},{\"x\":0.6550778300822282,\"y\":0.4112097860232102},{\"x\":0.6735652250402114,\"y\":0.41714802830349523},{\"x\":0.7206240485696231,\"y\":0.43377510668829333},{\"x\":0.7340694267208837,\"y\":0.4373380520564643},{\"x\":0.7458341326032366,\"y\":0.44090099742463534},{\"x\":0.7542374939477744,\"y\":0.44208864588069235},{\"x\":0.7660021998301274,\"y\":0.4444639427928064},{\"x\":0.7878509393259256,\"y\":0.4444639427928064},{\"x\":0.7962543006704635,\"y\":0.4444639427928064},{\"x\":0.8046576620150013,\"y\":0.4444639427928064},{\"x\":0.809699678821724,\"y\":0.4444639427928064}],\"color\":\"#ffeb3b\",\"thickness\":0.0067226890756302525}],\"pageNumber\":19,\"createdAt\":\"2025-09-11T06:00:04.272Z\",\"color\":\"#ffeb3b\"},{\"id\":\"drawing_1757570404928_61eoycprc\",\"type\":\"drawing\",\"paths\":[{\"points\":[{\"x\":0.794573628401556,\"y\":0.38745681690207},{\"x\":0.7928929561326483,\"y\":0.386269168446013},{\"x\":0.7912122838637408,\"y\":0.386269168446013},{\"x\":0.7323887544519762,\"y\":0.4052715437429251},{\"x\":0.7105400149561778,\"y\":0.4147727313913812},{\"x\":0.6836492586536568,\"y\":0.42664921595195127},{\"x\":0.6181030401662618,\"y\":0.45634042735337643},{\"x\":0.5643215275612198,\"y\":0.4812810449305736},{\"x\":0.5038173258805475,\"y\":0.5109722563319987},{\"x\":0.4735652250402114,\"y\":0.5240363893486258},{\"x\":0.4399517796620601,\"y\":0.540663467733424},{\"x\":0.41642236789735426,\"y\":0.552539952293994},{\"x\":0.3962543006704635,\"y\":0.5632287883985071},{\"x\":0.3660021998301274,\"y\":0.5786682183272481},{\"x\":0.355918166216682,\"y\":0.5834188121514762},{\"x\":0.3424727880654215,\"y\":0.5881694059757042}],\"color\":\"#ffeb3b\",\"thickness\":0.0067226890756302525}],\"pageNumber\":19,\"createdAt\":\"2025-09-11T06:00:04.928Z\",\"color\":\"#ffeb3b\"},{\"id\":\"drawing_1757570405609_zzolkxczp\",\"type\":\"drawing\",\"paths\":[{\"points\":[{\"x\":0.1374307712586988,\"y\":0.45871572426549045},{\"x\":0.1374307712586988,\"y\":0.45871572426549045},{\"x\":0.1424727880654215,\"y\":0.45871572426549045},{\"x\":0.15255682167886686,\"y\":0.45990337272154747},{\"x\":0.18112825025029544,\"y\":0.46702926345788953},{\"x\":0.22650640151079962,\"y\":0.4777180995624026},{\"x\":0.35255682167886687,\"y\":0.5038463655956568},{\"x\":0.529027409914161,\"y\":0.5335375769970819},{\"x\":0.6214643847040769,\"y\":0.5454140615576519},{\"x\":0.755918166216682,\"y\":0.5608534914863931},{\"x\":0.7760862334435727,\"y\":0.5620411399424501},{\"x\":0.7878509393259256,\"y\":0.5620411399424501},{\"x\":0.8012963174771862,\"y\":0.5620411399424501},{\"x\":0.8147416956284467,\"y\":0.5632287883985071},{\"x\":0.8298677460486148,\"y\":0.5644164368545641},{\"x\":0.8399517796620601,\"y\":0.5644164368545641}],\"color\":\"#ffeb3b\",\"thickness\":0.0067226890756302525}],\"pageNumber\":19,\"createdAt\":\"2025-09-11T06:00:05.609Z\",\"color\":\"#ffeb3b\"},{\"id\":\"drawing_1757570407703_052g6996j\",\"type\":\"drawing\",\"paths\":[{\"points\":[{\"x\":0.26516186369567357,\"y\":0.4325874582322363},{\"x\":0.26516186369567357,\"y\":0.4302121613201223},{\"x\":0.263481191426766,\"y\":0.4278368644080083},{\"x\":0.26180051915785846,\"y\":0.4278368644080083},{\"x\":0.2601198468889509,\"y\":0.4278368644080083},{\"x\":0.2567585023511358,\"y\":0.4278368644080083},{\"x\":0.2533971578133206,\"y\":0.4278368644080083},{\"x\":0.24835514100659795,\"y\":0.4278368644080083},{\"x\":0.2416324519309677,\"y\":0.4302121613201223},{\"x\":0.22650640151079962,\"y\":0.4872192872108586},{\"x\":0.2281870737797072,\"y\":0.5335375769970819},{\"x\":0.23322909058642988,\"y\":0.5620411399424501},{\"x\":0.23827110739315258,\"y\":0.5834188121514762},{\"x\":0.2466744687376904,\"y\":0.6024211874483884},{\"x\":0.2567585023511358,\"y\":0.6237988596574144},{\"x\":0.26684253596458113,\"y\":0.6416135864982696},{\"x\":0.2769265695780265,\"y\":0.6546777195148966},{\"x\":0.2853299309225643,\"y\":0.6618036102512387},{\"x\":0.29709463680491727,\"y\":0.6701171494436378},{\"x\":0.3088593426872702,\"y\":0.6772430401799798},{\"x\":0.31558203176290045,\"y\":0.6796183370920937},{\"x\":0.32566606537634585,\"y\":0.6808059855481507},{\"x\":0.33911144352760636,\"y\":0.6808059855481507},{\"x\":0.35255682167886687,\"y\":0.6808059855481507},{\"x\":0.3693635443679425,\"y\":0.6760553917239228},{\"x\":0.3878509393259257,\"y\":0.6641789071633527},{\"x\":0.41306102335953915,\"y\":0.6380506411300986},{\"x\":0.436590435124245,\"y\":0.6012335389923313},{\"x\":0.45171648554441307,\"y\":0.5703546791348492},{\"x\":0.4651618636956736,\"y\":0.53828817082131},{\"x\":0.475245897309119,\"y\":0.5109722563319987},{\"x\":0.4786072418469341,\"y\":0.4979081233153717},{\"x\":0.48364925865365677,\"y\":0.4800933964745166},{\"x\":0.4853299309225643,\"y\":0.4705922088260605},{\"x\":0.4870106031914719,\"y\":0.4622786696336615},{\"x\":0.4853299309225643,\"y\":0.45158983352914844},{\"x\":0.48364925865365677,\"y\":0.45040218507309143}],\"color\":\"#ffeb3b\",\"thickness\":0.013445378151260505}],\"pageNumber\":19,\"createdAt\":\"2025-09-11T06:00:07.703Z\",\"color\":\"#ffeb3b\"},{\"id\":\"highlight_1757681759823_3d26ghzvq\",\"type\":\"highlight\",\"text\":\"on so it is more than possible that our implementations differ from those\\nconsidered the norm.\\nYou should use this book alongside another on the same subject, but one\\nthat contains formal proofs of the algorithms in question. In this book we use\\nthe abstract big Oh notation to depict the run time complexity of algorithms\\nso that the book appeals to a larger audience.\\n1.2 Assumed knowledge\\nWe have written this book with few assumptions of the reader, but some have\\nbeen necessary in order to keep the book as concise and approachable as possible.\\nWe assume that the reader is familiar with the following:\\n1. Big Oh notation\\n2. An imperative programming language\\n3. Object oriented concepts\\n1.2.1 Big Oh notation\\nFor run time complexity analysis we use big Oh notation extensively so it is vital\\nthat you are familiar with the general concepts to determine which is the best\\nalgorithm for you in certain scenarios. We have chosen to use big Oh notation\\nfor a few reasons, the most important of which is that it provides an abstract\\nmeasurement by which we can judge the performance of algorithms without\\nusing mathematical proofs.\",\"bounds\":[{\"x\":0.22939217190782563,\"y\":0.47851772716096347,\"width\":0.5580767463235294,\"height\":0.013495982118004008},{\"x\":0.20979752740940127,\"y\":0.49379351473194405,\"width\":0.1536683667607668,\"height\":0.011825851476673843},{\"x\":0.20979752740940127,\"y\":0.4927138376122699,\"width\":0.1536683667607668,\"height\":0.013495982118004008},{\"x\":0.23488831079306724,\"y\":0.5079896251832504,\"width\":0.5525519875919118,\"height\":0.011825851476673843},{\"x\":0.23488831079306724,\"y\":0.5069099480635763,\"width\":0.5525519875919118,\"height\":0.013495982118004008},{\"x\":0.20979752740940127,\"y\":0.5221941442784108,\"width\":0.5776688263195904,\"height\":0.011825887720828385},{\"x\":0.20979752740940127,\"y\":0.5211144671587367,\"width\":0.5776688263195904,\"height\":0.013496018362158552},{\"x\":0.20979752740940127,\"y\":0.5363902547297172,\"width\":0.5776793920693277,\"height\":0.011825887720828385},{\"x\":0.20979752740940127,\"y\":0.5353105776100431,\"width\":0.5776793920693277,\"height\":0.013496018362158552},{\"x\":0.20979752740940127,\"y\":0.5505948100690321,\"width\":0.3370194122570903,\"height\":0.011825887720828385},{\"x\":0.20979752740940127,\"y\":0.5495151329493579,\"width\":0.3370194122570903,\"height\":0.013496018362158552},{\"x\":0.20979752740940127,\"y\":0.585591658277353,\"width\":0.03465514623818277,\"height\":0.01703025835993171},{\"x\":0.20979752740940127,\"y\":0.5839721244757645,\"width\":0.03465514623818277,\"height\":0.019434260642443586},{\"x\":0.24438979204963235,\"y\":0.585591658277353,\"width\":0.006696428571428571,\"height\":0.01703025835993171},{\"x\":0.24438979204963235,\"y\":0.5839721244757645,\"width\":0.006696428571428571,\"height\":0.019434260642443586},{\"x\":0.27149781299238446,\"y\":0.585591658277353,\"width\":0.2386775169051996,\"height\":0.01703025835993171},{\"x\":0.27149781299238446,\"y\":0.5839721244757645,\"width\":0.2386775169051996,\"height\":0.019434260642443586},{\"x\":0.20979752740940127,\"y\":0.6156961617730292,\"width\":0.5776890345982143,\"height\":0.011825887720828385},{\"x\":0.20979752740940127,\"y\":0.614616484653355,\"width\":0.5776890345982143,\"height\":0.013496018362158552},{\"x\":0.20979752740940127,\"y\":0.6298922722243356,\"width\":0.5776754940257353,\"height\":0.011825887720828385},{\"x\":0.20979752740940127,\"y\":0.6288125951046615,\"width\":0.5776754940257353,\"height\":0.013496018362158552},{\"x\":0.20979752740940127,\"y\":0.6440883826756421,\"width\":0.41856689453125,\"height\":0.011825887720828385},{\"x\":0.20979752740940127,\"y\":0.6430087055559679,\"width\":0.41856689453125,\"height\":0.013496018362158552},{\"x\":0.2301972204897584,\"y\":0.67009349107176,\"width\":0.14116734095982142,\"height\":0.011825887720828385},{\"x\":0.2301972204897584,\"y\":0.6690138139520858,\"width\":0.14116734095982142,\"height\":0.013496018362158552},{\"x\":0.2301972204897584,\"y\":0.6936946334295205,\"width\":0.29874883058692225,\"height\":0.011825887720828385},{\"x\":0.2301972204897584,\"y\":0.6926149563098464,\"width\":0.29874883058692225,\"height\":0.013496018362158552},{\"x\":0.2301972204897584,\"y\":0.7173885608229105,\"width\":0.20386357668067226,\"height\":0.011825887720828385},{\"x\":0.2301972204897584,\"y\":0.7163089199473909,\"width\":0.20386357668067226,\"height\":0.013495945873849466},{\"x\":0.20979752740940127,\"y\":0.7485896312142778,\"width\":0.04646714154411765,\"height\":0.014196110451306414},{\"x\":0.20979752740940127,\"y\":0.7475099903387582,\"width\":0.04646714154411765,\"height\":0.016195193039266628},{\"x\":0.25619511964942226,\"y\":0.7485896312142778,\"width\":0.005586306788340336,\"height\":0.014196110451306414},{\"x\":0.25619511964942226,\"y\":0.7475099903387582,\"width\":0.005586306788340336,\"height\":0.016195193039266628},{\"x\":0.278791052553834,\"y\":0.7485896312142778,\"width\":0.16080229943539917,\"height\":0.014196110451306414},{\"x\":0.278791052553834,\"y\":0.7475099903387582,\"width\":0.16080229943539917,\"height\":0.016195193039266628},{\"x\":0.20979752740940127,\"y\":0.7723931971751596,\"width\":0.5776804178702731,\"height\":0.011825887720828385},{\"x\":0.20979752740940127,\"y\":0.77131355629964,\"width\":0.5776804178702731,\"height\":0.013496018362158552},{\"x\":0.20979752740940127,\"y\":0.786589307626466,\"width\":0.5776807256105567,\"height\":0.011825887720828385},{\"x\":0.20979752740940127,\"y\":0.7855096667509464,\"width\":0.5776807256105567,\"height\":0.013496018362158552},{\"x\":0.20979752740940127,\"y\":0.8007938992099354,\"width\":0.5776807256105567,\"height\":0.011825815232519299},{\"x\":0.20979752740940127,\"y\":0.7997141858461068,\"width\":0.5776807256105567,\"height\":0.013496018362158552},{\"x\":0.20979752740940127,\"y\":0.8149900096612418,\"width\":0.5776661592371324,\"height\":0.011825815232519299},{\"x\":0.20979752740940127,\"y\":0.8139102962974132,\"width\":0.5776661592371324,\"height\":0.013496018362158552},{\"x\":0.20979752740940127,\"y\":0.8291945287564022,\"width\":0.5776670824579831,\"height\":0.011825887720828385},{\"x\":0.20979752740940127,\"y\":0.8281148153925735,\"width\":0.5776670824579831,\"height\":0.013496018362158552},{\"x\":0.20979752740940127,\"y\":0.8433906392077086,\"width\":0.19837820870535713,\"height\":0.011825887720828385},{\"x\":0.20979752740940127,\"y\":0.8423109258438799,\"width\":0.19837820870535713,\"height\":0.013496018362158552}],\"color\":\"#ffeb3b\",\"pageNumber\":12,\"createdAt\":\"2025-09-12T12:55:59.823Z\"},{\"id\":\"drawing_1757681764238_24uujg39r\",\"type\":\"drawing\",\"paths\":[{\"points\":[{\"x\":0.5779220965730042,\"y\":0.2157876383946797},{\"x\":0.5779220965730042,\"y\":0.2157876383946797},{\"x\":0.5796027688419118,\"y\":0.2157876383946797},{\"x\":0.5796027688419118,\"y\":0.2157876383946797},{\"x\":0.5796027688419118,\"y\":0.21816293530679373},{\"x\":0.5796027688419118,\"y\":0.22053823221890773},{\"x\":0.5947288192620799,\"y\":0.24191590442793387},{\"x\":0.6064935251444328,\"y\":0.2526047405324469},{\"x\":0.624980920102416,\"y\":0.264481225093017},{\"x\":0.6333842814469538,\"y\":0.268044170461188},{\"x\":0.6451489873293067,\"y\":0.27279476428541605},{\"x\":0.6854851217830882,\"y\":0.2799206550217581},{\"x\":0.7006111722032563,\"y\":0.2799206550217581},{\"x\":0.7426279789259453,\"y\":0.27517006119753007},{\"x\":0.7560733570772059,\"y\":0.269231818917245},{\"x\":0.7678380629595588,\"y\":0.260918279724846},{\"x\":0.7812834411108194,\"y\":0.24072825597187686},{\"x\":0.7829641133797269,\"y\":0.23360236523553482},{\"x\":0.786325457917542,\"y\":0.2134123414825657},{\"x\":0.7829641133797269,\"y\":0.20984939611439468},{\"x\":0.774560752035189,\"y\":0.20509880229016664},{\"x\":0.7325439453125,\"y\":0.19203466927353957},{\"x\":0.7140565503545168,\"y\":0.18847172390536854},{\"x\":0.6552330209427522,\"y\":0.18847172390536854},{\"x\":0.6350649537158614,\"y\":0.19559761464171058},{\"x\":0.6165775587578781,\"y\":0.20509880229016664},{\"x\":0.5779220965730042,\"y\":0.24310355288399088},{\"x\":0.5728800797662815,\"y\":0.2526047405324469},{\"x\":0.5644767184217437,\"y\":0.2775453581096441},{\"x\":0.5644767184217437,\"y\":0.2846712488459861},{\"x\":0.5644767184217437,\"y\":0.28823419421415714},{\"x\":0.5678380629595589,\"y\":0.2953600849504992},{\"x\":0.5695187352284664,\"y\":0.2965477334065562},{\"x\":0.571199407497374,\"y\":0.2977353818626132},{\"x\":0.5728800797662815,\"y\":0.3001106787747272}],\"color\":\"#ffeb3b\",\"thickness\":0.0033613445378151263}],\"pageNumber\":12,\"createdAt\":\"2025-09-12T12:56:04.238Z\",\"color\":\"#ffeb3b\"},{\"id\":\"highlight_1757681932073_hce4uwtbq\",\"type\":\"highlight\",\"text\":\"(2n) run times\",\"bounds\":[{\"x\":0.4055099102629333,\"y\":0.46871624310056276,\"width\":0.000011950581013655462,\"height\":0.013496018362158552},{\"x\":0.40568896381794906,\"y\":0.46979592022023686,\"width\":0.014886115579044118,\"height\":0.011825887720828385},{\"x\":0.40568896381794906,\"y\":0.46871624310056276,\"width\":0.014886115579044118,\"height\":0.013496018362158552},{\"x\":0.42059774959788604,\"y\":0.46829450611830326,\"width\":0.006517375016412815,\"height\":0.008274721702883759},{\"x\":0.42059774959788604,\"y\":0.4672148289986291,\"width\":0.006517375016412815,\"height\":0.009717094077067251},{\"x\":0.42969342400045957,\"y\":0.46871624310056276,\"width\":0.08551266453847164,\"height\":0.013496018362158552}],\"color\":\"#ffeb3b\",\"pageNumber\":13,\"createdAt\":\"2025-09-12T12:58:52.073Z\"},{\"id\":\"highlight_1757681943067_neptzoya2\",\"type\":\"highlight\",\"text\":\"very small problems\",\"bounds\":{\"x\":0.4138179746996455,\"y\":0.4829123535518692,\"width\":0.14892706350118173,\"height\":0.013496018362158552},\"color\":\"#e91e63\",\"pageNumber\":13,\"createdAt\":\"2025-09-12T12:59:03.067Z\"},{\"id\":\"drawing_1757681951483_8xbo9kafa\",\"type\":\"drawing\",\"paths\":[{\"points\":[{\"x\":0.8000763965254071,\"y\":0.4384177382371771},{\"x\":0.8000763965254071,\"y\":0.4384177382371771},{\"x\":0.8000763965254071,\"y\":0.4384177382371771},{\"x\":0.8017570687943146,\"y\":0.4384177382371771},{\"x\":0.8017570687943146,\"y\":0.4384177382371771},{\"x\":0.8034377410632222,\"y\":0.4384177382371771},{\"x\":0.8051184133321297,\"y\":0.4384177382371771},{\"x\":0.8051184133321297,\"y\":0.4384177382371771},{\"x\":0.8051184133321297,\"y\":0.4384177382371771},{\"x\":0.8067990856010373,\"y\":0.4384177382371771},{\"x\":0.8067990856010373,\"y\":0.4384177382371771},{\"x\":0.8067990856010373,\"y\":0.4384177382371771},{\"x\":0.8067990856010373,\"y\":0.4384177382371771},{\"x\":0.8067990856010373,\"y\":0.4384177382371771},{\"x\":0.8067990856010373,\"y\":0.4384177382371771},{\"x\":0.8084797578699449,\"y\":0.4396053866932341},{\"x\":0.8084797578699449,\"y\":0.4396053866932341},{\"x\":0.8101604301388524,\"y\":0.44079303514929113},{\"x\":0.8101604301388524,\"y\":0.44079303514929113},{\"x\":0.81184110240776,\"y\":0.44198068360534815},{\"x\":0.81184110240776,\"y\":0.44198068360534815},{\"x\":0.8135217746766675,\"y\":0.44316833206140516},{\"x\":0.8135217746766675,\"y\":0.44316833206140516},{\"x\":0.8135217746766675,\"y\":0.44316833206140516},{\"x\":0.8135217746766675,\"y\":0.44435598051746217},{\"x\":0.8152024469455751,\"y\":0.44435598051746217},{\"x\":0.8152024469455751,\"y\":0.44435598051746217},{\"x\":0.8152024469455751,\"y\":0.44435598051746217},{\"x\":0.8152024469455751,\"y\":0.4455436289735191},{\"x\":0.8152024469455751,\"y\":0.4455436289735191},{\"x\":0.8152024469455751,\"y\":0.4455436289735191},{\"x\":0.8152024469455751,\"y\":0.4455436289735191},{\"x\":0.8152024469455751,\"y\":0.4455436289735191},{\"x\":0.8152024469455751,\"y\":0.44673127742957613},{\"x\":0.8152024469455751,\"y\":0.44791892588563315},{\"x\":0.8152024469455751,\"y\":0.44910657434169016},{\"x\":0.8152024469455751,\"y\":0.45029422279774717},{\"x\":0.8152024469455751,\"y\":0.4514818712538042},{\"x\":0.8152024469455751,\"y\":0.4526695197098612},{\"x\":0.8152024469455751,\"y\":0.4538571681659182},{\"x\":0.8152024469455751,\"y\":0.4550448166219752},{\"x\":0.8152024469455751,\"y\":0.4562324650780322},{\"x\":0.8135217746766675,\"y\":0.45742011353408923},{\"x\":0.8135217746766675,\"y\":0.45860776199014625},{\"x\":0.8135217746766675,\"y\":0.45979541044620326},{\"x\":0.8135217746766675,\"y\":0.45979541044620326},{\"x\":0.8135217746766675,\"y\":0.46098305890226027},{\"x\":0.8135217746766675,\"y\":0.46098305890226027},{\"x\":0.8135217746766675,\"y\":0.4621707073583172},{\"x\":0.8135217746766675,\"y\":0.4621707073583172},{\"x\":0.8135217746766675,\"y\":0.46335835581437423},{\"x\":0.8135217746766675,\"y\":0.46335835581437423},{\"x\":0.8135217746766675,\"y\":0.46335835581437423},{\"x\":0.8135217746766675,\"y\":0.46335835581437423},{\"x\":0.8135217746766675,\"y\":0.46454600427043125},{\"x\":0.8135217746766675,\"y\":0.46454600427043125},{\"x\":0.8135217746766675,\"y\":0.46454600427043125},{\"x\":0.8135217746766675,\"y\":0.46454600427043125},{\"x\":0.8152024469455751,\"y\":0.46454600427043125},{\"x\":0.8168831192144826,\"y\":0.46454600427043125},{\"x\":0.8168831192144826,\"y\":0.46454600427043125},{\"x\":0.8185637914833902,\"y\":0.46454600427043125},{\"x\":0.8202444637522978,\"y\":0.46454600427043125},{\"x\":0.8202444637522978,\"y\":0.46454600427043125},{\"x\":0.8202444637522978,\"y\":0.46454600427043125},{\"x\":0.8219251360212053,\"y\":0.46454600427043125},{\"x\":0.8219251360212053,\"y\":0.46454600427043125},{\"x\":0.8219251360212053,\"y\":0.46454600427043125},{\"x\":0.8219251360212053,\"y\":0.46454600427043125},{\"x\":0.8236058082901129,\"y\":0.46454600427043125},{\"x\":0.8236058082901129,\"y\":0.46454600427043125},{\"x\":0.8236058082901129,\"y\":0.46454600427043125},{\"x\":0.8252864805590204,\"y\":0.46454600427043125},{\"x\":0.8269671528279281,\"y\":0.46454600427043125},{\"x\":0.8269671528279281,\"y\":0.46454600427043125},{\"x\":0.8269671528279281,\"y\":0.46454600427043125},{\"x\":0.8269671528279281,\"y\":0.46454600427043125},{\"x\":0.8286478250968357,\"y\":0.46454600427043125},{\"x\":0.8286478250968357,\"y\":0.46454600427043125},{\"x\":0.8286478250968357,\"y\":0.46454600427043125},{\"x\":0.8269671528279281,\"y\":0.46454600427043125},{\"x\":0.8252864805590204,\"y\":0.46692130118254527},{\"x\":0.8236058082901129,\"y\":0.4681089496386023},{\"x\":0.8219251360212053,\"y\":0.4692965980946593},{\"x\":0.8202444637522978,\"y\":0.4704842465507163},{\"x\":0.8185637914833902,\"y\":0.4728595434628303},{\"x\":0.8168831192144826,\"y\":0.47404719191888733},{\"x\":0.8152024469455751,\"y\":0.47523484037494435},{\"x\":0.8135217746766675,\"y\":0.47642248883100136},{\"x\":0.8135217746766675,\"y\":0.47761013728705837},{\"x\":0.81184110240776,\"y\":0.4787977857431153},{\"x\":0.81184110240776,\"y\":0.47998543419917233},{\"x\":0.81184110240776,\"y\":0.47998543419917233},{\"x\":0.8101604301388524,\"y\":0.47998543419917233},{\"x\":0.8101604301388524,\"y\":0.48117308265522934},{\"x\":0.8101604301388524,\"y\":0.48236073111128636},{\"x\":0.8101604301388524,\"y\":0.48354837956734337},{\"x\":0.8101604301388524,\"y\":0.4847360280234004},{\"x\":0.8101604301388524,\"y\":0.4859236764794574},{\"x\":0.8101604301388524,\"y\":0.4882989733915714},{\"x\":0.8101604301388524,\"y\":0.4894866218476284},{\"x\":0.8101604301388524,\"y\":0.49067427030368543},{\"x\":0.8101604301388524,\"y\":0.49186191875974244},{\"x\":0.81184110240776,\"y\":0.49304956721579946},{\"x\":0.81184110240776,\"y\":0.49423721567185647},{\"x\":0.81184110240776,\"y\":0.4954248641279134},{\"x\":0.81184110240776,\"y\":0.49661251258397043},{\"x\":0.81184110240776,\"y\":0.49780016104002744},{\"x\":0.8135217746766675,\"y\":0.49898780949608446},{\"x\":0.8135217746766675,\"y\":0.5001754579521415},{\"x\":0.8135217746766675,\"y\":0.5001754579521415},{\"x\":0.8135217746766675,\"y\":0.5013631064081985},{\"x\":0.8135217746766675,\"y\":0.5013631064081985},{\"x\":0.8135217746766675,\"y\":0.5025507548642555},{\"x\":0.8135217746766675,\"y\":0.5025507548642555},{\"x\":0.8135217746766675,\"y\":0.5037384033203125},{\"x\":0.8135217746766675,\"y\":0.5037384033203125},{\"x\":0.81184110240776,\"y\":0.5037384033203125},{\"x\":0.81184110240776,\"y\":0.5049260517763695},{\"x\":0.8101604301388524,\"y\":0.5049260517763695},{\"x\":0.8101604301388524,\"y\":0.5049260517763695},{\"x\":0.8084797578699449,\"y\":0.5061137002324265},{\"x\":0.8067990856010373,\"y\":0.5061137002324265},{\"x\":0.8067990856010373,\"y\":0.5061137002324265},{\"x\":0.8051184133321297,\"y\":0.5061137002324265},{\"x\":0.8051184133321297,\"y\":0.5073013486884835},{\"x\":0.8034377410632222,\"y\":0.5073013486884835}],\"color\":\"#ffeb3b\",\"thickness\":0.0033613445378151263}],\"pageNumber\":13,\"createdAt\":\"2025-09-12T12:59:11.483Z\",\"color\":\"#ffeb3b\"},{\"id\":\"drawing_1757681958591_sseom3h23\",\"type\":\"drawing\",\"paths\":[{\"points\":[{\"x\":0.8471352200548188,\"y\":0.45742011353408923},{\"x\":0.8471352200548188,\"y\":0.45742011353408923},{\"x\":0.8471352200548188,\"y\":0.45742011353408923},{\"x\":0.8488158923237263,\"y\":0.45860776199014625},{\"x\":0.8488158923237263,\"y\":0.45979541044620326},{\"x\":0.8488158923237263,\"y\":0.46098305890226027},{\"x\":0.8504965645926339,\"y\":0.46098305890226027},{\"x\":0.8504965645926339,\"y\":0.46098305890226027},{\"x\":0.8504965645926339,\"y\":0.4621707073583172},{\"x\":0.8504965645926339,\"y\":0.4621707073583172},{\"x\":0.8504965645926339,\"y\":0.4621707073583172},{\"x\":0.8504965645926339,\"y\":0.4621707073583172},{\"x\":0.8504965645926339,\"y\":0.46335835581437423},{\"x\":0.8504965645926339,\"y\":0.46335835581437423},{\"x\":0.8504965645926339,\"y\":0.46454600427043125},{\"x\":0.8504965645926339,\"y\":0.46573365272648826},{\"x\":0.8504965645926339,\"y\":0.46692130118254527},{\"x\":0.8521772368615415,\"y\":0.4681089496386023},{\"x\":0.8521772368615415,\"y\":0.4692965980946593},{\"x\":0.853857909130449,\"y\":0.4704842465507163},{\"x\":0.853857909130449,\"y\":0.4716718950067733},{\"x\":0.8555385813993566,\"y\":0.4716718950067733},{\"x\":0.8555385813993566,\"y\":0.4728595434628303},{\"x\":0.8555385813993566,\"y\":0.4728595434628303},{\"x\":0.8555385813993566,\"y\":0.47404719191888733},{\"x\":0.8572192536682642,\"y\":0.47404719191888733},{\"x\":0.8572192536682642,\"y\":0.47404719191888733},{\"x\":0.8572192536682642,\"y\":0.47404719191888733},{\"x\":0.8572192536682642,\"y\":0.4728595434628303},{\"x\":0.8572192536682642,\"y\":0.4716718950067733},{\"x\":0.8605805982060794,\"y\":0.4692965980946593},{\"x\":0.8639419427438945,\"y\":0.46692130118254527},{\"x\":0.8723453040884322,\"y\":0.45979541044620326},{\"x\":0.8773873208951549,\"y\":0.4550448166219752},{\"x\":0.8824293377018776,\"y\":0.44910657434169016},{\"x\":0.8857906822396927,\"y\":0.4455436289735191},{\"x\":0.8891520267775079,\"y\":0.44316833206140516},{\"x\":0.892513371315323,\"y\":0.4396053866932341},{\"x\":0.8941940435842306,\"y\":0.4372300897811201},{\"x\":0.8958747158531382,\"y\":0.4360424413250631},{\"x\":0.8975553881220457,\"y\":0.4348547928690061},{\"x\":0.8975553881220457,\"y\":0.4348547928690061},{\"x\":0.8975553881220457,\"y\":0.43366714441294907},{\"x\":0.8992360603909533,\"y\":0.43366714441294907},{\"x\":0.8992360603909533,\"y\":0.43366714441294907},{\"x\":0.8992360603909533,\"y\":0.43366714441294907}],\"color\":\"#ffeb3b\",\"thickness\":0.0033613445378151263}],\"pageNumber\":13,\"createdAt\":\"2025-09-12T12:59:18.591Z\",\"color\":\"#ffeb3b\"},{\"id\":\"highlight_1761621190045_cjj5lcetz\",\"type\":\"highlight\",\"text\":\"wth. An algorith\",\"bounds\":{\"x\":0.5053600663898372,\"y\":0.2642724225186962,\"width\":0.12242246996454832,\"height\":0.013855886572613569},\"color\":\"#ffeb3b\",\"pageNumber\":14,\"createdAt\":\"2025-10-28T03:13:10.045Z\"},{\"id\":\"highlight_1761621192960_veh2xkrjp\",\"type\":\"highlight\",\"text\":\"comes suitably large. Th\",\"bounds\":{\"x\":0.2938679158186712,\"y\":0.23586987203203869,\"width\":0.18387492203912814,\"height\":0.013855922816768111},\"color\":\"#4caf50\",\"pageNumber\":14,\"createdAt\":\"2025-10-28T03:13:12.960Z\"},{\"id\":\"drawing_1761621200599_w7w6bs6lp\",\"type\":\"drawing\",\"paths\":[{\"points\":[{\"x\":0.6527835621553308,\"y\":0.24059364518190507},{\"x\":0.6527835621553308,\"y\":0.24059364518190507},{\"x\":0.6527835621553308,\"y\":0.24059364518190507},{\"x\":0.6511028898864233,\"y\":0.24059364518190507},{\"x\":0.6494222176175157,\"y\":0.24059364518190507},{\"x\":0.6460608730797006,\"y\":0.24059364518190507},{\"x\":0.6426995285418855,\"y\":0.24059364518190507},{\"x\":0.6376575117351628,\"y\":0.24059364518190507},{\"x\":0.6326154949284402,\"y\":0.24059364518190507},{\"x\":0.6275734781217175,\"y\":0.24059364518190507},{\"x\":0.6225314613149947,\"y\":0.24059364518190507},{\"x\":0.617489444508272,\"y\":0.24059364518190507},{\"x\":0.6107667554326418,\"y\":0.24059364518190507},{\"x\":0.6040440663570116,\"y\":0.23821834826979105},{\"x\":0.5973213772813813,\"y\":0.23703069981373404},{\"x\":0.5889180159368435,\"y\":0.23465540290162},{\"x\":0.5805146545923057,\"y\":0.23228010598950602},{\"x\":0.5721112932477679,\"y\":0.229904809077392},{\"x\":0.5620272596343224,\"y\":0.22752951216527798},{\"x\":0.5536238982897846,\"y\":0.22515421525316398},{\"x\":0.5452205369452469,\"y\":0.22396656679710697},{\"x\":0.5368171756007091,\"y\":0.22159126988499295},{\"x\":0.5284138142561712,\"y\":0.21921597297287893},{\"x\":0.521691125180541,\"y\":0.21802832451682191},{\"x\":0.5132877638360032,\"y\":0.21684067606076493},{\"x\":0.5065650747603729,\"y\":0.21565302760470792},{\"x\":0.4981617134158351,\"y\":0.2144653791486509},{\"x\":0.49311969660911237,\"y\":0.2132777306925939},{\"x\":0.48639700753348214,\"y\":0.2120900822365369},{\"x\":0.4796743184578519,\"y\":0.21090243378047988},{\"x\":0.4729516293822216,\"y\":0.21090243378047988},{\"x\":0.4662289403065914,\"y\":0.20971478532442286},{\"x\":0.4595062512309611,\"y\":0.20971478532442286},{\"x\":0.45110288988642333,\"y\":0.20852713686836588},{\"x\":0.44438020081079305,\"y\":0.20852713686836588},{\"x\":0.4376575117351628,\"y\":0.20852713686836588},{\"x\":0.43261549492844015,\"y\":0.20852713686836588},{\"x\":0.42589280585280986,\"y\":0.20971478532442286},{\"x\":0.4208507890460872,\"y\":0.20971478532442286},{\"x\":0.4158087722393645,\"y\":0.21090243378047988},{\"x\":0.4107667554326418,\"y\":0.2132777306925939},{\"x\":0.4057247386259191,\"y\":0.21565302760470792},{\"x\":0.40068272181919645,\"y\":0.21684067606076493},{\"x\":0.3973213772813813,\"y\":0.21921597297287893},{\"x\":0.39396003274356617,\"y\":0.22159126988499295},{\"x\":0.39059868820575105,\"y\":0.22396656679710697},{\"x\":0.3855566713990284,\"y\":0.22752951216527798},{\"x\":0.38387599913012077,\"y\":0.229904809077392},{\"x\":0.38051465459230566,\"y\":0.23228010598950602},{\"x\":0.3788339823233981,\"y\":0.23584305135767702},{\"x\":0.37715331005449054,\"y\":0.23821834826979105},{\"x\":0.375472637785583,\"y\":0.24178129363796208},{\"x\":0.37379196551667543,\"y\":0.2465318874621901},{\"x\":0.37211129324776787,\"y\":0.2500948328303611},{\"x\":0.3704306209788603,\"y\":0.25484542665458915},{\"x\":0.36706927644104514,\"y\":0.2595960204788172},{\"x\":0.3653886041721376,\"y\":0.2631589658469882},{\"x\":0.36370793190323003,\"y\":0.2679095596712162},{\"x\":0.36370793190323003,\"y\":0.27028485658333024},{\"x\":0.3620272596343225,\"y\":0.27384780195150127},{\"x\":0.3620272596343225,\"y\":0.2774107473196723},{\"x\":0.3620272596343225,\"y\":0.2797860442317863},{\"x\":0.3620272596343225,\"y\":0.2833489895999573},{\"x\":0.3620272596343225,\"y\":0.2857242865120713},{\"x\":0.3620272596343225,\"y\":0.28691193496812833},{\"x\":0.3620272596343225,\"y\":0.29047488033629937},{\"x\":0.3620272596343225,\"y\":0.2928501772484134},{\"x\":0.3620272596343225,\"y\":0.2940378257044704},{\"x\":0.3620272596343225,\"y\":0.2952254741605274},{\"x\":0.3620272596343225,\"y\":0.2964131226165844},{\"x\":0.3620272596343225,\"y\":0.2976007710726414},{\"x\":0.36370793190323003,\"y\":0.2976007710726414},{\"x\":0.36370793190323003,\"y\":0.2976007710726414},{\"x\":0.36370793190323003,\"y\":0.2976007710726414},{\"x\":0.36370793190323003,\"y\":0.2976007710726414},{\"x\":0.3653886041721376,\"y\":0.2976007710726414},{\"x\":0.3653886041721376,\"y\":0.2976007710726414},{\"x\":0.3653886041721376,\"y\":0.2964131226165844},{\"x\":0.3653886041721376,\"y\":0.2964131226165844},{\"x\":0.36706927644104514,\"y\":0.2964131226165844},{\"x\":0.36706927644104514,\"y\":0.2952254741605274},{\"x\":0.36874994870995276,\"y\":0.2952254741605274},{\"x\":0.3704306209788603,\"y\":0.2940378257044704},{\"x\":0.37211129324776787,\"y\":0.2940378257044704},{\"x\":0.37379196551667543,\"y\":0.2940378257044704},{\"x\":0.375472637785583,\"y\":0.2928501772484134},{\"x\":0.37715331005449054,\"y\":0.2916625287923564},{\"x\":0.3821953268612132,\"y\":0.28928723188024236},{\"x\":0.38723734366793594,\"y\":0.28691193496812833},{\"x\":0.39396003274356617,\"y\":0.2845366380560143},{\"x\":0.40068272181919645,\"y\":0.2809736926878433},{\"x\":0.4057247386259191,\"y\":0.2785983957757293},{\"x\":0.41244742770154935,\"y\":0.2750354504075583},{\"x\":0.41917011677717964,\"y\":0.27147250503938725},{\"x\":0.4242121335839023,\"y\":0.2690972081272732},{\"x\":0.429254150390625,\"y\":0.2667219112151592},{\"x\":0.4309348226595326,\"y\":0.2655342627591022},{\"x\":0.4342961671973477,\"y\":0.2643466143030452},{\"x\":0.4342961671973477,\"y\":0.2643466143030452},{\"x\":0.43597683946625526,\"y\":0.2643466143030452},{\"x\":0.43597683946625526,\"y\":0.2643466143030452},{\"x\":0.43597683946625526,\"y\":0.2643466143030452},{\"x\":0.4342961671973477,\"y\":0.2655342627591022},{\"x\":0.4342961671973477,\"y\":0.2655342627591022},{\"x\":0.4342961671973477,\"y\":0.2667219112151592},{\"x\":0.43261549492844015,\"y\":0.2679095596712162},{\"x\":0.43261549492844015,\"y\":0.2690972081272732},{\"x\":0.43261549492844015,\"y\":0.2690972081272732},{\"x\":0.43261549492844015,\"y\":0.27028485658333024},{\"x\":0.4309348226595326,\"y\":0.27147250503938725},{\"x\":0.4309348226595326,\"y\":0.2750354504075583},{\"x\":0.429254150390625,\"y\":0.2785983957757293},{\"x\":0.4275734781217174,\"y\":0.2821613411439003},{\"x\":0.42589280585280986,\"y\":0.28691193496812833},{\"x\":0.4242121335839023,\"y\":0.29047488033629937},{\"x\":0.4242121335839023,\"y\":0.2940378257044704},{\"x\":0.42253146131499475,\"y\":0.2964131226165844},{\"x\":0.42253146131499475,\"y\":0.2987884195286984},{\"x\":0.4208507890460872,\"y\":0.3011637164408124},{\"x\":0.4208507890460872,\"y\":0.30472666180898345},{\"x\":0.4208507890460872,\"y\":0.30710195872109747},{\"x\":0.4208507890460872,\"y\":0.3094772556332115},{\"x\":0.4208507890460872,\"y\":0.3130402010013825},{\"x\":0.4208507890460872,\"y\":0.3154154979134965},{\"x\":0.4208507890460872,\"y\":0.3189784432816675},{\"x\":0.4208507890460872,\"y\":0.32254138864983856},{\"x\":0.4208507890460872,\"y\":0.3261043340180096},{\"x\":0.4208507890460872,\"y\":0.3284796309301236},{\"x\":0.4208507890460872,\"y\":0.3296672793861806},{\"x\":0.4208507890460872,\"y\":0.3296672793861806},{\"x\":0.42253146131499475,\"y\":0.3296672793861806},{\"x\":0.42253146131499475,\"y\":0.3296672793861806},{\"x\":0.42253146131499475,\"y\":0.3296672793861806},{\"x\":0.4242121335839023,\"y\":0.3296672793861806},{\"x\":0.42589280585280986,\"y\":0.3296672793861806},{\"x\":0.429254150390625,\"y\":0.3296672793861806},{\"x\":0.43261549492844015,\"y\":0.3284796309301236},{\"x\":0.43597683946625526,\"y\":0.3272919824740666},{\"x\":0.4393381840040704,\"y\":0.3261043340180096},{\"x\":0.44438020081079305,\"y\":0.32372903710589557},{\"x\":0.45110288988642333,\"y\":0.32254138864983856},{\"x\":0.456144906693146,\"y\":0.32016609173772453},{\"x\":0.4611869234998687,\"y\":0.3177907948256105},{\"x\":0.4662289403065914,\"y\":0.3166031463695535},{\"x\":0.4695902848444065,\"y\":0.3142278494574395},{\"x\":0.4729516293822216,\"y\":0.3118525525453255},{\"x\":0.47631297392003674,\"y\":0.3094772556332115},{\"x\":0.47799364618894435,\"y\":0.30710195872109747},{\"x\":0.48135499072675947,\"y\":0.30353901335292643},{\"x\":0.483035662995667,\"y\":0.2999760679847554},{\"x\":0.48639700753348214,\"y\":0.2964131226165844},{\"x\":0.48975835207129725,\"y\":0.2916625287923564},{\"x\":0.4914390243402048,\"y\":0.28809958342418535},{\"x\":0.49480036887802,\"y\":0.2845366380560143},{\"x\":0.49648104114692754,\"y\":0.2797860442317863},{\"x\":0.4981617134158351,\"y\":0.2762230988636153},{\"x\":0.5015230579536503,\"y\":0.27266015349544426},{\"x\":0.5015230579536503,\"y\":0.27147250503938725},{\"x\":0.5032037302225578,\"y\":0.27028485658333024},{\"x\":0.5032037302225578,\"y\":0.2690972081272732},{\"x\":0.5032037302225578,\"y\":0.2690972081272732},{\"x\":0.5032037302225578,\"y\":0.27028485658333024},{\"x\":0.5032037302225578,\"y\":0.27028485658333024},{\"x\":0.5032037302225578,\"y\":0.27147250503938725},{\"x\":0.5032037302225578,\"y\":0.27147250503938725},{\"x\":0.5032037302225578,\"y\":0.27266015349544426},{\"x\":0.5032037302225578,\"y\":0.27384780195150127},{\"x\":0.5032037302225578,\"y\":0.2750354504075583},{\"x\":0.5032037302225578,\"y\":0.2774107473196723},{\"x\":0.5032037302225578,\"y\":0.2809736926878433},{\"x\":0.5032037302225578,\"y\":0.2845366380560143},{\"x\":0.5048844024914654,\"y\":0.28809958342418535},{\"x\":0.5065650747603729,\"y\":0.2928501772484134},{\"x\":0.5065650747603729,\"y\":0.2964131226165844},{\"x\":0.5082457470292805,\"y\":0.2999760679847554},{\"x\":0.509926419298188,\"y\":0.30353901335292643},{\"x\":0.5116070915670956,\"y\":0.3082896071771545},{\"x\":0.5149684361049107,\"y\":0.3118525525453255},{\"x\":0.5166491083738183,\"y\":0.3154154979134965},{\"x\":0.5200104529116334,\"y\":0.3189784432816675},{\"x\":0.521691125180541,\"y\":0.32254138864983856},{\"x\":0.5250524697183561,\"y\":0.3249166855619526},{\"x\":0.5284138142561712,\"y\":0.3261043340180096},{\"x\":0.5300944865250787,\"y\":0.3272919824740666},{\"x\":0.5317751587939863,\"y\":0.3284796309301236},{\"x\":0.533455831062894,\"y\":0.3284796309301236},{\"x\":0.5351365033318015,\"y\":0.3296672793861806},{\"x\":0.5384978478696166,\"y\":0.3284796309301236},{\"x\":0.5418591924074317,\"y\":0.3272919824740666},{\"x\":0.5469012092141544,\"y\":0.3249166855619526},{\"x\":0.5519432260208771,\"y\":0.32254138864983856},{\"x\":0.5569852428275998,\"y\":0.32016609173772453},{\"x\":0.5603465873654149,\"y\":0.3177907948256105},{\"x\":0.5637079319032301,\"y\":0.3142278494574395},{\"x\":0.5670692764410452,\"y\":0.3118525525453255},{\"x\":0.5687499487099528,\"y\":0.3094772556332115},{\"x\":0.5687499487099528,\"y\":0.3082896071771545},{\"x\":0.5687499487099528,\"y\":0.30710195872109747},{\"x\":0.5687499487099528,\"y\":0.30710195872109747},{\"x\":0.5687499487099528,\"y\":0.30591431026504046},{\"x\":0.5687499487099528,\"y\":0.30472666180898345},{\"x\":0.5687499487099528,\"y\":0.2999760679847554},{\"x\":0.5687499487099528,\"y\":0.2952254741605274},{\"x\":0.5687499487099528,\"y\":0.2916625287923564},{\"x\":0.5687499487099528,\"y\":0.28928723188024236},{\"x\":0.5687499487099528,\"y\":0.28691193496812833},{\"x\":0.5687499487099528,\"y\":0.28691193496812833},{\"x\":0.5670692764410452,\"y\":0.2857242865120713},{\"x\":0.5670692764410452,\"y\":0.2857242865120713},{\"x\":0.5670692764410452,\"y\":0.2857242865120713},{\"x\":0.5670692764410452,\"y\":0.2857242865120713},{\"x\":0.5653886041721377,\"y\":0.2833489895999573},{\"x\":0.5653886041721377,\"y\":0.2833489895999573},{\"x\":0.5653886041721377,\"y\":0.2809736926878433},{\"x\":0.5637079319032301,\"y\":0.2785983957757293},{\"x\":0.5637079319032301,\"y\":0.2785983957757293},{\"x\":0.5620272596343224,\"y\":0.2774107473196723},{\"x\":0.5637079319032301,\"y\":0.2785983957757293},{\"x\":0.5637079319032301,\"y\":0.2785983957757293},{\"x\":0.5670692764410452,\"y\":0.2809736926878433},{\"x\":0.5737919655166754,\"y\":0.2821613411439003},{\"x\":0.5821953268612132,\"y\":0.2857242865120713},{\"x\":0.5939600327435661,\"y\":0.28809958342418535},{\"x\":0.6057247386259191,\"y\":0.28928723188024236},{\"x\":0.617489444508272,\"y\":0.29047488033629937},{\"x\":0.629254150390625,\"y\":0.29047488033629937},{\"x\":0.6426995285418855,\"y\":0.29047488033629937},{\"x\":0.656144906693146,\"y\":0.28928723188024236},{\"x\":0.6662289403065914,\"y\":0.28809958342418535},{\"x\":0.6763129739200368,\"y\":0.2857242865120713},{\"x\":0.683035662995667,\"y\":0.2821613411439003},{\"x\":0.6880776798023897,\"y\":0.2797860442317863},{\"x\":0.6914390243402049,\"y\":0.2785983957757293},{\"x\":0.6914390243402049,\"y\":0.2774107473196723},{\"x\":0.6931196966091124,\"y\":0.2762230988636153},{\"x\":0.6914390243402049,\"y\":0.27384780195150127},{\"x\":0.6897583520712973,\"y\":0.2690972081272732},{\"x\":0.683035662995667,\"y\":0.2643466143030452},{\"x\":0.6729516293822216,\"y\":0.2584083720227602},{\"x\":0.6628675957687763,\"y\":0.2524701297424751},{\"x\":0.6511028898864233,\"y\":0.2477195359182471},{\"x\":0.6376575117351628,\"y\":0.24296894209401906},{\"x\":0.6208507890460871,\"y\":0.23940599672584806},{\"x\":0.6074054108948267,\"y\":0.23703069981373404},{\"x\":0.5973213772813813,\"y\":0.23465540290162},{\"x\":0.5872373436679359,\"y\":0.23228010598950602},{\"x\":0.5771533100544906,\"y\":0.229904809077392},{\"x\":0.5704306209788603,\"y\":0.22752951216527798},{\"x\":0.5637079319032301,\"y\":0.22515421525316398},{\"x\":0.5586659150965073,\"y\":0.22396656679710697},{\"x\":0.5553045705586922,\"y\":0.22277891834104996},{\"x\":0.5536238982897846,\"y\":0.22277891834104996}],\"color\":\"#4caf50\",\"thickness\":0.0033613445378151263}],\"pageNumber\":14,\"createdAt\":\"2025-10-28T03:13:20.599Z\",\"color\":\"#4caf50\"}]", + "annotationType": "highlight" + }, + "relationships": { + "cardInfo.theme": { + "links": { + "self": null + } + } + } + } +} diff --git a/annotation-2f9c8aa5-a258-4390-839d-fc965f5e915e/annotation/annotation.gts b/annotation-2f9c8aa5-a258-4390-839d-fc965f5e915e/annotation/annotation.gts new file mode 100644 index 0000000..0dfa456 --- /dev/null +++ b/annotation-2f9c8aa5-a258-4390-839d-fc965f5e915e/annotation/annotation.gts @@ -0,0 +1,3953 @@ +// ═══ [EDIT TRACKING: ON] Mark all changes with ⁿ ═══ +import { + CardDef, + field, + contains, + containsMany, + Component, +} from 'https://cardstack.com/base/card-api'; // ¹ Core imports +import StringField from 'https://cardstack.com/base/string'; +import NumberField from 'https://cardstack.com/base/number'; +import UrlField from 'https://cardstack.com/base/url'; +import { Button } from '@cardstack/boxel-ui/components'; // ² UI components +import { fn, concat, array } from '@ember/helper'; +import { on } from '@ember/modifier'; +import { action } from '@ember/object'; +import { tracked } from '@glimmer/tracking'; +import { task } from 'ember-concurrency'; // ¹³ Task management +import { htmlSafe } from '@ember/template'; +import { + formatDateTime, + eq, + or, + gt, + multiply, +} from '@cardstack/boxel-ui/helpers'; +import EditIcon from '@cardstack/boxel-icons/edit'; + +// Annotation types and interfaces +interface AnnotationBase { + id: string; + type: 'highlight' | 'note' | 'drawing' | 'comment'; + pageNumber: number; + createdAt: string; + color?: string; +} + +interface TextHighlight extends AnnotationBase { + type: 'highlight'; + text: string; + bounds: + | { + x: number; + y: number; + width: number; + height: number; + } + | Array<{ + x: number; + y: number; + width: number; + height: number; + }>; // Support both single bounds (legacy) and multiple bounds (accurate) + color: string; +} + +interface NoteAnnotation extends AnnotationBase { + type: 'note'; + text: string; + position: { + x: number; + y: number; + }; + associatedText?: string; // Text that was selected when note was created +} + +interface DrawingAnnotation extends AnnotationBase { + type: 'drawing'; + paths: Array<{ + points: Array<{ x: number; y: number }>; + color: string; + thickness: number; + }>; +} + +interface CommentAnnotation extends AnnotationBase { + type: 'comment'; + text: string; + position: { + x: number; + y: number; + }; +} + +type Annotation = + | TextHighlight + | NoteAnnotation + | DrawingAnnotation + | CommentAnnotation; + +class AnnotationIsolated extends Component { + // ⁶ Isolated format + @tracked selectedTool = 'drawing'; + @tracked selectedColor = '#ffeb3b'; + @tracked showNotes = false; // ²⁵ Start with sidebar hidden + @tracked currentPage = 1; + @tracked pdfScale: number | string = 1.0; // ²⁶ PDF scaling factor + @tracked minScale = 0.5; // ²⁷ Minimum zoom level + @tracked maxScale = 3.0; // ²⁸ Maximum zoom level + @tracked totalPages = 1; + @tracked pdfDoc: any = null; + @tracked isSelecting = false; + @tracked selectedText = ''; + @tracked selectionRange: any = null; + + @tracked errorMessage = ''; + @tracked isDrawing = false; + @tracked currentDrawingPath: Array<{ x: number; y: number }> = []; + @tracked drawingThickness = 2; + + // Drawing functionality + @action + startDrawing(event: MouseEvent) { + if (this.selectedTool === 'drawing') { + event.preventDefault(); + event.stopPropagation(); + + // ¹⁰⁵ CRITICAL: Validate event originated from drawing layer + const drawingLayer = event.currentTarget as HTMLElement; + if (!drawingLayer || !drawingLayer.classList.contains('drawing-layer')) { + return; + } + + const canvas = document.getElementById('pdf-canvas') as HTMLCanvasElement; + if (!canvas) { + console.warn('Canvas not found, cannot start drawing'); + return; + } + + const rect = canvas.getBoundingClientRect(); + const x = event.clientX - rect.left; + const y = event.clientY - rect.top; + + // Validate coordinates are within canvas bounds + if (x < 0 || y < 0 || x > rect.width || y > rect.height) { + return; + } + + this.isDrawing = true; + this.currentDrawingPath = [{ x, y }]; + } + } + + @action + continueDrawing(event: MouseEvent) { + // ¹⁰⁶ CRITICAL: Validate drawing state before processing any mouse events + if ( + !this.isDrawing || + this.selectedTool !== 'drawing' || + !this.currentDrawingPath + ) { + return; + } + + event.preventDefault(); + event.stopPropagation(); + + const canvas = document.getElementById('pdf-canvas') as HTMLCanvasElement; + if (!canvas) { + console.warn('Canvas not found during drawing'); + this.stopDrawing(); + return; + } + + const rect = canvas.getBoundingClientRect(); + let x = event.clientX - rect.left; + let y = event.clientY - rect.top; + + // ¹⁰⁷ Validate coordinates are not NaN + if (isNaN(x) || isNaN(y)) { + console.warn('Invalid coordinates detected, stopping drawing'); + this.stopDrawing(); + return; + } + + // Clamp coordinates to canvas bounds + x = Math.max(0, Math.min(rect.width, x)); + y = Math.max(0, Math.min(rect.height, y)); + + this.currentDrawingPath.push({ x, y }); + + if (this.currentDrawingPath.length >= 2) { + this.drawCurrentPath(); + } + } + + @action + stopDrawing() { + const wasDrawing = this.isDrawing; + const pathLength = this.currentDrawingPath.length; + + this.isDrawing = false; + + if (wasDrawing && pathLength > 1) { + const canvas = document.getElementById('pdf-canvas') as HTMLCanvasElement; + if (!canvas) { + console.warn('Canvas not found when stopping drawing'); + this.currentDrawingPath = []; + this.cleanupDrawingPreviews(); + return; + } + + if (canvas.offsetWidth === 0 || canvas.offsetHeight === 0) { + console.warn('Canvas has zero dimensions, cannot save drawing'); + this.currentDrawingPath = []; + this.cleanupDrawingPreviews(); + return; + } + + try { + const normalizedPoints = this.currentDrawingPath.map((point) => ({ + x: Math.max(0, Math.min(1, point.x / canvas.offsetWidth)), + y: Math.max(0, Math.min(1, point.y / canvas.offsetHeight)), + })); + + if ( + normalizedPoints.length > 1 && + normalizedPoints.every((p) => !isNaN(p.x) && !isNaN(p.y)) + ) { + const drawing: DrawingAnnotation = { + id: `drawing_${Date.now()}_${Math.random() + .toString(36) + .substr(2, 9)}`, + type: 'drawing', + paths: [ + { + points: normalizedPoints, + color: this.selectedColor, + thickness: Math.max( + 0.001, + Math.min(0.1, this.drawingThickness / canvas.offsetWidth), + ), + }, + ], + pageNumber: this.currentPage, + createdAt: this.createTimestamp(), + color: this.selectedColor, + }; + + this.addAnnotation(drawing); + } + } catch (error) { + console.error('Error processing drawing:', error); + } + } + + this.currentDrawingPath = []; + this.cleanupDrawingPreviews(); + } + + private drawCurrentPath() { + const canvas = document.getElementById('pdf-canvas') as HTMLCanvasElement; + if (!canvas || this.currentDrawingPath.length < 2) return; + + try { + // ⁹³ CRITICAL: Cleanup any existing preview first to prevent accumulation + this.cleanupDrawingPreviews(); + + const tempCanvas = document.createElement('canvas'); + tempCanvas.width = canvas.width; + tempCanvas.height = canvas.height; + tempCanvas.style.position = 'absolute'; + tempCanvas.style.top = '0'; + tempCanvas.style.left = '0'; + tempCanvas.style.pointerEvents = 'none'; + tempCanvas.style.zIndex = '30'; + tempCanvas.style.width = canvas.style.width; + tempCanvas.style.height = canvas.style.height; + tempCanvas.className = 'drawing-preview'; + + const parent = canvas.parentElement; + if (!parent) { + console.warn('Canvas parent not found for preview'); + return; + } + + parent.appendChild(tempCanvas); + + const tempCtx = tempCanvas.getContext('2d'); + if (!tempCtx) return; + + // ⁹⁴ Validate device pixel ratio and drawing path + const devicePixelRatio = Math.max(1, window.devicePixelRatio || 1); + tempCtx.scale(devicePixelRatio, devicePixelRatio); + + tempCtx.strokeStyle = this.selectedColor; + tempCtx.lineWidth = Math.max(1, this.drawingThickness); // ⁹⁵ Ensure minimum line width + tempCtx.lineCap = 'round'; + tempCtx.lineJoin = 'round'; + + tempCtx.beginPath(); + const startPoint = this.currentDrawingPath[0]; + tempCtx.moveTo(startPoint.x, startPoint.y); + + for (let i = 1; i < this.currentDrawingPath.length; i++) { + const point = this.currentDrawingPath[i]; + // ⁹⁶ Validate each point before drawing + if (!isNaN(point.x) && !isNaN(point.y)) { + tempCtx.lineTo(point.x, point.y); + } + } + + tempCtx.stroke(); + } catch (error) { + console.error('Error drawing current path:', error); + this.cleanupDrawingPreviews(); // Clean up on error + } + } + + // Helper method to create ISO timestamp with fallbacks + private createTimestamp(): string { + try { + // Try standard Date first + return new Date().toISOString(); + } catch (e) { + try { + // Fallback to Date.now() + manual formatting + const now = Date.now(); + const date = new Date(now); + return date.toISOString(); + } catch (e2) { + // Final fallback - manual ISO string creation + const now = Date.now(); + const date = new Date(now); + const year = date.getFullYear(); + const month = String(date.getMonth() + 1).padStart(2, '0'); + const day = String(date.getDate()).padStart(2, '0'); + const hours = String(date.getHours()).padStart(2, '0'); + const minutes = String(date.getMinutes()).padStart(2, '0'); + const seconds = String(date.getSeconds()).padStart(2, '0'); + return `${year}-${month}-${day}T${hours}:${minutes}:${seconds}.000Z`; + } + } + } + + private getCanvas(): HTMLCanvasElement | null { + return document.getElementById('pdf-canvas') as HTMLCanvasElement | null; + } + private getPageWrapper(): HTMLElement | null { + const c = this.getCanvas(); + return (c?.parentElement as HTMLElement) ?? null; // .pageLayer + } + + // Clean selected text to remove extra whitespace and line breaks + private cleanupSelectedText(text: string): string { + return text + .replace(/\s+/g, ' ') // Replace multiple spaces with single space + .replace(/\n+/g, ' ') // Replace line breaks with spaces + .trim(); // Remove leading/trailing whitespace + } + + // Annotation storage + get annotations() { + try { + if (this.args.model?.annotationData) { + return JSON.parse(this.args.model.annotationData); + } + } catch (e) { + console.error('Failed to parse annotation data:', e); + } + return []; + } + + private getAnnotations(): Annotation[] { + if (!this.args.model?.annotationData) { + return []; + } + + try { + return JSON.parse(this.args.model.annotationData); + } catch (e) { + console.error('Failed to parse annotation data:', e); + return []; + } + } + + private saveAnnotations(annotations: Annotation[]) { + if (this.args.model) { + const annotationDataString = JSON.stringify(annotations); + + this.args.model.annotationData = annotationDataString; + this.args.model.createdAt = this.createTimestamp(); + } else { + console.error('No model available for saving annotations'); + } + } + + private addAnnotation(annotation: Annotation) { + const annotations = this.getAnnotations(); + + // Create a new array with the new annotation + const updatedAnnotations = [...annotations, annotation]; + + this.saveAnnotations(updatedAnnotations); + + // ⁷² Force re-render of annotations for the current page + if (annotation.pageNumber === this.currentPage) { + // ⁷³ Also trigger immediate redraw for drawings + if (annotation.type === 'drawing') { + setTimeout(() => { + this.redrawStoredAnnotations(this.currentPage); + }, 50); + } + } + } + + get annotationsForCurrentPage() { + const allAnnotations = this.getAnnotations(); + const currentPageAnnotations = allAnnotations.filter( + (ann) => ann.pageNumber === this.currentPage, + ); + + return currentPageAnnotations as any; + } + + private getAnnotationsForPage(pageNumber: number): Annotation[] { + const allAnnotations = this.getAnnotations(); + const pageAnnotations = allAnnotations.filter( + (ann) => ann.pageNumber === pageNumber, + ); + + return pageAnnotations; + } + + // ¹⁵ PDF.js integration + private loadPDFjs = task(async () => { + try { + // Load PDF.js CSS first + if (!document.querySelector('link[href*="pdf.js"]')) { + await this.loadCSS( + 'https://cdnjs.cloudflare.com/ajax/libs/pdf.js/3.11.174/pdf_viewer.css', + ); + } + + // Load PDF.js from CDN + if (!(globalThis as any).pdfjsLib) { + await this.loadScript( + 'https://cdnjs.cloudflare.com/ajax/libs/pdf.js/3.11.174/pdf.min.js', + ); + // Configure worker + (globalThis as any).pdfjsLib.GlobalWorkerOptions.workerSrc = + 'https://cdnjs.cloudflare.com/ajax/libs/pdf.js/3.11.174/pdf.worker.min.js'; + } + + // Wait a moment for PDF.js to fully initialize + await new Promise((resolve) => setTimeout(resolve, 100)); + } catch (error) { + console.error('Failed to load PDF.js', error); + this.errorMessage = 'Failed to load PDF viewer'; + } + }); + + private loadScript(src: string): Promise { + return new Promise((resolve, reject) => { + const script = document.createElement('script'); + script.src = src; + script.onload = () => resolve(); + script.onerror = reject; + document.head.appendChild(script); + }); + } + + private loadCSS(href: string): Promise { + return new Promise((resolve, reject) => { + const link = document.createElement('link'); + link.rel = 'stylesheet'; + link.href = href; + link.onload = () => resolve(); + link.onerror = reject; + document.head.appendChild(link); + }); + } + + // ¹⁶ PDF document loading + private loadPDF = task(async (url: string) => { + try { + await this.loadPDFjs.perform(); + const pdfjsLib = (globalThis as any).pdfjsLib; + + if (!pdfjsLib) { + throw new Error('PDF.js not loaded'); + } + + const loadingTask = pdfjsLib.getDocument(url); + this.pdfDoc = await loadingTask.promise; + this.totalPages = this.pdfDoc.numPages; + + // Use saved page number from model, or default to 1 + const savedPage = this.args.model?.pageNumber || 1; + this.currentPage = Math.min(Math.max(1, savedPage), this.totalPages); + + // Render the saved page (or page 1 if no saved page) + this.renderPage.perform(this.currentPage); + } catch (error: any) { + console.error('Failed to load PDF', error); + this.errorMessage = `Failed to load PDF: ${error.message || error}`; + } + }); + + // ¹⁷ Page rendering with improved reliability and better timing + private renderPage = task(async (pageNum: number) => { + if (!this.pdfDoc) { + console.warn('No PDF document loaded'); + return; + } + + try { + // Validate page number is within bounds + if (pageNum < 1 || pageNum > this.totalPages) { + console.warn(`Page ${pageNum} is out of bounds (1-${this.totalPages})`); + return; + } + + const page = await this.pdfDoc.getPage(pageNum); + + // Wait longer and check multiple times for canvas readiness + let canvas: HTMLCanvasElement | null = null; + let canvasAttempts = 0; + const maxCanvasAttempts = 10; + + while (!canvas && canvasAttempts < maxCanvasAttempts) { + await new Promise((resolve) => setTimeout(resolve, 200)); + canvas = document.getElementById('pdf-canvas') as HTMLCanvasElement; + canvasAttempts++; + } + + if (!canvas) { + console.error('Canvas element not found after multiple attempts'); + this.errorMessage = + 'PDF viewer canvas not ready. Please reload or try again.'; + return; + } + + const context = canvas.getContext('2d'); + if (!context) { + console.error('Could not get canvas 2D context'); + this.errorMessage = 'Canvas rendering not supported in this browser'; + return; + } + + // Calculate scale based on container width + const container = canvas.parentElement; + const containerWidth = container ? container.clientWidth : 800; + const baseViewport = page.getViewport({ scale: 1 }); + + let scale: number; + if (this.pdfScale === 'fit-width') { + const targetWidth = containerWidth - 20; // Some margin + scale = targetWidth / baseViewport.width; + this.pdfScale = scale; // Update tracked scale for UI display + } else { + scale = + typeof this.pdfScale === 'number' && this.pdfScale > 0 + ? this.pdfScale + : 1.0; + } + + const viewport = page.getViewport({ scale }); + + const wrapper = canvas.parentElement as HTMLElement; + if (wrapper) { + wrapper.style.position = 'relative'; + wrapper.style.width = `${Math.floor(viewport.width)}px`; + wrapper.style.height = `${Math.floor(viewport.height)}px`; + } + + const outputScale = window.devicePixelRatio || 1; + canvas.width = Math.floor(viewport.width * outputScale); + canvas.height = Math.floor(viewport.height * outputScale); + canvas.style.width = `${Math.floor(viewport.width)}px`; + canvas.style.height = `${Math.floor(viewport.height)}px`; + + const transform = + outputScale !== 1 ? [outputScale, 0, 0, outputScale, 0, 0] : null; + await page.render({ canvasContext: context, viewport, transform }) + .promise; + canvas.style.maxWidth = '100%'; + canvas.style.display = 'block'; + + // Update model with current page + if (this.args.model) { + this.args.model.pageNumber = pageNum; + } + + // Create text layer for text selection usi.textLayerng PDF.js TextLayerBuilder + await this.createTextLayer(page, viewport, canvas); + + // Clear any existing text selection when rendering a new page + this.clearTextSelection(); + + // Render highlights in text layer + this.renderPageHighlights(pageNum); + + // ⁷⁴ Important: Re-render any existing drawings after page render + setTimeout(() => { + this.redrawStoredAnnotations(pageNum); + + // ⁷⁸ CRITICAL: Clean up any drawing preview elements from previous drawings + this.cleanupDrawingPreviews(); + }, 150); // ⁷⁵ Slightly longer delay to ensure PDF rendering is complete + + // Clear any previous error message + this.errorMessage = ''; + } catch (error: any) { + console.error('Failed to render page', error); + this.errorMessage = `Failed to render page ${pageNum}: ${error.message}. Try refreshing the page.`; + } + }); + + // Create text layer for text selection using PDF.js CDN API + private async createTextLayer( + page: any, + viewport: any, + canvas: HTMLCanvasElement, + ) { + try { + // Remove any existing textLayer + const existingTextLayer = + canvas.parentElement?.querySelector('.textLayer'); + if (existingTextLayer) existingTextLayer.remove(); + + const canvasContainer = canvas.parentElement; + if (!canvasContainer) return; + + const textLayerDiv = document.createElement('div'); + textLayerDiv.className = 'textLayer'; + Object.assign(textLayerDiv.style, { + position: 'absolute', + left: '0', + top: '0', + width: `${Math.floor(viewport.width)}px`, + height: `${Math.floor(viewport.height)}px`, + pointerEvents: 'auto', + zIndex: '20', + }); + + textLayerDiv.style.setProperty('--scale-factor', String(viewport.scale)); + canvasContainer.appendChild(textLayerDiv); + + // Get PDF.js text content + const textContent = await page.getTextContent(); + const pdfjsLib = (globalThis as any).pdfjsLib; + + if (!pdfjsLib?.renderTextLayer) { + console.error('PDF.js renderTextLayer not available'); + return; + } + + // Render the text layer + const renderTask = pdfjsLib.renderTextLayer({ + textContent, + container: textLayerDiv, + viewport, + textDivs: [], + enhanceTextSelection: true, + }); + + if (renderTask.promise) await renderTask.promise; + + // Attach selection handler + textLayerDiv.addEventListener( + 'mouseup', + this.handlePDFTextSelection.bind(this), + ); + } catch (error: any) { + console.error('Failed to create text layer', error); + } + } + + // Render highlights in text layer, not on canvas + private renderPageHighlights(pageNum: number) { + const wrapper = this.getPageWrapper(); + if (!wrapper) return; + const textLayer = wrapper.querySelector('.textLayer'); + if (!textLayer) return; + + // Remove existing persistent highlights + textLayer + .querySelectorAll('.persistent-highlight') + .forEach((el) => el.remove()); + + // Get highlights for current page + const highlights = this.getAnnotationsForPage(pageNum).filter( + (ann) => ann.type === 'highlight', + ) as TextHighlight[]; + + highlights.forEach((highlight) => { + // Handle both single bounds (legacy) and multiple bounds (new) + const boundsArray = Array.isArray(highlight.bounds) + ? highlight.bounds + : [highlight.bounds]; + + this.createTextLayerHighlight(boundsArray, highlight.color); + }); + } + + // Export annotations as JSON + @action + exportAnnotations() { + const annotations = this.getAnnotations(); + const dataStr = JSON.stringify(annotations, null, 2); + const dataBlob = new Blob([dataStr], { type: 'application/json' }); + + const url = URL.createObjectURL(dataBlob); + const link = document.createElement('a'); + link.href = url; + link.download = `annotations_${ + this.args.model?.documentTitle || 'document' + }.json`; + link.click(); + + URL.revokeObjectURL(url); + } + + // Clear all annotations + @action + clearAllAnnotations() { + if ( + confirm( + 'Are you sure you want to clear all annotations? This cannot be undone.', + ) + ) { + this.saveAnnotations([]); + // Re-render current page to clear annotations + this.renderPage.perform(this.currentPage); + } + } + + // Clear annotations for current page only + @action + clearCurrentPageAnnotations() { + if (this.args.model) { + const allAnnotations = this.getAnnotations(); + const otherPageAnnotations = allAnnotations.filter( + (ann) => ann.pageNumber !== this.currentPage, + ); + + if (otherPageAnnotations.length > 0) { + this.args.model.annotationData = JSON.stringify(otherPageAnnotations); + } else { + this.args.model.annotationData = ''; + } + + this.args.model.createdAt = this.createTimestamp(); + + // ³⁶ Re-render the entire page to clear all annotations properly + this.renderPage.perform(this.currentPage); + } + } + + // ⁷⁰ Fixed method: Re-draw stored annotations with proper page filtering + private redrawStoredAnnotations(pageNum: number) { + const canvas = document.getElementById('pdf-canvas') as HTMLCanvasElement; + if (!canvas) { + return; + } + + const ctx = canvas.getContext('2d'); + if (!ctx) { + return; + } + + // ⁷⁶ CRITICAL: Clear any existing drawing overlay first + let drawingCanvas = canvas.parentElement?.querySelector( + '.drawing-overlay', + ) as HTMLCanvasElement; + if (drawingCanvas) { + const drawingCtx = drawingCanvas.getContext('2d'); + if (drawingCtx) { + drawingCtx.clearRect(0, 0, drawingCanvas.width, drawingCanvas.height); + } + } + + // ⁷¹ CRITICAL: Filter annotations by exact page number + const allAnnotations = this.getAnnotations(); + + const pageAnnotations = allAnnotations.filter( + (ann) => ann.pageNumber === pageNum, + ); + + const drawings = pageAnnotations.filter( + (ann) => ann.type === 'drawing', + ) as DrawingAnnotation[]; + + // ⁷⁷ If no drawings for this page, ensure overlay is cleared and return + if (drawings.length === 0) { + return; + } + + // ⁵⁷ Create or reuse dedicated drawing overlay canvas + if (!drawingCanvas) { + drawingCanvas = document.createElement('canvas'); + drawingCanvas.className = 'drawing-overlay'; + drawingCanvas.style.position = 'absolute'; + drawingCanvas.style.top = '0'; + drawingCanvas.style.left = '0'; + drawingCanvas.style.pointerEvents = 'none'; + drawingCanvas.style.zIndex = '25'; + canvas.parentElement?.appendChild(drawingCanvas); + } + + // ⁵⁸ Match the main canvas dimensions exactly + drawingCanvas.width = canvas.width; + drawingCanvas.height = canvas.height; + drawingCanvas.style.width = canvas.style.width; + drawingCanvas.style.height = canvas.style.height; + + const drawingCtx = drawingCanvas.getContext('2d'); + if (!drawingCtx) return; + + // ⁵⁹ Scale drawing context to match device pixel ratio + const devicePixelRatio = window.devicePixelRatio || 1; + drawingCtx.scale(devicePixelRatio, devicePixelRatio); + + // Clear previous drawings (redundant but ensures clean state) + drawingCtx.clearRect(0, 0, drawingCanvas.width, drawingCanvas.height); + + drawings.forEach((drawing) => { + drawing.paths.forEach((path) => { + if (path.points.length < 2) { + return; + } + + drawingCtx.strokeStyle = path.color; + // ⁶⁰ Convert normalized thickness back to display pixels + drawingCtx.lineWidth = path.thickness * canvas.offsetWidth; + drawingCtx.lineCap = 'round'; + drawingCtx.lineJoin = 'round'; + + drawingCtx.beginPath(); + + // ⁶¹ Convert normalized coordinates back to display coordinates + const startX = path.points[0].x * canvas.offsetWidth; + const startY = path.points[0].y * canvas.offsetHeight; + drawingCtx.moveTo(startX, startY); + + for (let i = 1; i < path.points.length; i++) { + const x = path.points[i].x * canvas.offsetWidth; + const y = path.points[i].y * canvas.offsetHeight; + drawingCtx.lineTo(x, y); + } + + drawingCtx.stroke(); + }); + }); + } + + // ¹³¹ Simple color palette + get annotationTools() { + return [{ id: 'drawing', name: 'Draw', icon: 'pen' }]; + } + + get highlightColors() { + return [ + { name: 'Yellow', value: '#ffeb3b' }, + { name: 'Green', value: '#4caf50' }, + { name: 'Blue', value: '#2196f3' }, + { name: 'Pink', value: '#e91e63' }, + { name: 'Orange', value: '#ff9800' }, + ]; + } + + @action + selectColor(color: string) { + this.selectedColor = color; + } + + @action + toggleNotes() { + this.showNotes = !this.showNotes; + } + + // ¹⁸ Navigation actions + @action + previousPage() { + if (this.currentPage > 1) { + this.currentPage--; + // Update model with new page number + if (this.args.model) { + this.args.model.pageNumber = this.currentPage; + } + // Clear text selection when changing pages + this.clearTextSelection(); + // ⁸² CRITICAL: Clean up drawing previews when changing pages + this.cleanupDrawingPreviews(); + // Force a small delay to ensure container is ready + setTimeout(() => { + this.renderPage.perform(this.currentPage); + }, 50); + } + } + + @action + nextPage() { + if (this.currentPage < this.totalPages) { + this.currentPage++; + // Update model with new page number + if (this.args.model) { + this.args.model.pageNumber = this.currentPage; + } + // Clear text selection when changing pages + this.clearTextSelection(); + // ⁸³ CRITICAL: Clean up drawing previews when changing pages + this.cleanupDrawingPreviews(); + // Force a small delay to ensure container is ready + setTimeout(() => { + this.renderPage.perform(this.currentPage); + }, 50); + } + } + + // ²⁹ PDF scaling actions + @action + zoomIn() { + if ((this.pdfScale as number) < this.maxScale) { + this.pdfScale = Math.min(this.maxScale, (this.pdfScale as number) + 0.25); + this.renderPage.perform(this.currentPage); + } + } + + @action + zoomOut() { + if ((this.pdfScale as number) > this.minScale) { + this.pdfScale = Math.max(this.minScale, (this.pdfScale as number) - 0.25); + this.renderPage.perform(this.currentPage); + } + } + + @action + resetZoom() { + this.pdfScale = 1.0; + this.renderPage.perform(this.currentPage); + } + + @action + fitToWidth() { + // Will be calculated in renderPage based on container width + this.pdfScale = 'fit-width'; + this.renderPage.perform(this.currentPage); + } + + // ¹⁹ File upload handling + @action + async handleFileUpload(event: Event) { + const input = event.target as HTMLInputElement; + const file = input.files?.[0]; + + if (file && file.type === 'application/pdf') { + try { + // Create blob URL for the uploaded file + const url = URL.createObjectURL(file); + + // Update model + if (this.args.model) { + this.args.model.documentUrl = url; + this.args.model.documentTitle = file.name.replace('.pdf', ''); + } + + // Load the PDF + await this.loadPDF.perform(url); + } catch (error: any) { + this.errorMessage = `Failed to upload file: ${error.message}`; + } + } else { + this.errorMessage = 'Please select a valid PDF file'; + } + } + + // ²⁰ Text selection handling + @action + handleTextSelection() { + // ¹¹⁷ CRITICAL: Don't process text selection when in drawing mode + if (this.selectedTool === 'drawing') { + return; + } + + // Check if we have a text selection from the PDF text layer + const selection = window.getSelection(); + if (selection && selection.toString().length > 0) { + this.selectedText = selection.toString().trim(); + this.selectionRange = selection.getRangeAt(0); + + if (this.selectedTool === 'highlight') { + this.addTextHighlight(); + } else if (this.selectedTool === 'note') { + this.showNotes = true; + } else if (this.selectedTool === 'comment') { + this.showNotes = true; + } + } + } + + // Handle text selection from PDF text layer + @action + handlePDFTextSelection(event: MouseEvent) { + // ¹¹⁴ CRITICAL: Don't process text selection when in drawing mode + if (this.selectedTool === 'drawing') { + return; + } + + // ¹¹⁶ CRITICAL: Also ignore if mouse was pressed outside and dragged in + if (event.buttons > 0) { + return; + } + + // Small delay to ensure selection is complete + setTimeout(() => { + const selection = window.getSelection(); + if (selection && selection.toString().length > 0) { + // Verify the selection is from the current page's text layer + if (!this.isSelectionValid(selection)) { + this.clearTextSelection(); + return; + } + + let rawText = selection.toString(); + + // Clean up the selected text to remove padding characters + this.selectedText = this.cleanupSelectedText(rawText); + this.selectionRange = selection.getRangeAt(0); + + // Highlight the selected text in the text layer + this.highlightSelectedText(); + + // Auto-create highlight if highlight tool is selected + if ( + this.selectedTool === 'highlight' && + this.selectedText.trim().length > 0 + ) { + this.addTextHighlight(); + } + } + }, 50); + } + + // Create persistent highlights in text layer using normalized coordinates + private createTextLayerHighlight( + bounds: Array<{ x: number; y: number; width: number; height: number }>, + color: string, + ) { + const wrapper = this.getPageWrapper(); + if (!wrapper) { + return; + } + const textLayer = wrapper.querySelector('.textLayer') as HTMLElement; + if (!textLayer) { + return; + } + + // Get current viewport scale for proper highlight positioning + + // Convert normalized bounds back to text layer coordinates + // The text layer size already reflects the current scale, so we don't need to scale again + const textLayerWidth = textLayer.offsetWidth; + const textLayerHeight = textLayer.offsetHeight; + + bounds.forEach((normalizedBound, index) => { + const highlight = document.createElement('div'); + highlight.className = 'persistent-highlight'; + highlight.dataset.annotationId = `temp_${Date.now()}_${index}`; + + // Convert from normalized (0-1) to actual text layer pixels + // The text layer already has the correct dimensions for the current scale + const left = normalizedBound.x * textLayerWidth; + const top = normalizedBound.y * textLayerHeight; + const width = normalizedBound.width * textLayerWidth; + const height = normalizedBound.height * textLayerHeight; + + // CRITICAL: Ensure highlight is visible above text layer + highlight.style.cssText = ` + position: absolute !important; + left: ${left}px; + top: ${top}px; + width: ${width}px; + height: ${height}px; + background: ${color}60 !important; + border: 1px solid ${color}90 !important; + pointer-events: none !important; + z-index: 25 !important; + border-radius: 2px; + box-shadow: 0 1px 3px rgba(0,0,0,0.1); + mix-blend-mode: multiply; + `; + + textLayer.appendChild(highlight); + }); + } + + // Highlight the selected text temporarily in the text layer + private highlightSelectedText() { + if (!this.selectionRange) return; + + const wrapper = this.getPageWrapper(); + if (!wrapper) return; + const textLayer = wrapper.querySelector('.textLayer'); + if (!textLayer) return; + + // Remove existing temporary highlights + textLayer + .querySelectorAll('.selection-highlight') + .forEach((el) => el.remove()); + + const rects = Array.from(this.selectionRange.getClientRects()); + const textLayerRect = textLayer.getBoundingClientRect(); + + rects.forEach((rect: any) => { + if ( + rect.width > 0 && + rect.height > 0 && + rect.right > textLayerRect.left && + rect.left < textLayerRect.right && + rect.bottom > textLayerRect.top && + rect.top < textLayerRect.bottom + ) { + const highlight = document.createElement('div'); + highlight.className = 'selection-highlight'; + + const relativeLeft = rect.left - textLayerRect.left; + const relativeTop = rect.top - textLayerRect.top; + + highlight.style.cssText = ` + position: absolute; + left: ${relativeLeft}px; + top: ${relativeTop}px; + width: ${rect.width}px; + height: ${rect.height}px; + background: rgba(0, 123, 255, 0.3); + border: 1px solid rgba(0, 123, 255, 0.5); + pointer-events: none; + z-index: 25; + border-radius: 2px; + `; + + textLayer.appendChild(highlight); + } + }); + } + + // Get normalized text selection bounds for PDF coordinates + private getTextSelectionBounds(): Array<{ + x: number; + y: number; + width: number; + height: number; + }> { + if (!this.selectionRange) { + return []; + } + + // Get current viewport for normalization + const wrapper = this.getPageWrapper(); + if (!wrapper) return []; + const textLayer = wrapper.querySelector('.textLayer') as HTMLElement; + if (!textLayer) { + return []; + } + + // Use getClientRects for accurate text bounds + const rects = Array.from(this.selectionRange.getClientRects()); + const textLayerRect = textLayer.getBoundingClientRect(); + + // Convert to normalized PDF coordinates (0-1 relative to page) + const bounds = rects + .map((rect: any) => { + // Check if rect intersects with text layer + if ( + rect.right < textLayerRect.left || + rect.left > textLayerRect.right || + rect.bottom < textLayerRect.top || + rect.top > textLayerRect.bottom + ) { + return null; + } + + // Calculate relative to text layer + const relativeToTextLayer = { + x: rect.left - textLayerRect.left, + y: rect.top - textLayerRect.top, + width: rect.width, + height: rect.height, + }; + + // Normalize to PDF coordinates (0-1) + const normalizedBounds = { + x: relativeToTextLayer.x / textLayer.offsetWidth, + y: relativeToTextLayer.y / textLayer.offsetHeight, + width: relativeToTextLayer.width / textLayer.offsetWidth, + height: relativeToTextLayer.height / textLayer.offsetHeight, + }; + + // Clamp to valid range + normalizedBounds.x = Math.max(0, Math.min(1, normalizedBounds.x)); + normalizedBounds.y = Math.max(0, Math.min(1, normalizedBounds.y)); + normalizedBounds.width = Math.max( + 0, + Math.min(1 - normalizedBounds.x, normalizedBounds.width), + ); + normalizedBounds.height = Math.max( + 0, + Math.min(1 - normalizedBounds.y, normalizedBounds.height), + ); + + return normalizedBounds; + }) + .filter((bound): bound is NonNullable => bound !== null); + + const validBounds = bounds.filter( + (bound) => bound.width > 0 && bound.height > 0, + ); + + return validBounds; + } + + // ²¹ Annotation actions + @action + addTextHighlight() { + if (this.selectedText && this.args.model) { + const boundsArray = this.getTextSelectionBounds(); + + if (boundsArray.length > 0) { + // Create highlight object + const highlight: TextHighlight = { + id: `highlight_${Date.now()}_${Math.random() + .toString(36) + .substr(2, 9)}`, + type: 'highlight', + text: this.selectedText, + bounds: boundsArray.length === 1 ? boundsArray[0] : boundsArray, + color: this.selectedColor, + pageNumber: this.currentPage, + createdAt: this.createTimestamp(), + }; + + // CRITICAL: Create persistent highlight IMMEDIATELY for instant feedback + const boundsForRender = Array.isArray(highlight.bounds) + ? highlight.bounds + : [highlight.bounds]; + this.createTextLayerHighlight(boundsForRender, highlight.color); + + // Then save to model (slower) + this.addAnnotation(highlight); + + // Clear selection AFTER creating persistent highlight + window.getSelection()?.removeAllRanges(); + this.selectedText = ''; + this.selectionRange = null; + + // Remove temporary selection highlight + const wrapper = this.getPageWrapper(); + if (wrapper) { + const textLayer = wrapper.querySelector('.textLayer'); + if (textLayer) { + textLayer + .querySelectorAll('.selection-highlight') + .forEach((el) => el.remove()); + } + } + } else { + } + } else { + console.error('Cannot create highlight'); + } + } + + @tracked hasInitialized = false; + + // Improved initialization with better timing + constructor(owner: any, args: any) { + super(owner, args); + // Use a slightly longer delay to ensure DOM is fully ready + setTimeout(() => { + this.initializePDF(); + }, 500); + } + + // Add resize observer to handle container size changes + private setupResizeObserver() { + const container = document.querySelector('.canvas-container'); + if (container && 'ResizeObserver' in window) { + const resizeObserver = new ResizeObserver(() => { + // Re-render current page when container size changes + if (this.pdfDoc && this.currentPage) { + this.renderPage.perform(this.currentPage); + } + }); + resizeObserver.observe(container); + } + } + + private initializePDF() { + if ( + this.args.model?.documentUrl && + !this.pdfDoc && + !this.loadPDF.isRunning && + !this.hasInitialized + ) { + this.hasInitialized = true; + + // Add a small delay before starting PDF load to ensure UI is ready + setTimeout(() => { + this.loadPDF.perform(this.args.model.documentUrl as string); + // Set up resize observer after PDF is loaded + this.setupResizeObserver(); + }, 100); + } + } + + // Improved retry mechanism with full reset + @action + retryPDF() { + this.errorMessage = ''; + this.hasInitialized = false; + this.pdfDoc = null; + this.currentPage = 1; + this.totalPages = 1; + + // Clear the canvas + const canvas = document.getElementById('pdf-canvas') as HTMLCanvasElement; + if (canvas) { + const context = canvas.getContext('2d'); + if (context) { + context.clearRect(0, 0, canvas.width, canvas.height); + } + } + + setTimeout(() => { + this.initializePDF(); + }, 100); + } + + +} + +export class AnnotationCard extends CardDef { + // ³ Annotation card definition + static displayName = 'Document Annotation'; + static icon = EditIcon; + + @field documentUrl = contains(UrlField); // ⁴ Document and annotation fields + @field documentTitle = contains(StringField); + @field annotations = containsMany(StringField); // Legacy field for backward compatibility + @field pageNumber = contains(NumberField); + @field position = contains(StringField); + @field annotationType = contains(StringField); + @field color = contains(StringField); + @field createdAt = contains(StringField); // Store as ISO string for compatibility + + // New structured annotation fields + @field annotationData = contains(StringField); // JSON string containing all annotations + + // ⁵ Computed title + @field cardTitle = contains(StringField, { + computeVia: function (this: AnnotationCard) { + try { + const docTitle = this.documentTitle || 'Document'; + const annotationCount = this.annotations?.length || 0; + return `${docTitle} (${annotationCount} annotations)`; + } catch (e) { + console.error('AnnotationCard: Error computing title', e); + return 'Document Annotations'; + } + }, + }); + + static isolated = AnnotationIsolated; + + static embedded = class Embedded extends Component { + // ⁹ Embedded format + + }; + + static fitted = class Fitted extends Component { + // ¹¹ Fitted format + + }; +}