Repository: 1j01/jspaint Branch: master Commit: bc07ca1bce92 Files: 2535 Total size: 14.4 MB Directory structure: gitextract_p5h0c0f0/ ├── .github/ │ └── FUNDING.yml ├── .gitignore ├── .vscode/ │ ├── extensions.json │ ├── launch.json │ ├── run-command-on-all-files.ahk │ └── settings.json ├── CHANGELOG.md ├── CNAME ├── CONTRIBUTING.md ├── LICENSE.txt ├── README.md ├── TODO.md ├── about.html ├── browserconfig.xml ├── cspell.json ├── cypress/ │ ├── cypress-image-snapshot-viewer.js │ ├── fixtures/ │ │ └── example.json │ ├── integration/ │ │ ├── tool-tests.spec.js │ │ └── visual-tests.spec.js │ ├── plugins/ │ │ └── index.js │ └── support/ │ ├── commands.js │ └── index.js ├── cypress.json ├── discord-activity/ │ ├── .gitignore │ ├── README.md │ ├── package.json │ └── packages/ │ └── server/ │ ├── environment.d.ts │ ├── package.json │ ├── src/ │ │ ├── app.ts │ │ ├── shared/ │ │ │ └── hello.ts │ │ └── utils.ts │ └── tsconfig.json ├── eslint.config.mjs ├── forge.config.js ├── help/ │ ├── coUA.css │ ├── default.html │ ├── memcopy.html │ ├── mspaint.hhc │ ├── mspaint.hhk │ ├── nobgcolor.css │ ├── online_support.htm │ ├── paint_airbrush.html │ ├── paint_blackwhite.html │ ├── paint_brush.html │ ├── paint_change_color.html │ ├── paint_change_size.html │ ├── paint_clear_image.html │ ├── paint_color_box.html │ ├── paint_curves.html │ ├── paint_custom_colors.html │ ├── paint_cutout_copy_move.html │ ├── paint_cutout_save.html │ ├── paint_cutout_select.html │ ├── paint_enlarge_area.html │ ├── paint_erase_large.html │ ├── paint_erase_small.html │ ├── paint_fill.html │ ├── paint_flip_picture.html │ ├── paint_freeform_lines.html │ ├── paint_grid.html │ ├── paint_insert_file.html │ ├── paint_invert.html │ ├── paint_lines.html │ ├── paint_not_in_color_box.html │ ├── paint_ovals.html │ ├── paint_polygons.html │ ├── paint_print.html │ ├── paint_rectangles.html │ ├── paint_set_default_colors.html │ ├── paint_skew_picture.html │ ├── paint_text.html │ ├── paint_toolbox.html │ ├── paint_trans_opaque.html │ ├── paint_undo.html │ ├── paint_wallpaper.html │ ├── paint_zoom.html │ ├── prettify-html.ahk │ └── vaporwave.js ├── images/ │ ├── 88x31/ │ │ └── custom/ │ │ ├── pipe-strip-88x31-v0.psd │ │ ├── pipe-strip-88x31-v1.psd │ │ ├── pipe-strip-88x31-v2.psd │ │ ├── pipe-strip-88x31-v3.psd │ │ ├── pipe-strip-88x31-v4.psd │ │ └── turbo-encabulator-88x31-v0.psd │ ├── bubblegum/ │ │ ├── bubblegum-recess.psd │ │ ├── eye-gaze-pause-button.psd │ │ └── fill-with-color.psd │ ├── icons/ │ │ └── jspaint.icns │ └── modern/ │ └── cursors/ │ ├── airbrush-alt.cur │ ├── airbrush.cur │ ├── crosshair-large.cur │ ├── crosshair.cur │ ├── ew-resize-large.cur │ ├── ew-resize.cur │ ├── eye-dropper-large.cur │ ├── eye-dropper.cur │ ├── magnifier-large.cur │ ├── magnifier.cur │ ├── move-large-alt.cur │ ├── move-large.cur │ ├── move.cur │ ├── nesw-resize-large.cur │ ├── nesw-resize.cur │ ├── ns-resize-large.cur │ ├── ns-resize.cur │ ├── nwse-resize-large.cur │ ├── nwse-resize.cur │ ├── paint-bucket-large.cur │ ├── paint-bucket.cur │ ├── pencil-large.cur │ ├── pencil.cur │ ├── precise-large.cur │ ├── precise.cur │ ├── select-alt.cur │ ├── select-large-alt.cur │ ├── select-large.cur │ ├── select.cur │ ├── text-large.cur │ ├── text.cur │ ├── zoom-in-large.cur │ ├── zoom-in.cur │ ├── zoom-out-large.cur │ └── zoom-out.cur ├── index.html ├── jsconfig.json ├── lib/ │ ├── 98.css/ │ │ ├── 98.custom-build.css │ │ ├── 98.custom-build.rtl.css │ │ ├── 98.custom-src.css │ │ └── modified-build.js │ ├── FileSaver.js │ ├── UPNG.js │ ├── UTIF.js │ ├── anypalette-0.6.0.js │ ├── bmp.js │ ├── discord-embedded-app-sdk-v1.2.0-bundled-with-skypack.js │ ├── firebase.js │ ├── font-detective.js │ ├── gif.js/ │ │ ├── gif.js │ │ └── gif.worker.js │ ├── imagetracer_v1.2.5.js │ ├── os-gui/ │ │ ├── $Window.js │ │ ├── MenuBar.js │ │ ├── build/ │ │ │ ├── blue.css │ │ │ ├── layout.css │ │ │ ├── layout.rtl.css │ │ │ ├── peggys-pastels.css │ │ │ ├── windows-98.css │ │ │ └── windows-default.css │ │ ├── os-gui.d.ts │ │ └── parse-theme.js │ ├── os-gui.patch │ ├── pdf.js/ │ │ ├── LICENSE │ │ ├── build/ │ │ │ ├── pdf.js │ │ │ ├── pdf.sandbox.js │ │ │ └── pdf.worker.js │ │ └── web/ │ │ ├── cmaps/ │ │ │ ├── 78-EUC-H.bcmap │ │ │ ├── 78-EUC-V.bcmap │ │ │ ├── 78-H.bcmap │ │ │ ├── 78-RKSJ-H.bcmap │ │ │ ├── 78-RKSJ-V.bcmap │ │ │ ├── 78-V.bcmap │ │ │ ├── 78ms-RKSJ-H.bcmap │ │ │ ├── 78ms-RKSJ-V.bcmap │ │ │ ├── 83pv-RKSJ-H.bcmap │ │ │ ├── 90ms-RKSJ-H.bcmap │ │ │ ├── 90ms-RKSJ-V.bcmap │ │ │ ├── 90msp-RKSJ-H.bcmap │ │ │ ├── 90msp-RKSJ-V.bcmap │ │ │ ├── 90pv-RKSJ-H.bcmap │ │ │ ├── 90pv-RKSJ-V.bcmap │ │ │ ├── Add-H.bcmap │ │ │ ├── Add-RKSJ-H.bcmap │ │ │ ├── Add-RKSJ-V.bcmap │ │ │ ├── Add-V.bcmap │ │ │ ├── Adobe-CNS1-0.bcmap │ │ │ ├── Adobe-CNS1-1.bcmap │ │ │ ├── Adobe-CNS1-2.bcmap │ │ │ ├── Adobe-CNS1-3.bcmap │ │ │ ├── Adobe-CNS1-4.bcmap │ │ │ ├── Adobe-CNS1-5.bcmap │ │ │ ├── Adobe-CNS1-6.bcmap │ │ │ ├── Adobe-CNS1-UCS2.bcmap │ │ │ ├── Adobe-GB1-0.bcmap │ │ │ ├── Adobe-GB1-1.bcmap │ │ │ ├── Adobe-GB1-2.bcmap │ │ │ ├── Adobe-GB1-3.bcmap │ │ │ ├── Adobe-GB1-4.bcmap │ │ │ ├── Adobe-GB1-5.bcmap │ │ │ ├── Adobe-GB1-UCS2.bcmap │ │ │ ├── Adobe-Japan1-0.bcmap │ │ │ ├── Adobe-Japan1-1.bcmap │ │ │ ├── Adobe-Japan1-2.bcmap │ │ │ ├── Adobe-Japan1-3.bcmap │ │ │ ├── Adobe-Japan1-4.bcmap │ │ │ ├── Adobe-Japan1-5.bcmap │ │ │ ├── Adobe-Japan1-6.bcmap │ │ │ ├── Adobe-Japan1-UCS2.bcmap │ │ │ ├── Adobe-Korea1-0.bcmap │ │ │ ├── Adobe-Korea1-1.bcmap │ │ │ ├── Adobe-Korea1-2.bcmap │ │ │ ├── Adobe-Korea1-UCS2.bcmap │ │ │ ├── B5-H.bcmap │ │ │ ├── B5-V.bcmap │ │ │ ├── B5pc-H.bcmap │ │ │ ├── B5pc-V.bcmap │ │ │ ├── CNS-EUC-H.bcmap │ │ │ ├── CNS-EUC-V.bcmap │ │ │ ├── CNS1-H.bcmap │ │ │ ├── CNS1-V.bcmap │ │ │ ├── CNS2-H.bcmap │ │ │ ├── CNS2-V.bcmap │ │ │ ├── ETHK-B5-H.bcmap │ │ │ ├── ETHK-B5-V.bcmap │ │ │ ├── ETen-B5-H.bcmap │ │ │ ├── ETen-B5-V.bcmap │ │ │ ├── ETenms-B5-H.bcmap │ │ │ ├── ETenms-B5-V.bcmap │ │ │ ├── EUC-H.bcmap │ │ │ ├── EUC-V.bcmap │ │ │ ├── Ext-H.bcmap │ │ │ ├── Ext-RKSJ-H.bcmap │ │ │ ├── Ext-RKSJ-V.bcmap │ │ │ ├── Ext-V.bcmap │ │ │ ├── GB-EUC-H.bcmap │ │ │ ├── GB-EUC-V.bcmap │ │ │ ├── GB-H.bcmap │ │ │ ├── GB-V.bcmap │ │ │ ├── GBK-EUC-H.bcmap │ │ │ ├── GBK-EUC-V.bcmap │ │ │ ├── GBK2K-H.bcmap │ │ │ ├── GBK2K-V.bcmap │ │ │ ├── GBKp-EUC-H.bcmap │ │ │ ├── GBKp-EUC-V.bcmap │ │ │ ├── GBT-EUC-H.bcmap │ │ │ ├── GBT-EUC-V.bcmap │ │ │ ├── GBT-H.bcmap │ │ │ ├── GBT-V.bcmap │ │ │ ├── GBTpc-EUC-H.bcmap │ │ │ ├── GBTpc-EUC-V.bcmap │ │ │ ├── GBpc-EUC-H.bcmap │ │ │ ├── GBpc-EUC-V.bcmap │ │ │ ├── H.bcmap │ │ │ ├── HKdla-B5-H.bcmap │ │ │ ├── HKdla-B5-V.bcmap │ │ │ ├── HKdlb-B5-H.bcmap │ │ │ ├── HKdlb-B5-V.bcmap │ │ │ ├── HKgccs-B5-H.bcmap │ │ │ ├── HKgccs-B5-V.bcmap │ │ │ ├── HKm314-B5-H.bcmap │ │ │ ├── HKm314-B5-V.bcmap │ │ │ ├── HKm471-B5-H.bcmap │ │ │ ├── HKm471-B5-V.bcmap │ │ │ ├── HKscs-B5-H.bcmap │ │ │ ├── HKscs-B5-V.bcmap │ │ │ ├── Hankaku.bcmap │ │ │ ├── Hiragana.bcmap │ │ │ ├── KSC-EUC-H.bcmap │ │ │ ├── KSC-EUC-V.bcmap │ │ │ ├── KSC-H.bcmap │ │ │ ├── KSC-Johab-H.bcmap │ │ │ ├── KSC-Johab-V.bcmap │ │ │ ├── KSC-V.bcmap │ │ │ ├── KSCms-UHC-H.bcmap │ │ │ ├── KSCms-UHC-HW-H.bcmap │ │ │ ├── KSCms-UHC-HW-V.bcmap │ │ │ ├── KSCms-UHC-V.bcmap │ │ │ ├── KSCpc-EUC-H.bcmap │ │ │ ├── KSCpc-EUC-V.bcmap │ │ │ ├── Katakana.bcmap │ │ │ ├── LICENSE │ │ │ ├── NWP-H.bcmap │ │ │ ├── NWP-V.bcmap │ │ │ ├── RKSJ-H.bcmap │ │ │ ├── RKSJ-V.bcmap │ │ │ ├── Roman.bcmap │ │ │ ├── UniCNS-UCS2-H.bcmap │ │ │ ├── UniCNS-UCS2-V.bcmap │ │ │ ├── UniCNS-UTF16-H.bcmap │ │ │ ├── UniCNS-UTF16-V.bcmap │ │ │ ├── UniCNS-UTF32-H.bcmap │ │ │ ├── UniCNS-UTF32-V.bcmap │ │ │ ├── UniCNS-UTF8-H.bcmap │ │ │ ├── UniCNS-UTF8-V.bcmap │ │ │ ├── UniGB-UCS2-H.bcmap │ │ │ ├── UniGB-UCS2-V.bcmap │ │ │ ├── UniGB-UTF16-H.bcmap │ │ │ ├── UniGB-UTF16-V.bcmap │ │ │ ├── UniGB-UTF32-H.bcmap │ │ │ ├── UniGB-UTF32-V.bcmap │ │ │ ├── UniGB-UTF8-H.bcmap │ │ │ ├── UniGB-UTF8-V.bcmap │ │ │ ├── UniJIS-UCS2-H.bcmap │ │ │ ├── UniJIS-UCS2-HW-H.bcmap │ │ │ ├── UniJIS-UCS2-HW-V.bcmap │ │ │ ├── UniJIS-UCS2-V.bcmap │ │ │ ├── UniJIS-UTF16-H.bcmap │ │ │ ├── UniJIS-UTF16-V.bcmap │ │ │ ├── UniJIS-UTF32-H.bcmap │ │ │ ├── UniJIS-UTF32-V.bcmap │ │ │ ├── UniJIS-UTF8-H.bcmap │ │ │ ├── UniJIS-UTF8-V.bcmap │ │ │ ├── UniJIS2004-UTF16-H.bcmap │ │ │ ├── UniJIS2004-UTF16-V.bcmap │ │ │ ├── UniJIS2004-UTF32-H.bcmap │ │ │ ├── UniJIS2004-UTF32-V.bcmap │ │ │ ├── UniJIS2004-UTF8-H.bcmap │ │ │ ├── UniJIS2004-UTF8-V.bcmap │ │ │ ├── UniJISPro-UCS2-HW-V.bcmap │ │ │ ├── UniJISPro-UCS2-V.bcmap │ │ │ ├── UniJISPro-UTF8-V.bcmap │ │ │ ├── UniJISX0213-UTF32-H.bcmap │ │ │ ├── UniJISX0213-UTF32-V.bcmap │ │ │ ├── UniJISX02132004-UTF32-H.bcmap │ │ │ ├── UniJISX02132004-UTF32-V.bcmap │ │ │ ├── UniKS-UCS2-H.bcmap │ │ │ ├── UniKS-UCS2-V.bcmap │ │ │ ├── UniKS-UTF16-H.bcmap │ │ │ ├── UniKS-UTF16-V.bcmap │ │ │ ├── UniKS-UTF32-H.bcmap │ │ │ ├── UniKS-UTF32-V.bcmap │ │ │ ├── UniKS-UTF8-H.bcmap │ │ │ ├── UniKS-UTF8-V.bcmap │ │ │ ├── V.bcmap │ │ │ └── WP-Symbol.bcmap │ │ ├── debugger.js │ │ ├── images/ │ │ │ ├── grab.cur │ │ │ └── grabbing.cur │ │ ├── locale/ │ │ │ ├── ach/ │ │ │ │ └── viewer.properties │ │ │ ├── af/ │ │ │ │ └── viewer.properties │ │ │ ├── an/ │ │ │ │ └── viewer.properties │ │ │ ├── ar/ │ │ │ │ └── viewer.properties │ │ │ ├── ast/ │ │ │ │ └── viewer.properties │ │ │ ├── az/ │ │ │ │ └── viewer.properties │ │ │ ├── be/ │ │ │ │ └── viewer.properties │ │ │ ├── bg/ │ │ │ │ └── viewer.properties │ │ │ ├── bn/ │ │ │ │ └── viewer.properties │ │ │ ├── bo/ │ │ │ │ └── viewer.properties │ │ │ ├── br/ │ │ │ │ └── viewer.properties │ │ │ ├── brx/ │ │ │ │ └── viewer.properties │ │ │ ├── bs/ │ │ │ │ └── viewer.properties │ │ │ ├── ca/ │ │ │ │ └── viewer.properties │ │ │ ├── cak/ │ │ │ │ └── viewer.properties │ │ │ ├── ckb/ │ │ │ │ └── viewer.properties │ │ │ ├── cs/ │ │ │ │ └── viewer.properties │ │ │ ├── cy/ │ │ │ │ └── viewer.properties │ │ │ ├── da/ │ │ │ │ └── viewer.properties │ │ │ ├── de/ │ │ │ │ └── viewer.properties │ │ │ ├── dsb/ │ │ │ │ └── viewer.properties │ │ │ ├── el/ │ │ │ │ └── viewer.properties │ │ │ ├── en-CA/ │ │ │ │ └── viewer.properties │ │ │ ├── en-GB/ │ │ │ │ └── viewer.properties │ │ │ ├── en-US/ │ │ │ │ └── viewer.properties │ │ │ ├── eo/ │ │ │ │ └── viewer.properties │ │ │ ├── es-AR/ │ │ │ │ └── viewer.properties │ │ │ ├── es-CL/ │ │ │ │ └── viewer.properties │ │ │ ├── es-ES/ │ │ │ │ └── viewer.properties │ │ │ ├── es-MX/ │ │ │ │ └── viewer.properties │ │ │ ├── et/ │ │ │ │ └── viewer.properties │ │ │ ├── eu/ │ │ │ │ └── viewer.properties │ │ │ ├── fa/ │ │ │ │ └── viewer.properties │ │ │ ├── ff/ │ │ │ │ └── viewer.properties │ │ │ ├── fi/ │ │ │ │ └── viewer.properties │ │ │ ├── fr/ │ │ │ │ └── viewer.properties │ │ │ ├── fy-NL/ │ │ │ │ └── viewer.properties │ │ │ ├── ga-IE/ │ │ │ │ └── viewer.properties │ │ │ ├── gd/ │ │ │ │ └── viewer.properties │ │ │ ├── gl/ │ │ │ │ └── viewer.properties │ │ │ ├── gn/ │ │ │ │ └── viewer.properties │ │ │ ├── gu-IN/ │ │ │ │ └── viewer.properties │ │ │ ├── he/ │ │ │ │ └── viewer.properties │ │ │ ├── hi-IN/ │ │ │ │ └── viewer.properties │ │ │ ├── hr/ │ │ │ │ └── viewer.properties │ │ │ ├── hsb/ │ │ │ │ └── viewer.properties │ │ │ ├── hu/ │ │ │ │ └── viewer.properties │ │ │ ├── hy-AM/ │ │ │ │ └── viewer.properties │ │ │ ├── hye/ │ │ │ │ └── viewer.properties │ │ │ ├── ia/ │ │ │ │ └── viewer.properties │ │ │ ├── id/ │ │ │ │ └── viewer.properties │ │ │ ├── is/ │ │ │ │ └── viewer.properties │ │ │ ├── it/ │ │ │ │ └── viewer.properties │ │ │ ├── ja/ │ │ │ │ └── viewer.properties │ │ │ ├── ka/ │ │ │ │ └── viewer.properties │ │ │ ├── kab/ │ │ │ │ └── viewer.properties │ │ │ ├── kk/ │ │ │ │ └── viewer.properties │ │ │ ├── km/ │ │ │ │ └── viewer.properties │ │ │ ├── kn/ │ │ │ │ └── viewer.properties │ │ │ ├── ko/ │ │ │ │ └── viewer.properties │ │ │ ├── lij/ │ │ │ │ └── viewer.properties │ │ │ ├── lo/ │ │ │ │ └── viewer.properties │ │ │ ├── locale.properties │ │ │ ├── lt/ │ │ │ │ └── viewer.properties │ │ │ ├── ltg/ │ │ │ │ └── viewer.properties │ │ │ ├── lv/ │ │ │ │ └── viewer.properties │ │ │ ├── meh/ │ │ │ │ └── viewer.properties │ │ │ ├── mk/ │ │ │ │ └── viewer.properties │ │ │ ├── mr/ │ │ │ │ └── viewer.properties │ │ │ ├── ms/ │ │ │ │ └── viewer.properties │ │ │ ├── my/ │ │ │ │ └── viewer.properties │ │ │ ├── nb-NO/ │ │ │ │ └── viewer.properties │ │ │ ├── ne-NP/ │ │ │ │ └── viewer.properties │ │ │ ├── nl/ │ │ │ │ └── viewer.properties │ │ │ ├── nn-NO/ │ │ │ │ └── viewer.properties │ │ │ ├── oc/ │ │ │ │ └── viewer.properties │ │ │ ├── pa-IN/ │ │ │ │ └── viewer.properties │ │ │ ├── pl/ │ │ │ │ └── viewer.properties │ │ │ ├── pt-BR/ │ │ │ │ └── viewer.properties │ │ │ ├── pt-PT/ │ │ │ │ └── viewer.properties │ │ │ ├── rm/ │ │ │ │ └── viewer.properties │ │ │ ├── ro/ │ │ │ │ └── viewer.properties │ │ │ ├── ru/ │ │ │ │ └── viewer.properties │ │ │ ├── scn/ │ │ │ │ └── viewer.properties │ │ │ ├── si/ │ │ │ │ └── viewer.properties │ │ │ ├── sk/ │ │ │ │ └── viewer.properties │ │ │ ├── sl/ │ │ │ │ └── viewer.properties │ │ │ ├── son/ │ │ │ │ └── viewer.properties │ │ │ ├── sq/ │ │ │ │ └── viewer.properties │ │ │ ├── sr/ │ │ │ │ └── viewer.properties │ │ │ ├── sv-SE/ │ │ │ │ └── viewer.properties │ │ │ ├── szl/ │ │ │ │ └── viewer.properties │ │ │ ├── ta/ │ │ │ │ └── viewer.properties │ │ │ ├── te/ │ │ │ │ └── viewer.properties │ │ │ ├── th/ │ │ │ │ └── viewer.properties │ │ │ ├── tl/ │ │ │ │ └── viewer.properties │ │ │ ├── tr/ │ │ │ │ └── viewer.properties │ │ │ ├── trs/ │ │ │ │ └── viewer.properties │ │ │ ├── uk/ │ │ │ │ └── viewer.properties │ │ │ ├── ur/ │ │ │ │ └── viewer.properties │ │ │ ├── uz/ │ │ │ │ └── viewer.properties │ │ │ ├── vi/ │ │ │ │ └── viewer.properties │ │ │ ├── wo/ │ │ │ │ └── viewer.properties │ │ │ ├── xh/ │ │ │ │ └── viewer.properties │ │ │ ├── zh-CN/ │ │ │ │ └── viewer.properties │ │ │ └── zh-TW/ │ │ │ └── viewer.properties │ │ ├── viewer.css │ │ ├── viewer.html │ │ └── viewer.js │ └── tracky-mouse/ │ ├── .gitattributes │ ├── .gitignore │ ├── .gitrepo │ ├── .vscode/ │ │ ├── extensions.json │ │ ├── launch.json │ │ └── settings.json │ ├── API.md │ ├── CHANGELOG.md │ ├── CLI.md │ ├── LICENSE.txt │ ├── README.md │ ├── core/ │ │ ├── README.md │ │ ├── facemesh.worker.js │ │ ├── lib/ │ │ │ ├── clmtrackr.js │ │ │ ├── facemesh/ │ │ │ │ ├── blazeface/ │ │ │ │ │ └── model.json │ │ │ │ ├── facemesh/ │ │ │ │ │ └── model.json │ │ │ │ └── facemesh.js │ │ │ ├── jsfeat-min.js │ │ │ ├── no-eval.js │ │ │ ├── stats.js │ │ │ └── tf.js │ │ ├── package.json │ │ ├── tracky-mouse.css │ │ └── tracky-mouse.js │ ├── cspell.json │ ├── desktop-app/ │ │ ├── forge.config.js │ │ ├── images/ │ │ │ └── tracky-mouse-logo.icns │ │ ├── package.json │ │ └── src/ │ │ ├── electron-app.html │ │ ├── electron-main/ │ │ │ ├── cli.js │ │ │ ├── electron-main.js │ │ │ ├── menus.js │ │ │ ├── spawner.js │ │ │ ├── squirrel-update.js │ │ │ ├── version.js │ │ │ └── win-powershell.js │ │ ├── electron-screen-overlay.html │ │ ├── preload-app-window.js │ │ ├── preload-screen-overlay.js │ │ ├── screen-overlay.css │ │ ├── screen-overlay.js │ │ └── tracky-mouse-bin.js │ ├── eslint.config.js │ ├── images/ │ │ ├── tracky-mouse-logo.blend │ │ └── tracky-mouse-logo.icns │ ├── package.json │ └── website/ │ ├── CNAME │ ├── demo.js │ ├── eval-is-evil.html │ ├── index.html │ ├── package.json │ └── tracky-mouse-homepage.css ├── localization/ │ ├── ar/ │ │ ├── Dialog/ │ │ │ └── 0401/ │ │ │ ├── 105.rc │ │ │ ├── 108.rc │ │ │ ├── 112.rc │ │ │ ├── 113.rc │ │ │ ├── 132.rc │ │ │ ├── 30721.rc │ │ │ ├── 30722.rc │ │ │ ├── 30723.rc │ │ │ ├── 37.rc │ │ │ └── 4001.rc │ │ ├── Menu/ │ │ │ └── 0401/ │ │ │ ├── 113.rc │ │ │ ├── 118.rc │ │ │ ├── 119.rc │ │ │ ├── 2.rc │ │ │ ├── 4.rc │ │ │ └── 5.rc │ │ ├── String Table/ │ │ │ └── 0401/ │ │ │ ├── 1.rc │ │ │ ├── 129.rc │ │ │ ├── 130.rc │ │ │ ├── 131.rc │ │ │ ├── 132.rc │ │ │ ├── 135.rc │ │ │ ├── 139.rc │ │ │ ├── 141.rc │ │ │ ├── 144.rc │ │ │ ├── 145.rc │ │ │ ├── 153.rc │ │ │ ├── 2.rc │ │ │ ├── 2049.rc │ │ │ ├── 2050.rc │ │ │ ├── 222.rc │ │ │ ├── 2354.rc │ │ │ ├── 2355.rc │ │ │ ├── 2356.rc │ │ │ ├── 2610.rc │ │ │ ├── 2628.rc │ │ │ ├── 2753.rc │ │ │ ├── 2757.rc │ │ │ ├── 2758.rc │ │ │ ├── 2765.rc │ │ │ ├── 2794.rc │ │ │ ├── 3.rc │ │ │ ├── 3585.rc │ │ │ ├── 3601.rc │ │ │ ├── 3602.rc │ │ │ ├── 3603.rc │ │ │ ├── 3605.rc │ │ │ ├── 3606.rc │ │ │ ├── 3713.rc │ │ │ ├── 3714.rc │ │ │ ├── 3825.rc │ │ │ ├── 3826.rc │ │ │ ├── 3841.rc │ │ │ ├── 3842.rc │ │ │ ├── 3843.rc │ │ │ ├── 3845.rc │ │ │ ├── 3849.rc │ │ │ ├── 3850.rc │ │ │ ├── 3857.rc │ │ │ ├── 3858.rc │ │ │ ├── 3859.rc │ │ │ ├── 3865.rc │ │ │ ├── 3866.rc │ │ │ ├── 3867.rc │ │ │ ├── 3868.rc │ │ │ ├── 3869.rc │ │ │ ├── 39.rc │ │ │ ├── 40.rc │ │ │ ├── 41.rc │ │ │ ├── 430.rc │ │ │ ├── 442.rc │ │ │ ├── 578.rc │ │ │ ├── 626.rc │ │ │ ├── 63.rc │ │ │ └── 7.rc │ │ └── localizations.js │ ├── cs/ │ │ ├── Dialog/ │ │ │ └── 0405/ │ │ │ ├── 105.rc │ │ │ ├── 108.rc │ │ │ ├── 112.rc │ │ │ ├── 113.rc │ │ │ ├── 132.rc │ │ │ ├── 30721.rc │ │ │ ├── 30722.rc │ │ │ ├── 30723.rc │ │ │ ├── 37.rc │ │ │ └── 4001.rc │ │ ├── Menu/ │ │ │ └── 0405/ │ │ │ ├── 113.rc │ │ │ ├── 118.rc │ │ │ ├── 119.rc │ │ │ ├── 2.rc │ │ │ ├── 4.rc │ │ │ └── 5.rc │ │ ├── String Table/ │ │ │ └── 0405/ │ │ │ ├── 1.rc │ │ │ ├── 129.rc │ │ │ ├── 130.rc │ │ │ ├── 131.rc │ │ │ ├── 132.rc │ │ │ ├── 135.rc │ │ │ ├── 139.rc │ │ │ ├── 141.rc │ │ │ ├── 144.rc │ │ │ ├── 145.rc │ │ │ ├── 153.rc │ │ │ ├── 2.rc │ │ │ ├── 2049.rc │ │ │ ├── 2050.rc │ │ │ ├── 222.rc │ │ │ ├── 2354.rc │ │ │ ├── 2355.rc │ │ │ ├── 2356.rc │ │ │ ├── 2610.rc │ │ │ ├── 2628.rc │ │ │ ├── 2753.rc │ │ │ ├── 2757.rc │ │ │ ├── 2758.rc │ │ │ ├── 2765.rc │ │ │ ├── 2794.rc │ │ │ ├── 3.rc │ │ │ ├── 3585.rc │ │ │ ├── 3601.rc │ │ │ ├── 3602.rc │ │ │ ├── 3603.rc │ │ │ ├── 3605.rc │ │ │ ├── 3606.rc │ │ │ ├── 3713.rc │ │ │ ├── 3714.rc │ │ │ ├── 3825.rc │ │ │ ├── 3826.rc │ │ │ ├── 3841.rc │ │ │ ├── 3842.rc │ │ │ ├── 3843.rc │ │ │ ├── 3845.rc │ │ │ ├── 3849.rc │ │ │ ├── 3850.rc │ │ │ ├── 3857.rc │ │ │ ├── 3858.rc │ │ │ ├── 3859.rc │ │ │ ├── 3865.rc │ │ │ ├── 3866.rc │ │ │ ├── 3867.rc │ │ │ ├── 3868.rc │ │ │ ├── 3869.rc │ │ │ ├── 39.rc │ │ │ ├── 40.rc │ │ │ ├── 41.rc │ │ │ ├── 430.rc │ │ │ ├── 442.rc │ │ │ ├── 578.rc │ │ │ ├── 626.rc │ │ │ ├── 63.rc │ │ │ └── 7.rc │ │ └── localizations.js │ ├── da/ │ │ ├── Dialog/ │ │ │ └── 0406/ │ │ │ ├── 105.rc │ │ │ ├── 108.rc │ │ │ ├── 112.rc │ │ │ ├── 113.rc │ │ │ ├── 132.rc │ │ │ ├── 30721.rc │ │ │ ├── 30722.rc │ │ │ ├── 30723.rc │ │ │ ├── 37.rc │ │ │ └── 4001.rc │ │ ├── Menu/ │ │ │ └── 0406/ │ │ │ ├── 113.rc │ │ │ ├── 118.rc │ │ │ ├── 119.rc │ │ │ ├── 2.rc │ │ │ ├── 4.rc │ │ │ └── 5.rc │ │ ├── String Table/ │ │ │ └── 0406/ │ │ │ ├── 1.rc │ │ │ ├── 129.rc │ │ │ ├── 130.rc │ │ │ ├── 131.rc │ │ │ ├── 132.rc │ │ │ ├── 135.rc │ │ │ ├── 139.rc │ │ │ ├── 141.rc │ │ │ ├── 144.rc │ │ │ ├── 145.rc │ │ │ ├── 153.rc │ │ │ ├── 2.rc │ │ │ ├── 2049.rc │ │ │ ├── 2050.rc │ │ │ ├── 222.rc │ │ │ ├── 2354.rc │ │ │ ├── 2355.rc │ │ │ ├── 2356.rc │ │ │ ├── 2610.rc │ │ │ ├── 2628.rc │ │ │ ├── 2753.rc │ │ │ ├── 2757.rc │ │ │ ├── 2758.rc │ │ │ ├── 2765.rc │ │ │ ├── 2794.rc │ │ │ ├── 3.rc │ │ │ ├── 3585.rc │ │ │ ├── 3601.rc │ │ │ ├── 3602.rc │ │ │ ├── 3603.rc │ │ │ ├── 3605.rc │ │ │ ├── 3606.rc │ │ │ ├── 3713.rc │ │ │ ├── 3714.rc │ │ │ ├── 3825.rc │ │ │ ├── 3826.rc │ │ │ ├── 3841.rc │ │ │ ├── 3842.rc │ │ │ ├── 3843.rc │ │ │ ├── 3845.rc │ │ │ ├── 3849.rc │ │ │ ├── 3850.rc │ │ │ ├── 3857.rc │ │ │ ├── 3858.rc │ │ │ ├── 3859.rc │ │ │ ├── 3865.rc │ │ │ ├── 3866.rc │ │ │ ├── 3867.rc │ │ │ ├── 3868.rc │ │ │ ├── 3869.rc │ │ │ ├── 39.rc │ │ │ ├── 40.rc │ │ │ ├── 41.rc │ │ │ ├── 430.rc │ │ │ ├── 442.rc │ │ │ ├── 578.rc │ │ │ ├── 626.rc │ │ │ ├── 63.rc │ │ │ └── 7.rc │ │ └── localizations.js │ ├── de/ │ │ ├── Dialog/ │ │ │ └── 0407/ │ │ │ ├── 105.rc │ │ │ ├── 108.rc │ │ │ ├── 112.rc │ │ │ ├── 113.rc │ │ │ ├── 132.rc │ │ │ ├── 30721.rc │ │ │ ├── 30722.rc │ │ │ ├── 30723.rc │ │ │ ├── 37.rc │ │ │ └── 4001.rc │ │ ├── Menu/ │ │ │ └── 0407/ │ │ │ ├── 113.rc │ │ │ ├── 118.rc │ │ │ ├── 119.rc │ │ │ ├── 2.rc │ │ │ ├── 4.rc │ │ │ └── 5.rc │ │ ├── String Table/ │ │ │ └── 0407/ │ │ │ ├── 1.rc │ │ │ ├── 129.rc │ │ │ ├── 130.rc │ │ │ ├── 131.rc │ │ │ ├── 132.rc │ │ │ ├── 135.rc │ │ │ ├── 139.rc │ │ │ ├── 141.rc │ │ │ ├── 144.rc │ │ │ ├── 145.rc │ │ │ ├── 153.rc │ │ │ ├── 2.rc │ │ │ ├── 2049.rc │ │ │ ├── 2050.rc │ │ │ ├── 222.rc │ │ │ ├── 2354.rc │ │ │ ├── 2355.rc │ │ │ ├── 2356.rc │ │ │ ├── 2610.rc │ │ │ ├── 2628.rc │ │ │ ├── 2753.rc │ │ │ ├── 2757.rc │ │ │ ├── 2758.rc │ │ │ ├── 2765.rc │ │ │ ├── 2794.rc │ │ │ ├── 3.rc │ │ │ ├── 3585.rc │ │ │ ├── 3601.rc │ │ │ ├── 3602.rc │ │ │ ├── 3603.rc │ │ │ ├── 3605.rc │ │ │ ├── 3606.rc │ │ │ ├── 3713.rc │ │ │ ├── 3714.rc │ │ │ ├── 3825.rc │ │ │ ├── 3826.rc │ │ │ ├── 3841.rc │ │ │ ├── 3842.rc │ │ │ ├── 3843.rc │ │ │ ├── 3845.rc │ │ │ ├── 3849.rc │ │ │ ├── 3850.rc │ │ │ ├── 3857.rc │ │ │ ├── 3858.rc │ │ │ ├── 3859.rc │ │ │ ├── 3865.rc │ │ │ ├── 3866.rc │ │ │ ├── 3867.rc │ │ │ ├── 3868.rc │ │ │ ├── 3869.rc │ │ │ ├── 39.rc │ │ │ ├── 40.rc │ │ │ ├── 41.rc │ │ │ ├── 430.rc │ │ │ ├── 442.rc │ │ │ ├── 578.rc │ │ │ ├── 626.rc │ │ │ ├── 63.rc │ │ │ └── 7.rc │ │ └── localizations.js │ ├── el/ │ │ ├── Dialog/ │ │ │ └── 0408/ │ │ │ ├── 105.rc │ │ │ ├── 108.rc │ │ │ ├── 112.rc │ │ │ ├── 113.rc │ │ │ ├── 132.rc │ │ │ ├── 30721.rc │ │ │ ├── 30722.rc │ │ │ ├── 30723.rc │ │ │ ├── 37.rc │ │ │ └── 4001.rc │ │ ├── Menu/ │ │ │ └── 0408/ │ │ │ ├── 113.rc │ │ │ ├── 118.rc │ │ │ ├── 119.rc │ │ │ ├── 2.rc │ │ │ ├── 4.rc │ │ │ └── 5.rc │ │ ├── String Table/ │ │ │ └── 0408/ │ │ │ ├── 1.rc │ │ │ ├── 129.rc │ │ │ ├── 130.rc │ │ │ ├── 131.rc │ │ │ ├── 132.rc │ │ │ ├── 135.rc │ │ │ ├── 139.rc │ │ │ ├── 141.rc │ │ │ ├── 144.rc │ │ │ ├── 145.rc │ │ │ ├── 153.rc │ │ │ ├── 2.rc │ │ │ ├── 2049.rc │ │ │ ├── 2050.rc │ │ │ ├── 222.rc │ │ │ ├── 2354.rc │ │ │ ├── 2355.rc │ │ │ ├── 2356.rc │ │ │ ├── 2610.rc │ │ │ ├── 2628.rc │ │ │ ├── 2753.rc │ │ │ ├── 2757.rc │ │ │ ├── 2758.rc │ │ │ ├── 2765.rc │ │ │ ├── 2794.rc │ │ │ ├── 3.rc │ │ │ ├── 3585.rc │ │ │ ├── 3601.rc │ │ │ ├── 3602.rc │ │ │ ├── 3603.rc │ │ │ ├── 3605.rc │ │ │ ├── 3606.rc │ │ │ ├── 3713.rc │ │ │ ├── 3714.rc │ │ │ ├── 3825.rc │ │ │ ├── 3826.rc │ │ │ ├── 3841.rc │ │ │ ├── 3842.rc │ │ │ ├── 3843.rc │ │ │ ├── 3845.rc │ │ │ ├── 3849.rc │ │ │ ├── 3850.rc │ │ │ ├── 3857.rc │ │ │ ├── 3858.rc │ │ │ ├── 3859.rc │ │ │ ├── 3865.rc │ │ │ ├── 3866.rc │ │ │ ├── 3867.rc │ │ │ ├── 3868.rc │ │ │ ├── 3869.rc │ │ │ ├── 39.rc │ │ │ ├── 40.rc │ │ │ ├── 41.rc │ │ │ ├── 430.rc │ │ │ ├── 442.rc │ │ │ ├── 578.rc │ │ │ ├── 626.rc │ │ │ ├── 63.rc │ │ │ └── 7.rc │ │ └── localizations.js │ ├── en/ │ │ ├── Dialog/ │ │ │ └── 0409/ │ │ │ ├── 105.rc │ │ │ ├── 108.rc │ │ │ ├── 112.rc │ │ │ ├── 113.rc │ │ │ ├── 132.rc │ │ │ ├── 30721.rc │ │ │ ├── 30722.rc │ │ │ ├── 30723.rc │ │ │ ├── 37.rc │ │ │ └── 4001.rc │ │ ├── Menu/ │ │ │ └── 0409/ │ │ │ ├── 113.rc │ │ │ ├── 118.rc │ │ │ ├── 119.rc │ │ │ ├── 2.rc │ │ │ ├── 4.rc │ │ │ └── 5.rc │ │ └── String Table/ │ │ └── 0409/ │ │ ├── 1.rc │ │ ├── 129.rc │ │ ├── 130.rc │ │ ├── 131.rc │ │ ├── 132.rc │ │ ├── 135.rc │ │ ├── 139.rc │ │ ├── 141.rc │ │ ├── 144.rc │ │ ├── 145.rc │ │ ├── 153.rc │ │ ├── 2.rc │ │ ├── 2049.rc │ │ ├── 2050.rc │ │ ├── 222.rc │ │ ├── 2354.rc │ │ ├── 2355.rc │ │ ├── 2356.rc │ │ ├── 2610.rc │ │ ├── 2628.rc │ │ ├── 2753.rc │ │ ├── 2757.rc │ │ ├── 2758.rc │ │ ├── 2765.rc │ │ ├── 2794.rc │ │ ├── 3.rc │ │ ├── 3585.rc │ │ ├── 3601.rc │ │ ├── 3602.rc │ │ ├── 3603.rc │ │ ├── 3605.rc │ │ ├── 3606.rc │ │ ├── 3713.rc │ │ ├── 3714.rc │ │ ├── 3825.rc │ │ ├── 3826.rc │ │ ├── 3841.rc │ │ ├── 3842.rc │ │ ├── 3843.rc │ │ ├── 3845.rc │ │ ├── 3849.rc │ │ ├── 3850.rc │ │ ├── 3857.rc │ │ ├── 3858.rc │ │ ├── 3859.rc │ │ ├── 3865.rc │ │ ├── 3866.rc │ │ ├── 3867.rc │ │ ├── 3868.rc │ │ ├── 3869.rc │ │ ├── 39.rc │ │ ├── 40.rc │ │ ├── 41.rc │ │ ├── 430.rc │ │ ├── 442.rc │ │ ├── 578.rc │ │ ├── 626.rc │ │ ├── 63.rc │ │ └── 7.rc │ ├── es/ │ │ ├── Dialog/ │ │ │ └── 0C0A/ │ │ │ ├── 105.rc │ │ │ ├── 108.rc │ │ │ ├── 112.rc │ │ │ ├── 113.rc │ │ │ ├── 132.rc │ │ │ ├── 30721.rc │ │ │ ├── 30722.rc │ │ │ ├── 30723.rc │ │ │ ├── 37.rc │ │ │ └── 4001.rc │ │ ├── Menu/ │ │ │ └── 0C0A/ │ │ │ ├── 113.rc │ │ │ ├── 118.rc │ │ │ ├── 119.rc │ │ │ ├── 2.rc │ │ │ ├── 4.rc │ │ │ └── 5.rc │ │ ├── String Table/ │ │ │ └── 0C0A/ │ │ │ ├── 1.rc │ │ │ ├── 129.rc │ │ │ ├── 130.rc │ │ │ ├── 131.rc │ │ │ ├── 132.rc │ │ │ ├── 135.rc │ │ │ ├── 139.rc │ │ │ ├── 141.rc │ │ │ ├── 144.rc │ │ │ ├── 145.rc │ │ │ ├── 153.rc │ │ │ ├── 2.rc │ │ │ ├── 2049.rc │ │ │ ├── 2050.rc │ │ │ ├── 222.rc │ │ │ ├── 2354.rc │ │ │ ├── 2355.rc │ │ │ ├── 2356.rc │ │ │ ├── 2610.rc │ │ │ ├── 2628.rc │ │ │ ├── 2753.rc │ │ │ ├── 2757.rc │ │ │ ├── 2758.rc │ │ │ ├── 2765.rc │ │ │ ├── 2794.rc │ │ │ ├── 3.rc │ │ │ ├── 3585.rc │ │ │ ├── 3601.rc │ │ │ ├── 3602.rc │ │ │ ├── 3603.rc │ │ │ ├── 3605.rc │ │ │ ├── 3606.rc │ │ │ ├── 3713.rc │ │ │ ├── 3714.rc │ │ │ ├── 3825.rc │ │ │ ├── 3826.rc │ │ │ ├── 3841.rc │ │ │ ├── 3842.rc │ │ │ ├── 3843.rc │ │ │ ├── 3845.rc │ │ │ ├── 3849.rc │ │ │ ├── 3850.rc │ │ │ ├── 3857.rc │ │ │ ├── 3858.rc │ │ │ ├── 3859.rc │ │ │ ├── 3865.rc │ │ │ ├── 3866.rc │ │ │ ├── 3867.rc │ │ │ ├── 3868.rc │ │ │ ├── 3869.rc │ │ │ ├── 39.rc │ │ │ ├── 40.rc │ │ │ ├── 41.rc │ │ │ ├── 430.rc │ │ │ ├── 442.rc │ │ │ ├── 578.rc │ │ │ ├── 626.rc │ │ │ ├── 63.rc │ │ │ └── 7.rc │ │ └── localizations.js │ ├── fi/ │ │ ├── Dialog/ │ │ │ └── 040B/ │ │ │ ├── 105.rc │ │ │ ├── 108.rc │ │ │ ├── 112.rc │ │ │ ├── 113.rc │ │ │ ├── 132.rc │ │ │ ├── 30721.rc │ │ │ ├── 30722.rc │ │ │ ├── 30723.rc │ │ │ ├── 37.rc │ │ │ └── 4001.rc │ │ ├── Menu/ │ │ │ └── 040B/ │ │ │ ├── 113.rc │ │ │ ├── 118.rc │ │ │ ├── 119.rc │ │ │ ├── 2.rc │ │ │ ├── 4.rc │ │ │ └── 5.rc │ │ ├── String Table/ │ │ │ └── 040B/ │ │ │ ├── 1.rc │ │ │ ├── 129.rc │ │ │ ├── 130.rc │ │ │ ├── 131.rc │ │ │ ├── 132.rc │ │ │ ├── 135.rc │ │ │ ├── 139.rc │ │ │ ├── 141.rc │ │ │ ├── 144.rc │ │ │ ├── 145.rc │ │ │ ├── 153.rc │ │ │ ├── 2.rc │ │ │ ├── 2049.rc │ │ │ ├── 2050.rc │ │ │ ├── 222.rc │ │ │ ├── 2354.rc │ │ │ ├── 2355.rc │ │ │ ├── 2356.rc │ │ │ ├── 2610.rc │ │ │ ├── 2628.rc │ │ │ ├── 2753.rc │ │ │ ├── 2757.rc │ │ │ ├── 2758.rc │ │ │ ├── 2765.rc │ │ │ ├── 2794.rc │ │ │ ├── 3.rc │ │ │ ├── 3585.rc │ │ │ ├── 3601.rc │ │ │ ├── 3602.rc │ │ │ ├── 3603.rc │ │ │ ├── 3605.rc │ │ │ ├── 3606.rc │ │ │ ├── 3713.rc │ │ │ ├── 3714.rc │ │ │ ├── 3825.rc │ │ │ ├── 3826.rc │ │ │ ├── 3841.rc │ │ │ ├── 3842.rc │ │ │ ├── 3843.rc │ │ │ ├── 3845.rc │ │ │ ├── 3849.rc │ │ │ ├── 3850.rc │ │ │ ├── 3857.rc │ │ │ ├── 3858.rc │ │ │ ├── 3859.rc │ │ │ ├── 3865.rc │ │ │ ├── 3866.rc │ │ │ ├── 3867.rc │ │ │ ├── 3868.rc │ │ │ ├── 3869.rc │ │ │ ├── 39.rc │ │ │ ├── 40.rc │ │ │ ├── 41.rc │ │ │ ├── 430.rc │ │ │ ├── 442.rc │ │ │ ├── 578.rc │ │ │ ├── 626.rc │ │ │ ├── 63.rc │ │ │ └── 7.rc │ │ └── localizations.js │ ├── fr/ │ │ ├── Dialog/ │ │ │ └── 040C/ │ │ │ ├── 105.rc │ │ │ ├── 108.rc │ │ │ ├── 112.rc │ │ │ ├── 113.rc │ │ │ ├── 132.rc │ │ │ ├── 30721.rc │ │ │ ├── 30722.rc │ │ │ ├── 30723.rc │ │ │ ├── 37.rc │ │ │ └── 4001.rc │ │ ├── Menu/ │ │ │ └── 040C/ │ │ │ ├── 113.rc │ │ │ ├── 118.rc │ │ │ ├── 119.rc │ │ │ ├── 2.rc │ │ │ ├── 4.rc │ │ │ └── 5.rc │ │ ├── String Table/ │ │ │ └── 040C/ │ │ │ ├── 1.rc │ │ │ ├── 129.rc │ │ │ ├── 130.rc │ │ │ ├── 131.rc │ │ │ ├── 132.rc │ │ │ ├── 135.rc │ │ │ ├── 139.rc │ │ │ ├── 141.rc │ │ │ ├── 144.rc │ │ │ ├── 145.rc │ │ │ ├── 153.rc │ │ │ ├── 2.rc │ │ │ ├── 2049.rc │ │ │ ├── 2050.rc │ │ │ ├── 222.rc │ │ │ ├── 2354.rc │ │ │ ├── 2355.rc │ │ │ ├── 2356.rc │ │ │ ├── 2610.rc │ │ │ ├── 2628.rc │ │ │ ├── 2753.rc │ │ │ ├── 2757.rc │ │ │ ├── 2758.rc │ │ │ ├── 2765.rc │ │ │ ├── 2794.rc │ │ │ ├── 3.rc │ │ │ ├── 3585.rc │ │ │ ├── 3601.rc │ │ │ ├── 3602.rc │ │ │ ├── 3603.rc │ │ │ ├── 3605.rc │ │ │ ├── 3606.rc │ │ │ ├── 3713.rc │ │ │ ├── 3714.rc │ │ │ ├── 3825.rc │ │ │ ├── 3826.rc │ │ │ ├── 3841.rc │ │ │ ├── 3842.rc │ │ │ ├── 3843.rc │ │ │ ├── 3845.rc │ │ │ ├── 3849.rc │ │ │ ├── 3850.rc │ │ │ ├── 3857.rc │ │ │ ├── 3858.rc │ │ │ ├── 3859.rc │ │ │ ├── 3865.rc │ │ │ ├── 3866.rc │ │ │ ├── 3867.rc │ │ │ ├── 3868.rc │ │ │ ├── 3869.rc │ │ │ ├── 39.rc │ │ │ ├── 40.rc │ │ │ ├── 41.rc │ │ │ ├── 430.rc │ │ │ ├── 442.rc │ │ │ ├── 578.rc │ │ │ ├── 626.rc │ │ │ ├── 63.rc │ │ │ └── 7.rc │ │ └── localizations.js │ ├── grab-files-from-vm.sh │ ├── he/ │ │ ├── Dialog/ │ │ │ └── 040D/ │ │ │ ├── 105.rc │ │ │ ├── 108.rc │ │ │ ├── 112.rc │ │ │ ├── 113.rc │ │ │ ├── 132.rc │ │ │ ├── 30721.rc │ │ │ ├── 30722.rc │ │ │ ├── 30723.rc │ │ │ ├── 37.rc │ │ │ └── 4001.rc │ │ ├── Menu/ │ │ │ └── 040D/ │ │ │ ├── 113.rc │ │ │ ├── 118.rc │ │ │ ├── 119.rc │ │ │ ├── 2.rc │ │ │ ├── 4.rc │ │ │ └── 5.rc │ │ ├── String Table/ │ │ │ └── 040D/ │ │ │ ├── 1.rc │ │ │ ├── 129.rc │ │ │ ├── 130.rc │ │ │ ├── 131.rc │ │ │ ├── 132.rc │ │ │ ├── 135.rc │ │ │ ├── 139.rc │ │ │ ├── 141.rc │ │ │ ├── 144.rc │ │ │ ├── 145.rc │ │ │ ├── 153.rc │ │ │ ├── 2.rc │ │ │ ├── 2049.rc │ │ │ ├── 2050.rc │ │ │ ├── 222.rc │ │ │ ├── 2354.rc │ │ │ ├── 2355.rc │ │ │ ├── 2356.rc │ │ │ ├── 2610.rc │ │ │ ├── 2628.rc │ │ │ ├── 2753.rc │ │ │ ├── 2757.rc │ │ │ ├── 2758.rc │ │ │ ├── 2765.rc │ │ │ ├── 2794.rc │ │ │ ├── 3.rc │ │ │ ├── 3585.rc │ │ │ ├── 3601.rc │ │ │ ├── 3602.rc │ │ │ ├── 3603.rc │ │ │ ├── 3605.rc │ │ │ ├── 3606.rc │ │ │ ├── 3713.rc │ │ │ ├── 3714.rc │ │ │ ├── 3825.rc │ │ │ ├── 3826.rc │ │ │ ├── 3841.rc │ │ │ ├── 3842.rc │ │ │ ├── 3843.rc │ │ │ ├── 3845.rc │ │ │ ├── 3849.rc │ │ │ ├── 3850.rc │ │ │ ├── 3857.rc │ │ │ ├── 3858.rc │ │ │ ├── 3859.rc │ │ │ ├── 3865.rc │ │ │ ├── 3866.rc │ │ │ ├── 3867.rc │ │ │ ├── 3868.rc │ │ │ ├── 3869.rc │ │ │ ├── 39.rc │ │ │ ├── 40.rc │ │ │ ├── 41.rc │ │ │ ├── 430.rc │ │ │ ├── 442.rc │ │ │ ├── 578.rc │ │ │ ├── 626.rc │ │ │ ├── 63.rc │ │ │ └── 7.rc │ │ └── localizations.js │ ├── hu/ │ │ ├── Dialog/ │ │ │ └── 040E/ │ │ │ ├── 105.rc │ │ │ ├── 108.rc │ │ │ ├── 112.rc │ │ │ ├── 113.rc │ │ │ ├── 132.rc │ │ │ ├── 30721.rc │ │ │ ├── 30722.rc │ │ │ ├── 30723.rc │ │ │ ├── 37.rc │ │ │ └── 4001.rc │ │ ├── Menu/ │ │ │ └── 040E/ │ │ │ ├── 113.rc │ │ │ ├── 118.rc │ │ │ ├── 119.rc │ │ │ ├── 2.rc │ │ │ ├── 4.rc │ │ │ └── 5.rc │ │ ├── String Table/ │ │ │ └── 040E/ │ │ │ ├── 1.rc │ │ │ ├── 129.rc │ │ │ ├── 130.rc │ │ │ ├── 131.rc │ │ │ ├── 132.rc │ │ │ ├── 135.rc │ │ │ ├── 139.rc │ │ │ ├── 141.rc │ │ │ ├── 144.rc │ │ │ ├── 145.rc │ │ │ ├── 153.rc │ │ │ ├── 2.rc │ │ │ ├── 2049.rc │ │ │ ├── 2050.rc │ │ │ ├── 222.rc │ │ │ ├── 2354.rc │ │ │ ├── 2355.rc │ │ │ ├── 2356.rc │ │ │ ├── 2610.rc │ │ │ ├── 2628.rc │ │ │ ├── 2753.rc │ │ │ ├── 2757.rc │ │ │ ├── 2758.rc │ │ │ ├── 2765.rc │ │ │ ├── 2794.rc │ │ │ ├── 3.rc │ │ │ ├── 3585.rc │ │ │ ├── 3601.rc │ │ │ ├── 3602.rc │ │ │ ├── 3603.rc │ │ │ ├── 3605.rc │ │ │ ├── 3606.rc │ │ │ ├── 3713.rc │ │ │ ├── 3714.rc │ │ │ ├── 3825.rc │ │ │ ├── 3826.rc │ │ │ ├── 3841.rc │ │ │ ├── 3842.rc │ │ │ ├── 3843.rc │ │ │ ├── 3845.rc │ │ │ ├── 3849.rc │ │ │ ├── 3850.rc │ │ │ ├── 3857.rc │ │ │ ├── 3858.rc │ │ │ ├── 3859.rc │ │ │ ├── 3865.rc │ │ │ ├── 3866.rc │ │ │ ├── 3867.rc │ │ │ ├── 3868.rc │ │ │ ├── 3869.rc │ │ │ ├── 39.rc │ │ │ ├── 40.rc │ │ │ ├── 41.rc │ │ │ ├── 430.rc │ │ │ ├── 442.rc │ │ │ ├── 578.rc │ │ │ ├── 626.rc │ │ │ ├── 63.rc │ │ │ └── 7.rc │ │ └── localizations.js │ ├── install-windows-98.sh │ ├── it/ │ │ ├── Dialog/ │ │ │ └── 0410/ │ │ │ ├── 105.rc │ │ │ ├── 108.rc │ │ │ ├── 112.rc │ │ │ ├── 113.rc │ │ │ ├── 132.rc │ │ │ ├── 30721.rc │ │ │ ├── 30722.rc │ │ │ ├── 30723.rc │ │ │ ├── 37.rc │ │ │ └── 4001.rc │ │ ├── Menu/ │ │ │ └── 0410/ │ │ │ ├── 113.rc │ │ │ ├── 118.rc │ │ │ ├── 119.rc │ │ │ ├── 2.rc │ │ │ ├── 4.rc │ │ │ └── 5.rc │ │ ├── String Table/ │ │ │ └── 0410/ │ │ │ ├── 1.rc │ │ │ ├── 129.rc │ │ │ ├── 130.rc │ │ │ ├── 131.rc │ │ │ ├── 132.rc │ │ │ ├── 135.rc │ │ │ ├── 139.rc │ │ │ ├── 141.rc │ │ │ ├── 144.rc │ │ │ ├── 145.rc │ │ │ ├── 153.rc │ │ │ ├── 2.rc │ │ │ ├── 2049.rc │ │ │ ├── 2050.rc │ │ │ ├── 222.rc │ │ │ ├── 2354.rc │ │ │ ├── 2355.rc │ │ │ ├── 2356.rc │ │ │ ├── 2610.rc │ │ │ ├── 2628.rc │ │ │ ├── 2753.rc │ │ │ ├── 2757.rc │ │ │ ├── 2758.rc │ │ │ ├── 2765.rc │ │ │ ├── 2794.rc │ │ │ ├── 3.rc │ │ │ ├── 3585.rc │ │ │ ├── 3601.rc │ │ │ ├── 3602.rc │ │ │ ├── 3603.rc │ │ │ ├── 3605.rc │ │ │ ├── 3606.rc │ │ │ ├── 3713.rc │ │ │ ├── 3714.rc │ │ │ ├── 3825.rc │ │ │ ├── 3826.rc │ │ │ ├── 3841.rc │ │ │ ├── 3842.rc │ │ │ ├── 3843.rc │ │ │ ├── 3845.rc │ │ │ ├── 3849.rc │ │ │ ├── 3850.rc │ │ │ ├── 3857.rc │ │ │ ├── 3858.rc │ │ │ ├── 3859.rc │ │ │ ├── 3865.rc │ │ │ ├── 3866.rc │ │ │ ├── 3867.rc │ │ │ ├── 3868.rc │ │ │ ├── 3869.rc │ │ │ ├── 39.rc │ │ │ ├── 40.rc │ │ │ ├── 41.rc │ │ │ ├── 430.rc │ │ │ ├── 442.rc │ │ │ ├── 578.rc │ │ │ ├── 626.rc │ │ │ ├── 63.rc │ │ │ └── 7.rc │ │ └── localizations.js │ ├── ja/ │ │ ├── Dialog/ │ │ │ └── 0411/ │ │ │ ├── 105.rc │ │ │ ├── 108.rc │ │ │ ├── 112.rc │ │ │ ├── 113.rc │ │ │ ├── 132.rc │ │ │ ├── 30721.rc │ │ │ ├── 30722.rc │ │ │ ├── 30723.rc │ │ │ ├── 37.rc │ │ │ └── 4001.rc │ │ ├── Menu/ │ │ │ └── 0411/ │ │ │ ├── 113.rc │ │ │ ├── 118.rc │ │ │ ├── 119.rc │ │ │ ├── 2.rc │ │ │ ├── 4.rc │ │ │ └── 5.rc │ │ ├── String Table/ │ │ │ └── 0411/ │ │ │ ├── 1.rc │ │ │ ├── 129.rc │ │ │ ├── 130.rc │ │ │ ├── 131.rc │ │ │ ├── 132.rc │ │ │ ├── 135.rc │ │ │ ├── 139.rc │ │ │ ├── 141.rc │ │ │ ├── 144.rc │ │ │ ├── 145.rc │ │ │ ├── 153.rc │ │ │ ├── 2.rc │ │ │ ├── 2049.rc │ │ │ ├── 2050.rc │ │ │ ├── 222.rc │ │ │ ├── 2354.rc │ │ │ ├── 2355.rc │ │ │ ├── 2356.rc │ │ │ ├── 2610.rc │ │ │ ├── 2628.rc │ │ │ ├── 2753.rc │ │ │ ├── 2757.rc │ │ │ ├── 2758.rc │ │ │ ├── 2765.rc │ │ │ ├── 2794.rc │ │ │ ├── 3.rc │ │ │ ├── 3585.rc │ │ │ ├── 3601.rc │ │ │ ├── 3602.rc │ │ │ ├── 3603.rc │ │ │ ├── 3605.rc │ │ │ ├── 3606.rc │ │ │ ├── 3713.rc │ │ │ ├── 3714.rc │ │ │ ├── 3825.rc │ │ │ ├── 3826.rc │ │ │ ├── 3841.rc │ │ │ ├── 3842.rc │ │ │ ├── 3843.rc │ │ │ ├── 3845.rc │ │ │ ├── 3849.rc │ │ │ ├── 3850.rc │ │ │ ├── 3857.rc │ │ │ ├── 3858.rc │ │ │ ├── 3859.rc │ │ │ ├── 3865.rc │ │ │ ├── 3866.rc │ │ │ ├── 3867.rc │ │ │ ├── 3868.rc │ │ │ ├── 3869.rc │ │ │ ├── 39.rc │ │ │ ├── 40.rc │ │ │ ├── 41.rc │ │ │ ├── 430.rc │ │ │ ├── 442.rc │ │ │ ├── 578.rc │ │ │ ├── 626.rc │ │ │ ├── 63.rc │ │ │ └── 7.rc │ │ └── localizations.js │ ├── ko/ │ │ ├── Dialog/ │ │ │ └── 0412/ │ │ │ ├── 105.rc │ │ │ ├── 108.rc │ │ │ ├── 112.rc │ │ │ ├── 113.rc │ │ │ ├── 132.rc │ │ │ ├── 30721.rc │ │ │ ├── 30722.rc │ │ │ ├── 30723.rc │ │ │ ├── 37.rc │ │ │ └── 4001.rc │ │ ├── Menu/ │ │ │ └── 0412/ │ │ │ ├── 113.rc │ │ │ ├── 118.rc │ │ │ ├── 119.rc │ │ │ ├── 2.rc │ │ │ ├── 4.rc │ │ │ └── 5.rc │ │ ├── String Table/ │ │ │ └── 0412/ │ │ │ ├── 1.rc │ │ │ ├── 129.rc │ │ │ ├── 130.rc │ │ │ ├── 131.rc │ │ │ ├── 132.rc │ │ │ ├── 135.rc │ │ │ ├── 139.rc │ │ │ ├── 141.rc │ │ │ ├── 144.rc │ │ │ ├── 145.rc │ │ │ ├── 153.rc │ │ │ ├── 2.rc │ │ │ ├── 2049.rc │ │ │ ├── 2050.rc │ │ │ ├── 222.rc │ │ │ ├── 2354.rc │ │ │ ├── 2355.rc │ │ │ ├── 2356.rc │ │ │ ├── 2610.rc │ │ │ ├── 2628.rc │ │ │ ├── 2753.rc │ │ │ ├── 2757.rc │ │ │ ├── 2758.rc │ │ │ ├── 2765.rc │ │ │ ├── 2794.rc │ │ │ ├── 3.rc │ │ │ ├── 3585.rc │ │ │ ├── 3601.rc │ │ │ ├── 3602.rc │ │ │ ├── 3603.rc │ │ │ ├── 3605.rc │ │ │ ├── 3606.rc │ │ │ ├── 3713.rc │ │ │ ├── 3714.rc │ │ │ ├── 3825.rc │ │ │ ├── 3826.rc │ │ │ ├── 3841.rc │ │ │ ├── 3842.rc │ │ │ ├── 3843.rc │ │ │ ├── 3845.rc │ │ │ ├── 3849.rc │ │ │ ├── 3850.rc │ │ │ ├── 3857.rc │ │ │ ├── 3858.rc │ │ │ ├── 3859.rc │ │ │ ├── 3865.rc │ │ │ ├── 3866.rc │ │ │ ├── 3867.rc │ │ │ ├── 3868.rc │ │ │ ├── 3869.rc │ │ │ ├── 39.rc │ │ │ ├── 40.rc │ │ │ ├── 41.rc │ │ │ ├── 430.rc │ │ │ ├── 442.rc │ │ │ ├── 578.rc │ │ │ ├── 626.rc │ │ │ ├── 63.rc │ │ │ └── 7.rc │ │ └── localizations.js │ ├── nl/ │ │ ├── Dialog/ │ │ │ └── 0413/ │ │ │ ├── 105.rc │ │ │ ├── 108.rc │ │ │ ├── 112.rc │ │ │ ├── 113.rc │ │ │ ├── 132.rc │ │ │ ├── 30721.rc │ │ │ ├── 30722.rc │ │ │ ├── 30723.rc │ │ │ ├── 37.rc │ │ │ └── 4001.rc │ │ ├── Menu/ │ │ │ └── 0413/ │ │ │ ├── 113.rc │ │ │ ├── 118.rc │ │ │ ├── 119.rc │ │ │ ├── 2.rc │ │ │ ├── 4.rc │ │ │ └── 5.rc │ │ ├── String Table/ │ │ │ └── 0413/ │ │ │ ├── 1.rc │ │ │ ├── 129.rc │ │ │ ├── 130.rc │ │ │ ├── 131.rc │ │ │ ├── 132.rc │ │ │ ├── 135.rc │ │ │ ├── 139.rc │ │ │ ├── 141.rc │ │ │ ├── 144.rc │ │ │ ├── 145.rc │ │ │ ├── 153.rc │ │ │ ├── 2.rc │ │ │ ├── 2049.rc │ │ │ ├── 2050.rc │ │ │ ├── 222.rc │ │ │ ├── 2354.rc │ │ │ ├── 2355.rc │ │ │ ├── 2356.rc │ │ │ ├── 2610.rc │ │ │ ├── 2628.rc │ │ │ ├── 2753.rc │ │ │ ├── 2757.rc │ │ │ ├── 2758.rc │ │ │ ├── 2765.rc │ │ │ ├── 2794.rc │ │ │ ├── 3.rc │ │ │ ├── 3585.rc │ │ │ ├── 3601.rc │ │ │ ├── 3602.rc │ │ │ ├── 3603.rc │ │ │ ├── 3605.rc │ │ │ ├── 3606.rc │ │ │ ├── 3713.rc │ │ │ ├── 3714.rc │ │ │ ├── 3825.rc │ │ │ ├── 3826.rc │ │ │ ├── 3841.rc │ │ │ ├── 3842.rc │ │ │ ├── 3843.rc │ │ │ ├── 3845.rc │ │ │ ├── 3849.rc │ │ │ ├── 3850.rc │ │ │ ├── 3857.rc │ │ │ ├── 3858.rc │ │ │ ├── 3859.rc │ │ │ ├── 3865.rc │ │ │ ├── 3866.rc │ │ │ ├── 3867.rc │ │ │ ├── 3868.rc │ │ │ ├── 3869.rc │ │ │ ├── 39.rc │ │ │ ├── 40.rc │ │ │ ├── 41.rc │ │ │ ├── 430.rc │ │ │ ├── 442.rc │ │ │ ├── 578.rc │ │ │ ├── 626.rc │ │ │ ├── 63.rc │ │ │ └── 7.rc │ │ └── localizations.js │ ├── no/ │ │ ├── Dialog/ │ │ │ └── 0414/ │ │ │ ├── 105.rc │ │ │ ├── 108.rc │ │ │ ├── 112.rc │ │ │ ├── 113.rc │ │ │ ├── 132.rc │ │ │ ├── 30721.rc │ │ │ ├── 30722.rc │ │ │ ├── 30723.rc │ │ │ ├── 37.rc │ │ │ └── 4001.rc │ │ ├── Menu/ │ │ │ └── 0414/ │ │ │ ├── 113.rc │ │ │ ├── 118.rc │ │ │ ├── 119.rc │ │ │ ├── 2.rc │ │ │ ├── 4.rc │ │ │ └── 5.rc │ │ ├── String Table/ │ │ │ └── 0414/ │ │ │ ├── 1.rc │ │ │ ├── 129.rc │ │ │ ├── 130.rc │ │ │ ├── 131.rc │ │ │ ├── 132.rc │ │ │ ├── 135.rc │ │ │ ├── 139.rc │ │ │ ├── 141.rc │ │ │ ├── 144.rc │ │ │ ├── 145.rc │ │ │ ├── 153.rc │ │ │ ├── 2.rc │ │ │ ├── 2049.rc │ │ │ ├── 2050.rc │ │ │ ├── 222.rc │ │ │ ├── 2354.rc │ │ │ ├── 2355.rc │ │ │ ├── 2356.rc │ │ │ ├── 2610.rc │ │ │ ├── 2628.rc │ │ │ ├── 2753.rc │ │ │ ├── 2757.rc │ │ │ ├── 2758.rc │ │ │ ├── 2765.rc │ │ │ ├── 2794.rc │ │ │ ├── 3.rc │ │ │ ├── 3585.rc │ │ │ ├── 3601.rc │ │ │ ├── 3602.rc │ │ │ ├── 3603.rc │ │ │ ├── 3605.rc │ │ │ ├── 3606.rc │ │ │ ├── 3713.rc │ │ │ ├── 3714.rc │ │ │ ├── 3825.rc │ │ │ ├── 3826.rc │ │ │ ├── 3841.rc │ │ │ ├── 3842.rc │ │ │ ├── 3843.rc │ │ │ ├── 3845.rc │ │ │ ├── 3849.rc │ │ │ ├── 3850.rc │ │ │ ├── 3857.rc │ │ │ ├── 3858.rc │ │ │ ├── 3859.rc │ │ │ ├── 3865.rc │ │ │ ├── 3866.rc │ │ │ ├── 3867.rc │ │ │ ├── 3868.rc │ │ │ ├── 3869.rc │ │ │ ├── 39.rc │ │ │ ├── 40.rc │ │ │ ├── 41.rc │ │ │ ├── 430.rc │ │ │ ├── 442.rc │ │ │ ├── 578.rc │ │ │ ├── 626.rc │ │ │ ├── 63.rc │ │ │ └── 7.rc │ │ └── localizations.js │ ├── parse-rc-file.js │ ├── pl/ │ │ ├── Dialog/ │ │ │ └── 0415/ │ │ │ ├── 105.rc │ │ │ ├── 108.rc │ │ │ ├── 112.rc │ │ │ ├── 113.rc │ │ │ ├── 132.rc │ │ │ ├── 30721.rc │ │ │ ├── 30722.rc │ │ │ ├── 30723.rc │ │ │ ├── 37.rc │ │ │ └── 4001.rc │ │ ├── Menu/ │ │ │ └── 0415/ │ │ │ ├── 113.rc │ │ │ ├── 118.rc │ │ │ ├── 119.rc │ │ │ ├── 2.rc │ │ │ ├── 4.rc │ │ │ └── 5.rc │ │ ├── String Table/ │ │ │ └── 0415/ │ │ │ ├── 1.rc │ │ │ ├── 129.rc │ │ │ ├── 130.rc │ │ │ ├── 131.rc │ │ │ ├── 132.rc │ │ │ ├── 135.rc │ │ │ ├── 139.rc │ │ │ ├── 141.rc │ │ │ ├── 144.rc │ │ │ ├── 145.rc │ │ │ ├── 153.rc │ │ │ ├── 2.rc │ │ │ ├── 2049.rc │ │ │ ├── 2050.rc │ │ │ ├── 222.rc │ │ │ ├── 2354.rc │ │ │ ├── 2355.rc │ │ │ ├── 2356.rc │ │ │ ├── 2610.rc │ │ │ ├── 2628.rc │ │ │ ├── 2753.rc │ │ │ ├── 2757.rc │ │ │ ├── 2758.rc │ │ │ ├── 2765.rc │ │ │ ├── 2794.rc │ │ │ ├── 3.rc │ │ │ ├── 3585.rc │ │ │ ├── 3601.rc │ │ │ ├── 3602.rc │ │ │ ├── 3603.rc │ │ │ ├── 3605.rc │ │ │ ├── 3606.rc │ │ │ ├── 3713.rc │ │ │ ├── 3714.rc │ │ │ ├── 3825.rc │ │ │ ├── 3826.rc │ │ │ ├── 3841.rc │ │ │ ├── 3842.rc │ │ │ ├── 3843.rc │ │ │ ├── 3845.rc │ │ │ ├── 3849.rc │ │ │ ├── 3850.rc │ │ │ ├── 3857.rc │ │ │ ├── 3858.rc │ │ │ ├── 3859.rc │ │ │ ├── 3865.rc │ │ │ ├── 3866.rc │ │ │ ├── 3867.rc │ │ │ ├── 3868.rc │ │ │ ├── 3869.rc │ │ │ ├── 39.rc │ │ │ ├── 40.rc │ │ │ ├── 41.rc │ │ │ ├── 430.rc │ │ │ ├── 442.rc │ │ │ ├── 578.rc │ │ │ ├── 626.rc │ │ │ ├── 63.rc │ │ │ └── 7.rc │ │ └── localizations.js │ ├── preprocess.js │ ├── pt/ │ │ ├── Dialog/ │ │ │ └── 0816/ │ │ │ ├── 105.rc │ │ │ ├── 108.rc │ │ │ ├── 112.rc │ │ │ ├── 113.rc │ │ │ ├── 132.rc │ │ │ ├── 30721.rc │ │ │ ├── 30722.rc │ │ │ ├── 30723.rc │ │ │ ├── 37.rc │ │ │ └── 4001.rc │ │ ├── Menu/ │ │ │ └── 0816/ │ │ │ ├── 113.rc │ │ │ ├── 118.rc │ │ │ ├── 119.rc │ │ │ ├── 2.rc │ │ │ ├── 4.rc │ │ │ └── 5.rc │ │ ├── String Table/ │ │ │ └── 0816/ │ │ │ ├── 1.rc │ │ │ ├── 129.rc │ │ │ ├── 130.rc │ │ │ ├── 131.rc │ │ │ ├── 132.rc │ │ │ ├── 135.rc │ │ │ ├── 139.rc │ │ │ ├── 141.rc │ │ │ ├── 144.rc │ │ │ ├── 145.rc │ │ │ ├── 153.rc │ │ │ ├── 2.rc │ │ │ ├── 2049.rc │ │ │ ├── 2050.rc │ │ │ ├── 222.rc │ │ │ ├── 2354.rc │ │ │ ├── 2355.rc │ │ │ ├── 2356.rc │ │ │ ├── 2610.rc │ │ │ ├── 2628.rc │ │ │ ├── 2753.rc │ │ │ ├── 2757.rc │ │ │ ├── 2758.rc │ │ │ ├── 2765.rc │ │ │ ├── 2794.rc │ │ │ ├── 3.rc │ │ │ ├── 3585.rc │ │ │ ├── 3601.rc │ │ │ ├── 3602.rc │ │ │ ├── 3603.rc │ │ │ ├── 3605.rc │ │ │ ├── 3606.rc │ │ │ ├── 3713.rc │ │ │ ├── 3714.rc │ │ │ ├── 3825.rc │ │ │ ├── 3826.rc │ │ │ ├── 3841.rc │ │ │ ├── 3842.rc │ │ │ ├── 3843.rc │ │ │ ├── 3845.rc │ │ │ ├── 3849.rc │ │ │ ├── 3850.rc │ │ │ ├── 3857.rc │ │ │ ├── 3858.rc │ │ │ ├── 3859.rc │ │ │ ├── 3865.rc │ │ │ ├── 3866.rc │ │ │ ├── 3867.rc │ │ │ ├── 3868.rc │ │ │ ├── 3869.rc │ │ │ ├── 39.rc │ │ │ ├── 40.rc │ │ │ ├── 41.rc │ │ │ ├── 430.rc │ │ │ ├── 442.rc │ │ │ ├── 578.rc │ │ │ ├── 626.rc │ │ │ ├── 63.rc │ │ │ └── 7.rc │ │ └── localizations.js │ ├── pt-br/ │ │ ├── Dialog/ │ │ │ └── 0416/ │ │ │ ├── 105.rc │ │ │ ├── 108.rc │ │ │ ├── 112.rc │ │ │ ├── 113.rc │ │ │ ├── 132.rc │ │ │ ├── 30721.rc │ │ │ ├── 30722.rc │ │ │ ├── 30723.rc │ │ │ ├── 37.rc │ │ │ └── 4001.rc │ │ ├── Menu/ │ │ │ └── 0416/ │ │ │ ├── 113.rc │ │ │ ├── 118.rc │ │ │ ├── 119.rc │ │ │ ├── 2.rc │ │ │ ├── 4.rc │ │ │ └── 5.rc │ │ ├── String Table/ │ │ │ └── 0416/ │ │ │ ├── 1.rc │ │ │ ├── 129.rc │ │ │ ├── 130.rc │ │ │ ├── 131.rc │ │ │ ├── 132.rc │ │ │ ├── 135.rc │ │ │ ├── 139.rc │ │ │ ├── 141.rc │ │ │ ├── 144.rc │ │ │ ├── 145.rc │ │ │ ├── 153.rc │ │ │ ├── 2.rc │ │ │ ├── 2049.rc │ │ │ ├── 2050.rc │ │ │ ├── 222.rc │ │ │ ├── 2354.rc │ │ │ ├── 2355.rc │ │ │ ├── 2356.rc │ │ │ ├── 2610.rc │ │ │ ├── 2628.rc │ │ │ ├── 2753.rc │ │ │ ├── 2757.rc │ │ │ ├── 2758.rc │ │ │ ├── 2765.rc │ │ │ ├── 2794.rc │ │ │ ├── 3.rc │ │ │ ├── 3585.rc │ │ │ ├── 3601.rc │ │ │ ├── 3602.rc │ │ │ ├── 3603.rc │ │ │ ├── 3605.rc │ │ │ ├── 3606.rc │ │ │ ├── 3713.rc │ │ │ ├── 3714.rc │ │ │ ├── 3825.rc │ │ │ ├── 3826.rc │ │ │ ├── 3841.rc │ │ │ ├── 3842.rc │ │ │ ├── 3843.rc │ │ │ ├── 3845.rc │ │ │ ├── 3849.rc │ │ │ ├── 3850.rc │ │ │ ├── 3857.rc │ │ │ ├── 3858.rc │ │ │ ├── 3859.rc │ │ │ ├── 3865.rc │ │ │ ├── 3866.rc │ │ │ ├── 3867.rc │ │ │ ├── 3868.rc │ │ │ ├── 3869.rc │ │ │ ├── 39.rc │ │ │ ├── 40.rc │ │ │ ├── 41.rc │ │ │ ├── 430.rc │ │ │ ├── 442.rc │ │ │ ├── 578.rc │ │ │ ├── 626.rc │ │ │ ├── 63.rc │ │ │ └── 7.rc │ │ └── localizations.js │ ├── ru/ │ │ ├── Dialog/ │ │ │ └── 0419/ │ │ │ ├── 105.rc │ │ │ ├── 108.rc │ │ │ ├── 112.rc │ │ │ ├── 113.rc │ │ │ ├── 132.rc │ │ │ ├── 30721.rc │ │ │ ├── 30722.rc │ │ │ ├── 30723.rc │ │ │ ├── 37.rc │ │ │ └── 4001.rc │ │ ├── Menu/ │ │ │ └── 0419/ │ │ │ ├── 113.rc │ │ │ ├── 118.rc │ │ │ ├── 119.rc │ │ │ ├── 2.rc │ │ │ ├── 4.rc │ │ │ └── 5.rc │ │ ├── String Table/ │ │ │ └── 0419/ │ │ │ ├── 1.rc │ │ │ ├── 129.rc │ │ │ ├── 130.rc │ │ │ ├── 131.rc │ │ │ ├── 132.rc │ │ │ ├── 135.rc │ │ │ ├── 139.rc │ │ │ ├── 141.rc │ │ │ ├── 144.rc │ │ │ ├── 145.rc │ │ │ ├── 153.rc │ │ │ ├── 2.rc │ │ │ ├── 2049.rc │ │ │ ├── 2050.rc │ │ │ ├── 222.rc │ │ │ ├── 2354.rc │ │ │ ├── 2355.rc │ │ │ ├── 2356.rc │ │ │ ├── 2610.rc │ │ │ ├── 2628.rc │ │ │ ├── 2753.rc │ │ │ ├── 2757.rc │ │ │ ├── 2758.rc │ │ │ ├── 2765.rc │ │ │ ├── 2794.rc │ │ │ ├── 3.rc │ │ │ ├── 3585.rc │ │ │ ├── 3601.rc │ │ │ ├── 3602.rc │ │ │ ├── 3603.rc │ │ │ ├── 3605.rc │ │ │ ├── 3606.rc │ │ │ ├── 3713.rc │ │ │ ├── 3714.rc │ │ │ ├── 3825.rc │ │ │ ├── 3826.rc │ │ │ ├── 3841.rc │ │ │ ├── 3842.rc │ │ │ ├── 3843.rc │ │ │ ├── 3845.rc │ │ │ ├── 3849.rc │ │ │ ├── 3850.rc │ │ │ ├── 3857.rc │ │ │ ├── 3858.rc │ │ │ ├── 3859.rc │ │ │ ├── 3865.rc │ │ │ ├── 3866.rc │ │ │ ├── 3867.rc │ │ │ ├── 3868.rc │ │ │ ├── 3869.rc │ │ │ ├── 39.rc │ │ │ ├── 40.rc │ │ │ ├── 41.rc │ │ │ ├── 430.rc │ │ │ ├── 442.rc │ │ │ ├── 578.rc │ │ │ ├── 626.rc │ │ │ ├── 63.rc │ │ │ └── 7.rc │ │ └── localizations.js │ ├── sk/ │ │ ├── Dialog/ │ │ │ └── 041B/ │ │ │ ├── 105.rc │ │ │ ├── 108.rc │ │ │ ├── 112.rc │ │ │ ├── 113.rc │ │ │ ├── 132.rc │ │ │ ├── 30721.rc │ │ │ ├── 30722.rc │ │ │ ├── 30723.rc │ │ │ ├── 37.rc │ │ │ └── 4001.rc │ │ ├── Menu/ │ │ │ └── 041B/ │ │ │ ├── 113.rc │ │ │ ├── 118.rc │ │ │ ├── 119.rc │ │ │ ├── 2.rc │ │ │ ├── 4.rc │ │ │ └── 5.rc │ │ ├── String Table/ │ │ │ └── 041B/ │ │ │ ├── 1.rc │ │ │ ├── 129.rc │ │ │ ├── 130.rc │ │ │ ├── 131.rc │ │ │ ├── 132.rc │ │ │ ├── 135.rc │ │ │ ├── 139.rc │ │ │ ├── 141.rc │ │ │ ├── 144.rc │ │ │ ├── 145.rc │ │ │ ├── 153.rc │ │ │ ├── 2.rc │ │ │ ├── 2049.rc │ │ │ ├── 2050.rc │ │ │ ├── 222.rc │ │ │ ├── 2354.rc │ │ │ ├── 2355.rc │ │ │ ├── 2356.rc │ │ │ ├── 2610.rc │ │ │ ├── 2628.rc │ │ │ ├── 2753.rc │ │ │ ├── 2757.rc │ │ │ ├── 2758.rc │ │ │ ├── 2765.rc │ │ │ ├── 2794.rc │ │ │ ├── 3.rc │ │ │ ├── 3585.rc │ │ │ ├── 3601.rc │ │ │ ├── 3602.rc │ │ │ ├── 3603.rc │ │ │ ├── 3605.rc │ │ │ ├── 3606.rc │ │ │ ├── 3713.rc │ │ │ ├── 3714.rc │ │ │ ├── 3825.rc │ │ │ ├── 3826.rc │ │ │ ├── 3841.rc │ │ │ ├── 3842.rc │ │ │ ├── 3843.rc │ │ │ ├── 3845.rc │ │ │ ├── 3849.rc │ │ │ ├── 3850.rc │ │ │ ├── 3857.rc │ │ │ ├── 3858.rc │ │ │ ├── 3859.rc │ │ │ ├── 3865.rc │ │ │ ├── 3866.rc │ │ │ ├── 3867.rc │ │ │ ├── 3868.rc │ │ │ ├── 3869.rc │ │ │ ├── 39.rc │ │ │ ├── 40.rc │ │ │ ├── 41.rc │ │ │ ├── 430.rc │ │ │ ├── 442.rc │ │ │ ├── 578.rc │ │ │ ├── 626.rc │ │ │ ├── 63.rc │ │ │ └── 7.rc │ │ └── localizations.js │ ├── sl/ │ │ ├── Dialog/ │ │ │ └── 0424/ │ │ │ ├── 105.rc │ │ │ ├── 108.rc │ │ │ ├── 112.rc │ │ │ ├── 113.rc │ │ │ ├── 132.rc │ │ │ ├── 30721.rc │ │ │ ├── 30722.rc │ │ │ ├── 30723.rc │ │ │ ├── 37.rc │ │ │ └── 4001.rc │ │ ├── Menu/ │ │ │ └── 0424/ │ │ │ ├── 113.rc │ │ │ ├── 118.rc │ │ │ ├── 119.rc │ │ │ ├── 2.rc │ │ │ ├── 4.rc │ │ │ └── 5.rc │ │ ├── String Table/ │ │ │ └── 0424/ │ │ │ ├── 1.rc │ │ │ ├── 129.rc │ │ │ ├── 130.rc │ │ │ ├── 131.rc │ │ │ ├── 132.rc │ │ │ ├── 135.rc │ │ │ ├── 139.rc │ │ │ ├── 141.rc │ │ │ ├── 144.rc │ │ │ ├── 145.rc │ │ │ ├── 153.rc │ │ │ ├── 2.rc │ │ │ ├── 2049.rc │ │ │ ├── 2050.rc │ │ │ ├── 222.rc │ │ │ ├── 2354.rc │ │ │ ├── 2355.rc │ │ │ ├── 2356.rc │ │ │ ├── 2610.rc │ │ │ ├── 2628.rc │ │ │ ├── 2753.rc │ │ │ ├── 2757.rc │ │ │ ├── 2758.rc │ │ │ ├── 2765.rc │ │ │ ├── 2794.rc │ │ │ ├── 3.rc │ │ │ ├── 3585.rc │ │ │ ├── 3601.rc │ │ │ ├── 3602.rc │ │ │ ├── 3603.rc │ │ │ ├── 3605.rc │ │ │ ├── 3606.rc │ │ │ ├── 3713.rc │ │ │ ├── 3714.rc │ │ │ ├── 3825.rc │ │ │ ├── 3826.rc │ │ │ ├── 3841.rc │ │ │ ├── 3842.rc │ │ │ ├── 3843.rc │ │ │ ├── 3845.rc │ │ │ ├── 3849.rc │ │ │ ├── 3850.rc │ │ │ ├── 3857.rc │ │ │ ├── 3858.rc │ │ │ ├── 3859.rc │ │ │ ├── 3865.rc │ │ │ ├── 3866.rc │ │ │ ├── 3867.rc │ │ │ ├── 3868.rc │ │ │ ├── 3869.rc │ │ │ ├── 39.rc │ │ │ ├── 40.rc │ │ │ ├── 41.rc │ │ │ ├── 430.rc │ │ │ ├── 442.rc │ │ │ ├── 578.rc │ │ │ ├── 626.rc │ │ │ ├── 63.rc │ │ │ └── 7.rc │ │ └── localizations.js │ ├── sv/ │ │ ├── Dialog/ │ │ │ └── 041D/ │ │ │ ├── 105.rc │ │ │ ├── 108.rc │ │ │ ├── 112.rc │ │ │ ├── 113.rc │ │ │ ├── 132.rc │ │ │ ├── 30721.rc │ │ │ ├── 30722.rc │ │ │ ├── 30723.rc │ │ │ ├── 37.rc │ │ │ └── 4001.rc │ │ ├── Menu/ │ │ │ └── 041D/ │ │ │ ├── 113.rc │ │ │ ├── 118.rc │ │ │ ├── 119.rc │ │ │ ├── 2.rc │ │ │ ├── 4.rc │ │ │ └── 5.rc │ │ ├── String Table/ │ │ │ └── 041D/ │ │ │ ├── 1.rc │ │ │ ├── 129.rc │ │ │ ├── 130.rc │ │ │ ├── 131.rc │ │ │ ├── 132.rc │ │ │ ├── 135.rc │ │ │ ├── 139.rc │ │ │ ├── 141.rc │ │ │ ├── 144.rc │ │ │ ├── 145.rc │ │ │ ├── 153.rc │ │ │ ├── 2.rc │ │ │ ├── 2049.rc │ │ │ ├── 2050.rc │ │ │ ├── 222.rc │ │ │ ├── 2354.rc │ │ │ ├── 2355.rc │ │ │ ├── 2356.rc │ │ │ ├── 2610.rc │ │ │ ├── 2628.rc │ │ │ ├── 2753.rc │ │ │ ├── 2757.rc │ │ │ ├── 2758.rc │ │ │ ├── 2765.rc │ │ │ ├── 2794.rc │ │ │ ├── 3.rc │ │ │ ├── 3585.rc │ │ │ ├── 3601.rc │ │ │ ├── 3602.rc │ │ │ ├── 3603.rc │ │ │ ├── 3605.rc │ │ │ ├── 3606.rc │ │ │ ├── 3713.rc │ │ │ ├── 3714.rc │ │ │ ├── 3825.rc │ │ │ ├── 3826.rc │ │ │ ├── 3841.rc │ │ │ ├── 3842.rc │ │ │ ├── 3843.rc │ │ │ ├── 3845.rc │ │ │ ├── 3849.rc │ │ │ ├── 3850.rc │ │ │ ├── 3857.rc │ │ │ ├── 3858.rc │ │ │ ├── 3859.rc │ │ │ ├── 3865.rc │ │ │ ├── 3866.rc │ │ │ ├── 3867.rc │ │ │ ├── 3868.rc │ │ │ ├── 3869.rc │ │ │ ├── 39.rc │ │ │ ├── 40.rc │ │ │ ├── 41.rc │ │ │ ├── 430.rc │ │ │ ├── 442.rc │ │ │ ├── 578.rc │ │ │ ├── 626.rc │ │ │ ├── 63.rc │ │ │ └── 7.rc │ │ └── localizations.js │ ├── tr/ │ │ ├── Dialog/ │ │ │ └── 041F/ │ │ │ ├── 105.rc │ │ │ ├── 108.rc │ │ │ ├── 112.rc │ │ │ ├── 113.rc │ │ │ ├── 132.rc │ │ │ ├── 30721.rc │ │ │ ├── 30722.rc │ │ │ ├── 30723.rc │ │ │ ├── 37.rc │ │ │ └── 4001.rc │ │ ├── Menu/ │ │ │ └── 041F/ │ │ │ ├── 113.rc │ │ │ ├── 118.rc │ │ │ ├── 119.rc │ │ │ ├── 2.rc │ │ │ ├── 4.rc │ │ │ └── 5.rc │ │ ├── String Table/ │ │ │ └── 041F/ │ │ │ ├── 1.rc │ │ │ ├── 129.rc │ │ │ ├── 130.rc │ │ │ ├── 131.rc │ │ │ ├── 132.rc │ │ │ ├── 135.rc │ │ │ ├── 139.rc │ │ │ ├── 141.rc │ │ │ ├── 144.rc │ │ │ ├── 145.rc │ │ │ ├── 153.rc │ │ │ ├── 2.rc │ │ │ ├── 2049.rc │ │ │ ├── 2050.rc │ │ │ ├── 222.rc │ │ │ ├── 2354.rc │ │ │ ├── 2355.rc │ │ │ ├── 2356.rc │ │ │ ├── 2610.rc │ │ │ ├── 2628.rc │ │ │ ├── 2753.rc │ │ │ ├── 2757.rc │ │ │ ├── 2758.rc │ │ │ ├── 2765.rc │ │ │ ├── 2794.rc │ │ │ ├── 3.rc │ │ │ ├── 3585.rc │ │ │ ├── 3601.rc │ │ │ ├── 3602.rc │ │ │ ├── 3603.rc │ │ │ ├── 3605.rc │ │ │ ├── 3606.rc │ │ │ ├── 3713.rc │ │ │ ├── 3714.rc │ │ │ ├── 3825.rc │ │ │ ├── 3826.rc │ │ │ ├── 3841.rc │ │ │ ├── 3842.rc │ │ │ ├── 3843.rc │ │ │ ├── 3845.rc │ │ │ ├── 3849.rc │ │ │ ├── 3850.rc │ │ │ ├── 3857.rc │ │ │ ├── 3858.rc │ │ │ ├── 3859.rc │ │ │ ├── 3865.rc │ │ │ ├── 3866.rc │ │ │ ├── 3867.rc │ │ │ ├── 3868.rc │ │ │ ├── 3869.rc │ │ │ ├── 39.rc │ │ │ ├── 40.rc │ │ │ ├── 41.rc │ │ │ ├── 430.rc │ │ │ ├── 442.rc │ │ │ ├── 578.rc │ │ │ ├── 626.rc │ │ │ ├── 63.rc │ │ │ └── 7.rc │ │ └── localizations.js │ ├── zh/ │ │ ├── Dialog/ │ │ │ └── 0404/ │ │ │ ├── 105.rc │ │ │ ├── 108.rc │ │ │ ├── 112.rc │ │ │ ├── 113.rc │ │ │ ├── 132.rc │ │ │ ├── 30721.rc │ │ │ ├── 30722.rc │ │ │ ├── 30723.rc │ │ │ ├── 37.rc │ │ │ └── 4001.rc │ │ ├── Menu/ │ │ │ └── 0404/ │ │ │ ├── 113.rc │ │ │ ├── 118.rc │ │ │ ├── 119.rc │ │ │ ├── 2.rc │ │ │ ├── 4.rc │ │ │ └── 5.rc │ │ ├── String Table/ │ │ │ └── 0404/ │ │ │ ├── 1.rc │ │ │ ├── 129.rc │ │ │ ├── 130.rc │ │ │ ├── 131.rc │ │ │ ├── 132.rc │ │ │ ├── 135.rc │ │ │ ├── 139.rc │ │ │ ├── 141.rc │ │ │ ├── 144.rc │ │ │ ├── 145.rc │ │ │ ├── 153.rc │ │ │ ├── 2.rc │ │ │ ├── 2049.rc │ │ │ ├── 2050.rc │ │ │ ├── 222.rc │ │ │ ├── 2354.rc │ │ │ ├── 2355.rc │ │ │ ├── 2356.rc │ │ │ ├── 2610.rc │ │ │ ├── 2628.rc │ │ │ ├── 2753.rc │ │ │ ├── 2757.rc │ │ │ ├── 2758.rc │ │ │ ├── 2765.rc │ │ │ ├── 2794.rc │ │ │ ├── 3.rc │ │ │ ├── 3585.rc │ │ │ ├── 3601.rc │ │ │ ├── 3602.rc │ │ │ ├── 3603.rc │ │ │ ├── 3605.rc │ │ │ ├── 3606.rc │ │ │ ├── 3713.rc │ │ │ ├── 3714.rc │ │ │ ├── 3825.rc │ │ │ ├── 3826.rc │ │ │ ├── 3841.rc │ │ │ ├── 3842.rc │ │ │ ├── 3843.rc │ │ │ ├── 3845.rc │ │ │ ├── 3849.rc │ │ │ ├── 3850.rc │ │ │ ├── 3857.rc │ │ │ ├── 3858.rc │ │ │ ├── 3859.rc │ │ │ ├── 3865.rc │ │ │ ├── 3866.rc │ │ │ ├── 3867.rc │ │ │ ├── 3868.rc │ │ │ ├── 3869.rc │ │ │ ├── 39.rc │ │ │ ├── 40.rc │ │ │ ├── 41.rc │ │ │ ├── 430.rc │ │ │ ├── 442.rc │ │ │ ├── 578.rc │ │ │ ├── 626.rc │ │ │ ├── 63.rc │ │ │ └── 7.rc │ │ └── localizations.js │ └── zh-simplified/ │ ├── Dialog/ │ │ └── 0804/ │ │ ├── 105.rc │ │ ├── 108.rc │ │ ├── 112.rc │ │ ├── 113.rc │ │ ├── 132.rc │ │ ├── 30721.rc │ │ ├── 30722.rc │ │ ├── 30723.rc │ │ ├── 37.rc │ │ └── 4001.rc │ ├── Menu/ │ │ └── 0804/ │ │ ├── 113.rc │ │ ├── 118.rc │ │ ├── 119.rc │ │ ├── 2.rc │ │ ├── 4.rc │ │ └── 5.rc │ ├── String Table/ │ │ └── 0804/ │ │ ├── 1.rc │ │ ├── 129.rc │ │ ├── 130.rc │ │ ├── 131.rc │ │ ├── 132.rc │ │ ├── 135.rc │ │ ├── 139.rc │ │ ├── 141.rc │ │ ├── 144.rc │ │ ├── 145.rc │ │ ├── 153.rc │ │ ├── 2.rc │ │ ├── 2049.rc │ │ ├── 2050.rc │ │ ├── 222.rc │ │ ├── 2354.rc │ │ ├── 2355.rc │ │ ├── 2356.rc │ │ ├── 2610.rc │ │ ├── 2628.rc │ │ ├── 2753.rc │ │ ├── 2757.rc │ │ ├── 2758.rc │ │ ├── 2765.rc │ │ ├── 2794.rc │ │ ├── 3.rc │ │ ├── 3585.rc │ │ ├── 3601.rc │ │ ├── 3602.rc │ │ ├── 3603.rc │ │ ├── 3605.rc │ │ ├── 3606.rc │ │ ├── 3713.rc │ │ ├── 3714.rc │ │ ├── 3825.rc │ │ ├── 3826.rc │ │ ├── 3841.rc │ │ ├── 3842.rc │ │ ├── 3843.rc │ │ ├── 3845.rc │ │ ├── 3849.rc │ │ ├── 3850.rc │ │ ├── 3857.rc │ │ ├── 3858.rc │ │ ├── 3859.rc │ │ ├── 3865.rc │ │ ├── 3866.rc │ │ ├── 3867.rc │ │ ├── 3868.rc │ │ ├── 3869.rc │ │ ├── 39.rc │ │ ├── 40.rc │ │ ├── 41.rc │ │ ├── 430.rc │ │ ├── 442.rc │ │ ├── 578.rc │ │ ├── 626.rc │ │ ├── 63.rc │ │ └── 7.rc │ └── localizations.js ├── manifest.webmanifest ├── package.json ├── privacy.html ├── prune-globals.js ├── src/ │ ├── $ColorBox.js │ ├── $Component.js │ ├── $FontBox.js │ ├── $ToolBox.js │ ├── $ToolWindow.js │ ├── Handles.js │ ├── OnCanvasHelperLayer.js │ ├── OnCanvasObject.js │ ├── OnCanvasSelection.js │ ├── OnCanvasTextBox.js │ ├── app-localization.js │ ├── app-state.js │ ├── app.js │ ├── color-data.js │ ├── copy-inkscape-labels.js │ ├── discord-activity-client.js │ ├── edit-colors.js │ ├── electron-injected.js │ ├── electron-main.js │ ├── error-handling-basic.js │ ├── error-handling-enhanced.js │ ├── extra-tools.js │ ├── eye-gaze-mode.js │ ├── file-format-data.js │ ├── functions.js │ ├── globals.d.ts │ ├── help.js │ ├── helpers.js │ ├── image-manipulation.js │ ├── imgur.js │ ├── konami.js │ ├── manage-storage.js │ ├── menus.js │ ├── msgbox.js │ ├── repack-spritesheet.js │ ├── save-history-as-spritesheet.js │ ├── sessions.js │ ├── simulate-random-gestures.js │ ├── speech-recognition.js │ ├── storage.js │ ├── test-news.js │ ├── theme.js │ ├── tool-options.js │ ├── tools.js │ └── vaporwave-fun.js ├── styles/ │ ├── about.css │ ├── layout.css │ ├── layout.rtl.css │ ├── legal.css │ ├── normalize.css │ ├── print.css │ └── themes/ │ ├── bubblegum.css │ ├── classic.css │ ├── dark.css │ ├── modern-dark.css │ ├── modern.css │ ├── occult.css │ ├── red-wine.css │ ├── vista-esque-midnight-green.css │ └── winter.css ├── svg-paint/ │ ├── index.html │ └── svg-paint.js ├── sync-package.js └── test-news-newer.html ================================================ FILE CONTENTS ================================================ ================================================ FILE: .github/FUNDING.yml ================================================ custom: ["https://www.paypal.me/IsaiahOdhner"] ================================================ FILE: .gitignore ================================================ # cypress-image-snapshot visual diffs __diff_output__ # cypress-image-snapshot images of the whole cypress UI *(failed).snap.png # electron forge output out/ # npm node_modules/ *.log *.log.* # os crap Thumbs.db ~* ================================================ FILE: .vscode/extensions.json ================================================ { "recommendations": [ "streetsidesoftware.code-spell-checker", "dbaeumer.vscode-eslint" ] } ================================================ FILE: .vscode/launch.json ================================================ { // Use IntelliSense to learn about possible attributes. // Hover to view descriptions of existing attributes. // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 "version": "0.2.0", "configurations": [ { // To use this configuration, you must run Chrome with a flag: // google-chrome --remote-debugging-port=9222 http://127.0.0.1:1999 // or for Windows: // start chrome --remote-debugging-port=9222 http://127.0.0.1:1999 // and Chrome must not be running beforehand, as the flag won't apply otherwise. // And you need to have the dev server running: // npm run dev // If you really don't want to close Chrome, you can use a temporary profile: // mkdir C:\TempChromeProfile // echo {"browser": {"has_seen_welcome_page": true, "default_browser_infobar_last_declined": "13354566465257726"}} > C:\TempChromeProfile\Preferences // start chrome --remote-debugging-port=9222 --user-data-dir="C:\TempChromeProfile" --disable-fre --no-default-browser-check --no-first-run http://127.0.0.1:1999 // rmdir /s /q C:\TempChromeProfile "type": "chrome", "request": "attach", "name": "Attach to Chrome", "port": 9222, "urlFilter": "http://127.0.0.1:1999/*", "webRoot": "${workspaceFolder}" }, { // https://www.electronjs.org/docs/latest/tutorial/debugging-vscode "name": "Electron: Debug Main Process", "type": "node", "request": "launch", "cwd": "${workspaceFolder}", "runtimeExecutable": "${workspaceFolder}/node_modules/.bin/electron", "windows": { "runtimeExecutable": "${workspaceFolder}/node_modules/.bin/electron.cmd" }, "args": [ "." ], "outputCapture": "std" } ] } ================================================ FILE: .vscode/run-command-on-all-files.ahk ================================================ ; This script runs on AutoHotkey v2. ; ; I tried the VS Code extension "Command on All Files" first: https://marketplace.visualstudio.com/items?itemName=rioj7.commandOnAllFiles ; but it didn't work with the "cSpell.addIssuesToDictionary" command. ; I think it was too fast, and the spell checker didn't have time to run. ; ; A better solution would be to: ; - Improve the "Command on All Files" extension: ; - add delay options ; - add a dry run mode, which I had to work around by setting it to a near-no-op command ; - just listing the files would be a lot nicer than opening them all one by one ; - unify file matching; you shouldn't have to specify a list of file extensions to include, it should be a glob like the exclusions ; Or: ; - Add a command to the cspell-cli to accept spellings ; Or: ; - Implement an external Node.js script using cspell's API (but that's less helpful than making a PR) root := A_ScriptDir "\..\*" ignoreFolders := [ ".git", ".history", "node_modules", "lib", "out", "localization", ] ignoreExtensions := [ "png", "gif", "jpg", "jpeg", "svg", "cur", "ico", "icns", "wav", ] command := "cSpell.addIssuesToDictionary" beforeRunInfo := "This script is designed to add all spelling issues to the dictionary.`nTo use it to prune the dictionary of no-longer-needed words, you must empty the dictionary first.`n`nThis script will run the VS Code command '" command "' on all files in the directory '" root "'.`n`n" delayBeforeCommand := 2000 ; Give enough time for spell checker to run delayAfterCommand := 2000 ; Give enough time for CSpell to update the dictionary closeFileAfterCommand := false appName := "VS Code Automation" popup := Gui(, appName) popup.Opt("+AlwaysOnTop +Disabled -SysMenu +Owner") ; +Owner avoids a taskbar button. popup.Add("Text", , "`nPress Esc to stop the script.`n`n") statusBar := popup.Add("StatusBar") windowId := WinExist("ahk_exe Code.exe") IsIgnoredPath(path) { SplitPath path, &name, &dir, &ext, &nameNoExt, &drive for _, ignoreExtension in ignoreExtensions { if (StrLower(ext) = ignoreExtension) { return true } } parts := StrSplit(path, "\") for index, part in parts { for _, ignoreFolder in ignoreFolders { if (part = ignoreFolder) { return true } } } return false } Automate() { targets := [] ; Loop through files (F) recursively (R) loop files, root, "FR" { if (IsIgnoredPath(A_LoopFileFullPath)) { continue } targets.Push(A_LoopFileFullPath) } if (targets.Length = 0) { MsgBox "No files found for pattern: " root return } ; Focus VS Code before confirmation to avoid confusion between multiple VS Code windows try { WinActivate { Hwnd: windowId } } catch TargetError as e { MsgBox "Could not find VS Code window. Please open it and try again.", appName, 0x10 return } ; Ask for confirmation if MsgBox(beforeRunInfo "Found " targets.Length " files. Continue?", appName, 4) = "No" { if MsgBox("Copy file paths to clipboard?", appName, 4) = "Yes" { A_Clipboard := Join("`n", targets) } return } RunCommandOnFiles(targets) } RunCommandOnFiles(targets) { popup.Show("NoActivate") ; NoActivate avoids deactivating the currently active window. for index, target in targets { statusBar.SetText(index "/" targets.Length) try { RunCommandOnFile(target) } catch TargetError as e { popup.Destroy() MsgBox "Lost VS Code window. Please open it and try again.`n`n" index " out of " targets.Length " files were processed.", appName, 0x10 return } } popup.Destroy() MsgBox "Processed " targets.Length " files." return } SendToVSCode(keys) { ; ControlSend(keys, , { Hwnd: windowId }) WinActivate { Hwnd: windowId } Send keys } RunCommandOnFile(target) { ; Open file in VS Code using Ctrl+P file switcher SendToVSCode "^p" Sleep 100 SendToVSCode target Sleep 100 SendToVSCode "{Enter}" Sleep delayBeforeCommand ; Run command via F1 command palette SendToVSCode "{F1}" Sleep 100 SendToVSCode command Sleep 100 SendToVSCode "{Enter}" Sleep delayAfterCommand ; Close the file (optional) if closeFileAfterCommand { SendToVSCode "^w" } } Join(sep, items) { str := "" for index, item in items { str .= item . sep } return SubStr(str, 1, -StrLen(sep)) } ; Escape hatch Esc:: { ExitApp } Automate() ExitApp() ================================================ FILE: .vscode/settings.json ================================================ { // This hides files from the file tree as well as search results. "files.exclude": { "**/node_modules": true, "**/out": true, }, // This affects Find In Files (Ctrl+Shift+F) but also Go To File (Ctrl+P) and // the Quick Search, which I've been using a lot since it was released. "search.exclude": { "**/images": true, "**/lib": true, "**/out": true, // The package lock file contains a lot of repetation, and is usually noise in search results. // You can often search with `npm ls` if you want to check if a package is installed, // and what depends on what. "package-lock.json": true, // Ignore localization data, which is in subfolders, but not helper scripts. // Any time a search matches a localized string, it matches an overwhelming number of files. "**/localization/*/**/*": true, }, "editor.formatOnSave": true, "editor.insertSpaces": false, "editor.detectIndentation": false, "editor.codeActionsOnSave": { "source.organizeImports": "always", }, "javascript.preferences.importModuleSpecifierEnding": "js", "typescript.preferences.importModuleSpecifierEnding": "js", "html.format.unformattedContentDelimiter": "", "[css]": { // The CSS in this project uses (the lack of) newlines between rules for grouping, as well as inline comments. // VS Code's default formatter adds newlines between all rules, and forces comments to the next line, dissociating them. "editor.formatOnSave": false, }, "[markdown]": { // Formatting markdown tables automatically is cool, but doesn't allow padding cells to avoid superflous git diffs. // Also, VS Code's markdown formatter doesn't handle emoji in tables as well as it could. "editor.formatOnSave": false, }, // Note: this doesn't apply to "JSON with comments" files, such as this one. That's [jsonc]. "[json]": { // npm respects different indent styles, but always adds a newline at the end of package.json/package-lock.json, // so this avoids ping-ponging changes in git. // This could be applied to all files for consistency, but it may introduce noise if all files aren't formatted at once. "files.insertFinalNewline": true, // Maintaining current indentation for now, but could remove this for consistency. "editor.detectIndentation": true, }, // Use local TypeScript version instead of the one bundled with VS Code. // You may need to run "TypeScript: Select TypeScript Version..." and choose "Use workspace version" // or that command might just set this setting for you, I'm not sure. // Go to a TS or JS file for the command to show up in the command palette. "typescript.tsdk": "node_modules/typescript/lib", // Prevent accidental editing. // This can always be overridden with the command "File: Toggle Active Editor Read-only in Session" "files.readonlyInclude": { // Electron Forge output "out/**": true, // Built/installed app (sometimes I follow error message links into the built app's code, and end up editing it by mistake) "**/resources/app/**": true, // Node.js "node_modules/**": true, "package-lock.json": true, // RTLCSS output "**/*.rtl.css": true, }, } ================================================ FILE: CHANGELOG.md ================================================ # Changelog All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] ### Changed - `systemHooks.writeBlobToHandle` promise can resolve with `true` to indicate success, in which case **File > Save** will not prompt to save the file again. `false` indicates failure or cancellation, whereas `undefined` can be used if it is unknown whether the file will be saved successfully, as is the case when using the `download` attribute on an anchor element. If saving as a monochrome bitmap, `undefined` will cause the canvas to become monochrome, but it will still prompt to save the file again. This tradeoff is reasonable because the download attribute doesn't support saving over an already saved file anyways ## [1.0.0] - 2022-08-02 ### Added - `systemHooks` API for overriding file dialogs, file saving/loading, and Set as Wallpaper commands - `systemHooks.showSaveFileDialog = async ({ formats, defaultFileName, defaultPath, defaultFileFormatID, getBlob, savedCallbackUnreliable, dialogTitle }) => { ... };` - `systemHooks.showOpenFileDialog = async ({ formats }) => { ... };` - `systemHooks.writeBlobToHandle = async (save_file_handle, blob) => { ... };` - `systemHooks.readBlobFromHandle = async (file_handle) => { ... };` - `systemHooks.setWallpaperTiled = (canvas) => { ... };` - `systemHooks.setWallpaperCentered = (canvas) => { ... };` - function `undoable({ name, icon }, actionFunction)` to make an action undoable, as far is it modifies the canvas - function `show_error_message(message, [error])` to show an error message dialog box, optionally with expandable error details - function `open_from_file(blob, source_file_handle)` to load a file from a blob and file handle pair (kinda quirky API) - function `set_theme(theme_file_name)` to switch themes - function `set_language(language_code)` to switch languages, prompting the user to reload the application - You can use `.main-canvas` selector to access the canvas element. - URL parameter `#load:` to load a file from a URL [Unreleased]: https://github.com/1j01/jspaint/compare/v1.0.0...HEAD [1.1.0]: https://github.com/1j01/jspaint/compare/v1.0.0...v1.1.0 [1.0.0]: https://github.com/1j01/jspaint/releases/tag/v1.0.0 ================================================ FILE: CNAME ================================================ jspaint.app ================================================ FILE: CONTRIBUTING.md ================================================ # Contributing ## Pull Requests Let me know before you work on something by opening an issue or commenting on an existing one. Someone may be already working on it, or I may have specific plans or requirements. I don't want your effort to be wasted! ## Issues [Bugs and feature requests are tracked on GitHub.](https://github.com/1j01/jspaint/issues) Before opening an issue for a bug or feature request, search to see if it's already been reported. You can also [email me](mailto:isaiahodhner@gmail.com) if you prefer. ## Windows 98 Note: JS Paint's GUI is primarily based on Paint from Windows 98. There's a nice [online emulator](https://copy.sh/v86/?profile=windows98) that you can play around with and use as a reference. ## Dev Setup See [**Development Setup**](./README.md#Development-Setup) on the readme. ### Project Structure - `index.html` and `app.js` are the main entry points for the app. - `functions.js` has functions that shouldn't own any global state, altho they very much modify global state, and there may be a few stateful global variables defined in there. - The project uses [jQuery](https://jquery.com/), and a convention of prefixing variables that hold jQuery objects with `$` - There are also some weird pseudo-classes like `$ColorBox` which extend and return jQuery objects. I don't recommend this pattern for new code. - Menu code and windowing code lives in the [os-gui](https://github.com/1j01/os-gui) project. - It can be synced (one-way) by running `npm i os-gui@latest --save-exact && npm run sync-os-gui` - To develop os-gui in the context of jspaint, you can run `npm link` in a clone of os-gui, then run `npm link os-gui && npm run sync-os-gui` in jspaint after making any changes in os-gui. - (Maybe I should version this using git-subrepo?) - Some window behavior specific to jspaint is in `$ToolWindow.js` and `$Component.js` - `image-manipulation.js` should contain just rendering related code, and ideally no dialogs except maybe some error messages. - Some image manipulation code is also in `tools.js` and `functions.js` - CSS is in `styles/` - Layout-important CSS is kept separate from theme CSS - Localization data is in `localization/` - As of writing there's no good way to contribute translations, but [get in touch!](https://github.com/1j01/jspaint/issues/80) Any good IDE or code editor has a project-wide search (often with Ctrl+Shift+F). I use this all the time. I also use the "Intellisense" feature of [VS Code](https://code.visualstudio.com/) to jump to function definitions (an extra convenience over searching for function names). ================================================ FILE: LICENSE.txt ================================================ MIT License Copyright (c) 2022 Isaiah Odhner Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: README.md ================================================ # [![](images/icons/32x32.png) JS Paint](https://jspaint.app) A pixel-perfect web-based MS Paint remake and more... [Try it out!](https://jspaint.app) Then join the [Discord server](https://discord.gg/jxQBK3k8tx) to share your art! JS Paint recreates every tool and menu of MS Paint, and even [little-known features](#did-you-know), to a high degree of fidelity. It supports themes, additional file types, and accessibility features like a Dwell Clicker and Speech Recognition. ![Screenshot](images/meta/main-screenshot.png) Ah yes, good old Paint. Not the one with the [ribbons][] or the [new skeuomorphic one][Fresh Paint] with the interface that can take up nearly half the screen. (And not the even newer [Paint 3D][].) [ribbons]: https://www.google.com/search?tbm=isch&q=MS+Paint+Windows+7+ribbons "Google Search: MS Paint Windows 7 ribbons" [Fresh Paint]: https://www.google.com/search?tbm=isch&q=MS+Fresh+Paint "Google Search: MS Fresh Paint" [Paint 3D]: https://www.microsoft.com/en-us/store/p/paint-3d-preview/9nblggh5fv99 Windows 95, 98, and XP were the golden years of Paint. You had a tool box and a color box, a foreground color and a background color, and that was all you needed. Things were simple. But we want to undo more than three actions. We want to edit transparent images. We can't just keep using the old Paint. So that's why I'm making JS Paint. I want to bring good old Paint into the modern era. #### Current improvements include: * Open source ([MIT licensed](LICENSE.txt)) * Cross-platform * Mobile friendly * Touch support: use two fingers to pan the view, and pinch to zoom * Click/tap the selected colors area to swap the foreground and background colors * **View > Fullscreen** to toggle fullscreen mode, nice for small screens * **Extras > Quick Undo Button** to add a floating undo button for easier access * (this may be enabled by default in the future for touch devices) * Web features * **File > Load From URL...** to open an image from the Web. * **File > Upload to Imgur** to upload the current image to Imgur. * **Paste** supports loading from URLs. * You can create links that will open an image from the Web in JS Paint. For example, this link will start with an isometric grid as a template: * Rudimentary **multi-user** collaboration support. Start up a session at [jspaint.app/#session:multi-user-test](https://jspaint.app/#session:multi-user-test) and send the link to your friends! It isn't seamless; actions by other users interrupt what you're doing, and visa versa. Sessions are not private, and you may lose your work at any time. If you want better collaboration support, follow the development of [Mopaint](https://github.com/1j01/mopaint). * **Extras > Themes** to change the look of the app. * Dark and light variants * Vector tool icons handcrafted to match the pixel art versions, for both Modern and Classic themes * Occult theme, in the spirit of Halloween * Winter theme, with a special color palette including candy cane stripes, and advent calendar style flaps revealing pixel art for each tool * Bubblegum theme, featuring *Business Pink* color scheme and AI-generated icons * **Extras > Enlarge UI** to make buttons and menus bigger, for usage with an eye tracker, head tracker, or other course input devices. May also work well for a tablet, but not so much for a phone at the moment. * **Extras > Dwell Clicker** to click automatically by hovering in one spot, for usage with an eye tracker or head tracker. * Hovered buttons are highlighted, and the click is performed after a delay. * Supports dragging windows and drawing on the canvas. * With just a webcam, you can try it out with [Enable Viacam](https://eviacam.crea-si.com/) (head tracker), [GazePointer](https://sourceforge.net/projects/gazepointer/) (eye tracker), or the built in [ Tracky Mouse](https://trackymouse.js.org/) head tracker using **Extras > Head Tracker**. * This feature can be easily added to other web applications, using the [ Tracky Mouse API](https://www.npmjs.com/package/tracky-mouse). * **Extras > Speech Recognition** to control the app with your voice. * Select tools and colors ("fill tool", "orange", etc.) * Pan the view ("scroll down and to the left", or "go southwest", etc.) * Explore the menus, or activate any menu item without opening the menus first * Interact with windows * Dictate text with the Text tool * Create an animated GIF from the current document history. Accessible from the Extras menu or with Ctrl+Shift+G. It's pretty nifty, you should try it out! You might want to limit the size of the image though. * Load and save [many different palette formats](#color-palette-formats) with **Colors > Get Colors** and **Colors > Save Colors**. (I made a library for this: [AnyPalette.js](https://github.com/1j01/anypalette.js).) * You can also drag and drop palette files into the app to load. Editing Features: * Use Alt+Mousewheel to zoom in and out * Edit transparent images! To create a transparent image, go to **Image > Attributes...** and select Transparent, then OK, and then **Image > Clear Image** or use the Eraser tool. Images with *any* translucent pixels will open in Transparent mode. * You can crop the image by making a selection while holding Ctrl * Keyboard shortcuts for rotation: Ctrl+. and Ctrl+, (< and >) * Rotate by any arbitrary angle in **Image > Flip/Rotate** * In **Image > Stretch/Skew**, you can stretch more than 500% at once * Zoom to an arbitrary scale in **View > Zoom > Custom...** * Zoom to fit the canvas within the window with **View > Zoom > Zoom To Window** * Non-contiguous fill: Replace a color in the entire image by holding Shift when using the fill tool Miscellaneous Improvements: * [Vertical Color Box mode](https://jspaint.app/#vertical-color-box-mode), accessible from **Extras > Vertical Color Box** * You can use the Text tool at any zoom level (and it previews the exact pixels that will end up on the canvas). * Spellcheck is available in the textbox if your browser supports it. * Resize handles are easier to grab than in Windows 10's Paint. * Omits some Thumbnail view bugs, like the selection showing in the wrong place. * Unlimited undos/redos (as opposed to a measly 3 in Windows XP, or a measly 50 in Windows 7) * Undo history is *nonlinear*, which means if you undo and do something other than redo, the redos aren't discarded. Instead, a new branch is created in the *history tree*. Jump to any point in history with **Edit > History** or Ctrl+Shift+Y * Automatically keeps a backup of your image. Only one backup per image tho, which doesn't give you a lot of safety. Remember to save with **File > Save** or Ctrl+S! Manage backups with **File > Manage Storage**. ![JS Paint drawing of JS Paint on a phone](images/meta/mobipaint.png) #### Limitations: A few things with the tools aren't done yet. See [TODO.md](TODO.md#Tools) Full clipboard support in the web app requires a browser supporting the [Async Clipboard API w/ Images](https://developers.google.com/web/updates/2019/07/image-support-for-async-clipboard), namely Chrome 76+ at the time of writing. In other browsers you can still copy with Ctrl+C, cut with Ctrl+X, and paste with Ctrl+V, but data copied from JS Paint can only be pasted into other instances of JS Paint. External images can be pasted in. ## Supported File Formats ### Image Formats ⚠️ Saving as JPEG will introduce artifacts that cause problems when using the Fill tool or transparent selections. ⚠️ Saving in some formats will reduce the number of colors in the image. 💡 Unlike in MS Paint, you can use **Edit > Undo** to revert color or quality reduction from saving. This doesn't undo saving the file, but allows you to then save in a different format with higher quality, using **File > Save As**. 💡 Saving as PNG is recommended as it gives small file sizes while retaining full quality. | File Extension | Name | Read | Write | Read Palette | Write Palette | |-------------------------------|-------------------------------|:----:|:-----:|:------------:|:-------------:| | .png | [PNG][] | ✅ | ✅ | 🔜 | | | .bmp, .dib | [Monochrome Bitmap][BMP] | ✅ | ✅ | 🔜 | ✅ | | .bmp, .dib | [16 Color Bitmap][BMP] | ✅ | ✅ | 🔜 | ✅ | | .bmp, .dib | [256 Color Bitmap][BMP] | ✅ | ✅ | 🔜 | ✅ | | .bmp, .dib | [24-bit Bitmap][BMP] | ✅ | ✅ | N/A | N/A | | .tif, .tiff, .dng, .cr2, .nef | [TIFF][] (loads first page) | ✅ | ✅ | | | | .pdf | [PDF][] (loads first page) | ✅ | | | | | .webp | [WebP][] | 🌐 | 🌐 | | | | .gif | [GIF][] | 🌐 | 🌐 | | | | .jpeg, .jpg | [JPEG][] | 🌐 | 🌐 | N/A | N/A | | .svg | [SVG][] (only default size) | 🌐 | | | | | .ico | [ICO][] (only default size) | 🌐 | | | | Capabilities marked with 🌐 are currently left up to the browser to support or not. If "Write" is marked with 🌐, the format will appear in the file type dropdown but may not work when you try to save. For opening files, see Wikipedia's [browser image format support table][] for more information. Capabilities marked with 🔜 may be coming soon, and N/A means not applicable. "Read Palette" refers to loading the colors into the Colors box automatically (from an [indexed color][] image), and "Write Palette" refers to writing an [indexed color][] image. [PNG]: https://en.wikipedia.org/wiki/Portable_Network_Graphics [BMP]: https://en.wikipedia.org/wiki/BMP_file_format [TIFF]: https://en.wikipedia.org/wiki/TIFF [PDF]: https://en.wikipedia.org/wiki/PDF [WebP]: https://en.wikipedia.org/wiki/WebP [GIF]: https://en.wikipedia.org/wiki/GIF [JPEG]: https://en.wikipedia.org/wiki/JPEG [SVG]: https://en.wikipedia.org/wiki/Scalable_Vector_Graphics [ICO]: https://en.wikipedia.org/wiki/ICO_(file_format) [indexed color]: https://en.wikipedia.org/wiki/Indexed_color [browser image format support table]: https://en.wikipedia.org/wiki/Comparison_of_web_browsers#Image_format_support ### Color Palette Formats With **Colors > Save Colors** and **Colors > Get Colors** you can save and load colors in many different formats, for compatibility with a wide range of programs. If you want to add extensive palette support to another application, I've made this functionality available as a library: [AnyPalette.js](https://github.com/1j01/anypalette.js) | File Extension | Name | Programs | Read | Write | |-------------------|-----------------------------------|-----------------------------------------------------------------------------------|:-------:|:-------:| | .pal | [RIFF] Palette | [MS Paint] for Windows 95 and Windows NT 4.0 | ✅ | ✅ | | .gpl | [GIMP][Gimp] Palette | [Gimp], [Inkscape], [Krita], [KolourPaint], [Scribus], [CinePaint], [MyPaint] | ✅ | ✅ | | .aco | Adobe Color Swatch | Adobe [Photoshop] | ✅ | ✅ | | .ase | Adobe Swatch Exchange | Adobe [Photoshop], [InDesign], and [Illustrator] | ✅ | ✅ | | .txt | [Paint.NET] Palette | [Paint.NET] | ✅ | ✅ | | .act | Adobe Color Table | Adobe [Photoshop] and [Illustrator] | ✅ | ✅ | | .pal, .psppalette | [Paint Shop Pro] Palette | [Paint Shop Pro] (Jasc Software / Corel) | ✅ | ✅ | | .hpl | [Homesite] Palette | Allaire [Homesite] / Macromedia [ColdFusion] | ✅ | ✅ | | .cs | ColorSchemer | ColorSchemer Studio | ✅ | | | .pal | [StarCraft] Palette | [StarCraft] | ✅ | ✅ | | .wpe | [StarCraft] Terrain Palette | [StarCraft] | ✅ | ✅ | | .sketchpalette | [Sketch] Palette | [Sketch] | ✅ | ✅ | | .spl | [Skencil] Palette | [Skencil] (formerly called Sketch) | ✅ | ✅ | | .soc | StarOffice Colors | [StarOffice], [OpenOffice], [LibreOffice] | ✅ | ✅ | | .colors | KolourPaint Color Collection | [KolourPaint] | ✅ | ✅ | | .colors | Plasma Desktop Color Scheme | [KDE] Plasma Desktop | ✅ | | | .theme | Windows Theme | [Windows] Desktop | ✅ | | | .themepack | Windows Theme | [Windows] Desktop | ✅ | | | .css, .scss, .styl| Cascading StyleSheets | Web browsers / web pages | ✅ | ✅ | | .html, .svg, .js | any text files with CSS colors | Web browsers / web pages | ✅ | | [RIFF]: https://en.wikipedia.org/wiki/Resource_Interchange_File_Format [MS Paint]: https://en.wikipedia.org/wiki/Microsoft_Paint [Paint.NET]: https://www.getpaint.net/ [Paint Shop Pro]: https://www.paintshoppro.com/en/ [StarCraft]: https://en.wikipedia.org/wiki/StarCraft [Homesite]: https://en.wikipedia.org/wiki/Macromedia_HomeSite [ColdFusion]: https://en.wikipedia.org/wiki/Adobe_ColdFusion [StarOffice]: https://en.wikipedia.org/wiki/StarOffice [OpenOffice]: https://www.openoffice.org/ [LibreOffice]: https://www.libreoffice.org/ [Sketch]: https://www.sketchapp.com/ [Skencil]: https://skencil.org/ [Photoshop]: https://www.adobe.com/products/photoshop.html [InDesign]: https://www.adobe.com/products/indesign.html [Illustrator]: https://www.adobe.com/products/illustrator.html [Gimp]: https://www.gimp.org/ [Inkscape]: https://inkscape.org/en/ [Krita]: https://www.calligra.org/krita/ [KolourPaint]: http://kolourpaint.org/ [KDE]: https://kde.org/ [Windows]: https://en.wikipedia.org/wiki/Microsoft_Windows [Scribus]: https://www.scribus.net/ [CinePaint]: http://www.cinepaint.org/ [MyPaint]: http://mypaint.org/ ## Did you know? * There's a black and white mode with *patterns* instead of colors in the palette, which you can get to from **Image > Attributes...** * You can drag the color box and tool box around if you grab them by the right place. You can even drag them out into little windows. You can dock the windows back to the side by double-clicking on their title bars. * In addition to the left-click foreground color and the right-click background color, there's a third color you can access by holding Ctrl while you draw. It starts out with no color so you'll need to hold Ctrl and select a color first. The fancy thing about this color slot is you can press and release Ctrl to switch colors *while drawing*. * You can apply image transformations like Flip/Rotate, Stretch/Skew or Invert (in the Image menu) either to the whole image or to a selection. Try scribbling with the Free-Form Select tool and then doing **Image > Invert** * These Tips and Tricks from [a tutorial for MS Paint](https://www.albinoblacksheep.com/tutorial/mspaint) also work in JS Paint: * [x] Brush Scaling (+ & - on the number pad to adjust brush size) * [x] "Custom Brushes" (hold Shift and drag the selection to smear it) * [x] The 'Stamp' "Tool" (hold Shift and click the selection to stamp it) * [x] Image Scaling (+ & - on the number pad to scale the selection by factors of 2) * [x] Color Replacement (right mouse button with Eraser to selectively replace the foreground color with the background color) * [x] The Grid (Ctrl+G & Zoom to 4x+) * [x] Quick Undo (Pressing a second mouse button cancels the action you were performing. I also made it redoable, in case you do it by accident!) * [ ] Scroll Wheel Bug (Hmm, let's maybe not recreate this?) ## Desktop App ### PWA JS Paint can be installed as a Progressive Web App (PWA), although it doesn't work offline yet. Look for the install prompt in the address bar. PWA features: - No address bar; middle-ground between web and native - Cross-platform (macOS, Windows, Linux, Android, iOS) - Basic file integration: - File > Open - File > Save downloads the file after asking for a filename and format - Drag and drop files onto the window to open them Missing features: -
Directly saving to files is implemented but not enabled currently.I was concerned about data loss for two reasons: 1. the change in behavior of File > Save / Ctrl+S from effectively acting as Save As to overwriting files directly, although I made a warning dialog for this, with a don't show again option; 2. there was a bad bug with saved files ending up completely empty (zero bytes), which I don't know if was a bug in my code or in Chrome.
-
Offline support is not implemented.I've taken a few stabs at this, and I'm not the only one, but there are some huge caveats, such as the development server not being able to live-reload without disabling the service worker.
### Electron I've also built it into a desktop app with [Electron][] and [Electron Forge][]. You can download it from the [releases page][]. ![JS Paint running as a desktop app on macOS](images/meta/electron-app-screenshot-mac.png) Electron app features: - Native-like experience (runs in a window with no address bar) - Cross-platform (macOS, Windows, Linux) - Clipboard support - Files can be opened in various ways: - **File > Open** - Drag and drop onto window - Drag and drop onto dock icon on macOS - Drag and drop onto desktop shortcut - **Right Click > Open With** in file manager (macOS and Linux) - On Windows, you can manually paste the path to the executable into the Open With dialog, which you can find by right clicking the app in the taskbar, then right clicking the app's name, and selecting Properties. In the Shortcut tab, the Target field is the path to the executable. Once you open the app in this way, the app will show up in the Open With list, and if you select "Always", it will become the default app for that file type. - Command line: type `jspaint path/to/file.png` in the terminal - **File > Save** will save directly to the file - **File > Set As Wallpaper (Tiled)** and **File > Set As Wallpaper (Centered)** - On macOS, an icon representing the currently open file is shown in the titlebar. You can drag this icon into other applications, for example to include the image you're editing in an email. The icon is dimmed while there are unsaved changes.
Electron app limitations - Basics: - Execution is blocked by default on Mac and Windows - On macOS you need to Ctrl+click the file and then say Open - On Windows, you need to say "More info" and then "Run" (or "Run anyway"?) - I would need to pay a fee for code signing to avoid this. It's basically *security by extortion*. - There are no automatic updates. Apparently I would need to pay a fee for code signing to get this free service. - That said, **Help > About Paint** can tell you if JS Paint is out of date, at least in terms of news updates. - Electron is out of date. It may, for instance, contain image decoding vulnerabilities that have since been fixed. However, I've taken precautions to sandbox the app and restrict write access to a list of files explicitly opened in the app, the list being controlled by the main process, separate from the renderer process which would handle image decoding. - Only a single editor window can be opened at once. - The File menu's recent files list is not implemented, nor are [OS-specific jump menus](https://www.electronjs.org/docs/latest/tutorial/recent-documents). - Minor details: - A very confusing message is shown if you edit a document before clicking an Open link in the Manage Storage dialog. - WebGL error messages tell you to refresh without offering a way to reload; also, calling the app a web page feels unpolished - The File > Open dialog does not have an All Files (\*.\*) option, and the list of file types supported is not exhaustive; for example, AVIF images can be loaded but only by drag and drop - Drag and drop shows two "Save changes to X?" dialogs on top of each other? - I'm not sure if all of these are still issues, need to retest them: - Quit doesn't exit app completely, only closes the window if it's open... intended behavior? shouldn't right click > Quit really quit? https://stackoverflow.com/questions/44316306/how-to-quit-electron-app-on-mac - Quit doesn't show/focus window when save changes prompt is shown on maybe mac/linux - Ctrl+C doesn't exit on mac/linux https://github.com/electron/electron/issues/5273 - this is because of `editor_window.on("close")` calling `preventDefault` and may be a feature but needs to show/focus the window - https://stackoverflow.com/questions/75362687/electron-js-processes-do-not-exit-on-app-quit - Opening an SVG file also isn't working via command line argument (dragging onto the shortcut in File Explorer) even though dragging and dropping into the window works. - Seems to load load SVG as a palette... Is this what I was running into?
[Electron]: https://electronjs.org/ [Electron Forge]: https://electronforge.io/ [releases page]: https://github.com/1j01/jspaint/releases/ ## Development Setup [Clone the repo.](https://help.github.com/articles/cloning-a-repository/) Install [Node.js][] if you don't have it, then open up a command prompt / terminal in the project directory. ### Quality Assurance Run `npm run lint` to check for spelling errors, type errors, code style issues, and other problems. Run `npm run format` to automatically fix formatting issues, or `npx eslint --fix` to fix all auto-fixable issues. The formatting rules are configured for compatibility with VS Code's built-in formatter. Run `npm test` to run browser-based tests with Cypress. (It's slow to start up and run tests, unfortunately.) Run `npm run accept` to accept any visual changes. This unfortunately re-runs all the tests, rather than accepting results of the previous test, so you could end up with different results than the previous test. If you use [GitHub Desktop](https://desktop.github.com/), you can view diffs of images, in four different modes. To open the Cypress UI, first run `npm run test:start-server`, then concurrently `npm run cy:open` ### Web App (https://jspaint.app) After you've installed dependencies with `npm i`, use `npm run dev` to start a live-reloading server. Make sure any layout-important styles go in `layout.css`. When updating `layout.css`, a right-to-left version of the stylesheet is generated, using [RTLCSS](https://rtlcss.com/). You should test the RTL layout by changing the language to Arabic or Hebrew. Go to **Extras > Language > العربية** or **עברית**. See [Control Directives](https://rtlcss.com/learn/usage-guide/control-directives/) for how to control the RTL layout. There is a VS Code launch task for attaching to Chrome for debugging. See `.vscode/launch.json` for usage instructions. ### Desktop App (Electron) - Install dependencies with `npm i` - Start the electron app with `npm run electron:start` [electron-debug][] is included, so you can use F5/Ctrl+R to reload and F12/Ctrl+Shift+I to open the devtools. You can build for production with `npm run electron:make` There is a VS Code launch task for debugging the Electron main process. For the renderer process, you can use the embedded Chrome DevTools. [Live Server]: https://github.com/1j01/live-server [Node.js]: https://nodejs.org/ [electron-debug]: https://github.com/sindresorhus/electron-debug ## Deployment JS Paint can be deployed using a regular web server. Nothing needs to be compiled. ### CORS proxy Optionally, you can set up a [CORS Anywhere](https://github.com/Rob--W/cors-anywhere) server, for loading images from the web, if you paste a URL into JS Paint, or use the `#load:` feature with images that are not on the same domain. By default it will use a [CORS Anywhere instance](https://jspaint-cors-proxy.herokuapp.com) set up to work with [jspaint.app](https://jspaint.app). It is hosted for free on [Heroku](https://www.heroku.com/), and you can set up your own instance and configure it to work with your own domain. You'll have to find and replace `https://jspaint-cors-proxy.herokuapp.com` with your own instance URL. ### Multiplayer Support Multiplayer support currently relies on Firebase, which is not open source software. You could create a [Firebase Realtime Database](https://firebase.google.com/docs/database/web/start) instance and edit JS Paint's `sessions.js` to point to it, replacing the `config` passed to `initializeApp` with the config from the Firebase Console when you set up a Web App. But the multiplayer mode is very shoddy so far. It should be replaced with something open source, more secure, more efficient, and more robust. ## Embed in your website ### Simple Add this to your HTML: ```html ``` #### Start with an image You can have it load an image from a URL by adding `#load:` to the URL. ```html ``` ### Advanced If you want to control JS Paint, how it saves/loads files, or access the canvas directly, there is an unstable API. First you need to [clone the repo](https://help.github.com/articles/cloning-a-repository/), so you can point an `iframe` to your local copy. The local copy of JS Paint has to be hosted on the same web server as the containing page, or more specifically, it has to share the [same origin](https://en.wikipedia.org/wiki/Same-origin_policy). Having a local copy also means things won't break any time the API changes. If JS Paint is cloned to a folder called `jspaint`, which lives in the same folder as the page you want to embed it in, you can use this: ```html ``` If it lives somewhere else, you may need to add `../` to the start of the path, to go up a level. For example, `src="../../apps/jspaint/index.html"`. You can also use an absolute URL, like `src="https://example.com/cool-apps/jspaint/index.html"`. #### Changing how files are saved/loaded You can override the file saving and opening dialogs with JS Paint's `systemHooks` API. ```html ``` A [Blob](https://developer.mozilla.org/en-US/docs/Web/API/Blob) represents the contents of a file in memory. A file handle is anything that can identify a file. You get to own this concept, and define how to identify files. It could be anything from an index into an array, to a Dropbox file ID, to an IPFS URL, to a file path. It can be any type, or maybe it needs to be a string, I forget. Once you have a concept of a file handle, you can implement file pickers using the system hooks, and functions to read and write files. | Command | Hooks Used | | ------- | ---------- | | **File > Save As** | [`systemHooks.showSaveFileDialog`][], then when a file is picked, [`systemHooks.writeBlobToHandle`][] | | **File > Open** | [`systemHooks.showOpenFileDialog`][], then when a file is picked, [`systemHooks.readBlobFromHandle`][] | | **File > Save** | [`systemHooks.writeBlobToHandle`][] (or same as **File > Save As** if there's no file open yet) | | **Edit > Copy To** | [`systemHooks.showSaveFileDialog`][], then when a file is picked, [`systemHooks.writeBlobToHandle`][] | | **Edit > Paste From** | [`systemHooks.showOpenFileDialog`][], then when a file is picked, [`systemHooks.readBlobFromHandle`][] | | **File > Set As Wallpaper (Tiled)** | [`systemHooks.setWallpaperTiled`][] if defined, else [`systemHooks.setWallpaperCentered`][] if defined, else same as **File > Save As** | | **File > Set As Wallpaper (Centered)** | [`systemHooks.setWallpaperCentered`][] if defined, else same as **File > Save As** | | **Extras > Render History As GIF** | Same as **File > Save As** | | **Colors > Save Colors** | Same as **File > Save As** | | **Colors > Get Colors** | Same as **File > Open** | #### Loading a file initially To start the app with a file loaded for editing, wait for the app to load, then call [`systemHooks.readBlobFromHandle`][] with a file handle, and tell the app to load that file blob. ```js const file_handle = "initial-file-to-load"; systemHooks.readBlobFromHandle(file_handle).then(file => { if (file) { contentWindow.open_from_file(file, file_handle); } }, (error) => { // Note: in some cases, this handler may not be called, and instead an error message is shown by readBlobFromHandle directly. contentWindow.show_error_message(`Failed to open file ${file_handle}`, error); }); ``` This is clumsy, and in the future there may be a query string parameter to load an initial file by its handle. (Note to self: it will need to wait for your system hooks to be registered, somehow.) There's already a query string parameter to load from a URL: ```html ``` But this won't set up the file handle for saving. #### Integrating Set as Wallpaper You can define two functions to set the wallpaper, which will be used by **File > Set As Wallpaper (Tiled)** and **File > Set As Wallpaper (Centered)**. - [`systemHooks.setWallpaperTiled`][]` = (canvas) => { ... };` - [`systemHooks.setWallpaperCentered`][]` = (canvas) => { ... };` If you define only [`systemHooks.setWallpaperCentered`][], JS Paint will attempt to guess your screen's dimensions and tile the image, applying it by calling your [`systemHooks.setWallpaperCentered`][] function. If you don't specify [`systemHooks.setWallpaperCentered`][], JS Paint will default to saving a file (` wallpaper.png`) using [`systemHooks.showSaveFileDialog`][] and [`systemHooks.writeBlobToHandle`][]. Here's a full example supporting a persistent custom wallpaper as a background on the containing page: ```js const wallpaper = document.querySelector("body"); // or some other element jspaint.systemHooks.setWallpaperCentered = (canvas) => { canvas.toBlob((blob) => { setDesktopWallpaper(blob, "no-repeat", true); }); }; jspaint.systemHooks.setWallpaperTiled = (canvas) => { canvas.toBlob((blob) => { setDesktopWallpaper(blob, "repeat", true); }); }; function setDesktopWallpaper(file, repeat, saveToLocalStorage) { const blob_url = URL.createObjectURL(file); wallpaper.style.backgroundImage = `url(${blob_url})`; wallpaper.style.backgroundRepeat = repeat; wallpaper.style.backgroundPosition = "center"; wallpaper.style.backgroundSize = "auto"; if (saveToLocalStorage) { const fileReader = new FileReader(); fileReader.onload = () => { localStorage.setItem("wallpaper-data-url", fileReader.result); localStorage.setItem("wallpaper-repeat", repeat); }; fileReader.onerror = () => { console.error("Error reading file (for setting wallpaper)", file); }; fileReader.readAsDataURL(file); } } // Initialize the wallpaper from localStorage, if it exists try { const wallpaper_data_url = localStorage.getItem("wallpaper-data-url"); const wallpaper_repeat = localStorage.getItem("wallpaper-repeat"); if (wallpaper_data_url) { fetch(wallpaper_data_url).then(response => response.blob()).then(file => { setDesktopWallpaper(file, wallpaper_repeat, false); }); } } catch (error) { console.error(error); } ``` It's a little bit recursive, sorry; it could probably be done simpler. Like by just using data URLs. (Actually, I think I wanted to use blob URLs just so that it doesn't bloat the DOM inspector with a super long URL. Which is really a devtools UX bug. Maybe they've improved this?) #### Specifying the canvas size You can load a file that has the desired dimensions. There's no special API for this at the moment. See [Loading a file initially](#loading-a-file-initially). #### Specifying the theme You could change the theme programmatically: ```js var iframe = document.getElementById("jspaint-iframe"); var jspaint = iframe.contentWindow; jspaint.set_theme("modern.css"); ``` but this will break the user preference. The **Extras > Themes** menu will still work, but the preference won't persist when reloading the page. In the future there may be a query string parameter to specify the default theme. You could also fork jspaint to change the default theme. #### Specifying the language Similar to the theme, you can try to change the language programmatically: ```js var iframe = document.getElementById("jspaint-iframe"); var jspaint = iframe.contentWindow; jspaint.set_language("ar"); ``` but this will actually **ask the user to reload the application** to change languages. The **Extras > Language** menu will still work, but the user will be bothered to change the language every time they reload the page. In the future there may be a query string parameter to specify the default language. You could also fork jspaint to change the default language. #### Adding custom menus Not supported yet. You could fork jspaint and add your own menus. #### Accessing the canvas directly With access to the canvas, you can implement a live preview of your drawing, for example updating a texture in a game engine in realtime. ```js var iframe = document.getElementById("jspaint-iframe"); // contentDocument here refers to the webpage loaded in the iframe, not the image document loaded in jspaint. // We're just reaching inside the iframe to get the canvas. var canvas = iframe.contentDocument.querySelector(".main-canvas"); ``` It's recommended **not** to use this for loading a document, as it won't change the document title, or reset undo/redo history, among other things. Instead use [`open_from_file`][]. #### Performing custom actions If you want to make buttons or other UI to do things to the document, you should (probably) make it undoable. It's very easy, just wrap your action in a call to [`undoable`][]. ```js var iframe = document.getElementById("jspaint-iframe"); var jspaint = iframe.contentWindow; var icon = new Image(); icon.src = "some-folder/some-image-15x11-pixels.png"; jspaint.undoable({ name: "Seam Carve", icon: icon, // optional }, function() { // do something to the canvas }); ``` #### async function `systemHooks.showSaveFileDialog({ formats, defaultFileName, defaultPath, defaultFileFormatID, getBlob, savedCallbackUnreliable, dialogTitle })` [`systemHooks.showSaveFileDialog`]: #systemHooks.showSaveFileDialog Define this function to override the default save dialog. This is used both for saving images, as well as palette files, and animations. Arguments: - `formats`: an array of objects representing types of files, with the following properties: - `formatID`: a string that uniquely identifies the format (may be the same as `mimeType`) - `mimeType` (optional): the file format's designated [media type](https://en.wikipedia.org/wiki/Media_type), e.g. `"image/png"` (palette formats do not have this property) - `name`: the file format's name, e.g. `"WebP"` - `nameWithExtensions`: the file format's name followed by a list of extensions, e.g. `"TIFF (*.tif;*.tiff)"` - `extensions`: an array of file extensions, excluding the dot, with the preferred extension first, e.g. `["bmp", "dib"]` - `defaultFileName` (optional): a suggested file name, e.g. `"Untitled.png"` or the name of an open document. - `defaultPath` (optional): a file handle for a document that was opened, so you can save to the same folder easily. Misnomer: this may not be a path, it depends on how you define file handles. - `defaultFileFormatID` (optional): the `formatID` of a file format to select by default. - `async function getBlob(formatID)`: a function you call to get a file in one of the supported formats. It takes a `formatID` and returns a `Promise` that resolves with a `Blob` representing the file contents to save. - `function savedCallbackUnreliable({ newFileName, newFileFormatID, newFileHandle, newBlob })` (optional): a function you call when the user has saved the file. The `newBlob` should come from `getBlob(newFileFormatID)`. - `dialogTitle` (optional): a title for the save dialog. Note the inversion of control here: JS Paint calls your `systemHooks.showSaveFileDialog` function, and then you call JS Paint's `getBlob` function. Once `getBlob` resolves, you can call the `savedCallbackUnreliable` function which is defined by JS Paint. (Hopefully I can clarify this in the future.) Also note that this function is responsible for saving the file, not just picking a save location. You may reuse your `systemHooks.writeBlobToHandle` function if it's helpful. #### async function `systemHooks.showOpenFileDialog({ formats })` [`systemHooks.showOpenFileDialog`]: #systemHooks.showOpenFileDialog Define this function to override the default open dialog. This is used for opening images and palettes. Arguments: - `formats`: same as `systemHooks.showSaveFileDialog` Note that this function is responsible for loading the contents of the file, not just picking a file. You may reuse your `systemHooks.readBlobFromHandle` function if it's helpful. #### async function `systemHooks.writeBlobToHandle(fileHandle, blob)` [`systemHooks.writeBlobToHandle`]: #systemHooks.writeBlobToHandle Define this function to tell JS Paint how to save a file. Arguments: - `fileHandle`: a file handle, as defined by your system, representing the file to write to. - `blob`: a `Blob` representing the file contents to save. Returns: - `Promise` that resolves with `true` if the file was definitely saved successfully, `false` if an error occurred or the user canceled, or `undefined` if it is not known whether the file was saved successfully, as is the case with file downloading with ``. The promise should not reject; errors should be handled by showing an error message and returning `false`. #### async function `systemHooks.readBlobFromHandle(fileHandle)` [`systemHooks.readBlobFromHandle`]: #systemHooks.readBlobFromHandle Define this function to tell JS Paint how to load a file. Arguments: - `fileHandle`: a file handle, as defined by your system, representing the file to read from. #### function `systemHooks.setWallpaperTiled(canvas)` [`systemHooks.setWallpaperTiled`]: #systemHooks.setWallpaperTiled Define this function to tell JS Paint how to set the wallpaper. See [Integrating Set as Wallpaper](#integrating-set-as-wallpaper) for an example. Arguments: - `canvas`: a `HTMLCanvasElement` with the image to set as the wallpaper. #### function `systemHooks.setWallpaperCentered(canvas)` [`systemHooks.setWallpaperCentered`]: #systemHooks.setWallpaperCentered Define this function to tell JS Paint how to set the wallpaper. See [Integrating Set as Wallpaper](#integrating-set-as-wallpaper) for an example. Arguments: - `canvas`: a `HTMLCanvasElement` with the image to set as the wallpaper. #### function `undoable({ name, icon }, actionFunction)` [`undoable`]: #undoable Use this to make an action undoable. This function takes a snapshot of the canvas, and some other state, and then calls the `actionFunction` function. It creates an entry in the history so it can be undone. Arguments: - `name`: a name for the action, e.g. `"Brush"` or `"Rotate Image 270°"` - `icon` (optional): an `Image` to display in the History window. It is recommended to be 15x11 pixels. - `actionFunction`: a function that takes no arguments, and modifies the canvas. #### function `show_error_message(message, [error])` [`show_error_message`]: #show_error_message Use this to show an error message dialog box, optionally with expandable error details. Arguments: - `message`: plain text to show in the dialog box. - `error` (optional): an `Error` object to show in the dialog box, collapsed by default in a "Details" expandable section. #### function `open_from_file(blob, source_file_handle)` [`open_from_file`]: #open_from_file Use this to load a file into the app. Arguments: - `blob`: a `Blob` object representing the file to load. - `source_file_handle`: a *corresponding* file handle for the file, as defined by your system. Sorry for the quirky API. The API is new, and parts of it have not been designed at all. This was just a hack that I came to depend on, reaching into the internals of JS Paint to load a file. I decided to document it as the first version of the API, since I'll want a changelog when upgrading my usage of it anyways. #### function `set_theme(theme_file_name)` [`set_theme`]: #set_theme Use this to change the look of the application. Arguments: - `theme_file_name`: the name of the theme file to load, one of: - `"classic.css"`: the Windows98 theme. - `"dark.css"`: the Dark theme. - `"modern.css"`: the Modern theme. - `"winter.css"`: the festive Winter theme. - `"occult.css"`: a Satanic theme. #### function `set_language(language_code)` [`set_language`]: #set_language You can kind of use this to change the language of the application. But actually it will show a prompt to the user to change the language, because the application needs to reload to apply the change. And if that dialog isn't in the right language, well, they'll probably be confused. Arguments: - `language_code`: the language code to use, e.g. `"en"` for English, `"zh"` for Traditional Chinese, `"zh-simplified"` for Simplified Chinese, etc. #### Changelog The API will change a lot, but changes will be documented in the [Changelog](CHANGELOG.md). Not just a history of changes, but a migration/upgrading guide. For general project news, click **Extras > Project News** in the app. ## License JS Paint is free and open source software, licensed under the permissive [MIT license](https://opensource.org/licenses/MIT). [![License](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) [![GitHub Repo stars](https://img.shields.io/github/stars/1j01/jspaint?label=GitHub%20Stars&style=social)](https://github.com/1j01/jspaint/stargazers) [![GitHub forks](https://img.shields.io/github/forks/1j01/jspaint?style=social)](https://github.com/1j01/jspaint/network/members) ================================================ FILE: TODO.md ================================================ # ![](images/icons/32x32.png) JS Paint Todo ### Help * Link-esque things * Popups (I'd probably make the text within the popups selectable) * Related topics (I'd probably make this a heading with links instead of the weird context menu thing) * Add topics * In "Tips and Tricks" (which is just a lame section) * Transparency * Multi-user / collaboration / "To share the document On-Line" or whatever * Index * Search * Keyboard support * Interactive tutorials? * Possibly hosted by Clippy, with [ClippyJS](https://www.smore.com/clippy-js) * Links the cat has a good "GetArtsy" animation, which would be good to use especially if talking about stamping and smearing selections * Highlight elements on the page * Be sure to cover undo/redo, and file saving ### Visual * Fill bucket and airbrush cursors are supposed to invert the background in parts. This is not possible with `.png` files. Microsoft Edge also apparently requires `.cur` files for custom cursors. I already have `.cur` files in the repo for the modern theme (unused), and extracted (outside the repo) for the classic theme. I just need to copy them, rename them semantically, use them, and do some testing to see if format fallbacks work as expected. ### Extended editing * Optional fill tolerance (slider that you enable from a settings menu?) * Transparency * Color opacity slider * Toggle between blend and copy (overwrite) modes * Maybe equivalize any rgba(X, X, X, 0) in fill algorithm? There'd still be the possibility of 1/255th opacity pixels, but if you're creating colors from the combination of a color picker and an opacity slider, you might naturally introduce differing zero-opacity color values a lot. * Documents with multiple sub-images * Component to switch between sub-images * Handle undo/redo for sub-images * Animated GIFs * Transparency ([jnordberg/gif.js issue #5](https://github.com/jnordberg/gif.js/issues/5)) * Animated Transparent APNGs * APNG Library: [UPNG.js](https://github.com/photopea/UPNG.js/) (already used for loading/saving PNGs) * Multi-size Icons * Windows ICO ([jBinary can read](https://jdataview.github.io/jBinary.Repo/demo/#ico) and presumably write ICO files) * Mac ICNS * Layered images * Photoshop PSD ([via psd.js](https://github.com/samccone/psd.js) * OpenRaster ORA ([via ora.js](https://github.com/zsgalusz/ora.js)) * Paged Images * PDF (via [pdf.js](https://github.com/mozilla/pdf.js)) (single page already supported) * DjVu (via [djvu.js](https://djvu.js.org/)) * TIFF (via [utif.js](https://github.com/photopea/UTIF.js/)) (single page/frame already supported) * Online (multi-user) and local (single-user) sessions * See [sessions.js](src/sessions.js) * Issues * There's no conflict resolution; user edits revert other user edits * It's not eventually consistent * Cursors from other users that go outside the parent can cause the page to be scrollable * Symmetry, tesselation, painting texture on 3D models, and even an infinite canvas, all could be done with a shared system * For symmetry and tesselation, [geometry can be generated](), and then it can work the same as painting on a 3D model * An infinite canvas engine would generate simple square geometry, but would require support for multiple editable textures (also useful for 3D models) * And of course layers and animations and multi-size icons need a similar system (multiple sub-images) * For 3D model painting, it's important to note there's a few different possible approaches. 1. UV-dynamic, like [Chameleon](https://www-ui.is.s.u-tokyo.ac.jp/~takeo/chameleon/chameleon.htm) & [Chameleon.js](https://tomtung.github.io/chameleon.js/) (can adapt texture resolution as you paint) 2. UV-static 1. Ray tracing the pointer to find texture coordinates (gives texture coordinate space scaled result by default) 2. Screen-space drawing (gives screen space scaled result by default); I saw a good medium post or two about this * Also, some approaches might not extend to tesselation and symmetry. ["Very important, this means that we assume our uv has no overlapping triangles. So no \[tileable\] textures."](https://shahriyarshahrabi.medium.com/mesh-texture-painting-in-unity-using-shaders-8eb7fc31221c) * Existing 3D texturing systems: * Closed source project: https://discourse.threejs.org/t/a-fully-fledged-texture-painter-for-the-web/15678/16 * Open source project with adaptive UVs: https://tomtung.github.io/chameleon.js/ * Open source project with adaptive and static UV modes, for both painting and sculpting: https://github.com/stephomi/sculptgl (check Dynamic Topology > Activated) * Save text and record transformations so the image can be saved as SVG (or HTML?) with invisible selectable transformed text elements? * Every time you move a selection, duplicate the text and create a clip-path for both parts? * Make only one of them audible for screen-readers ### Device support * Prevent text selection in buttons and history entries * Enlarge menus on touch devices * Enlarge window titlebar close buttons on touch devices * Magnifier: on touchscreens, wait until pointerup to zoom * To detect touchscreen usage, could keep track of whether the last pointermove had any buttons pressed... or use `pointerType`, right? * Alternative way to access "Color Eraser" feature without a secondary mouse button? * Alternative access to functionality that would normally require a keyboard (with a numpad!) * Numpad +/-: Increase/Decrease brush size, Double/Halve selection size, ... * Shift toggles a handful of things (could have one toggle button renamed contextually?): * Proportional Resize * Smear / Trail Selection * Snap to 8 directions * An isometric mode would also be good * Ctrl+Select: "Crop To Selection" menu option * Don't drag toolbars out into windows with touch, it's too easy to do accidentally ### Tools * Select and Free-Form Select * Passive: create no undoables until you do something like move or invert the selection * You should be able to make a selection, then change the secondary color, then drag the selection cutting it out with the color you selected * Select and deselect with no actions in between should create no undoables * Proportionally resize selection while holding Shift * (or maybe by default? I feel like it should be the default, tbh.) * Text * If it would go over the edge of the canvas, reject the input (at least, that's what mspaint does) * Add padding left to text area when font has glyphs that extend left, like italic 'f' in Times New Roman * mspaint has access to font metrics * jspaint could render text to see when it would overflow * To do it efficiently, * Take all glyphs in the text * (And maybe a set of common letters like the alphabet) * Split with a library to handle Unicode (emojis etc.) * Uniquify * Place them *all on top of each other*, positioned absolutely, leaving room to the left of them to detect pixels * Scan the pixels at the left to find the maximum extent left * Could store, per font, what glyphs have been tested and what's the maximum extent detected, in order to not have to rerender these * "What glyphs have been tested" should be specific to font size and attributes, since an italic 'f' may extend more than a normal 'f' for instance * Store position of FontBox * Shape Styles * Shapes: respond to Ctrl (It's complicated) * Patterns (black and white mode, winter theme) * Check to make sure patterns are aligned properly for all the tools * There's supposed to be a mapping between color values and pattern fills, used by the text tool and for the palette when switching between modes (colors should be kept between going to black and white mode and back) ### Desktop App (Electron) Electron boilerplate stuff: * Remember window position/state * Set up autoupdating * Keep window hidden until loaded (`show: false`, [`ready-to-show`](https://electronjs.org/docs/api/browser-window#event-ready-to-show)) Security: * Context isolation * Disable multiplayer?? should be fine Functionality: * Subwindows as separate windows * Document recovery without having to know about File > Manage Storage - pop up contextually with a dialog when you need it * Show link URLs when you hover over them, in the status bar (because we have a status bar! haha) (there's this API: [event: update-target-url](https://github.com/electron/electron/blob/master/docs/api/web-contents.md#event-update-target-url), which gave me the idea, or it could be implemented with mouse events) * Recent files (could also be implemented for 98.js.org in the future) * macOS: * `win.setSheetOffset` with the menu bar height * Windows: maybe handle `session-end` event and ask to save? * Detect if file changes on disk, ask if you want to reload it? ### Also * Anything marked `@TODO` or `@FIXME` in the source code * See [Issues on GitHub](https://github.com/1j01/jspaint/issues) * CSS * DRY, especially button styles, with [os-gui](https://github.com/1j01/os-gui) * Clearer `z-index` handling, maybe with CSS variables? * JS * Organize things into files better; "functions.js" is like ONE step above saying "code.js" * `$ToolWindow` has a `$Button` facility; `$DialogWindow` overrides it with essentially a better one; now there's `showMessageBox` too! and `$ToolWindow` is a wrapper for OS-GUI's `$Window`, and should be removed at some point; btw, should `show_error_message` functionality be folded into `showMessageBox`? * Make code clearer / improve code quality * https://codeclimate.com/github/1j01/jspaint * Images * Use a shared sprite sheet per theme (and optimize it I guess) ================================================ FILE: about.html ================================================ JS Paint — MS Paint online


JS Paint

JS Paint is a pixel-perfect remake of Microsoft Paint that runs in the browser.

Free Open source under the permissive MIT License.

Ideas Request features and report bugs on GitHub or by email.

THIS SITE IS... Under Construction Paint bucket
untitled - Paint
hand pointing left Try me!

More info Read about the project and extra features on the readme.

$ Support the project at paypal.me/IsaiahOdhner.

Windows 98 online

Windows logo button Windows 98 flag pole animation JS Paint is also included in a web-based version of Windows 98, along with Notepad, Minesweeper, Sound Recorder, Calculator, and Winamp.




Desktop Version (New!)

built with Electron
screenshot of JS Paint Electron app running on macOS

For a more native experience, you can install the JS Paint desktop app. It works on Windows, macOS, and Linux.

Features:

  • Runs offline
  • Clipboard support
  • Open and save files like a native app
  • Set wallpaper from File menu

Download Here Grey tabby cat

Progressive Web App

JS Paint on a phone

Alternatively, you can install JS Paint as a PWA (Progressive Web App), but this does not yet support offline use (as it doesn't include a Service Worker). It's more like a bookmark (for now), except it runs in a special window.

The user interface for installing PWAs differs by browser and operating system.

On most desktop browsers, the install prompt is in the URL bar. On mobile, the install prompt is generally found in the menu of browser options. See Installing PWAs for visual guidance.

_____ _ _ |_ _|____ _| |_ _ _ __ _| | | |/ -_) \ / _| || / _` | | |_|\___/_\_\\__|\_,_\__,_|_| ___ _ _ | _ \__ _(_)_ _| |_ | _/ _` | | ' \ _| |_| \__,_|_|_||_\__|


I also made a separate elaborate MS Paint clone that runs in the terminal, and edits ANSI art in addition to bitmaps.

You can install it with: pip install textual-paint

And then run with simply: textual-paint

Requires Python 3.10 or later, and a terminal emulator with Unicode and true color support.

  • Windows logo Runs well in Windows Terminal, but not in the older Windows Console.
  • Macintosh logo Runs well in iTerm2, but not the built in macOS Terminal.app.
  • Linux mascot Tux the penguin Runs well in GNOME Terminal, and most Linux terminal emulators, but not the Linux console.
screenshot of Textual Paint showing the About Paint dialog Computer typing on its own keyboard

Textual Paint was built using the Textual framework, which was very fun to work with!

I may have more Paint projects planned, the mad man that I am. 🎨

What's more retro than a terminal-based Paint program, I wonder?

Other Projects

Home button Check out my home page for more projects!

Created by
Isaiah Odhner

LEGO Junkbot minifig eating a recycling bin
Guitar film reel Dat Boi Dat Boi

Here are some buttons I made

Feel free to copy these to your site! Some of them are rubbish, but a few of them I'm quite happy with.

Right click on the image and select "Save image as..." to download it, then copy and paste the HTML code below it into your site, and update the src attribute to point to where you're hosting the image.

JS Paint JS Paint JS Paint JS Paint JS Paint Made with JS Paint Made with JS Paint 98.JS It's dangerous to go alone. Take this, Now! (Legend of Zelda parody) Powered by turbo encabulator Built with VS Code Built with VS Code Windows 7 is still better than Windows 11 Creative constraints (doodle progress animation) Creative constraints I hate Electron! How Now! (brown cow) Play LEGO Junkbot Play LEGO Junkbot Play LEGO Junkbot Play LEGO Junkbot Panel 1. Jon is sitting on the sofa reading the newspaper, and he searches the table beside him with his hand. Panel 2. Jon, no longer relaxing with his leg kicked up turns to face the viewer, and thinks to himself, "Now where could my pipe be?" Panel 3. Garfield, Jon's orange tabby cat, is smoking Jon's pipe. Jon is shocked and shouts from off-screen "Garfield!!" A little bit of everything, Now! Get uBlock Origin now! Get uBlock Origin now!

Here are some buttons I collected

I don't know where most of these came from, and I've repurposed some of them.

Long live MS Paint! Made with Mouse Made with Microsoft Windows 98. Get! This is an anti-NFT site. NFT - No Fucking Thanks Get Paint.NET graphic design is my passion Fight for open web standards. Fight for online privacy. Fight against monopolistic practices. Stand up to Google! I miss Windows XP Internet Archive Is it slow? Say so! Please do not force this img to be lonely Network neighborhood Visual Studio Code WebDisk, Now I use MS Paint 98 Plus! Get Flashpoint web game archive Up all night Bookmark this page CSS is difficult Made for dark mode DuckDuckGo Delete Twitter. Make a Neocities. Despacito, Now! Something completely different, Now! Winamp bubbles eSheep, Now! EZGIF.COM, Now! A folder with several tabs Games Powered by Microsoft GitHub Pages Check out my GitHub!
================================================ FILE: browserconfig.xml ================================================ #008080 ================================================ FILE: cspell.json ================================================ { "ignorePaths": [ ".history", // VS Code "Local History" extension "node_modules", "lib", "out", // Electron Forge output "*.png", "*.gif", "*.jpg", "*.jpeg", "*.svg", "*.cur", "*.ico", "*.icns", "*.wav", "*.psd", "*.mp4", "localization" ], "words": [ "abcdefghijklmnopqrstuvwxyzabcdef", "Adlm", "airb", "airbrushbrush", "Allaire", "anypalette", "apng", "appinstalled", "argparse", "atombgwht", "autoupdating", "beforeinstallprompt", "bepis", "Bgau", "bigfix", "blackwhite", "Bopo", "Bresenham", "Bresenham's", "browserconfig", "checkmarks", "clipart", "Clippy", "clmtrackr", "cloudflared", "clsid", "cmaps", "colorbar", "colorbox", "colorstr", "colyseus", "contenteditable", "Corel", "ctype", "Darude", "datetime", "dectree", "desaturated", "Despacito", "discoverability", "divs", "djvu", "documentedly", "duplicately", "ellipticals", "encabulator", "endonym", "endregion", "equivalize", "ertical", "espree", "esque", "Excelsi", "eyedrop", "EZGIF", "farbling", "fieldsets", "firebaseapp", "firebaseio", "firstrun", "flagani", "fliph", "flippable", "flipv", "floodfill", "floodfilling", "fontbox", "frowny", "fullscreen", "ghostwhite", "Glag", "gons", "greyscale", "gridlines", "hackily", "haha", "Hanb", "hcanvas", "hctx", "hideothers", "hilight", "HKEY", "homescreen", "hotspot", "hslrgb", "hsrgb", "humbnail", "Icci", "ICNS", "iconify", "IFDs", "iframes", "IIFE", "Imgur", "Inkscape", "IPFS", "isaiahodhner", "isded", "Jasc", "jfif", "jnordberg", "JSGF", "jspaint", "jsperf", "Junkbot", "keyshortcuts", "Khoj", "Kolour", "Konami", "Krita", "labelledby", "lerp", "libgconf", "libtess", "Linb", "linebreak", "liveweb", "llpaper", "localdomain", "localforage", "lookpath", "lors", "Lospec", "lrgb", "ltres", "Luciferi", "Macromedia", "mediump", "menuitemcheckbox", "menuitemradio", "mimg", "minifig", "mobipaint", "Mopaint", "Mousewheel", "msapplication", "msgbox", "MSPaint", "multilines", "multitools", "multitouch", "multiuser", "murl", "Naptha", "nargs", "Nbat", "Neocities", "nesw", "nevermind", "Nkoo", "nocheck", "nomine", "nonblock", "nonwords", "nostri", "numberofcolors", "numpad", "occluder", "octree", "Odhner", "oleobject", "onestep", "Optikey", "orizontal", "OSGUI", "ovaloid", "ovaloids", "oviforms", "paintbucket", "pako", "palettized", "pearlescent", "Peggys", "Phlp", "Photoshop", "pipx", "pixeling", "PLTE", "pointermove", "pointerup", "proch", "proclabel", "pseudorandomly", "psppalette", "qtres", "redoable", "Rege", "relh", "reltopics", "repurposable", "resizer", "retarget", "retargeted", "retrofuturist", "retrofuturistic", "RGBA", "RGBAs", "rightclick", "rotologo", "roundrect", "roundrects", "rrect", "RTLCSS", "sandboxing", "Satana", "Satanas", "Scribus", "scrollbars", "Shft", "Skencil", "sketchpalette", "skeuomorphic", "skypack", "smslant", "sorthweast", "SoundCloud", "spacebar", "spirobrush", "spraycan", "spraypaint", "spraypainting", "spritesheet", "styl", "stylable", "subh", "subrepo", "subwindows", "tesselator", "tessy", "textareas", "textbox", "textboxes", "themeable", "themepack", "throwie", "tileable", "timespan", "titlebar", "togglable", "topich", "tracedata", "Tracky", "Tvcy", "typecheck", "typechecked", "typestyles", "undecagons", "undoable", "undoables", "undock", "undocked", "undos", "unfocusing", "uniquify", "unmaximize", "unminimize", "unpackaged", "unpremultiplied", "unwantedly", "UPNG", "ustom", "UTIF", "vaporwave", "verts", "Viacam", "viewports", "VSNs", "Wayback", "Webamp", "webglcontextlost", "webglcontextrestored", "webp", "wicg", "Winamp", "WINTRAP", "woah", "Wolfie", "xfconf", "xtras", "zoomable", "zoomer", "עברית", "العربية", "𖦹ᯅ𖦹" ] } ================================================ FILE: cypress/cypress-image-snapshot-viewer.js ================================================ // ==UserScript== // @name Cypress Image Snapshot Viewer // @namespace https://github.com/1j01/ // @version 0.1 // @description Show diffs of screenshots within the Cypress Dashboard. Works with images from cypress-image-snapshot. To use, press D in the gallery, and then move the mouse over and out of the image. // @author Isaiah Odhner // @match https://dashboard.cypress.io/* // @grant none // @noframes // ==/UserScript== (function () { "use strict"; let cleanUp = null; function showDiffView(originalImg) { if (cleanUp) { cleanUp(); } var screenshotWidth = originalImg.naturalWidth / 3; var screenshotHeight = originalImg.naturalHeight; originalImg.style.opacity = "0"; var img = document.createElement("img"); img.src = originalImg.src; img.style.position = "absolute"; img.style.left = "0"; img.style.pointerEvents = "all"; img.draggable = false; img.addEventListener("mouseenter", () => { img.style.left = `${-2 * screenshotWidth}px`; }); img.addEventListener("mouseleave", () => { img.style.left = "0"; }); var container = document.createElement("div"); container.style.width = `${screenshotWidth}px`; container.style.height = `${screenshotHeight}px`; container.style.position = "relative"; container.style.overflow = "hidden"; container.style.margin = "auto"; var outerContainer = document.createElement("div"); outerContainer.style.position = "fixed"; outerContainer.style.display = "flex"; outerContainer.style.left = "0"; outerContainer.style.right = "0"; outerContainer.style.top = "0"; outerContainer.style.bottom = "0"; outerContainer.style.zIndex = "100000"; outerContainer.style.pointerEvents = "none"; outerContainer.appendChild(container); container.appendChild(img); document.body.appendChild(outerContainer); cleanUp = () => { originalImg.style.opacity = ""; container.style.transformOrigin = "center center"; container.style.transition = "opacity 0.2s ease, transform 0.2s ease"; container.style.opacity = 0; container.style.transform = "scale(0.9)"; setTimeout(() => { outerContainer.remove(); }, 500); cleanUp = null; }; } addEventListener("keydown", (e) => { if (e.key === "d") { if (cleanUp) { cleanUp(); } else { var originalImg = document.elementFromPoint(innerWidth / 2, innerHeight / 2); if (!originalImg || !originalImg.matches("img")) { console.warn("Didn't find an image in the middle of the page. Found", originalImg); return; } showDiffView(originalImg); } } else if (e.key === "Escape") { if (cleanUp) { cleanUp(); } } }); // mousedown is TAKEN - with stopPropagation, presumably // (useCapture doesn't help) addEventListener("pointerdown", (_event) => { if (cleanUp) { cleanUp(); } }); })(); ================================================ FILE: cypress/fixtures/example.json ================================================ { "name": "Using fixtures to represent data", "email": "hello@cypress.io", "body": "Fixtures are a great way to mock data for responses to routes" } ================================================ FILE: cypress/integration/tool-tests.spec.js ================================================ /// context("tool tests", () => { // @TODO: make rounded tools render consistently across platforms const roundedToolsCompareOptions = { failureThreshold: 13, failureThresholdType: "pixel", }; before(() => { cy.visit("/"); cy.setResolution([800, 500]); cy.window().should("have.property", "api_for_cypress_tests"); // wait for app to be loaded }); beforeEach(() => { // eslint-disable-next-line require-await cy.window().then({ timeout: 60000 }, async (win) => { win.api_for_cypress_tests.reset_for_next_test(); }); }); const simulateGesture = (win, { start, end, shift, /*shiftToggleChance = 0.01,*/ secondary, /*secondaryToggleChance,*/ target }) => { target = target || win.$(".main-canvas")[0]; let startWithinRect = target.getBoundingClientRect(); let canvasAreaRect = win.$(".canvas-area")[0].getBoundingClientRect(); let startMinX = Math.max(startWithinRect.left, canvasAreaRect.left); let startMaxX = Math.min(startWithinRect.right, canvasAreaRect.right); let startMinY = Math.max(startWithinRect.top, canvasAreaRect.top); let startMaxY = Math.min(startWithinRect.bottom, canvasAreaRect.bottom); let startPointX = startMinX + start.x * (startMaxX - startMinX); let startPointY = startMinY + start.y * (startMaxY - startMinY); let endPointX = startMinX + end.x * (startMaxX - startMinX); let endPointY = startMinY + end.y * (startMaxY - startMinY); const $cursor = win.$(``); $cursor.css({ position: "absolute", left: 0, top: 0, opacity: 0, zIndex: 5, // @#: z-index pointerEvents: "none", transition: "opacity 0.5s", }); $cursor.appendTo(".jspaint"); let triggerMouseEvent = (type, point) => { const clientX = point.x; const clientY = point.y; // const el_over = win.document.elementFromPoint(clientX, clientY); const do_nothing = false;//!type.match(/move/) && (!el_over || !el_over.closest(".canvas-area")); $cursor.css({ display: "block", position: "absolute", left: clientX, top: clientY, opacity: do_nothing ? 0.5 : 1, }); if (do_nothing) { return; } let event = new win.$.Event(type, { view: window, bubbles: true, cancelable: true, clientX, clientY, screenX: clientX, screenY: clientY, offsetX: point.x, offsetY: point.y, button: secondary ? 2 : 0, buttons: secondary ? 2 : 1, shiftKey: shift, }); win.$(target).trigger(event); }; let t = 0; const stepsInGesture = 3; let pointForTime = (t) => { return { x: startPointX + (endPointX - startPointX) * t, y: startPointY + (endPointY - startPointY) * Math.pow(t, 0.3), }; }; return new Promise((resolve) => { triggerMouseEvent("pointerenter", pointForTime(t)); // so dynamic cursors follow the simulation cursor triggerMouseEvent("pointerdown", pointForTime(t)); let move = () => { t += 1 / stepsInGesture; // if (seededRandom() < shiftToggleChance) { // shift = !shift; // } // if (seededRandom() < secondaryToggleChance) { // secondary = !secondary; // } if (t > 1) { triggerMouseEvent("pointerup", pointForTime(t)); $cursor.remove(); resolve(); } else { triggerMouseEvent("pointermove", pointForTime(t)); /*gestureTimeoutID =*/ setTimeout(move, 10); } }; triggerMouseEvent("pointerleave", pointForTime(t)); move(); }); }; // const gesture = (points) => { // const options = { secondary: false, shift: false }; // // @TODO: while loop // trigger("pointerenter", points[0].x, points[0].y, options); // trigger("pointerdown", points[0].x, points[0].y, options); // let i = 0; // for (; i < points.length; i++) { // trigger("pointermove", points[i].x, points[i].y, options); // } // i--; // trigger("pointerup", points[i].x, points[i].y, options); // }; // it("brush tool", () => { // cy.get(".tool[title='Brush']").click(); // // gesture([{ x: 50, y: 50 }, { x: 100, y: 100 }]); // cy.get(".swatch:nth-child(21)").rightclick(); // cy.window().then({ timeout: 8000 }, async (win) => { // for (let secondary = 0; secondary <= 1; secondary++) { // for (let b = 0; b < 12; b++) { // win.$(`.chooser > :nth-child(${b + 1})`).click(); // const start = { x: 0.05 + b * 0.05, y: 0.1 + 0.1 * secondary }; // const end = { x: start.x + 0.04, y: start.y + 0.04 }; // await simulateGesture(win, { shift: false, secondary: !!secondary, start, end }); // } // } // }); // cy.matchImageSnapshot(); // }); // @TODO: test transparent document mode it("eraser tool", () => { cy.get(".tool[title='Eraser/Color Eraser']").click(); // gesture([{ x: 50, y: 50 }, { x: 100, y: 100 }]); cy.window().then({ timeout: 60000 }, async (win) => { const { selected_colors } = win.api_for_cypress_tests; for (let row = 0; row < 4; row++) { const secondary = !!(row % 2); const increaseSize = row >= 2; let $options = win.$(".chooser > *"); for (let o = 0; o < $options.length; o++) { $options[o].click(); if (increaseSize) { for (let i = 0; i < 5; i++) { win.$("body").trigger(new win.$.Event("keydown", { code: "NumpadAdd" })); } } selected_colors.background = "#f0f"; const start = { x: 0.05 + o * 0.05, y: 0.1 + 0.1 * row }; const end = { x: start.x + 0.04, y: start.y + 0.04 }; await simulateGesture(win, { shift: false, secondary: false, start, end }); if (secondary) { selected_colors.background = "#ff0"; selected_colors.foreground = "#f0f"; const start = { x: 0.04 + o * 0.05, y: 0.11 + 0.1 * row }; const end = { x: start.x + 0.03, y: start.y + 0.02 }; await simulateGesture(win, { shift: false, secondary: true, start, end }); } } } }); cy.get(".main-canvas").matchImageSnapshot(); }); ["Brush", "Pencil", "Rectangle", "Rounded Rectangle", "Ellipse", "Line"].forEach((toolName) => { it(`${toolName.toLowerCase()} tool`, () => { cy.get(`.tool[title='${toolName}']`).click(); // gesture([{ x: 50, y: 50 }, { x: 100, y: 100 }]); cy.get(".swatch:nth-child(22)").rightclick(); cy.window().then({ timeout: 60000 }, async (win) => { for (let row = 0; row < 4; row++) { const secondary = !!(row % 2); const increaseSize = row >= 2; let $options = win.$(".chooser > *"); // Pencil has no options if ($options.length === 0) { $options = win.$(""); } for (let o = 0; o < $options.length; o++) { $options[o].click(); if (increaseSize && (o === 0 || toolName === "Brush" || toolName === "Line")) { for (let i = 0; i < 5; i++) { win.$("body").trigger(new win.$.Event("keydown", { code: "NumpadAdd" })); } } const start = { x: 0.05 + o * 0.05, y: 0.1 + 0.1 * row }; const end = { x: start.x + 0.04, y: start.y + 0.04 }; await simulateGesture(win, { shift: false, secondary: !!secondary, start, end }); } } }); cy.get(".main-canvas").matchImageSnapshot(toolName.match(/Rounded Rectangle|Ellipse/) ? roundedToolsCompareOptions : undefined); }); }); }); ================================================ FILE: cypress/integration/visual-tests.spec.js ================================================ /// context("visual tests", () => { // These tests are not really cross-platform or even cross-computer, // since they depend on pixel-exact text and SVG rendering, as well as browser-specific built-in styles and layout. // Unfortunately, increasing the threshold to a point where the tests pass on all systems would introduce RIDICULOUS false negatives, // like changing the entire icon set wasn't even detected as a change, in Eye Gaze Mode (now Enlarge UI mode), where the icons are HUGE! // And again unfortunately, decreasing the threshold to the point where it detects most changes that matter, // it produces RIDICULOUS false positives, like the window title bar gradient and all text being said to be different, // even on the same machine! In short, the image comparison is unusable. // I suspect it treats a difference between 254 and 255 (white and white) the same as a difference between 0 and 255 (black and white), // and if it just summed the differences instead of counting the number of pixels that differ, it would be much more useful, // although still not cross-device due to font rendering differences etc. // For now, I've removed the thresholds so it will always detect changes; // that way I can at least use it to view the diffs, occasionally, if not automatically check for changes. const withTextCompareOptions = { // failureThreshold: 0.05, // masks HUGE differences // failureThresholdType: "percent" // not actually percent - fraction failureThreshold: 0, failureThresholdType: "pixel", }; const withMuchTextCompareOptions = { // failureThreshold: 0.08, // masks HUGE differences // failureThresholdType: "percent" // not actually percent - fraction failureThreshold: 0, failureThresholdType: "pixel", }; const toolboxCompareOptions = { // failureThreshold: 40, // failureThresholdType: "pixel" failureThreshold: 0, failureThresholdType: "pixel", }; const escapeRegExp = (string) => string.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); // $& means the whole matched string // Menus need pointer events currently. // These "click*" functions are used to interact with menus, and don't trigger click events. const clickElementWithExactText = (selector, text) => { cy.contains(selector, new RegExp(`^${escapeRegExp(text)}$`)) // .click(); .trigger("pointerdown", { which: 1 }) .trigger("pointerup", { force: true }); }; const closeMenus = () => { cy.get(".status-text").click({ force: true }); // force because a menu may be covering the status bar / part of it }; const clickMenuButton = (label) => { clickElementWithExactText(".menu-button", label); }; const clickMenuItem = (label) => { clickElementWithExactText(".menu-item-label", label); }; const selectTheme = (themeName) => { clickMenuButton("Extras"); clickMenuItem("Themes"); clickMenuItem(themeName); closeMenus(); cy.wait(1000); // give a bit of time for theme to load }; // `intercept` requires Cypress 6+ // cypress-image-snapshot@4.0.1 has a peer dependency on cypress@"^4.5.0", // although I believe it works with v9, and only really has problems on v10. // That said, this didn't work! So. No point in upgrading just yet. // I'll upgrade when I'm ready to replace the visual testing framework. // const waitForRequest = (urlPattern, callback) => { // // intercept without changing or stubbing response // cy.intercept(urlPattern).as("urlPattern"); // cy.wait("@urlPattern").then(callback); // }; const waitForImage = (selector) => { // should automatically retries // checking visibility first ensures we're testing at least one image, theoretically cy.get(selector).should("be.visible"); cy.get(selector).should(($imgs) => { for (const img of $imgs) { expect(img.naturalWidth).to.be.greaterThan(0); expect(img.naturalHeight).to.be.greaterThan(0); } }); }; before(() => { // Hides the news indicator, which shouldn't affect the visual tests. // If by the year 3000 AI doesn't automatically find and fix stupid code like this, humanity will have already been doomed. cy.clock(32503698000000); cy.visit("/"); cy.setResolution([760, 490]); cy.window().should("have.property", "api_for_cypress_tests"); // wait for app to be loaded // Needed, given `cy.clock` is used, for `requestAnimationFrame` in `update_$swatch`, // so the color palette is rendered correctly. cy.tick(100); }); it("main screenshot", () => { cy.matchImageSnapshot(withTextCompareOptions); }); it("brush selected", () => { cy.get('.tool[title="Brush"]').click(); cy.get(".tools-component").matchImageSnapshot(toolboxCompareOptions); }); it("select selected", () => { cy.get('.tool[title="Select"]').click(); cy.get(".tools-component").matchImageSnapshot(toolboxCompareOptions); }); it("magnifier selected", () => { cy.get('.tool[title="Magnifier"]').click(); cy.get(".tools-component").matchImageSnapshot(toolboxCompareOptions); }); it("airbrush selected", () => { cy.get('.tool[title="Airbrush"]').click(); cy.get(".tools-component").matchImageSnapshot(toolboxCompareOptions); }); it("eraser selected", () => { cy.get('.tool[title="Eraser/Color Eraser"]').click(); cy.get(".tools-component").matchImageSnapshot(toolboxCompareOptions); }); it("line selected", () => { cy.get('.tool[title="Line"]').click(); cy.get(".tools-component").matchImageSnapshot(toolboxCompareOptions); }); it("rectangle selected", () => { cy.get('.tool[title="Rectangle"]').click(); cy.get(".tools-component").matchImageSnapshot(toolboxCompareOptions); }); beforeEach(() => { if (Cypress.$(".window:visible")[0]) { cy.get(".window:visible .window-close-button").click(); cy.get(".window").should("not.be.visible"); } }); it("image attributes window", () => { cy.get("body").type("{ctrl}e"); cy.get(".window:visible").matchImageSnapshot(withMuchTextCompareOptions); }); it("modern dark theme -- image attributes window", () => { selectTheme("Modern Dark"); cy.get("body").type("{ctrl}e"); cy.get(".window:visible").matchImageSnapshot(withMuchTextCompareOptions); }); it("modern dark theme -- custom zoom window", () => { clickMenuButton("View"); clickMenuItem("Zoom"); clickMenuItem("Custom..."); cy.get(".window:visible").matchImageSnapshot(withMuchTextCompareOptions); }); it("bubblegum theme - custom zoom window", () => { // selectTheme("Bubblegum"); // not released yet cy.window().then((win) => { win.api_for_cypress_tests.set_theme("bubblegum.css"); }); clickMenuButton("View"); clickMenuItem("Zoom"); clickMenuItem("Custom..."); cy.get(".window:visible").matchImageSnapshot(withMuchTextCompareOptions); }); it("custom zoom window", () => { selectTheme("Classic Light"); clickMenuButton("View"); clickMenuItem("Zoom"); clickMenuItem("Custom..."); cy.get(".window:visible").matchImageSnapshot(withMuchTextCompareOptions); }); it("flip and rotate window", () => { clickMenuButton("Image"); clickMenuItem("Flip/Rotate"); cy.get(".window:visible").matchImageSnapshot(withMuchTextCompareOptions); }); it("stretch and skew window", () => { clickMenuButton("Image"); clickMenuItem("Stretch/Skew"); waitForImage(".window:visible img"); cy.get(".window:visible").matchImageSnapshot(withTextCompareOptions); }); it("help window", () => { clickMenuButton("Help"); clickMenuItem("Help Topics"); cy.get(".window:visible .folder", { timeout: 10000 }); // wait for sidebar contents to load // @TODO: wait for iframe to load cy.get(".window:visible").matchImageSnapshot(Object.assign({}, withTextCompareOptions, { blackout: ["iframe"] })); }); it("about window", () => { clickMenuButton("Help"); clickMenuItem("About Paint"); waitForImage("#about-paint-icon"); cy.get(".window:visible").matchImageSnapshot(Object.assign({}, withMuchTextCompareOptions, { blackout: ["#maybe-outdated-line", "#jspaint-version"] })); }); const toggleEyeGazeMode = () => { // Eye Gaze Mode has been split into several features. clickMenuButton("Extras"); clickMenuItem("Vertical Color Box"); closeMenus(); clickMenuButton("Extras"); clickMenuItem("Quick Undo Button"); closeMenus(); clickMenuButton("Extras"); clickMenuItem("Dwell Clicker"); closeMenus(); clickMenuButton("Extras"); clickMenuItem("Enlarge UI"); closeMenus(); }; it("eye gaze mode", () => { cy.get('.tool[title="Select"]').click(); toggleEyeGazeMode(); // clickMenuButton("View"); // cy.get("body").trigger("pointermove", { clientX: 200, clientY: 150 }); cy.wait(100); cy.get(".floating-undo-button").should("exist"); cy.matchImageSnapshot(withTextCompareOptions); }); it("bubblegum theme -- eye gaze mode", () => { cy.get(".floating-undo-button").should("exist"); // selectTheme("Bubblegum"); // not released yet cy.window().then((win) => { win.api_for_cypress_tests.set_theme("bubblegum.css"); }); // clickMenuButton("View"); // cy.get("body").trigger("pointermove", { clientX: 200, clientY: 150 }); cy.wait(100); cy.matchImageSnapshot(withTextCompareOptions); }); it("modern light theme -- eye gaze mode", () => { cy.get(".floating-undo-button").should("exist"); selectTheme("Modern Light"); // clickMenuButton("View"); // cy.get("body").trigger("pointermove", { clientX: 200, clientY: 150 }); cy.wait(100); cy.matchImageSnapshot(withTextCompareOptions); }); it("exit eye gaze mode", () => { // this acts as teardown for the eye gaze mode tests toggleEyeGazeMode(); cy.get(".floating-undo-button").should("not.exist"); }); it("modern light theme -- main screenshot", () => { cy.wait(100); // clickMenuButton("View"); // cy.get("body").trigger("pointermove", { clientX: 200, clientY: 150 }); closeMenus(); cy.wait(100); cy.matchImageSnapshot(withTextCompareOptions); }); const test_edit_colors_dialog = (expand = true) => { clickMenuButton("Colors"); clickMenuItem("Edit Colors..."); cy.wait(100); if (expand) { cy.contains("button", "Define Custom Colors >>").click(); } cy.get(".window:visible").matchImageSnapshot(Object.assign({}, withTextCompareOptions)); }; it("modern light theme -- edit colors dialog (expanded)", () => { test_edit_colors_dialog(true); }); it("bubblegum theme -- main screenshot", () => { // selectTheme("Bubblegum"); // not released yet cy.window().then((win) => { win.api_for_cypress_tests.set_theme("bubblegum.css"); }); // clickMenuButton("View"); // cy.get("body").trigger("pointermove", { clientX: 200, clientY: 150 }); cy.wait(100); cy.matchImageSnapshot(withTextCompareOptions); }); it("bubblegum theme -- about window", () => { clickMenuButton("Help"); clickMenuItem("About Paint"); // waitForImage("#about-paint-icon"); // it's actually replaced with a background image in this theme // waitForRequest("/images/bubblegum/bubblegum-paint-128x128.png", () => { // not working // waitForRequest("**/bubblegum-paint-*.png", () => { // not working cy.wait(1000); // wait and hope it's loaded cy.get(".window:visible").matchImageSnapshot(Object.assign({}, withMuchTextCompareOptions, { blackout: ["#maybe-outdated-line", "#jspaint-version"] })); // }); }); it("winter theme -- main screenshot", () => { selectTheme("Winter"); // clickMenuButton("View"); // cy.get("body").trigger("pointermove", { clientX: 200, clientY: 150 }); cy.wait(100); cy.matchImageSnapshot(withTextCompareOptions); }); it("winter theme -- edit colors dialog (expanded)", () => { test_edit_colors_dialog(true); }); it("winter theme -- vertical color box", () => { cy.wait(500); clickMenuButton("Extras"); clickMenuItem("Vertical Color Box"); cy.wait(500); closeMenus(); cy.wait(100); cy.matchImageSnapshot(withTextCompareOptions); }); it("vertical color box", () => { selectTheme("Classic Light"); cy.matchImageSnapshot(withTextCompareOptions); }); it("edit colors dialog", () => { test_edit_colors_dialog(false); }); it("modern light theme -- vertical color box", () => { selectTheme("Modern Light"); cy.matchImageSnapshot(withTextCompareOptions); }); it("about window during pride month", () => { // TODO: DRY with other about window tests and the app loading in the `before` hook, // maybe enable test isolation even though it's slower to load the app every time // June 19, 3000 cy.clock(32518299600000); cy.visit("/"); cy.setResolution([760, 490]); cy.window().should("have.property", "api_for_cypress_tests"); // wait for app to be loaded // Needed, given `cy.clock` is used, for `requestAnimationFrame` in `update_$swatch`, // so the color palette is rendered correctly. // (Doesn't apply to this test.) cy.tick(100); clickMenuButton("Help"); clickMenuItem("About Paint"); waitForImage("#about-paint-icon"); cy.get(".window:visible").matchImageSnapshot(Object.assign({}, withMuchTextCompareOptions, { blackout: ["#maybe-outdated-line", "#jspaint-version"] })); }); }); ================================================ FILE: cypress/plugins/index.js ================================================ // This function is called when a project is opened or re-opened (e.g. due to // the project's config changing) const { addMatchImageSnapshotPlugin, } = require("cypress-image-snapshot/plugin"); module.exports = (on, config) => { // `on` is used to hook into various events Cypress emits // `config` is the resolved Cypress config addMatchImageSnapshotPlugin(on, config); }; ================================================ FILE: cypress/support/commands.js ================================================ import { addMatchImageSnapshotCommand } from "cypress-image-snapshot/command"; addMatchImageSnapshotCommand({ failureThreshold: 0, failureThresholdType: "pixel", customDiffConfig: { threshold: 0 }, capture: "viewport", }); Cypress.Commands.add("setResolution", (size) => { if (Cypress._.isArray(size)) { cy.viewport(size[0], size[1]); } else { cy.viewport(size); } }); ================================================ FILE: cypress/support/index.js ================================================ // *********************************************************** // This support/index.js is processed and // loaded automatically before your test files. // // https://on.cypress.io/configuration import "./commands"; ================================================ FILE: cypress.json ================================================ { "projectId": "6im7v7", "baseUrl": "http://localhost:11822", "video": false } ================================================ FILE: discord-activity/.gitignore ================================================ node_modules *.pem *.log .DS_Store build dist .env ================================================ FILE: discord-activity/README.md ================================================ # Discord Embedded App Starter This repo is a minimal starter-project. Getting an embedded app running in Discord can be complex. The goal of this example is to get you up-and-running as quickly as possible, while making it easy to swap in pieces to fit your embedded app's client and server needs. ## Client architecture The client (aka front-end) is using vanilla JS. ### Server architecture The server (aka back-end) is using Express with typescript. ## Setting up your Discord Application Before we write any code, lets follow the instructions [here](https://discord.com/developers/docs/activities/building-an-activity#step-1-creating-a-new-app) to make sure your Discord application is set up correctly. ## Setting up your environment variables In this directory (`/examples/discord-activity-starter`) we need to create a `.env` file with the OAuth2 variables, as described [here](https://discord.com/developers/docs/activities/building-an-activity#find-your-oauth2-credentials). ```env VITE_CLIENT_ID=123456789012345678 CLIENT_SECRET=abcdefghijklmnopqrstuvwxyzabcdef ``` ### Adding a new environment variable In order to add new environment variables, you will need to do the following: 1. Add the environment key and value to `.env` 2. Add the key to [/examples/discord-activity-starter/packages/client/src/vite-env.d.ts](/examples/discord-activity-starter/packages/client/src/vite-env.d.ts) 3. Add the key to [/examples/discord-activity-starter/packages/server/environment.d.ts](/examples/discord-activity-starter/packages/server/environment.d.ts) This will ensure that you have type safety when consuming your environment variables ## Running your app locally As described [here](https://discord.com/developers/docs/activities/building-an-activity#step-4-running-your-app-locally-in-discord), we encourage using a tunnel solution such as [cloudflared](https://github.com/cloudflare/cloudflared#installing-cloudflared) for local development. To run your app locally, run the following from this directory (/examples/discord-activity-starter) ``` pnpm install # only need to run this the first time pnpm dev pnpm tunnel # from another terminal ``` Be sure to complete all the steps listed [here](https://discord.com/developers/docs/activities/building-an-activity) to ensure your development setup is working as expected. ================================================ FILE: discord-activity/package.json ================================================ { "name": "discord-activity-starter", "private": true, "version": "0.1.0", "description": "A minimal starter project using embedded-app-sdk", "main": "index.js", "scripts": { "dev": "pnpm run --filter \"./packages/**\" --parallel dev", "tunnel": "cloudflared tunnel --url http://localhost:3000" }, "author": "", "license": "ISC", "dependencies": { "express": "^4.19.2" }, "devDependencies": { "@types/express": "^4.17.21", "@types/node": "^20.12.7", "nodemon": "^3.1.0", "npm-run-all2": "^6.0.0", "rimraf": "^5.0.0", "ts-node": "^10.9.1", "typescript": "~5.4.0" } } ================================================ FILE: discord-activity/packages/server/environment.d.ts ================================================ declare global { namespace NodeJS { interface ProcessEnv { VITE_CLIENT_ID: string; CLIENT_SECRET: string; NODE_ENV: "development" | "production"; PORT?: string; PWD: string; } } } export { }; ================================================ FILE: discord-activity/packages/server/package.json ================================================ { "name": "server", "version": "0.1.0", "description": "The app server", "main": "index.js", "scripts": { "start": "npm-run-all build start:prod", "start:prod": "node ./dist/app.js", "dev": "nodemon --watch src -e ts,ejs --exec $npm_execpath start", "build": "npm-run-all build:clean build:tsc", "build:clean": "rimraf dist", "build:tsc": "tsc", "debug:start": "npm-run-all build debug:start:prod", "debug:start:prod": "node --nolazy --inspect-brk=9229 ./dist/app.js" }, "license": "ISC", "dependencies": { "body-parser": "^1.20.2", "dotenv": "^16.0.1", "express-ws": "^5.0.2", "nodemon": "^3.1.0" }, "devDependencies": { "@types/express-ws": "^3.0.4", "npm-run-all2": "^6.0.0" } } ================================================ FILE: discord-activity/packages/server/src/app.ts ================================================ import bodyParser from "body-parser"; import dotenv from "dotenv"; import express, { Application, Request, Response } from "express"; // import enableWs from "express-ws"; import fs from "fs"; import path from "path"; import { fetchAndRetry } from "./utils"; dotenv.config({ path: "../../.env" }); const app: Application = express(); const port: number = Number(process.env.PORT) || 1999; // enableWs(app); app.use(express.json()); const clientSourcePath = path.join(__dirname, "../../../.."); const clientId = process.env.VITE_CLIENT_ID; const clientIdNeedle = "$$$$$CLIENT_ID$$$$$"; // same length as the client ID, just in case const urlPathForPatching = "/src/discord-activity-client.js"; const fsPathForPatching = path.join(clientSourcePath, urlPathForPatching); // Ensure the file exists and prepare it for serving // const patchedFileContent = fs.readFileSync(fsPathForPatching, "utf8").replace(clientIdNeedle, clientId); // // Serve the patched file // app.get(urlPathForPatching, (req, res) => { // res.setHeader("Content-Type", "text/javascript"); // res.send(patchedFileContent); // }); if (!fs.existsSync(fsPathForPatching)) { throw new Error(`Could not find file at ${fsPathForPatching}`); } // Serve the patched file without caching it, for development purposes app.get(urlPathForPatching, (req, res) => { fs.readFile(fsPathForPatching, "utf8", (err, data) => { if (err) { res.status(500).send(err); return; } res.setHeader("Content-Type", "text/javascript"); res.send(data.replace(clientIdNeedle, clientId)); }); }); // if (process.env.NODE_ENV === "production") { // const clientBuildPath = path.join(__dirname, "../../client/dist"); // app.use(express.static(clientBuildPath)); // } // I'm hacking this to work without Vite, without a build step, and without a client folder / monorepo structure. // This will include odds and ends like .git and .env files by default, so we need to exclude them with an extra route, // as .env is a security risk and .git and .history are potentially sensitive as well. app.use((req, res, next) => { // Must be case-insensitive for Windows FS! // There are quite possibly ways to bypass this, with URL encoding or similar... // TODO: use a clean allowed set of files. if (req.path.match(/\.(git|history|env)/i)) { res.status(403).send("Forbidden"); return; } next(); }); app.use(express.static(clientSourcePath)); // Fetch token from developer portal and return to the embedded app app.post("/api/token", async (req: Request, res: Response) => { const response = await fetchAndRetry(`https://discord.com/api/oauth2/token`, { method: "POST", headers: { "Content-Type": "application/x-www-form-urlencoded", }, body: new URLSearchParams({ client_id: process.env.VITE_CLIENT_ID, client_secret: process.env.CLIENT_SECRET, grant_type: "authorization_code", code: req.body.code, }), }); const { access_token } = (await response.json()) as { access_token: string; }; res.send({ access_token }); }); // Simple multiplayer image editing const rooms: { [key: string]: string } = {}; // app.post("/api/rooms", (req: Request, res: Response) => { // const roomId = uuid(); // or the room id might be the Discord Activity instance ID // rooms[roomId] = ""; // res.send({ roomId }); // }); app.get("/api/rooms/:roomId/data", (req: Request, res: Response) => { const { roomId } = req.params; res.send(rooms[roomId]); }); app.put("/api/rooms/:roomId/data", bodyParser.text({ type: "*/*" }), (req: Request, res: Response) => { const { roomId } = req.params; const image = req.body; rooms[roomId] = image; res.send({ success: true }); }); // app.ws("/api/sessions/:session_id", (ws, req) => { // console.log("WebSocket support is enabled") // @ts-ignore // app.ws("/api/session", (ws, req) => { // console.log("WebSocket was opened") // ws.on("message", (msg: string) => { // console.log("Received message", msg) // ws.send(msg) // }) // ws.on("close", () => { // console.log("WebSocket was closed") // }) // }) app.listen(port, () => { // eslint-disable-next-line no-console console.log(`App is listening on port ${port} !`); }); ================================================ FILE: discord-activity/packages/server/src/shared/hello.ts ================================================ export function hello() { console.log("hello from the server's shared folder"); } ================================================ FILE: discord-activity/packages/server/src/utils.ts ================================================ export function sleep(ms: number) { return new Promise((resolve) => setTimeout(resolve, ms)); } /** * This function extends fetch to allow retrying * If the request returns a 429 error code, it will wait and retry after "retry_after" seconds */ export async function fetchAndRetry( input: RequestInfo, init?: RequestInit | undefined, nRetries: number = 3, ): Promise { try { // Make the request const response = await fetch(input, init); // If there's a 429 error code, retry after retry_after seconds // https://discord.com/developers/docs/topics/rate-limits#rate-limits if (response.status === 429 && nRetries > 0) { const retryAfter = Number(response.headers.get("retry_after")); if (Number.isNaN(retryAfter)) { return response; } await sleep(retryAfter * 1000); return await fetchAndRetry(input, init, nRetries - 1); } else { return response; } } catch (ex) { if (nRetries <= 0) { throw ex; } // If the request failed, wait one second before trying again // This could probably be fancier with exponential backoff await sleep(1000); return await fetchAndRetry(input, init, nRetries - 1); } } ================================================ FILE: discord-activity/packages/server/tsconfig.json ================================================ { "compilerOptions": { "outDir": "dist", "target": "es6", "module": "commonjs", "strict": true, "esModuleInterop": true, "skipLibCheck": true, "forceConsistentCasingInFileNames": true }, "include": [ "src/**/*.ts", "./environment.d.ts" ], "exclude": [ "node_modules" ] } ================================================ FILE: eslint.config.mjs ================================================ import js from "@eslint/js"; import stylistic from "@stylistic/eslint-plugin"; import globals from "globals"; /** @type {import("@types/eslint").Linter.FlatConfig[]} */ export default [ { // "if an ignores key is used without any other keys in the configuration object, then the patterns act as global ignores" "ignores": [ "**/node_modules/", "**/.git/", "**/.history/", "**/.idea/", "**/.vscode/", "**/lib/", // vendored dependencies "**/out/", // Electron build "**/build/", // maybe nothing "**/dist/", // maybe nothing "**/localization/*/*.js", // generated files (note that there is some non-generated JS directly in `localization/`, hence not using `**/localization/**/*.js`) ], }, js.configs.recommended, { "linterOptions": { "reportUnusedDisableDirectives": "warn", }, "languageOptions": { "ecmaVersion": 2022, "sourceType": "module", "globals": { ...globals.browser, ...globals.es2022, // libraries "$": "readonly", "jQuery": "readonly", "libtess": "readonly", "firebase": "readonly", "GIF": "readonly", "saveAs": "readonly", "YT": "readonly", "FontDetective": "readonly", "AnyPalette": "readonly", "ImageTracer": "readonly", // os-gui's MenuBar.js // "MenuBar": "readonly", // "MENU_DIVIDER": "readonly", // os-gui's $Window.js // "$Window": "readonly", // "$FormWindow": "readonly", // os-gui's parse-theme.js has more }, }, "plugins": { "@stylistic": stylistic, }, "rules": { "no-undef": "warn", "no-unused-vars": ["warn", { "args": "all", "argsIgnorePattern": "^_", "caughtErrorsIgnorePattern": "^_", // "varsIgnorePattern": "^_", }], // "eqeqeq": "error", // "class-methods-use-this": "error", "no-alert": "error", "no-extend-native": "error", "no-extra-bind": "error", "no-invalid-this": "error", "no-new-func": "error", "no-eval": "error", "no-new-wrappers": "error", "no-proto": "error", "no-return-assign": "error", "no-script-url": "error", "no-self-compare": "error", "no-sequences": "error", "no-throw-literal": "error", "no-unmodified-loop-condition": "error", "no-unused-expressions": "error", // Tip: `a && a();` can become `a?.();` https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Optional_chaining "no-useless-concat": "error", "prefer-promise-reject-errors": "error", "radix": "error", "require-await": "error", // "vars-on-top": "error", "no-label-var": "error", // "no-shadow": "error", // "no-use-before-define": "error", // To target specific variables to rename or otherwise address: "no-restricted-globals": ["error", "event", "canvas", "ctx", "colors", "i", "j", "k", "x", "y", "z", "width", "height", "w", "h"], // Stylistic: "@stylistic/array-bracket-newline": ["error", "consistent"], "@stylistic/array-bracket-spacing": ["error", "never"], // "@stylistic/array-element-newline": ["error", "consistent"], // lot of big arrays with sometimes meaningful line breaks; could exclude certain files though "@stylistic/arrow-parens": ["error", "always"], "@stylistic/arrow-spacing": ["error", { "before": true, "after": true }], "@stylistic/block-spacing": ["error", "always"], "@stylistic/brace-style": ["error", "1tbs", { "allowSingleLine": true }], "@stylistic/comma-dangle": ["error", { "arrays": "always-multiline", // ensure commas to avoid confusing git diffs "objects": "always-multiline", // ensure commas to avoid confusing git diffs "imports": "never", // always a single line anyways "exports": "never", // matches VS Code's default JS/TS formatter "functions": "only-multiline", // commas sometimes avoid confusing git diffs, sometimes are confusing themselves }], "@stylistic/comma-spacing": ["error", { "before": false, "after": true }], "@stylistic/comma-style": ["error", "last"], "@stylistic/computed-property-spacing": ["error", "never"], "@stylistic/dot-location": ["error", "property"], "@stylistic/eol-last": ["error", "always"], // "@stylistic/function-call-argument-newline": ["error", "consistent"], // several places with meaningful line breaks grouping arguments "@stylistic/function-call-spacing": ["error", "never"], // "@stylistic/function-paren-newline": ["error", "multiline-arguments"], // several places with meaningful line breaks grouping arguments "@stylistic/generator-star-spacing": ["error", "after"], // "@stylistic/implicit-arrow-linebreak": ["error", "beside"], // could encourage parens for clarity, but ESLint won't mention that's the reason, so probably not a good idea // The indent settings are mostly defaults copied from https://github.com/eslint-stylistic/eslint-stylistic/blob/c11f1d6f26c13b29fd44c95c908922cb79a0ac82/packages/eslint-plugin/configs/customize.ts#L115-L154 "@stylistic/indent": ["error", "tab", { ArrayExpression: 1, CallExpression: { arguments: 1 }, flatTernaryExpressions: false, FunctionDeclaration: { body: 1, parameters: 1 }, FunctionExpression: { body: 1, parameters: 1 }, ignoreComments: true, // modified from default ignoredNodes: [ "TemplateLiteral *", "JSXElement", "JSXElement > *", "JSXAttribute", "JSXIdentifier", "JSXNamespacedName", "JSXMemberExpression", "JSXSpreadAttribute", "JSXExpressionContainer", "JSXOpeningElement", "JSXClosingElement", "JSXFragment", "JSXOpeningFragment", "JSXClosingFragment", "JSXText", "JSXEmptyExpression", "JSXSpreadChild", "TSUnionType", "TSIntersectionType", "TSTypeParameterInstantiation", "FunctionExpression > .params[decorators.length > 0]", "FunctionExpression > .params > :matches(Decorator, :not(:first-child))", "ClassBody.body > PropertyDefinition[decorators.length > 0] > .key", ], ImportDeclaration: 1, MemberExpression: 1, ObjectExpression: 1, offsetTernaryExpressions: false, outerIIFEBody: 1, SwitchCase: 1, VariableDeclarator: 1, }], "@stylistic/indent-binary-ops": ["error", "tab"], // "@stylistic/jsx-child-element-spacing": "off", // "@stylistic/jsx-closing-bracket-location": "off", // "@stylistic/jsx-closing-tag-location": "off", // "@stylistic/jsx-curly-brace-presence": "off", // "@stylistic/jsx-curly-newline": "off", // "@stylistic/jsx-curly-spacing": "off", // "@stylistic/jsx-equals-spacing": "off", // "@stylistic/jsx-first-prop-new-line": "off", // "@stylistic/jsx-function-call-newline": "off", // "@stylistic/jsx-indent": "off", // "@stylistic/jsx-indent-props": "off", // "@stylistic/jsx-max-props-per-line": "off", // "@stylistic/jsx-newline": "off", // "@stylistic/jsx-one-expression-per-line": "off", // "@stylistic/jsx-pascal-case": "off", // "@stylistic/jsx-props-no-multi-spaces": "off", // "@stylistic/jsx-quotes": "off", // "@stylistic/jsx-self-closing-comp": "off", // "@stylistic/jsx-sort-props": "off", // "@stylistic/jsx-tag-spacing": "off", // "@stylistic/jsx-wrap-multilines": "off", "@stylistic/key-spacing": ["error", { "beforeColon": false, "afterColon": true }], "@stylistic/keyword-spacing": ["error", { "before": true, "after": true }], // "@stylistic/line-comment-position": "off", // "@stylistic/linebreak-style": "off", // "@stylistic/lines-around-comment": ["error", ""], // TODO maybe (so many options...) "@stylistic/lines-between-class-members": ["error", "never"], // "@stylistic/max-len": ["error", ""], // TODO maybe along with changing export {} to individual exports "@stylistic/max-statements-per-line": ["error", { "max": 4 }], // TODO: maybe decrease this // TODO: lint .d.ts files, and ideally JSDoc comments // "@stylistic/member-delimiter-style": ["error", { "multiline": { "delimiter": "semi", "requireLast": true }, "singleline": { "delimiter": "semi", "requireLast": true } }], // "@stylistic/multiline-comment-style": ["error", "separate-lines"], // I use block comments sometimes for disabled code; also this is detecting a few JSDoc comments even though it says it won't without "checkJSDoc" set to true. // "@stylistic/multiline-ternary": ["error", "always-multiline"], // might want to change the ternary style in the future... "@stylistic/new-parens": ["error", "always"], "@stylistic/newline-per-chained-call": ["error", { "ignoreChainWithDepth": 5 }], // TODO: maybe decrease this // "@stylistic/no-confusing-arrow": ["error", { "allowParens": true }], // don't really like the changes this implies in the couple of places it flags // "@stylistic/no-extra-parens": ["error", "all"], // if there are extra parens, it's probably for clarity (TODO: look at the granular options), also, this doesn't seem to detect cases it should for function calls? "@stylistic/no-extra-semi": "error", "@stylistic/no-floating-decimal": "error", // "@stylistic/no-mixed-operators": ["error", ...], // TODO: investigate options "@stylistic/no-mixed-spaces-and-tabs": "error", "@stylistic/no-multi-spaces": "error", "@stylistic/no-multiple-empty-lines": ["error", { "max": 2, "maxEOF": 1 }], // "@stylistic/no-tabs": "off", // I use tabs for indentation, in disabled code, and in template literals "@stylistic/no-trailing-spaces": "error", "@stylistic/no-whitespace-before-property": "error", "@stylistic/nonblock-statement-body-position": ["error", "beside"], // TODO: maybe drop curly braces from single line conditionals // "@stylistic/object-curly-newline": ["error", ""], // TODO: investigate options "@stylistic/object-curly-spacing": ["error", "always"], "@stylistic/object-property-newline": ["error", { "allowAllPropertiesOnSameLine": true }], // "@stylistic/one-var-declaration-per-line": ["error", "always"], // TODO maybe? there is a risk of `let a, b = 0;` leaving `a` as undefined, but sometimes it just looks better, for related variables... "@stylistic/operator-linebreak": ["error", "after"], // not sure about ternary operator tbh // "@stylistic/padded-blocks": "off", // it depends, especially on how much stuff is in the block // "@stylistic/padding-line-between-statements": ["error", ""], // TODO: investigate options, looks very complex // "@stylistic/quote-props": ["error", "consistent"], // I prefer it inconsistent if it's just for a few CSS custom properties when setting several CSS properties at once, especially since it's not going to be consistent with object property shorthand e.g. { "--requires-quotes": requiresQuotes, "quotedForConsistency": true, inconsistent } "@stylistic/quotes": ["error", "double", { "avoidEscape": true, "allowTemplateLiterals": true }], // Note: allowTemplateLiterals allows template literals without any substitutions, and removing "allowTemplateLiterals" doesn't allow them for avoiding escaping "@stylistic/rest-spread-spacing": ["error", "never"], "@stylistic/semi": ["error", "always"], "@stylistic/semi-spacing": ["error", { "before": false, "after": true }], "@stylistic/semi-style": ["error", "last"], "@stylistic/space-before-blocks": ["error", "always"], "@stylistic/space-before-function-paren": ["error", { "anonymous": "always", "named": "never", "asyncArrow": "always", }], "@stylistic/space-in-parens": ["error", "never"], "@stylistic/space-infix-ops": "error", "@stylistic/space-unary-ops": ["error", { "words": true, "nonwords": false, }], // "@stylistic/spaced-comment": ["error", "always"], // TODO: investigate "@stylistic/switch-colon-spacing": ["error", { "after": true, "before": false }], "@stylistic/template-curly-spacing": ["error", "never"], "@stylistic/template-tag-spacing": ["error", "never"], // "@stylistic/type-annotation-spacing": ["error", ""], // TODO: lint TS // "@stylistic/type-generic-spacing": ["error", ""], // TODO: lint TS // "@stylistic/type-named-tuple-spacing": ["error", ""], // TODO: lint TS "@stylistic/wrap-iife": ["error", "inside"], // "@stylistic/wrap-regex": "error", // does that really clarify things? eh "@stylistic/yield-star-spacing": ["error", "after"], }, }, { "files": [ "help/vaporwave.js", "src/app-localization.js", "src/app-state.js", "src/copy-inkscape-labels.js", "src/error-handling-basic.js", "svg-paint/svg-paint.js", "localization/**/*.js", ], "languageOptions": { "sourceType": "script", }, }, { "files": [ "forge.config.js", "src/electron-injected.js", "src/electron-main.js", "sync-package.js", "prune-globals.js", "cypress/plugins/index.js", "localization/*.js", ], "languageOptions": { "sourceType": "commonjs", "globals": { ...globals.node, }, }, }, { "files": [ "cypress/**/*.js", ], "languageOptions": { "globals": { ...globals.mocha, "expect": "readonly", "cy": "readonly", "Cypress": "readonly", }, }, }, ]; ================================================ FILE: forge.config.js ================================================ const sharedDebRpmOptions = { name: "jspaint", productName: "JS Paint", productDescription: "MS Paint clone with extra features", genericName: "Image Editor", homepage: "https://jspaint.app/about", icon: "images/icons/512x512.png", categories: [ "Graphics", ], mimeType: [ // Affects whether the app shows as a recommended app in the "Open With" menu/dialog "image/*", // wildcard doesn't seem to work "image/bmp", "image/gif", "image/jpeg", "image/png", "image/tiff", "image/webp", "image/avif", "image/x-icon", "image/vnd.microsoft.icon", "image/x-win-bitmap", "image/x-icns", "application/x-gimp-palette", ], }; module.exports = { packagerConfig: { icon: "./images/icons/jspaint", name: "JS Paint", executableName: "jspaint", appBundleId: "io.isaiahodhner.jspaint", appCategoryType: "public.app-category.graphics-design", appCopyright: "© 2024 Isaiah Odhner", extendInfo: { // Based on https://gist.github.com/sonnypgs/de2b6a4a4936d5b8e0fe43946002964a // This extends Info.plist to allow dropping files onto the macOS dock icon. // (all files, not just images, since it's much simpler and I support loading palettes from arbitrary text files) CFBundleDocumentTypes: [ { CFBundleTypeName: "All Files", CFBundleTypeRole: "Editor", // * LSHandlerRank: "Alternate", LSItemContentTypes: [ "public.data", "public.content", ], }, ], // *Added, but... I'm not sure what CFBundleTypeRole exactly affects in practice. // The app is an editor, of both images and palettes, but it's not an editor of all file types, // so it's unclear if this is appropriate. // TODO: granular image types? // like https://github.com/electron/forge/issues/492#issuecomment-385956851 }, junk: true, // TODO: assess filtering of files; I see eslint in node_modules, why? prune is true by default ignore: [ ".history", // VS Code "Local History" extension "cypress", // Cypress tests "cypress.json", // Cypress config "browserconfig.xml", // Windows 8/10 start menu tile "about.html", // homepage "parse-rc-file.js", // localization "preprocess.js", // localization /\.rc$/, // localization /\.sh$/, // localization /\.psd$/, // theming source files "images/meta", // images used on README, OpenGraph, etc. (arguably README images could be included) // TODO: "lib/pdf.js/web", // PDF.js UI? (PDF.js is only used as a library, but does it use data from this folder?) // TODO: Bubblegum theme has some files that are embedded in an SVG, so they're not used directly // I'd want to move them to a folder or give them a suffix or something, rather than just ignoring them as they are, // since I may want to use them in the future. ], // TODO: maybe // https://electron.github.io/packager/main/interfaces/Options.html#darwinDarkModeSupport }, makers: [ { name: "@electron-forge/maker-squirrel", config: { name: "jspaint", exe: "jspaint.exe", title: "JS Paint", description: "MS Paint clone with extra features", iconUrl: "https://raw.githubusercontent.com/1j01/jspaint/5af996478e28a32627794526ec9d25a799187119/images/icons/192x192.png", setupIcon: "./images/icons/jspaint.ico", loadingGif: "images/about/flagani.gif", }, }, { name: "@electron-forge/maker-zip", platforms: [ "darwin", // macOS uses a .zip, which may be automatically extracted when opened ], }, { name: "@electron-forge/maker-deb", config: { options: { ...sharedDebRpmOptions, section: "graphics", maintainer: "Isaiah Odhner ", }, }, }, { name: "@electron-forge/maker-rpm", config: { options: { ...sharedDebRpmOptions, license: "MIT", }, }, }, ], publishers: [ { name: "@electron-forge/publisher-github", config: { repository: { owner: "1j01", name: "jspaint", }, prerelease: true, draft: true, }, }, ], }; ================================================ FILE: help/coUA.css ================================================ /* Originally: Cascading Style Sheet for IE4.01 last updated 1-28-98 */ /* for scrollbars and selection color */ @import "../lib/os-gui/build/windows-98.css"; body { background: #FFFFFF; /* background: var(--Info); */ /* color: var(--InfoText); */ color: var(--WindowText); font-size: 70%; font-family: Verdana, Arial, Helvetica, "MS Sans Serif"; } a:link { color: #0000CC; color: var(--HotTrackingColor); } a:active { color: #996699; } a:visited { color: #996699; } p { margin-top: .6em; margin-bottom: .6em; } p.bigfix { margin-top: -.4em; margin-bottom: 0em; } p.margin { /* for SMS links */ margin-left: 2em; margin-top: -1.75em; } p.K2 { margin-top: 0em; margin-left: 10pt; } /* HEADING TAGS */ h1 { font-size: 145%; margin-bottom: .5em; } h2 { font-size: 125%; margin-top: 1.5em; margin-bottom: .5em; } h3 { font-size: 110%; margin-top: 1.2em; margin-bottom: .5em; } h4 { font-size: 105%; margin-top: 1.2em; margin-bottom: .5em; } h5 { font-size: 100%; margin-top: 1.2em; margin-bottom: .5em; } big { font-weight: bold; font-size: 105%; } p.proclabel { /* procedure heading */ font-weight: bold; font-size: 100%; margin-top: 1.2em; } /* LIST TAGS */ ol { margin-top: .6em; margin-bottom: 0em; margin-left: 4em; /* @FIXME */ } ul { margin-top: .6em; margin-bottom: 0em; } ol ul { list-style: disc; margin-top: .6em; } ul ul { list-style: disc; } li { margin-bottom: .7em; margin-left: -2em; } /* TERM AND DEFINITION TAGS */ dl { margin-top: 0em; } dt { font-weight: bold; margin-top: 1em; /* margin-left: 0em; */ /* for SMS terms */ margin-left: 1.5em; } dd { margin-bottom: 0em; /*not currently working*/ margin-left: 1.5em; } dl li { margin-bottom: .7em; } /*list item inside a term/def list*/ dl dl { margin-top: 0em; margin-left: 0em; } /*term/def list inside a term/def list*/ /* TABLE TAGS */ table { font-size: 100%; margin-top: 1em; margin-bottom: 1em; } th { text-align: left; vertical-align: bottom; background: #dddddd; } th.center { text-align: center; } tr { vertical-align: top; } td { /* not used for K2 */ vertical-align: top; background: #eeeeee; } /* MISC. TAGS */ pre { font-family: Courier; font-size: 125%; margin-top: 1.2em; margin-bottom: 1.5em; } code { font-family: Courier; font-size: 125%; } pre code { font-size: 100%; } hr.sms { /* SMS specific rule used under procedure title */ color: black; text-align: left; } hr.iis { /* IIS specific - preceding copyright */ color: black; } ================================================ FILE: help/default.html ================================================ Welcome to Help


Welcome to Help

Use the Help system to learn more about 98.js.org and JS Paint.

  • Find answers to your questions.
  • Browse the online version of the Getting Started book.
  • Connect to the Web to get software updates.
  • Troubleshoot your system.






Original documentation © 1998 Microsoft Corporation, all rights reserved.

================================================ FILE: help/memcopy.html ================================================ Legal Information

Legal Information

Microsoft Windows 98

Information in this document is subject to change without notice. The names of companies, products, people, characters, and/or data mentioned herein are fictitious and are in no way intended to represent any real individual, company, product, or event, unless otherwise noted. Complying with all applicable copyright laws is the responsibility of the user. No part of this document may be reproduced or transmitted in any form or by any means, electronic or mechanical, for any purpose, without the express written permission of Microsoft Corporation.

Microsoft may have patents, patent applications, trademarks, copyrights, or other intellectual property rights covering subject matter in this document. Except as expressly provided in any written license agreement from Microsoft, the furnishing of this document does not give you any license to these patents, trademarks, copyrights, or other intellectual property.

© 1998 Microsoft Corporation. All rights reserved.

Microsoft, ActiveX, BackOffice, MS, MS-DOS, MSN, Windows, and Windows NT are either registered trademarks or trademarks of Microsoft Corporation in the U.S.A. and/or other countries.

Other product and company names mentioned herein may be the trademarks of their respective owners.

================================================ FILE: help/mspaint.hhc ================================================
================================================ FILE: help/mspaint.hhk ================================================
  • ================================================ FILE: help/nobgcolor.css ================================================ /* Originally: Cascading Style Sheet for IE4 build 1008+ */ /* for scrollbars and selection color */ @import "../lib/os-gui/build/windows-98.css"; body { font-size: 70%; font-family: Verdana, Arial, Helvetica, "MS Sans Serif"; } html, body { margin: 0; height: 100%; } #background-animation { position: absolute; left: 0; top: 0; right: 0; bottom: 0; overflow: hidden; } #foreground-contents { position: absolute; left: 0; top: 0; right: 0; bottom: 0; margin-left: 35px; margin-top: 10px; overflow: auto; } #os-logo-link { text-decoration: none; } #os-logo-colorbar { position: absolute; left: 0; right: 0; top: 79px; pointer-events: none; border: 0; height: 1px; /* Permalink - use to edit and share this gradient: http://colorzilla.com/gradient-editor/#ff3100+0,ff3100+14,f7df1e+14,f7df1e+29,63ce30+29,63ce30+43,009cff+43,009cff+43 */ background: #ff3100; /* Old browsers */ background: -moz-linear-gradient(left, #ff3100 0%, #ff3100 14%, #f7df1e 14%, #f7df1e 29%, #63ce30 29%, #63ce30 43%, #009cff 43%, #009cff 43%); /* FF3.6-15 */ background: -webkit-linear-gradient(left, #ff3100 0%,#ff3100 14%,#f7df1e 14%,#f7df1e 29%,#63ce30 29%,#63ce30 43%,#009cff 43%,#009cff 43%); /* Chrome10-25,Safari5.1-6 */ background: linear-gradient(to right, #ff3100 0%,#ff3100 14%,#f7df1e 14%,#f7df1e 29%,#63ce30 29%,#63ce30 43%,#009cff 43%,#009cff 43%); /* W3C, IE10+, FF16+, Chrome26+, Opera12+, Safari7+ */ filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#ff3100', endColorstr='#009cff',GradientType=1 ); /* IE6-9 */ } a:link { color: #0000CC; } a:active { color: #996699; } a:visited { color: #996699; } h1 { font-size: 145%; margin-bottom: .5em; } h2 { font-size: 125%; margin-top: 1.5em; margin-bottom: .5em; } h3 { font-size: 110%; margin-top: 1.2em; margin-bottom: .5em; } h4 { font-size: 105%; } h5 { font-size: 100%; } p.proclabel { font-weight: bold; font-size: 100%; } p { margin-top: .6em; margin-bottom: .6em; } li p { margin-top: 0; margin-bottom: .6em; } ol { margin-top: .5em; margin-bottom: 0em; margin-left: 4em; } ul { margin-top: .6em; margin-bottom: 0em; } ol ul { list-style: disc; margin-top: 2em; } li { padding-bottom: .7em; margin-left: -2em; } dl ul { /* list item inside a def/term */ margin-top: 2em; margin-bottom: 0em; } dl { margin-top: -1em; } ol dl { /* term/def list inside a numbered list */ margin-top: -1.5em; margin-left: 0em; } ol dl dl { /* term/def list inside a term/def list */ margin-top: 0em; margin-left: .2em; } dd { margin-bottom: 0em; /* not currently working */ margin-left: 1.5em; } dt { padding-top: 2em; font-weight: bold; margin-left: 1.5em; } pre { margin-top: 0em; margin-bottom: 1.5em; font-family: Courier; font-size: 125%; } table { font-size: 100%; margin-top: 1em; margin-bottom: 1em; } th.center { text-align: center; } th { text-align: left; background: #dddddd; margin: 3pt; vertical-align: bottom; } tr { vertical-align: top; } td { margin: 3pt; vertical-align: top; } /* MISC. TAGS */ hr.sms { /* SMS specific rule used under procedure title */ color: red; text-align: left; } hr.iis { color: red; } /*IIS specific - preceding copyright*/ /* IE 4.0 TAGS */ /* a:visited { color: #0000FF; } */ p.dis { font-size: 6pt; } ul.onestep { list-style: square; } h5 { } h5.active { background: #000000; color: #FFCC99; } /* -- subheading -- */ h5.subh { color: #660000; margin-bottom: -1em; margin-top: 1.5em; } /* -- procedure heading -- */ h5.proch { margin-bottom: 4pt; color: #003399; } /* -- topic heading -- */ h5.topich { color: #FF0033; margin-bottom: -1em; } /* -- note 'n' tip heading -- */ h5.note { margin-top: 2em; margin-bottom: -1em; color: #99CC99; } /* -- related topics heading -- */ h5.relh { margin-top: 2.25em; margin-bottom: -1em; color: #9933CC; } /* -------------- miscellany 'n' stuff -------------- */ /* intended to applied with
    tags to groups of links */ .dectree { margin-left: 1.33em; margin-top: 1.5em; } div.dectree p { margin-top: 1em; color: orange; } div.dectree p:first-letter { font-size: 3em; color: orange; } a:link .dectree p { color: yellow; } .reltopics { line-height: .5em; margin-top: 2em; } div.reltopics p { margin-top: 1em; } ================================================ FILE: help/online_support.htm ================================================ Technical Support Online


    Additional help via the Internet

    If you have a technical question on a 98.js.org product and can't find your answer in the product Help file or manual, take advantage of one of these online resources:

    • Your primary source for support is the computer manufacturer who provided your software. Your computer manufacturer may provide a web site to help you find answers to technical questions. Check the documentation that came with your computer to determine the availability of an online support site.
    • For the latest technical information on 98.js.org products, you can also find answers at GitHub. From README articles in the repositories, to Troubleshooting that there aren't any Wizards, the repositories on GitHub have the specific resources most likely to help you find the answer to your question. To begin your search, go to Support Online.

    ================================================ FILE: help/paint_airbrush.html ================================================ To create an airbrush effect

    To create an airbrush effect

    1. In the toolbox, click the spray paint can.
    2. At the bottom of the toolbox, click a spray size.
    3. To spray, drag the pointer.

    Notes

    • The default background and foreground colors appear at the left in the color box. You can draw with the foreground color by clicking, or you can draw with the background color by right-clicking.
    • You can undo any number of changes by clicking the Edit menu and then clicking Undo for each change.
    ================================================ FILE: help/paint_blackwhite.html ================================================ To use black and white instead of color

    To use black and white instead of color

    1. On the Image menu, click Attributes.
    2. Click Black and white.
    ================================================ FILE: help/paint_brush.html ================================================ To paint with a brush

    To paint with a brush

    1. In the toolbox, click the brush.
    2. At the bottom of the toolbox, click a brush shape.
    3. To paint, drag the pointer.

    Notes

    • The default background and foreground colors appear at the left in the color box. You can paint with the foreground color by clicking, or you can paint with the background color by right-clicking.
    • You can undo any number of changes by clicking the Edit menu and then clicking Undo for each change.
    ================================================ FILE: help/paint_change_color.html ================================================ To change the color of an existing line

    To change the color of an existing line

    1. In the toolbox, click the inkwell.
    2. In the color box, click a different color.
    3. Position the pointer so that it is touching the line you want to change, and then click.

    Notes

    • If the line is part of a shape, any connecting vertical and horizontal lines will also change to the new color.
    • To make sure you change only the line color and not the surrounding area, you can zoom the picture to a larger size.
    • You can undo any number of changes by clicking the Edit menu and then clicking Undo for each change.

    ================================================ FILE: help/paint_change_size.html ================================================ To change the size of your picture

    To change the size of your picture

    1. On the Image menu, click Attributes.
    2. Click the unit of measurement you want to use for the width and height.
    3. Type the measurements in Width and Height.

    Notes

    • You can also resize your picture by dragging the three image resize handles, located at the bottom right corner and along the bottom and right sides of your picture.
    • If your current picture is bigger than the new size, the picture is cut from the right side and bottom to fit within the smaller area. If your current picture is smaller than the new size, the extra area is filled with the selected background color.
    • You can undo any number of changes by clicking the Edit menu and then clicking Undo for each change.
    ================================================ FILE: help/paint_clear_image.html ================================================ To clear an entire image

    To clear an entire image

    1. If any part of the image is selected, click outside of the selected area.
    2. On the Image menu, click Clear Image.

    Note

    • The current background color will be used to fill the cleared area. You can choose a different background color by right-clicking a color in the color box.

    ================================================ FILE: help/paint_color_box.html ================================================ To show or hide the color box

    To show or hide the color box

    To show the color box, on the View menu, make sure a check mark appears next to Color Box. To hide the color box, click to clear the check mark.

    Note

    • You can drag the color box to any location in the window.
    ================================================ FILE: help/paint_curves.html ================================================ To draw a curve

    To draw a curve

    1. In the toolbox, click the 's' line.
    2. At the bottom of the toolbox, click a line width.
    3. Draw a straight line by dragging the pointer.
    4. Click where you want one arc of the curve to be, and then drag the pointer to adjust the curve. Repeat this step for a second arc.

    Notes

    • The default background and foreground colors appear at the left in the color box. You can paint with the foreground color by clicking, or you can paint with the background color by right-clicking.
    • Each curve must have at least one arc but no more than two.
    • You can undo any number of changes by clicking the Edit menu and then clicking Undo for each change.
    ================================================ FILE: help/paint_custom_colors.html ================================================ To create custom colors

    To create custom colors

    1. In the color box, click the color you want to change.
    2. On the Colors menu, click Edit Colors.
    3. Click Define Custom Colors.
    4. Click the color swatch to change the Hue and saturation (Sat), and then move the slider in the color gradient to change the luminescence (Lum).
    5. Click Add to Custom Colors, and then click OK.

    Notes

    • You can also double click on a color in the color box to edit.
    ================================================ FILE: help/paint_cutout_copy_move.html ================================================ To copy and paste part of a picture

    To copy and paste part of a picture

    1. In the toolbox, click the rectangular selection tool to select a rectangular area or click the free form selection tool to select a free-form area.
    2. Drag the pointer to define the area you want to copy.
    3. Select a method of pasting:
    4. On the Edit menu, click Copy.
    5. On the Edit menu, click Paste.
    6. Drag the selection where you want it.

    Notes

    • You cannot paste graphics when the text tool is selected.
    • You can paste multiple copies of an object by holding down CTRL while you drag the pasted object to a new location. Repeat as needed.
    • You can undo any number of changes by clicking the Edit menu and then clicking Undo for each change.
    • You can remove the selection box by clicking outside the box.
    ================================================ FILE: help/paint_cutout_save.html ================================================ To save part of a picture into another bitmap file

    To save part of a picture into another bitmap file

    1. In the toolbox, click the rectangular selection tool to select a rectangular area or click the free form selection tool to select a free-form area.
    2. Drag the pointer to define the area you want to save.
    3. On the Edit menu, click Copy To.
    4. Specify a folder and a file name, and then click Save.
    ================================================ FILE: help/paint_cutout_select.html ================================================ To select part of a picture

    To select part of a picture

    In the toolbox, click the rectangular selection tool to select a rectangular area, and then drag the pointer diagonally across the area.

    Or, click the free form selection tool to select a free-form area, and then drag the pointer around the area.

    Note

    • You can remove the selection box by clicking outside the box.
    ================================================ FILE: help/paint_enlarge_area.html ================================================ To enlarge the size of the viewing area

    To enlarge the size of the viewing area

    On the View menu, click View Bitmap.

    Your picture fills the entire viewing area. You can return to your former view by clicking anywhere in the picture.

    Notes

    • You cannot make changes to a picture in this view.
    • You can also enlarge the size of the viewing area by hiding the toolbox, color box, or status bar. You do this by clearing their check marks on the View menu.

    ================================================ FILE: help/paint_erase_large.html ================================================ To erase a large area

    To erase a large area

    1. In the toolbox, click the rectangular selection tool to select a rectangular area or click the free form selection tool to select a free-form area.
    2. Drag the pointer to select the area you want to erase.
    3. On the Edit menu, click Clear Selection.

    Note

    • The current background color will be used to fill the cleared area. You can choose a different background color by right-clicking a color in the color box.

    ================================================ FILE: help/paint_erase_small.html ================================================ To erase a small area

    To erase a small area

    1. In the toolbox, click the eraser tool.
    2. At the bottom of the toolbox, click an eraser shape.
    3. Drag the pointer over the area you want to erase.

    Notes

    • The selected background color shows what color the eraser will leave behind. You can change the background color by right-clicking another color in the color box.
    • You can change a specific color (and nothing else) by changing the foreground color to the color you want to erase and the background color to the color you want to replace it with. Then, when you click the eraser, you can right-click to change the color.
    • You can undo any number of changes by clicking the Edit menu and then clicking Undo for each change.

    ================================================ FILE: help/paint_fill.html ================================================ To fill an area or object with color

    To fill an area or object with color

    1. In the toolbox, click the inkwell.
    2. Click the area or object you want to fill.

    Notes

    • If the shape being filled has any breaks in its border, the filling color leaks through to the rest of the drawing area. You can find and close any openings by clicking the View menu, pointing to Zoom, and then clicking Large Size or Custom.
    • The default background and foreground colors appear at the left in the color box. You can fill with the foreground color by clicking, or you can fill with the background color by right-clicking.
    • You can undo any number of changes by clicking the Edit menu and then clicking Undo for each change.
    ================================================ FILE: help/paint_flip_picture.html ================================================ To flip or rotate a picture or object

    To flip or rotate a picture or object

    1. In the toolbox, click the rectangular selection tool to select a rectangular area or click the free form selection tool to select a free-form area.
    2. Drag a box around the item you want to flip or rotate.
    3. At the bottom of the toolbox, select one of the following:
    4. On the Image menu, click Flip/Rotate.
    5. Click the option you want.

    Note

    • You can undo any number of changes by clicking the Edit menu and then clicking Undo for each change.

    ================================================ FILE: help/paint_freeform_lines.html ================================================ To draw a free-form line

    To draw a free-form line

    1. In the toolbox, click the pencil.
    2. To draw the line, drag the pointer.

    Notes

    • The default background and foreground colors appear at the left in the color box. You can draw with the foreground color by clicking, or you can draw with the background color by right-clicking.
    • You can undo any number of changes by clicking the Edit menu and then clicking Undo for each change.
    ================================================ FILE: help/paint_grid.html ================================================ To display gridlines

    To display gridlines

    1. On the View menu, point to Zoom, and then click Custom.
    2. Under Zoom to, click 400%, 600%, or 800%, and then click OK.
    3. On the View menu, point to Zoom, and then click Show Grid.

    Note

    • You can remove the gridlines by repeating step 3 and clearing the Show Grid check mark, or by clicking View, pointing to Zoom, and then clicking Normal Size.
    ================================================ FILE: help/paint_insert_file.html ================================================ To insert a bitmap into the current picture

    To insert a bitmap into the current picture

    1. In the toolbox, click the rectangular selection tool and then drag the pointer to define an area to put the bitmap in.
    2. On the Edit menu, click Paste From.
    3. Locate and double-click the bitmap file you want to insert.
    4. Drag the bitmap where you want it, and then click outside the selection.
    ================================================ FILE: help/paint_invert.html ================================================ To invert all the colors in a picture

    To invert all the colors in a picture

    On the Image menu, click Invert Colors.

    Note

    • Each color is replaced by its color complement. For example, red becomes cyan, and blue becomes yellow.
    ================================================ FILE: help/paint_lines.html ================================================ To draw a straight line

    To draw a straight line

    1. In the toolbox, click the diagonal line tool.
    2. At the bottom of the toolbox, click a line width.
    3. To draw the line, drag the pointer.

    Notes

    • The default background and foreground colors appear at the left in the color box. You can draw with the foreground color by clicking, or you can draw with the background color by right-clicking.
    • You can draw a perfectly horizontal, vertical, or 45-degree diagonal line by holding down SHIFT while dragging.
    ================================================ FILE: help/paint_not_in_color_box.html ================================================ To copy color from one area or object to another

    To copy color from one area or object to another

    1. In the toolbox, click the eyedropper tool.
    2. Click the object whose color you want to copy.
    3. In the toolbox, click the inkwell.
    4. Click the object or area where you want the new color.

    Note

    • To use a color as a background color, or to erase with a color that isn't in the color box, right-click the color in your picture.

    ================================================ FILE: help/paint_ovals.html ================================================ To draw an ellipse or circle

    To draw an ellipse or circle

    1. In the toolbox, click the oval tool.
    2. Drag the pointer diagonally.

      You can draw a perfect circle by holding down SHIFT while you drag.

    Notes

    • You can create a colored fill by clicking a fill style at the bottom of the toolbox. Click a new color in the color box to change the line color, or right-click a new color to change the fill color.
    • The default background and foreground colors appear at the left in the color box. You can draw with the foreground color by clicking, or you can draw with the background color by right-clicking.
    • You can undo any number of changes by clicking the Edit menu and then clicking Undo for each change.
    ================================================ FILE: help/paint_polygons.html ================================================ To draw a polygon

    To draw a polygon

    1. In the toolbox, click the polygon tool.
    2. To draw the polygon, drag the pointer and click at each corner, and then double-click when done.

      To use only 45- and 90-degree angles, hold down SHIFT while dragging.

    Notes

    • The default background and foreground colors appear at the left in the color box. You can draw with the foreground color by clicking, or you can draw with the background color by right-clicking.
    • You can undo any number of changes by clicking the Edit menu and then clicking Undo for each change.
    • You can create a colored fill by clicking a fill style at the bottom of the toolbox.
    ================================================ FILE: help/paint_print.html ================================================ To print a picture

    To print a picture

    On the File menu, click Print.

    Notes

    • You can see how the printed picture will look before you print by clicking the File menu and then clicking Print Preview.
    • You can set margins or change orientation by clicking the File menu and then clicking Page Setup.
    ================================================ FILE: help/paint_rectangles.html ================================================ To draw a rectangle or square

    To draw a rectangle or square

    1. In the toolbox, click the rectangle tool to create a square-cornered shape, or click the round corner box tool to create a round-cornered shape.
    2. To draw a rectangle, drag the pointer diagonally in the direction you want.
    3. To draw a square, hold down SHIFT while dragging the pointer.

    Notes

    • The default background and foreground colors appear at the left in the color box. You can draw with the foreground color by clicking, or you can draw with the background color by right-clicking.
    • You can create a colored fill by clicking a fill style at the bottom of the toolbox.
    • The border width of the box is the same as the thickness selected for the line tools. To change the border thickness, click the line or curve tool in the toolbox, and then click the thickness you want in the box below the toolbox.
    ================================================ FILE: help/paint_set_default_colors.html ================================================ To set the default foreground and background colors

    To set the default foreground and background colors

    Note

    • The default background and foreground colors appear at the left in the color box. The top color chip represents the foreground color. The bottom color chip represents the background color.
    ================================================ FILE: help/paint_skew_picture.html ================================================ To stretch or skew an item

    To stretch or skew an item

    1. In the toolbox, click the rectangular selection tool to select a rectangular area or click the free form selection tool to select a free-form area.
    2. Drag a box around the item you want to change.
    3. On the Image menu, click Stretch/Skew.
    4. Click the stretching or skewing option you want, and then enter the amount.
    5. At the bottom of the toolbox, select one of the following:

    Note

    • You can undo any number of changes by clicking the Edit menu and then clicking Undo for each change.

    ================================================ FILE: help/paint_text.html ================================================ To type and format text

    To type and format text

    1. In the toolbox, click the 'A' button.
    2. To create a text frame, drag the pointer diagonally to the size you want.
    3. On the text toolbar, click the font, size, and style you want for the text.
    4. Click inside the text frame, type the text, and then do any of the following as needed.
      • Move or enlarge the text frame.
      • Click a color to change the color of the text.
      • Click opaque image button in the toolbox to insert the text on a colored background. Then right-click in the color box to change the background color.

    Notes

    • You can view the text toolbar by clicking the View menu and then clicking Text Toolbar. If it obscures part of the Paint window, you can drag the toolbar to any location in the window.
    • You can enter text into a picture only in Normal view.
    • You can insert text into the picture by clicking outside the text frame.
    • When the text tool is selected, you can paste text only. You cannot paste graphics.
    • You can undo any number of changes by clicking the Edit menu and then clicking Undo for each change.

    ================================================ FILE: help/paint_toolbox.html ================================================ To show or hide the toolbox

    To show or hide the toolbox

    To show the toolbox, click the View menu and make sure a check mark appears next to Tool Box. To hide the toolbox, click to clear the check mark.

    Note

    • You can drag the toolbox to any location in the window.
    ================================================ FILE: help/paint_trans_opaque.html ================================================ To specify transparent or opaque drawing

    To specify transparent or opaque drawing

    To specify transparent drawing, on the Image menu, click to clear the check mark next to Draw Opaque. To specify opaque drawing, make sure a check mark appears next to Draw Opaque.

    ================================================ FILE: help/paint_undo.html ================================================ To undo changes

    To undo changes

    On the Edit menu, click Undo.

    Note

    • You can undo any number of changes by clicking the Edit menu and then clicking Undo for each change.

    ================================================ FILE: help/paint_wallpaper.html ================================================ To use a picture as the desktop background

    To use a picture as the desktop background

    1. On the File menu, click either of the following commands:
      • Set As Wallpaper (Tiled) covers the screen with repetitions of your picture.
      • Set As Wallpaper (Centered) places your picture in the center of the screen.
    2. Save the picture.
    3. Go into your system settings to choose the wallpaper.

    Notes

    • JS Paint can't directly set your wallpaper, but it can generate a tiled image the size of your desktop.
    • The Set As Wallpaper (Centered) option doesn't currently use your desktop size, it just saves a copy of the image. You need to make sure in your system settings to choose to center the image.
    ================================================ FILE: help/paint_zoom.html ================================================ To zoom in or out of a picture

    To zoom in or out of a picture

    On the View menu, point to Zoom, and then click Normal Size, Large Size, or Custom.

    Note

    • You can enter text into a picture only in Normal view.

    ================================================ FILE: help/prettify-html.ahk ================================================ ; AutoHotkey script for formatting HTML with DirtyMarkup ; They actually have an API, but I decided to go this route instead of... looking for a CLI... which does exist ; Usage: ; * Open https://www.10bestdesign.com/dirtymarkup/ ; * Check "Allow proprietary attributes" ; * Switch to your editor where you have some HTML ; * Press F12 F12:: ; SetKeyDelay, 69, 69 ; (extra) delays are needed only for interacting with the webpage ; so I've done sleeps below instead ; (they might also be needed if the editor is a webpage) OriginalClipboard := ClipboardAll Clipboard := WinGet, CodeEditorWinID, ID, A Send, ^a Send, ^c ClipWait, 1 If ErrorLevel { MsgBox, Failed to copy from code editor (no change to clipboard in timeout period) Goto, ResetAndEnd } If Trim(Clipboard) = { MsgBox, Failed to copy from code editor (clipboard empty) Goto, ResetAndEnd } WinActivate, DirtyMarkup WinWaitActive, DirtyMarkup, , 1 If ErrorLevel { MsgBox, Failed to activate DirtyMarkup; I'm not gonna open it for u just open it lol (and focus the tab) Goto, ResetAndEnd } Click, 420, 420 Sleep, 50 Send, ^a Sleep, 150 ; not sure this needs to be higher Send, ^v Sleep, 150 ; not sure this needs to be higher Click, 69, 420 Clipboard := Click, 420, 420 Sleep, 50 Send, ^a Sleep, 50 Send, ^c ClipWait, 1 If ErrorLevel { MsgBox, Failed to copy from DirtyMarkup Goto, ResetAndEnd } WinActivate ahk_id %CodeEditorWinID% Send, ^a Send, ^v ResetAndEnd: Clipboard := OriginalClipboard Return ; Shortcut to move to next file ; This could be set up in your editor instead F11:: Send ^0 ; Ctrl+0 focuses the sidebar in VS Code Send {Down}{Enter} Return ================================================ FILE: help/vaporwave.js ================================================ const clouds_img = document.createElement("img"); clouds_img.src = "clouds.jpg"; const mask_img = document.createElement("img"); mask_img.src = "cloud-mask.png"; const something_img = document.createElement("img"); something_img.src = "../images/icons/32x32.png"; const canvas = document.createElement("canvas"); document.getElementById("background-animation").append(canvas); const ctx = canvas.getContext("2d"); const animate = () => { requestAnimationFrame(animate); if ( canvas.width !== mask_img.width || canvas.height !== mask_img.height ) { canvas.width = mask_img.width; canvas.height = mask_img.height; } const clouds_scale = 1; const clouds_width = clouds_img.width * clouds_scale; const clouds_height = clouds_img.width * clouds_scale; const x_extent = (clouds_width - canvas.width) / 2; const y_extent = (clouds_height - canvas.height) / 2; const x_interval_ms = 19000; const y_interval_ms = 7000; const now = performance.now(); if (!( mask_img.complete && mask_img.naturalWidth > 1 && clouds_img.complete && clouds_img.naturalWidth > 1 )) { return; } ctx.drawImage( clouds_img, Math.sin(now / x_interval_ms) * x_extent - x_extent, Math.cos(now / y_interval_ms) * y_extent - y_extent, clouds_width, clouds_height ); if (something_img.complete && something_img.naturalWidth > 1) { let t = now / 5000; ctx.globalAlpha = 0.3 + Math.max(0, Math.sin(-t) * 1); ctx.drawImage( something_img, ~~(Math.sin(-t) * canvas.width * 0.7), ~~(Math.cos(-t) * 70) ); ctx.globalAlpha = 1; } ctx.globalCompositeOperation = "screen"; ctx.drawImage(mask_img, 0, 0); ctx.globalCompositeOperation = "source-over"; ctx.fillStyle = "white"; ctx.fillRect(0, mask_img.naturalHeight, mask_img.naturalWidth, canvas.height); ctx.fillRect(mask_img.naturalWidth, 0, 50, canvas.height); // for scrollbar }; animate(); ================================================ FILE: index.html ================================================ JS Paint ================================================ FILE: jsconfig.json ================================================ { "compilerOptions": { "target": "ES2022", "module": "ES2022", "moduleResolution": "node", // Fixes error TS2792: Cannot find module 'electron'. https://stackoverflow.com/a/46562884/2624876 }, "include": [ "src/**/*", "localization/*.js", "lib/os-gui/os-gui.d.ts" ] } ================================================ FILE: lib/98.css/98.custom-build.css ================================================ /*! 98.css custom build - https://github.com/jdan/98.css */ /** * 98.css * Copyright (c) 2020 Jordan Scales * https://github.com/jdan/98.css/blob/main/LICENSE */ :root { /* Color */ --surface: var(--ButtonFace, #c0c0c0); --button-highlight: var(--ButtonHilight, #ffffff); --button-face: var(--ButtonFace, #dfdfdf); --button-shadow: var(--ButtonShadow, #808080); --window-frame: var(--WindowFrame, #0a0a0a); --dialog-blue: var(--ActiveTitle, #000080); --dialog-blue-light: var(--GradientActiveTitle, #1084d0); --dialog-gray: var(--InactiveTitle, #808080); --dialog-gray-light: var(--GradientInactiveTitle, #b5b5b5); --link-blue: #0000ff; /* Spacing */ --element-spacing: 8px; --grouped-button-spacing: 4px; --grouped-element-spacing: 6px; --radio-width: 12px; --checkbox-width: 13px; --radio-label-spacing: 6px; --range-track-height: 4px; --range-spacing: 10px; /* Some detailed computations for radio buttons and checkboxes */ --radio-total-width-precalc: var(--radio-width) + var(--radio-label-spacing); --radio-total-width: calc(var(--radio-total-width-precalc)); --radio-left: calc(-1 * var(--radio-total-width-precalc)); --radio-dot-width: 4px; --radio-dot-top: calc(var(--radio-width) / 2 - var(--radio-dot-width) / 2); --radio-dot-left: calc( -1 * (var(--radio-total-width-precalc)) + var(--radio-width) / 2 - var( --radio-dot-width ) / 2 ); --checkbox-total-width-precalc: var(--checkbox-width) + var(--radio-label-spacing); --checkbox-total-width: calc(var(--checkbox-total-width-precalc)); --checkbox-left: calc(-1 * var(--checkbox-total-width-precalc)); --checkmark-width: 7px; --checkmark-top: 3px; --checkmark-left: 3px; /* Borders */ --border-width: 1px; /* rtl:ignore */ --border-raised-outer: inset -1px -1px var(--window-frame), inset 1px 1px var(--button-highlight); /* rtl:ignore */ --border-raised-inner: inset -2px -2px var(--button-shadow), inset 2px 2px var(--button-face); /* rtl:ignore */ --border-sunken-outer: inset -1px -1px var(--button-highlight), inset 1px 1px var(--window-frame); /* rtl:ignore */ --border-sunken-inner: inset -2px -2px var(--button-face), inset 2px 2px var(--button-shadow); /* Window borders flip button-face and button-highlight */ /* rtl:ignore */ --border-window-outer: inset -1px -1px var(--window-frame), inset 1px 1px var(--button-face); /* rtl:ignore */ --border-window-inner: inset -2px -2px var(--button-shadow), inset 2px 2px var(--button-highlight); /* Field borders (checkbox, input, etc) flip window-frame and button-shadow */ /* rtl:ignore */ --border-field: inset -1px -1px var(--button-highlight), inset 1px 1px var(--button-shadow), inset -2px -2px var(--button-face), inset 2px 2px var(--window-frame); } /* @font-face { font-family: "Pixelated MS Sans Serif"; src: url("fonts/converted/ms_sans_serif.woff") format("woff"); src: url("fonts/converted/ms_sans_serif.woff2") format("woff2"); font-weight: normal; font-style: normal; } @font-face { font-family: "Pixelated MS Sans Serif"; src: url("fonts/converted/ms_sans_serif_bold.woff") format("woff"); src: url("fonts/converted/ms_sans_serif_bold.woff2") format("woff2"); font-weight: bold; font-style: normal; } body { font-family: Arial; font-size: 12px; color: #222222; } button, label, input, textarea, select, option, ul.tree-view, .window, .title-bar { font-family: "Pixelated MS Sans Serif", Arial; -webkit-font-smoothing: none; font-size: 11px; } h1 { font-size: 5rem; } h2 { font-size: 2.5rem; } h3 { font-size: 2rem; } h4 { font-size: 1.5rem; } u { text-decoration: none; border-bottom: 0.5px solid #222222; } button { box-sizing: border-box; border: none; background: var(--surface); box-shadow: var(--border-raised-outer), var(--border-raised-inner); border-radius: 0; min-width: 75px; min-height: 23px; padding: 0 12px; } .vertical-bar { width: 4px; height: 20px; background: #c0c0c0; box-shadow: var(--border-raised-outer), var(--border-raised-inner); } button:not(:disabled):active { box-shadow: var(--border-sunken-outer), var(--border-sunken-inner); padding: 2px 11px 0 13px; } @media (not(hover)) { button:not(:disabled):hover { box-shadow: var(--border-sunken-outer), var(--border-sunken-inner); } } button:focus { outline: 1px dotted #000000; outline-offset: -4px; } button::-moz-focus-inner { border: 0; } :disabled, :disabled + label { color: var(--button-shadow); } button:disabled, :disabled + label { text-shadow: 1px 1px 0 var(--button-highlight); } .window { box-shadow: var(--border-window-outer), var(--border-window-inner); background: var(--surface); padding: 3px; } .title-bar { background: linear-gradient( 90deg, var(--dialog-blue), var(--dialog-blue-light) ); padding: 3px 2px 3px 3px; display: flex; justify-content: space-between; align-items: center; } .title-bar.inactive { background: linear-gradient( 90deg, var(--dialog-gray), var(--dialog-gray-light) ); } .title-bar-text { font-weight: bold; color: white; letter-spacing: 0; margin-right: 24px; } .title-bar-controls { display: flex; } .title-bar-controls button { padding: 0; display: block; min-width: 16px; min-height: 14px; } .title-bar-controls button:active { padding: 0; } .title-bar-controls button:focus { outline: none; } .title-bar-controls button[aria-label="Minimize"] { background-image: svg-load("./icon/minimize.svg"); background-repeat: no-repeat; background-position: bottom 3px left 4px; } .title-bar-controls button[aria-label="Maximize"] { background-image: svg-load("./icon/maximize.svg"); background-repeat: no-repeat; background-position: top 2px left 3px; } .title-bar-controls button[aria-label="Restore"] { background-image: svg-load("./icon/restore.svg"); background-repeat: no-repeat; background-position: top 2px left 3px; } .title-bar-controls button[aria-label="Help"] { background-image: svg-load("./icon/help.svg"); background-repeat: no-repeat; background-position: top 2px left 5px; } .title-bar-controls button[aria-label="Close"] { margin-left: 2px; background-image: svg-load("./icon/close.svg"); background-repeat: no-repeat; background-position: top 3px left 4px; } .status-bar { margin: 0px 1px; display: flex; gap: 1px; } .status-bar-field { box-shadow: inset -1px -1px #dfdfdf, inset 1px 1px #808080; flex-grow: 1; padding: 2px 3px; margin: 0; } .window-body { margin: var(--element-spacing); } */ fieldset { border-image: url("data:image/svg+xml;charset=utf-8,%3Csvg width='5' height='5' viewBox='0 0 5 5' fill='grey' xmlns='http://www.w3.org/2000/svg'%3E %3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M0 0H5V5H0V2H2V3H3V2H0' fill='white'/%3E %3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M0 0H4V4H0V1H1V3H3V1H0' fill='%23808080'/%3E %3C/svg%3E") 2; padding: calc(2 * var(--border-width) + var(--element-spacing)); padding-block-start: var(--element-spacing); margin: 0; } legend { background: var(--surface); } /* .field-row { display: flex; align-items: center; } [class^="field-row"] + [class^="field-row"] { margin-top: var(--grouped-element-spacing); } .field-row > * + * { margin-left: var(--grouped-element-spacing); } .field-row-stacked { display: flex; flex-direction: column; } .field-row-stacked * + * { margin-top: var(--grouped-element-spacing); } .field-row label { display: inline-flex; align-items: center; } */ input[type="radio"], input[type="checkbox"] { appearance: none; -webkit-appearance: none; -moz-appearance: none; margin: 0; background: 0; position: fixed; opacity: 0; border: none; } input[type="radio"] + label, input[type="checkbox"] + label { line-height: 13px; } input[type="radio"] + label { position: relative; margin-left: var(--radio-total-width); } input[type="radio"] + label::before { content: ""; position: absolute; top: 0; left: calc(-1 * (var(--radio-total-width-precalc))); display: inline-block; width: var(--radio-width); height: var(--radio-width); margin-right: var(--radio-label-spacing); background: url("data:image/svg+xml;charset=utf-8,%3Csvg width='12' height='12' viewBox='0 0 12 12' fill='none' xmlns='http://www.w3.org/2000/svg'%3E %3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M8 0H4V1H2V2H1V4H0V8H1V10H2V8H1V4H2V2H4V1H8V2H10V1H8V0Z' fill='%23808080'/%3E %3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M8 1H4V2H2V3V4H1V8H2V9H3V8H2V4H3V3H4V2H8V3H10V2H8V1Z' fill='black'/%3E %3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M9 3H10V4H9V3ZM10 8V4H11V8H10ZM8 10V9H9V8H10V9V10H8ZM4 10V11H8V10H4ZM4 10V9H2V10H4Z' fill='%23DFDFDF'/%3E %3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M11 2H10V4H11V8H10V10H8V11H4V10H2V11H4V12H8V11H10V10H11V8H12V4H11V2Z' fill='white'/%3E %3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M4 2H8V3H9V4H10V8H9V9H8V10H4V9H3V8H2V4H3V3H4V2Z' fill='white'/%3E %3C/svg%3E"); } input[type="radio"]:active + label::before { background: url("data:image/svg+xml;charset=utf-8,%3Csvg width='12' height='12' viewBox='0 0 12 12' fill='none' xmlns='http://www.w3.org/2000/svg'%3E %3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M8 0H4V1H2V2H1V4H0V8H1V10H2V8H1V4H2V2H4V1H8V2H10V1H8V0Z' fill='%23808080'/%3E %3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M8 1H4V2H2V3V4H1V8H2V9H3V8H2V4H3V3H4V2H8V3H10V2H8V1Z' fill='black'/%3E %3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M9 3H10V4H9V3ZM10 8V4H11V8H10ZM8 10V9H9V8H10V9V10H8ZM4 10V11H8V10H4ZM4 10V9H2V10H4Z' fill='%23DFDFDF'/%3E %3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M11 2H10V4H11V8H10V10H8V11H4V10H2V11H4V12H8V11H10V10H11V8H12V4H11V2Z' fill='white'/%3E %3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M4 2H8V3H9V4H10V8H9V9H8V10H4V9H3V8H2V4H3V3H4V2Z' fill='%23C0C0C0'/%3E %3C/svg%3E"); } input[type="radio"]:checked + label::after { content: ""; display: block; width: var(--radio-dot-width); height: var(--radio-dot-width); top: var(--radio-dot-top); left: var(--radio-dot-left); position: absolute; background: url("data:image/svg+xml;charset=utf-8,%3Csvg width='4' height='4' viewBox='0 0 4 4' fill='none' xmlns='http://www.w3.org/2000/svg'%3E %3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M3 0H1V1H0V2V3H1V4H3V3H4V2V1H3V0Z' fill='black'/%3E %3C/svg%3E"); } input[type="radio"]:focus + label, input[type="checkbox"]:focus + label { outline: 1px dotted #000000; } input[type="radio"][disabled] + label::before { background: url("data:image/svg+xml;charset=utf-8,%3Csvg width='12' height='12' viewBox='0 0 12 12' fill='none' xmlns='http://www.w3.org/2000/svg'%3E %3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M8 0H4V1H2V2H1V4H0V8H1V10H2V8H1V4H2V2H4V1H8V2H10V1H8V0Z' fill='%23808080'/%3E %3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M8 1H4V2H2V3V4H1V8H2V9H3V8H2V4H3V3H4V2H8V3H10V2H8V1Z' fill='black'/%3E %3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M9 3H10V4H9V3ZM10 8V4H11V8H10ZM8 10V9H9V8H10V9V10H8ZM4 10V11H8V10H4ZM4 10V9H2V10H4Z' fill='%23DFDFDF'/%3E %3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M11 2H10V4H11V8H10V10H8V11H4V10H2V11H4V12H8V11H10V10H11V8H12V4H11V2Z' fill='white'/%3E %3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M4 2H8V3H9V4H10V8H9V9H8V10H4V9H3V8H2V4H3V3H4V2Z' fill='%23C0C0C0'/%3E %3C/svg%3E"); } input[type="radio"][disabled]:checked + label::after { background: url("data:image/svg+xml;charset=utf-8,%3Csvg width='4' height='4' viewBox='0 0 4 4' fill='none' xmlns='http://www.w3.org/2000/svg'%3E %3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M3 0H1V1H0V2V3H1V4H3V3H4V2V1H3V0Z' fill='%23808080'/%3E %3C/svg%3E"); } input[type="checkbox"] + label { position: relative; margin-left: var(--checkbox-total-width); } input[type="checkbox"] + label::before { content: ""; position: absolute; left: calc(-1 * (var(--checkbox-total-width-precalc))); display: inline-block; width: var(--checkbox-width); height: var(--checkbox-width); background: var(--Window); box-shadow: var(--border-field); margin-right: var(--radio-label-spacing); } input[type="checkbox"]:active + label::before { background: var(--surface); } input[type="checkbox"]:checked + label::after { content: ""; display: block; width: var(--checkmark-width); height: var(--checkmark-width); position: absolute; top: var(--checkmark-top); left: calc( -1 * (var(--checkbox-total-width-precalc)) + var(--checkmark-left) ); background: url("data:image/svg+xml;charset=utf-8,%3Csvg width='7' height='7' viewBox='0 0 7 7' fill='none' xmlns='http://www.w3.org/2000/svg'%3E %3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M7 0H6V1H5V2H4V3H3V4H2V3H1V2H0V5H1V6H2V7H3V6H4V5H5V4H6V3H7V0Z' fill='black'/%3E %3C/svg%3E"); } input[type="checkbox"][disabled] + label::before { background: var(--surface); } input[type="checkbox"][disabled]:checked + label::after { background: url("data:image/svg+xml;charset=utf-8,%3Csvg width='7' height='7' viewBox='0 0 7 7' fill='none' xmlns='http://www.w3.org/2000/svg'%3E %3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M7 0H6V1H5V2H4V3H3V4H2V3H1V2H0V5H1V6H2V7H3V6H4V5H5V4H6V3H7V0Z' fill='%23808080'/%3E %3C/svg%3E"); } /* input[type="text"], input[type="password"], input[type="email"], select, textarea { padding: 3px 4px; border: none; box-shadow: var(--border-field); background-color: var(--Window); color: var(--WindowText); box-sizing: border-box; -webkit-appearance: none; -moz-appearance: none; appearance: none; border-radius: 0; } input[type="text"], input[type="password"], input[type="email"], select { height: 21px; } input[type="text"], input[type="password"], input[type="email"] { /* For some reason descenders are getting cut off without this *.../ line-height: 2; } input[type="text"]:disabled, input[type="password"]:disabled, input[type="email"]:disabled, textarea:disabled { background-color: var(--surface); } select { appearance: none; -webkit-appearance: none; -moz-appearance: none; position: relative; padding-right: 32px; background-image: svg-load("./icon/button-down.svg"); background-position: top 2px right 2px; background-repeat: no-repeat; border-radius: 0; } select:focus, input[type="text"]:focus, input[type="password"]:focus, input[type="email"]:focus, textarea:focus { outline: none; } */ input[type="range"] { -webkit-appearance: none; width: 100%; background: transparent; } input[type="range"]:focus { outline: none; } input[type="range"]::-webkit-slider-thumb { -webkit-appearance: none; height: 21px; width: 11px; background: url("data:image/svg+xml;charset=utf-8,%3Csvg width='11' height='21' viewBox='0 0 11 21' fill='none' xmlns='http://www.w3.org/2000/svg'%3E %3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M0 0V16H2V18H4V20H5V19H3V17H1V1H10V0Z' fill='white'/%3E %3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M1 1V16H2V17H3V18H4V19H6V18H7V17H8V16H9V1Z' fill='%23C0C7C8'/%3E %3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M9 1H10V16H8V18H6V20H5V19H7V17H9Z' fill='%2387888F'/%3E %3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M10 0H11V16H9V18H7V20H5V21H6V19H8V17H10Z' fill='black'/%3E %3C/svg%3E"); transform: translateY(-8px); } input[type="range"].has-box-indicator::-webkit-slider-thumb { background: url("data:image/svg+xml;charset=utf-8,%3Csvg width='11' height='21' viewBox='0 0 11 21' fill='none' xmlns='http://www.w3.org/2000/svg'%3E %3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M0 0V20H1V1H10V0Z' fill='white'/%3E %3Crect x='1' y='1' width='8' height='18' fill='%23C0C7C8'/%3E %3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M9 1H10V20H1V19H9Z' fill='%2387888F'/%3E %3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M10 0H11V21H0V20H10Z' fill='black'/%3E %3C/svg%3E"); transform: translateY(-10px); } input[type="range"]::-moz-range-thumb { height: 21px; width: 11px; border: 0; border-radius: 0; background: url("data:image/svg+xml;charset=utf-8,%3Csvg width='11' height='21' viewBox='0 0 11 21' fill='none' xmlns='http://www.w3.org/2000/svg'%3E %3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M0 0V16H2V18H4V20H5V19H3V17H1V1H10V0Z' fill='white'/%3E %3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M1 1V16H2V17H3V18H4V19H6V18H7V17H8V16H9V1Z' fill='%23C0C7C8'/%3E %3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M9 1H10V16H8V18H6V20H5V19H7V17H9Z' fill='%2387888F'/%3E %3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M10 0H11V16H9V18H7V20H5V21H6V19H8V17H10Z' fill='black'/%3E %3C/svg%3E"); transform: translateY(2px); } input[type="range"].has-box-indicator::-moz-range-thumb { background: url("data:image/svg+xml;charset=utf-8,%3Csvg width='11' height='21' viewBox='0 0 11 21' fill='none' xmlns='http://www.w3.org/2000/svg'%3E %3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M0 0V20H1V1H10V0Z' fill='white'/%3E %3Crect x='1' y='1' width='8' height='18' fill='%23C0C7C8'/%3E %3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M9 1H10V20H1V19H9Z' fill='%2387888F'/%3E %3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M10 0H11V21H0V20H10Z' fill='black'/%3E %3C/svg%3E"); transform: translateY(0px); } input[type="range"]::-webkit-slider-runnable-track { width: 100%; height: 2px; box-sizing: border-box; background: black; border-right: 1px solid grey; border-bottom: 1px solid grey; /* rtl:ignore */ box-shadow: 1px 0 0 white, 1px 1px 0 white, 0 1px 0 white, -1px 0 0 darkgrey, -1px -1px 0 darkgrey, 0 -1px 0 darkgrey, -1px 1px 0 white, 1px -1px darkgrey; } input[type="range"]::-moz-range-track { width: 100%; height: 2px; box-sizing: border-box; background: black; border-right: 1px solid grey; border-bottom: 1px solid grey; /* rtl:ignore */ box-shadow: 1px 0 0 white, 1px 1px 0 white, 0 1px 0 white, -1px 0 0 darkgrey, -1px -1px 0 darkgrey, 0 -1px 0 darkgrey, -1px 1px 0 white, 1px -1px darkgrey; } .is-vertical { display: inline-block; width: 4px; height: 150px; transform: translateY(50%); } .is-vertical > input[type="range"] { width: 150px; height: 4px; margin: 0 calc(var(--grouped-element-spacing) + var(--range-spacing)) 0 var(--range-spacing); transform-origin: left; transform: rotate(270deg) translateX(calc(-50% + var(--element-spacing))); } .is-vertical > input[type="range"]::-webkit-slider-runnable-track { border-left: 1px solid grey; border-right: 0; border-bottom: 1px solid grey; /* rtl:ignore */ box-shadow: -1px 0 0 white, -1px 1px 0 white, 0 1px 0 white, 1px 0 0 darkgrey, 1px -1px 0 darkgrey, 0 -1px 0 darkgrey, 1px 1px 0 white, -1px -1px darkgrey; } .is-vertical > input[type="range"]::-moz-range-track { border-left: 1px solid grey; border-right: 0; border-bottom: 1px solid grey; /* rtl:ignore */ box-shadow: -1px 0 0 white, -1px 1px 0 white, 0 1px 0 white, 1px 0 0 darkgrey, 1px -1px 0 darkgrey, 0 -1px 0 darkgrey, 1px 1px 0 white, -1px -1px darkgrey; } .is-vertical > input[type="range"]::-webkit-slider-thumb { transform: translateY(-8px) scaleX(-1); } .is-vertical > input[type="range"].has-box-indicator::-webkit-slider-thumb { transform: translateY(-10px) scaleX(-1); } .is-vertical > input[type="range"]::-moz-range-thumb { transform: translateY(2px) scaleX(-1); } .is-vertical > input[type="range"].has-box-indicator::-moz-range-thumb { transform: translateY(0px) scaleX(-1); } /* select:focus { color: var(--HilightText); background-color: var(--Hilight); } select:focus option { color: #000; background-color: #fff; } select:active { background-image: svg-load("./icon/button-down-active.svg"); } */ /* a { color: var(--link-blue); } a:focus { outline: 1px dotted var(--link-blue); } */ /* ul.tree-view { display: block; background: var(--Window); box-shadow: var(--border-field); padding: 6px; margin: 0; } ul.tree-view li { list-style-type: none; } ul.tree-view a { text-decoration: none; color: #000; } ul.tree-view a:focus { background-color: var(--Hilight); color: var(--HilightText); } ul.tree-view ul, ul.tree-view li { margin-top: 3px; } ul.tree-view ul { margin-left: 16px; padding-left: 16px; /* Goes down too far *.../ border-left: 1px dotted #808080; } ul.tree-view ul > li { position: relative; } ul.tree-view ul > li::before { content: ""; display: block; position: absolute; left: -16px; top: 6px; width: 12px; border-bottom: 1px dotted #808080; } /* Cover the bottom of the left dotted border *.../ ul.tree-view ul > li:last-child::after { content: ""; display: block; position: absolute; left: -20px; top: 7px; bottom: 0px; width: 8px; background: var(--Window); } ul.tree-view details { margin-top: 0; } ul.tree-view details[open] summary { margin-bottom: 0; } ul.tree-view ul details > summary:before { margin-left: -22px; position: relative; z-index: 1; } ul.tree-view details > summary:before { text-align: center; display: block; float: left; content: "+"; border: 1px solid #808080; width: 8px; height: 9px; line-height: 8px; margin-right: 5px; padding-left: 1px; background-color: #fff; } ul.tree-view details[open] > summary:before { content: "-"; } */ /* pre { display: block; background: var(--Window); box-shadow: var(--border-field); padding: 12px 8px; margin: 0; } code, code * { font-family: monospace; } summary:focus { outline: 1px dotted #000000; } */ /* ::-webkit-scrollbar { width: 16px; } ::-webkit-scrollbar:horizontal { height: 17px; } ::-webkit-scrollbar-corner { background: var(--button-face); } ::-webkit-scrollbar-track { background-image: svg-load("./icon/scrollbar-background.svg"); } ::-webkit-scrollbar-thumb { background-color: var(--button-face); box-shadow: var(--border-raised-outer), var(--border-raised-inner); } ::-webkit-scrollbar-button:horizontal:start:decrement, ::-webkit-scrollbar-button:horizontal:end:increment, ::-webkit-scrollbar-button:vertical:start:decrement, ::-webkit-scrollbar-button:vertical:end:increment { display: block; } ::-webkit-scrollbar-button:vertical:start { height: 17px; background-image: svg-load("./icon/button-up.svg"); } ::-webkit-scrollbar-button:vertical:end { height: 17px; background-image: svg-load("./icon/button-down.svg"); } ::-webkit-scrollbar-button:horizontal:start { width: 16px; background-image: svg-load("./icon/button-left.svg"); } ::-webkit-scrollbar-button:horizontal:end { width: 16px; background-image: svg-load("./icon/button-right.svg"); } */ /*# sourceMappingURL=98.custom-build.css.map */ ================================================ FILE: lib/98.css/98.custom-build.rtl.css ================================================ /*! 98.css custom build - https://github.com/jdan/98.css */ /** * 98.css * Copyright (c) 2020 Jordan Scales * https://github.com/jdan/98.css/blob/main/LICENSE */ :root { /* Color */ --surface: var(--ButtonFace, #c0c0c0); --button-highlight: var(--ButtonHilight, #ffffff); --button-face: var(--ButtonFace, #dfdfdf); --button-shadow: var(--ButtonShadow, #808080); --window-frame: var(--WindowFrame, #0a0a0a); --dialog-blue: var(--ActiveTitle, #000080); --dialog-blue-light: var(--GradientActiveTitle, #1084d0); --dialog-gray: var(--InactiveTitle, #808080); --dialog-gray-light: var(--GradientInactiveTitle, #b5b5b5); --link-blue: #0000ff; /* Spacing */ --element-spacing: 8px; --grouped-button-spacing: 4px; --grouped-element-spacing: 6px; --radio-width: 12px; --checkbox-width: 13px; --radio-label-spacing: 6px; --range-track-height: 4px; --range-spacing: 10px; /* Some detailed computations for radio buttons and checkboxes */ --radio-total-width-precalc: var(--radio-width) + var(--radio-label-spacing); --radio-total-width: calc(var(--radio-total-width-precalc)); --radio-left: calc(-1 * var(--radio-total-width-precalc)); --radio-dot-width: 4px; --radio-dot-top: calc(var(--radio-width) / 2 - var(--radio-dot-width) / 2); --radio-dot-left: calc( -1 * (var(--radio-total-width-precalc)) + var(--radio-width) / 2 - var( --radio-dot-width ) / 2 ); --checkbox-total-width-precalc: var(--checkbox-width) + var(--radio-label-spacing); --checkbox-total-width: calc(var(--checkbox-total-width-precalc)); --checkbox-left: calc(-1 * var(--checkbox-total-width-precalc)); --checkmark-width: 7px; --checkmark-top: 3px; --checkmark-left: 3px; /* Borders */ --border-width: 1px; --border-raised-outer: inset -1px -1px var(--window-frame), inset 1px 1px var(--button-highlight); --border-raised-inner: inset -2px -2px var(--button-shadow), inset 2px 2px var(--button-face); --border-sunken-outer: inset -1px -1px var(--button-highlight), inset 1px 1px var(--window-frame); --border-sunken-inner: inset -2px -2px var(--button-face), inset 2px 2px var(--button-shadow); /* Window borders flip button-face and button-highlight */ --border-window-outer: inset -1px -1px var(--window-frame), inset 1px 1px var(--button-face); --border-window-inner: inset -2px -2px var(--button-shadow), inset 2px 2px var(--button-highlight); /* Field borders (checkbox, input, etc) flip window-frame and button-shadow */ --border-field: inset -1px -1px var(--button-highlight), inset 1px 1px var(--button-shadow), inset -2px -2px var(--button-face), inset 2px 2px var(--window-frame); } /* @font-face { font-family: "Pixelated MS Sans Serif"; src: url("fonts/converted/ms_sans_serif.woff") format("woff"); src: url("fonts/converted/ms_sans_serif.woff2") format("woff2"); font-weight: normal; font-style: normal; } @font-face { font-family: "Pixelated MS Sans Serif"; src: url("fonts/converted/ms_sans_serif_bold.woff") format("woff"); src: url("fonts/converted/ms_sans_serif_bold.woff2") format("woff2"); font-weight: bold; font-style: normal; } body { font-family: Arial; font-size: 12px; color: #222222; } button, label, input, textarea, select, option, ul.tree-view, .window, .title-bar { font-family: "Pixelated MS Sans Serif", Arial; -webkit-font-smoothing: none; font-size: 11px; } h1 { font-size: 5rem; } h2 { font-size: 2.5rem; } h3 { font-size: 2rem; } h4 { font-size: 1.5rem; } u { text-decoration: none; border-bottom: 0.5px solid #222222; } button { box-sizing: border-box; border: none; background: var(--surface); box-shadow: var(--border-raised-outer), var(--border-raised-inner); border-radius: 0; min-width: 75px; min-height: 23px; padding: 0 12px; } .vertical-bar { width: 4px; height: 20px; background: #c0c0c0; box-shadow: var(--border-raised-outer), var(--border-raised-inner); } button:not(:disabled):active { box-shadow: var(--border-sunken-outer), var(--border-sunken-inner); padding: 2px 11px 0 13px; } @media (not(hover)) { button:not(:disabled):hover { box-shadow: var(--border-sunken-outer), var(--border-sunken-inner); } } button:focus { outline: 1px dotted #000000; outline-offset: -4px; } button::-moz-focus-inner { border: 0; } :disabled, :disabled + label { color: var(--button-shadow); } button:disabled, :disabled + label { text-shadow: 1px 1px 0 var(--button-highlight); } .window { box-shadow: var(--border-window-outer), var(--border-window-inner); background: var(--surface); padding: 3px; } .title-bar { background: linear-gradient( 90deg, var(--dialog-blue), var(--dialog-blue-light) ); padding: 3px 2px 3px 3px; display: flex; justify-content: space-between; align-items: center; } .title-bar.inactive { background: linear-gradient( 90deg, var(--dialog-gray), var(--dialog-gray-light) ); } .title-bar-text { font-weight: bold; color: white; letter-spacing: 0; margin-right: 24px; } .title-bar-controls { display: flex; } .title-bar-controls button { padding: 0; display: block; min-width: 16px; min-height: 14px; } .title-bar-controls button:active { padding: 0; } .title-bar-controls button:focus { outline: none; } .title-bar-controls button[aria-label="Minimize"] { background-image: svg-load("./icon/minimize.svg"); background-repeat: no-repeat; background-position: bottom 3px left 4px; } .title-bar-controls button[aria-label="Maximize"] { background-image: svg-load("./icon/maximize.svg"); background-repeat: no-repeat; background-position: top 2px left 3px; } .title-bar-controls button[aria-label="Restore"] { background-image: svg-load("./icon/restore.svg"); background-repeat: no-repeat; background-position: top 2px left 3px; } .title-bar-controls button[aria-label="Help"] { background-image: svg-load("./icon/help.svg"); background-repeat: no-repeat; background-position: top 2px left 5px; } .title-bar-controls button[aria-label="Close"] { margin-left: 2px; background-image: svg-load("./icon/close.svg"); background-repeat: no-repeat; background-position: top 3px left 4px; } .status-bar { margin: 0px 1px; display: flex; gap: 1px; } .status-bar-field { box-shadow: inset -1px -1px #dfdfdf, inset 1px 1px #808080; flex-grow: 1; padding: 2px 3px; margin: 0; } .window-body { margin: var(--element-spacing); } */ fieldset { border-image: url("data:image/svg+xml;charset=utf-8,%3Csvg width='5' height='5' viewBox='0 0 5 5' fill='grey' xmlns='http://www.w3.org/2000/svg'%3E %3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M0 0H5V5H0V2H2V3H3V2H0' fill='white'/%3E %3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M0 0H4V4H0V1H1V3H3V1H0' fill='%23808080'/%3E %3C/svg%3E") 2; padding: calc(2 * var(--border-width) + var(--element-spacing)); padding-block-start: var(--element-spacing); margin: 0; } legend { background: var(--surface); } /* .field-row { display: flex; align-items: center; } [class^="field-row"] + [class^="field-row"] { margin-top: var(--grouped-element-spacing); } .field-row > * + * { margin-left: var(--grouped-element-spacing); } .field-row-stacked { display: flex; flex-direction: column; } .field-row-stacked * + * { margin-top: var(--grouped-element-spacing); } .field-row label { display: inline-flex; align-items: center; } */ input[type="radio"], input[type="checkbox"] { appearance: none; -webkit-appearance: none; -moz-appearance: none; margin: 0; background: 100%; position: fixed; opacity: 0; border: none; } input[type="radio"] + label, input[type="checkbox"] + label { line-height: 13px; } input[type="radio"] + label { position: relative; margin-right: var(--radio-total-width); } input[type="radio"] + label::before { content: ""; position: absolute; top: 0; right: calc(-1 * (var(--radio-total-width-precalc))); display: inline-block; width: var(--radio-width); height: var(--radio-width); margin-left: var(--radio-label-spacing); background: url("data:image/svg+xml;charset=utf-8,%3Csvg width='12' height='12' viewBox='0 0 12 12' fill='none' xmlns='http://www.w3.org/2000/svg'%3E %3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M8 0H4V1H2V2H1V4H0V8H1V10H2V8H1V4H2V2H4V1H8V2H10V1H8V0Z' fill='%23808080'/%3E %3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M8 1H4V2H2V3V4H1V8H2V9H3V8H2V4H3V3H4V2H8V3H10V2H8V1Z' fill='black'/%3E %3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M9 3H10V4H9V3ZM10 8V4H11V8H10ZM8 10V9H9V8H10V9V10H8ZM4 10V11H8V10H4ZM4 10V9H2V10H4Z' fill='%23DFDFDF'/%3E %3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M11 2H10V4H11V8H10V10H8V11H4V10H2V11H4V12H8V11H10V10H11V8H12V4H11V2Z' fill='white'/%3E %3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M4 2H8V3H9V4H10V8H9V9H8V10H4V9H3V8H2V4H3V3H4V2Z' fill='white'/%3E %3C/svg%3E"); } input[type="radio"]:active + label::before { background: url("data:image/svg+xml;charset=utf-8,%3Csvg width='12' height='12' viewBox='0 0 12 12' fill='none' xmlns='http://www.w3.org/2000/svg'%3E %3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M8 0H4V1H2V2H1V4H0V8H1V10H2V8H1V4H2V2H4V1H8V2H10V1H8V0Z' fill='%23808080'/%3E %3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M8 1H4V2H2V3V4H1V8H2V9H3V8H2V4H3V3H4V2H8V3H10V2H8V1Z' fill='black'/%3E %3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M9 3H10V4H9V3ZM10 8V4H11V8H10ZM8 10V9H9V8H10V9V10H8ZM4 10V11H8V10H4ZM4 10V9H2V10H4Z' fill='%23DFDFDF'/%3E %3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M11 2H10V4H11V8H10V10H8V11H4V10H2V11H4V12H8V11H10V10H11V8H12V4H11V2Z' fill='white'/%3E %3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M4 2H8V3H9V4H10V8H9V9H8V10H4V9H3V8H2V4H3V3H4V2Z' fill='%23C0C0C0'/%3E %3C/svg%3E"); } input[type="radio"]:checked + label::after { content: ""; display: block; width: var(--radio-dot-width); height: var(--radio-dot-width); top: var(--radio-dot-top); right: var(--radio-dot-left); position: absolute; background: url("data:image/svg+xml;charset=utf-8,%3Csvg width='4' height='4' viewBox='0 0 4 4' fill='none' xmlns='http://www.w3.org/2000/svg'%3E %3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M3 0H1V1H0V2V3H1V4H3V3H4V2V1H3V0Z' fill='black'/%3E %3C/svg%3E"); } input[type="radio"]:focus + label, input[type="checkbox"]:focus + label { outline: 1px dotted #000000; } input[type="radio"][disabled] + label::before { background: url("data:image/svg+xml;charset=utf-8,%3Csvg width='12' height='12' viewBox='0 0 12 12' fill='none' xmlns='http://www.w3.org/2000/svg'%3E %3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M8 0H4V1H2V2H1V4H0V8H1V10H2V8H1V4H2V2H4V1H8V2H10V1H8V0Z' fill='%23808080'/%3E %3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M8 1H4V2H2V3V4H1V8H2V9H3V8H2V4H3V3H4V2H8V3H10V2H8V1Z' fill='black'/%3E %3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M9 3H10V4H9V3ZM10 8V4H11V8H10ZM8 10V9H9V8H10V9V10H8ZM4 10V11H8V10H4ZM4 10V9H2V10H4Z' fill='%23DFDFDF'/%3E %3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M11 2H10V4H11V8H10V10H8V11H4V10H2V11H4V12H8V11H10V10H11V8H12V4H11V2Z' fill='white'/%3E %3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M4 2H8V3H9V4H10V8H9V9H8V10H4V9H3V8H2V4H3V3H4V2Z' fill='%23C0C0C0'/%3E %3C/svg%3E"); } input[type="radio"][disabled]:checked + label::after { background: url("data:image/svg+xml;charset=utf-8,%3Csvg width='4' height='4' viewBox='0 0 4 4' fill='none' xmlns='http://www.w3.org/2000/svg'%3E %3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M3 0H1V1H0V2V3H1V4H3V3H4V2V1H3V0Z' fill='%23808080'/%3E %3C/svg%3E"); } input[type="checkbox"] + label { position: relative; margin-right: var(--checkbox-total-width); } input[type="checkbox"] + label::before { content: ""; position: absolute; right: calc(-1 * (var(--checkbox-total-width-precalc))); display: inline-block; width: var(--checkbox-width); height: var(--checkbox-width); background: var(--Window); box-shadow: var(--border-field); margin-left: var(--radio-label-spacing); } input[type="checkbox"]:active + label::before { background: var(--surface); } input[type="checkbox"]:checked + label::after { content: ""; display: block; width: var(--checkmark-width); height: var(--checkmark-width); position: absolute; top: var(--checkmark-top); right: calc( -1 * (var(--checkbox-total-width-precalc)) + var(--checkmark-left) ); background: url("data:image/svg+xml;charset=utf-8,%3Csvg width='7' height='7' viewBox='0 0 7 7' fill='none' xmlns='http://www.w3.org/2000/svg'%3E %3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M7 0H6V1H5V2H4V3H3V4H2V3H1V2H0V5H1V6H2V7H3V6H4V5H5V4H6V3H7V0Z' fill='black'/%3E %3C/svg%3E"); } input[type="checkbox"][disabled] + label::before { background: var(--surface); } input[type="checkbox"][disabled]:checked + label::after { background: url("data:image/svg+xml;charset=utf-8,%3Csvg width='7' height='7' viewBox='0 0 7 7' fill='none' xmlns='http://www.w3.org/2000/svg'%3E %3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M7 0H6V1H5V2H4V3H3V4H2V3H1V2H0V5H1V6H2V7H3V6H4V5H5V4H6V3H7V0Z' fill='%23808080'/%3E %3C/svg%3E"); } /* input[type="text"], input[type="password"], input[type="email"], select, textarea { padding: 3px 4px; border: none; box-shadow: var(--border-field); background-color: var(--Window); color: var(--WindowText); box-sizing: border-box; -webkit-appearance: none; -moz-appearance: none; appearance: none; border-radius: 0; } input[type="text"], input[type="password"], input[type="email"], select { height: 21px; } input[type="text"], input[type="password"], input[type="email"] { /* For some reason descenders are getting cut off without this *.../ line-height: 2; } input[type="text"]:disabled, input[type="password"]:disabled, input[type="email"]:disabled, textarea:disabled { background-color: var(--surface); } select { appearance: none; -webkit-appearance: none; -moz-appearance: none; position: relative; padding-right: 32px; background-image: svg-load("./icon/button-down.svg"); background-position: top 2px right 2px; background-repeat: no-repeat; border-radius: 0; } select:focus, input[type="text"]:focus, input[type="password"]:focus, input[type="email"]:focus, textarea:focus { outline: none; } */ input[type="range"] { -webkit-appearance: none; width: 100%; background: transparent; } input[type="range"]:focus { outline: none; } input[type="range"]::-webkit-slider-thumb { -webkit-appearance: none; height: 21px; width: 11px; background: url("data:image/svg+xml;charset=utf-8,%3Csvg width='11' height='21' viewBox='0 0 11 21' fill='none' xmlns='http://www.w3.org/2000/svg'%3E %3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M0 0V16H2V18H4V20H5V19H3V17H1V1H10V0Z' fill='white'/%3E %3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M1 1V16H2V17H3V18H4V19H6V18H7V17H8V16H9V1Z' fill='%23C0C7C8'/%3E %3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M9 1H10V16H8V18H6V20H5V19H7V17H9Z' fill='%2387888F'/%3E %3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M10 0H11V16H9V18H7V20H5V21H6V19H8V17H10Z' fill='black'/%3E %3C/svg%3E"); transform: translateY(-8px); } input[type="range"].has-box-indicator::-webkit-slider-thumb { background: url("data:image/svg+xml;charset=utf-8,%3Csvg width='11' height='21' viewBox='0 0 11 21' fill='none' xmlns='http://www.w3.org/2000/svg'%3E %3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M0 0V20H1V1H10V0Z' fill='white'/%3E %3Crect x='1' y='1' width='8' height='18' fill='%23C0C7C8'/%3E %3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M9 1H10V20H1V19H9Z' fill='%2387888F'/%3E %3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M10 0H11V21H0V20H10Z' fill='black'/%3E %3C/svg%3E"); transform: translateY(-10px); } input[type="range"]::-moz-range-thumb { height: 21px; width: 11px; border: 0; border-radius: 0; background: url("data:image/svg+xml;charset=utf-8,%3Csvg width='11' height='21' viewBox='0 0 11 21' fill='none' xmlns='http://www.w3.org/2000/svg'%3E %3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M0 0V16H2V18H4V20H5V19H3V17H1V1H10V0Z' fill='white'/%3E %3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M1 1V16H2V17H3V18H4V19H6V18H7V17H8V16H9V1Z' fill='%23C0C7C8'/%3E %3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M9 1H10V16H8V18H6V20H5V19H7V17H9Z' fill='%2387888F'/%3E %3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M10 0H11V16H9V18H7V20H5V21H6V19H8V17H10Z' fill='black'/%3E %3C/svg%3E"); transform: translateY(2px); } input[type="range"].has-box-indicator::-moz-range-thumb { background: url("data:image/svg+xml;charset=utf-8,%3Csvg width='11' height='21' viewBox='0 0 11 21' fill='none' xmlns='http://www.w3.org/2000/svg'%3E %3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M0 0V20H1V1H10V0Z' fill='white'/%3E %3Crect x='1' y='1' width='8' height='18' fill='%23C0C7C8'/%3E %3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M9 1H10V20H1V19H9Z' fill='%2387888F'/%3E %3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M10 0H11V21H0V20H10Z' fill='black'/%3E %3C/svg%3E"); transform: translateY(0px); } input[type="range"]::-webkit-slider-runnable-track { width: 100%; height: 2px; box-sizing: border-box; background: black; border-left: 1px solid grey; border-bottom: 1px solid grey; box-shadow: 1px 0 0 white, 1px 1px 0 white, 0 1px 0 white, -1px 0 0 darkgrey, -1px -1px 0 darkgrey, 0 -1px 0 darkgrey, -1px 1px 0 white, 1px -1px darkgrey; } input[type="range"]::-moz-range-track { width: 100%; height: 2px; box-sizing: border-box; background: black; border-left: 1px solid grey; border-bottom: 1px solid grey; box-shadow: 1px 0 0 white, 1px 1px 0 white, 0 1px 0 white, -1px 0 0 darkgrey, -1px -1px 0 darkgrey, 0 -1px 0 darkgrey, -1px 1px 0 white, 1px -1px darkgrey; } .is-vertical { display: inline-block; width: 4px; height: 150px; transform: translateY(50%); } .is-vertical > input[type="range"] { width: 150px; height: 4px; margin: 0 var(--range-spacing) 0 calc(var(--grouped-element-spacing) + var(--range-spacing)); transform-origin: right; transform: rotate(-270deg) translateX(calc(-1*(-50% + var(--element-spacing)))); } .is-vertical > input[type="range"]::-webkit-slider-runnable-track { border-right: 1px solid grey; border-left: 0; border-bottom: 1px solid grey; box-shadow: -1px 0 0 white, -1px 1px 0 white, 0 1px 0 white, 1px 0 0 darkgrey, 1px -1px 0 darkgrey, 0 -1px 0 darkgrey, 1px 1px 0 white, -1px -1px darkgrey; } .is-vertical > input[type="range"]::-moz-range-track { border-right: 1px solid grey; border-left: 0; border-bottom: 1px solid grey; box-shadow: -1px 0 0 white, -1px 1px 0 white, 0 1px 0 white, 1px 0 0 darkgrey, 1px -1px 0 darkgrey, 0 -1px 0 darkgrey, 1px 1px 0 white, -1px -1px darkgrey; } .is-vertical > input[type="range"]::-webkit-slider-thumb { transform: translateY(-8px) scaleX(-1); } .is-vertical > input[type="range"].has-box-indicator::-webkit-slider-thumb { transform: translateY(-10px) scaleX(-1); } .is-vertical > input[type="range"]::-moz-range-thumb { transform: translateY(2px) scaleX(-1); } .is-vertical > input[type="range"].has-box-indicator::-moz-range-thumb { transform: translateY(0px) scaleX(-1); } /* select:focus { color: var(--HilightText); background-color: var(--Hilight); } select:focus option { color: #000; background-color: #fff; } select:active { background-image: svg-load("./icon/button-down-active.svg"); } */ /* a { color: var(--link-blue); } a:focus { outline: 1px dotted var(--link-blue); } */ /* ul.tree-view { display: block; background: var(--Window); box-shadow: var(--border-field); padding: 6px; margin: 0; } ul.tree-view li { list-style-type: none; } ul.tree-view a { text-decoration: none; color: #000; } ul.tree-view a:focus { background-color: var(--Hilight); color: var(--HilightText); } ul.tree-view ul, ul.tree-view li { margin-top: 3px; } ul.tree-view ul { margin-left: 16px; padding-left: 16px; /* Goes down too far *.../ border-left: 1px dotted #808080; } ul.tree-view ul > li { position: relative; } ul.tree-view ul > li::before { content: ""; display: block; position: absolute; left: -16px; top: 6px; width: 12px; border-bottom: 1px dotted #808080; } /* Cover the bottom of the left dotted border *.../ ul.tree-view ul > li:last-child::after { content: ""; display: block; position: absolute; left: -20px; top: 7px; bottom: 0px; width: 8px; background: var(--Window); } ul.tree-view details { margin-top: 0; } ul.tree-view details[open] summary { margin-bottom: 0; } ul.tree-view ul details > summary:before { margin-left: -22px; position: relative; z-index: 1; } ul.tree-view details > summary:before { text-align: center; display: block; float: left; content: "+"; border: 1px solid #808080; width: 8px; height: 9px; line-height: 8px; margin-right: 5px; padding-left: 1px; background-color: #fff; } ul.tree-view details[open] > summary:before { content: "-"; } */ /* pre { display: block; background: var(--Window); box-shadow: var(--border-field); padding: 12px 8px; margin: 0; } code, code * { font-family: monospace; } summary:focus { outline: 1px dotted #000000; } */ /* ::-webkit-scrollbar { width: 16px; } ::-webkit-scrollbar:horizontal { height: 17px; } ::-webkit-scrollbar-corner { background: var(--button-face); } ::-webkit-scrollbar-track { background-image: svg-load("./icon/scrollbar-background.svg"); } ::-webkit-scrollbar-thumb { background-color: var(--button-face); box-shadow: var(--border-raised-outer), var(--border-raised-inner); } ::-webkit-scrollbar-button:horizontal:start:decrement, ::-webkit-scrollbar-button:horizontal:end:increment, ::-webkit-scrollbar-button:vertical:start:decrement, ::-webkit-scrollbar-button:vertical:end:increment { display: block; } ::-webkit-scrollbar-button:vertical:start { height: 17px; background-image: svg-load("./icon/button-up.svg"); } ::-webkit-scrollbar-button:vertical:end { height: 17px; background-image: svg-load("./icon/button-down.svg"); } ::-webkit-scrollbar-button:horizontal:start { width: 16px; background-image: svg-load("./icon/button-left.svg"); } ::-webkit-scrollbar-button:horizontal:end { width: 16px; background-image: svg-load("./icon/button-right.svg"); } */ ================================================ FILE: lib/98.css/98.custom-src.css ================================================ /** * 98.css * Copyright (c) 2020 Jordan Scales * https://github.com/jdan/98.css/blob/main/LICENSE */ :root { /* Color */ --surface: var(--ButtonFace, #c0c0c0); --button-highlight: var(--ButtonHilight, #ffffff); --button-face: var(--ButtonFace, #dfdfdf); --button-shadow: var(--ButtonShadow, #808080); --window-frame: var(--WindowFrame, #0a0a0a); --dialog-blue: var(--ActiveTitle, #000080); --dialog-blue-light: var(--GradientActiveTitle, #1084d0); --dialog-gray: var(--InactiveTitle, #808080); --dialog-gray-light: var(--GradientInactiveTitle, #b5b5b5); --link-blue: #0000ff; /* Spacing */ --element-spacing: 8px; --grouped-button-spacing: 4px; --grouped-element-spacing: 6px; --radio-width: 12px; --checkbox-width: 13px; --radio-label-spacing: 6px; --range-track-height: 4px; --range-spacing: 10px; /* Some detailed computations for radio buttons and checkboxes */ --radio-total-width-precalc: var(--radio-width) + var(--radio-label-spacing); --radio-total-width: calc(var(--radio-total-width-precalc)); --radio-left: calc(-1 * var(--radio-total-width-precalc)); --radio-dot-width: 4px; --radio-dot-top: calc(var(--radio-width) / 2 - var(--radio-dot-width) / 2); --radio-dot-left: calc( -1 * (var(--radio-total-width-precalc)) + var(--radio-width) / 2 - var( --radio-dot-width ) / 2 ); --checkbox-total-width-precalc: var(--checkbox-width) + var(--radio-label-spacing); --checkbox-total-width: calc(var(--checkbox-total-width-precalc)); --checkbox-left: calc(-1 * var(--checkbox-total-width-precalc)); --checkmark-width: 7px; --checkmark-top: 3px; --checkmark-left: 3px; /* Borders */ --border-width: 1px; /* rtl:ignore */ --border-raised-outer: inset -1px -1px var(--window-frame), inset 1px 1px var(--button-highlight); /* rtl:ignore */ --border-raised-inner: inset -2px -2px var(--button-shadow), inset 2px 2px var(--button-face); /* rtl:ignore */ --border-sunken-outer: inset -1px -1px var(--button-highlight), inset 1px 1px var(--window-frame); /* rtl:ignore */ --border-sunken-inner: inset -2px -2px var(--button-face), inset 2px 2px var(--button-shadow); /* Window borders flip button-face and button-highlight */ /* rtl:ignore */ --border-window-outer: inset -1px -1px var(--window-frame), inset 1px 1px var(--button-face); /* rtl:ignore */ --border-window-inner: inset -2px -2px var(--button-shadow), inset 2px 2px var(--button-highlight); /* Field borders (checkbox, input, etc) flip window-frame and button-shadow */ /* rtl:ignore */ --border-field: inset -1px -1px var(--button-highlight), inset 1px 1px var(--button-shadow), inset -2px -2px var(--button-face), inset 2px 2px var(--window-frame); } /* @font-face { font-family: "Pixelated MS Sans Serif"; src: url("fonts/converted/ms_sans_serif.woff") format("woff"); src: url("fonts/converted/ms_sans_serif.woff2") format("woff2"); font-weight: normal; font-style: normal; } @font-face { font-family: "Pixelated MS Sans Serif"; src: url("fonts/converted/ms_sans_serif_bold.woff") format("woff"); src: url("fonts/converted/ms_sans_serif_bold.woff2") format("woff2"); font-weight: bold; font-style: normal; } body { font-family: Arial; font-size: 12px; color: #222222; } button, label, input, textarea, select, option, ul.tree-view, .window, .title-bar { font-family: "Pixelated MS Sans Serif", Arial; -webkit-font-smoothing: none; font-size: 11px; } h1 { font-size: 5rem; } h2 { font-size: 2.5rem; } h3 { font-size: 2rem; } h4 { font-size: 1.5rem; } u { text-decoration: none; border-bottom: 0.5px solid #222222; } button { box-sizing: border-box; border: none; background: var(--surface); box-shadow: var(--border-raised-outer), var(--border-raised-inner); border-radius: 0; min-width: 75px; min-height: 23px; padding: 0 12px; } .vertical-bar { width: 4px; height: 20px; background: #c0c0c0; box-shadow: var(--border-raised-outer), var(--border-raised-inner); } button:not(:disabled):active { box-shadow: var(--border-sunken-outer), var(--border-sunken-inner); padding: 2px 11px 0 13px; } @media (not(hover)) { button:not(:disabled):hover { box-shadow: var(--border-sunken-outer), var(--border-sunken-inner); } } button:focus { outline: 1px dotted #000000; outline-offset: -4px; } button::-moz-focus-inner { border: 0; } :disabled, :disabled + label { color: var(--button-shadow); } button:disabled, :disabled + label { text-shadow: 1px 1px 0 var(--button-highlight); } .window { box-shadow: var(--border-window-outer), var(--border-window-inner); background: var(--surface); padding: 3px; } .title-bar { background: linear-gradient( 90deg, var(--dialog-blue), var(--dialog-blue-light) ); padding: 3px 2px 3px 3px; display: flex; justify-content: space-between; align-items: center; } .title-bar.inactive { background: linear-gradient( 90deg, var(--dialog-gray), var(--dialog-gray-light) ); } .title-bar-text { font-weight: bold; color: white; letter-spacing: 0; margin-right: 24px; } .title-bar-controls { display: flex; } .title-bar-controls button { padding: 0; display: block; min-width: 16px; min-height: 14px; } .title-bar-controls button:active { padding: 0; } .title-bar-controls button:focus { outline: none; } .title-bar-controls button[aria-label="Minimize"] { background-image: svg-load("./icon/minimize.svg"); background-repeat: no-repeat; background-position: bottom 3px left 4px; } .title-bar-controls button[aria-label="Maximize"] { background-image: svg-load("./icon/maximize.svg"); background-repeat: no-repeat; background-position: top 2px left 3px; } .title-bar-controls button[aria-label="Restore"] { background-image: svg-load("./icon/restore.svg"); background-repeat: no-repeat; background-position: top 2px left 3px; } .title-bar-controls button[aria-label="Help"] { background-image: svg-load("./icon/help.svg"); background-repeat: no-repeat; background-position: top 2px left 5px; } .title-bar-controls button[aria-label="Close"] { margin-left: 2px; background-image: svg-load("./icon/close.svg"); background-repeat: no-repeat; background-position: top 3px left 4px; } .status-bar { margin: 0px 1px; display: flex; gap: 1px; } .status-bar-field { box-shadow: inset -1px -1px #dfdfdf, inset 1px 1px #808080; flex-grow: 1; padding: 2px 3px; margin: 0; } .window-body { margin: var(--element-spacing); } */ fieldset { border-image: svg-load("./icon/groupbox-border.svg") 2; padding: calc(2 * var(--border-width) + var(--element-spacing)); padding-block-start: var(--element-spacing); margin: 0; } legend { background: var(--surface); } /* .field-row { display: flex; align-items: center; } [class^="field-row"] + [class^="field-row"] { margin-top: var(--grouped-element-spacing); } .field-row > * + * { margin-left: var(--grouped-element-spacing); } .field-row-stacked { display: flex; flex-direction: column; } .field-row-stacked * + * { margin-top: var(--grouped-element-spacing); } .field-row label { display: inline-flex; align-items: center; } */ input[type="radio"], input[type="checkbox"] { appearance: none; -webkit-appearance: none; -moz-appearance: none; margin: 0; background: 0; position: fixed; opacity: 0; border: none; } input[type="radio"] + label, input[type="checkbox"] + label { line-height: 13px; } input[type="radio"] + label { position: relative; margin-left: var(--radio-total-width); } input[type="radio"] + label::before { content: ""; position: absolute; top: 0; left: calc(-1 * (var(--radio-total-width-precalc))); display: inline-block; width: var(--radio-width); height: var(--radio-width); margin-right: var(--radio-label-spacing); background: svg-load("./icon/radio-border.svg"); } input[type="radio"]:active + label::before { background: svg-load("./icon/radio-border-disabled.svg"); } input[type="radio"]:checked + label::after { content: ""; display: block; width: var(--radio-dot-width); height: var(--radio-dot-width); top: var(--radio-dot-top); left: var(--radio-dot-left); position: absolute; background: svg-load("./icon/radio-dot.svg"); } input[type="radio"]:focus + label, input[type="checkbox"]:focus + label { outline: 1px dotted #000000; } input[type="radio"][disabled] + label::before { background: svg-load("./icon/radio-border-disabled.svg"); } input[type="radio"][disabled]:checked + label::after { background: svg-load("./icon/radio-dot-disabled.svg"); } input[type="checkbox"] + label { position: relative; margin-left: var(--checkbox-total-width); } input[type="checkbox"] + label::before { content: ""; position: absolute; left: calc(-1 * (var(--checkbox-total-width-precalc))); display: inline-block; width: var(--checkbox-width); height: var(--checkbox-width); background: var(--Window); box-shadow: var(--border-field); margin-right: var(--radio-label-spacing); } input[type="checkbox"]:active + label::before { background: var(--surface); } input[type="checkbox"]:checked + label::after { content: ""; display: block; width: var(--checkmark-width); height: var(--checkmark-width); position: absolute; top: var(--checkmark-top); left: calc( -1 * (var(--checkbox-total-width-precalc)) + var(--checkmark-left) ); background: svg-load("./icon/checkmark.svg"); } input[type="checkbox"][disabled] + label::before { background: var(--surface); } input[type="checkbox"][disabled]:checked + label::after { background: svg-load("./icon/checkmark-disabled.svg"); } /* input[type="text"], input[type="password"], input[type="email"], select, textarea { padding: 3px 4px; border: none; box-shadow: var(--border-field); background-color: var(--Window); color: var(--WindowText); box-sizing: border-box; -webkit-appearance: none; -moz-appearance: none; appearance: none; border-radius: 0; } input[type="text"], input[type="password"], input[type="email"], select { height: 21px; } input[type="text"], input[type="password"], input[type="email"] { /* For some reason descenders are getting cut off without this *.../ line-height: 2; } input[type="text"]:disabled, input[type="password"]:disabled, input[type="email"]:disabled, textarea:disabled { background-color: var(--surface); } select { appearance: none; -webkit-appearance: none; -moz-appearance: none; position: relative; padding-right: 32px; background-image: svg-load("./icon/button-down.svg"); background-position: top 2px right 2px; background-repeat: no-repeat; border-radius: 0; } select:focus, input[type="text"]:focus, input[type="password"]:focus, input[type="email"]:focus, textarea:focus { outline: none; } */ input[type="range"] { -webkit-appearance: none; width: 100%; background: transparent; } input[type="range"]:focus { outline: none; } input[type="range"]::-webkit-slider-thumb { -webkit-appearance: none; height: 21px; width: 11px; background: svg-load("./icon/indicator-horizontal.svg"); transform: translateY(-8px); } input[type="range"].has-box-indicator::-webkit-slider-thumb { background: svg-load("./icon/indicator-rectangle-horizontal.svg"); transform: translateY(-10px); } input[type="range"]::-moz-range-thumb { height: 21px; width: 11px; border: 0; border-radius: 0; background: svg-load("./icon/indicator-horizontal.svg"); transform: translateY(2px); } input[type="range"].has-box-indicator::-moz-range-thumb { background: svg-load("./icon/indicator-rectangle-horizontal.svg"); transform: translateY(0px); } input[type="range"]::-webkit-slider-runnable-track { width: 100%; height: 2px; box-sizing: border-box; background: black; border-right: 1px solid grey; border-bottom: 1px solid grey; /* rtl:ignore */ box-shadow: 1px 0 0 white, 1px 1px 0 white, 0 1px 0 white, -1px 0 0 darkgrey, -1px -1px 0 darkgrey, 0 -1px 0 darkgrey, -1px 1px 0 white, 1px -1px darkgrey; } input[type="range"]::-moz-range-track { width: 100%; height: 2px; box-sizing: border-box; background: black; border-right: 1px solid grey; border-bottom: 1px solid grey; /* rtl:ignore */ box-shadow: 1px 0 0 white, 1px 1px 0 white, 0 1px 0 white, -1px 0 0 darkgrey, -1px -1px 0 darkgrey, 0 -1px 0 darkgrey, -1px 1px 0 white, 1px -1px darkgrey; } .is-vertical { display: inline-block; width: 4px; height: 150px; transform: translateY(50%); } .is-vertical > input[type="range"] { width: 150px; height: 4px; margin: 0 calc(var(--grouped-element-spacing) + var(--range-spacing)) 0 var(--range-spacing); transform-origin: left; transform: rotate(270deg) translateX(calc(-50% + var(--element-spacing))); } .is-vertical > input[type="range"]::-webkit-slider-runnable-track { border-left: 1px solid grey; border-right: 0; border-bottom: 1px solid grey; /* rtl:ignore */ box-shadow: -1px 0 0 white, -1px 1px 0 white, 0 1px 0 white, 1px 0 0 darkgrey, 1px -1px 0 darkgrey, 0 -1px 0 darkgrey, 1px 1px 0 white, -1px -1px darkgrey; } .is-vertical > input[type="range"]::-moz-range-track { border-left: 1px solid grey; border-right: 0; border-bottom: 1px solid grey; /* rtl:ignore */ box-shadow: -1px 0 0 white, -1px 1px 0 white, 0 1px 0 white, 1px 0 0 darkgrey, 1px -1px 0 darkgrey, 0 -1px 0 darkgrey, 1px 1px 0 white, -1px -1px darkgrey; } .is-vertical > input[type="range"]::-webkit-slider-thumb { transform: translateY(-8px) scaleX(-1); } .is-vertical > input[type="range"].has-box-indicator::-webkit-slider-thumb { transform: translateY(-10px) scaleX(-1); } .is-vertical > input[type="range"]::-moz-range-thumb { transform: translateY(2px) scaleX(-1); } .is-vertical > input[type="range"].has-box-indicator::-moz-range-thumb { transform: translateY(0px) scaleX(-1); } /* select:focus { color: var(--HilightText); background-color: var(--Hilight); } select:focus option { color: #000; background-color: #fff; } select:active { background-image: svg-load("./icon/button-down-active.svg"); } */ /* a { color: var(--link-blue); } a:focus { outline: 1px dotted var(--link-blue); } */ /* ul.tree-view { display: block; background: var(--Window); box-shadow: var(--border-field); padding: 6px; margin: 0; } ul.tree-view li { list-style-type: none; } ul.tree-view a { text-decoration: none; color: #000; } ul.tree-view a:focus { background-color: var(--Hilight); color: var(--HilightText); } ul.tree-view ul, ul.tree-view li { margin-top: 3px; } ul.tree-view ul { margin-left: 16px; padding-left: 16px; /* Goes down too far *.../ border-left: 1px dotted #808080; } ul.tree-view ul > li { position: relative; } ul.tree-view ul > li::before { content: ""; display: block; position: absolute; left: -16px; top: 6px; width: 12px; border-bottom: 1px dotted #808080; } /* Cover the bottom of the left dotted border *.../ ul.tree-view ul > li:last-child::after { content: ""; display: block; position: absolute; left: -20px; top: 7px; bottom: 0px; width: 8px; background: var(--Window); } ul.tree-view details { margin-top: 0; } ul.tree-view details[open] summary { margin-bottom: 0; } ul.tree-view ul details > summary:before { margin-left: -22px; position: relative; z-index: 1; } ul.tree-view details > summary:before { text-align: center; display: block; float: left; content: "+"; border: 1px solid #808080; width: 8px; height: 9px; line-height: 8px; margin-right: 5px; padding-left: 1px; background-color: #fff; } ul.tree-view details[open] > summary:before { content: "-"; } */ /* pre { display: block; background: var(--Window); box-shadow: var(--border-field); padding: 12px 8px; margin: 0; } code, code * { font-family: monospace; } summary:focus { outline: 1px dotted #000000; } */ /* ::-webkit-scrollbar { width: 16px; } ::-webkit-scrollbar:horizontal { height: 17px; } ::-webkit-scrollbar-corner { background: var(--button-face); } ::-webkit-scrollbar-track { background-image: svg-load("./icon/scrollbar-background.svg"); } ::-webkit-scrollbar-thumb { background-color: var(--button-face); box-shadow: var(--border-raised-outer), var(--border-raised-inner); } ::-webkit-scrollbar-button:horizontal:start:decrement, ::-webkit-scrollbar-button:horizontal:end:increment, ::-webkit-scrollbar-button:vertical:start:decrement, ::-webkit-scrollbar-button:vertical:end:increment { display: block; } ::-webkit-scrollbar-button:vertical:start { height: 17px; background-image: svg-load("./icon/button-up.svg"); } ::-webkit-scrollbar-button:vertical:end { height: 17px; background-image: svg-load("./icon/button-down.svg"); } ::-webkit-scrollbar-button:horizontal:start { width: 16px; background-image: svg-load("./icon/button-left.svg"); } ::-webkit-scrollbar-button:horizontal:end { width: 16px; background-image: svg-load("./icon/button-right.svg"); } */ ================================================ FILE: lib/98.css/modified-build.js ================================================ #!/usr/bin/env node const dedent = require("dedent"); const ejs = require("ejs"); const fs = require("fs"); const glob = require("glob"); const hljs = require("highlight.js"); const mkdirp = require("mkdirp"); const path = require("path"); const postcss = require("postcss"); const { homepage, version } = require("./package.json"); function buildCSS() { const input = `/*! 98.css custom build - ${homepage} */\n` + fs.readFileSync("style.css"); return postcss() .use(require("postcss-inline-svg")) // .use(require("postcss-css-variables")) // .use(require("postcss-calc")) .use(require("postcss-copy")({ dest: "dist", template: "[name].[ext]" })) // .use(require("cssnano")) .process(input, { from: "style.css", to: "dist/98.custom-build.css", map: { inline: false }, }) .then((result) => { mkdirp.sync("dist"); fs.writeFileSync("dist/98.custom-build.css", result.css); fs.writeFileSync("dist/98.custom-build.css.map", result.map.toString()); }); } function buildDocs() { let id = 0; function getNewId() { return ++id; } function getCurrentId() { return id; } const template = fs.readFileSync("docs/index.html.ejs", "utf-8"); function example(code) { const magicBrackets = /\[\[(.*)\]\]/g; const dedented = dedent(code); const inline = dedented.replace(magicBrackets, "$1"); const escaped = hljs.highlight("html", dedented.replace(magicBrackets, "")) .value; return `
    ${inline}
    Show code
    ${escaped}
    `; } glob("docs/*", (err, files) => { if (!err) { files.forEach((srcFile) => fs.copyFileSync(srcFile, path.join("dist", path.basename(srcFile))) ); } else throw "error globbing dist directory."; }); fs.writeFileSync( path.join(__dirname, "/dist/index.html"), ejs.render(template, { getNewId, getCurrentId, example }) ); } function build() { buildCSS() .then(buildDocs) .catch((err) => console.log(err)); } module.exports = build; build(); ================================================ FILE: lib/FileSaver.js ================================================ (function (global, factory) { if (typeof define === "function" && define.amd) { define([], factory); } else if (typeof exports !== "undefined") { factory(); } else { var mod = { exports: {} }; factory(); global.FileSaver = mod.exports; } })(this, function () { "use strict"; /* * FileSaver.js * A saveAs() FileSaver implementation. * * By Eli Grey, http://eligrey.com * * License : https://github.com/eligrey/FileSaver.js/blob/master/LICENSE.md (MIT) * source : http://purl.eligrey.com/github/FileSaver.js */ // The one and only way of getting global scope in all environments // https://stackoverflow.com/q/3277182/1008999 var _global = typeof window === 'object' && window.window === window ? window : typeof self === 'object' && self.self === self ? self : typeof global === 'object' && global.global === global ? global : void 0; function bom(blob, opts) { if (typeof opts === 'undefined') opts = { autoBom: false };else if (typeof opts !== 'object') { console.warn('Deprecated: Expected third argument to be a object'); opts = { autoBom: !opts }; } // prepend BOM for UTF-8 XML and text/* types (including HTML) // note: your browser will automatically convert UTF-16 U+FEFF to EF BB BF if (opts.autoBom && /^\s*(?:text\/\S*|application\/xml|\S*\/\S*\+xml)\s*;.*charset\s*=\s*utf-8/i.test(blob.type)) { return new Blob([String.fromCharCode(0xFEFF), blob], { type: blob.type }); } return blob; } function download(url, name, opts) { var xhr = new XMLHttpRequest(); xhr.open('GET', url); xhr.responseType = 'blob'; xhr.onload = function () { saveAs(xhr.response, name, opts); }; xhr.onerror = function () { console.error('could not download file'); }; xhr.send(); } function corsEnabled(url) { var xhr = new XMLHttpRequest(); // use sync to avoid popup blocker xhr.open('HEAD', url, false); try { xhr.send(); } catch (e) {} return xhr.status >= 200 && xhr.status <= 299; } // `a.click()` doesn't work for all browsers (#465) function click(node) { try { node.dispatchEvent(new MouseEvent('click')); } catch (e) { var evt = document.createEvent('MouseEvents'); evt.initMouseEvent('click', true, true, window, 0, 0, 0, 80, 20, false, false, false, false, 0, null); node.dispatchEvent(evt); } } // Detect WebView inside a native macOS app by ruling out all browsers // We just need to check for 'Safari' because all other browsers (besides Firefox) include that too // https://www.whatismybrowser.com/guides/the-latest-user-agent/macos var isMacOSWebView = /Macintosh/.test(navigator.userAgent) && /AppleWebKit/.test(navigator.userAgent) && !/Safari/.test(navigator.userAgent); var saveAs = _global.saveAs || ( // probably in some web worker typeof window !== 'object' || window !== _global ? function saveAs() {} /* noop */ // Use download attribute first if possible (#193 Lumia mobile) unless this is a macOS WebView : 'download' in HTMLAnchorElement.prototype && !isMacOSWebView ? function saveAs(blob, name, opts) { var URL = _global.URL || _global.webkitURL; var a = document.createElement('a'); name = name || blob.name || 'download'; a.download = name; a.rel = 'noopener'; // tabnabbing // TODO: detect chrome extensions & packaged apps // a.target = '_blank' if (typeof blob === 'string') { // Support regular links a.href = blob; if (a.origin !== location.origin) { corsEnabled(a.href) ? download(blob, name, opts) : click(a, a.target = '_blank'); } else { click(a); } } else { // Support blobs a.href = URL.createObjectURL(blob); setTimeout(function () { URL.revokeObjectURL(a.href); }, 4E4); // 40s setTimeout(function () { click(a); }, 0); } } // Use msSaveOrOpenBlob as a second approach : 'msSaveOrOpenBlob' in navigator ? function saveAs(blob, name, opts) { name = name || blob.name || 'download'; if (typeof blob === 'string') { if (corsEnabled(blob)) { download(blob, name, opts); } else { var a = document.createElement('a'); a.href = blob; a.target = '_blank'; setTimeout(function () { click(a); }); } } else { navigator.msSaveOrOpenBlob(bom(blob, opts), name); } } // Fallback to using FileReader and a popup : function saveAs(blob, name, opts, popup) { // Open a popup immediately do go around popup blocker // Mostly only available on user interaction and the fileReader is async so... popup = popup || open('', '_blank'); if (popup) { popup.document.title = popup.document.body.innerText = 'downloading...'; } if (typeof blob === 'string') return download(blob, name, opts); var force = blob.type === 'application/octet-stream'; var isSafari = /constructor/i.test(_global.HTMLElement) || _global.safari; var isChromeIOS = /CriOS\/[\d]+/.test(navigator.userAgent); if ((isChromeIOS || force && isSafari || isMacOSWebView) && typeof FileReader !== 'undefined') { // Safari doesn't allow downloading of blob URLs var reader = new FileReader(); reader.onloadend = function () { var url = reader.result; url = isChromeIOS ? url : url.replace(/^data:[^;]*;/, 'data:attachment/file;'); if (popup) popup.location.href = url;else location = url; popup = null; // reverse-tabnabbing #460 }; reader.readAsDataURL(blob); } else { var URL = _global.URL || _global.webkitURL; var url = URL.createObjectURL(blob); if (popup) popup.location = url;else location.href = url; popup = null; // reverse-tabnabbing #460 setTimeout(function () { URL.revokeObjectURL(url); }, 4E4); // 40s } }); _global.saveAs = saveAs.saveAs = saveAs; if (typeof module !== 'undefined') { module.exports = saveAs; } }); ================================================ FILE: lib/UPNG.js ================================================ var UPNG = {}; UPNG.toRGBA8 = function(out) { var w = out.width, h = out.height; if(out.tabs.acTL==null) return [UPNG.toRGBA8.decodeImage(out.data, w, h, out).buffer]; var frms = []; if(out.frames[0].data==null) out.frames[0].data = out.data; var len = w*h*4, img = new Uint8Array(len), empty = new Uint8Array(len), prev=new Uint8Array(len); for(var i=0; i>3)]>>(7-((i&7)<<0)))& 1), cj=3*j; bf[qi]=p[cj]; bf[qi+1]=p[cj+1]; bf[qi+2]=p[cj+2]; bf[qi+3]=(j>2)]>>(6-((i&3)<<1)))& 3), cj=3*j; bf[qi]=p[cj]; bf[qi+1]=p[cj+1]; bf[qi+2]=p[cj+2]; bf[qi+3]=(j>1)]>>(4-((i&1)<<2)))&15), cj=3*j; bf[qi]=p[cj]; bf[qi+1]=p[cj+1]; bf[qi+2]=p[cj+2]; bf[qi+3]=(j>>3)]>>>(7 -((x&7) )))& 1), al=(gr==tr*255)?0:255; bf32[to+x]=(al<<24)|(gr<<16)|(gr<<8)|gr; } else if(depth== 2) for(var x=0; x>>2)]>>>(6 -((x&3)<<1)))& 3), al=(gr==tr* 85)?0:255; bf32[to+x]=(al<<24)|(gr<<16)|(gr<<8)|gr; } else if(depth== 4) for(var x=0; x>>1)]>>>(4 -((x&1)<<2)))&15), al=(gr==tr* 17)?0:255; bf32[to+x]=(al<<24)|(gr<<16)|(gr<<8)|gr; } else if(depth== 8) for(var x=0; x>>2<<5);while(i==0){i=n(N,d,1);m=n(N,d+1,2);d+=3;if(m==0){if((d&7)!=0)d+=8-(d&7); var D=(d>>>3)+4,q=N[D-4]|N[D-3]<<8;if(Z)W=H.H.W(W,w+q);W.set(new R(N.buffer,N.byteOffset+D,q),w);d=D+q<<3; w+=q;continue}if(Z)W=H.H.W(W,w+(1<<17));if(m==1){v=b.J;C=b.h;X=(1<<9)-1;u=(1<<5)-1}if(m==2){J=A(N,d,5)+257; h=A(N,d+5,5)+1;Q=A(N,d+10,4)+4;d+=14;var E=d,j=1;for(var c=0;c<38;c+=2){b.Q[c]=0;b.Q[c+1]=0}for(var c=0; cj)j=K}d+=3*Q;M(b.Q,j);I(b.Q,j,b.u);v=b.w;C=b.d; d=l(b.u,(1<>>4;if(p>>>8==0){W[w++]=p}else if(p==256){break}else{var z=w+p-254; if(p>264){var _=b.q[p-257];z=w+(_>>>3)+A(N,d,_&7);d+=_&7}var $=C[e(N,d)&u];d+=$&15;var s=$>>>4,Y=b.c[s],a=(Y>>>4)+n(N,d,Y&15); d+=Y&15;while(w>>4; if(b<=15){A[I]=b;I++}else{var Z=0,m=0;if(b==16){m=3+l(V,n,2);n+=2;Z=A[I-1]}else if(b==17){m=3+l(V,n,3); n+=3}else if(b==18){m=11+l(V,n,7);n+=7}var J=I+m;while(I>>1; while(An)n=M;A++}while(A>1,I=N[l+1],e=M<<4|I,b=W-I,Z=N[l]<>>15-W;R[J]=e;Z++}}};H.H.l=function(N,W){var R=H.H.m.r,V=15-W;for(var n=0;n>>V}};H.H.M=function(N,W,R){R=R<<(W&7);var V=W>>>3;N[V]|=R;N[V+1]|=R>>>8}; H.H.I=function(N,W,R){R=R<<(W&7);var V=W>>>3;N[V]|=R;N[V+1]|=R>>>8;N[V+2]|=R>>>16};H.H.e=function(N,W,R){return(N[W>>>3]|N[(W>>>3)+1]<<8)>>>(W&7)&(1<>>3]|N[(W>>>3)+1]<<8|N[(W>>>3)+2]<<16)>>>(W&7)&(1<>>3]|N[(W>>>3)+1]<<8|N[(W>>>3)+2]<<16)>>>(W&7)}; H.H.i=function(N,W){return(N[W>>>3]|N[(W>>>3)+1]<<8|N[(W>>>3)+2]<<16|N[(W>>>3)+3]<<24)>>>(W&7)};H.H.m=function(){var N=Uint16Array,W=Uint32Array; return{K:new N(16),j:new N(16),X:[16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15],S:[3,4,5,6,7,8,9,10,11,13,15,17,19,23,27,31,35,43,51,59,67,83,99,115,131,163,195,227,258,999,999,999],T:[0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0,0,0,0],q:new N(32),p:[1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193,257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577,65535,65535],z:[0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13,0,0],c:new W(32),J:new N(512),_:[],h:new N(32),$:[],w:new N(32768),C:[],v:[],d:new N(32768),D:[],u:new N(512),Q:[],r:new N(1<<15),s:new W(286),Y:new W(30),a:new W(19),t:new W(15e3),k:new N(1<<16),g:new N(1<<15)}}(); (function(){var N=H.H.m,W=1<<15;for(var R=0;R>>1|(V&1431655765)<<1; V=(V&3435973836)>>>2|(V&858993459)<<2;V=(V&4042322160)>>>4|(V&252645135)<<4;V=(V&4278255360)>>>8|(V&16711935)<<8; N.r[R]=(V>>>16|V<<16)>>>17}function n(A,l,M){while(l--!=0)A.push(0,M)}for(var R=0;R<32;R++){N.q[R]=N.S[R]<<3|N.T[R]; N.c[R]=N.p[R]<<4|N.z[R]}n(N._,144,8);n(N._,255-143,9);n(N._,279-255,7);n(N._,287-279,8);H.H.n(N._,9); H.H.A(N._,9,N.J);H.H.l(N._,9);n(N.$,32,5);H.H.n(N.$,5);H.H.A(N.$,5,N.h);H.H.l(N.$,5);n(N.Q,19,0);n(N.C,286,0); n(N.D,30,0);n(N.v,320,0)}());return H.H.N}() UPNG.decode._readInterlace = function(data, out) { var w = out.width, h = out.height; var bpp = UPNG.decode._getBPP(out), cbpp = bpp>>3, bpl = Math.ceil(w*bpp/8); var img = new Uint8Array( h * bpl ); var di = 0; var starting_row = [ 0, 0, 4, 0, 2, 0, 1 ]; var starting_col = [ 0, 4, 0, 2, 0, 1, 0 ]; var row_increment = [ 8, 8, 8, 4, 4, 2, 2 ]; var col_increment = [ 8, 8, 4, 4, 2, 2, 1 ]; var pass=0; while(pass<7) { var ri = row_increment[pass], ci = col_increment[pass]; var sw = 0, sh = 0; var cr = starting_row[pass]; while(cr>3]; val = (val>>(7-(cdi&7)))&1; img[row*bpl + (col>>3)] |= (val << (7-((col&7)<<0))); } if(bpp==2) { var val = data[cdi>>3]; val = (val>>(6-(cdi&7)))&3; img[row*bpl + (col>>2)] |= (val << (6-((col&3)<<1))); } if(bpp==4) { var val = data[cdi>>3]; val = (val>>(4-(cdi&7)))&15; img[row*bpl + (col>>1)] |= (val << (4-((col&1)<<2))); } if(bpp>=8) { var ii = row*bpl+col*cbpp; for(var j=0; j>3)+j]; } cdi+=bpp; col+=ci; } y++; row += ri; } if(sw*sh!=0) di += sh * (1 + bpll); pass = pass + 1; } return img; } UPNG.decode._getBPP = function(out) { var noc = [1,null,3,1,2,null,4][out.ctype]; return noc * out.depth; } UPNG.decode._filterZero = function(data, out, off, w, h) { var bpp = UPNG.decode._getBPP(out), bpl = Math.ceil(w*bpp/8), paeth = UPNG.decode._paeth; bpp = Math.ceil(bpp/8); var i=0, di=1, type=data[off], x=0; if(type>1) data[off]=[0,0,1][type-2]; if(type==3) for(x=bpp; x>>1) )&255; for(var y=0; y>>1)); for(; x>>1) ); } else { for(; x>8)&255; buff[p+1] = n&255; }, readUint : function(buff,p) { return (buff[p]*(256*256*256)) + ((buff[p+1]<<16) | (buff[p+2]<< 8) | buff[p+3]); }, writeUint : function(buff,p,n){ buff[p]=(n>>24)&255; buff[p+1]=(n>>16)&255; buff[p+2]=(n>>8)&255; buff[p+3]=n&255; }, readASCII : function(buff,p,l){ var s = ""; for(var i=0; i=0 && yoff>=0) { si = (y*sw+x)<<2; ti = (( yoff+y)*tw+xoff+x)<<2; } else { si = ((-yoff+y)*sw-xoff+x)<<2; ti = (y*tw+x)<<2; } if (mode==0) { tb[ti] = sb[si]; tb[ti+1] = sb[si+1]; tb[ti+2] = sb[si+2]; tb[ti+3] = sb[si+3]; } else if(mode==1) { var fa = sb[si+3]*(1/255), fr=sb[si]*fa, fg=sb[si+1]*fa, fb=sb[si+2]*fa; var ba = tb[ti+3]*(1/255), br=tb[ti]*ba, bg=tb[ti+1]*ba, bb=tb[ti+2]*ba; var ifa=1-fa, oa = fa+ba*ifa, ioa = (oa==0?0:1/oa); tb[ti+3] = 255*oa; tb[ti+0] = (fr+br*ifa)*ioa; tb[ti+1] = (fg+bg*ifa)*ioa; tb[ti+2] = (fb+bb*ifa)*ioa; } else if(mode==2){ // copy only differences, otherwise zero var fa = sb[si+3], fr=sb[si], fg=sb[si+1], fb=sb[si+2]; var ba = tb[ti+3], br=tb[ti], bg=tb[ti+1], bb=tb[ti+2]; if(fa==ba && fr==br && fg==bg && fb==bb) { tb[ti]=0; tb[ti+1]=0; tb[ti+2]=0; tb[ti+3]=0; } else { tb[ti]=fr; tb[ti+1]=fg; tb[ti+2]=fb; tb[ti+3]=fa; } } else if(mode==3){ // check if can be blended var fa = sb[si+3], fr=sb[si], fg=sb[si+1], fb=sb[si+2]; var ba = tb[ti+3], br=tb[ti], bg=tb[ti+1], bb=tb[ti+2]; if(fa==ba && fr==br && fg==bg && fb==bb) continue; //if(fa!=255 && ba!=0) return false; if(fa<220 && ba>20) return false; } } return true; } UPNG.encode = function(bufs, w, h, ps, dels, tabs, forbidPlte) { if(ps==null) ps=0; if(forbidPlte==null) forbidPlte = false; var nimg = UPNG.encode.compress(bufs, w, h, ps, [false, false, false, 0, forbidPlte]); UPNG.encode.compressPNG(nimg, -1); return UPNG.encode._main(nimg, w, h, dels, tabs); } UPNG.encodeLL = function(bufs, w, h, cc, ac, depth, dels, tabs) { var nimg = { ctype: 0 + (cc==1 ? 0 : 2) + (ac==0 ? 0 : 4), depth: depth, frames: [] }; var time = Date.now(); var bipp = (cc+ac)*depth, bipl = bipp * w; for(var i=0; i1, pltAlpha = false; var leng = 8 + (16+5+4) /*+ (9+4)*/ + (anim ? 20 : 0); if(tabs["sRGB"]!=null) leng += 8+1+4; if(tabs["pHYs"]!=null) leng += 8+9+4; if(nimg.ctype==3) { var dl = nimg.plte.length; for(var i=0; i>>24)!=255) pltAlpha = true; leng += (8 + dl*3 + 4) + (pltAlpha ? (8 + dl*1 + 4) : 0); } for(var j=0; j>>8)&255, b=(c>>>16)&255; data[offset+ti+0]=r; data[offset+ti+1]=g; data[offset+ti+2]=b; } offset+=dl*3; wUi(data,offset,crc(data,offset-dl*3-4,dl*3+4)); offset+=4; // crc if(pltAlpha) { wUi(data,offset, dl); offset+=4; wAs(data,offset,"tRNS"); offset+=4; for(var i=0; i>>24)&255; offset+=dl; wUi(data,offset,crc(data,offset-dl-4,dl+4)); offset+=4; // crc } } var fi = 0; for(var j=0; j>2, bln>>2)); for(var j=0; jnw && c==img32[i-nw]) ind[i]=ind[i-nw]; else { var cmc = cmap[c]; if(cmc==null) { cmap[c]=cmc=plte.length; plte.push(c); if(plte.length>=300) break; } ind[i]=cmc; } } } //console.log("make palette", Date.now()-time); time = Date.now(); } var cc=plte.length; //console.log("colors:",cc); if(cc<=256 && forbidPlte==false) { if(cc<= 2) depth=1; else if(cc<= 4) depth=2; else if(cc<=16) depth=4; else depth=8; depth = Math.max(depth, minBits); } for(var j=0; j>1)] |= (inj[ii+x]<<(4-(x&1)*4)); else if(depth==2) for(var x=0; x>2)] |= (inj[ii+x]<<(6-(x&3)*2)); else if(depth==1) for(var x=0; x>3)] |= (inj[ii+x]<<(7-(x&7)*1)); } cimg=nimg; ctype=3; bpp=1; } else if(gotAlpha==false && frms.length==1) { // some next "reduced" frames may contain alpha for blending var nimg = new Uint8Array(nw*nh*3), area=nw*nh; for(var i=0; i palette indices", Date.now()-time); time = Date.now(); return {ctype:ctype, depth:depth, plte:plte, frames:frms }; } UPNG.encode.framize = function(bufs,w,h,alwaysBlend,evenCrd,forbidPrev) { /* DISPOSE - 0 : no change - 1 : clear to transparent - 2 : retstore to content before rendering (previous frame disposed) BLEND - 0 : replace - 1 : blend */ var frms = []; for(var j=0; jmax) max=x; if(ymay) may=y; } } if(max==-1) mix=miy=max=may=0; if(evenCrd) { if((mix&1)==1)mix--; if((miy&1)==1)miy--; } var sarea = (max-mix+1)*(may-miy+1); if(sareamax) max=cx; if(cymay) may=cy; } } if(max==-1) mix=miy=max=may=0; if(evenCrd) { if((mix&1)==1)mix--; if((miy&1)==1)miy--; } r = {x:mix, y:miy, width:max-mix+1, height:may-miy+1}; var fr = frms[i]; fr.rect = r; fr.blend = 1; fr.img = new Uint8Array(r.width*r.height*4); if(frms[i-1].dispose==0) { UPNG._copyTile(pimg,w,h, fr.img,r.width,r.height, -r.x,-r.y, 0); UPNG.encode._prepareDiff(cimg,w,h,fr.img,r); //UPNG._copyTile(cimg,w,h, fr.img,r.width,r.height, -r.x,-r.y, 2); } else UPNG._copyTile(cimg,w,h, fr.img,r.width,r.height, -r.x,-r.y, 0); } UPNG.encode._prepareDiff = function(cimg, w,h, nimg, rec) { UPNG._copyTile(cimg,w,h, nimg,rec.width,rec.height, -rec.x,-rec.y, 2); /* var n32 = new Uint32Array(nimg.buffer); var og = new Uint8Array(rec.width*rec.height*4), o32 = new Uint32Array(og.buffer); UPNG._copyTile(cimg,w,h, og,rec.width,rec.height, -rec.x,-rec.y, 0); for(var i=4; i>>2]==o32[(i>>>2)-1]) { n32[i>>>2]=o32[i>>>2]; //var j = i, c=p32[(i>>>2)-1]; //while(p32[j>>>2]==c) { n32[j>>>2]=c; j+=4; } } } for(var i=nimg.length-8; i>0; i-=4) { if(nimg[i+7]!=0 && nimg[i+3]==0 && o32[i>>>2]==o32[(i>>>2)+1]) { n32[i>>>2]=o32[i>>>2]; //var j = i, c=p32[(i>>>2)-1]; //while(p32[j>>>2]==c) { n32[j>>>2]=c; j+=4; } } }*/ } UPNG.encode._filterZero = function(img,h,bpp,bpl,data, filter, levelZero) { var fls = [], ftry=[0,1,2,3,4]; if (filter!=-1) ftry=[filter]; else if(h*bpl>500000 || bpp==1) ftry=[0]; var opts; if(levelZero) opts={level:0}; var CMPR = (data.length>10e6 && typeof UZIP!="undefined" && UZIP!=null) ? UZIP : pako; var time = Date.now(); for(var i=0; i>1) +256)&255; if(type==4) for(var x=bpp; x>1))&255; for(var x=bpp; x>1))&255; } if(type==4) { for(var x= 0; x>> 1); else c = c >>> 1; } tab[n] = c; } return tab; })(), update : function(c, buf, off, len) { for (var i=0; i>> 8); return c; }, crc : function(b,o,l) { return UPNG.crc.update(0xffffffff,b,o,l) ^ 0xffffffff; } } UPNG.quantize = function(abuf, ps) { var oimg = new Uint8Array(abuf), nimg = oimg.slice(0), nimg32 = new Uint32Array(nimg.buffer); var KD = UPNG.quantize.getKDtree(nimg, ps); var root = KD[0], leafs = KD[1]; var planeDst = UPNG.quantize.planeDst; var sb = oimg, tb = nimg32, len=sb.length; var inds = new Uint8Array(oimg.length>>2), nd; if(oimg.length<20e6) // precise, but slow :( for(var i=0; i>2] = nd.ind; tb[i>>2] = nd.est.rgba; } else for(var i=0; i>2] = nd.ind; tb[i>>2] = nd.est.rgba; } return { abuf:nimg.buffer, inds:inds, plte:leafs }; } UPNG.quantize.getKDtree = function(nimg, ps, err) { if(err==null) err = 0.0001; var nimg32 = new Uint32Array(nimg.buffer); var root = {i0:0, i1:nimg.length, bst:null, est:null, tdst:0, left:null, right:null }; // basic statistic, extra statistic root.bst = UPNG.quantize.stats( nimg,root.i0, root.i1 ); root.est = UPNG.quantize.estats( root.bst ); var leafs = [root]; while(leafs.length maxL) { maxL=leafs[i].est.L; mi=i; } if(maxL=s0 || node.i1<=s0); //console.log(maxL, leafs.length, mi); if(s0wrong) { node.est.L=0; continue; } var ln = {i0:node.i0, i1:s0, bst:null, est:null, tdst:0, left:null, right:null }; ln.bst = UPNG.quantize.stats( nimg, ln.i0, ln.i1 ); ln.est = UPNG.quantize.estats( ln.bst ); var rn = {i0:s0, i1:node.i1, bst:null, est:null, tdst:0, left:null, right:null }; rn.bst = {R:[], m:[], N:node.bst.N-ln.bst.N}; for(var i=0; i<16; i++) rn.bst.R[i] = node.bst.R[i]-ln.bst.R[i]; for(var i=0; i< 4; i++) rn.bst.m[i] = node.bst.m[i]-ln.bst.m[i]; rn.est = UPNG.quantize.estats( rn.bst ); node.left = ln; node.right = rn; leafs[mi]=ln; leafs.push(rn); } leafs.sort(function(a,b) { return b.bst.N-a.bst.N; }); for(var i=0; i0) { node0=nd.right; node1=nd.left; } var ln = UPNG.quantize.getNearest(node0, r,g,b,a); if(ln.tdst<=planeDst*planeDst) return ln; var rn = UPNG.quantize.getNearest(node1, r,g,b,a); return rn.tdst eMq) i1-=4; if(i0>=i1) break; var t = nimg32[i0>>2]; nimg32[i0>>2] = nimg32[i1>>2]; nimg32[i1>>2]=t; i0+=4; i1-=4; } while(vecDot(nimg, i0, e)>eMq) i0-=4; return i0+4; } UPNG.quantize.vecDot = function(nimg, i, e) { return nimg[i]*e[0] + nimg[i+1]*e[1] + nimg[i+2]*e[2] + nimg[i+3]*e[3]; } UPNG.quantize.stats = function(nimg, i0, i1){ var R = [0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0]; var m = [0,0,0,0]; var N = (i1-i0)>>2; for(var i=i0; i>>0) }; } UPNG.M4 = { multVec : function(m,v) { return [ m[ 0]*v[0] + m[ 1]*v[1] + m[ 2]*v[2] + m[ 3]*v[3], m[ 4]*v[0] + m[ 5]*v[1] + m[ 6]*v[2] + m[ 7]*v[3], m[ 8]*v[0] + m[ 9]*v[1] + m[10]*v[2] + m[11]*v[3], m[12]*v[0] + m[13]*v[1] + m[14]*v[2] + m[15]*v[3] ]; }, dot : function(x,y) { return x[0]*y[0]+x[1]*y[1]+x[2]*y[2]+x[3]*y[3]; }, sml : function(a,y) { return [a*y[0],a*y[1],a*y[2],a*y[3]]; } } UPNG.encode.concatRGBA = function(bufs) { var tlen = 0; for(var i=0; i0&&!Q[a-1]){a--}G.push({children:[],index:0});var C=G[0];for(n=0;n0){C=G.pop()}C.index++;G.push(C);while(G.length<=n){G.push(F={children:[],index:0});C.children[C.index]=F.children;C=F}f++}if(n+10){V--;return J>>V&1}J=Q[h++];if(J===255){var I=Q[h++];if(I){if(I===220&&d){h+=2;var l=Z(Q,h);h+=2;if(l>0&&l!==f.s){throw new DNLMarkerError("Found DNL marker (0xFFDC) while parsing scan data",l)}}else if(I===217){if(d){var M=q*8; if(M>0&&M>>7}function u(I){var l=I;while(!0){l=l[Y()];switch(typeof l){case"number":return l;case"object":continue}throw new W("invalid huffman sequence")}}function m(I){var e=0;while(I>0){e=e<<1|Y();I--}return e}function j(I){if(I===1){return Y()===1?1:-1}var e=m(I);if(e>=1<>4;if(i===0){if(A<15){break}N+=16;continue}N+=A;var o=p[N];X.D[I+o]=j(i);N++}}function $(X,I){var l=u(X.J),M=l===0?0:j(l)<0){r--;return}var N=E,l=a;while(N<=l){var M=u(X.i),S=M&15,i=M>>4;if(S===0){if(i<15){r=m(i)+(1<>4;if(S===0){if(M<15){r=m(M)+(1<0){for(O=0;O0?"unexpected":"excessive";h=k.offset}if(k.M>=65488&&k.M<=65495){h+=2}else{break}}return h-z}function al(Q,h,f){var G=Q.$,n=Q.D,E,a,C,F,d,T,U,z,J,V,Y,u,m,j,v,$,b;if(!G){throw new W("missing required Quantization Table.")}for(var r=0;r<64;r+=8){J=n[h+r];V=n[h+r+1];Y=n[h+r+2];u=n[h+r+3];m=n[h+r+4];j=n[h+r+5];v=n[h+r+6];$=n[h+r+7];J*=G[r];if((V|Y|u|m|j|v|$)===0){b=s*J+512>>10;f[r]=b;f[r+1]=b;f[r+2]=b;f[r+3]=b;f[r+4]=b;f[r+5]=b;f[r+6]=b;f[r+7]=b;continue}V*=G[r+1];Y*=G[r+2];u*=G[r+3];m*=G[r+4];j*=G[r+5];v*=G[r+6];$*=G[r+7];E=s*J+128>>8;a=s*m+128>>8;C=Y;F=v;d=ad*(V-$)+128>>8;z=ad*(V+$)+128>>8; T=u<<4;U=j<<4;E=E+a+1>>1;a=E-a;b=C*ai+F*ar+128>>8;C=C*ar-F*ai+128>>8;F=b;d=d+U+1>>1;U=d-U;z=z+T+1>>1;T=z-T;E=E+F+1>>1;F=E-F;a=a+C+1>>1;C=a-C;b=d*ao+z*ah+2048>>12;d=d*ah-z*ao+2048>>12;z=b;b=T*ac+U*t+2048>>12;T=T*t-U*ac+2048>>12;U=b;f[r]=E+z;f[r+7]=E-z;f[r+1]=a+U;f[r+6]=a-U;f[r+2]=C+T;f[r+5]=C-T;f[r+3]=F+d;f[r+4]=F-d}for(var P=0;P<8;++P){J=f[P];V=f[P+8];Y=f[P+16];u=f[P+24];m=f[P+32];j=f[P+40];v=f[P+48];$=f[P+56];if((V|Y|u|m|j|v|$)===0){b=s*J+8192>>14;if(b<-2040){b=0}else if(b>=2024){b=255}else{b=b+2056>>4}n[h+P]=b;n[h+P+8]=b;n[h+P+16]=b;n[h+P+24]=b;n[h+P+32]=b;n[h+P+40]=b;n[h+P+48]=b;n[h+P+56]=b;continue}E=s*J+2048>>12;a=s*m+2048>>12;C=Y;F=v;d=ad*(V-$)+2048>>12;z=ad*(V+$)+2048>>12;T=u;U=j;E=(E+a+1>>1)+4112;a=E-a;b=C*ai+F*ar+2048>>12;C=C*ar-F*ai+2048>>12;F=b;d=d+U+1>>1;U=d-U;z=z+T+1>>1;T=z-T;E=E+F+1>>1;F=E-F;a=a+C+1>>1;C=a-C;b=d*ao+z*ah+2048>>12;d=d*ah-z*ao+2048>>12;z=b; b=T*ac+U*t+2048>>12;T=T*t-U*ac+2048>>12;U=b;J=E+z;$=E-z;V=a+U;v=a-U;Y=C+T;j=C-T;u=F+d;m=F-d;if(J<16){J=0}else if(J>=4080){J=255}else{J>>=4}if(V<16){V=0}else if(V>=4080){V=255}else{V>>=4}if(Y<16){Y=0}else if(Y>=4080){Y=255}else{Y>>=4}if(u<16){u=0}else if(u>=4080){u=255}else{u>>=4}if(m<16){m=0}else if(m>=4080){m=255}else{m>>=4}if(j<16){j=0}else if(j>=4080){j=255}else{j>>=4}if(v<16){v=0}else if(v>=4080){v=255}else{v>>=4}if($<16){$=0}else if($>=4080){$=255}else{$>>=4}n[h+P]=J; n[h+P+8]=V;n[h+P+16]=Y;n[h+P+24]=u;n[h+P+32]=m;n[h+P+40]=j;n[h+P+48]=v;n[h+P+56]=$}}function a0(Q,h){var f=h.P,G=h.c,n=new Int16Array(64);for(var E=0;E=G){return null}var E=Z(Q,h);if(E>=65472&&E<=65534){return{u:null,M:E,offset:h}}var a=Z(Q,n);while(!(a>=65472&&a<=65534)){if(++n>=G){return null}a=Z(Q,n)}return{u:E.toString(16),M:a,offset:n}}ak.prototype={parse(Q,h){if(h==null)h={}; var f=h.F,E=0,a=null,C=null,F,d,T=0;function G(){var o=Z(Q,E);E+=2;var B=E+o-2,V=an(Q,B,E);if(V&&V.u){B=V.offset}var ab=Q.subarray(E,B);E+=ab.length;return ab}function n(F){var o=Math.ceil(F.o/8/F.X),B=Math.ceil(F.s/8/F.B);for(var Y=0;Y>4===0){for(u=0;u<64;u++){b=p[u];P[b]=Q[E++]}}else if(r>>4===1){for(u=0;u<64;u++){b=p[u];P[b]=Z(Q,E);E+=2}}else{throw new W("DQT - invalid table spec")}U[r&15]=P}break;case 65472:case 65473:case 65474:if(F){throw new W("Only single frame JPEGs supported")}E+=2;F={};F.G=V===65473;F.Z=V===65474;F.precision=Q[E++];var D=Z(Q,E),a4,q=0,H=0;E+=2;F.s=f||D;F.o=Z(Q,E);E+=2;F.W=[];F._={};var a8=Q[E++];for(Y=0;Y>4,y=Q[E+1]&15;if(q>4===0?J:z)[_&15]=a5(N,K)}break;case 65501:E+=2;d=Z(Q,E);E+=2;break;case 65498:var x=++T===1&&!f,R;E+=2;var k=Q[E++],g=[];for(Y=0;Y>4];R.i=z[a6&15];g.push(R)}var I=Q[E++],l=Q[E++],M=Q[E++];try{var S=a7(Q,E,F,g,d,I,l,M>>4,M&15,x);E+=S}catch(ex){if(ex instanceof DNLMarkerError){return this.parse(Q,{F:ex.s})}else if(ex instanceof EOIMarkerError){break markerLoop}throw ex}break;case 65500:E+=4;break;case 65535:if(Q[E]!==255){E--}break;default:var i=an(Q,E-2,E-3);if(i&&i.u){E=i.offset;break}if(E>=Q.length-1){break markerLoop}throw new W("JpegImage.parse - unknown marker: "+V.toString(16))}V=Z(Q,E);E+=2}this.width=F.o;this.height=F.s;this.g=a;this.b=C;this.W=[];for(Y=0;Y>8)+P[J+1]}}}return v},get f(){if(this.b){return!!this.b.a}if(this.p===3){if(this.N===0){return!1}else if(this.W[0].index===82&&this.W[1].index===71&&this.W[2].index===66){return!1}return!0}if(this.N===1){return!0}return!1},z:function aj(Q){var h,f,G; for(var n=0,E=Q.length;n4){throw new W("Unsupported color mode")}var E=this.Y(h,f,n);if(this.p===1&&G){var a=E.length,C=new Uint8ClampedArray(a*3),F=0;for(var d=0;d>24}function Z(p,t){return p[t]<<8|p[t+1]}function am(p,t){return(p[t]<<24|p[t+1]<<16|p[t+2]<<8|p[t+3])>>>0}UTIF.JpegDecoder=ak}()); //UTIF.JpegDecoder = PDFJS.JpegImage; UTIF.encodeImage = function(rgba, w, h, metadata) { var idf = { "t256":[w], "t257":[h], "t258":[8,8,8,8], "t259":[1], "t262":[2], "t273":[1000], // strips offset "t277":[4], "t278":[h], /* rows per strip */ "t279":[w*h*4], // strip byte counts "t282":[[72,1]], "t283":[[72,1]], "t284":[1], "t286":[[0,1]], "t287":[[0,1]], "t296":[1], "t305": ["Photopea (UTIF.js)"], "t338":[1] }; if (metadata) for (var i in metadata) idf[i] = metadata[i]; var prfx = new Uint8Array(UTIF.encode([idf])); var img = new Uint8Array(rgba); var data = new Uint8Array(1000+w*h*4); for(var i=0; i probably not an image img.isLE = id=="II"; img.width = img["t256"][0]; //delete img["t256"]; img.height = img["t257"][0]; //delete img["t257"]; var cmpr = img["t259"] ? img["t259"][0] : 1; //delete img["t259"]; var fo = img["t266"] ? img["t266"][0] : 1; //delete img["t266"]; if(img["t284"] && img["t284"][0]==2) log("PlanarConfiguration 2 should not be used!"); var bipp; // bits per pixel if(img["t258"]) bipp = Math.min(32,img["t258"][0])*img["t258"].length; else bipp = (img["t277"]?img["t277"][0]:1); // Some .NEF files have t258==14, even though they use 16 bits per pixel if(cmpr==1 && img["t279"]!=null && img["t278"] && img["t262"][0]==32803) { bipp = Math.round((img["t279"][0]*8)/(img.width*img["t278"][0])); } var bipl = Math.ceil(img.width*bipp/8)*8; var soff = img["t273"]; if(soff==null) soff = img["t324"]; var bcnt = img["t279"]; if(cmpr==1 && soff.length==1) bcnt = [img.height*(bipl>>>3)]; if(bcnt==null) bcnt = img["t325"]; //bcnt[0] = Math.min(bcnt[0], data.length); // Hasselblad, "RAW_HASSELBLAD_H3D39II.3FR" var bytes = new Uint8Array(img.height*(bipl>>>3)), bilen = 0; if(img["t322"]!=null) // tiled { var tw = img["t322"][0], th = img["t323"][0]; var tx = Math.floor((img.width + tw - 1) / tw); var ty = Math.floor((img.height + th - 1) / th); var tbuff = new Uint8Array(Math.ceil(tw*th*bipp/8)|0); for(var y=0; y>>3, h = (img["t278"] ? img["t278"][0] : img.height), bpl = Math.ceil(bps*noc*img.width/8); // convert to Little Endian /* if(bps==16 && !img.isLE && img["t33422"]==null) // not DNG for(var y=0; y>>8)&255; } else if(noc==3) for(var j= 3; j>>3]>>>7-(P&7)&1;B[1]++;return D}function aj(B,P){if(x==null){x={}; for(var D=0;D>>1}return B}function c(B,P){return B>>P}function N(B,P,D,U,X,y){P[D]=c(c(11*B[X]-4*B[X+y]+B[X+y+y]+4,3)+B[U],1); P[D+y]=c(c(5*B[X]+4*B[X+y]-B[X+y+y]+4,3)-B[U],1)}function g(B,P,D,U,X,y){var n=B[X-y]-B[X+y],S=B[X],O=B[U]; P[D]=c(c(n+4,3)+S+O,1);P[D+y]=c(c(-n+4,3)+S-O,1)}function L(B,P,D,U,X,y){P[D]=c(c(5*B[X]+4*B[X-y]-B[X-y-y]+4,3)+B[U],1); P[D+y]=c(c(11*B[X]-4*B[X-y]+B[X-y-y]+4,3)-B[U],1)}function t(B){B=B<0?0:B>4095?4095:B;B=H[B]>>>2;return B}function ab(B,P,D,U,X){U=new Uint16Array(U.buffer); var y=Date.now(),n=UTIF._binBE,S=P+D,O,q,i,M,m,aA,T,a8,a0,am,au,a3,aw,ao,v,ax,p,k;P+=4;while(P>>1)*(i>>>1));k=new Int16Array((q>>>1)*(i>>>1));u=new Int16Array(1024); for(var f=0;f<1024;f++){var aF=f-512,j=Math.abs(aF),O=Math.floor(768*j*j*j/(255*255*255))+j;u[f]=Math.sign(aF)*O}H=new Uint16Array(4096); var al=(1<<16)-1;for(var f=0;f<4096;f++){var ad=f,az=al*(Math.pow(113,ad/4095)-1)/112;H[f]=Math.min(az,al)}}var Z=p[T],V=Q(q,1+d[M]),z=Q(i,1+d[M]); if(M==0){for(var b=0;b>>1)+G]=B[w]<<8|B[w+1]}}else{var aC=[B,P*8],aq=[],a5=0,ae=V*z,I=[0,0],s=0,E=0; while(a50){aq[a5++]=E;s--}}var $=(M-1)%3,aE=$!=1?V:0,as=$!=0?z:0; for(var b=0;b>>1)+aE,aa=b*V;for(var G=0;G>>1,an=V*2,at=z*2; for(var b=0;b>14-r*2&3;var af=a6[aD];if(af!=0)for(var b=0;b>>1)*(q>>>1)+(G>>>1),R=a2[w],ak=ar[w]-2048,aB=ah[w]-2048,av=a1[w]-2048,a4=(ak<<1)+R,a9=(aB<<1)+R,ap=R+av,ag=R-av; U[J]=t(a4);U[J+1]=t(ap);U[J+q]=t(ag);U[J+q+1]=t(a9)}}P+=o*4}else if(C==16388){P+=o*4}else if(F==8192||F==8448||F==9216){}else throw C.toString(16)}}console.log(Date.now()-y)}return ab}() UTIF.decode._ljpeg_diff = function(data, prm, huff) { var getbithuff = UTIF.decode._getbithuff; var len, diff; len = getbithuff(data, prm, huff[0], huff); diff = getbithuff(data, prm, len, 0); if ((diff & (1 << (len-1))) == 0) diff -= (1 << len) - 1; return diff; } UTIF.decode._decodeARW = function(img, inp, off, src_length, tgt, toff) { var raw_width = img["t256"][0], height=img["t257"][0], tiff_bps=img["t258"][0]; var bin=(img.isLE ? UTIF._binLE : UTIF._binBE); //console.log(raw_width, height, tiff_bps, raw_width*height, src_length); var arw2 = (raw_width*height == src_length) || (raw_width*height*1.5 == src_length); //arw2 = true; //console.log("ARW2: ", arw2, raw_width*height, src_length, tgt.length); if(!arw2) { //"sony_arw_load_raw"; // not arw2 height+=8; var prm = [off,0,0,0]; var huff = new Uint16Array(32770); var tab = [ 0xf11,0xf10,0xe0f,0xd0e,0xc0d,0xb0c,0xa0b,0x90a,0x809, 0x708,0x607,0x506,0x405,0x304,0x303,0x300,0x202,0x201 ]; var i, c, n, col, row, sum=0; var ljpeg_diff = UTIF.decode._ljpeg_diff; huff[0] = 15; for (n=i=0; i < 18; i++) { var lim = 32768 >>> (tab[i] >>> 8); for(var c=0; c>>4); tgt[toff+i+1]=(b0<<4)|(b2>>>4); tgt[toff+i+2]=(b2<<4)|(b1>>>4); } return; } var pix = new Uint16Array(16); var row, col, val, max, min, imax, imin, sh, bit, i, dp; var data = new Uint8Array(raw_width+1); for (row=0; row < height; row++) { //fread (data, 1, raw_width, ifp); for(var j=0; j>> 11); imax = 0x0f & (val >>> 22); imin = 0x0f & (val >>> 26); for (sh=0; sh < 4 && 0x80 << sh <= max-min; sh++); for (bit=30, i=0; i < 16; i++) if (i == imax) pix[i] = max; else if (i == imin) pix[i] = min; else { pix[i] = ((bin.readUshort(data, dp+(bit >> 3)) >>> (bit & 7) & 0x7f) << sh) + min; if (pix[i] > 0x7ff) pix[i] = 0x7ff; bit += 7; } for (i=0; i < 16; i++, col+=2) { //RAW(row,col) = curve[pix[i] << 1] >> 2; var clr = pix[i]<<1; //clr = 0xffff; UTIF.decode._putsF(tgt, (row*raw_width+col)*tiff_bps, clr<<(16-tiff_bps)); } col -= col & 1 ? 1:31; } } } UTIF.decode._decodeNikon = function(img,imgs, data, off, src_length, tgt, toff) { var nikon_tree = [ [ 0, 0,1,5,1,1,1,1,1,1,2,0,0,0,0,0,0, /* 12-bit lossy */ 5,4,3,6,2,7,1,0,8,9,11,10,12 ], [ 0, 0,1,5,1,1,1,1,1,1,2,0,0,0,0,0,0, /* 12-bit lossy after split */ 0x39,0x5a,0x38,0x27,0x16,5,4,3,2,1,0,11,12,12 ], [ 0, 0,1,4,2,3,1,2,0,0,0,0,0,0,0,0,0, /* 12-bit lossless */ 5,4,6,3,7,2,8,1,9,0,10,11,12 ], [ 0, 0,1,4,3,1,1,1,1,1,2,0,0,0,0,0,0, /* 14-bit lossy */ 5,6,4,7,8,3,9,2,1,0,10,11,12,13,14 ], [ 0, 0,1,5,1,1,1,1,1,1,1,2,0,0,0,0,0, /* 14-bit lossy after split */ 8,0x5c,0x4b,0x3a,0x29,7,6,5,4,3,2,1,0,13,14 ], [ 0, 0,1,4,2,2,3,1,2,0,0,0,0,0,0,0,0, /* 14-bit lossless */ 7,6,8,5,9,4,10,3,11,12,2,0,1,13,14 ] ]; var raw_width = img["t256"][0], height=img["t257"][0], tiff_bps=img["t258"][0]; var tree = 0, split = 0; var make_decoder = UTIF.decode._make_decoder; var getbithuff = UTIF.decode._getbithuff; var mn = imgs[0].exifIFD.makerNote, md = mn["t150"]?mn["t150"]:mn["t140"], mdo=0; //console.log(mn,md); //console.log(md[0].toString(16), md[1].toString(16), tiff_bps); var ver0 = md[mdo++], ver1 = md[mdo++]; if (ver0 == 0x49 || ver1 == 0x58) mdo+=2110; if (ver0 == 0x46) tree = 2; if (tiff_bps == 14) tree += 3; var vpred = [[0,0],[0,0]], bin=(img.isLE ? UTIF._binLE : UTIF._binBE); for(var i=0; i<2; i++) for(var j=0; j<2; j++) { vpred[i][j] = bin.readShort(md,mdo); mdo+=2; } // not sure here ... [i][j] or [j][i] //console.log(vpred); var max = 1 << tiff_bps & 0x7fff, step=0; var csize = bin.readShort(md,mdo); mdo+=2; if (csize > 1) step = Math.floor(max / (csize-1)); if (ver0 == 0x44 && ver1 == 0x20 && step > 0) split = bin.readShort(md,562); var i; var row, col; var len, shl, diff; var min_v = 0; var hpred = [0,0]; var huff = make_decoder(nikon_tree[tree]); //var g_input_offset=0, bitbuf=0, vbits=0, reset=0; var prm = [off,0,0,0]; //console.log(split); split = 170; for (min_v=row=0; row < height; row++) { if (split && row == split) { //free (huff); huff = make_decoder (nikon_tree[tree+1]); //max_v += (min_v = 16) << 1; } for (col=0; col < raw_width; col++) { i = getbithuff(data,prm,huff[0],huff); len = i & 15; shl = i >>> 4; diff = (((getbithuff(data,prm,len-shl,0) << 1) + 1) << shl) >>> 1; if ((diff & (1 << (len-1))) == 0) diff -= (1 << len) - (shl==0?1:0); if (col < 2) hpred[col] = vpred[row & 1][col] += diff; else hpred[col & 1] += diff; var clr = Math.min(Math.max(hpred[col & 1],0),(1<>>3); dt[o]|=val>>>16; dt[o+1]|=val>>>8; dt[o+2]|=val; } UTIF.decode._getbithuff = function(data,prm,nbits, huff) { var zero_after_ff = 0; var get_byte = UTIF.decode._get_byte; var c; var off=prm[0], bitbuf=prm[1], vbits=prm[2], reset=prm[3]; //if (nbits > 25) return 0; //if (nbits < 0) return bitbuf = vbits = reset = 0; if (nbits == 0 || vbits < 0) return 0; while (!reset && vbits < nbits && (c = data[off++]) != -1 && !(reset = zero_after_ff && c == 0xff && data[off++])) { //console.log("byte read into c"); bitbuf = (bitbuf << 8) + c; vbits += 8; } c = (bitbuf << (32-vbits)) >>> (32-nbits); if (huff) { vbits -= huff[c+1] >>> 8; //console.log(c, huff[c]>>8); c = huff[c+1]&255; } else vbits -= nbits; if (vbits < 0) throw "e"; prm[0]=off; prm[1]=bitbuf; prm[2]=vbits; prm[3]=reset; return c; } UTIF.decode._make_decoder = function(source) { var max, len, h, i, j; var huff = []; for (max=16; max!=0 && !source[max]; max--); var si=17; huff[0] = max; for (h=len=1; len <= max; len++) for (i=0; i < source[len]; i++, ++si) for (j=0; j < 1 << (max-len); j++) if (h <= 1 << max) huff[h++] = (len << 8) | source[si]; return huff; } UTIF.decode._decodeNewJPEG = function(img, data, off, len, tgt, toff) { len = Math.min(len, data.length-off); var tables = img["t347"], tlen = tables ? tables.length : 0, buff = new Uint8Array(tlen + len); if (tables) { var SOI = 216, EOI = 217, boff = 0; for (var i=0; i<(tlen-1); i++) { // Skip EOI marker from JPEGTables if (tables[i]==255 && tables[i+1]==EOI) break; buff[boff++] = tables[i]; } // Skip SOI marker from data var byte1 = data[off], byte2 = data[off + 1]; if (byte1!=255 || byte2!=SOI) { buff[boff++] = byte1; buff[boff++] = byte2; } for (var i=2; i>>8); } else for(var i=0; i>>8); tgt[toff+(i<<1)+1] = (out[i]&255); } } else if(bps==14 || bps==12) { // 4 * 14 == 56 == 7 * 8 var rst = 16-bps; for(var i=0; i 1); } if(!isTiled) { if(data[off]==255 && data[off+1]==SOI) return { jpegOffset: off }; if(jpgIchgFmt!=null) { if(data[off+jifoff]==255 && data[off+jifoff+1]==SOI) joff = off+jifoff; else log("JPEGInterchangeFormat does not point to SOI"); if(jpgIchgFmtLen==null) log("JPEGInterchangeFormatLength field is missing"); else if(jifoff >= soff || (jifoff+jiflen) <= soff) log("JPEGInterchangeFormatLength field value is invalid"); if(joff != null) return { jpegOffset: joff }; } } if(ycbcrss!=null) { ssx = ycbcrss[0]; ssy = ycbcrss[1]; } if(jpgIchgFmt!=null) if(jpgIchgFmtLen!=null) if(jiflen >= 2 && (jifoff+jiflen) <= soff) { if(data[off+jifoff+jiflen-2]==255 && data[off+jifoff+jiflen-1]==SOI) tables = new Uint8Array(jiflen-2); else tables = new Uint8Array(jiflen); for(i=0; i offset to first strip or tile"); if(tables == null) { var ooff = 0, out = []; out[ooff++] = 255; out[ooff++] = SOI; var qtables = img["t519"]; if(qtables==null) throw new Error("JPEGQTables tag is missing"); for(i=0; i>> 8); out[ooff++] = nc & 255; out[ooff++] = (i | (k << 4)); for(j=0; j<16; j++) out[ooff++] = data[off+htables[i]+j]; for(j=0; j>> 8) & 255; out[ooff++] = img.height & 255; out[ooff++] = (img.width >>> 8) & 255; out[ooff++] = img.width & 255; out[ooff++] = spp; if(spp==1) { out[ooff++] = 1; out[ooff++] = 17; out[ooff++] = 0; } else for(i=0; i<3; i++) { out[ooff++] = i + 1; out[ooff++] = (i != 0) ? 17 : (((ssx & 15) << 4) | (ssy & 15)); out[ooff++] = i; } if(jpgresint!=null && jpgresint[0]!=0) { out[ooff++] = 255; out[ooff++] = DRI; out[ooff++] = 0; out[ooff++] = 4; out[ooff++] = (jpgresint[0] >>> 8) & 255; out[ooff++] = jpgresint[0] & 255; } tables = new Uint8Array(out); } var sofpos = -1; i = 0; while(i < (tables.length - 1)) { if(tables[i]==255 && tables[i+1]==SOF0) { sofpos = i; break; } i++; } if(sofpos == -1) { var tmptab = new Uint8Array(tables.length + 10 + 3*spp); tmptab.set(tables); var tmpoff = tables.length; sofpos = tables.length; tables = tmptab; tables[tmpoff++] = 255; tables[tmpoff++] = SOF0; tables[tmpoff++] = 0; tables[tmpoff++] = 8 + 3*spp; tables[tmpoff++] = 8; tables[tmpoff++] = (img.height >>> 8) & 255; tables[tmpoff++] = img.height & 255; tables[tmpoff++] = (img.width >>> 8) & 255; tables[tmpoff++] = img.width & 255; tables[tmpoff++] = spp; if(spp==1) { tables[tmpoff++] = 1; tables[tmpoff++] = 17; tables[tmpoff++] = 0; } else for(i=0; i<3; i++) { tables[tmpoff++] = i + 1; tables[tmpoff++] = (i != 0) ? 17 : (((ssx & 15) << 4) | (ssy & 15)); tables[tmpoff++] = i; } } if(data[soff]==255 && data[soff+1]==SOS) { var soslen = (data[soff+2]<<8) | data[soff+3]; sosMarker = new Uint8Array(soslen+2); sosMarker[0] = data[soff]; sosMarker[1] = data[soff+1]; sosMarker[2] = data[soff+2]; sosMarker[3] = data[soff+3]; for(i=0; i<(soslen-2); i++) sosMarker[i+4] = data[soff+i+4]; } else { sosMarker = new Uint8Array(2 + 6 + 2*spp); var sosoff = 0; sosMarker[sosoff++] = 255; sosMarker[sosoff++] = SOS; sosMarker[sosoff++] = 0; sosMarker[sosoff++] = 6 + 2*spp; sosMarker[sosoff++] = spp; if(spp==1) { sosMarker[sosoff++] = 1; sosMarker[sosoff++] = 0; } else for(i=0; i<3; i++) { sosMarker[sosoff++] = i+1; sosMarker[sosoff++] = (i << 4) | i; } sosMarker[sosoff++] = 0; sosMarker[sosoff++] = 63; sosMarker[sosoff++] = 0; } return { jpegOffset: off, tables: tables, sosMarker: sosMarker, sofPosition: sofpos }; } UTIF.decode._decodeOldJPEG = function(img, data, off, len, tgt, toff) { var i, dlen, tlen, buff, buffoff; var jpegData = UTIF.decode._decodeOldJPEGInit(img, data, off, len); if(jpegData.jpegOffset!=null) { dlen = off+len-jpegData.jpegOffset; buff = new Uint8Array(dlen); for(i=0; i>> 8) & 255; buff[jpegData.sofPosition+6] = img.height & 255; buff[jpegData.sofPosition+7] = (img.width >>> 8) & 255; buff[jpegData.sofPosition+8] = img.width & 255; if(data[off]!=255 || data[off+1]!=SOS) { buff.set(jpegData.sosMarker, buffoff); buffoff += sosMarker.length; } for(i=0; i=0 && n<128) for(var i=0; i< n+1; i++) { ta[toff]=sa[off]; toff++; off++; } if(n>=-127 && n<0) { for(var i=0; i<-n+1; i++) { ta[toff]=sa[off]; toff++; } off++; } } } UTIF.decode._decodeThunder = function(data, off, len, tgt, toff) { var d2 = [ 0, 1, 0, -1 ], d3 = [ 0, 1, 2, 3, 0, -3, -2, -1 ]; var lim = off+len, qoff = toff*2, px = 0; while(off>>6), n = (b&63); off++; if(msk==3) { px=(n&15); tgt[qoff>>>1] |= (px<<(4*(1-qoff&1))); qoff++; } if(msk==0) for(var i=0; i>>1] |= (px<<(4*(1-qoff&1))); qoff++; } if(msk==2) for(var i=0; i<2; i++) { var d=(n>>>(3*(1-i)))&7; if(d!=4) { px+=d3[d]; tgt[qoff>>>1] |= (px<<(4*(1-qoff&1))); qoff++; } } if(msk==1) for(var i=0; i<3; i++) { var d=(n>>>(2*(2-i)))&3; if(d!=2) { px+=d2[d]; tgt[qoff>>>1] |= (px<<(4*(1-qoff&1))); qoff++; } } } } UTIF.decode._dmap = { "1":0,"011":1,"000011":2,"0000011":3, "010":-1,"000010":-2,"0000010":-3 }; UTIF.decode._lens = ( function() { var addKeys = function(lens, arr, i0, inc) { for(var i=0; i>>3)>>3]>>>(7-(boff&7)))&1; if(fo==2) bit = (data[boff>>>3]>>>( (boff&7)))&1; boff++; wrd+=bit; if(mode=="H") { if(U._lens[clr][wrd]!=null) { var dl=U._lens[clr][wrd]; wrd=""; len+=dl; if(dl<64) { U._addNtimes(line,len,clr); a0+=len; clr=1-clr; len=0; toRead--; if(toRead==0) mode=""; } } } else { if(wrd=="0001") { wrd=""; U._addNtimes(line,b2-a0,clr); a0=b2; } if(wrd=="001" ) { wrd=""; mode="H"; toRead=2; } if(U._dmap[wrd]!=null) { a1 = b1+U._dmap[wrd]; U._addNtimes(line, a1-a0, clr); a0=a1; wrd=""; clr=1-clr; } } if(line.length==w && mode=="") { U._writeBits(line, tgt, toff*8+y*bipl); clr=0; y++; a0=0; pline=U._makeDiff(line); line=[]; } //if(wrd.length>150) { log(wrd); break; throw "e"; } } } UTIF.decode._findDiff = function(line, x, clr) { for(var i=0; i=x && line[i+1]==clr) return line[i]; } UTIF.decode._makeDiff = function(line) { var out = []; if(line[0]==1) out.push(0,1); for(var i=1; i>>3)>>3]>>>(7-(boff&7)))&1; if(fo==2) bit = (data[boff>>>3]>>>( (boff&7)))&1; boff++; wrd+=bit; if(is1D) { if(U._lens[clr][wrd]!=null) { var dl=U._lens[clr][wrd]; wrd=""; len+=dl; if(dl<64) { U._addNtimes(line,len,clr); clr=1-clr; len=0; } } } else { if(mode=="H") { if(U._lens[clr][wrd]!=null) { var dl=U._lens[clr][wrd]; wrd=""; len+=dl; if(dl<64) { U._addNtimes(line,len,clr); a0+=len; clr=1-clr; len=0; toRead--; if(toRead==0) mode=""; } } } else { if(wrd=="0001") { wrd=""; U._addNtimes(line,b2-a0,clr); a0=b2; } if(wrd=="001" ) { wrd=""; mode="H"; toRead=2; } if(U._dmap[wrd]!=null) { a1 = b1+U._dmap[wrd]; U._addNtimes(line, a1-a0, clr); a0=a1; wrd=""; clr=1-clr; } } } if(wrd.endsWith("000000000001")) // needed for some files { if(y>=0) U._writeBits(line, tgt, toff*8+y*bipl); if(twoDim) { if(fo==1) is1D = ((data[boff>>>3]>>>(7-(boff&7)))&1)==1; if(fo==2) is1D = ((data[boff>>>3]>>>( (boff&7)))&1)==1; boff++; } //log("EOL",y, "next 1D:", is1D); wrd=""; clr=0; y++; a0=0; pline=U._makeDiff(line); line=[]; } } if(line.length==w) U._writeBits(line, tgt, toff*8+y*bipl); } UTIF.decode._addNtimes = function(arr, n, val) { for(var i=0; i>>3] |= (bits[i]<<(7-((boff+i)&7))); } UTIF.decode._decodeLZW=UTIF.decode._decodeLZW=function(){var e,U,Z,u,K=0,V=0,g=0,N=0,O=function(){var S=e>>>3,A=U[S]<<16|U[S+1]<<8|U[S+2],j=A>>>24-(e&7)-V&(1<>>----------------"); for(var i=0; i4) { bin.writeUint(data, offset, eoff); toff=eoff; } if (type== 1 || type==7) { for(var i=0; i4) { dlen += (dlen&1); eoff += dlen; } offset += 4; } return [offset, eoff]; } UTIF.toRGBA8 = function(out, scl) { var w = out.width, h = out.height, area = w*h, qarea = area*4, data = out.data; var img = new Uint8Array(area*4); //console.log(out); // 0: WhiteIsZero, 1: BlackIsZero, 2: RGB, 3: Palette color, 4: Transparency mask, 5: CMYK var intp = (out["t262"] ? out["t262"][0]: 2), bps = (out["t258"]?Math.min(32,out["t258"][0]):1); if(out["t262"]==null && bps==1) intp=0; //log("interpretation: ", intp, "bps", bps, out); if(false) {} else if(intp==0) { var bpl = Math.ceil(bps*w/8); for(var y=0; y>3)])>>(7- (i&7)))& 1; img[qi]=img[qi+1]=img[qi+2]=( 1-px)*255; img[qi+3]=255; } if(bps== 4) for(var i=0; i>1)])>>(4-4*(i&1)))&15; img[qi]=img[qi+1]=img[qi+2]=(15-px)* 17; img[qi+3]=255; } if(bps== 8) for(var i=0; i>3)])>>(7- (i&7)))&1; img[qi]=img[qi+1]=img[qi+2]=(px)*255; img[qi+3]=255; } if(bps== 2) for(var i=0; i>2)])>>(6-2*(i&3)))&3; img[qi]=img[qi+1]=img[qi+2]=(px)* 85; img[qi+3]=255; } if(bps== 8) for(var i=0; i>>3)]>>>(7-(x&7)))&1; else if(bps==2) mi=(data[dof+(x>>>2)]>>>(6-2*(x&3)))&3; else if(bps==4) mi=(data[dof+(x>>>1)]>>>(4-4*(x&1)))&15; else if(bps==8) mi= data[dof+x*smpls]; else throw bps; img[qi]=(map[mi]>>8); img[qi+1]=(map[cn+mi]>>8); img[qi+2]=(map[cn+cn+mi]>>8); img[qi+3]=255; } } else if(intp==5) { var smpls = out["t258"]?out["t258"].length : 4; var gotAlpha = smpls>4 ? 1 : 0; for(var i=0; i>>1); var Y = data[si+(j&1)], Cb=data[si+2]-128, Cr=data[si+3]-128; var r = Y + ( (Cr >> 2) + (Cr >> 3) + (Cr >> 5) ) ; var g = Y - ( (Cb >> 2) + (Cb >> 4) + (Cb >> 5)) - ( (Cr >> 1) + (Cr >> 3) + (Cr >> 4) + (Cr >> 5)) ; var b = Y + ( Cb + (Cb >> 1) + (Cb >> 2) + (Cb >> 6)) ; img[qi ]=Math.max(0,Math.min(255,r)); img[qi+1]=Math.max(0,Math.min(255,g)); img[qi+2]=Math.max(0,Math.min(255,b)); img[qi+3]=255; } } } else log("Unknown Photometric interpretation: "+intp); return img; } UTIF.replaceIMG = function(imgs) { if(imgs==null) imgs = document.getElementsByTagName("img"); var sufs = ["tif","tiff","dng","cr2","nef"] for (var i=0; ima) { ma=ar; page=img; } } UTIF.decodeImage(buff, page, ifds); var rgba = UTIF.toRGBA8(page), w=page.width, h=page.height; var cnv = document.createElement("canvas"); cnv.width=w; cnv.height=h; var ctx = cnv.getContext("2d"); var imgd = new ImageData(new Uint8ClampedArray(rgba.buffer),w,h); ctx.putImageData(imgd,0,0); return cnv.toDataURL(); } UTIF._binBE = { nextZero : function(data, o) { while(data[o]!=0) o++; return o; }, readUshort : function(buff, p) { return (buff[p]<< 8) | buff[p+1]; }, readShort : function(buff, p) { var a=UTIF._binBE.ui8; a[0]=buff[p+1]; a[1]=buff[p+0]; return UTIF._binBE. i16[0]; }, readInt : function(buff, p) { var a=UTIF._binBE.ui8; a[0]=buff[p+3]; a[1]=buff[p+2]; a[2]=buff[p+1]; a[3]=buff[p+0]; return UTIF._binBE. i32[0]; }, readUint : function(buff, p) { var a=UTIF._binBE.ui8; a[0]=buff[p+3]; a[1]=buff[p+2]; a[2]=buff[p+1]; a[3]=buff[p+0]; return UTIF._binBE.ui32[0]; }, readASCII : function(buff, p, l) { var s = ""; for(var i=0; i> 8)&255; buff[p+1] = n&255; }, writeInt : function(buff, p, n) { var a=UTIF._binBE.ui8; UTIF._binBE.i32[0]=n; buff[p+3]=a[0]; buff[p+2]=a[1]; buff[p+1]=a[2]; buff[p+0]=a[3]; }, writeUint : function(buff, p, n) { buff[p] = (n>>24)&255; buff[p+1] = (n>>16)&255; buff[p+2] = (n>>8)&255; buff[p+3] = (n>>0)&255; }, writeASCII : function(buff, p, s) { for(var i = 0; i < s.length; i++) buff[p+i] = s.charCodeAt(i); }, writeDouble: function(buff, p, n) { UTIF._binBE.fl64[0] = n; for (var i = 0; i < 8; i++) buff[p + i] = UTIF._binBE.ui8[7 - i]; } } UTIF._binBE.ui8 = new Uint8Array (8); UTIF._binBE.i16 = new Int16Array (UTIF._binBE.ui8.buffer); UTIF._binBE.i32 = new Int32Array (UTIF._binBE.ui8.buffer); UTIF._binBE.ui32 = new Uint32Array (UTIF._binBE.ui8.buffer); UTIF._binBE.fl32 = new Float32Array(UTIF._binBE.ui8.buffer); UTIF._binBE.fl64 = new Float64Array(UTIF._binBE.ui8.buffer); UTIF._binLE = { nextZero : UTIF._binBE.nextZero, readUshort : function(buff, p) { return (buff[p+1]<< 8) | buff[p]; }, readShort : function(buff, p) { var a=UTIF._binBE.ui8; a[0]=buff[p+0]; a[1]=buff[p+1]; return UTIF._binBE. i16[0]; }, readInt : function(buff, p) { var a=UTIF._binBE.ui8; a[0]=buff[p+0]; a[1]=buff[p+1]; a[2]=buff[p+2]; a[3]=buff[p+3]; return UTIF._binBE. i32[0]; }, readUint : function(buff, p) { var a=UTIF._binBE.ui8; a[0]=buff[p+0]; a[1]=buff[p+1]; a[2]=buff[p+2]; a[3]=buff[p+3]; return UTIF._binBE.ui32[0]; }, readASCII : UTIF._binBE.readASCII, readFloat : function(buff, p) { var a=UTIF._binBE.ui8; for(var i=0;i<4;i++) a[i]=buff[p+ i]; return UTIF._binBE.fl32[0]; }, readDouble : function(buff, p) { var a=UTIF._binBE.ui8; for(var i=0;i<8;i++) a[i]=buff[p+ i]; return UTIF._binBE.fl64[0]; }, writeUshort: function(buff, p, n) { buff[p] = (n)&255; buff[p+1] = (n>>8)&255; }, writeInt : function(buff, p, n) { var a=UTIF._binBE.ui8; UTIF._binBE.i32[0]=n; buff[p+0]=a[0]; buff[p+1]=a[1]; buff[p+2]=a[2]; buff[p+3]=a[3]; }, writeUint : function(buff, p, n) { buff[p] = (n>>>0)&255; buff[p+1] = (n>>>8)&255; buff[p+2] = (n>>>16)&255; buff[p+3] = (n>>>24)&255; }, writeASCII : UTIF._binBE.writeASCII } UTIF._copyTile = function(tb, tw, th, b, w, h, xoff, yoff) { //log("copyTile", tw, th, w, h, xoff, yoff); var xlim = Math.min(tw, w-xoff); var ylim = Math.min(th, h-yoff); for(var y=0; y>--u&1; k=r[k+J]}t[z]=k}}function m(p,r,c,z){if(p[r+3]!=255)return 0;if(c==0)return r;for(var G=0;G<2;G++){if(p[r+G]==0){p[r+G]=p.length; p.push(0,0,z,255)}var I=m(p,p[r+G],c-1,z+1);if(I!=0)return I}return 0}function B(p){var r=p.e,c=p.c; while(r<25&&p.a>>8;c=c<<8|z;r+=8}p.e=r;p.c=c}function g(p,r){if(r.e>(r.e-=p)&65535>>16-p}function w(p,r){var c=p[0],z=0,G=255,I=0;if(r.e<16)B(r);var E=r.c>>r.e-8&255; z=p[1][E];G=c[z+3];r.e-=c[z+2];while(G==255){I=r.c>>--r.e&1;z=c[z+I];G=c[z+3]}return G}function o(p,r){if(p<32768>>16-r)p+=-(1<>>1);else if(I==6)v=p[J-r]+(K-p[J-r-z]>>>1); else if(I==7)v=K+p[J-r]>>>1;else throw I;p[J]=v+x(E[t],c)}}s+=r}}function f(p,r){return o(g(p,r),p)}function d(p,r,c){var z=y.length-D; for(var G=0;G>>4]}l=q();D+=2;break}else{D+=c-2}}var s=j>8?Uint16Array:Uint8Array,k=F*i,J=new s(H*k),K={e:0,c:0,b:l==8,a:D,data:y,d:y.length}; if(K.b)d(J,k,K);else n(J,k,K);return J}return h}(); (function(){var O=0,d=1,n=2,F=3,w=4,j=5,C=6,l=7,k=8,P=9,a9=10,g=11,U=12,t=13,L=14,Y=15,Q=16,M=17,u=18; function a4($){var z=UTIF._binBE.readUshort,v={m:z($,0),f:$[2],r:$[3],a:$[4],d:z($,5),t:z($,7),h:z($,9),n:z($,11),v:$[13],p:z($,14)}; if(v.m!=18771||v.f>1||v.d<6||v.d%6||v.h<768||v.h%24||v.n!=768||v.t=v.n||v.v>16||v.v!=v.t/v.n||v.v!=Math.ceil(v.h/v.n)||v.p!=v.d/6||v.a!=12&&v.a!=14&&v.a!=16||v.r!=16&&v.r!=0){throw"Invalid data"}if(v.f==0){throw"Not implemented. We need this file!"}v.o=v.r==16; v.c=(v.o?v.n*2/3:v.n>>>1)|0;v.g=v.c+2;v.q=64;v.j=(1<>>6);for(var i=0;i<3;i++){for(var y=0; y<41;y++){z[i][y]=[v,1]}}return z}function a8($){for(var z=-1,v=0;!v;z++){v=$[$.l]>>>7-$.s&1;$.s++;$.s&=7; if(!$.s)$.l++}return z}function R($,z){var v=0,i=8-$.s,y=$.l,A=$.s;if(z){if(z>=i){do{v<<=i;z-=i;v|=$[$.l]&(1<=8)}if(z){v<<=z;i-=z;v|=$[$.l]>>>i&(1<X&&s>>2;if(r){h[W]=q;return}E=z.e*z.u[$.j+x-T]+z.u[$.j+I-x]}else{q=x>I&&x>G||x>>2:c+D>>>1; E=z.e*z.u[$.j+x-I]+z.u[$.j+I-c]}p=Z(E);var _=a8(v);if(_<$.w-z.b-1){var a=a2(B[p][0],B[p][1]);f=R(v,a)+(_<>>1):f>>>1; B[p][0]+=Z(f);if(B[p][1]==$.q){B[p][0]>>>=1;B[p][1]>>>=1}B[p][1]++;q=E<0?q-f:q+f;if($.f){if(q<0)q+=z.i; else if(q>$.j)q-=z.i}h[W]=q>=0?Math.min(q,$.j):0}function S($,z,v){var i=$[0].length;for(var y=z;y<=v; y++){$[y][0]=$[y-1][1];$[y][i-1]=$[y-1][i-2]}}function b($){S($,l,U);S($,n,w);S($,Y,M)}function m($,z,v,i,y,A,B,r,W,o,J,K,f){var E=0,p=1,h=yw; while(p<$.c){if(E<$.c){V($,z,v,i,y,E,B[W],$.o&&(h&&o||!h&&(J||(E&K)==f)));V($,z,v,i,A,E,B[W],$.o&&(!h&&o||h&&(J||(E&K)==f))); E+=2}if(E>8){V($,z,v,i,y,p,r[W]);V($,z,v,i,A,p,r[W]);p+=2}}b(i)}function a0($,z,v,i,y,A){m($,z,v,i,n,l,y,A,0,0,1,0,8); m($,z,v,i,k,Y,y,A,1,0,1,0,8);m($,z,v,i,F,P,y,A,2,1,0,3,0);m($,z,v,i,a9,Q,y,A,0,0,0,3,2);m($,z,v,i,w,g,y,A,1,0,0,3,2); m($,z,v,i,U,M,y,A,2,1,0,3,0)}function a5($,z,v,i,y,A){var B=A.length,r=$.n;if(y+1==$.v)r=$.h-y*$.n;var W=6*$.h*i+y*$.n; for(var o=0;o<6;o++){for(var J=0;J>>1)}else if(K==2){f=Y+(o>>>1)}else{f=l+o}var E=$.o?(J*2/3&2147483646|J%3&1)+(J%3>>>1):J>>>1; z[W+J]=v[f][E+1]}W+=$.h}}UTIF._decompressRAF=function($,z){var v=a4($),i=a6($,v),y=a1(v),A=new Int16Array(v.h*v.d); if(z==null){z=v.o?[[1,1,0,1,1,2],[1,1,2,1,1,0],[2,0,1,0,2,1],[1,1,2,1,1,0],[1,1,0,1,1,2],[0,2,1,2,0,1]]:[[0,1],[3,2]]}var B=[[O,F],[d,w],[j,g],[C,U],[t,Q],[L,M]],r=[]; for(var W=0;W * homepage: https://1j01.github.io/anypalette.js/ * version: 0.6.0 * * base64-js: * license: MIT (http://opensource.org/licenses/MIT) * author: T. Jameson Little * homepage: https://github.com/beatgammit/base64-js * version: 1.5.1 * * browser-resolve: * license: MIT (http://opensource.org/licenses/MIT) * author: Roman Shtylman * homepage: https://github.com/browserify/browser-resolve#readme * version: 2.0.0 * * buffer: * license: MIT (http://opensource.org/licenses/MIT) * author: Feross Aboukhadijeh * contributors: Romain Beauxis , James Halliday * homepage: https://github.com/feross/buffer * version: 5.2.1 * * css.escape: * license: MIT (http://opensource.org/licenses/MIT) * author: Mathias Bynens * homepage: https://mths.be/cssescape * version: 1.5.1 * * events: * license: MIT (http://opensource.org/licenses/MIT) * author: Irakli Gozalishvili * homepage: https://github.com/Gozala/events#readme * version: 3.2.0 * * ieee754: * license: BSD-3-Clause (http://opensource.org/licenses/BSD-3-Clause) * author: Feross Aboukhadijeh * contributors: Romain Beauxis * homepage: https://github.com/feross/ieee754#readme * version: 1.2.1 * * inherits: * license: ISC (http://opensource.org/licenses/ISC) * homepage: https://github.com/isaacs/inherits#readme * version: 2.0.4 * * jdataview: * licenses: WTFPL (http://www.wtfpl.net/about/) * author: Vjeux * contributors: Vjeux , RReverser * homepage: http://jDataView.github.io/ * version: 2.5.0 * * process: * license: MIT (http://opensource.org/licenses/MIT) * author: Roman Shtylman * homepage: https://github.com/shtylman/node-process#readme * version: 0.11.10 * * readable-stream: * license: MIT (http://opensource.org/licenses/MIT) * homepage: https://github.com/nodejs/readable-stream#readme * version: 3.6.0 * * safe-buffer: * license: MIT (http://opensource.org/licenses/MIT) * author: Feross Aboukhadijeh * homepage: https://github.com/feross/safe-buffer * version: 5.1.2 * * sax: * license: ISC (http://opensource.org/licenses/ISC) * author: Isaac Z. Schlueter * homepage: https://github.com/isaacs/sax-js#readme * version: 1.2.4 * * stream-browserify: * license: MIT (http://opensource.org/licenses/MIT) * author: James Halliday * homepage: https://github.com/browserify/stream-browserify * version: 3.0.0 * * string_decoder: * license: MIT (http://opensource.org/licenses/MIT) * homepage: https://github.com/nodejs/string_decoder * version: 1.1.1 * * util-deprecate: * license: MIT (http://opensource.org/licenses/MIT) * author: Nathan Rajlich * homepage: https://github.com/TooTallNate/util-deprecate * version: 1.0.2 * * xml-js: * license: MIT (http://opensource.org/licenses/MIT) * author: Yousuf Almarzooqi * homepage: https://github.com/nashwaan/xml-js#readme * version: 1.6.11 * * This header is generated by licensify (https://github.com/twada/licensify) */ (function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.AnyPalette = f()}})(function(){var define,module,exports;return (function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i 0) { throw new Error('Invalid string. Length must be a multiple of 4') } // Trim off extra bytes after placeholder bytes are found // See: https://github.com/beatgammit/base64-js/issues/42 var validLen = b64.indexOf('=') if (validLen === -1) validLen = len var placeHoldersLen = validLen === len ? 0 : 4 - (validLen % 4) return [validLen, placeHoldersLen] } // base64 is 4/3 + up to two characters of the original data function byteLength (b64) { var lens = getLens(b64) var validLen = lens[0] var placeHoldersLen = lens[1] return ((validLen + placeHoldersLen) * 3 / 4) - placeHoldersLen } function _byteLength (b64, validLen, placeHoldersLen) { return ((validLen + placeHoldersLen) * 3 / 4) - placeHoldersLen } function toByteArray (b64) { var tmp var lens = getLens(b64) var validLen = lens[0] var placeHoldersLen = lens[1] var arr = new Arr(_byteLength(b64, validLen, placeHoldersLen)) var curByte = 0 // if there are placeholders, only get up to the last complete 4 chars var len = placeHoldersLen > 0 ? validLen - 4 : validLen var i for (i = 0; i < len; i += 4) { tmp = (revLookup[b64.charCodeAt(i)] << 18) | (revLookup[b64.charCodeAt(i + 1)] << 12) | (revLookup[b64.charCodeAt(i + 2)] << 6) | revLookup[b64.charCodeAt(i + 3)] arr[curByte++] = (tmp >> 16) & 0xFF arr[curByte++] = (tmp >> 8) & 0xFF arr[curByte++] = tmp & 0xFF } if (placeHoldersLen === 2) { tmp = (revLookup[b64.charCodeAt(i)] << 2) | (revLookup[b64.charCodeAt(i + 1)] >> 4) arr[curByte++] = tmp & 0xFF } if (placeHoldersLen === 1) { tmp = (revLookup[b64.charCodeAt(i)] << 10) | (revLookup[b64.charCodeAt(i + 1)] << 4) | (revLookup[b64.charCodeAt(i + 2)] >> 2) arr[curByte++] = (tmp >> 8) & 0xFF arr[curByte++] = tmp & 0xFF } return arr } function tripletToBase64 (num) { return lookup[num >> 18 & 0x3F] + lookup[num >> 12 & 0x3F] + lookup[num >> 6 & 0x3F] + lookup[num & 0x3F] } function encodeChunk (uint8, start, end) { var tmp var output = [] for (var i = start; i < end; i += 3) { tmp = ((uint8[i] << 16) & 0xFF0000) + ((uint8[i + 1] << 8) & 0xFF00) + (uint8[i + 2] & 0xFF) output.push(tripletToBase64(tmp)) } return output.join('') } function fromByteArray (uint8) { var tmp var len = uint8.length var extraBytes = len % 3 // if we have 1 byte left, pad 2 bytes var parts = [] var maxChunkLength = 16383 // must be multiple of 3 // go through the array every three bytes, we'll deal with trailing stuff later for (var i = 0, len2 = len - extraBytes; i < len2; i += maxChunkLength) { parts.push(encodeChunk(uint8, i, (i + maxChunkLength) > len2 ? len2 : (i + maxChunkLength))) } // pad the end with zeros, but make sure to not forget the extra bytes if (extraBytes === 1) { tmp = uint8[len - 1] parts.push( lookup[tmp >> 2] + lookup[(tmp << 4) & 0x3F] + '==' ) } else if (extraBytes === 2) { tmp = (uint8[len - 2] << 8) + uint8[len - 1] parts.push( lookup[tmp >> 10] + lookup[(tmp >> 4) & 0x3F] + lookup[(tmp << 2) & 0x3F] + '=' ) } return parts.join('') } },{}],2:[function(require,module,exports){ },{}],3:[function(require,module,exports){ (function (Buffer){(function (){ /*! * The buffer module from node.js, for the browser. * * @author Feross Aboukhadijeh * @license MIT */ /* eslint-disable no-proto */ 'use strict' var base64 = require('base64-js') var ieee754 = require('ieee754') exports.Buffer = Buffer exports.SlowBuffer = SlowBuffer exports.INSPECT_MAX_BYTES = 50 var K_MAX_LENGTH = 0x7fffffff exports.kMaxLength = K_MAX_LENGTH /** * If `Buffer.TYPED_ARRAY_SUPPORT`: * === true Use Uint8Array implementation (fastest) * === false Print warning and recommend using `buffer` v4.x which has an Object * implementation (most compatible, even IE6) * * Browsers that support typed arrays are IE 10+, Firefox 4+, Chrome 7+, Safari 5.1+, * Opera 11.6+, iOS 4.2+. * * We report that the browser does not support typed arrays if the are not subclassable * using __proto__. Firefox 4-29 lacks support for adding new properties to `Uint8Array` * (See: https://bugzilla.mozilla.org/show_bug.cgi?id=695438). IE 10 lacks support * for __proto__ and has a buggy typed array implementation. */ Buffer.TYPED_ARRAY_SUPPORT = typedArraySupport() if (!Buffer.TYPED_ARRAY_SUPPORT && typeof console !== 'undefined' && typeof console.error === 'function') { console.error( 'This browser lacks typed array (Uint8Array) support which is required by ' + '`buffer` v5.x. Use `buffer` v4.x if you require old browser support.' ) } function typedArraySupport () { // Can typed array instances can be augmented? try { var arr = new Uint8Array(1) arr.__proto__ = { __proto__: Uint8Array.prototype, foo: function () { return 42 } } return arr.foo() === 42 } catch (e) { return false } } Object.defineProperty(Buffer.prototype, 'parent', { enumerable: true, get: function () { if (!Buffer.isBuffer(this)) return undefined return this.buffer } }) Object.defineProperty(Buffer.prototype, 'offset', { enumerable: true, get: function () { if (!Buffer.isBuffer(this)) return undefined return this.byteOffset } }) function createBuffer (length) { if (length > K_MAX_LENGTH) { throw new RangeError('The value "' + length + '" is invalid for option "size"') } // Return an augmented `Uint8Array` instance var buf = new Uint8Array(length) buf.__proto__ = Buffer.prototype return buf } /** * The Buffer constructor returns instances of `Uint8Array` that have their * prototype changed to `Buffer.prototype`. Furthermore, `Buffer` is a subclass of * `Uint8Array`, so the returned instances will have all the node `Buffer` methods * and the `Uint8Array` methods. Square bracket notation works as expected -- it * returns a single octet. * * The `Uint8Array` prototype remains unmodified. */ function Buffer (arg, encodingOrOffset, length) { // Common case. if (typeof arg === 'number') { if (typeof encodingOrOffset === 'string') { throw new TypeError( 'The "string" argument must be of type string. Received type number' ) } return allocUnsafe(arg) } return from(arg, encodingOrOffset, length) } // Fix subarray() in ES2016. See: https://github.com/feross/buffer/pull/97 if (typeof Symbol !== 'undefined' && Symbol.species != null && Buffer[Symbol.species] === Buffer) { Object.defineProperty(Buffer, Symbol.species, { value: null, configurable: true, enumerable: false, writable: false }) } Buffer.poolSize = 8192 // not used by this implementation function from (value, encodingOrOffset, length) { if (typeof value === 'string') { return fromString(value, encodingOrOffset) } if (ArrayBuffer.isView(value)) { return fromArrayLike(value) } if (value == null) { throw TypeError( 'The first argument must be one of type string, Buffer, ArrayBuffer, Array, ' + 'or Array-like Object. Received type ' + (typeof value) ) } if (isInstance(value, ArrayBuffer) || (value && isInstance(value.buffer, ArrayBuffer))) { return fromArrayBuffer(value, encodingOrOffset, length) } if (typeof value === 'number') { throw new TypeError( 'The "value" argument must not be of type number. Received type number' ) } var valueOf = value.valueOf && value.valueOf() if (valueOf != null && valueOf !== value) { return Buffer.from(valueOf, encodingOrOffset, length) } var b = fromObject(value) if (b) return b if (typeof Symbol !== 'undefined' && Symbol.toPrimitive != null && typeof value[Symbol.toPrimitive] === 'function') { return Buffer.from( value[Symbol.toPrimitive]('string'), encodingOrOffset, length ) } throw new TypeError( 'The first argument must be one of type string, Buffer, ArrayBuffer, Array, ' + 'or Array-like Object. Received type ' + (typeof value) ) } /** * Functionally equivalent to Buffer(arg, encoding) but throws a TypeError * if value is a number. * Buffer.from(str[, encoding]) * Buffer.from(array) * Buffer.from(buffer) * Buffer.from(arrayBuffer[, byteOffset[, length]]) **/ Buffer.from = function (value, encodingOrOffset, length) { return from(value, encodingOrOffset, length) } // Note: Change prototype *after* Buffer.from is defined to workaround Chrome bug: // https://github.com/feross/buffer/pull/148 Buffer.prototype.__proto__ = Uint8Array.prototype Buffer.__proto__ = Uint8Array function assertSize (size) { if (typeof size !== 'number') { throw new TypeError('"size" argument must be of type number') } else if (size < 0) { throw new RangeError('The value "' + size + '" is invalid for option "size"') } } function alloc (size, fill, encoding) { assertSize(size) if (size <= 0) { return createBuffer(size) } if (fill !== undefined) { // Only pay attention to encoding if it's a string. This // prevents accidentally sending in a number that would // be interpretted as a start offset. return typeof encoding === 'string' ? createBuffer(size).fill(fill, encoding) : createBuffer(size).fill(fill) } return createBuffer(size) } /** * Creates a new filled Buffer instance. * alloc(size[, fill[, encoding]]) **/ Buffer.alloc = function (size, fill, encoding) { return alloc(size, fill, encoding) } function allocUnsafe (size) { assertSize(size) return createBuffer(size < 0 ? 0 : checked(size) | 0) } /** * Equivalent to Buffer(num), by default creates a non-zero-filled Buffer instance. * */ Buffer.allocUnsafe = function (size) { return allocUnsafe(size) } /** * Equivalent to SlowBuffer(num), by default creates a non-zero-filled Buffer instance. */ Buffer.allocUnsafeSlow = function (size) { return allocUnsafe(size) } function fromString (string, encoding) { if (typeof encoding !== 'string' || encoding === '') { encoding = 'utf8' } if (!Buffer.isEncoding(encoding)) { throw new TypeError('Unknown encoding: ' + encoding) } var length = byteLength(string, encoding) | 0 var buf = createBuffer(length) var actual = buf.write(string, encoding) if (actual !== length) { // Writing a hex string, for example, that contains invalid characters will // cause everything after the first invalid character to be ignored. (e.g. // 'abxxcd' will be treated as 'ab') buf = buf.slice(0, actual) } return buf } function fromArrayLike (array) { var length = array.length < 0 ? 0 : checked(array.length) | 0 var buf = createBuffer(length) for (var i = 0; i < length; i += 1) { buf[i] = array[i] & 255 } return buf } function fromArrayBuffer (array, byteOffset, length) { if (byteOffset < 0 || array.byteLength < byteOffset) { throw new RangeError('"offset" is outside of buffer bounds') } if (array.byteLength < byteOffset + (length || 0)) { throw new RangeError('"length" is outside of buffer bounds') } var buf if (byteOffset === undefined && length === undefined) { buf = new Uint8Array(array) } else if (length === undefined) { buf = new Uint8Array(array, byteOffset) } else { buf = new Uint8Array(array, byteOffset, length) } // Return an augmented `Uint8Array` instance buf.__proto__ = Buffer.prototype return buf } function fromObject (obj) { if (Buffer.isBuffer(obj)) { var len = checked(obj.length) | 0 var buf = createBuffer(len) if (buf.length === 0) { return buf } obj.copy(buf, 0, 0, len) return buf } if (obj.length !== undefined) { if (typeof obj.length !== 'number' || numberIsNaN(obj.length)) { return createBuffer(0) } return fromArrayLike(obj) } if (obj.type === 'Buffer' && Array.isArray(obj.data)) { return fromArrayLike(obj.data) } } function checked (length) { // Note: cannot use `length < K_MAX_LENGTH` here because that fails when // length is NaN (which is otherwise coerced to zero.) if (length >= K_MAX_LENGTH) { throw new RangeError('Attempt to allocate Buffer larger than maximum ' + 'size: 0x' + K_MAX_LENGTH.toString(16) + ' bytes') } return length | 0 } function SlowBuffer (length) { if (+length != length) { // eslint-disable-line eqeqeq length = 0 } return Buffer.alloc(+length) } Buffer.isBuffer = function isBuffer (b) { return b != null && b._isBuffer === true && b !== Buffer.prototype // so Buffer.isBuffer(Buffer.prototype) will be false } Buffer.compare = function compare (a, b) { if (isInstance(a, Uint8Array)) a = Buffer.from(a, a.offset, a.byteLength) if (isInstance(b, Uint8Array)) b = Buffer.from(b, b.offset, b.byteLength) if (!Buffer.isBuffer(a) || !Buffer.isBuffer(b)) { throw new TypeError( 'The "buf1", "buf2" arguments must be one of type Buffer or Uint8Array' ) } if (a === b) return 0 var x = a.length var y = b.length for (var i = 0, len = Math.min(x, y); i < len; ++i) { if (a[i] !== b[i]) { x = a[i] y = b[i] break } } if (x < y) return -1 if (y < x) return 1 return 0 } Buffer.isEncoding = function isEncoding (encoding) { switch (String(encoding).toLowerCase()) { case 'hex': case 'utf8': case 'utf-8': case 'ascii': case 'latin1': case 'binary': case 'base64': case 'ucs2': case 'ucs-2': case 'utf16le': case 'utf-16le': return true default: return false } } Buffer.concat = function concat (list, length) { if (!Array.isArray(list)) { throw new TypeError('"list" argument must be an Array of Buffers') } if (list.length === 0) { return Buffer.alloc(0) } var i if (length === undefined) { length = 0 for (i = 0; i < list.length; ++i) { length += list[i].length } } var buffer = Buffer.allocUnsafe(length) var pos = 0 for (i = 0; i < list.length; ++i) { var buf = list[i] if (isInstance(buf, Uint8Array)) { buf = Buffer.from(buf) } if (!Buffer.isBuffer(buf)) { throw new TypeError('"list" argument must be an Array of Buffers') } buf.copy(buffer, pos) pos += buf.length } return buffer } function byteLength (string, encoding) { if (Buffer.isBuffer(string)) { return string.length } if (ArrayBuffer.isView(string) || isInstance(string, ArrayBuffer)) { return string.byteLength } if (typeof string !== 'string') { throw new TypeError( 'The "string" argument must be one of type string, Buffer, or ArrayBuffer. ' + 'Received type ' + typeof string ) } var len = string.length var mustMatch = (arguments.length > 2 && arguments[2] === true) if (!mustMatch && len === 0) return 0 // Use a for loop to avoid recursion var loweredCase = false for (;;) { switch (encoding) { case 'ascii': case 'latin1': case 'binary': return len case 'utf8': case 'utf-8': return utf8ToBytes(string).length case 'ucs2': case 'ucs-2': case 'utf16le': case 'utf-16le': return len * 2 case 'hex': return len >>> 1 case 'base64': return base64ToBytes(string).length default: if (loweredCase) { return mustMatch ? -1 : utf8ToBytes(string).length // assume utf8 } encoding = ('' + encoding).toLowerCase() loweredCase = true } } } Buffer.byteLength = byteLength function slowToString (encoding, start, end) { var loweredCase = false // No need to verify that "this.length <= MAX_UINT32" since it's a read-only // property of a typed array. // This behaves neither like String nor Uint8Array in that we set start/end // to their upper/lower bounds if the value passed is out of range. // undefined is handled specially as per ECMA-262 6th Edition, // Section 13.3.3.7 Runtime Semantics: KeyedBindingInitialization. if (start === undefined || start < 0) { start = 0 } // Return early if start > this.length. Done here to prevent potential uint32 // coercion fail below. if (start > this.length) { return '' } if (end === undefined || end > this.length) { end = this.length } if (end <= 0) { return '' } // Force coersion to uint32. This will also coerce falsey/NaN values to 0. end >>>= 0 start >>>= 0 if (end <= start) { return '' } if (!encoding) encoding = 'utf8' while (true) { switch (encoding) { case 'hex': return hexSlice(this, start, end) case 'utf8': case 'utf-8': return utf8Slice(this, start, end) case 'ascii': return asciiSlice(this, start, end) case 'latin1': case 'binary': return latin1Slice(this, start, end) case 'base64': return base64Slice(this, start, end) case 'ucs2': case 'ucs-2': case 'utf16le': case 'utf-16le': return utf16leSlice(this, start, end) default: if (loweredCase) throw new TypeError('Unknown encoding: ' + encoding) encoding = (encoding + '').toLowerCase() loweredCase = true } } } // This property is used by `Buffer.isBuffer` (and the `is-buffer` npm package) // to detect a Buffer instance. It's not possible to use `instanceof Buffer` // reliably in a browserify context because there could be multiple different // copies of the 'buffer' package in use. This method works even for Buffer // instances that were created from another copy of the `buffer` package. // See: https://github.com/feross/buffer/issues/154 Buffer.prototype._isBuffer = true function swap (b, n, m) { var i = b[n] b[n] = b[m] b[m] = i } Buffer.prototype.swap16 = function swap16 () { var len = this.length if (len % 2 !== 0) { throw new RangeError('Buffer size must be a multiple of 16-bits') } for (var i = 0; i < len; i += 2) { swap(this, i, i + 1) } return this } Buffer.prototype.swap32 = function swap32 () { var len = this.length if (len % 4 !== 0) { throw new RangeError('Buffer size must be a multiple of 32-bits') } for (var i = 0; i < len; i += 4) { swap(this, i, i + 3) swap(this, i + 1, i + 2) } return this } Buffer.prototype.swap64 = function swap64 () { var len = this.length if (len % 8 !== 0) { throw new RangeError('Buffer size must be a multiple of 64-bits') } for (var i = 0; i < len; i += 8) { swap(this, i, i + 7) swap(this, i + 1, i + 6) swap(this, i + 2, i + 5) swap(this, i + 3, i + 4) } return this } Buffer.prototype.toString = function toString () { var length = this.length if (length === 0) return '' if (arguments.length === 0) return utf8Slice(this, 0, length) return slowToString.apply(this, arguments) } Buffer.prototype.toLocaleString = Buffer.prototype.toString Buffer.prototype.equals = function equals (b) { if (!Buffer.isBuffer(b)) throw new TypeError('Argument must be a Buffer') if (this === b) return true return Buffer.compare(this, b) === 0 } Buffer.prototype.inspect = function inspect () { var str = '' var max = exports.INSPECT_MAX_BYTES str = this.toString('hex', 0, max).replace(/(.{2})/g, '$1 ').trim() if (this.length > max) str += ' ... ' return '' } Buffer.prototype.compare = function compare (target, start, end, thisStart, thisEnd) { if (isInstance(target, Uint8Array)) { target = Buffer.from(target, target.offset, target.byteLength) } if (!Buffer.isBuffer(target)) { throw new TypeError( 'The "target" argument must be one of type Buffer or Uint8Array. ' + 'Received type ' + (typeof target) ) } if (start === undefined) { start = 0 } if (end === undefined) { end = target ? target.length : 0 } if (thisStart === undefined) { thisStart = 0 } if (thisEnd === undefined) { thisEnd = this.length } if (start < 0 || end > target.length || thisStart < 0 || thisEnd > this.length) { throw new RangeError('out of range index') } if (thisStart >= thisEnd && start >= end) { return 0 } if (thisStart >= thisEnd) { return -1 } if (start >= end) { return 1 } start >>>= 0 end >>>= 0 thisStart >>>= 0 thisEnd >>>= 0 if (this === target) return 0 var x = thisEnd - thisStart var y = end - start var len = Math.min(x, y) var thisCopy = this.slice(thisStart, thisEnd) var targetCopy = target.slice(start, end) for (var i = 0; i < len; ++i) { if (thisCopy[i] !== targetCopy[i]) { x = thisCopy[i] y = targetCopy[i] break } } if (x < y) return -1 if (y < x) return 1 return 0 } // Finds either the first index of `val` in `buffer` at offset >= `byteOffset`, // OR the last index of `val` in `buffer` at offset <= `byteOffset`. // // Arguments: // - buffer - a Buffer to search // - val - a string, Buffer, or number // - byteOffset - an index into `buffer`; will be clamped to an int32 // - encoding - an optional encoding, relevant is val is a string // - dir - true for indexOf, false for lastIndexOf function bidirectionalIndexOf (buffer, val, byteOffset, encoding, dir) { // Empty buffer means no match if (buffer.length === 0) return -1 // Normalize byteOffset if (typeof byteOffset === 'string') { encoding = byteOffset byteOffset = 0 } else if (byteOffset > 0x7fffffff) { byteOffset = 0x7fffffff } else if (byteOffset < -0x80000000) { byteOffset = -0x80000000 } byteOffset = +byteOffset // Coerce to Number. if (numberIsNaN(byteOffset)) { // byteOffset: it it's undefined, null, NaN, "foo", etc, search whole buffer byteOffset = dir ? 0 : (buffer.length - 1) } // Normalize byteOffset: negative offsets start from the end of the buffer if (byteOffset < 0) byteOffset = buffer.length + byteOffset if (byteOffset >= buffer.length) { if (dir) return -1 else byteOffset = buffer.length - 1 } else if (byteOffset < 0) { if (dir) byteOffset = 0 else return -1 } // Normalize val if (typeof val === 'string') { val = Buffer.from(val, encoding) } // Finally, search either indexOf (if dir is true) or lastIndexOf if (Buffer.isBuffer(val)) { // Special case: looking for empty string/buffer always fails if (val.length === 0) { return -1 } return arrayIndexOf(buffer, val, byteOffset, encoding, dir) } else if (typeof val === 'number') { val = val & 0xFF // Search for a byte value [0-255] if (typeof Uint8Array.prototype.indexOf === 'function') { if (dir) { return Uint8Array.prototype.indexOf.call(buffer, val, byteOffset) } else { return Uint8Array.prototype.lastIndexOf.call(buffer, val, byteOffset) } } return arrayIndexOf(buffer, [ val ], byteOffset, encoding, dir) } throw new TypeError('val must be string, number or Buffer') } function arrayIndexOf (arr, val, byteOffset, encoding, dir) { var indexSize = 1 var arrLength = arr.length var valLength = val.length if (encoding !== undefined) { encoding = String(encoding).toLowerCase() if (encoding === 'ucs2' || encoding === 'ucs-2' || encoding === 'utf16le' || encoding === 'utf-16le') { if (arr.length < 2 || val.length < 2) { return -1 } indexSize = 2 arrLength /= 2 valLength /= 2 byteOffset /= 2 } } function read (buf, i) { if (indexSize === 1) { return buf[i] } else { return buf.readUInt16BE(i * indexSize) } } var i if (dir) { var foundIndex = -1 for (i = byteOffset; i < arrLength; i++) { if (read(arr, i) === read(val, foundIndex === -1 ? 0 : i - foundIndex)) { if (foundIndex === -1) foundIndex = i if (i - foundIndex + 1 === valLength) return foundIndex * indexSize } else { if (foundIndex !== -1) i -= i - foundIndex foundIndex = -1 } } } else { if (byteOffset + valLength > arrLength) byteOffset = arrLength - valLength for (i = byteOffset; i >= 0; i--) { var found = true for (var j = 0; j < valLength; j++) { if (read(arr, i + j) !== read(val, j)) { found = false break } } if (found) return i } } return -1 } Buffer.prototype.includes = function includes (val, byteOffset, encoding) { return this.indexOf(val, byteOffset, encoding) !== -1 } Buffer.prototype.indexOf = function indexOf (val, byteOffset, encoding) { return bidirectionalIndexOf(this, val, byteOffset, encoding, true) } Buffer.prototype.lastIndexOf = function lastIndexOf (val, byteOffset, encoding) { return bidirectionalIndexOf(this, val, byteOffset, encoding, false) } function hexWrite (buf, string, offset, length) { offset = Number(offset) || 0 var remaining = buf.length - offset if (!length) { length = remaining } else { length = Number(length) if (length > remaining) { length = remaining } } var strLen = string.length if (length > strLen / 2) { length = strLen / 2 } for (var i = 0; i < length; ++i) { var parsed = parseInt(string.substr(i * 2, 2), 16) if (numberIsNaN(parsed)) return i buf[offset + i] = parsed } return i } function utf8Write (buf, string, offset, length) { return blitBuffer(utf8ToBytes(string, buf.length - offset), buf, offset, length) } function asciiWrite (buf, string, offset, length) { return blitBuffer(asciiToBytes(string), buf, offset, length) } function latin1Write (buf, string, offset, length) { return asciiWrite(buf, string, offset, length) } function base64Write (buf, string, offset, length) { return blitBuffer(base64ToBytes(string), buf, offset, length) } function ucs2Write (buf, string, offset, length) { return blitBuffer(utf16leToBytes(string, buf.length - offset), buf, offset, length) } Buffer.prototype.write = function write (string, offset, length, encoding) { // Buffer#write(string) if (offset === undefined) { encoding = 'utf8' length = this.length offset = 0 // Buffer#write(string, encoding) } else if (length === undefined && typeof offset === 'string') { encoding = offset length = this.length offset = 0 // Buffer#write(string, offset[, length][, encoding]) } else if (isFinite(offset)) { offset = offset >>> 0 if (isFinite(length)) { length = length >>> 0 if (encoding === undefined) encoding = 'utf8' } else { encoding = length length = undefined } } else { throw new Error( 'Buffer.write(string, encoding, offset[, length]) is no longer supported' ) } var remaining = this.length - offset if (length === undefined || length > remaining) length = remaining if ((string.length > 0 && (length < 0 || offset < 0)) || offset > this.length) { throw new RangeError('Attempt to write outside buffer bounds') } if (!encoding) encoding = 'utf8' var loweredCase = false for (;;) { switch (encoding) { case 'hex': return hexWrite(this, string, offset, length) case 'utf8': case 'utf-8': return utf8Write(this, string, offset, length) case 'ascii': return asciiWrite(this, string, offset, length) case 'latin1': case 'binary': return latin1Write(this, string, offset, length) case 'base64': // Warning: maxLength not taken into account in base64Write return base64Write(this, string, offset, length) case 'ucs2': case 'ucs-2': case 'utf16le': case 'utf-16le': return ucs2Write(this, string, offset, length) default: if (loweredCase) throw new TypeError('Unknown encoding: ' + encoding) encoding = ('' + encoding).toLowerCase() loweredCase = true } } } Buffer.prototype.toJSON = function toJSON () { return { type: 'Buffer', data: Array.prototype.slice.call(this._arr || this, 0) } } function base64Slice (buf, start, end) { if (start === 0 && end === buf.length) { return base64.fromByteArray(buf) } else { return base64.fromByteArray(buf.slice(start, end)) } } function utf8Slice (buf, start, end) { end = Math.min(buf.length, end) var res = [] var i = start while (i < end) { var firstByte = buf[i] var codePoint = null var bytesPerSequence = (firstByte > 0xEF) ? 4 : (firstByte > 0xDF) ? 3 : (firstByte > 0xBF) ? 2 : 1 if (i + bytesPerSequence <= end) { var secondByte, thirdByte, fourthByte, tempCodePoint switch (bytesPerSequence) { case 1: if (firstByte < 0x80) { codePoint = firstByte } break case 2: secondByte = buf[i + 1] if ((secondByte & 0xC0) === 0x80) { tempCodePoint = (firstByte & 0x1F) << 0x6 | (secondByte & 0x3F) if (tempCodePoint > 0x7F) { codePoint = tempCodePoint } } break case 3: secondByte = buf[i + 1] thirdByte = buf[i + 2] if ((secondByte & 0xC0) === 0x80 && (thirdByte & 0xC0) === 0x80) { tempCodePoint = (firstByte & 0xF) << 0xC | (secondByte & 0x3F) << 0x6 | (thirdByte & 0x3F) if (tempCodePoint > 0x7FF && (tempCodePoint < 0xD800 || tempCodePoint > 0xDFFF)) { codePoint = tempCodePoint } } break case 4: secondByte = buf[i + 1] thirdByte = buf[i + 2] fourthByte = buf[i + 3] if ((secondByte & 0xC0) === 0x80 && (thirdByte & 0xC0) === 0x80 && (fourthByte & 0xC0) === 0x80) { tempCodePoint = (firstByte & 0xF) << 0x12 | (secondByte & 0x3F) << 0xC | (thirdByte & 0x3F) << 0x6 | (fourthByte & 0x3F) if (tempCodePoint > 0xFFFF && tempCodePoint < 0x110000) { codePoint = tempCodePoint } } } } if (codePoint === null) { // we did not generate a valid codePoint so insert a // replacement char (U+FFFD) and advance only 1 byte codePoint = 0xFFFD bytesPerSequence = 1 } else if (codePoint > 0xFFFF) { // encode to utf16 (surrogate pair dance) codePoint -= 0x10000 res.push(codePoint >>> 10 & 0x3FF | 0xD800) codePoint = 0xDC00 | codePoint & 0x3FF } res.push(codePoint) i += bytesPerSequence } return decodeCodePointsArray(res) } // Based on http://stackoverflow.com/a/22747272/680742, the browser with // the lowest limit is Chrome, with 0x10000 args. // We go 1 magnitude less, for safety var MAX_ARGUMENTS_LENGTH = 0x1000 function decodeCodePointsArray (codePoints) { var len = codePoints.length if (len <= MAX_ARGUMENTS_LENGTH) { return String.fromCharCode.apply(String, codePoints) // avoid extra slice() } // Decode in chunks to avoid "call stack size exceeded". var res = '' var i = 0 while (i < len) { res += String.fromCharCode.apply( String, codePoints.slice(i, i += MAX_ARGUMENTS_LENGTH) ) } return res } function asciiSlice (buf, start, end) { var ret = '' end = Math.min(buf.length, end) for (var i = start; i < end; ++i) { ret += String.fromCharCode(buf[i] & 0x7F) } return ret } function latin1Slice (buf, start, end) { var ret = '' end = Math.min(buf.length, end) for (var i = start; i < end; ++i) { ret += String.fromCharCode(buf[i]) } return ret } function hexSlice (buf, start, end) { var len = buf.length if (!start || start < 0) start = 0 if (!end || end < 0 || end > len) end = len var out = '' for (var i = start; i < end; ++i) { out += toHex(buf[i]) } return out } function utf16leSlice (buf, start, end) { var bytes = buf.slice(start, end) var res = '' for (var i = 0; i < bytes.length; i += 2) { res += String.fromCharCode(bytes[i] + (bytes[i + 1] * 256)) } return res } Buffer.prototype.slice = function slice (start, end) { var len = this.length start = ~~start end = end === undefined ? len : ~~end if (start < 0) { start += len if (start < 0) start = 0 } else if (start > len) { start = len } if (end < 0) { end += len if (end < 0) end = 0 } else if (end > len) { end = len } if (end < start) end = start var newBuf = this.subarray(start, end) // Return an augmented `Uint8Array` instance newBuf.__proto__ = Buffer.prototype return newBuf } /* * Need to make sure that buffer isn't trying to write out of bounds. */ function checkOffset (offset, ext, length) { if ((offset % 1) !== 0 || offset < 0) throw new RangeError('offset is not uint') if (offset + ext > length) throw new RangeError('Trying to access beyond buffer length') } Buffer.prototype.readUIntLE = function readUIntLE (offset, byteLength, noAssert) { offset = offset >>> 0 byteLength = byteLength >>> 0 if (!noAssert) checkOffset(offset, byteLength, this.length) var val = this[offset] var mul = 1 var i = 0 while (++i < byteLength && (mul *= 0x100)) { val += this[offset + i] * mul } return val } Buffer.prototype.readUIntBE = function readUIntBE (offset, byteLength, noAssert) { offset = offset >>> 0 byteLength = byteLength >>> 0 if (!noAssert) { checkOffset(offset, byteLength, this.length) } var val = this[offset + --byteLength] var mul = 1 while (byteLength > 0 && (mul *= 0x100)) { val += this[offset + --byteLength] * mul } return val } Buffer.prototype.readUInt8 = function readUInt8 (offset, noAssert) { offset = offset >>> 0 if (!noAssert) checkOffset(offset, 1, this.length) return this[offset] } Buffer.prototype.readUInt16LE = function readUInt16LE (offset, noAssert) { offset = offset >>> 0 if (!noAssert) checkOffset(offset, 2, this.length) return this[offset] | (this[offset + 1] << 8) } Buffer.prototype.readUInt16BE = function readUInt16BE (offset, noAssert) { offset = offset >>> 0 if (!noAssert) checkOffset(offset, 2, this.length) return (this[offset] << 8) | this[offset + 1] } Buffer.prototype.readUInt32LE = function readUInt32LE (offset, noAssert) { offset = offset >>> 0 if (!noAssert) checkOffset(offset, 4, this.length) return ((this[offset]) | (this[offset + 1] << 8) | (this[offset + 2] << 16)) + (this[offset + 3] * 0x1000000) } Buffer.prototype.readUInt32BE = function readUInt32BE (offset, noAssert) { offset = offset >>> 0 if (!noAssert) checkOffset(offset, 4, this.length) return (this[offset] * 0x1000000) + ((this[offset + 1] << 16) | (this[offset + 2] << 8) | this[offset + 3]) } Buffer.prototype.readIntLE = function readIntLE (offset, byteLength, noAssert) { offset = offset >>> 0 byteLength = byteLength >>> 0 if (!noAssert) checkOffset(offset, byteLength, this.length) var val = this[offset] var mul = 1 var i = 0 while (++i < byteLength && (mul *= 0x100)) { val += this[offset + i] * mul } mul *= 0x80 if (val >= mul) val -= Math.pow(2, 8 * byteLength) return val } Buffer.prototype.readIntBE = function readIntBE (offset, byteLength, noAssert) { offset = offset >>> 0 byteLength = byteLength >>> 0 if (!noAssert) checkOffset(offset, byteLength, this.length) var i = byteLength var mul = 1 var val = this[offset + --i] while (i > 0 && (mul *= 0x100)) { val += this[offset + --i] * mul } mul *= 0x80 if (val >= mul) val -= Math.pow(2, 8 * byteLength) return val } Buffer.prototype.readInt8 = function readInt8 (offset, noAssert) { offset = offset >>> 0 if (!noAssert) checkOffset(offset, 1, this.length) if (!(this[offset] & 0x80)) return (this[offset]) return ((0xff - this[offset] + 1) * -1) } Buffer.prototype.readInt16LE = function readInt16LE (offset, noAssert) { offset = offset >>> 0 if (!noAssert) checkOffset(offset, 2, this.length) var val = this[offset] | (this[offset + 1] << 8) return (val & 0x8000) ? val | 0xFFFF0000 : val } Buffer.prototype.readInt16BE = function readInt16BE (offset, noAssert) { offset = offset >>> 0 if (!noAssert) checkOffset(offset, 2, this.length) var val = this[offset + 1] | (this[offset] << 8) return (val & 0x8000) ? val | 0xFFFF0000 : val } Buffer.prototype.readInt32LE = function readInt32LE (offset, noAssert) { offset = offset >>> 0 if (!noAssert) checkOffset(offset, 4, this.length) return (this[offset]) | (this[offset + 1] << 8) | (this[offset + 2] << 16) | (this[offset + 3] << 24) } Buffer.prototype.readInt32BE = function readInt32BE (offset, noAssert) { offset = offset >>> 0 if (!noAssert) checkOffset(offset, 4, this.length) return (this[offset] << 24) | (this[offset + 1] << 16) | (this[offset + 2] << 8) | (this[offset + 3]) } Buffer.prototype.readFloatLE = function readFloatLE (offset, noAssert) { offset = offset >>> 0 if (!noAssert) checkOffset(offset, 4, this.length) return ieee754.read(this, offset, true, 23, 4) } Buffer.prototype.readFloatBE = function readFloatBE (offset, noAssert) { offset = offset >>> 0 if (!noAssert) checkOffset(offset, 4, this.length) return ieee754.read(this, offset, false, 23, 4) } Buffer.prototype.readDoubleLE = function readDoubleLE (offset, noAssert) { offset = offset >>> 0 if (!noAssert) checkOffset(offset, 8, this.length) return ieee754.read(this, offset, true, 52, 8) } Buffer.prototype.readDoubleBE = function readDoubleBE (offset, noAssert) { offset = offset >>> 0 if (!noAssert) checkOffset(offset, 8, this.length) return ieee754.read(this, offset, false, 52, 8) } function checkInt (buf, value, offset, ext, max, min) { if (!Buffer.isBuffer(buf)) throw new TypeError('"buffer" argument must be a Buffer instance') if (value > max || value < min) throw new RangeError('"value" argument is out of bounds') if (offset + ext > buf.length) throw new RangeError('Index out of range') } Buffer.prototype.writeUIntLE = function writeUIntLE (value, offset, byteLength, noAssert) { value = +value offset = offset >>> 0 byteLength = byteLength >>> 0 if (!noAssert) { var maxBytes = Math.pow(2, 8 * byteLength) - 1 checkInt(this, value, offset, byteLength, maxBytes, 0) } var mul = 1 var i = 0 this[offset] = value & 0xFF while (++i < byteLength && (mul *= 0x100)) { this[offset + i] = (value / mul) & 0xFF } return offset + byteLength } Buffer.prototype.writeUIntBE = function writeUIntBE (value, offset, byteLength, noAssert) { value = +value offset = offset >>> 0 byteLength = byteLength >>> 0 if (!noAssert) { var maxBytes = Math.pow(2, 8 * byteLength) - 1 checkInt(this, value, offset, byteLength, maxBytes, 0) } var i = byteLength - 1 var mul = 1 this[offset + i] = value & 0xFF while (--i >= 0 && (mul *= 0x100)) { this[offset + i] = (value / mul) & 0xFF } return offset + byteLength } Buffer.prototype.writeUInt8 = function writeUInt8 (value, offset, noAssert) { value = +value offset = offset >>> 0 if (!noAssert) checkInt(this, value, offset, 1, 0xff, 0) this[offset] = (value & 0xff) return offset + 1 } Buffer.prototype.writeUInt16LE = function writeUInt16LE (value, offset, noAssert) { value = +value offset = offset >>> 0 if (!noAssert) checkInt(this, value, offset, 2, 0xffff, 0) this[offset] = (value & 0xff) this[offset + 1] = (value >>> 8) return offset + 2 } Buffer.prototype.writeUInt16BE = function writeUInt16BE (value, offset, noAssert) { value = +value offset = offset >>> 0 if (!noAssert) checkInt(this, value, offset, 2, 0xffff, 0) this[offset] = (value >>> 8) this[offset + 1] = (value & 0xff) return offset + 2 } Buffer.prototype.writeUInt32LE = function writeUInt32LE (value, offset, noAssert) { value = +value offset = offset >>> 0 if (!noAssert) checkInt(this, value, offset, 4, 0xffffffff, 0) this[offset + 3] = (value >>> 24) this[offset + 2] = (value >>> 16) this[offset + 1] = (value >>> 8) this[offset] = (value & 0xff) return offset + 4 } Buffer.prototype.writeUInt32BE = function writeUInt32BE (value, offset, noAssert) { value = +value offset = offset >>> 0 if (!noAssert) checkInt(this, value, offset, 4, 0xffffffff, 0) this[offset] = (value >>> 24) this[offset + 1] = (value >>> 16) this[offset + 2] = (value >>> 8) this[offset + 3] = (value & 0xff) return offset + 4 } Buffer.prototype.writeIntLE = function writeIntLE (value, offset, byteLength, noAssert) { value = +value offset = offset >>> 0 if (!noAssert) { var limit = Math.pow(2, (8 * byteLength) - 1) checkInt(this, value, offset, byteLength, limit - 1, -limit) } var i = 0 var mul = 1 var sub = 0 this[offset] = value & 0xFF while (++i < byteLength && (mul *= 0x100)) { if (value < 0 && sub === 0 && this[offset + i - 1] !== 0) { sub = 1 } this[offset + i] = ((value / mul) >> 0) - sub & 0xFF } return offset + byteLength } Buffer.prototype.writeIntBE = function writeIntBE (value, offset, byteLength, noAssert) { value = +value offset = offset >>> 0 if (!noAssert) { var limit = Math.pow(2, (8 * byteLength) - 1) checkInt(this, value, offset, byteLength, limit - 1, -limit) } var i = byteLength - 1 var mul = 1 var sub = 0 this[offset + i] = value & 0xFF while (--i >= 0 && (mul *= 0x100)) { if (value < 0 && sub === 0 && this[offset + i + 1] !== 0) { sub = 1 } this[offset + i] = ((value / mul) >> 0) - sub & 0xFF } return offset + byteLength } Buffer.prototype.writeInt8 = function writeInt8 (value, offset, noAssert) { value = +value offset = offset >>> 0 if (!noAssert) checkInt(this, value, offset, 1, 0x7f, -0x80) if (value < 0) value = 0xff + value + 1 this[offset] = (value & 0xff) return offset + 1 } Buffer.prototype.writeInt16LE = function writeInt16LE (value, offset, noAssert) { value = +value offset = offset >>> 0 if (!noAssert) checkInt(this, value, offset, 2, 0x7fff, -0x8000) this[offset] = (value & 0xff) this[offset + 1] = (value >>> 8) return offset + 2 } Buffer.prototype.writeInt16BE = function writeInt16BE (value, offset, noAssert) { value = +value offset = offset >>> 0 if (!noAssert) checkInt(this, value, offset, 2, 0x7fff, -0x8000) this[offset] = (value >>> 8) this[offset + 1] = (value & 0xff) return offset + 2 } Buffer.prototype.writeInt32LE = function writeInt32LE (value, offset, noAssert) { value = +value offset = offset >>> 0 if (!noAssert) checkInt(this, value, offset, 4, 0x7fffffff, -0x80000000) this[offset] = (value & 0xff) this[offset + 1] = (value >>> 8) this[offset + 2] = (value >>> 16) this[offset + 3] = (value >>> 24) return offset + 4 } Buffer.prototype.writeInt32BE = function writeInt32BE (value, offset, noAssert) { value = +value offset = offset >>> 0 if (!noAssert) checkInt(this, value, offset, 4, 0x7fffffff, -0x80000000) if (value < 0) value = 0xffffffff + value + 1 this[offset] = (value >>> 24) this[offset + 1] = (value >>> 16) this[offset + 2] = (value >>> 8) this[offset + 3] = (value & 0xff) return offset + 4 } function checkIEEE754 (buf, value, offset, ext, max, min) { if (offset + ext > buf.length) throw new RangeError('Index out of range') if (offset < 0) throw new RangeError('Index out of range') } function writeFloat (buf, value, offset, littleEndian, noAssert) { value = +value offset = offset >>> 0 if (!noAssert) { checkIEEE754(buf, value, offset, 4, 3.4028234663852886e+38, -3.4028234663852886e+38) } ieee754.write(buf, value, offset, littleEndian, 23, 4) return offset + 4 } Buffer.prototype.writeFloatLE = function writeFloatLE (value, offset, noAssert) { return writeFloat(this, value, offset, true, noAssert) } Buffer.prototype.writeFloatBE = function writeFloatBE (value, offset, noAssert) { return writeFloat(this, value, offset, false, noAssert) } function writeDouble (buf, value, offset, littleEndian, noAssert) { value = +value offset = offset >>> 0 if (!noAssert) { checkIEEE754(buf, value, offset, 8, 1.7976931348623157E+308, -1.7976931348623157E+308) } ieee754.write(buf, value, offset, littleEndian, 52, 8) return offset + 8 } Buffer.prototype.writeDoubleLE = function writeDoubleLE (value, offset, noAssert) { return writeDouble(this, value, offset, true, noAssert) } Buffer.prototype.writeDoubleBE = function writeDoubleBE (value, offset, noAssert) { return writeDouble(this, value, offset, false, noAssert) } // copy(targetBuffer, targetStart=0, sourceStart=0, sourceEnd=buffer.length) Buffer.prototype.copy = function copy (target, targetStart, start, end) { if (!Buffer.isBuffer(target)) throw new TypeError('argument should be a Buffer') if (!start) start = 0 if (!end && end !== 0) end = this.length if (targetStart >= target.length) targetStart = target.length if (!targetStart) targetStart = 0 if (end > 0 && end < start) end = start // Copy 0 bytes; we're done if (end === start) return 0 if (target.length === 0 || this.length === 0) return 0 // Fatal error conditions if (targetStart < 0) { throw new RangeError('targetStart out of bounds') } if (start < 0 || start >= this.length) throw new RangeError('Index out of range') if (end < 0) throw new RangeError('sourceEnd out of bounds') // Are we oob? if (end > this.length) end = this.length if (target.length - targetStart < end - start) { end = target.length - targetStart + start } var len = end - start if (this === target && typeof Uint8Array.prototype.copyWithin === 'function') { // Use built-in when available, missing from IE11 this.copyWithin(targetStart, start, end) } else if (this === target && start < targetStart && targetStart < end) { // descending copy from end for (var i = len - 1; i >= 0; --i) { target[i + targetStart] = this[i + start] } } else { Uint8Array.prototype.set.call( target, this.subarray(start, end), targetStart ) } return len } // Usage: // buffer.fill(number[, offset[, end]]) // buffer.fill(buffer[, offset[, end]]) // buffer.fill(string[, offset[, end]][, encoding]) Buffer.prototype.fill = function fill (val, start, end, encoding) { // Handle string cases: if (typeof val === 'string') { if (typeof start === 'string') { encoding = start start = 0 end = this.length } else if (typeof end === 'string') { encoding = end end = this.length } if (encoding !== undefined && typeof encoding !== 'string') { throw new TypeError('encoding must be a string') } if (typeof encoding === 'string' && !Buffer.isEncoding(encoding)) { throw new TypeError('Unknown encoding: ' + encoding) } if (val.length === 1) { var code = val.charCodeAt(0) if ((encoding === 'utf8' && code < 128) || encoding === 'latin1') { // Fast path: If `val` fits into a single byte, use that numeric value. val = code } } } else if (typeof val === 'number') { val = val & 255 } // Invalid ranges are not set to a default, so can range check early. if (start < 0 || this.length < start || this.length < end) { throw new RangeError('Out of range index') } if (end <= start) { return this } start = start >>> 0 end = end === undefined ? this.length : end >>> 0 if (!val) val = 0 var i if (typeof val === 'number') { for (i = start; i < end; ++i) { this[i] = val } } else { var bytes = Buffer.isBuffer(val) ? val : Buffer.from(val, encoding) var len = bytes.length if (len === 0) { throw new TypeError('The value "' + val + '" is invalid for argument "value"') } for (i = 0; i < end - start; ++i) { this[i + start] = bytes[i % len] } } return this } // HELPER FUNCTIONS // ================ var INVALID_BASE64_RE = /[^+/0-9A-Za-z-_]/g function base64clean (str) { // Node takes equal signs as end of the Base64 encoding str = str.split('=')[0] // Node strips out invalid characters like \n and \t from the string, base64-js does not str = str.trim().replace(INVALID_BASE64_RE, '') // Node converts strings with length < 2 to '' if (str.length < 2) return '' // Node allows for non-padded base64 strings (missing trailing ===), base64-js does not while (str.length % 4 !== 0) { str = str + '=' } return str } function toHex (n) { if (n < 16) return '0' + n.toString(16) return n.toString(16) } function utf8ToBytes (string, units) { units = units || Infinity var codePoint var length = string.length var leadSurrogate = null var bytes = [] for (var i = 0; i < length; ++i) { codePoint = string.charCodeAt(i) // is surrogate component if (codePoint > 0xD7FF && codePoint < 0xE000) { // last char was a lead if (!leadSurrogate) { // no lead yet if (codePoint > 0xDBFF) { // unexpected trail if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD) continue } else if (i + 1 === length) { // unpaired lead if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD) continue } // valid lead leadSurrogate = codePoint continue } // 2 leads in a row if (codePoint < 0xDC00) { if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD) leadSurrogate = codePoint continue } // valid surrogate pair codePoint = (leadSurrogate - 0xD800 << 10 | codePoint - 0xDC00) + 0x10000 } else if (leadSurrogate) { // valid bmp char, but last char was a lead if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD) } leadSurrogate = null // encode utf8 if (codePoint < 0x80) { if ((units -= 1) < 0) break bytes.push(codePoint) } else if (codePoint < 0x800) { if ((units -= 2) < 0) break bytes.push( codePoint >> 0x6 | 0xC0, codePoint & 0x3F | 0x80 ) } else if (codePoint < 0x10000) { if ((units -= 3) < 0) break bytes.push( codePoint >> 0xC | 0xE0, codePoint >> 0x6 & 0x3F | 0x80, codePoint & 0x3F | 0x80 ) } else if (codePoint < 0x110000) { if ((units -= 4) < 0) break bytes.push( codePoint >> 0x12 | 0xF0, codePoint >> 0xC & 0x3F | 0x80, codePoint >> 0x6 & 0x3F | 0x80, codePoint & 0x3F | 0x80 ) } else { throw new Error('Invalid code point') } } return bytes } function asciiToBytes (str) { var byteArray = [] for (var i = 0; i < str.length; ++i) { // Node's code seems to be doing this and not & 0x7F.. byteArray.push(str.charCodeAt(i) & 0xFF) } return byteArray } function utf16leToBytes (str, units) { var c, hi, lo var byteArray = [] for (var i = 0; i < str.length; ++i) { if ((units -= 2) < 0) break c = str.charCodeAt(i) hi = c >> 8 lo = c % 256 byteArray.push(lo) byteArray.push(hi) } return byteArray } function base64ToBytes (str) { return base64.toByteArray(base64clean(str)) } function blitBuffer (src, dst, offset, length) { for (var i = 0; i < length; ++i) { if ((i + offset >= dst.length) || (i >= src.length)) break dst[i + offset] = src[i] } return i } // ArrayBuffer or Uint8Array objects from other contexts (i.e. iframes) do not pass // the `instanceof` check but they should be treated as of that type. // See: https://github.com/feross/buffer/issues/166 function isInstance (obj, type) { return obj instanceof type || (obj != null && obj.constructor != null && obj.constructor.name != null && obj.constructor.name === type.name) } function numberIsNaN (obj) { // For IE11 support return obj !== obj // eslint-disable-line no-self-compare } }).call(this)}).call(this,require("buffer").Buffer) },{"base64-js":1,"buffer":3,"ieee754":6}],4:[function(require,module,exports){ (function (global){(function (){ /*! https://mths.be/cssescape v1.5.1 by @mathias | MIT license */ ;(function(root, factory) { // https://github.com/umdjs/umd/blob/master/returnExports.js if (typeof exports == 'object') { // For Node.js. module.exports = factory(root); } else if (typeof define == 'function' && define.amd) { // For AMD. Register as an anonymous module. define([], factory.bind(root, root)); } else { // For browser globals (not exposing the function separately). factory(root); } }(typeof global != 'undefined' ? global : this, function(root) { if (root.CSS && root.CSS.escape) { return root.CSS.escape; } // https://drafts.csswg.org/cssom/#serialize-an-identifier var cssEscape = function(value) { if (arguments.length == 0) { throw new TypeError('`CSS.escape` requires an argument.'); } var string = String(value); var length = string.length; var index = -1; var codeUnit; var result = ''; var firstCodeUnit = string.charCodeAt(0); while (++index < length) { codeUnit = string.charCodeAt(index); // Note: there’s no need to special-case astral symbols, surrogate // pairs, or lone surrogates. // If the character is NULL (U+0000), then the REPLACEMENT CHARACTER // (U+FFFD). if (codeUnit == 0x0000) { result += '\uFFFD'; continue; } if ( // If the character is in the range [\1-\1F] (U+0001 to U+001F) or is // U+007F, […] (codeUnit >= 0x0001 && codeUnit <= 0x001F) || codeUnit == 0x007F || // If the character is the first character and is in the range [0-9] // (U+0030 to U+0039), […] (index == 0 && codeUnit >= 0x0030 && codeUnit <= 0x0039) || // If the character is the second character and is in the range [0-9] // (U+0030 to U+0039) and the first character is a `-` (U+002D), […] ( index == 1 && codeUnit >= 0x0030 && codeUnit <= 0x0039 && firstCodeUnit == 0x002D ) ) { // https://drafts.csswg.org/cssom/#escape-a-character-as-code-point result += '\\' + codeUnit.toString(16) + ' '; continue; } if ( // If the character is the first character and is a `-` (U+002D), and // there is no second character, […] index == 0 && length == 1 && codeUnit == 0x002D ) { result += '\\' + string.charAt(index); continue; } // If the character is not handled by one of the above rules and is // greater than or equal to U+0080, is `-` (U+002D) or `_` (U+005F), or // is in one of the ranges [0-9] (U+0030 to U+0039), [A-Z] (U+0041 to // U+005A), or [a-z] (U+0061 to U+007A), […] if ( codeUnit >= 0x0080 || codeUnit == 0x002D || codeUnit == 0x005F || codeUnit >= 0x0030 && codeUnit <= 0x0039 || codeUnit >= 0x0041 && codeUnit <= 0x005A || codeUnit >= 0x0061 && codeUnit <= 0x007A ) { // the character itself result += string.charAt(index); continue; } // Otherwise, the escaped character. // https://drafts.csswg.org/cssom/#escape-a-character result += '\\' + string.charAt(index); } return result; }; if (!root.CSS) { root.CSS = {}; } root.CSS.escape = cssEscape; return cssEscape; })); }).call(this)}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) },{}],5:[function(require,module,exports){ // Copyright Joyent, Inc. and other Node contributors. // // Permission is hereby granted, free of charge, to any person obtaining a // copy of this software and associated documentation files (the // "Software"), to deal in the Software without restriction, including // without limitation the rights to use, copy, modify, merge, publish, // distribute, sublicense, and/or sell copies of the Software, and to permit // persons to whom the Software is furnished to do so, subject to the // following conditions: // // The above copyright notice and this permission notice shall be included // in all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE // USE OR OTHER DEALINGS IN THE SOFTWARE. 'use strict'; var R = typeof Reflect === 'object' ? Reflect : null var ReflectApply = R && typeof R.apply === 'function' ? R.apply : function ReflectApply(target, receiver, args) { return Function.prototype.apply.call(target, receiver, args); } var ReflectOwnKeys if (R && typeof R.ownKeys === 'function') { ReflectOwnKeys = R.ownKeys } else if (Object.getOwnPropertySymbols) { ReflectOwnKeys = function ReflectOwnKeys(target) { return Object.getOwnPropertyNames(target) .concat(Object.getOwnPropertySymbols(target)); }; } else { ReflectOwnKeys = function ReflectOwnKeys(target) { return Object.getOwnPropertyNames(target); }; } function ProcessEmitWarning(warning) { if (console && console.warn) console.warn(warning); } var NumberIsNaN = Number.isNaN || function NumberIsNaN(value) { return value !== value; } function EventEmitter() { EventEmitter.init.call(this); } module.exports = EventEmitter; module.exports.once = once; // Backwards-compat with node 0.10.x EventEmitter.EventEmitter = EventEmitter; EventEmitter.prototype._events = undefined; EventEmitter.prototype._eventsCount = 0; EventEmitter.prototype._maxListeners = undefined; // By default EventEmitters will print a warning if more than 10 listeners are // added to it. This is a useful default which helps finding memory leaks. var defaultMaxListeners = 10; function checkListener(listener) { if (typeof listener !== 'function') { throw new TypeError('The "listener" argument must be of type Function. Received type ' + typeof listener); } } Object.defineProperty(EventEmitter, 'defaultMaxListeners', { enumerable: true, get: function() { return defaultMaxListeners; }, set: function(arg) { if (typeof arg !== 'number' || arg < 0 || NumberIsNaN(arg)) { throw new RangeError('The value of "defaultMaxListeners" is out of range. It must be a non-negative number. Received ' + arg + '.'); } defaultMaxListeners = arg; } }); EventEmitter.init = function() { if (this._events === undefined || this._events === Object.getPrototypeOf(this)._events) { this._events = Object.create(null); this._eventsCount = 0; } this._maxListeners = this._maxListeners || undefined; }; // Obviously not all Emitters should be limited to 10. This function allows // that to be increased. Set to zero for unlimited. EventEmitter.prototype.setMaxListeners = function setMaxListeners(n) { if (typeof n !== 'number' || n < 0 || NumberIsNaN(n)) { throw new RangeError('The value of "n" is out of range. It must be a non-negative number. Received ' + n + '.'); } this._maxListeners = n; return this; }; function _getMaxListeners(that) { if (that._maxListeners === undefined) return EventEmitter.defaultMaxListeners; return that._maxListeners; } EventEmitter.prototype.getMaxListeners = function getMaxListeners() { return _getMaxListeners(this); }; EventEmitter.prototype.emit = function emit(type) { var args = []; for (var i = 1; i < arguments.length; i++) args.push(arguments[i]); var doError = (type === 'error'); var events = this._events; if (events !== undefined) doError = (doError && events.error === undefined); else if (!doError) return false; // If there is no 'error' event listener then throw. if (doError) { var er; if (args.length > 0) er = args[0]; if (er instanceof Error) { // Note: The comments on the `throw` lines are intentional, they show // up in Node's output if this results in an unhandled exception. throw er; // Unhandled 'error' event } // At least give some kind of context to the user var err = new Error('Unhandled error.' + (er ? ' (' + er.message + ')' : '')); err.context = er; throw err; // Unhandled 'error' event } var handler = events[type]; if (handler === undefined) return false; if (typeof handler === 'function') { ReflectApply(handler, this, args); } else { var len = handler.length; var listeners = arrayClone(handler, len); for (var i = 0; i < len; ++i) ReflectApply(listeners[i], this, args); } return true; }; function _addListener(target, type, listener, prepend) { var m; var events; var existing; checkListener(listener); events = target._events; if (events === undefined) { events = target._events = Object.create(null); target._eventsCount = 0; } else { // To avoid recursion in the case that type === "newListener"! Before // adding it to the listeners, first emit "newListener". if (events.newListener !== undefined) { target.emit('newListener', type, listener.listener ? listener.listener : listener); // Re-assign `events` because a newListener handler could have caused the // this._events to be assigned to a new object events = target._events; } existing = events[type]; } if (existing === undefined) { // Optimize the case of one listener. Don't need the extra array object. existing = events[type] = listener; ++target._eventsCount; } else { if (typeof existing === 'function') { // Adding the second element, need to change to array. existing = events[type] = prepend ? [listener, existing] : [existing, listener]; // If we've already got an array, just append. } else if (prepend) { existing.unshift(listener); } else { existing.push(listener); } // Check for listener leak m = _getMaxListeners(target); if (m > 0 && existing.length > m && !existing.warned) { existing.warned = true; // No error code for this since it is a Warning // eslint-disable-next-line no-restricted-syntax var w = new Error('Possible EventEmitter memory leak detected. ' + existing.length + ' ' + String(type) + ' listeners ' + 'added. Use emitter.setMaxListeners() to ' + 'increase limit'); w.name = 'MaxListenersExceededWarning'; w.emitter = target; w.type = type; w.count = existing.length; ProcessEmitWarning(w); } } return target; } EventEmitter.prototype.addListener = function addListener(type, listener) { return _addListener(this, type, listener, false); }; EventEmitter.prototype.on = EventEmitter.prototype.addListener; EventEmitter.prototype.prependListener = function prependListener(type, listener) { return _addListener(this, type, listener, true); }; function onceWrapper() { if (!this.fired) { this.target.removeListener(this.type, this.wrapFn); this.fired = true; if (arguments.length === 0) return this.listener.call(this.target); return this.listener.apply(this.target, arguments); } } function _onceWrap(target, type, listener) { var state = { fired: false, wrapFn: undefined, target: target, type: type, listener: listener }; var wrapped = onceWrapper.bind(state); wrapped.listener = listener; state.wrapFn = wrapped; return wrapped; } EventEmitter.prototype.once = function once(type, listener) { checkListener(listener); this.on(type, _onceWrap(this, type, listener)); return this; }; EventEmitter.prototype.prependOnceListener = function prependOnceListener(type, listener) { checkListener(listener); this.prependListener(type, _onceWrap(this, type, listener)); return this; }; // Emits a 'removeListener' event if and only if the listener was removed. EventEmitter.prototype.removeListener = function removeListener(type, listener) { var list, events, position, i, originalListener; checkListener(listener); events = this._events; if (events === undefined) return this; list = events[type]; if (list === undefined) return this; if (list === listener || list.listener === listener) { if (--this._eventsCount === 0) this._events = Object.create(null); else { delete events[type]; if (events.removeListener) this.emit('removeListener', type, list.listener || listener); } } else if (typeof list !== 'function') { position = -1; for (i = list.length - 1; i >= 0; i--) { if (list[i] === listener || list[i].listener === listener) { originalListener = list[i].listener; position = i; break; } } if (position < 0) return this; if (position === 0) list.shift(); else { spliceOne(list, position); } if (list.length === 1) events[type] = list[0]; if (events.removeListener !== undefined) this.emit('removeListener', type, originalListener || listener); } return this; }; EventEmitter.prototype.off = EventEmitter.prototype.removeListener; EventEmitter.prototype.removeAllListeners = function removeAllListeners(type) { var listeners, events, i; events = this._events; if (events === undefined) return this; // not listening for removeListener, no need to emit if (events.removeListener === undefined) { if (arguments.length === 0) { this._events = Object.create(null); this._eventsCount = 0; } else if (events[type] !== undefined) { if (--this._eventsCount === 0) this._events = Object.create(null); else delete events[type]; } return this; } // emit removeListener for all listeners on all events if (arguments.length === 0) { var keys = Object.keys(events); var key; for (i = 0; i < keys.length; ++i) { key = keys[i]; if (key === 'removeListener') continue; this.removeAllListeners(key); } this.removeAllListeners('removeListener'); this._events = Object.create(null); this._eventsCount = 0; return this; } listeners = events[type]; if (typeof listeners === 'function') { this.removeListener(type, listeners); } else if (listeners !== undefined) { // LIFO order for (i = listeners.length - 1; i >= 0; i--) { this.removeListener(type, listeners[i]); } } return this; }; function _listeners(target, type, unwrap) { var events = target._events; if (events === undefined) return []; var evlistener = events[type]; if (evlistener === undefined) return []; if (typeof evlistener === 'function') return unwrap ? [evlistener.listener || evlistener] : [evlistener]; return unwrap ? unwrapListeners(evlistener) : arrayClone(evlistener, evlistener.length); } EventEmitter.prototype.listeners = function listeners(type) { return _listeners(this, type, true); }; EventEmitter.prototype.rawListeners = function rawListeners(type) { return _listeners(this, type, false); }; EventEmitter.listenerCount = function(emitter, type) { if (typeof emitter.listenerCount === 'function') { return emitter.listenerCount(type); } else { return listenerCount.call(emitter, type); } }; EventEmitter.prototype.listenerCount = listenerCount; function listenerCount(type) { var events = this._events; if (events !== undefined) { var evlistener = events[type]; if (typeof evlistener === 'function') { return 1; } else if (evlistener !== undefined) { return evlistener.length; } } return 0; } EventEmitter.prototype.eventNames = function eventNames() { return this._eventsCount > 0 ? ReflectOwnKeys(this._events) : []; }; function arrayClone(arr, n) { var copy = new Array(n); for (var i = 0; i < n; ++i) copy[i] = arr[i]; return copy; } function spliceOne(list, index) { for (; index + 1 < list.length; index++) list[index] = list[index + 1]; list.pop(); } function unwrapListeners(arr) { var ret = new Array(arr.length); for (var i = 0; i < ret.length; ++i) { ret[i] = arr[i].listener || arr[i]; } return ret; } function once(emitter, name) { return new Promise(function (resolve, reject) { function eventListener() { if (errorListener !== undefined) { emitter.removeListener('error', errorListener); } resolve([].slice.call(arguments)); }; var errorListener; // Adding an error listener is not optional because // if an error is thrown on an event emitter we cannot // guarantee that the actual event we are waiting will // be fired. The result could be a silent way to create // memory or file descriptor leaks, which is something // we should avoid. if (name !== 'error') { errorListener = function errorListener(err) { emitter.removeListener(name, eventListener); reject(err); }; emitter.once('error', errorListener); } emitter.once(name, eventListener); }); } },{}],6:[function(require,module,exports){ /*! ieee754. BSD-3-Clause License. Feross Aboukhadijeh */ exports.read = function (buffer, offset, isLE, mLen, nBytes) { var e, m var eLen = (nBytes * 8) - mLen - 1 var eMax = (1 << eLen) - 1 var eBias = eMax >> 1 var nBits = -7 var i = isLE ? (nBytes - 1) : 0 var d = isLE ? -1 : 1 var s = buffer[offset + i] i += d e = s & ((1 << (-nBits)) - 1) s >>= (-nBits) nBits += eLen for (; nBits > 0; e = (e * 256) + buffer[offset + i], i += d, nBits -= 8) {} m = e & ((1 << (-nBits)) - 1) e >>= (-nBits) nBits += mLen for (; nBits > 0; m = (m * 256) + buffer[offset + i], i += d, nBits -= 8) {} if (e === 0) { e = 1 - eBias } else if (e === eMax) { return m ? NaN : ((s ? -1 : 1) * Infinity) } else { m = m + Math.pow(2, mLen) e = e - eBias } return (s ? -1 : 1) * m * Math.pow(2, e - mLen) } exports.write = function (buffer, value, offset, isLE, mLen, nBytes) { var e, m, c var eLen = (nBytes * 8) - mLen - 1 var eMax = (1 << eLen) - 1 var eBias = eMax >> 1 var rt = (mLen === 23 ? Math.pow(2, -24) - Math.pow(2, -77) : 0) var i = isLE ? 0 : (nBytes - 1) var d = isLE ? 1 : -1 var s = value < 0 || (value === 0 && 1 / value < 0) ? 1 : 0 value = Math.abs(value) if (isNaN(value) || value === Infinity) { m = isNaN(value) ? 1 : 0 e = eMax } else { e = Math.floor(Math.log(value) / Math.LN2) if (value * (c = Math.pow(2, -e)) < 1) { e-- c *= 2 } if (e + eBias >= 1) { value += rt / c } else { value += rt * Math.pow(2, 1 - eBias) } if (value * c >= 2) { e++ c /= 2 } if (e + eBias >= eMax) { m = 0 e = eMax } else if (e + eBias >= 1) { m = ((value * c) - 1) * Math.pow(2, mLen) e = e + eBias } else { m = value * Math.pow(2, eBias - 1) * Math.pow(2, mLen) e = 0 } } for (; mLen >= 8; buffer[offset + i] = m & 0xff, i += d, m /= 256, mLen -= 8) {} e = (e << mLen) | m eLen += mLen for (; eLen > 0; buffer[offset + i] = e & 0xff, i += d, e /= 256, eLen -= 8) {} buffer[offset + i - d] |= s * 128 } },{}],7:[function(require,module,exports){ (function (Buffer){(function (){ !function(factory) { var global = this; module.exports = factory(global); }(function(global) { "use strict"; function is(obj, Ctor) { return "object" != typeof obj || null === obj ? !1 : obj.constructor === Ctor || Object.prototype.toString.call(obj) === "[object " + Ctor.name + "]"; } function arrayFrom(arrayLike, forceCopy) { return !forceCopy && is(arrayLike, Array) ? arrayLike : Array.prototype.slice.call(arrayLike); } function defined(value, defaultValue) { return void 0 !== value ? value : defaultValue; } function jDataView(buffer, byteOffset, byteLength, littleEndian) { if (jDataView.is(buffer)) { var result = buffer.slice(byteOffset, byteOffset + byteLength); return result._littleEndian = defined(littleEndian, result._littleEndian), result; } if (!jDataView.is(this)) return new jDataView(buffer, byteOffset, byteLength, littleEndian); if (this.buffer = buffer = jDataView.wrapBuffer(buffer), this._isArrayBuffer = compatibility.ArrayBuffer && is(buffer, ArrayBuffer), this._isPixelData = !1, this._isDataView = compatibility.DataView && this._isArrayBuffer, this._isNodeBuffer = !0 && compatibility.NodeBuffer && is(buffer, Buffer), !this._isNodeBuffer && !this._isArrayBuffer && !is(buffer, Array)) throw new TypeError("jDataView buffer has an incompatible type"); this._littleEndian = !!littleEndian; var bufferLength = "byteLength" in buffer ? buffer.byteLength : buffer.length; this.byteOffset = byteOffset = defined(byteOffset, 0), this.byteLength = byteLength = defined(byteLength, bufferLength - byteOffset), this._offset = this._bitOffset = 0, this._isDataView ? this._view = new DataView(buffer, byteOffset, byteLength) : this._checkBounds(byteOffset, byteLength, bufferLength), this._engineAction = this._isDataView ? this._dataViewAction : this._isNodeBuffer ? this._nodeBufferAction : this._isArrayBuffer ? this._arrayBufferAction : this._arrayAction; } function getCharCodes(string) { if (compatibility.NodeBuffer) return new Buffer(string, "binary"); for (var Type = compatibility.ArrayBuffer ? Uint8Array : Array, codes = new Type(string.length), i = 0, length = string.length; length > i; i++) codes[i] = 255 & string.charCodeAt(i); return codes; } function pow2(n) { return n >= 0 && 31 > n ? 1 << n : pow2[n] || (pow2[n] = Math.pow(2, n)); } function Uint64(lo, hi) { this.lo = lo, this.hi = hi; } function Int64() { Uint64.apply(this, arguments); } var compatibility = { NodeBuffer: !0 && "Buffer" in global, DataView: "DataView" in global, ArrayBuffer: "ArrayBuffer" in global, PixelData: !1 }, TextEncoder = global.TextEncoder, TextDecoder = global.TextDecoder; compatibility.NodeBuffer && !function(buffer) { try { buffer.writeFloatLE(1/0, 0); } catch (e) { compatibility.NodeBuffer = !1; } }(new Buffer(4)); var dataTypes = { Int8: 1, Int16: 2, Int32: 4, Uint8: 1, Uint16: 2, Uint32: 4, Float32: 4, Float64: 8 }; jDataView.wrapBuffer = function(buffer) { switch (typeof buffer) { case "number": if (compatibility.NodeBuffer) buffer = new Buffer(buffer), buffer.fill(0); else if (compatibility.ArrayBuffer) buffer = new Uint8Array(buffer).buffer; else { buffer = new Array(buffer); for (var i = 0; i < buffer.length; i++) buffer[i] = 0; } return buffer; case "string": buffer = getCharCodes(buffer); default: return "length" in buffer && !(compatibility.NodeBuffer && is(buffer, Buffer) || compatibility.ArrayBuffer && is(buffer, ArrayBuffer)) && (compatibility.NodeBuffer ? buffer = new Buffer(buffer) : compatibility.ArrayBuffer ? is(buffer, ArrayBuffer) || (buffer = new Uint8Array(buffer).buffer, is(buffer, ArrayBuffer) || (buffer = new Uint8Array(arrayFrom(buffer, !0)).buffer)) : buffer = arrayFrom(buffer)), buffer; } }, jDataView.is = function(view) { return view && view.jDataView; }, jDataView.from = function() { return new jDataView(arguments); }, jDataView.Uint64 = Uint64, Uint64.prototype = { valueOf: function() { return this.lo + pow2(32) * this.hi; }, toString: function() { return Number.prototype.toString.apply(this.valueOf(), arguments); } }, Uint64.fromNumber = function(number) { var hi = Math.floor(number / pow2(32)), lo = number - hi * pow2(32); return new Uint64(lo, hi); }, jDataView.Int64 = Int64, Int64.prototype = "create" in Object ? Object.create(Uint64.prototype) : new Uint64(), Int64.prototype.valueOf = function() { return this.hi < pow2(31) ? Uint64.prototype.valueOf.apply(this, arguments) : -(pow2(32) - this.lo + pow2(32) * (pow2(32) - 1 - this.hi)); }, Int64.fromNumber = function(number) { var lo, hi; if (number >= 0) { var unsigned = Uint64.fromNumber(number); lo = unsigned.lo, hi = unsigned.hi; } else hi = Math.floor(number / pow2(32)), lo = number - hi * pow2(32), hi += pow2(32); return new Int64(lo, hi); }; var proto = jDataView.prototype = { compatibility: compatibility, jDataView: !0, _checkBounds: function(byteOffset, byteLength, maxLength) { if ("number" != typeof byteOffset) throw new TypeError("Offset is not a number."); if ("number" != typeof byteLength) throw new TypeError("Size is not a number."); if (0 > byteLength) throw new RangeError("Length is negative."); if (0 > byteOffset || byteOffset + byteLength > defined(maxLength, this.byteLength)) throw new RangeError("Offsets are out of bounds."); }, _action: function(type, isReadAction, byteOffset, littleEndian, value) { return this._engineAction(type, isReadAction, defined(byteOffset, this._offset), defined(littleEndian, this._littleEndian), value); }, _dataViewAction: function(type, isReadAction, byteOffset, littleEndian, value) { return this._offset = byteOffset + dataTypes[type], isReadAction ? this._view["get" + type](byteOffset, littleEndian) : this._view["set" + type](byteOffset, value, littleEndian); }, _arrayBufferAction: function(type, isReadAction, byteOffset, littleEndian, value) { var typedArray, size = dataTypes[type], TypedArray = global[type + "Array"]; if (littleEndian = defined(littleEndian, this._littleEndian), 1 === size || (this.byteOffset + byteOffset) % size === 0 && littleEndian) return typedArray = new TypedArray(this.buffer, this.byteOffset + byteOffset, 1), this._offset = byteOffset + size, isReadAction ? typedArray[0] : typedArray[0] = value; var bytes = new Uint8Array(isReadAction ? this.getBytes(size, byteOffset, littleEndian, !0) : size); return typedArray = new TypedArray(bytes.buffer, 0, 1), isReadAction ? typedArray[0] : (typedArray[0] = value, void this._setBytes(byteOffset, bytes, littleEndian)); }, _arrayAction: function(type, isReadAction, byteOffset, littleEndian, value) { return isReadAction ? this["_get" + type](byteOffset, littleEndian) : this["_set" + type](byteOffset, value, littleEndian); }, _getBytes: function(length, byteOffset, littleEndian) { littleEndian = defined(littleEndian, this._littleEndian), byteOffset = defined(byteOffset, this._offset), length = defined(length, this.byteLength - byteOffset), this._checkBounds(byteOffset, length), byteOffset += this.byteOffset, this._offset = byteOffset - this.byteOffset + length; var result = this._isArrayBuffer ? new Uint8Array(this.buffer, byteOffset, length) : (this.buffer.slice || Array.prototype.slice).call(this.buffer, byteOffset, byteOffset + length); return littleEndian || 1 >= length ? result : arrayFrom(result).reverse(); }, getBytes: function(length, byteOffset, littleEndian, toArray) { var result = this._getBytes(length, byteOffset, defined(littleEndian, !0)); return toArray ? arrayFrom(result) : result; }, _setBytes: function(byteOffset, bytes, littleEndian) { var length = bytes.length; if (0 !== length) { if (littleEndian = defined(littleEndian, this._littleEndian), byteOffset = defined(byteOffset, this._offset), this._checkBounds(byteOffset, length), !littleEndian && length > 1 && (bytes = arrayFrom(bytes, !0).reverse()), byteOffset += this.byteOffset, this._isArrayBuffer) new Uint8Array(this.buffer, byteOffset, length).set(bytes); else if (this._isNodeBuffer) new Buffer(bytes).copy(this.buffer, byteOffset); else for (var i = 0; length > i; i++) this.buffer[byteOffset + i] = bytes[i]; this._offset = byteOffset - this.byteOffset + length; } }, setBytes: function(byteOffset, bytes, littleEndian) { this._setBytes(byteOffset, bytes, defined(littleEndian, !0)); }, getString: function(byteLength, byteOffset, encoding) { if (this._isNodeBuffer) return byteOffset = defined(byteOffset, this._offset), byteLength = defined(byteLength, this.byteLength - byteOffset), this._checkBounds(byteOffset, byteLength), this._offset = byteOffset + byteLength, this.buffer.toString(encoding || "binary", this.byteOffset + byteOffset, this.byteOffset + this._offset); var bytes = this._getBytes(byteLength, byteOffset, !0); if (encoding = "utf8" === encoding ? "utf-8" : encoding || "binary", TextDecoder && "binary" !== encoding) return new TextDecoder(encoding).decode(this._isArrayBuffer ? bytes : new Uint8Array(bytes)); var string = ""; byteLength = bytes.length; for (var i = 0; byteLength > i; i++) string += String.fromCharCode(bytes[i]); return "utf-8" === encoding && (string = decodeURIComponent(escape(string))), string; }, setString: function(byteOffset, subString, encoding) { if (this._isNodeBuffer) return byteOffset = defined(byteOffset, this._offset), this._checkBounds(byteOffset, subString.length), void (this._offset = byteOffset + this.buffer.write(subString, this.byteOffset + byteOffset, encoding || "binary")); encoding = "utf8" === encoding ? "utf-8" : encoding || "binary"; var bytes; TextEncoder && "binary" !== encoding ? bytes = new TextEncoder(encoding).encode(subString) : ("utf-8" === encoding && (subString = unescape(encodeURIComponent(subString))), bytes = getCharCodes(subString)), this._setBytes(byteOffset, bytes, !0); }, getChar: function(byteOffset) { return this.getString(1, byteOffset); }, setChar: function(byteOffset, character) { this.setString(byteOffset, character); }, tell: function() { return this._offset; }, seek: function(byteOffset) { return this._checkBounds(byteOffset, 0), this._offset = byteOffset; }, skip: function(byteLength) { return this.seek(this._offset + byteLength); }, slice: function(start, end, forceCopy) { function normalizeOffset(offset, byteLength) { return 0 > offset ? offset + byteLength : offset; } return start = normalizeOffset(start, this.byteLength), end = normalizeOffset(defined(end, this.byteLength), this.byteLength), forceCopy ? new jDataView(this.getBytes(end - start, start, !0, !0), void 0, void 0, this._littleEndian) : new jDataView(this.buffer, this.byteOffset + start, end - start, this._littleEndian); }, alignBy: function(byteCount) { return this._bitOffset = 0, 1 !== defined(byteCount, 1) ? this.skip(byteCount - (this._offset % byteCount || byteCount)) : this._offset; }, _getFloat64: function(byteOffset, littleEndian) { var b = this._getBytes(8, byteOffset, littleEndian), sign = 1 - 2 * (b[7] >> 7), exponent = ((b[7] << 1 & 255) << 3 | b[6] >> 4) - 1023, mantissa = (15 & b[6]) * pow2(48) + b[5] * pow2(40) + b[4] * pow2(32) + b[3] * pow2(24) + b[2] * pow2(16) + b[1] * pow2(8) + b[0]; return 1024 === exponent ? 0 !== mantissa ? 0/0 : 1/0 * sign : -1023 === exponent ? sign * mantissa * pow2(-1074) : sign * (1 + mantissa * pow2(-52)) * pow2(exponent); }, _getFloat32: function(byteOffset, littleEndian) { var b = this._getBytes(4, byteOffset, littleEndian), sign = 1 - 2 * (b[3] >> 7), exponent = (b[3] << 1 & 255 | b[2] >> 7) - 127, mantissa = (127 & b[2]) << 16 | b[1] << 8 | b[0]; return 128 === exponent ? 0 !== mantissa ? 0/0 : 1/0 * sign : -127 === exponent ? sign * mantissa * pow2(-149) : sign * (1 + mantissa * pow2(-23)) * pow2(exponent); }, _get64: function(Type, byteOffset, littleEndian) { littleEndian = defined(littleEndian, this._littleEndian), byteOffset = defined(byteOffset, this._offset); for (var parts = littleEndian ? [ 0, 4 ] : [ 4, 0 ], i = 0; 2 > i; i++) parts[i] = this.getUint32(byteOffset + parts[i], littleEndian); return this._offset = byteOffset + 8, new Type(parts[0], parts[1]); }, getInt64: function(byteOffset, littleEndian) { return this._get64(Int64, byteOffset, littleEndian); }, getUint64: function(byteOffset, littleEndian) { return this._get64(Uint64, byteOffset, littleEndian); }, _getInt32: function(byteOffset, littleEndian) { var b = this._getBytes(4, byteOffset, littleEndian); return b[3] << 24 | b[2] << 16 | b[1] << 8 | b[0]; }, _getUint32: function(byteOffset, littleEndian) { return this._getInt32(byteOffset, littleEndian) >>> 0; }, _getInt16: function(byteOffset, littleEndian) { return this._getUint16(byteOffset, littleEndian) << 16 >> 16; }, _getUint16: function(byteOffset, littleEndian) { var b = this._getBytes(2, byteOffset, littleEndian); return b[1] << 8 | b[0]; }, _getInt8: function(byteOffset) { return this._getUint8(byteOffset) << 24 >> 24; }, _getUint8: function(byteOffset) { return this._getBytes(1, byteOffset)[0]; }, _getBitRangeData: function(bitLength, byteOffset) { var startBit = (defined(byteOffset, this._offset) << 3) + this._bitOffset, endBit = startBit + bitLength, start = startBit >>> 3, end = endBit + 7 >>> 3, b = this._getBytes(end - start, start, !0), wideValue = 0; (this._bitOffset = 7 & endBit) && (this._bitOffset -= 8); for (var i = 0, length = b.length; length > i; i++) wideValue = wideValue << 8 | b[i]; return { start: start, bytes: b, wideValue: wideValue }; }, getSigned: function(bitLength, byteOffset) { var shift = 32 - bitLength; return this.getUnsigned(bitLength, byteOffset) << shift >> shift; }, getUnsigned: function(bitLength, byteOffset) { var value = this._getBitRangeData(bitLength, byteOffset).wideValue >>> -this._bitOffset; return 32 > bitLength ? value & ~(-1 << bitLength) : value; }, _setBinaryFloat: function(byteOffset, value, mantSize, expSize, littleEndian) { var exponent, mantissa, signBit = 0 > value ? 1 : 0, eMax = ~(-1 << expSize - 1), eMin = 1 - eMax; 0 > value && (value = -value), 0 === value ? (exponent = 0, mantissa = 0) : isNaN(value) ? (exponent = 2 * eMax + 1, mantissa = 1) : 1/0 === value ? (exponent = 2 * eMax + 1, mantissa = 0) : (exponent = Math.floor(Math.log(value) / Math.LN2), exponent >= eMin && eMax >= exponent ? (mantissa = Math.floor((value * pow2(-exponent) - 1) * pow2(mantSize)), exponent += eMax) : (mantissa = Math.floor(value / pow2(eMin - mantSize)), exponent = 0)); for (var b = []; mantSize >= 8; ) b.push(mantissa % 256), mantissa = Math.floor(mantissa / 256), mantSize -= 8; for (exponent = exponent << mantSize | mantissa, expSize += mantSize; expSize >= 8; ) b.push(255 & exponent), exponent >>>= 8, expSize -= 8; b.push(signBit << expSize | exponent), this._setBytes(byteOffset, b, littleEndian); }, _setFloat32: function(byteOffset, value, littleEndian) { this._setBinaryFloat(byteOffset, value, 23, 8, littleEndian); }, _setFloat64: function(byteOffset, value, littleEndian) { this._setBinaryFloat(byteOffset, value, 52, 11, littleEndian); }, _set64: function(Type, byteOffset, value, littleEndian) { "object" != typeof value && (value = Type.fromNumber(value)), littleEndian = defined(littleEndian, this._littleEndian), byteOffset = defined(byteOffset, this._offset); var parts = littleEndian ? { lo: 0, hi: 4 } : { lo: 4, hi: 0 }; for (var partName in parts) this.setUint32(byteOffset + parts[partName], value[partName], littleEndian); this._offset = byteOffset + 8; }, setInt64: function(byteOffset, value, littleEndian) { this._set64(Int64, byteOffset, value, littleEndian); }, setUint64: function(byteOffset, value, littleEndian) { this._set64(Uint64, byteOffset, value, littleEndian); }, _setUint32: function(byteOffset, value, littleEndian) { this._setBytes(byteOffset, [ 255 & value, value >>> 8 & 255, value >>> 16 & 255, value >>> 24 ], littleEndian); }, _setUint16: function(byteOffset, value, littleEndian) { this._setBytes(byteOffset, [ 255 & value, value >>> 8 & 255 ], littleEndian); }, _setUint8: function(byteOffset, value) { this._setBytes(byteOffset, [ 255 & value ]); }, setUnsigned: function(byteOffset, value, bitLength) { var data = this._getBitRangeData(bitLength, byteOffset), wideValue = data.wideValue, b = data.bytes; wideValue &= ~(~(-1 << bitLength) << -this._bitOffset), wideValue |= (32 > bitLength ? value & ~(-1 << bitLength) : value) << -this._bitOffset; for (var i = b.length - 1; i >= 0; i--) b[i] = 255 & wideValue, wideValue >>>= 8; this._setBytes(data.start, b, !0); } }, nodeNaming = { Int8: "Int8", Int16: "Int16", Int32: "Int32", Uint8: "UInt8", Uint16: "UInt16", Uint32: "UInt32", Float32: "Float", Float64: "Double" }; proto._nodeBufferAction = function(type, isReadAction, byteOffset, littleEndian, value) { this._offset = byteOffset + dataTypes[type]; var nodeName = nodeNaming[type] + ("Int8" === type || "Uint8" === type ? "" : littleEndian ? "LE" : "BE"); return byteOffset += this.byteOffset, isReadAction ? this.buffer["read" + nodeName](byteOffset) : this.buffer["write" + nodeName](value, byteOffset); }; for (var type in dataTypes) !function(type) { proto["get" + type] = function(byteOffset, littleEndian) { return this._action(type, !0, byteOffset, littleEndian); }, proto["set" + type] = function(byteOffset, value, littleEndian) { this._action(type, !1, byteOffset, littleEndian, value); }; }(type); proto._setInt32 = proto._setUint32, proto._setInt16 = proto._setUint16, proto._setInt8 = proto._setUint8, proto.setSigned = proto.setUnsigned; for (var method in proto) "set" === method.slice(0, 3) && !function(type) { proto["write" + type] = function() { Array.prototype.unshift.call(arguments, void 0), this["set" + type].apply(this, arguments); }; }(method.slice(3)); return jDataView; }); }).call(this)}).call(this,require("buffer").Buffer) },{"buffer":3}],8:[function(require,module,exports){ // shim for using process in browser var process = module.exports = {}; // cached from whatever global is present so that test runners that stub it // don't break things. But we need to wrap it in a try catch in case it is // wrapped in strict mode code which doesn't define any globals. It's inside a // function because try/catches deoptimize in certain engines. var cachedSetTimeout; var cachedClearTimeout; function defaultSetTimout() { throw new Error('setTimeout has not been defined'); } function defaultClearTimeout () { throw new Error('clearTimeout has not been defined'); } (function () { try { if (typeof setTimeout === 'function') { cachedSetTimeout = setTimeout; } else { cachedSetTimeout = defaultSetTimout; } } catch (e) { cachedSetTimeout = defaultSetTimout; } try { if (typeof clearTimeout === 'function') { cachedClearTimeout = clearTimeout; } else { cachedClearTimeout = defaultClearTimeout; } } catch (e) { cachedClearTimeout = defaultClearTimeout; } } ()) function runTimeout(fun) { if (cachedSetTimeout === setTimeout) { //normal enviroments in sane situations return setTimeout(fun, 0); } // if setTimeout wasn't available but was latter defined if ((cachedSetTimeout === defaultSetTimout || !cachedSetTimeout) && setTimeout) { cachedSetTimeout = setTimeout; return setTimeout(fun, 0); } try { // when when somebody has screwed with setTimeout but no I.E. maddness return cachedSetTimeout(fun, 0); } catch(e){ try { // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally return cachedSetTimeout.call(null, fun, 0); } catch(e){ // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error return cachedSetTimeout.call(this, fun, 0); } } } function runClearTimeout(marker) { if (cachedClearTimeout === clearTimeout) { //normal enviroments in sane situations return clearTimeout(marker); } // if clearTimeout wasn't available but was latter defined if ((cachedClearTimeout === defaultClearTimeout || !cachedClearTimeout) && clearTimeout) { cachedClearTimeout = clearTimeout; return clearTimeout(marker); } try { // when when somebody has screwed with setTimeout but no I.E. maddness return cachedClearTimeout(marker); } catch (e){ try { // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally return cachedClearTimeout.call(null, marker); } catch (e){ // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error. // Some versions of I.E. have different rules for clearTimeout vs setTimeout return cachedClearTimeout.call(this, marker); } } } var queue = []; var draining = false; var currentQueue; var queueIndex = -1; function cleanUpNextTick() { if (!draining || !currentQueue) { return; } draining = false; if (currentQueue.length) { queue = currentQueue.concat(queue); } else { queueIndex = -1; } if (queue.length) { drainQueue(); } } function drainQueue() { if (draining) { return; } var timeout = runTimeout(cleanUpNextTick); draining = true; var len = queue.length; while(len) { currentQueue = queue; queue = []; while (++queueIndex < len) { if (currentQueue) { currentQueue[queueIndex].run(); } } queueIndex = -1; len = queue.length; } currentQueue = null; draining = false; runClearTimeout(timeout); } process.nextTick = function (fun) { var args = new Array(arguments.length - 1); if (arguments.length > 1) { for (var i = 1; i < arguments.length; i++) { args[i - 1] = arguments[i]; } } queue.push(new Item(fun, args)); if (queue.length === 1 && !draining) { runTimeout(drainQueue); } }; // v8 likes predictible objects function Item(fun, array) { this.fun = fun; this.array = array; } Item.prototype.run = function () { this.fun.apply(null, this.array); }; process.title = 'browser'; process.browser = true; process.env = {}; process.argv = []; process.version = ''; // empty string to avoid regexp issues process.versions = {}; function noop() {} process.on = noop; process.addListener = noop; process.once = noop; process.off = noop; process.removeListener = noop; process.removeAllListeners = noop; process.emit = noop; process.prependListener = noop; process.prependOnceListener = noop; process.listeners = function (name) { return [] } process.binding = function (name) { throw new Error('process.binding is not supported'); }; process.cwd = function () { return '/' }; process.chdir = function (dir) { throw new Error('process.chdir is not supported'); }; process.umask = function() { return 0; }; },{}],9:[function(require,module,exports){ /* eslint-disable node/no-deprecated-api */ var buffer = require('buffer') var Buffer = buffer.Buffer // alternative to using Object.keys for old browsers function copyProps (src, dst) { for (var key in src) { dst[key] = src[key] } } if (Buffer.from && Buffer.alloc && Buffer.allocUnsafe && Buffer.allocUnsafeSlow) { module.exports = buffer } else { // Copy properties from require('buffer') copyProps(buffer, exports) exports.Buffer = SafeBuffer } function SafeBuffer (arg, encodingOrOffset, length) { return Buffer(arg, encodingOrOffset, length) } // Copy static methods from Buffer copyProps(Buffer, SafeBuffer) SafeBuffer.from = function (arg, encodingOrOffset, length) { if (typeof arg === 'number') { throw new TypeError('Argument must not be a number') } return Buffer(arg, encodingOrOffset, length) } SafeBuffer.alloc = function (size, fill, encoding) { if (typeof size !== 'number') { throw new TypeError('Argument must be a number') } var buf = Buffer(size) if (fill !== undefined) { if (typeof encoding === 'string') { buf.fill(fill, encoding) } else { buf.fill(fill) } } else { buf.fill(0) } return buf } SafeBuffer.allocUnsafe = function (size) { if (typeof size !== 'number') { throw new TypeError('Argument must be a number') } return Buffer(size) } SafeBuffer.allocUnsafeSlow = function (size) { if (typeof size !== 'number') { throw new TypeError('Argument must be a number') } return buffer.SlowBuffer(size) } },{"buffer":3}],10:[function(require,module,exports){ (function (Buffer){(function (){ ;(function (sax) { // wrapper for non-node envs sax.parser = function (strict, opt) { return new SAXParser(strict, opt) } sax.SAXParser = SAXParser sax.SAXStream = SAXStream sax.createStream = createStream // When we pass the MAX_BUFFER_LENGTH position, start checking for buffer overruns. // When we check, schedule the next check for MAX_BUFFER_LENGTH - (max(buffer lengths)), // since that's the earliest that a buffer overrun could occur. This way, checks are // as rare as required, but as often as necessary to ensure never crossing this bound. // Furthermore, buffers are only tested at most once per write(), so passing a very // large string into write() might have undesirable effects, but this is manageable by // the caller, so it is assumed to be safe. Thus, a call to write() may, in the extreme // edge case, result in creating at most one complete copy of the string passed in. // Set to Infinity to have unlimited buffers. sax.MAX_BUFFER_LENGTH = 64 * 1024 var buffers = [ 'comment', 'sgmlDecl', 'textNode', 'tagName', 'doctype', 'procInstName', 'procInstBody', 'entity', 'attribName', 'attribValue', 'cdata', 'script' ] sax.EVENTS = [ 'text', 'processinginstruction', 'sgmldeclaration', 'doctype', 'comment', 'opentagstart', 'attribute', 'opentag', 'closetag', 'opencdata', 'cdata', 'closecdata', 'error', 'end', 'ready', 'script', 'opennamespace', 'closenamespace' ] function SAXParser (strict, opt) { if (!(this instanceof SAXParser)) { return new SAXParser(strict, opt) } var parser = this clearBuffers(parser) parser.q = parser.c = '' parser.bufferCheckPosition = sax.MAX_BUFFER_LENGTH parser.opt = opt || {} parser.opt.lowercase = parser.opt.lowercase || parser.opt.lowercasetags parser.looseCase = parser.opt.lowercase ? 'toLowerCase' : 'toUpperCase' parser.tags = [] parser.closed = parser.closedRoot = parser.sawRoot = false parser.tag = parser.error = null parser.strict = !!strict parser.noscript = !!(strict || parser.opt.noscript) parser.state = S.BEGIN parser.strictEntities = parser.opt.strictEntities parser.ENTITIES = parser.strictEntities ? Object.create(sax.XML_ENTITIES) : Object.create(sax.ENTITIES) parser.attribList = [] // namespaces form a prototype chain. // it always points at the current tag, // which protos to its parent tag. if (parser.opt.xmlns) { parser.ns = Object.create(rootNS) } // mostly just for error reporting parser.trackPosition = parser.opt.position !== false if (parser.trackPosition) { parser.position = parser.line = parser.column = 0 } emit(parser, 'onready') } if (!Object.create) { Object.create = function (o) { function F () {} F.prototype = o var newf = new F() return newf } } if (!Object.keys) { Object.keys = function (o) { var a = [] for (var i in o) if (o.hasOwnProperty(i)) a.push(i) return a } } function checkBufferLength (parser) { var maxAllowed = Math.max(sax.MAX_BUFFER_LENGTH, 10) var maxActual = 0 for (var i = 0, l = buffers.length; i < l; i++) { var len = parser[buffers[i]].length if (len > maxAllowed) { // Text/cdata nodes can get big, and since they're buffered, // we can get here under normal conditions. // Avoid issues by emitting the text node now, // so at least it won't get any bigger. switch (buffers[i]) { case 'textNode': closeText(parser) break case 'cdata': emitNode(parser, 'oncdata', parser.cdata) parser.cdata = '' break case 'script': emitNode(parser, 'onscript', parser.script) parser.script = '' break default: error(parser, 'Max buffer length exceeded: ' + buffers[i]) } } maxActual = Math.max(maxActual, len) } // schedule the next check for the earliest possible buffer overrun. var m = sax.MAX_BUFFER_LENGTH - maxActual parser.bufferCheckPosition = m + parser.position } function clearBuffers (parser) { for (var i = 0, l = buffers.length; i < l; i++) { parser[buffers[i]] = '' } } function flushBuffers (parser) { closeText(parser) if (parser.cdata !== '') { emitNode(parser, 'oncdata', parser.cdata) parser.cdata = '' } if (parser.script !== '') { emitNode(parser, 'onscript', parser.script) parser.script = '' } } SAXParser.prototype = { end: function () { end(this) }, write: write, resume: function () { this.error = null; return this }, close: function () { return this.write(null) }, flush: function () { flushBuffers(this) } } var Stream try { Stream = require('stream').Stream } catch (ex) { Stream = function () {} } var streamWraps = sax.EVENTS.filter(function (ev) { return ev !== 'error' && ev !== 'end' }) function createStream (strict, opt) { return new SAXStream(strict, opt) } function SAXStream (strict, opt) { if (!(this instanceof SAXStream)) { return new SAXStream(strict, opt) } Stream.apply(this) this._parser = new SAXParser(strict, opt) this.writable = true this.readable = true var me = this this._parser.onend = function () { me.emit('end') } this._parser.onerror = function (er) { me.emit('error', er) // if didn't throw, then means error was handled. // go ahead and clear error, so we can write again. me._parser.error = null } this._decoder = null streamWraps.forEach(function (ev) { Object.defineProperty(me, 'on' + ev, { get: function () { return me._parser['on' + ev] }, set: function (h) { if (!h) { me.removeAllListeners(ev) me._parser['on' + ev] = h return h } me.on(ev, h) }, enumerable: true, configurable: false }) }) } SAXStream.prototype = Object.create(Stream.prototype, { constructor: { value: SAXStream } }) SAXStream.prototype.write = function (data) { if (typeof Buffer === 'function' && typeof Buffer.isBuffer === 'function' && Buffer.isBuffer(data)) { if (!this._decoder) { var SD = require('string_decoder').StringDecoder this._decoder = new SD('utf8') } data = this._decoder.write(data) } this._parser.write(data.toString()) this.emit('data', data) return true } SAXStream.prototype.end = function (chunk) { if (chunk && chunk.length) { this.write(chunk) } this._parser.end() return true } SAXStream.prototype.on = function (ev, handler) { var me = this if (!me._parser['on' + ev] && streamWraps.indexOf(ev) !== -1) { me._parser['on' + ev] = function () { var args = arguments.length === 1 ? [arguments[0]] : Array.apply(null, arguments) args.splice(0, 0, ev) me.emit.apply(me, args) } } return Stream.prototype.on.call(me, ev, handler) } // this really needs to be replaced with character classes. // XML allows all manner of ridiculous numbers and digits. var CDATA = '[CDATA[' var DOCTYPE = 'DOCTYPE' var XML_NAMESPACE = 'http://www.w3.org/XML/1998/namespace' var XMLNS_NAMESPACE = 'http://www.w3.org/2000/xmlns/' var rootNS = { xml: XML_NAMESPACE, xmlns: XMLNS_NAMESPACE } // http://www.w3.org/TR/REC-xml/#NT-NameStartChar // This implementation works on strings, a single character at a time // as such, it cannot ever support astral-plane characters (10000-EFFFF) // without a significant breaking change to either this parser, or the // JavaScript language. Implementation of an emoji-capable xml parser // is left as an exercise for the reader. var nameStart = /[:_A-Za-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD]/ var nameBody = /[:_A-Za-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD\u00B7\u0300-\u036F\u203F-\u2040.\d-]/ var entityStart = /[#:_A-Za-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD]/ var entityBody = /[#:_A-Za-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD\u00B7\u0300-\u036F\u203F-\u2040.\d-]/ function isWhitespace (c) { return c === ' ' || c === '\n' || c === '\r' || c === '\t' } function isQuote (c) { return c === '"' || c === '\'' } function isAttribEnd (c) { return c === '>' || isWhitespace(c) } function isMatch (regex, c) { return regex.test(c) } function notMatch (regex, c) { return !isMatch(regex, c) } var S = 0 sax.STATE = { BEGIN: S++, // leading byte order mark or whitespace BEGIN_WHITESPACE: S++, // leading whitespace TEXT: S++, // general stuff TEXT_ENTITY: S++, // & and such. OPEN_WAKA: S++, // < SGML_DECL: S++, // SCRIPT: S++, //
    Current View
    ================================================ FILE: lib/pdf.js/web/viewer.js ================================================ /** * @licstart The following is the entire license notice for the * Javascript code in this page * * Copyright 2021 Mozilla Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * @licend The above is the entire license notice for the * Javascript code in this page */ /******/ (() => { // webpackBootstrap /******/ "use strict"; /******/ var __webpack_modules__ = ([ /* 0 */, /* 1 */ /***/ ((__unused_webpack_module, exports, __webpack_require__) => { Object.defineProperty(exports, "__esModule", ({ value: true })); exports.OptionKind = exports.AppOptions = void 0; var _viewer_compatibility = __webpack_require__(2); const OptionKind = { VIEWER: 0x02, API: 0x04, WORKER: 0x08, PREFERENCE: 0x80 }; exports.OptionKind = OptionKind; const defaultOptions = { cursorToolOnLoad: { value: 0, kind: OptionKind.VIEWER + OptionKind.PREFERENCE }, defaultUrl: { value: "compressed.tracemonkey-pldi-09.pdf", kind: OptionKind.VIEWER }, defaultZoomValue: { value: "", kind: OptionKind.VIEWER + OptionKind.PREFERENCE }, disableHistory: { value: false, kind: OptionKind.VIEWER }, disablePageLabels: { value: false, kind: OptionKind.VIEWER + OptionKind.PREFERENCE }, enablePermissions: { value: false, kind: OptionKind.VIEWER + OptionKind.PREFERENCE }, enablePrintAutoRotate: { value: true, kind: OptionKind.VIEWER + OptionKind.PREFERENCE }, enableScripting: { value: true, kind: OptionKind.VIEWER + OptionKind.PREFERENCE }, enableWebGL: { value: false, kind: OptionKind.VIEWER + OptionKind.PREFERENCE }, externalLinkRel: { value: "noopener noreferrer nofollow", kind: OptionKind.VIEWER }, externalLinkTarget: { value: 0, kind: OptionKind.VIEWER + OptionKind.PREFERENCE }, historyUpdateUrl: { value: false, kind: OptionKind.VIEWER + OptionKind.PREFERENCE }, ignoreDestinationZoom: { value: false, kind: OptionKind.VIEWER + OptionKind.PREFERENCE }, imageResourcesPath: { value: "./images/", kind: OptionKind.VIEWER }, maxCanvasPixels: { value: 16777216, compatibility: _viewer_compatibility.viewerCompatibilityParams.maxCanvasPixels, kind: OptionKind.VIEWER }, pdfBugEnabled: { value: false, kind: OptionKind.VIEWER + OptionKind.PREFERENCE }, printResolution: { value: 150, kind: OptionKind.VIEWER }, renderer: { value: "canvas", kind: OptionKind.VIEWER + OptionKind.PREFERENCE }, renderInteractiveForms: { value: true, kind: OptionKind.VIEWER + OptionKind.PREFERENCE }, sidebarViewOnLoad: { value: -1, kind: OptionKind.VIEWER + OptionKind.PREFERENCE }, scrollModeOnLoad: { value: -1, kind: OptionKind.VIEWER + OptionKind.PREFERENCE }, spreadModeOnLoad: { value: -1, kind: OptionKind.VIEWER + OptionKind.PREFERENCE }, textLayerMode: { value: 1, kind: OptionKind.VIEWER + OptionKind.PREFERENCE }, useOnlyCssZoom: { value: false, kind: OptionKind.VIEWER + OptionKind.PREFERENCE }, viewerCssTheme: { value: 0, kind: OptionKind.VIEWER + OptionKind.PREFERENCE }, viewOnLoad: { value: 0, kind: OptionKind.VIEWER + OptionKind.PREFERENCE }, cMapPacked: { value: true, kind: OptionKind.API }, cMapUrl: { value: "../web/cmaps/", kind: OptionKind.API }, disableAutoFetch: { value: false, kind: OptionKind.API + OptionKind.PREFERENCE }, disableFontFace: { value: false, kind: OptionKind.API + OptionKind.PREFERENCE }, disableRange: { value: false, kind: OptionKind.API + OptionKind.PREFERENCE }, disableStream: { value: false, kind: OptionKind.API + OptionKind.PREFERENCE }, docBaseUrl: { value: "", kind: OptionKind.API }, enableXfa: { value: false, kind: OptionKind.API }, fontExtraProperties: { value: false, kind: OptionKind.API }, isEvalSupported: { value: true, kind: OptionKind.API }, maxImageSize: { value: -1, kind: OptionKind.API }, pdfBug: { value: false, kind: OptionKind.API }, verbosity: { value: 1, kind: OptionKind.API }, workerPort: { value: null, kind: OptionKind.WORKER }, workerSrc: { value: "../build/pdf.worker.js", kind: OptionKind.WORKER } }; { defaultOptions.disablePreferences = { value: false, kind: OptionKind.VIEWER }; defaultOptions.locale = { value: typeof navigator !== "undefined" ? navigator.language : "en-US", kind: OptionKind.VIEWER }; defaultOptions.sandboxBundleSrc = { value: "../build/pdf.sandbox.js", kind: OptionKind.VIEWER }; } const userOptions = Object.create(null); class AppOptions { constructor() { throw new Error("Cannot initialize AppOptions."); } static get(name) { const userOption = userOptions[name]; if (userOption !== undefined) { return userOption; } const defaultOption = defaultOptions[name]; if (defaultOption !== undefined) { return defaultOption.compatibility ?? defaultOption.value; } return undefined; } static getAll(kind = null) { const options = Object.create(null); for (const name in defaultOptions) { const defaultOption = defaultOptions[name]; if (kind) { if ((kind & defaultOption.kind) === 0) { continue; } if (kind === OptionKind.PREFERENCE) { const value = defaultOption.value, valueType = typeof value; if (valueType === "boolean" || valueType === "string" || valueType === "number" && Number.isInteger(value)) { options[name] = value; continue; } throw new Error(`Invalid type for preference: ${name}`); } } const userOption = userOptions[name]; options[name] = userOption !== undefined ? userOption : defaultOption.compatibility ?? defaultOption.value; } return options; } static set(name, value) { userOptions[name] = value; } static setAll(options) { for (const name in options) { userOptions[name] = options[name]; } } static remove(name) { delete userOptions[name]; } } exports.AppOptions = AppOptions; /***/ }), /* 2 */ /***/ ((__unused_webpack_module, exports) => { Object.defineProperty(exports, "__esModule", ({ value: true })); exports.viewerCompatibilityParams = void 0; const compatibilityParams = Object.create(null); { const userAgent = typeof navigator !== "undefined" && navigator.userAgent || ""; const platform = typeof navigator !== "undefined" && navigator.platform || ""; const maxTouchPoints = typeof navigator !== "undefined" && navigator.maxTouchPoints || 1; const isAndroid = /Android/.test(userAgent); const isIOS = /\b(iPad|iPhone|iPod)(?=;)/.test(userAgent) || platform === "MacIntel" && maxTouchPoints > 1; const isIOSChrome = /CriOS/.test(userAgent); (function checkOnBlobSupport() { if (isIOSChrome) { compatibilityParams.disableCreateObjectURL = true; } })(); (function checkCanvasSizeLimitation() { if (isIOS || isAndroid) { compatibilityParams.maxCanvasPixels = 5242880; } })(); } const viewerCompatibilityParams = Object.freeze(compatibilityParams); exports.viewerCompatibilityParams = viewerCompatibilityParams; /***/ }), /* 3 */ /***/ ((__unused_webpack_module, exports, __webpack_require__) => { Object.defineProperty(exports, "__esModule", ({ value: true })); exports.PDFViewerApplication = exports.PDFPrintServiceFactory = exports.DefaultExternalServices = void 0; var _ui_utils = __webpack_require__(4); var _app_options = __webpack_require__(1); var _pdfjsLib = __webpack_require__(5); var _pdf_cursor_tools = __webpack_require__(6); var _pdf_rendering_queue = __webpack_require__(8); var _overlay_manager = __webpack_require__(9); var _password_prompt = __webpack_require__(10); var _pdf_attachment_viewer = __webpack_require__(11); var _pdf_document_properties = __webpack_require__(13); var _pdf_find_bar = __webpack_require__(14); var _pdf_find_controller = __webpack_require__(15); var _pdf_history = __webpack_require__(17); var _pdf_layer_viewer = __webpack_require__(18); var _pdf_link_service = __webpack_require__(19); var _pdf_outline_viewer = __webpack_require__(20); var _pdf_presentation_mode = __webpack_require__(21); var _pdf_scripting_manager = __webpack_require__(22); var _pdf_sidebar = __webpack_require__(23); var _pdf_sidebar_resizer = __webpack_require__(24); var _pdf_thumbnail_viewer = __webpack_require__(25); var _pdf_viewer = __webpack_require__(27); var _secondary_toolbar = __webpack_require__(34); var _toolbar = __webpack_require__(36); var _viewer_compatibility = __webpack_require__(2); var _view_history = __webpack_require__(37); const DEFAULT_SCALE_DELTA = 1.1; const DISABLE_AUTO_FETCH_LOADING_BAR_TIMEOUT = 5000; const FORCE_PAGES_LOADED_TIMEOUT = 10000; const WHEEL_ZOOM_DISABLED_TIMEOUT = 1000; const ENABLE_PERMISSIONS_CLASS = "enablePermissions"; const ViewOnLoad = { UNKNOWN: -1, PREVIOUS: 0, INITIAL: 1 }; const ViewerCssTheme = { AUTOMATIC: 0, LIGHT: 1, DARK: 2 }; const KNOWN_VERSIONS = ["1.0", "1.1", "1.2", "1.3", "1.4", "1.5", "1.6", "1.7", "1.8", "1.9", "2.0", "2.1", "2.2", "2.3"]; const KNOWN_GENERATORS = ["acrobat distiller", "acrobat pdfwriter", "adobe livecycle", "adobe pdf library", "adobe photoshop", "ghostscript", "tcpdf", "cairo", "dvipdfm", "dvips", "pdftex", "pdfkit", "itext", "prince", "quarkxpress", "mac os x", "microsoft", "openoffice", "oracle", "luradocument", "pdf-xchange", "antenna house", "aspose.cells", "fpdf"]; class DefaultExternalServices { constructor() { throw new Error("Cannot initialize DefaultExternalServices."); } static updateFindControlState(data) {} static updateFindMatchesCount(data) {} static initPassiveLoading(callbacks) {} static async fallback(data) {} static reportTelemetry(data) {} static createDownloadManager(options) { throw new Error("Not implemented: createDownloadManager"); } static createPreferences() { throw new Error("Not implemented: createPreferences"); } static createL10n(options) { throw new Error("Not implemented: createL10n"); } static createScripting(options) { throw new Error("Not implemented: createScripting"); } static get supportsIntegratedFind() { return (0, _pdfjsLib.shadow)(this, "supportsIntegratedFind", false); } static get supportsDocumentFonts() { return (0, _pdfjsLib.shadow)(this, "supportsDocumentFonts", true); } static get supportedMouseWheelZoomModifierKeys() { return (0, _pdfjsLib.shadow)(this, "supportedMouseWheelZoomModifierKeys", { ctrlKey: true, metaKey: true }); } static get isInAutomation() { return (0, _pdfjsLib.shadow)(this, "isInAutomation", false); } } exports.DefaultExternalServices = DefaultExternalServices; const PDFViewerApplication = { initialBookmark: document.location.hash.substring(1), _initializedCapability: (0, _pdfjsLib.createPromiseCapability)(), fellback: false, appConfig: null, pdfDocument: null, pdfLoadingTask: null, printService: null, pdfViewer: null, pdfThumbnailViewer: null, pdfRenderingQueue: null, pdfPresentationMode: null, pdfDocumentProperties: null, pdfLinkService: null, pdfHistory: null, pdfSidebar: null, pdfSidebarResizer: null, pdfOutlineViewer: null, pdfAttachmentViewer: null, pdfLayerViewer: null, pdfCursorTools: null, pdfScriptingManager: null, store: null, downloadManager: null, overlayManager: null, preferences: null, toolbar: null, secondaryToolbar: null, eventBus: null, l10n: null, isInitialViewSet: false, downloadComplete: false, isViewerEmbedded: window.parent !== window, url: "", baseUrl: "", externalServices: DefaultExternalServices, _boundEvents: Object.create(null), documentInfo: null, metadata: null, _contentDispositionFilename: null, _contentLength: null, triggerDelayedFallback: null, _saveInProgress: false, _wheelUnusedTicks: 0, _idleCallbacks: new Set(), async initialize(appConfig) { this.preferences = this.externalServices.createPreferences(); this.appConfig = appConfig; await this._readPreferences(); await this._parseHashParameters(); this._forceCssTheme(); await this._initializeL10n(); if (this.isViewerEmbedded && _app_options.AppOptions.get("externalLinkTarget") === _pdfjsLib.LinkTarget.NONE) { _app_options.AppOptions.set("externalLinkTarget", _pdfjsLib.LinkTarget.TOP); } await this._initializeViewerComponents(); this.bindEvents(); this.bindWindowEvents(); const appContainer = appConfig.appContainer || document.documentElement; this.l10n.translate(appContainer).then(() => { this.eventBus.dispatch("localized", { source: this }); }); this._initializedCapability.resolve(); }, async _readPreferences() { if (_app_options.AppOptions.get("disablePreferences")) { return; } try { _app_options.AppOptions.setAll(await this.preferences.getAll()); } catch (reason) { console.error(`_readPreferences: "${reason?.message}".`); } }, async _parseHashParameters() { if (!_app_options.AppOptions.get("pdfBugEnabled")) { return undefined; } const hash = document.location.hash.substring(1); if (!hash) { return undefined; } const hashParams = (0, _ui_utils.parseQueryString)(hash), waitOn = []; if ("disableworker" in hashParams && hashParams.disableworker === "true") { waitOn.push(loadFakeWorker()); } if ("disablerange" in hashParams) { _app_options.AppOptions.set("disableRange", hashParams.disablerange === "true"); } if ("disablestream" in hashParams) { _app_options.AppOptions.set("disableStream", hashParams.disablestream === "true"); } if ("disableautofetch" in hashParams) { _app_options.AppOptions.set("disableAutoFetch", hashParams.disableautofetch === "true"); } if ("disablefontface" in hashParams) { _app_options.AppOptions.set("disableFontFace", hashParams.disablefontface === "true"); } if ("disablehistory" in hashParams) { _app_options.AppOptions.set("disableHistory", hashParams.disablehistory === "true"); } if ("webgl" in hashParams) { _app_options.AppOptions.set("enableWebGL", hashParams.webgl === "true"); } if ("verbosity" in hashParams) { _app_options.AppOptions.set("verbosity", hashParams.verbosity | 0); } if ("textlayer" in hashParams) { switch (hashParams.textlayer) { case "off": _app_options.AppOptions.set("textLayerMode", _ui_utils.TextLayerMode.DISABLE); break; case "visible": case "shadow": case "hover": const viewer = this.appConfig.viewerContainer; viewer.classList.add("textLayer-" + hashParams.textlayer); break; } } if ("pdfbug" in hashParams) { _app_options.AppOptions.set("pdfBug", true); _app_options.AppOptions.set("fontExtraProperties", true); const enabled = hashParams.pdfbug.split(","); waitOn.push(loadAndEnablePDFBug(enabled)); } if ("locale" in hashParams) { _app_options.AppOptions.set("locale", hashParams.locale); } if (waitOn.length === 0) { return undefined; } return Promise.all(waitOn).catch(reason => { console.error(`_parseHashParameters: "${reason.message}".`); }); }, async _initializeL10n() { this.l10n = this.externalServices.createL10n({ locale: _app_options.AppOptions.get("locale") }); const dir = await this.l10n.getDirection(); document.getElementsByTagName("html")[0].dir = dir; }, _forceCssTheme() { const cssTheme = _app_options.AppOptions.get("viewerCssTheme"); if (cssTheme === ViewerCssTheme.AUTOMATIC || !Object.values(ViewerCssTheme).includes(cssTheme)) { return; } try { const styleSheet = document.styleSheets[0]; const cssRules = styleSheet?.cssRules || []; for (let i = 0, ii = cssRules.length; i < ii; i++) { const rule = cssRules[i]; if (rule instanceof CSSMediaRule && rule.media?.[0] === "(prefers-color-scheme: dark)") { if (cssTheme === ViewerCssTheme.LIGHT) { styleSheet.deleteRule(i); return; } const darkRules = /^@media \(prefers-color-scheme: dark\) {\n\s*([\w\s-.,:;/\\{}()]+)\n}$/.exec(rule.cssText); if (darkRules?.[1]) { styleSheet.deleteRule(i); styleSheet.insertRule(darkRules[1], i); } return; } } } catch (reason) { console.error(`_forceCssTheme: "${reason?.message}".`); } }, async _initializeViewerComponents() { const appConfig = this.appConfig; const eventBus = appConfig.eventBus || new _ui_utils.EventBus({ isInAutomation: this.externalServices.isInAutomation }); this.eventBus = eventBus; this.overlayManager = new _overlay_manager.OverlayManager(); const pdfRenderingQueue = new _pdf_rendering_queue.PDFRenderingQueue(); pdfRenderingQueue.onIdle = this._cleanup.bind(this); this.pdfRenderingQueue = pdfRenderingQueue; const pdfLinkService = new _pdf_link_service.PDFLinkService({ eventBus, externalLinkTarget: _app_options.AppOptions.get("externalLinkTarget"), externalLinkRel: _app_options.AppOptions.get("externalLinkRel"), ignoreDestinationZoom: _app_options.AppOptions.get("ignoreDestinationZoom") }); this.pdfLinkService = pdfLinkService; const downloadManager = this.externalServices.createDownloadManager(); this.downloadManager = downloadManager; const findController = new _pdf_find_controller.PDFFindController({ linkService: pdfLinkService, eventBus }); this.findController = findController; const pdfScriptingManager = new _pdf_scripting_manager.PDFScriptingManager({ eventBus, sandboxBundleSrc: _app_options.AppOptions.get("sandboxBundleSrc"), scriptingFactory: this.externalServices, docPropertiesLookup: this._scriptingDocProperties.bind(this) }); this.pdfScriptingManager = pdfScriptingManager; const container = appConfig.mainContainer; const viewer = appConfig.viewerContainer; this.pdfViewer = new _pdf_viewer.PDFViewer({ container, viewer, eventBus, renderingQueue: pdfRenderingQueue, linkService: pdfLinkService, downloadManager, findController, scriptingManager: pdfScriptingManager, renderer: _app_options.AppOptions.get("renderer"), enableWebGL: _app_options.AppOptions.get("enableWebGL"), l10n: this.l10n, textLayerMode: _app_options.AppOptions.get("textLayerMode"), imageResourcesPath: _app_options.AppOptions.get("imageResourcesPath"), renderInteractiveForms: _app_options.AppOptions.get("renderInteractiveForms"), enablePrintAutoRotate: _app_options.AppOptions.get("enablePrintAutoRotate"), useOnlyCssZoom: _app_options.AppOptions.get("useOnlyCssZoom"), maxCanvasPixels: _app_options.AppOptions.get("maxCanvasPixels"), enableScripting: _app_options.AppOptions.get("enableScripting") }); pdfRenderingQueue.setViewer(this.pdfViewer); pdfLinkService.setViewer(this.pdfViewer); pdfScriptingManager.setViewer(this.pdfViewer); this.pdfThumbnailViewer = new _pdf_thumbnail_viewer.PDFThumbnailViewer({ container: appConfig.sidebar.thumbnailView, eventBus, renderingQueue: pdfRenderingQueue, linkService: pdfLinkService, l10n: this.l10n }); pdfRenderingQueue.setThumbnailViewer(this.pdfThumbnailViewer); this.pdfHistory = new _pdf_history.PDFHistory({ linkService: pdfLinkService, eventBus }); pdfLinkService.setHistory(this.pdfHistory); if (!this.supportsIntegratedFind) { this.findBar = new _pdf_find_bar.PDFFindBar(appConfig.findBar, eventBus, this.l10n); } this.pdfDocumentProperties = new _pdf_document_properties.PDFDocumentProperties(appConfig.documentProperties, this.overlayManager, eventBus, this.l10n); this.pdfCursorTools = new _pdf_cursor_tools.PDFCursorTools({ container, eventBus, cursorToolOnLoad: _app_options.AppOptions.get("cursorToolOnLoad") }); this.toolbar = new _toolbar.Toolbar(appConfig.toolbar, eventBus, this.l10n); this.secondaryToolbar = new _secondary_toolbar.SecondaryToolbar(appConfig.secondaryToolbar, container, eventBus); if (this.supportsFullscreen) { this.pdfPresentationMode = new _pdf_presentation_mode.PDFPresentationMode({ container, pdfViewer: this.pdfViewer, eventBus }); } this.passwordPrompt = new _password_prompt.PasswordPrompt(appConfig.passwordOverlay, this.overlayManager, this.l10n, this.isViewerEmbedded); this.pdfOutlineViewer = new _pdf_outline_viewer.PDFOutlineViewer({ container: appConfig.sidebar.outlineView, eventBus, linkService: pdfLinkService }); this.pdfAttachmentViewer = new _pdf_attachment_viewer.PDFAttachmentViewer({ container: appConfig.sidebar.attachmentsView, eventBus, downloadManager }); this.pdfLayerViewer = new _pdf_layer_viewer.PDFLayerViewer({ container: appConfig.sidebar.layersView, eventBus, l10n: this.l10n }); this.pdfSidebar = new _pdf_sidebar.PDFSidebar({ elements: appConfig.sidebar, pdfViewer: this.pdfViewer, pdfThumbnailViewer: this.pdfThumbnailViewer, eventBus, l10n: this.l10n }); this.pdfSidebar.onToggled = this.forceRendering.bind(this); this.pdfSidebarResizer = new _pdf_sidebar_resizer.PDFSidebarResizer(appConfig.sidebarResizer, eventBus, this.l10n); }, run(config) { this.initialize(config).then(webViewerInitialized); }, get initialized() { return this._initializedCapability.settled; }, get initializedPromise() { return this._initializedCapability.promise; }, zoomIn(ticks) { if (this.pdfViewer.isInPresentationMode) { return; } let newScale = this.pdfViewer.currentScale; do { newScale = (newScale * DEFAULT_SCALE_DELTA).toFixed(2); newScale = Math.ceil(newScale * 10) / 10; newScale = Math.min(_ui_utils.MAX_SCALE, newScale); } while (--ticks > 0 && newScale < _ui_utils.MAX_SCALE); this.pdfViewer.currentScaleValue = newScale; }, zoomOut(ticks) { if (this.pdfViewer.isInPresentationMode) { return; } let newScale = this.pdfViewer.currentScale; do { newScale = (newScale / DEFAULT_SCALE_DELTA).toFixed(2); newScale = Math.floor(newScale * 10) / 10; newScale = Math.max(_ui_utils.MIN_SCALE, newScale); } while (--ticks > 0 && newScale > _ui_utils.MIN_SCALE); this.pdfViewer.currentScaleValue = newScale; }, zoomReset() { if (this.pdfViewer.isInPresentationMode) { return; } this.pdfViewer.currentScaleValue = _ui_utils.DEFAULT_SCALE_VALUE; }, get pagesCount() { return this.pdfDocument ? this.pdfDocument.numPages : 0; }, get page() { return this.pdfViewer.currentPageNumber; }, set page(val) { this.pdfViewer.currentPageNumber = val; }, get supportsPrinting() { return PDFPrintServiceFactory.instance.supportsPrinting; }, get supportsFullscreen() { const doc = document.documentElement; let support = !!(doc.requestFullscreen || doc.mozRequestFullScreen || doc.webkitRequestFullScreen); if (document.fullscreenEnabled === false || document.mozFullScreenEnabled === false || document.webkitFullscreenEnabled === false) { support = false; } return (0, _pdfjsLib.shadow)(this, "supportsFullscreen", support); }, get supportsIntegratedFind() { return this.externalServices.supportsIntegratedFind; }, get supportsDocumentFonts() { return this.externalServices.supportsDocumentFonts; }, get loadingBar() { const bar = new _ui_utils.ProgressBar("#loadingBar"); return (0, _pdfjsLib.shadow)(this, "loadingBar", bar); }, get supportedMouseWheelZoomModifierKeys() { return this.externalServices.supportedMouseWheelZoomModifierKeys; }, initPassiveLoading() { throw new Error("Not implemented: initPassiveLoading"); }, setTitleUsingUrl(url = "") { this.url = url; this.baseUrl = url.split("#")[0]; let title = (0, _pdfjsLib.getPdfFilenameFromUrl)(url, ""); if (!title) { try { title = decodeURIComponent((0, _pdfjsLib.getFilenameFromUrl)(url)) || url; } catch (ex) { title = url; } } this.setTitle(title); }, setTitle(title) { if (this.isViewerEmbedded) { return; } document.title = title; }, get _docFilename() { return this._contentDispositionFilename || (0, _pdfjsLib.getPdfFilenameFromUrl)(this.url); }, _cancelIdleCallbacks() { if (!this._idleCallbacks.size) { return; } for (const callback of this._idleCallbacks) { window.cancelIdleCallback(callback); } this._idleCallbacks.clear(); }, async close() { this._unblockDocumentLoadEvent(); const { container } = this.appConfig.errorWrapper; container.hidden = true; if (!this.pdfLoadingTask) { return; } if (this.pdfDocument?.annotationStorage.size > 0 && this._annotationStorageModified) { try { await this.save({ sourceEventType: "save" }); } catch (reason) {} } const promises = []; promises.push(this.pdfLoadingTask.destroy()); this.pdfLoadingTask = null; if (this.pdfDocument) { this.pdfDocument = null; this.pdfThumbnailViewer.setDocument(null); this.pdfViewer.setDocument(null); this.pdfLinkService.setDocument(null); this.pdfDocumentProperties.setDocument(null); } webViewerResetPermissions(); this.store = null; this.isInitialViewSet = false; this.downloadComplete = false; this.url = ""; this.baseUrl = ""; this.documentInfo = null; this.metadata = null; this._contentDispositionFilename = null; this._contentLength = null; this.triggerDelayedFallback = null; this._saveInProgress = false; this._cancelIdleCallbacks(); promises.push(this.pdfScriptingManager.destroyPromise); this.pdfSidebar.reset(); this.pdfOutlineViewer.reset(); this.pdfAttachmentViewer.reset(); this.pdfLayerViewer.reset(); if (this.pdfHistory) { this.pdfHistory.reset(); } if (this.findBar) { this.findBar.reset(); } this.toolbar.reset(); this.secondaryToolbar.reset(); if (typeof PDFBug !== "undefined") { PDFBug.cleanup(); } await Promise.all(promises); }, async open(file, args) { if (this.pdfLoadingTask) { await this.close(); } const workerParameters = _app_options.AppOptions.getAll(_app_options.OptionKind.WORKER); for (const key in workerParameters) { _pdfjsLib.GlobalWorkerOptions[key] = workerParameters[key]; } const parameters = Object.create(null); if (typeof file === "string") { this.setTitleUsingUrl(file); parameters.url = file; } else if (file && "byteLength" in file) { parameters.data = file; } else if (file.url && file.originalUrl) { this.setTitleUsingUrl(file.originalUrl); parameters.url = file.url; } const apiParameters = _app_options.AppOptions.getAll(_app_options.OptionKind.API); for (const key in apiParameters) { let value = apiParameters[key]; if (key === "docBaseUrl" && !value) {} parameters[key] = value; } if (args) { for (const key in args) { parameters[key] = args[key]; } } const loadingTask = (0, _pdfjsLib.getDocument)(parameters); this.pdfLoadingTask = loadingTask; loadingTask.onPassword = (updateCallback, reason) => { this.pdfLinkService.externalLinkEnabled = false; this.passwordPrompt.setUpdateCallback(updateCallback, reason); this.passwordPrompt.open(); }; loadingTask.onProgress = ({ loaded, total }) => { this.progress(loaded / total); }; loadingTask.onUnsupportedFeature = this.fallback.bind(this); return loadingTask.promise.then(pdfDocument => { this.load(pdfDocument); }, exception => { if (loadingTask !== this.pdfLoadingTask) { return undefined; } let key = "loading_error"; if (exception instanceof _pdfjsLib.InvalidPDFException) { key = "invalid_file_error"; } else if (exception instanceof _pdfjsLib.MissingPDFException) { key = "missing_file_error"; } else if (exception instanceof _pdfjsLib.UnexpectedResponseException) { key = "unexpected_response_error"; } return this.l10n.get(key).then(msg => { this._documentError(msg, { message: exception?.message }); throw exception; }); }); }, _ensureDownloadComplete() { if (this.pdfDocument && this.downloadComplete) { return; } throw new Error("PDF document not downloaded."); }, async download({ sourceEventType = "download" } = {}) { const url = this.baseUrl, filename = this._docFilename; try { this._ensureDownloadComplete(); const data = await this.pdfDocument.getData(); const blob = new Blob([data], { type: "application/pdf" }); await this.downloadManager.download(blob, url, filename, sourceEventType); } catch (reason) { await this.downloadManager.downloadUrl(url, filename); } }, async save({ sourceEventType = "download" } = {}) { if (this._saveInProgress) { return; } this._saveInProgress = true; await this.pdfScriptingManager.dispatchWillSave(); const url = this.baseUrl, filename = this._docFilename; try { this._ensureDownloadComplete(); const data = await this.pdfDocument.saveDocument(this.pdfDocument.annotationStorage); const blob = new Blob([data], { type: "application/pdf" }); await this.downloadManager.download(blob, url, filename, sourceEventType); } catch (reason) { await this.download({ sourceEventType }); } finally { await this.pdfScriptingManager.dispatchDidSave(); this._saveInProgress = false; } }, downloadOrSave(options) { if (this.pdfDocument?.annotationStorage.size > 0) { this.save(options); } else { this.download(options); } }, _delayedFallback(featureId) { this.externalServices.reportTelemetry({ type: "unsupportedFeature", featureId }); if (!this.triggerDelayedFallback) { this.triggerDelayedFallback = () => { this.fallback(featureId); this.triggerDelayedFallback = null; }; } }, fallback(featureId) { this.externalServices.reportTelemetry({ type: "unsupportedFeature", featureId }); switch (featureId) { case _pdfjsLib.UNSUPPORTED_FEATURES.errorFontLoadNative: case _pdfjsLib.UNSUPPORTED_FEATURES.errorFontMissing: return; } if (this.fellback) { return; } this.fellback = true; this.externalServices.fallback({ featureId, url: this.baseUrl }).then(download => { if (!download) { return; } this.download({ sourceEventType: "download" }); }); }, _documentError(message, moreInfo = null) { this._unblockDocumentLoadEvent(); this._otherError(message, moreInfo); }, _otherError(message, moreInfo = null) { const moreInfoText = [this.l10n.get("error_version_info", { version: _pdfjsLib.version || "?", build: _pdfjsLib.build || "?" })]; if (moreInfo) { moreInfoText.push(this.l10n.get("error_message", { message: moreInfo.message })); if (moreInfo.stack) { moreInfoText.push(this.l10n.get("error_stack", { stack: moreInfo.stack })); } else { if (moreInfo.filename) { moreInfoText.push(this.l10n.get("error_file", { file: moreInfo.filename })); } if (moreInfo.lineNumber) { moreInfoText.push(this.l10n.get("error_line", { line: moreInfo.lineNumber })); } } } const errorWrapperConfig = this.appConfig.errorWrapper; const errorWrapper = errorWrapperConfig.container; errorWrapper.hidden = false; const errorMessage = errorWrapperConfig.errorMessage; errorMessage.textContent = message; const closeButton = errorWrapperConfig.closeButton; closeButton.onclick = function () { errorWrapper.hidden = true; }; const errorMoreInfo = errorWrapperConfig.errorMoreInfo; const moreInfoButton = errorWrapperConfig.moreInfoButton; const lessInfoButton = errorWrapperConfig.lessInfoButton; moreInfoButton.onclick = function () { errorMoreInfo.hidden = false; moreInfoButton.hidden = true; lessInfoButton.hidden = false; errorMoreInfo.style.height = errorMoreInfo.scrollHeight + "px"; }; lessInfoButton.onclick = function () { errorMoreInfo.hidden = true; moreInfoButton.hidden = false; lessInfoButton.hidden = true; }; moreInfoButton.oncontextmenu = _ui_utils.noContextMenuHandler; lessInfoButton.oncontextmenu = _ui_utils.noContextMenuHandler; closeButton.oncontextmenu = _ui_utils.noContextMenuHandler; moreInfoButton.hidden = false; lessInfoButton.hidden = true; Promise.all(moreInfoText).then(parts => { errorMoreInfo.value = parts.join("\n"); }); }, progress(level) { if (this.downloadComplete) { return; } const percent = Math.round(level * 100); if (percent > this.loadingBar.percent || isNaN(percent)) { this.loadingBar.percent = percent; const disableAutoFetch = this.pdfDocument ? this.pdfDocument.loadingParams.disableAutoFetch : _app_options.AppOptions.get("disableAutoFetch"); if (disableAutoFetch && percent) { if (this.disableAutoFetchLoadingBarTimeout) { clearTimeout(this.disableAutoFetchLoadingBarTimeout); this.disableAutoFetchLoadingBarTimeout = null; } this.loadingBar.show(); this.disableAutoFetchLoadingBarTimeout = setTimeout(() => { this.loadingBar.hide(); this.disableAutoFetchLoadingBarTimeout = null; }, DISABLE_AUTO_FETCH_LOADING_BAR_TIMEOUT); } } }, load(pdfDocument) { this.pdfDocument = pdfDocument; pdfDocument.getDownloadInfo().then(({ length }) => { this._contentLength = length; this.downloadComplete = true; this.loadingBar.hide(); firstPagePromise.then(() => { this.eventBus.dispatch("documentloaded", { source: this }); }); }); const pageLayoutPromise = pdfDocument.getPageLayout().catch(function () {}); const pageModePromise = pdfDocument.getPageMode().catch(function () {}); const openActionPromise = pdfDocument.getOpenAction().catch(function () {}); this.toolbar.setPagesCount(pdfDocument.numPages, false); this.secondaryToolbar.setPagesCount(pdfDocument.numPages); let baseDocumentUrl; baseDocumentUrl = null; this.pdfLinkService.setDocument(pdfDocument, baseDocumentUrl); this.pdfDocumentProperties.setDocument(pdfDocument, this.url); const pdfViewer = this.pdfViewer; pdfViewer.setDocument(pdfDocument); const { firstPagePromise, onePageRendered, pagesPromise } = pdfViewer; const pdfThumbnailViewer = this.pdfThumbnailViewer; pdfThumbnailViewer.setDocument(pdfDocument); const storedPromise = (this.store = new _view_history.ViewHistory(pdfDocument.fingerprint)).getMultiple({ page: null, zoom: _ui_utils.DEFAULT_SCALE_VALUE, scrollLeft: "0", scrollTop: "0", rotation: null, sidebarView: _ui_utils.SidebarView.UNKNOWN, scrollMode: _ui_utils.ScrollMode.UNKNOWN, spreadMode: _ui_utils.SpreadMode.UNKNOWN }).catch(() => { return Object.create(null); }); firstPagePromise.then(pdfPage => { this.loadingBar.setWidth(this.appConfig.viewerContainer); this._initializeAnnotationStorageCallbacks(pdfDocument); Promise.all([_ui_utils.animationStarted, storedPromise, pageLayoutPromise, pageModePromise, openActionPromise]).then(async ([timeStamp, stored, pageLayout, pageMode, openAction]) => { const viewOnLoad = _app_options.AppOptions.get("viewOnLoad"); this._initializePdfHistory({ fingerprint: pdfDocument.fingerprint, viewOnLoad, initialDest: openAction?.dest }); const initialBookmark = this.initialBookmark; const zoom = _app_options.AppOptions.get("defaultZoomValue"); let hash = zoom ? `zoom=${zoom}` : null; let rotation = null; let sidebarView = _app_options.AppOptions.get("sidebarViewOnLoad"); let scrollMode = _app_options.AppOptions.get("scrollModeOnLoad"); let spreadMode = _app_options.AppOptions.get("spreadModeOnLoad"); if (stored.page && viewOnLoad !== ViewOnLoad.INITIAL) { hash = `page=${stored.page}&zoom=${zoom || stored.zoom},` + `${stored.scrollLeft},${stored.scrollTop}`; rotation = parseInt(stored.rotation, 10); if (sidebarView === _ui_utils.SidebarView.UNKNOWN) { sidebarView = stored.sidebarView | 0; } if (scrollMode === _ui_utils.ScrollMode.UNKNOWN) { scrollMode = stored.scrollMode | 0; } if (spreadMode === _ui_utils.SpreadMode.UNKNOWN) { spreadMode = stored.spreadMode | 0; } } if (pageMode && sidebarView === _ui_utils.SidebarView.UNKNOWN) { sidebarView = (0, _ui_utils.apiPageModeToSidebarView)(pageMode); } if (pageLayout && spreadMode === _ui_utils.SpreadMode.UNKNOWN) { spreadMode = (0, _ui_utils.apiPageLayoutToSpreadMode)(pageLayout); } this.setInitialView(hash, { rotation, sidebarView, scrollMode, spreadMode }); this.eventBus.dispatch("documentinit", { source: this }); if (!this.isViewerEmbedded) { pdfViewer.focus(); } this._initializePermissions(pdfDocument); await Promise.race([pagesPromise, new Promise(resolve => { setTimeout(resolve, FORCE_PAGES_LOADED_TIMEOUT); })]); if (!initialBookmark && !hash) { return; } if (pdfViewer.hasEqualPageSizes) { return; } this.initialBookmark = initialBookmark; pdfViewer.currentScaleValue = pdfViewer.currentScaleValue; this.setInitialView(hash); }).catch(() => { this.setInitialView(); }).then(function () { pdfViewer.update(); }); }); pagesPromise.then(() => { this._unblockDocumentLoadEvent(); this._initializeAutoPrint(pdfDocument, openActionPromise); }); onePageRendered.then(() => { pdfDocument.getOutline().then(outline => { this.pdfOutlineViewer.render({ outline, pdfDocument }); }); pdfDocument.getAttachments().then(attachments => { this.pdfAttachmentViewer.render({ attachments }); }); pdfViewer.optionalContentConfigPromise.then(optionalContentConfig => { this.pdfLayerViewer.render({ optionalContentConfig, pdfDocument }); }); if ("requestIdleCallback" in window) { const callback = window.requestIdleCallback(() => { this._collectTelemetry(pdfDocument); this._idleCallbacks.delete(callback); }, { timeout: 1000 }); this._idleCallbacks.add(callback); } }); this._initializePageLabels(pdfDocument); this._initializeMetadata(pdfDocument); }, async _scriptingDocProperties(pdfDocument) { if (!this.documentInfo) { await new Promise(resolve => { this.eventBus._on("metadataloaded", resolve, { once: true }); }); if (pdfDocument !== this.pdfDocument) { return null; } } if (!this._contentLength) { await new Promise(resolve => { this.eventBus._on("documentloaded", resolve, { once: true }); }); if (pdfDocument !== this.pdfDocument) { return null; } } return { ...this.documentInfo, baseURL: this.baseUrl, filesize: this._contentLength, filename: this._docFilename, metadata: this.metadata?.getRaw(), authors: this.metadata?.get("dc:creator"), numPages: this.pagesCount, URL: this.url }; }, async _collectTelemetry(pdfDocument) { const markInfo = await this.pdfDocument.getMarkInfo(); if (pdfDocument !== this.pdfDocument) { return; } const tagged = markInfo?.Marked || false; this.externalServices.reportTelemetry({ type: "tagged", tagged }); }, async _initializeAutoPrint(pdfDocument, openActionPromise) { const [openAction, javaScript] = await Promise.all([openActionPromise, !this.pdfViewer.enableScripting ? pdfDocument.getJavaScript() : null]); if (pdfDocument !== this.pdfDocument) { return; } let triggerAutoPrint = false; if (openAction?.action === "Print") { triggerAutoPrint = true; } if (javaScript) { javaScript.some(js => { if (!js) { return false; } console.warn("Warning: JavaScript is not supported"); this._delayedFallback(_pdfjsLib.UNSUPPORTED_FEATURES.javaScript); return true; }); if (!triggerAutoPrint) { for (const js of javaScript) { if (js && _ui_utils.AutoPrintRegExp.test(js)) { triggerAutoPrint = true; break; } } } } if (triggerAutoPrint) { this.triggerPrinting(); } }, async _initializeMetadata(pdfDocument) { const { info, metadata, contentDispositionFilename, contentLength } = await pdfDocument.getMetadata(); if (pdfDocument !== this.pdfDocument) { return; } this.documentInfo = info; this.metadata = metadata; this._contentDispositionFilename ?? (this._contentDispositionFilename = contentDispositionFilename); this._contentLength ?? (this._contentLength = contentLength); console.log(`PDF ${pdfDocument.fingerprint} [${info.PDFFormatVersion} ` + `${(info.Producer || "-").trim()} / ${(info.Creator || "-").trim()}] ` + `(PDF.js: ${_pdfjsLib.version || "-"}` + `${this.pdfViewer.enableWebGL ? " [WebGL]" : ""})`); let pdfTitle = info?.Title; const metadataTitle = metadata?.get("dc:title"); if (metadataTitle) { if (metadataTitle !== "Untitled" && !/[\uFFF0-\uFFFF]/g.test(metadataTitle)) { pdfTitle = metadataTitle; } } if (pdfTitle) { this.setTitle(`${pdfTitle} - ${contentDispositionFilename || document.title}`); } else if (contentDispositionFilename) { this.setTitle(contentDispositionFilename); } if (info.IsXFAPresent && !info.IsAcroFormPresent && !pdfDocument.isPureXfa) { console.warn("Warning: XFA is not supported"); this._delayedFallback(_pdfjsLib.UNSUPPORTED_FEATURES.forms); } else if ((info.IsAcroFormPresent || info.IsXFAPresent) && !this.pdfViewer.renderInteractiveForms) { console.warn("Warning: Interactive form support is not enabled"); this._delayedFallback(_pdfjsLib.UNSUPPORTED_FEATURES.forms); } let versionId = "other"; if (KNOWN_VERSIONS.includes(info.PDFFormatVersion)) { versionId = `v${info.PDFFormatVersion.replace(".", "_")}`; } let generatorId = "other"; if (info.Producer) { const producer = info.Producer.toLowerCase(); KNOWN_GENERATORS.some(function (generator) { if (!producer.includes(generator)) { return false; } generatorId = generator.replace(/[ .-]/g, "_"); return true; }); } let formType = null; if (info.IsXFAPresent) { formType = "xfa"; } else if (info.IsAcroFormPresent) { formType = "acroform"; } this.externalServices.reportTelemetry({ type: "documentInfo", version: versionId, generator: generatorId, formType }); this.eventBus.dispatch("metadataloaded", { source: this }); }, async _initializePageLabels(pdfDocument) { const labels = await pdfDocument.getPageLabels(); if (pdfDocument !== this.pdfDocument) { return; } if (!labels || _app_options.AppOptions.get("disablePageLabels")) { return; } const numLabels = labels.length; if (numLabels !== this.pagesCount) { console.error("The number of Page Labels does not match the number of pages in the document."); return; } let i = 0; while (i < numLabels && labels[i] === (i + 1).toString()) { i++; } if (i === numLabels) { return; } const { pdfViewer, pdfThumbnailViewer, toolbar } = this; pdfViewer.setPageLabels(labels); pdfThumbnailViewer.setPageLabels(labels); toolbar.setPagesCount(numLabels, true); toolbar.setPageNumber(pdfViewer.currentPageNumber, pdfViewer.currentPageLabel); }, _initializePdfHistory({ fingerprint, viewOnLoad, initialDest = null }) { if (this.isViewerEmbedded || _app_options.AppOptions.get("disableHistory")) { return; } this.pdfHistory.initialize({ fingerprint, resetHistory: viewOnLoad === ViewOnLoad.INITIAL, updateUrl: _app_options.AppOptions.get("historyUpdateUrl") }); if (this.pdfHistory.initialBookmark) { this.initialBookmark = this.pdfHistory.initialBookmark; this.initialRotation = this.pdfHistory.initialRotation; } if (initialDest && !this.initialBookmark && viewOnLoad === ViewOnLoad.UNKNOWN) { this.initialBookmark = JSON.stringify(initialDest); this.pdfHistory.push({ explicitDest: initialDest, pageNumber: null }); } }, async _initializePermissions(pdfDocument) { const permissions = await pdfDocument.getPermissions(); if (pdfDocument !== this.pdfDocument) { return; } if (!permissions || !_app_options.AppOptions.get("enablePermissions")) { return; } if (!permissions.includes(_pdfjsLib.PermissionFlag.COPY)) { this.appConfig.viewerContainer.classList.add(ENABLE_PERMISSIONS_CLASS); } }, _initializeAnnotationStorageCallbacks(pdfDocument) { if (pdfDocument !== this.pdfDocument) { return; } const { annotationStorage } = pdfDocument; annotationStorage.onSetModified = () => { window.addEventListener("beforeunload", beforeUnload); this._annotationStorageModified = true; }; annotationStorage.onResetModified = () => { window.removeEventListener("beforeunload", beforeUnload); delete this._annotationStorageModified; }; }, setInitialView(storedHash, { rotation, sidebarView, scrollMode, spreadMode } = {}) { const setRotation = angle => { if ((0, _ui_utils.isValidRotation)(angle)) { this.pdfViewer.pagesRotation = angle; } }; const setViewerModes = (scroll, spread) => { if ((0, _ui_utils.isValidScrollMode)(scroll)) { this.pdfViewer.scrollMode = scroll; } if ((0, _ui_utils.isValidSpreadMode)(spread)) { this.pdfViewer.spreadMode = spread; } }; this.isInitialViewSet = true; this.pdfSidebar.setInitialView(sidebarView); setViewerModes(scrollMode, spreadMode); if (this.initialBookmark) { setRotation(this.initialRotation); delete this.initialRotation; this.pdfLinkService.setHash(this.initialBookmark); this.initialBookmark = null; } else if (storedHash) { setRotation(rotation); this.pdfLinkService.setHash(storedHash); } this.toolbar.setPageNumber(this.pdfViewer.currentPageNumber, this.pdfViewer.currentPageLabel); this.secondaryToolbar.setPageNumber(this.pdfViewer.currentPageNumber); if (!this.pdfViewer.currentScaleValue) { this.pdfViewer.currentScaleValue = _ui_utils.DEFAULT_SCALE_VALUE; } }, _cleanup() { if (!this.pdfDocument) { return; } this.pdfViewer.cleanup(); this.pdfThumbnailViewer.cleanup(); this.pdfDocument.cleanup(this.pdfViewer.renderer === _ui_utils.RendererType.SVG); }, forceRendering() { this.pdfRenderingQueue.printing = !!this.printService; this.pdfRenderingQueue.isThumbnailViewEnabled = this.pdfSidebar.isThumbnailViewVisible; this.pdfRenderingQueue.renderHighestPriority(); }, beforePrint() { this.pdfScriptingManager.dispatchWillPrint(); if (this.printService) { return; } if (!this.supportsPrinting) { this.l10n.get("printing_not_supported").then(msg => { this._otherError(msg); }); return; } if (!this.pdfViewer.pageViewsReady) { this.l10n.get("printing_not_ready").then(msg => { window.alert(msg); }); return; } const pagesOverview = this.pdfViewer.getPagesOverview(); const printContainer = this.appConfig.printContainer; const printResolution = _app_options.AppOptions.get("printResolution"); const optionalContentConfigPromise = this.pdfViewer.optionalContentConfigPromise; const printService = PDFPrintServiceFactory.instance.createPrintService(this.pdfDocument, pagesOverview, printContainer, printResolution, optionalContentConfigPromise, this.l10n); this.printService = printService; this.forceRendering(); printService.layout(); this.externalServices.reportTelemetry({ type: "print" }); }, afterPrint() { this.pdfScriptingManager.dispatchDidPrint(); if (this.printService) { this.printService.destroy(); this.printService = null; if (this.pdfDocument) { this.pdfDocument.annotationStorage.resetModified(); } } this.forceRendering(); }, rotatePages(delta) { this.pdfViewer.pagesRotation += delta; }, requestPresentationMode() { if (!this.pdfPresentationMode) { return; } this.pdfPresentationMode.request(); }, triggerPrinting() { if (!this.supportsPrinting) { return; } window.print(); }, bindEvents() { const { eventBus, _boundEvents } = this; _boundEvents.beforePrint = this.beforePrint.bind(this); _boundEvents.afterPrint = this.afterPrint.bind(this); eventBus._on("resize", webViewerResize); eventBus._on("hashchange", webViewerHashchange); eventBus._on("beforeprint", _boundEvents.beforePrint); eventBus._on("afterprint", _boundEvents.afterPrint); eventBus._on("pagerendered", webViewerPageRendered); eventBus._on("updateviewarea", webViewerUpdateViewarea); eventBus._on("pagechanging", webViewerPageChanging); eventBus._on("scalechanging", webViewerScaleChanging); eventBus._on("rotationchanging", webViewerRotationChanging); eventBus._on("sidebarviewchanged", webViewerSidebarViewChanged); eventBus._on("pagemode", webViewerPageMode); eventBus._on("namedaction", webViewerNamedAction); eventBus._on("presentationmodechanged", webViewerPresentationModeChanged); eventBus._on("presentationmode", webViewerPresentationMode); eventBus._on("print", webViewerPrint); eventBus._on("download", webViewerDownload); eventBus._on("save", webViewerSave); eventBus._on("firstpage", webViewerFirstPage); eventBus._on("lastpage", webViewerLastPage); eventBus._on("nextpage", webViewerNextPage); eventBus._on("previouspage", webViewerPreviousPage); eventBus._on("zoomin", webViewerZoomIn); eventBus._on("zoomout", webViewerZoomOut); eventBus._on("zoomreset", webViewerZoomReset); eventBus._on("pagenumberchanged", webViewerPageNumberChanged); eventBus._on("scalechanged", webViewerScaleChanged); eventBus._on("rotatecw", webViewerRotateCw); eventBus._on("rotateccw", webViewerRotateCcw); eventBus._on("optionalcontentconfig", webViewerOptionalContentConfig); eventBus._on("switchscrollmode", webViewerSwitchScrollMode); eventBus._on("scrollmodechanged", webViewerScrollModeChanged); eventBus._on("switchspreadmode", webViewerSwitchSpreadMode); eventBus._on("spreadmodechanged", webViewerSpreadModeChanged); eventBus._on("documentproperties", webViewerDocumentProperties); eventBus._on("find", webViewerFind); eventBus._on("findfromurlhash", webViewerFindFromUrlHash); eventBus._on("updatefindmatchescount", webViewerUpdateFindMatchesCount); eventBus._on("updatefindcontrolstate", webViewerUpdateFindControlState); if (_app_options.AppOptions.get("pdfBug")) { _boundEvents.reportPageStatsPDFBug = reportPageStatsPDFBug; eventBus._on("pagerendered", _boundEvents.reportPageStatsPDFBug); eventBus._on("pagechanging", _boundEvents.reportPageStatsPDFBug); } eventBus._on("fileinputchange", webViewerFileInputChange); eventBus._on("openfile", webViewerOpenFile); }, bindWindowEvents() { const { eventBus, _boundEvents } = this; _boundEvents.windowResize = () => { eventBus.dispatch("resize", { source: window }); }; _boundEvents.windowHashChange = () => { eventBus.dispatch("hashchange", { source: window, hash: document.location.hash.substring(1) }); }; _boundEvents.windowBeforePrint = () => { eventBus.dispatch("beforeprint", { source: window }); }; _boundEvents.windowAfterPrint = () => { eventBus.dispatch("afterprint", { source: window }); }; _boundEvents.windowUpdateFromSandbox = event => { eventBus.dispatch("updatefromsandbox", { source: window, detail: event.detail }); }; window.addEventListener("visibilitychange", webViewerVisibilityChange); window.addEventListener("wheel", webViewerWheel, { passive: false }); window.addEventListener("touchstart", webViewerTouchStart, { passive: false }); window.addEventListener("click", webViewerClick); window.addEventListener("keydown", webViewerKeyDown); window.addEventListener("keyup", webViewerKeyUp); window.addEventListener("resize", _boundEvents.windowResize); window.addEventListener("hashchange", _boundEvents.windowHashChange); window.addEventListener("beforeprint", _boundEvents.windowBeforePrint); window.addEventListener("afterprint", _boundEvents.windowAfterPrint); window.addEventListener("updatefromsandbox", _boundEvents.windowUpdateFromSandbox); }, unbindEvents() { const { eventBus, _boundEvents } = this; eventBus._off("resize", webViewerResize); eventBus._off("hashchange", webViewerHashchange); eventBus._off("beforeprint", _boundEvents.beforePrint); eventBus._off("afterprint", _boundEvents.afterPrint); eventBus._off("pagerendered", webViewerPageRendered); eventBus._off("updateviewarea", webViewerUpdateViewarea); eventBus._off("pagechanging", webViewerPageChanging); eventBus._off("scalechanging", webViewerScaleChanging); eventBus._off("rotationchanging", webViewerRotationChanging); eventBus._off("sidebarviewchanged", webViewerSidebarViewChanged); eventBus._off("pagemode", webViewerPageMode); eventBus._off("namedaction", webViewerNamedAction); eventBus._off("presentationmodechanged", webViewerPresentationModeChanged); eventBus._off("presentationmode", webViewerPresentationMode); eventBus._off("print", webViewerPrint); eventBus._off("download", webViewerDownload); eventBus._off("save", webViewerSave); eventBus._off("firstpage", webViewerFirstPage); eventBus._off("lastpage", webViewerLastPage); eventBus._off("nextpage", webViewerNextPage); eventBus._off("previouspage", webViewerPreviousPage); eventBus._off("zoomin", webViewerZoomIn); eventBus._off("zoomout", webViewerZoomOut); eventBus._off("zoomreset", webViewerZoomReset); eventBus._off("pagenumberchanged", webViewerPageNumberChanged); eventBus._off("scalechanged", webViewerScaleChanged); eventBus._off("rotatecw", webViewerRotateCw); eventBus._off("rotateccw", webViewerRotateCcw); eventBus._off("optionalcontentconfig", webViewerOptionalContentConfig); eventBus._off("switchscrollmode", webViewerSwitchScrollMode); eventBus._off("scrollmodechanged", webViewerScrollModeChanged); eventBus._off("switchspreadmode", webViewerSwitchSpreadMode); eventBus._off("spreadmodechanged", webViewerSpreadModeChanged); eventBus._off("documentproperties", webViewerDocumentProperties); eventBus._off("find", webViewerFind); eventBus._off("findfromurlhash", webViewerFindFromUrlHash); eventBus._off("updatefindmatchescount", webViewerUpdateFindMatchesCount); eventBus._off("updatefindcontrolstate", webViewerUpdateFindControlState); if (_boundEvents.reportPageStatsPDFBug) { eventBus._off("pagerendered", _boundEvents.reportPageStatsPDFBug); eventBus._off("pagechanging", _boundEvents.reportPageStatsPDFBug); _boundEvents.reportPageStatsPDFBug = null; } eventBus._off("fileinputchange", webViewerFileInputChange); eventBus._off("openfile", webViewerOpenFile); _boundEvents.beforePrint = null; _boundEvents.afterPrint = null; }, unbindWindowEvents() { const { _boundEvents } = this; window.removeEventListener("visibilitychange", webViewerVisibilityChange); window.removeEventListener("wheel", webViewerWheel, { passive: false }); window.removeEventListener("touchstart", webViewerTouchStart, { passive: false }); window.removeEventListener("click", webViewerClick); window.removeEventListener("keydown", webViewerKeyDown); window.removeEventListener("keyup", webViewerKeyUp); window.removeEventListener("resize", _boundEvents.windowResize); window.removeEventListener("hashchange", _boundEvents.windowHashChange); window.removeEventListener("beforeprint", _boundEvents.windowBeforePrint); window.removeEventListener("afterprint", _boundEvents.windowAfterPrint); window.removeEventListener("updatefromsandbox", _boundEvents.windowUpdateFromSandbox); _boundEvents.windowResize = null; _boundEvents.windowHashChange = null; _boundEvents.windowBeforePrint = null; _boundEvents.windowAfterPrint = null; _boundEvents.windowUpdateFromSandbox = null; }, accumulateWheelTicks(ticks) { if (this._wheelUnusedTicks > 0 && ticks < 0 || this._wheelUnusedTicks < 0 && ticks > 0) { this._wheelUnusedTicks = 0; } this._wheelUnusedTicks += ticks; const wholeTicks = Math.sign(this._wheelUnusedTicks) * Math.floor(Math.abs(this._wheelUnusedTicks)); this._wheelUnusedTicks -= wholeTicks; return wholeTicks; }, _unblockDocumentLoadEvent() { if (document.blockUnblockOnload) { document.blockUnblockOnload(false); } this._unblockDocumentLoadEvent = () => {}; }, get scriptingReady() { return this.pdfScriptingManager.ready; } }; exports.PDFViewerApplication = PDFViewerApplication; let validateFileURL; { const HOSTED_VIEWER_ORIGINS = ["null", "http://mozilla.github.io", "https://mozilla.github.io"]; validateFileURL = function (file) { if (file === undefined) { return; } try { const viewerOrigin = new URL(window.location.href).origin || "null"; if (HOSTED_VIEWER_ORIGINS.includes(viewerOrigin)) { return; } const { origin, protocol } = new URL(file, window.location.href); if (origin !== viewerOrigin && protocol !== "blob:") { throw new Error("file origin does not match viewer's"); } } catch (ex) { PDFViewerApplication.l10n.get("loading_error").then(msg => { PDFViewerApplication._documentError(msg, { message: ex?.message }); }); throw ex; } }; } async function loadFakeWorker() { if (!_pdfjsLib.GlobalWorkerOptions.workerSrc) { _pdfjsLib.GlobalWorkerOptions.workerSrc = _app_options.AppOptions.get("workerSrc"); } return (0, _pdfjsLib.loadScript)(_pdfjsLib.PDFWorker.getWorkerSrc()); } function loadAndEnablePDFBug(enabledTabs) { const appConfig = PDFViewerApplication.appConfig; return (0, _pdfjsLib.loadScript)(appConfig.debuggerScriptPath).then(function () { PDFBug.enable(enabledTabs); PDFBug.init({ OPS: _pdfjsLib.OPS }, appConfig.mainContainer); }); } function reportPageStatsPDFBug({ pageNumber }) { if (typeof Stats === "undefined" || !Stats.enabled) { return; } const pageView = PDFViewerApplication.pdfViewer.getPageView(pageNumber - 1); const pageStats = pageView?.pdfPage?.stats; if (!pageStats) { return; } Stats.add(pageNumber, pageStats); } function webViewerInitialized() { const appConfig = PDFViewerApplication.appConfig; let file; const queryString = document.location.search.substring(1); const params = (0, _ui_utils.parseQueryString)(queryString); file = "file" in params ? params.file : _app_options.AppOptions.get("defaultUrl"); validateFileURL(file); const fileInput = document.createElement("input"); fileInput.id = appConfig.openFileInputName; fileInput.className = "fileInput"; fileInput.setAttribute("type", "file"); fileInput.oncontextmenu = _ui_utils.noContextMenuHandler; document.body.appendChild(fileInput); if (!window.File || !window.FileReader || !window.FileList || !window.Blob) { appConfig.toolbar.openFile.hidden = true; appConfig.secondaryToolbar.openFileButton.hidden = true; } else { fileInput.value = null; } fileInput.addEventListener("change", function (evt) { const files = evt.target.files; if (!files || files.length === 0) { return; } PDFViewerApplication.eventBus.dispatch("fileinputchange", { source: this, fileInput: evt.target }); }); appConfig.mainContainer.addEventListener("dragover", function (evt) { evt.preventDefault(); evt.dataTransfer.dropEffect = "move"; }); appConfig.mainContainer.addEventListener("drop", function (evt) { evt.preventDefault(); const files = evt.dataTransfer.files; if (!files || files.length === 0) { return; } PDFViewerApplication.eventBus.dispatch("fileinputchange", { source: this, fileInput: evt.dataTransfer }); }); if (!PDFViewerApplication.supportsDocumentFonts) { _app_options.AppOptions.set("disableFontFace", true); PDFViewerApplication.l10n.get("web_fonts_disabled").then(msg => { console.warn(msg); }); } if (!PDFViewerApplication.supportsPrinting) { appConfig.toolbar.print.classList.add("hidden"); appConfig.secondaryToolbar.printButton.classList.add("hidden"); } if (!PDFViewerApplication.supportsFullscreen) { appConfig.toolbar.presentationModeButton.classList.add("hidden"); appConfig.secondaryToolbar.presentationModeButton.classList.add("hidden"); } if (PDFViewerApplication.supportsIntegratedFind) { appConfig.toolbar.viewFind.classList.add("hidden"); } appConfig.mainContainer.addEventListener("transitionend", function (evt) { if (evt.target === this) { PDFViewerApplication.eventBus.dispatch("resize", { source: this }); } }, true); try { webViewerOpenFileViaURL(file); } catch (reason) { PDFViewerApplication.l10n.get("loading_error").then(msg => { PDFViewerApplication._documentError(msg, reason); }); } } function webViewerOpenFileViaURL(file) { if (file) { PDFViewerApplication.open(file); } } function webViewerResetPermissions() { const { appConfig } = PDFViewerApplication; if (!appConfig) { return; } appConfig.viewerContainer.classList.remove(ENABLE_PERMISSIONS_CLASS); } function webViewerPageRendered({ pageNumber, timestamp, error }) { if (pageNumber === PDFViewerApplication.page) { PDFViewerApplication.toolbar.updateLoadingIndicatorState(false); } if (PDFViewerApplication.pdfSidebar.isThumbnailViewVisible) { const pageView = PDFViewerApplication.pdfViewer.getPageView(pageNumber - 1); const thumbnailView = PDFViewerApplication.pdfThumbnailViewer.getThumbnail(pageNumber - 1); if (pageView && thumbnailView) { thumbnailView.setImage(pageView); } } if (error) { PDFViewerApplication.l10n.get("rendering_error").then(msg => { PDFViewerApplication._otherError(msg, error); }); } PDFViewerApplication.externalServices.reportTelemetry({ type: "pageInfo", timestamp }); PDFViewerApplication.pdfDocument.getStats().then(function (stats) { PDFViewerApplication.externalServices.reportTelemetry({ type: "documentStats", stats }); }); } function webViewerPageMode({ mode }) { let view; switch (mode) { case "thumbs": view = _ui_utils.SidebarView.THUMBS; break; case "bookmarks": case "outline": view = _ui_utils.SidebarView.OUTLINE; break; case "attachments": view = _ui_utils.SidebarView.ATTACHMENTS; break; case "layers": view = _ui_utils.SidebarView.LAYERS; break; case "none": view = _ui_utils.SidebarView.NONE; break; default: console.error('Invalid "pagemode" hash parameter: ' + mode); return; } PDFViewerApplication.pdfSidebar.switchView(view, true); } function webViewerNamedAction(evt) { switch (evt.action) { case "GoToPage": PDFViewerApplication.appConfig.toolbar.pageNumber.select(); break; case "Find": if (!PDFViewerApplication.supportsIntegratedFind) { PDFViewerApplication.findBar.toggle(); } break; case "Print": PDFViewerApplication.triggerPrinting(); break; case "SaveAs": webViewerSave(); break; } } function webViewerPresentationModeChanged(evt) { PDFViewerApplication.pdfViewer.presentationModeState = evt.state; } function webViewerSidebarViewChanged(evt) { PDFViewerApplication.pdfRenderingQueue.isThumbnailViewEnabled = PDFViewerApplication.pdfSidebar.isThumbnailViewVisible; const store = PDFViewerApplication.store; if (store && PDFViewerApplication.isInitialViewSet) { store.set("sidebarView", evt.view).catch(function () {}); } } function webViewerUpdateViewarea(evt) { const location = evt.location, store = PDFViewerApplication.store; if (store && PDFViewerApplication.isInitialViewSet) { store.setMultiple({ page: location.pageNumber, zoom: location.scale, scrollLeft: location.left, scrollTop: location.top, rotation: location.rotation }).catch(function () {}); } const href = PDFViewerApplication.pdfLinkService.getAnchorUrl(location.pdfOpenParams); PDFViewerApplication.appConfig.toolbar.viewBookmark.href = href; PDFViewerApplication.appConfig.secondaryToolbar.viewBookmarkButton.href = href; const currentPage = PDFViewerApplication.pdfViewer.getPageView(PDFViewerApplication.page - 1); const loading = currentPage?.renderingState !== _pdf_rendering_queue.RenderingStates.FINISHED; PDFViewerApplication.toolbar.updateLoadingIndicatorState(loading); } function webViewerScrollModeChanged(evt) { const store = PDFViewerApplication.store; if (store && PDFViewerApplication.isInitialViewSet) { store.set("scrollMode", evt.mode).catch(function () {}); } } function webViewerSpreadModeChanged(evt) { const store = PDFViewerApplication.store; if (store && PDFViewerApplication.isInitialViewSet) { store.set("spreadMode", evt.mode).catch(function () {}); } } function webViewerResize() { const { pdfDocument, pdfViewer } = PDFViewerApplication; if (!pdfDocument) { return; } const currentScaleValue = pdfViewer.currentScaleValue; if (currentScaleValue === "auto" || currentScaleValue === "page-fit" || currentScaleValue === "page-width") { pdfViewer.currentScaleValue = currentScaleValue; } pdfViewer.update(); } function webViewerHashchange(evt) { const hash = evt.hash; if (!hash) { return; } if (!PDFViewerApplication.isInitialViewSet) { PDFViewerApplication.initialBookmark = hash; } else if (!PDFViewerApplication.pdfHistory.popStateInProgress) { PDFViewerApplication.pdfLinkService.setHash(hash); } } let webViewerFileInputChange, webViewerOpenFile; { webViewerFileInputChange = function (evt) { if (PDFViewerApplication.pdfViewer?.isInPresentationMode) { return; } const file = evt.fileInput.files[0]; if (!_viewer_compatibility.viewerCompatibilityParams.disableCreateObjectURL) { let url = URL.createObjectURL(file); if (file.name) { url = { url, originalUrl: file.name }; } PDFViewerApplication.open(url); } else { PDFViewerApplication.setTitleUsingUrl(file.name); const fileReader = new FileReader(); fileReader.onload = function webViewerChangeFileReaderOnload(event) { const buffer = event.target.result; PDFViewerApplication.open(new Uint8Array(buffer)); }; fileReader.readAsArrayBuffer(file); } const appConfig = PDFViewerApplication.appConfig; appConfig.toolbar.viewBookmark.hidden = true; appConfig.secondaryToolbar.viewBookmarkButton.hidden = true; appConfig.toolbar.download.hidden = true; appConfig.secondaryToolbar.downloadButton.hidden = true; }; webViewerOpenFile = function (evt) { const openFileInputName = PDFViewerApplication.appConfig.openFileInputName; document.getElementById(openFileInputName).click(); }; } function webViewerPresentationMode() { PDFViewerApplication.requestPresentationMode(); } function webViewerPrint() { PDFViewerApplication.triggerPrinting(); } function webViewerDownload() { PDFViewerApplication.downloadOrSave({ sourceEventType: "download" }); } function webViewerSave() { PDFViewerApplication.downloadOrSave({ sourceEventType: "save" }); } function webViewerFirstPage() { if (PDFViewerApplication.pdfDocument) { PDFViewerApplication.page = 1; } } function webViewerLastPage() { if (PDFViewerApplication.pdfDocument) { PDFViewerApplication.page = PDFViewerApplication.pagesCount; } } function webViewerNextPage() { PDFViewerApplication.pdfViewer.nextPage(); } function webViewerPreviousPage() { PDFViewerApplication.pdfViewer.previousPage(); } function webViewerZoomIn() { PDFViewerApplication.zoomIn(); } function webViewerZoomOut() { PDFViewerApplication.zoomOut(); } function webViewerZoomReset() { PDFViewerApplication.zoomReset(); } function webViewerPageNumberChanged(evt) { const pdfViewer = PDFViewerApplication.pdfViewer; if (evt.value !== "") { PDFViewerApplication.pdfLinkService.goToPage(evt.value); } if (evt.value !== pdfViewer.currentPageNumber.toString() && evt.value !== pdfViewer.currentPageLabel) { PDFViewerApplication.toolbar.setPageNumber(pdfViewer.currentPageNumber, pdfViewer.currentPageLabel); } } function webViewerScaleChanged(evt) { PDFViewerApplication.pdfViewer.currentScaleValue = evt.value; } function webViewerRotateCw() { PDFViewerApplication.rotatePages(90); } function webViewerRotateCcw() { PDFViewerApplication.rotatePages(-90); } function webViewerOptionalContentConfig(evt) { PDFViewerApplication.pdfViewer.optionalContentConfigPromise = evt.promise; } function webViewerSwitchScrollMode(evt) { PDFViewerApplication.pdfViewer.scrollMode = evt.mode; } function webViewerSwitchSpreadMode(evt) { PDFViewerApplication.pdfViewer.spreadMode = evt.mode; } function webViewerDocumentProperties() { PDFViewerApplication.pdfDocumentProperties.open(); } function webViewerFind(evt) { PDFViewerApplication.findController.executeCommand("find" + evt.type, { query: evt.query, phraseSearch: evt.phraseSearch, caseSensitive: evt.caseSensitive, entireWord: evt.entireWord, highlightAll: evt.highlightAll, findPrevious: evt.findPrevious }); } function webViewerFindFromUrlHash(evt) { PDFViewerApplication.findController.executeCommand("find", { query: evt.query, phraseSearch: evt.phraseSearch, caseSensitive: false, entireWord: false, highlightAll: true, findPrevious: false }); } function webViewerUpdateFindMatchesCount({ matchesCount }) { if (PDFViewerApplication.supportsIntegratedFind) { PDFViewerApplication.externalServices.updateFindMatchesCount(matchesCount); } else { PDFViewerApplication.findBar.updateResultsCount(matchesCount); } } function webViewerUpdateFindControlState({ state, previous, matchesCount, rawQuery }) { if (PDFViewerApplication.supportsIntegratedFind) { PDFViewerApplication.externalServices.updateFindControlState({ result: state, findPrevious: previous, matchesCount, rawQuery }); } else { PDFViewerApplication.findBar.updateUIState(state, previous, matchesCount); } } function webViewerScaleChanging(evt) { PDFViewerApplication.toolbar.setPageScale(evt.presetValue, evt.scale); PDFViewerApplication.pdfViewer.update(); } function webViewerRotationChanging(evt) { PDFViewerApplication.pdfThumbnailViewer.pagesRotation = evt.pagesRotation; PDFViewerApplication.forceRendering(); PDFViewerApplication.pdfViewer.currentPageNumber = evt.pageNumber; } function webViewerPageChanging({ pageNumber, pageLabel }) { PDFViewerApplication.toolbar.setPageNumber(pageNumber, pageLabel); PDFViewerApplication.secondaryToolbar.setPageNumber(pageNumber); if (PDFViewerApplication.pdfSidebar.isThumbnailViewVisible) { PDFViewerApplication.pdfThumbnailViewer.scrollThumbnailIntoView(pageNumber); } } function webViewerVisibilityChange(evt) { if (document.visibilityState === "visible") { setZoomDisabledTimeout(); } } let zoomDisabledTimeout = null; function setZoomDisabledTimeout() { if (zoomDisabledTimeout) { clearTimeout(zoomDisabledTimeout); } zoomDisabledTimeout = setTimeout(function () { zoomDisabledTimeout = null; }, WHEEL_ZOOM_DISABLED_TIMEOUT); } function webViewerWheel(evt) { const { pdfViewer, supportedMouseWheelZoomModifierKeys } = PDFViewerApplication; if (pdfViewer.isInPresentationMode) { return; } if (evt.ctrlKey && supportedMouseWheelZoomModifierKeys.ctrlKey || evt.metaKey && supportedMouseWheelZoomModifierKeys.metaKey) { evt.preventDefault(); if (zoomDisabledTimeout || document.visibilityState === "hidden") { return; } const previousScale = pdfViewer.currentScale; const delta = (0, _ui_utils.normalizeWheelEventDirection)(evt); let ticks = 0; if (evt.deltaMode === WheelEvent.DOM_DELTA_LINE || evt.deltaMode === WheelEvent.DOM_DELTA_PAGE) { if (Math.abs(delta) >= 1) { ticks = Math.sign(delta); } else { ticks = PDFViewerApplication.accumulateWheelTicks(delta); } } else { const PIXELS_PER_LINE_SCALE = 30; ticks = PDFViewerApplication.accumulateWheelTicks(delta / PIXELS_PER_LINE_SCALE); } if (ticks < 0) { PDFViewerApplication.zoomOut(-ticks); } else if (ticks > 0) { PDFViewerApplication.zoomIn(ticks); } const currentScale = pdfViewer.currentScale; if (previousScale !== currentScale) { const scaleCorrectionFactor = currentScale / previousScale - 1; const rect = pdfViewer.container.getBoundingClientRect(); const dx = evt.clientX - rect.left; const dy = evt.clientY - rect.top; pdfViewer.container.scrollLeft += dx * scaleCorrectionFactor; pdfViewer.container.scrollTop += dy * scaleCorrectionFactor; } } else { setZoomDisabledTimeout(); } } function webViewerTouchStart(evt) { if (evt.touches.length > 1) { evt.preventDefault(); } } function webViewerClick(evt) { if (PDFViewerApplication.triggerDelayedFallback && PDFViewerApplication.pdfViewer.containsElement(evt.target)) { PDFViewerApplication.triggerDelayedFallback(); } if (!PDFViewerApplication.secondaryToolbar.isOpen) { return; } const appConfig = PDFViewerApplication.appConfig; if (PDFViewerApplication.pdfViewer.containsElement(evt.target) || appConfig.toolbar.container.contains(evt.target) && evt.target !== appConfig.secondaryToolbar.toggleButton) { PDFViewerApplication.secondaryToolbar.close(); } } function webViewerKeyUp(evt) { if (evt.keyCode === 9) { if (PDFViewerApplication.triggerDelayedFallback) { PDFViewerApplication.triggerDelayedFallback(); } } } function webViewerKeyDown(evt) { if (PDFViewerApplication.overlayManager.active) { return; } let handled = false, ensureViewerFocused = false; const cmd = (evt.ctrlKey ? 1 : 0) | (evt.altKey ? 2 : 0) | (evt.shiftKey ? 4 : 0) | (evt.metaKey ? 8 : 0); const pdfViewer = PDFViewerApplication.pdfViewer; const isViewerInPresentationMode = pdfViewer?.isInPresentationMode; if (cmd === 1 || cmd === 8 || cmd === 5 || cmd === 12) { switch (evt.keyCode) { case 70: if (!PDFViewerApplication.supportsIntegratedFind && !evt.shiftKey) { PDFViewerApplication.findBar.open(); handled = true; } break; case 71: if (!PDFViewerApplication.supportsIntegratedFind) { const findState = PDFViewerApplication.findController.state; if (findState) { PDFViewerApplication.findController.executeCommand("findagain", { query: findState.query, phraseSearch: findState.phraseSearch, caseSensitive: findState.caseSensitive, entireWord: findState.entireWord, highlightAll: findState.highlightAll, findPrevious: cmd === 5 || cmd === 12 }); } handled = true; } break; case 61: case 107: case 187: case 171: if (!isViewerInPresentationMode) { PDFViewerApplication.zoomIn(); } handled = true; break; case 173: case 109: case 189: if (!isViewerInPresentationMode) { PDFViewerApplication.zoomOut(); } handled = true; break; case 48: case 96: if (!isViewerInPresentationMode) { setTimeout(function () { PDFViewerApplication.zoomReset(); }); handled = false; } break; case 38: if (isViewerInPresentationMode || PDFViewerApplication.page > 1) { PDFViewerApplication.page = 1; handled = true; ensureViewerFocused = true; } break; case 40: if (isViewerInPresentationMode || PDFViewerApplication.page < PDFViewerApplication.pagesCount) { PDFViewerApplication.page = PDFViewerApplication.pagesCount; handled = true; ensureViewerFocused = true; } break; } } const { eventBus } = PDFViewerApplication; if (cmd === 1 || cmd === 8) { switch (evt.keyCode) { case 83: eventBus.dispatch("download", { source: window }); handled = true; break; case 79: { eventBus.dispatch("openfile", { source: window }); handled = true; } break; } } if (cmd === 3 || cmd === 10) { switch (evt.keyCode) { case 80: PDFViewerApplication.requestPresentationMode(); handled = true; break; case 71: PDFViewerApplication.appConfig.toolbar.pageNumber.select(); handled = true; break; } } if (handled) { if (ensureViewerFocused && !isViewerInPresentationMode) { pdfViewer.focus(); } evt.preventDefault(); return; } const curElement = (0, _ui_utils.getActiveOrFocusedElement)(); const curElementTagName = curElement?.tagName.toUpperCase(); if (curElementTagName === "INPUT" || curElementTagName === "TEXTAREA" || curElementTagName === "SELECT" || curElement?.isContentEditable) { if (evt.keyCode !== 27) { return; } } if (cmd === 0) { let turnPage = 0, turnOnlyIfPageFit = false; switch (evt.keyCode) { case 38: case 33: if (pdfViewer.isVerticalScrollbarEnabled) { turnOnlyIfPageFit = true; } turnPage = -1; break; case 8: if (!isViewerInPresentationMode) { turnOnlyIfPageFit = true; } turnPage = -1; break; case 37: if (pdfViewer.isHorizontalScrollbarEnabled) { turnOnlyIfPageFit = true; } case 75: case 80: turnPage = -1; break; case 27: if (PDFViewerApplication.secondaryToolbar.isOpen) { PDFViewerApplication.secondaryToolbar.close(); handled = true; } if (!PDFViewerApplication.supportsIntegratedFind && PDFViewerApplication.findBar.opened) { PDFViewerApplication.findBar.close(); handled = true; } break; case 40: case 34: if (pdfViewer.isVerticalScrollbarEnabled) { turnOnlyIfPageFit = true; } turnPage = 1; break; case 13: case 32: if (!isViewerInPresentationMode) { turnOnlyIfPageFit = true; } turnPage = 1; break; case 39: if (pdfViewer.isHorizontalScrollbarEnabled) { turnOnlyIfPageFit = true; } case 74: case 78: turnPage = 1; break; case 36: if (isViewerInPresentationMode || PDFViewerApplication.page > 1) { PDFViewerApplication.page = 1; handled = true; ensureViewerFocused = true; } break; case 35: if (isViewerInPresentationMode || PDFViewerApplication.page < PDFViewerApplication.pagesCount) { PDFViewerApplication.page = PDFViewerApplication.pagesCount; handled = true; ensureViewerFocused = true; } break; case 83: PDFViewerApplication.pdfCursorTools.switchTool(_pdf_cursor_tools.CursorTool.SELECT); break; case 72: PDFViewerApplication.pdfCursorTools.switchTool(_pdf_cursor_tools.CursorTool.HAND); break; case 82: PDFViewerApplication.rotatePages(90); break; case 115: PDFViewerApplication.pdfSidebar.toggle(); break; } if (turnPage !== 0 && (!turnOnlyIfPageFit || pdfViewer.currentScaleValue === "page-fit")) { if (turnPage > 0) { pdfViewer.nextPage(); } else { pdfViewer.previousPage(); } handled = true; } } if (cmd === 4) { switch (evt.keyCode) { case 13: case 32: if (!isViewerInPresentationMode && pdfViewer.currentScaleValue !== "page-fit") { break; } if (PDFViewerApplication.page > 1) { PDFViewerApplication.page--; } handled = true; break; case 82: PDFViewerApplication.rotatePages(-90); break; } } if (!handled && !isViewerInPresentationMode) { if (evt.keyCode >= 33 && evt.keyCode <= 40 || evt.keyCode === 32 && curElementTagName !== "BUTTON") { ensureViewerFocused = true; } } if (ensureViewerFocused && !pdfViewer.containsElement(curElement)) { pdfViewer.focus(); } if (handled) { evt.preventDefault(); } } function beforeUnload(evt) { evt.preventDefault(); evt.returnValue = ""; return false; } const PDFPrintServiceFactory = { instance: { supportsPrinting: false, createPrintService() { throw new Error("Not implemented: createPrintService"); } } }; exports.PDFPrintServiceFactory = PDFPrintServiceFactory; /***/ }), /* 4 */ /***/ ((__unused_webpack_module, exports) => { Object.defineProperty(exports, "__esModule", ({ value: true })); exports.apiPageLayoutToSpreadMode = apiPageLayoutToSpreadMode; exports.apiPageModeToSidebarView = apiPageModeToSidebarView; exports.approximateFraction = approximateFraction; exports.backtrackBeforeAllVisibleElements = backtrackBeforeAllVisibleElements; exports.binarySearchFirstItem = binarySearchFirstItem; exports.getActiveOrFocusedElement = getActiveOrFocusedElement; exports.getOutputScale = getOutputScale; exports.getPageSizeInches = getPageSizeInches; exports.getVisibleElements = getVisibleElements; exports.isPortraitOrientation = isPortraitOrientation; exports.isValidRotation = isValidRotation; exports.isValidScrollMode = isValidScrollMode; exports.isValidSpreadMode = isValidSpreadMode; exports.moveToEndOfArray = moveToEndOfArray; exports.noContextMenuHandler = noContextMenuHandler; exports.normalizeWheelEventDelta = normalizeWheelEventDelta; exports.normalizeWheelEventDirection = normalizeWheelEventDirection; exports.parseQueryString = parseQueryString; exports.roundToDivide = roundToDivide; exports.scrollIntoView = scrollIntoView; exports.waitOnEventOrTimeout = waitOnEventOrTimeout; exports.watchScroll = watchScroll; exports.WaitOnType = exports.VERTICAL_PADDING = exports.UNKNOWN_SCALE = exports.TextLayerMode = exports.SpreadMode = exports.SidebarView = exports.ScrollMode = exports.SCROLLBAR_PADDING = exports.RendererType = exports.ProgressBar = exports.PresentationModeState = exports.MIN_SCALE = exports.MAX_SCALE = exports.MAX_AUTO_SCALE = exports.EventBus = exports.DEFAULT_SCALE_VALUE = exports.DEFAULT_SCALE = exports.CSS_UNITS = exports.AutoPrintRegExp = exports.animationStarted = void 0; const CSS_UNITS = 96.0 / 72.0; exports.CSS_UNITS = CSS_UNITS; const DEFAULT_SCALE_VALUE = "auto"; exports.DEFAULT_SCALE_VALUE = DEFAULT_SCALE_VALUE; const DEFAULT_SCALE = 1.0; exports.DEFAULT_SCALE = DEFAULT_SCALE; const MIN_SCALE = 0.1; exports.MIN_SCALE = MIN_SCALE; const MAX_SCALE = 10.0; exports.MAX_SCALE = MAX_SCALE; const UNKNOWN_SCALE = 0; exports.UNKNOWN_SCALE = UNKNOWN_SCALE; const MAX_AUTO_SCALE = 1.25; exports.MAX_AUTO_SCALE = MAX_AUTO_SCALE; const SCROLLBAR_PADDING = 40; exports.SCROLLBAR_PADDING = SCROLLBAR_PADDING; const VERTICAL_PADDING = 5; exports.VERTICAL_PADDING = VERTICAL_PADDING; const LOADINGBAR_END_OFFSET_VAR = "--loadingBar-end-offset"; const PresentationModeState = { UNKNOWN: 0, NORMAL: 1, CHANGING: 2, FULLSCREEN: 3 }; exports.PresentationModeState = PresentationModeState; const SidebarView = { UNKNOWN: -1, NONE: 0, THUMBS: 1, OUTLINE: 2, ATTACHMENTS: 3, LAYERS: 4 }; exports.SidebarView = SidebarView; const RendererType = { CANVAS: "canvas", SVG: "svg" }; exports.RendererType = RendererType; const TextLayerMode = { DISABLE: 0, ENABLE: 1, ENABLE_ENHANCE: 2 }; exports.TextLayerMode = TextLayerMode; const ScrollMode = { UNKNOWN: -1, VERTICAL: 0, HORIZONTAL: 1, WRAPPED: 2 }; exports.ScrollMode = ScrollMode; const SpreadMode = { UNKNOWN: -1, NONE: 0, ODD: 1, EVEN: 2 }; exports.SpreadMode = SpreadMode; const AutoPrintRegExp = /\bprint\s*\(/; exports.AutoPrintRegExp = AutoPrintRegExp; function getOutputScale(ctx) { const devicePixelRatio = window.devicePixelRatio || 1; const backingStoreRatio = ctx.webkitBackingStorePixelRatio || ctx.mozBackingStorePixelRatio || ctx.backingStorePixelRatio || 1; const pixelRatio = devicePixelRatio / backingStoreRatio; return { sx: pixelRatio, sy: pixelRatio, scaled: pixelRatio !== 1 }; } function scrollIntoView(element, spot, skipOverflowHiddenElements = false) { let parent = element.offsetParent; if (!parent) { console.error("offsetParent is not set -- cannot scroll"); return; } let offsetY = element.offsetTop + element.clientTop; let offsetX = element.offsetLeft + element.clientLeft; while (parent.clientHeight === parent.scrollHeight && parent.clientWidth === parent.scrollWidth || skipOverflowHiddenElements && getComputedStyle(parent).overflow === "hidden") { if (parent.dataset._scaleY) { offsetY /= parent.dataset._scaleY; offsetX /= parent.dataset._scaleX; } offsetY += parent.offsetTop; offsetX += parent.offsetLeft; parent = parent.offsetParent; if (!parent) { return; } } if (spot) { if (spot.top !== undefined) { offsetY += spot.top; } if (spot.left !== undefined) { offsetX += spot.left; parent.scrollLeft = offsetX; } } parent.scrollTop = offsetY; } function watchScroll(viewAreaElement, callback) { const debounceScroll = function (evt) { if (rAF) { return; } rAF = window.requestAnimationFrame(function viewAreaElementScrolled() { rAF = null; const currentX = viewAreaElement.scrollLeft; const lastX = state.lastX; if (currentX !== lastX) { state.right = currentX > lastX; } state.lastX = currentX; const currentY = viewAreaElement.scrollTop; const lastY = state.lastY; if (currentY !== lastY) { state.down = currentY > lastY; } state.lastY = currentY; callback(state); }); }; const state = { right: true, down: true, lastX: viewAreaElement.scrollLeft, lastY: viewAreaElement.scrollTop, _eventHandler: debounceScroll }; let rAF = null; viewAreaElement.addEventListener("scroll", debounceScroll, true); return state; } function parseQueryString(query) { const parts = query.split("&"); const params = Object.create(null); for (let i = 0, ii = parts.length; i < ii; ++i) { const param = parts[i].split("="); const key = param[0].toLowerCase(); const value = param.length > 1 ? param[1] : null; params[decodeURIComponent(key)] = decodeURIComponent(value); } return params; } function binarySearchFirstItem(items, condition) { let minIndex = 0; let maxIndex = items.length - 1; if (maxIndex < 0 || !condition(items[maxIndex])) { return items.length; } if (condition(items[minIndex])) { return minIndex; } while (minIndex < maxIndex) { const currentIndex = minIndex + maxIndex >> 1; const currentItem = items[currentIndex]; if (condition(currentItem)) { maxIndex = currentIndex; } else { minIndex = currentIndex + 1; } } return minIndex; } function approximateFraction(x) { if (Math.floor(x) === x) { return [x, 1]; } const xinv = 1 / x; const limit = 8; if (xinv > limit) { return [1, limit]; } else if (Math.floor(xinv) === xinv) { return [1, xinv]; } const x_ = x > 1 ? xinv : x; let a = 0, b = 1, c = 1, d = 1; while (true) { const p = a + c, q = b + d; if (q > limit) { break; } if (x_ <= p / q) { c = p; d = q; } else { a = p; b = q; } } let result; if (x_ - a / b < c / d - x_) { result = x_ === x ? [a, b] : [b, a]; } else { result = x_ === x ? [c, d] : [d, c]; } return result; } function roundToDivide(x, div) { const r = x % div; return r === 0 ? x : Math.round(x - r + div); } function getPageSizeInches({ view, userUnit, rotate }) { const [x1, y1, x2, y2] = view; const changeOrientation = rotate % 180 !== 0; const width = (x2 - x1) / 72 * userUnit; const height = (y2 - y1) / 72 * userUnit; return { width: changeOrientation ? height : width, height: changeOrientation ? width : height }; } function backtrackBeforeAllVisibleElements(index, views, top) { if (index < 2) { return index; } let elt = views[index].div; let pageTop = elt.offsetTop + elt.clientTop; if (pageTop >= top) { elt = views[index - 1].div; pageTop = elt.offsetTop + elt.clientTop; } for (let i = index - 2; i >= 0; --i) { elt = views[i].div; if (elt.offsetTop + elt.clientTop + elt.clientHeight <= pageTop) { break; } index = i; } return index; } function getVisibleElements({ scrollEl, views, sortByVisibility = false, horizontal = false, rtl = false }) { const top = scrollEl.scrollTop, bottom = top + scrollEl.clientHeight; const left = scrollEl.scrollLeft, right = left + scrollEl.clientWidth; function isElementBottomAfterViewTop(view) { const element = view.div; const elementBottom = element.offsetTop + element.clientTop + element.clientHeight; return elementBottom > top; } function isElementNextAfterViewHorizontally(view) { const element = view.div; const elementLeft = element.offsetLeft + element.clientLeft; const elementRight = elementLeft + element.clientWidth; return rtl ? elementLeft < right : elementRight > left; } const visible = [], numViews = views.length; let firstVisibleElementInd = binarySearchFirstItem(views, horizontal ? isElementNextAfterViewHorizontally : isElementBottomAfterViewTop); if (firstVisibleElementInd > 0 && firstVisibleElementInd < numViews && !horizontal) { firstVisibleElementInd = backtrackBeforeAllVisibleElements(firstVisibleElementInd, views, top); } let lastEdge = horizontal ? right : -1; for (let i = firstVisibleElementInd; i < numViews; i++) { const view = views[i], element = view.div; const currentWidth = element.offsetLeft + element.clientLeft; const currentHeight = element.offsetTop + element.clientTop; const viewWidth = element.clientWidth, viewHeight = element.clientHeight; const viewRight = currentWidth + viewWidth; const viewBottom = currentHeight + viewHeight; if (lastEdge === -1) { if (viewBottom >= bottom) { lastEdge = viewBottom; } } else if ((horizontal ? currentWidth : currentHeight) > lastEdge) { break; } if (viewBottom <= top || currentHeight >= bottom || viewRight <= left || currentWidth >= right) { continue; } const hiddenHeight = Math.max(0, top - currentHeight) + Math.max(0, viewBottom - bottom); const hiddenWidth = Math.max(0, left - currentWidth) + Math.max(0, viewRight - right); const fractionHeight = (viewHeight - hiddenHeight) / viewHeight, fractionWidth = (viewWidth - hiddenWidth) / viewWidth; const percent = fractionHeight * fractionWidth * 100 | 0; visible.push({ id: view.id, x: currentWidth, y: currentHeight, view, percent, widthPercent: fractionWidth * 100 | 0 }); } const first = visible[0], last = visible[visible.length - 1]; if (sortByVisibility) { visible.sort(function (a, b) { const pc = a.percent - b.percent; if (Math.abs(pc) > 0.001) { return -pc; } return a.id - b.id; }); } return { first, last, views: visible }; } function noContextMenuHandler(evt) { evt.preventDefault(); } function normalizeWheelEventDirection(evt) { let delta = Math.hypot(evt.deltaX, evt.deltaY); const angle = Math.atan2(evt.deltaY, evt.deltaX); if (-0.25 * Math.PI < angle && angle < 0.75 * Math.PI) { delta = -delta; } return delta; } function normalizeWheelEventDelta(evt) { let delta = normalizeWheelEventDirection(evt); const MOUSE_DOM_DELTA_PIXEL_MODE = 0; const MOUSE_DOM_DELTA_LINE_MODE = 1; const MOUSE_PIXELS_PER_LINE = 30; const MOUSE_LINES_PER_PAGE = 30; if (evt.deltaMode === MOUSE_DOM_DELTA_PIXEL_MODE) { delta /= MOUSE_PIXELS_PER_LINE * MOUSE_LINES_PER_PAGE; } else if (evt.deltaMode === MOUSE_DOM_DELTA_LINE_MODE) { delta /= MOUSE_LINES_PER_PAGE; } return delta; } function isValidRotation(angle) { return Number.isInteger(angle) && angle % 90 === 0; } function isValidScrollMode(mode) { return Number.isInteger(mode) && Object.values(ScrollMode).includes(mode) && mode !== ScrollMode.UNKNOWN; } function isValidSpreadMode(mode) { return Number.isInteger(mode) && Object.values(SpreadMode).includes(mode) && mode !== SpreadMode.UNKNOWN; } function isPortraitOrientation(size) { return size.width <= size.height; } const WaitOnType = { EVENT: "event", TIMEOUT: "timeout" }; exports.WaitOnType = WaitOnType; function waitOnEventOrTimeout({ target, name, delay = 0 }) { return new Promise(function (resolve, reject) { if (typeof target !== "object" || !(name && typeof name === "string") || !(Number.isInteger(delay) && delay >= 0)) { throw new Error("waitOnEventOrTimeout - invalid parameters."); } function handler(type) { if (target instanceof EventBus) { target._off(name, eventHandler); } else { target.removeEventListener(name, eventHandler); } if (timeout) { clearTimeout(timeout); } resolve(type); } const eventHandler = handler.bind(null, WaitOnType.EVENT); if (target instanceof EventBus) { target._on(name, eventHandler); } else { target.addEventListener(name, eventHandler); } const timeoutHandler = handler.bind(null, WaitOnType.TIMEOUT); const timeout = setTimeout(timeoutHandler, delay); }); } const animationStarted = new Promise(function (resolve) { window.requestAnimationFrame(resolve); }); exports.animationStarted = animationStarted; function dispatchDOMEvent(eventName, args = null) { throw new Error("Not implemented: dispatchDOMEvent"); } class EventBus { constructor(options) { this._listeners = Object.create(null); } on(eventName, listener, options = null) { this._on(eventName, listener, { external: true, once: options?.once }); } off(eventName, listener, options = null) { this._off(eventName, listener, { external: true, once: options?.once }); } dispatch(eventName) { const eventListeners = this._listeners[eventName]; if (!eventListeners || eventListeners.length === 0) { return; } const args = Array.prototype.slice.call(arguments, 1); let externalListeners; eventListeners.slice(0).forEach(({ listener, external, once }) => { if (once) { this._off(eventName, listener); } if (external) { (externalListeners || (externalListeners = [])).push(listener); return; } listener.apply(null, args); }); if (externalListeners) { externalListeners.forEach(listener => { listener.apply(null, args); }); externalListeners = null; } } _on(eventName, listener, options = null) { var _this$_listeners; const eventListeners = (_this$_listeners = this._listeners)[eventName] || (_this$_listeners[eventName] = []); eventListeners.push({ listener, external: options?.external === true, once: options?.once === true }); } _off(eventName, listener, options = null) { const eventListeners = this._listeners[eventName]; if (!eventListeners) { return; } for (let i = 0, ii = eventListeners.length; i < ii; i++) { if (eventListeners[i].listener === listener) { eventListeners.splice(i, 1); return; } } } } exports.EventBus = EventBus; function clamp(v, min, max) { return Math.min(Math.max(v, min), max); } class ProgressBar { constructor(id, { height, width, units } = {}) { this.visible = true; this.div = document.querySelector(id + " .progress"); this.bar = this.div.parentNode; this.height = height || 100; this.width = width || 100; this.units = units || "%"; this.div.style.height = this.height + this.units; this.percent = 0; } _updateBar() { if (this._indeterminate) { this.div.classList.add("indeterminate"); this.div.style.width = this.width + this.units; return; } this.div.classList.remove("indeterminate"); const progressSize = this.width * this._percent / 100; this.div.style.width = progressSize + this.units; } get percent() { return this._percent; } set percent(val) { this._indeterminate = isNaN(val); this._percent = clamp(val, 0, 100); this._updateBar(); } setWidth(viewer) { if (!viewer) { return; } const container = viewer.parentNode; const scrollbarWidth = container.offsetWidth - viewer.offsetWidth; if (scrollbarWidth > 0) { const doc = document.documentElement; doc.style.setProperty(LOADINGBAR_END_OFFSET_VAR, `${scrollbarWidth}px`); } } hide() { if (!this.visible) { return; } this.visible = false; this.bar.classList.add("hidden"); } show() { if (this.visible) { return; } this.visible = true; this.bar.classList.remove("hidden"); } } exports.ProgressBar = ProgressBar; function moveToEndOfArray(arr, condition) { const moved = [], len = arr.length; let write = 0; for (let read = 0; read < len; ++read) { if (condition(arr[read])) { moved.push(arr[read]); } else { arr[write] = arr[read]; ++write; } } for (let read = 0; write < len; ++read, ++write) { arr[write] = moved[read]; } } function getActiveOrFocusedElement() { let curRoot = document; let curActiveOrFocused = curRoot.activeElement || curRoot.querySelector(":focus"); while (curActiveOrFocused?.shadowRoot) { curRoot = curActiveOrFocused.shadowRoot; curActiveOrFocused = curRoot.activeElement || curRoot.querySelector(":focus"); } return curActiveOrFocused; } function apiPageLayoutToSpreadMode(layout) { switch (layout) { case "SinglePage": case "OneColumn": return SpreadMode.NONE; case "TwoColumnLeft": case "TwoPageLeft": return SpreadMode.ODD; case "TwoColumnRight": case "TwoPageRight": return SpreadMode.EVEN; } return SpreadMode.NONE; } function apiPageModeToSidebarView(mode) { switch (mode) { case "UseNone": return SidebarView.NONE; case "UseThumbs": return SidebarView.THUMBS; case "UseOutlines": return SidebarView.OUTLINE; case "UseAttachments": return SidebarView.ATTACHMENTS; case "UseOC": return SidebarView.LAYERS; } return SidebarView.NONE; } /***/ }), /* 5 */ /***/ ((module) => { let pdfjsLib; if (typeof window !== "undefined" && window["pdfjs-dist/build/pdf"]) { pdfjsLib = window["pdfjs-dist/build/pdf"]; } else { pdfjsLib = require("../build/pdf.js"); } module.exports = pdfjsLib; /***/ }), /* 6 */ /***/ ((__unused_webpack_module, exports, __webpack_require__) => { Object.defineProperty(exports, "__esModule", ({ value: true })); exports.PDFCursorTools = exports.CursorTool = void 0; var _grab_to_pan = __webpack_require__(7); var _ui_utils = __webpack_require__(4); const CursorTool = { SELECT: 0, HAND: 1, ZOOM: 2 }; exports.CursorTool = CursorTool; class PDFCursorTools { constructor({ container, eventBus, cursorToolOnLoad = CursorTool.SELECT }) { this.container = container; this.eventBus = eventBus; this.active = CursorTool.SELECT; this.activeBeforePresentationMode = null; this.handTool = new _grab_to_pan.GrabToPan({ element: this.container }); this._addEventListeners(); Promise.resolve().then(() => { this.switchTool(cursorToolOnLoad); }); } get activeTool() { return this.active; } switchTool(tool) { if (this.activeBeforePresentationMode !== null) { return; } if (tool === this.active) { return; } const disableActiveTool = () => { switch (this.active) { case CursorTool.SELECT: break; case CursorTool.HAND: this.handTool.deactivate(); break; case CursorTool.ZOOM: } }; switch (tool) { case CursorTool.SELECT: disableActiveTool(); break; case CursorTool.HAND: disableActiveTool(); this.handTool.activate(); break; case CursorTool.ZOOM: default: console.error(`switchTool: "${tool}" is an unsupported value.`); return; } this.active = tool; this._dispatchEvent(); } _dispatchEvent() { this.eventBus.dispatch("cursortoolchanged", { source: this, tool: this.active }); } _addEventListeners() { this.eventBus._on("switchcursortool", evt => { this.switchTool(evt.tool); }); this.eventBus._on("presentationmodechanged", evt => { switch (evt.state) { case _ui_utils.PresentationModeState.FULLSCREEN: { const previouslyActive = this.active; this.switchTool(CursorTool.SELECT); this.activeBeforePresentationMode = previouslyActive; break; } case _ui_utils.PresentationModeState.NORMAL: { const previouslyActive = this.activeBeforePresentationMode; this.activeBeforePresentationMode = null; this.switchTool(previouslyActive); break; } } }); } } exports.PDFCursorTools = PDFCursorTools; /***/ }), /* 7 */ /***/ ((__unused_webpack_module, exports) => { Object.defineProperty(exports, "__esModule", ({ value: true })); exports.GrabToPan = GrabToPan; function GrabToPan(options) { this.element = options.element; this.document = options.element.ownerDocument; if (typeof options.ignoreTarget === "function") { this.ignoreTarget = options.ignoreTarget; } this.onActiveChanged = options.onActiveChanged; this.activate = this.activate.bind(this); this.deactivate = this.deactivate.bind(this); this.toggle = this.toggle.bind(this); this._onmousedown = this._onmousedown.bind(this); this._onmousemove = this._onmousemove.bind(this); this._endPan = this._endPan.bind(this); const overlay = this.overlay = document.createElement("div"); overlay.className = "grab-to-pan-grabbing"; } GrabToPan.prototype = { CSS_CLASS_GRAB: "grab-to-pan-grab", activate: function GrabToPan_activate() { if (!this.active) { this.active = true; this.element.addEventListener("mousedown", this._onmousedown, true); this.element.classList.add(this.CSS_CLASS_GRAB); if (this.onActiveChanged) { this.onActiveChanged(true); } } }, deactivate: function GrabToPan_deactivate() { if (this.active) { this.active = false; this.element.removeEventListener("mousedown", this._onmousedown, true); this._endPan(); this.element.classList.remove(this.CSS_CLASS_GRAB); if (this.onActiveChanged) { this.onActiveChanged(false); } } }, toggle: function GrabToPan_toggle() { if (this.active) { this.deactivate(); } else { this.activate(); } }, ignoreTarget: function GrabToPan_ignoreTarget(node) { return node.matches("a[href], a[href] *, input, textarea, button, button *, select, option"); }, _onmousedown: function GrabToPan__onmousedown(event) { if (event.button !== 0 || this.ignoreTarget(event.target)) { return; } if (event.originalTarget) { try { event.originalTarget.tagName; } catch (e) { return; } } this.scrollLeftStart = this.element.scrollLeft; this.scrollTopStart = this.element.scrollTop; this.clientXStart = event.clientX; this.clientYStart = event.clientY; this.document.addEventListener("mousemove", this._onmousemove, true); this.document.addEventListener("mouseup", this._endPan, true); this.element.addEventListener("scroll", this._endPan, true); event.preventDefault(); event.stopPropagation(); const focusedElement = document.activeElement; if (focusedElement && !focusedElement.contains(event.target)) { focusedElement.blur(); } }, _onmousemove: function GrabToPan__onmousemove(event) { this.element.removeEventListener("scroll", this._endPan, true); if (isLeftMouseReleased(event)) { this._endPan(); return; } const xDiff = event.clientX - this.clientXStart; const yDiff = event.clientY - this.clientYStart; const scrollTop = this.scrollTopStart - yDiff; const scrollLeft = this.scrollLeftStart - xDiff; if (this.element.scrollTo) { this.element.scrollTo({ top: scrollTop, left: scrollLeft, behavior: "instant" }); } else { this.element.scrollTop = scrollTop; this.element.scrollLeft = scrollLeft; } if (!this.overlay.parentNode) { document.body.appendChild(this.overlay); } }, _endPan: function GrabToPan__endPan() { this.element.removeEventListener("scroll", this._endPan, true); this.document.removeEventListener("mousemove", this._onmousemove, true); this.document.removeEventListener("mouseup", this._endPan, true); this.overlay.remove(); } }; function isLeftMouseReleased(event) { if ("buttons" in event) { return !(event.buttons & 1); } const chrome = window.chrome; const isChrome15OrOpera15plus = chrome && (chrome.webstore || chrome.app); const isSafari6plus = /Apple/.test(navigator.vendor) && /Version\/([6-9]\d*|[1-5]\d+)/.test(navigator.userAgent); if (isChrome15OrOpera15plus || isSafari6plus) { return event.which === 0; } return false; } /***/ }), /* 8 */ /***/ ((__unused_webpack_module, exports, __webpack_require__) => { Object.defineProperty(exports, "__esModule", ({ value: true })); exports.RenderingStates = exports.PDFRenderingQueue = void 0; var _pdfjsLib = __webpack_require__(5); const CLEANUP_TIMEOUT = 30000; const RenderingStates = { INITIAL: 0, RUNNING: 1, PAUSED: 2, FINISHED: 3 }; exports.RenderingStates = RenderingStates; class PDFRenderingQueue { constructor() { this.pdfViewer = null; this.pdfThumbnailViewer = null; this.onIdle = null; this.highestPriorityPage = null; this.idleTimeout = null; this.printing = false; this.isThumbnailViewEnabled = false; } setViewer(pdfViewer) { this.pdfViewer = pdfViewer; } setThumbnailViewer(pdfThumbnailViewer) { this.pdfThumbnailViewer = pdfThumbnailViewer; } isHighestPriority(view) { return this.highestPriorityPage === view.renderingId; } renderHighestPriority(currentlyVisiblePages) { if (this.idleTimeout) { clearTimeout(this.idleTimeout); this.idleTimeout = null; } if (this.pdfViewer.forceRendering(currentlyVisiblePages)) { return; } if (this.pdfThumbnailViewer && this.isThumbnailViewEnabled) { if (this.pdfThumbnailViewer.forceRendering()) { return; } } if (this.printing) { return; } if (this.onIdle) { this.idleTimeout = setTimeout(this.onIdle.bind(this), CLEANUP_TIMEOUT); } } getHighestPriority(visible, views, scrolledDown) { const visibleViews = visible.views; const numVisible = visibleViews.length; if (numVisible === 0) { return null; } for (let i = 0; i < numVisible; ++i) { const view = visibleViews[i].view; if (!this.isViewFinished(view)) { return view; } } if (scrolledDown) { const nextPageIndex = visible.last.id; if (views[nextPageIndex] && !this.isViewFinished(views[nextPageIndex])) { return views[nextPageIndex]; } } else { const previousPageIndex = visible.first.id - 2; if (views[previousPageIndex] && !this.isViewFinished(views[previousPageIndex])) { return views[previousPageIndex]; } } return null; } isViewFinished(view) { return view.renderingState === RenderingStates.FINISHED; } renderView(view) { switch (view.renderingState) { case RenderingStates.FINISHED: return false; case RenderingStates.PAUSED: this.highestPriorityPage = view.renderingId; view.resume(); break; case RenderingStates.RUNNING: this.highestPriorityPage = view.renderingId; break; case RenderingStates.INITIAL: this.highestPriorityPage = view.renderingId; view.draw().finally(() => { this.renderHighestPriority(); }).catch(reason => { if (reason instanceof _pdfjsLib.RenderingCancelledException) { return; } console.error(`renderView: "${reason}"`); }); break; } return true; } } exports.PDFRenderingQueue = PDFRenderingQueue; /***/ }), /* 9 */ /***/ ((__unused_webpack_module, exports) => { Object.defineProperty(exports, "__esModule", ({ value: true })); exports.OverlayManager = void 0; class OverlayManager { constructor() { this._overlays = {}; this._active = null; this._keyDownBound = this._keyDown.bind(this); } get active() { return this._active; } async register(name, element, callerCloseMethod = null, canForceClose = false) { let container; if (!name || !element || !(container = element.parentNode)) { throw new Error("Not enough parameters."); } else if (this._overlays[name]) { throw new Error("The overlay is already registered."); } this._overlays[name] = { element, container, callerCloseMethod, canForceClose }; } async unregister(name) { if (!this._overlays[name]) { throw new Error("The overlay does not exist."); } else if (this._active === name) { throw new Error("The overlay cannot be removed while it is active."); } delete this._overlays[name]; } async open(name) { if (!this._overlays[name]) { throw new Error("The overlay does not exist."); } else if (this._active) { if (this._overlays[name].canForceClose) { this._closeThroughCaller(); } else if (this._active === name) { throw new Error("The overlay is already active."); } else { throw new Error("Another overlay is currently active."); } } this._active = name; this._overlays[this._active].element.classList.remove("hidden"); this._overlays[this._active].container.classList.remove("hidden"); window.addEventListener("keydown", this._keyDownBound); } async close(name) { if (!this._overlays[name]) { throw new Error("The overlay does not exist."); } else if (!this._active) { throw new Error("The overlay is currently not active."); } else if (this._active !== name) { throw new Error("Another overlay is currently active."); } this._overlays[this._active].container.classList.add("hidden"); this._overlays[this._active].element.classList.add("hidden"); this._active = null; window.removeEventListener("keydown", this._keyDownBound); } _keyDown(evt) { if (this._active && evt.keyCode === 27) { this._closeThroughCaller(); evt.preventDefault(); } } _closeThroughCaller() { if (this._overlays[this._active].callerCloseMethod) { this._overlays[this._active].callerCloseMethod(); } if (this._active) { this.close(this._active); } } } exports.OverlayManager = OverlayManager; /***/ }), /* 10 */ /***/ ((__unused_webpack_module, exports, __webpack_require__) => { Object.defineProperty(exports, "__esModule", ({ value: true })); exports.PasswordPrompt = void 0; var _pdfjsLib = __webpack_require__(5); class PasswordPrompt { constructor(options, overlayManager, l10n, isViewerEmbedded = false) { this.overlayName = options.overlayName; this.container = options.container; this.label = options.label; this.input = options.input; this.submitButton = options.submitButton; this.cancelButton = options.cancelButton; this.overlayManager = overlayManager; this.l10n = l10n; this._isViewerEmbedded = isViewerEmbedded; this.updateCallback = null; this.reason = null; this.submitButton.addEventListener("click", this.verify.bind(this)); this.cancelButton.addEventListener("click", this.close.bind(this)); this.input.addEventListener("keydown", e => { if (e.keyCode === 13) { this.verify(); } }); this.overlayManager.register(this.overlayName, this.container, this.close.bind(this), true); } async open() { await this.overlayManager.open(this.overlayName); const passwordIncorrect = this.reason === _pdfjsLib.PasswordResponses.INCORRECT_PASSWORD; if (!this._isViewerEmbedded || passwordIncorrect) { this.input.focus(); } this.label.textContent = await this.l10n.get(`password_${passwordIncorrect ? "invalid" : "label"}`); } close() { this.overlayManager.close(this.overlayName).then(() => { this.input.value = ""; }); } verify() { const password = this.input.value; if (password?.length > 0) { this.close(); this.updateCallback(password); } } setUpdateCallback(updateCallback, reason) { this.updateCallback = updateCallback; this.reason = reason; } } exports.PasswordPrompt = PasswordPrompt; /***/ }), /* 11 */ /***/ ((__unused_webpack_module, exports, __webpack_require__) => { Object.defineProperty(exports, "__esModule", ({ value: true })); exports.PDFAttachmentViewer = void 0; var _pdfjsLib = __webpack_require__(5); var _base_tree_viewer = __webpack_require__(12); class PDFAttachmentViewer extends _base_tree_viewer.BaseTreeViewer { constructor(options) { super(options); this.downloadManager = options.downloadManager; this.eventBus._on("fileattachmentannotation", this._appendAttachment.bind(this)); } reset(keepRenderedCapability = false) { super.reset(); this._attachments = null; if (!keepRenderedCapability) { this._renderedCapability = (0, _pdfjsLib.createPromiseCapability)(); } if (this._pendingDispatchEvent) { clearTimeout(this._pendingDispatchEvent); } this._pendingDispatchEvent = null; } _dispatchEvent(attachmentsCount) { this._renderedCapability.resolve(); if (this._pendingDispatchEvent) { clearTimeout(this._pendingDispatchEvent); this._pendingDispatchEvent = null; } if (attachmentsCount === 0) { this._pendingDispatchEvent = setTimeout(() => { this.eventBus.dispatch("attachmentsloaded", { source: this, attachmentsCount: 0 }); this._pendingDispatchEvent = null; }); return; } this.eventBus.dispatch("attachmentsloaded", { source: this, attachmentsCount }); } _bindLink(element, { content, filename }) { element.onclick = () => { this.downloadManager.openOrDownloadData(element, content, filename); return false; }; } render({ attachments, keepRenderedCapability = false }) { if (this._attachments) { this.reset(keepRenderedCapability); } this._attachments = attachments || null; if (!attachments) { this._dispatchEvent(0); return; } const names = Object.keys(attachments).sort(function (a, b) { return a.toLowerCase().localeCompare(b.toLowerCase()); }); const fragment = document.createDocumentFragment(); let attachmentsCount = 0; for (const name of names) { const item = attachments[name]; const content = item.content, filename = (0, _pdfjsLib.getFilenameFromUrl)(item.filename); const div = document.createElement("div"); div.className = "treeItem"; const element = document.createElement("a"); this._bindLink(element, { content, filename }); element.textContent = this._normalizeTextContent(filename); div.appendChild(element); fragment.appendChild(div); attachmentsCount++; } this._finishRendering(fragment, attachmentsCount); } _appendAttachment({ id, filename, content }) { const renderedPromise = this._renderedCapability.promise; renderedPromise.then(() => { if (renderedPromise !== this._renderedCapability.promise) { return; } let attachments = this._attachments; if (!attachments) { attachments = Object.create(null); } else { for (const name in attachments) { if (id === name) { return; } } } attachments[id] = { filename, content }; this.render({ attachments, keepRenderedCapability: true }); }); } } exports.PDFAttachmentViewer = PDFAttachmentViewer; /***/ }), /* 12 */ /***/ ((__unused_webpack_module, exports, __webpack_require__) => { Object.defineProperty(exports, "__esModule", ({ value: true })); exports.BaseTreeViewer = void 0; var _pdfjsLib = __webpack_require__(5); const TREEITEM_OFFSET_TOP = -100; const TREEITEM_SELECTED_CLASS = "selected"; class BaseTreeViewer { constructor(options) { if (this.constructor === BaseTreeViewer) { throw new Error("Cannot initialize BaseTreeViewer."); } this.container = options.container; this.eventBus = options.eventBus; this.reset(); } reset() { this._pdfDocument = null; this._lastToggleIsShow = true; this._currentTreeItem = null; this.container.textContent = ""; this.container.classList.remove("treeWithDeepNesting"); } _dispatchEvent(count) { throw new Error("Not implemented: _dispatchEvent"); } _bindLink(element, params) { throw new Error("Not implemented: _bindLink"); } _normalizeTextContent(str) { return (0, _pdfjsLib.removeNullCharacters)(str) || "\u2013"; } _addToggleButton(div, hidden = false) { const toggler = document.createElement("div"); toggler.className = "treeItemToggler"; if (hidden) { toggler.classList.add("treeItemsHidden"); } toggler.onclick = evt => { evt.stopPropagation(); toggler.classList.toggle("treeItemsHidden"); if (evt.shiftKey) { const shouldShowAll = !toggler.classList.contains("treeItemsHidden"); this._toggleTreeItem(div, shouldShowAll); } }; div.insertBefore(toggler, div.firstChild); } _toggleTreeItem(root, show = false) { this._lastToggleIsShow = show; for (const toggler of root.querySelectorAll(".treeItemToggler")) { toggler.classList.toggle("treeItemsHidden", !show); } } _toggleAllTreeItems() { this._toggleTreeItem(this.container, !this._lastToggleIsShow); } _finishRendering(fragment, count, hasAnyNesting = false) { if (hasAnyNesting) { this.container.classList.add("treeWithDeepNesting"); this._lastToggleIsShow = !fragment.querySelector(".treeItemsHidden"); } this.container.appendChild(fragment); this._dispatchEvent(count); } render(params) { throw new Error("Not implemented: render"); } _updateCurrentTreeItem(treeItem = null) { if (this._currentTreeItem) { this._currentTreeItem.classList.remove(TREEITEM_SELECTED_CLASS); this._currentTreeItem = null; } if (treeItem) { treeItem.classList.add(TREEITEM_SELECTED_CLASS); this._currentTreeItem = treeItem; } } _scrollToCurrentTreeItem(treeItem) { if (!treeItem) { return; } let currentNode = treeItem.parentNode; while (currentNode && currentNode !== this.container) { if (currentNode.classList.contains("treeItem")) { const toggler = currentNode.firstElementChild; toggler?.classList.remove("treeItemsHidden"); } currentNode = currentNode.parentNode; } this._updateCurrentTreeItem(treeItem); this.container.scrollTo(treeItem.offsetLeft, treeItem.offsetTop + TREEITEM_OFFSET_TOP); } } exports.BaseTreeViewer = BaseTreeViewer; /***/ }), /* 13 */ /***/ ((__unused_webpack_module, exports, __webpack_require__) => { Object.defineProperty(exports, "__esModule", ({ value: true })); exports.PDFDocumentProperties = void 0; var _pdfjsLib = __webpack_require__(5); var _ui_utils = __webpack_require__(4); const DEFAULT_FIELD_CONTENT = "-"; const NON_METRIC_LOCALES = ["en-us", "en-lr", "my"]; const US_PAGE_NAMES = { "8.5x11": "Letter", "8.5x14": "Legal" }; const METRIC_PAGE_NAMES = { "297x420": "A3", "210x297": "A4" }; function getPageName(size, isPortrait, pageNames) { const width = isPortrait ? size.width : size.height; const height = isPortrait ? size.height : size.width; return pageNames[`${width}x${height}`]; } class PDFDocumentProperties { constructor({ overlayName, fields, container, closeButton }, overlayManager, eventBus, l10n) { this.overlayName = overlayName; this.fields = fields; this.container = container; this.overlayManager = overlayManager; this.l10n = l10n; this._reset(); closeButton.addEventListener("click", this.close.bind(this)); this.overlayManager.register(this.overlayName, this.container, this.close.bind(this)); eventBus._on("pagechanging", evt => { this._currentPageNumber = evt.pageNumber; }); eventBus._on("rotationchanging", evt => { this._pagesRotation = evt.pagesRotation; }); this._isNonMetricLocale = true; l10n.getLanguage().then(locale => { this._isNonMetricLocale = NON_METRIC_LOCALES.includes(locale); }); } async open() { const freezeFieldData = data => { Object.defineProperty(this, "fieldData", { value: Object.freeze(data), writable: false, enumerable: true, configurable: true }); }; await Promise.all([this.overlayManager.open(this.overlayName), this._dataAvailableCapability.promise]); const currentPageNumber = this._currentPageNumber; const pagesRotation = this._pagesRotation; if (this.fieldData && currentPageNumber === this.fieldData._currentPageNumber && pagesRotation === this.fieldData._pagesRotation) { this._updateUI(); return; } const { info, contentDispositionFilename, contentLength } = await this.pdfDocument.getMetadata(); const [fileName, fileSize, creationDate, modificationDate, pageSize, isLinearized] = await Promise.all([contentDispositionFilename || (0, _pdfjsLib.getPdfFilenameFromUrl)(this.url), this._parseFileSize(contentLength), this._parseDate(info.CreationDate), this._parseDate(info.ModDate), this.pdfDocument.getPage(currentPageNumber).then(pdfPage => { return this._parsePageSize((0, _ui_utils.getPageSizeInches)(pdfPage), pagesRotation); }), this._parseLinearization(info.IsLinearized)]); freezeFieldData({ fileName, fileSize, title: info.Title, author: info.Author, subject: info.Subject, keywords: info.Keywords, creationDate, modificationDate, creator: info.Creator, producer: info.Producer, version: info.PDFFormatVersion, pageCount: this.pdfDocument.numPages, pageSize, linearized: isLinearized, _currentPageNumber: currentPageNumber, _pagesRotation: pagesRotation }); this._updateUI(); const { length } = await this.pdfDocument.getDownloadInfo(); if (contentLength === length) { return; } const data = Object.assign(Object.create(null), this.fieldData); data.fileSize = await this._parseFileSize(length); freezeFieldData(data); this._updateUI(); } close() { this.overlayManager.close(this.overlayName); } setDocument(pdfDocument, url = null) { if (this.pdfDocument) { this._reset(); this._updateUI(true); } if (!pdfDocument) { return; } this.pdfDocument = pdfDocument; this.url = url; this._dataAvailableCapability.resolve(); } _reset() { this.pdfDocument = null; this.url = null; delete this.fieldData; this._dataAvailableCapability = (0, _pdfjsLib.createPromiseCapability)(); this._currentPageNumber = 1; this._pagesRotation = 0; } _updateUI(reset = false) { if (reset || !this.fieldData) { for (const id in this.fields) { this.fields[id].textContent = DEFAULT_FIELD_CONTENT; } return; } if (this.overlayManager.active !== this.overlayName) { return; } for (const id in this.fields) { const content = this.fieldData[id]; this.fields[id].textContent = content || content === 0 ? content : DEFAULT_FIELD_CONTENT; } } async _parseFileSize(fileSize = 0) { const kb = fileSize / 1024, mb = kb / 1024; if (!kb) { return undefined; } return this.l10n.get(`document_properties_${mb >= 1 ? "mb" : "kb"}`, { size_mb: mb >= 1 && (+mb.toPrecision(3)).toLocaleString(), size_kb: mb < 1 && (+kb.toPrecision(3)).toLocaleString(), size_b: fileSize.toLocaleString() }); } async _parsePageSize(pageSizeInches, pagesRotation) { if (!pageSizeInches) { return undefined; } if (pagesRotation % 180 !== 0) { pageSizeInches = { width: pageSizeInches.height, height: pageSizeInches.width }; } const isPortrait = (0, _ui_utils.isPortraitOrientation)(pageSizeInches); let sizeInches = { width: Math.round(pageSizeInches.width * 100) / 100, height: Math.round(pageSizeInches.height * 100) / 100 }; let sizeMillimeters = { width: Math.round(pageSizeInches.width * 25.4 * 10) / 10, height: Math.round(pageSizeInches.height * 25.4 * 10) / 10 }; let rawName = getPageName(sizeInches, isPortrait, US_PAGE_NAMES) || getPageName(sizeMillimeters, isPortrait, METRIC_PAGE_NAMES); if (!rawName && !(Number.isInteger(sizeMillimeters.width) && Number.isInteger(sizeMillimeters.height))) { const exactMillimeters = { width: pageSizeInches.width * 25.4, height: pageSizeInches.height * 25.4 }; const intMillimeters = { width: Math.round(sizeMillimeters.width), height: Math.round(sizeMillimeters.height) }; if (Math.abs(exactMillimeters.width - intMillimeters.width) < 0.1 && Math.abs(exactMillimeters.height - intMillimeters.height) < 0.1) { rawName = getPageName(intMillimeters, isPortrait, METRIC_PAGE_NAMES); if (rawName) { sizeInches = { width: Math.round(intMillimeters.width / 25.4 * 100) / 100, height: Math.round(intMillimeters.height / 25.4 * 100) / 100 }; sizeMillimeters = intMillimeters; } } } const [{ width, height }, unit, name, orientation] = await Promise.all([this._isNonMetricLocale ? sizeInches : sizeMillimeters, this.l10n.get(`document_properties_page_size_unit_${this._isNonMetricLocale ? "inches" : "millimeters"}`), rawName && this.l10n.get(`document_properties_page_size_name_${rawName.toLowerCase()}`), this.l10n.get(`document_properties_page_size_orientation_${isPortrait ? "portrait" : "landscape"}`)]); return this.l10n.get(`document_properties_page_size_dimension_${name ? "name_" : ""}string`, { width: width.toLocaleString(), height: height.toLocaleString(), unit, name, orientation }); } async _parseDate(inputDate) { const dateObject = _pdfjsLib.PDFDateString.toDateObject(inputDate); if (!dateObject) { return undefined; } return this.l10n.get("document_properties_date_string", { date: dateObject.toLocaleDateString(), time: dateObject.toLocaleTimeString() }); } _parseLinearization(isLinearized) { return this.l10n.get(`document_properties_linearized_${isLinearized ? "yes" : "no"}`); } } exports.PDFDocumentProperties = PDFDocumentProperties; /***/ }), /* 14 */ /***/ ((__unused_webpack_module, exports, __webpack_require__) => { Object.defineProperty(exports, "__esModule", ({ value: true })); exports.PDFFindBar = void 0; var _pdf_find_controller = __webpack_require__(15); const MATCHES_COUNT_LIMIT = 1000; class PDFFindBar { constructor(options, eventBus, l10n) { this.opened = false; this.bar = options.bar; this.toggleButton = options.toggleButton; this.findField = options.findField; this.highlightAll = options.highlightAllCheckbox; this.caseSensitive = options.caseSensitiveCheckbox; this.entireWord = options.entireWordCheckbox; this.findMsg = options.findMsg; this.findResultsCount = options.findResultsCount; this.findPreviousButton = options.findPreviousButton; this.findNextButton = options.findNextButton; this.eventBus = eventBus; this.l10n = l10n; this.toggleButton.addEventListener("click", () => { this.toggle(); }); this.findField.addEventListener("input", () => { this.dispatchEvent(""); }); this.bar.addEventListener("keydown", e => { switch (e.keyCode) { case 13: if (e.target === this.findField) { this.dispatchEvent("again", e.shiftKey); } break; case 27: this.close(); break; } }); this.findPreviousButton.addEventListener("click", () => { this.dispatchEvent("again", true); }); this.findNextButton.addEventListener("click", () => { this.dispatchEvent("again", false); }); this.highlightAll.addEventListener("click", () => { this.dispatchEvent("highlightallchange"); }); this.caseSensitive.addEventListener("click", () => { this.dispatchEvent("casesensitivitychange"); }); this.entireWord.addEventListener("click", () => { this.dispatchEvent("entirewordchange"); }); this.eventBus._on("resize", this._adjustWidth.bind(this)); } reset() { this.updateUIState(); } dispatchEvent(type, findPrev) { this.eventBus.dispatch("find", { source: this, type, query: this.findField.value, phraseSearch: true, caseSensitive: this.caseSensitive.checked, entireWord: this.entireWord.checked, highlightAll: this.highlightAll.checked, findPrevious: findPrev }); } updateUIState(state, previous, matchesCount) { let findMsg = Promise.resolve(""); let status = ""; switch (state) { case _pdf_find_controller.FindState.FOUND: break; case _pdf_find_controller.FindState.PENDING: status = "pending"; break; case _pdf_find_controller.FindState.NOT_FOUND: findMsg = this.l10n.get("find_not_found"); status = "notFound"; break; case _pdf_find_controller.FindState.WRAPPED: findMsg = this.l10n.get(`find_reached_${previous ? "top" : "bottom"}`); break; } this.findField.setAttribute("data-status", status); findMsg.then(msg => { this.findMsg.textContent = msg; this._adjustWidth(); }); this.updateResultsCount(matchesCount); } updateResultsCount({ current = 0, total = 0 } = {}) { const limit = MATCHES_COUNT_LIMIT; let matchCountMsg = Promise.resolve(""); if (total > 0) { if (total > limit) { let key = "find_match_count_limit"; matchCountMsg = this.l10n.get(key, { limit }); } else { let key = "find_match_count"; matchCountMsg = this.l10n.get(key, { current, total }); } } matchCountMsg.then(msg => { this.findResultsCount.textContent = msg; this.findResultsCount.classList.toggle("hidden", !total); this._adjustWidth(); }); } open() { if (!this.opened) { this.opened = true; this.toggleButton.classList.add("toggled"); this.toggleButton.setAttribute("aria-expanded", "true"); this.bar.classList.remove("hidden"); } this.findField.select(); this.findField.focus(); this._adjustWidth(); } close() { if (!this.opened) { return; } this.opened = false; this.toggleButton.classList.remove("toggled"); this.toggleButton.setAttribute("aria-expanded", "false"); this.bar.classList.add("hidden"); this.eventBus.dispatch("findbarclose", { source: this }); } toggle() { if (this.opened) { this.close(); } else { this.open(); } } _adjustWidth() { if (!this.opened) { return; } this.bar.classList.remove("wrapContainers"); const findbarHeight = this.bar.clientHeight; const inputContainerHeight = this.bar.firstElementChild.clientHeight; if (findbarHeight > inputContainerHeight) { this.bar.classList.add("wrapContainers"); } } } exports.PDFFindBar = PDFFindBar; /***/ }), /* 15 */ /***/ ((__unused_webpack_module, exports, __webpack_require__) => { Object.defineProperty(exports, "__esModule", ({ value: true })); exports.PDFFindController = exports.FindState = void 0; var _pdfjsLib = __webpack_require__(5); var _pdf_find_utils = __webpack_require__(16); var _ui_utils = __webpack_require__(4); const FindState = { FOUND: 0, NOT_FOUND: 1, WRAPPED: 2, PENDING: 3 }; exports.FindState = FindState; const FIND_TIMEOUT = 250; const MATCH_SCROLL_OFFSET_TOP = -50; const MATCH_SCROLL_OFFSET_LEFT = -400; const CHARACTERS_TO_NORMALIZE = { "\u2018": "'", "\u2019": "'", "\u201A": "'", "\u201B": "'", "\u201C": '"', "\u201D": '"', "\u201E": '"', "\u201F": '"', "\u00BC": "1/4", "\u00BD": "1/2", "\u00BE": "3/4" }; let normalizationRegex = null; function normalize(text) { if (!normalizationRegex) { const replace = Object.keys(CHARACTERS_TO_NORMALIZE).join(""); normalizationRegex = new RegExp(`[${replace}]`, "g"); } let diffs = null; const normalizedText = text.replace(normalizationRegex, function (ch, index) { const normalizedCh = CHARACTERS_TO_NORMALIZE[ch], diff = normalizedCh.length - ch.length; if (diff !== 0) { (diffs || (diffs = [])).push([index, diff]); } return normalizedCh; }); return [normalizedText, diffs]; } function getOriginalIndex(matchIndex, diffs = null) { if (!diffs) { return matchIndex; } let totalDiff = 0; for (const [index, diff] of diffs) { const currentIndex = index + totalDiff; if (currentIndex >= matchIndex) { break; } if (currentIndex + diff > matchIndex) { totalDiff += matchIndex - currentIndex; break; } totalDiff += diff; } return matchIndex - totalDiff; } class PDFFindController { constructor({ linkService, eventBus }) { this._linkService = linkService; this._eventBus = eventBus; this._reset(); eventBus._on("findbarclose", this._onFindBarClose.bind(this)); } get highlightMatches() { return this._highlightMatches; } get pageMatches() { return this._pageMatches; } get pageMatchesLength() { return this._pageMatchesLength; } get selected() { return this._selected; } get state() { return this._state; } setDocument(pdfDocument) { if (this._pdfDocument) { this._reset(); } if (!pdfDocument) { return; } this._pdfDocument = pdfDocument; this._firstPageCapability.resolve(); } executeCommand(cmd, state) { if (!state) { return; } const pdfDocument = this._pdfDocument; if (this._state === null || this._shouldDirtyMatch(cmd, state)) { this._dirtyMatch = true; } this._state = state; if (cmd !== "findhighlightallchange") { this._updateUIState(FindState.PENDING); } this._firstPageCapability.promise.then(() => { if (!this._pdfDocument || pdfDocument && this._pdfDocument !== pdfDocument) { return; } this._extractText(); const findbarClosed = !this._highlightMatches; const pendingTimeout = !!this._findTimeout; if (this._findTimeout) { clearTimeout(this._findTimeout); this._findTimeout = null; } if (cmd === "find") { this._findTimeout = setTimeout(() => { this._nextMatch(); this._findTimeout = null; }, FIND_TIMEOUT); } else if (this._dirtyMatch) { this._nextMatch(); } else if (cmd === "findagain") { this._nextMatch(); if (findbarClosed && this._state.highlightAll) { this._updateAllPages(); } } else if (cmd === "findhighlightallchange") { if (pendingTimeout) { this._nextMatch(); } else { this._highlightMatches = true; } this._updateAllPages(); } else { this._nextMatch(); } }); } scrollMatchIntoView({ element = null, pageIndex = -1, matchIndex = -1 }) { if (!this._scrollMatches || !element) { return; } else if (matchIndex === -1 || matchIndex !== this._selected.matchIdx) { return; } else if (pageIndex === -1 || pageIndex !== this._selected.pageIdx) { return; } this._scrollMatches = false; const spot = { top: MATCH_SCROLL_OFFSET_TOP, left: MATCH_SCROLL_OFFSET_LEFT }; (0, _ui_utils.scrollIntoView)(element, spot, true); } _reset() { this._highlightMatches = false; this._scrollMatches = false; this._pdfDocument = null; this._pageMatches = []; this._pageMatchesLength = []; this._state = null; this._selected = { pageIdx: -1, matchIdx: -1 }; this._offset = { pageIdx: null, matchIdx: null, wrapped: false }; this._extractTextPromises = []; this._pageContents = []; this._pageDiffs = []; this._matchesCountTotal = 0; this._pagesToSearch = null; this._pendingFindMatches = Object.create(null); this._resumePageIdx = null; this._dirtyMatch = false; clearTimeout(this._findTimeout); this._findTimeout = null; this._firstPageCapability = (0, _pdfjsLib.createPromiseCapability)(); } get _query() { if (this._state.query !== this._rawQuery) { this._rawQuery = this._state.query; [this._normalizedQuery] = normalize(this._state.query); } return this._normalizedQuery; } _shouldDirtyMatch(cmd, state) { if (state.query !== this._state.query) { return true; } switch (cmd) { case "findagain": const pageNumber = this._selected.pageIdx + 1; const linkService = this._linkService; if (pageNumber >= 1 && pageNumber <= linkService.pagesCount && pageNumber !== linkService.page && !linkService.isPageVisible(pageNumber)) { return true; } return false; case "findhighlightallchange": return false; } return true; } _prepareMatches(matchesWithLength, matches, matchesLength) { function isSubTerm(currentIndex) { const currentElem = matchesWithLength[currentIndex]; const nextElem = matchesWithLength[currentIndex + 1]; if (currentIndex < matchesWithLength.length - 1 && currentElem.match === nextElem.match) { currentElem.skipped = true; return true; } for (let i = currentIndex - 1; i >= 0; i--) { const prevElem = matchesWithLength[i]; if (prevElem.skipped) { continue; } if (prevElem.match + prevElem.matchLength < currentElem.match) { break; } if (prevElem.match + prevElem.matchLength >= currentElem.match + currentElem.matchLength) { currentElem.skipped = true; return true; } } return false; } matchesWithLength.sort(function (a, b) { return a.match === b.match ? a.matchLength - b.matchLength : a.match - b.match; }); for (let i = 0, len = matchesWithLength.length; i < len; i++) { if (isSubTerm(i)) { continue; } matches.push(matchesWithLength[i].match); matchesLength.push(matchesWithLength[i].matchLength); } } _isEntireWord(content, startIdx, length) { if (startIdx > 0) { const first = content.charCodeAt(startIdx); const limit = content.charCodeAt(startIdx - 1); if ((0, _pdf_find_utils.getCharacterType)(first) === (0, _pdf_find_utils.getCharacterType)(limit)) { return false; } } const endIdx = startIdx + length - 1; if (endIdx < content.length - 1) { const last = content.charCodeAt(endIdx); const limit = content.charCodeAt(endIdx + 1); if ((0, _pdf_find_utils.getCharacterType)(last) === (0, _pdf_find_utils.getCharacterType)(limit)) { return false; } } return true; } _calculatePhraseMatch(query, pageIndex, pageContent, pageDiffs, entireWord) { const matches = [], matchesLength = []; const queryLen = query.length; let matchIdx = -queryLen; while (true) { matchIdx = pageContent.indexOf(query, matchIdx + queryLen); if (matchIdx === -1) { break; } if (entireWord && !this._isEntireWord(pageContent, matchIdx, queryLen)) { continue; } const originalMatchIdx = getOriginalIndex(matchIdx, pageDiffs), matchEnd = matchIdx + queryLen - 1, originalQueryLen = getOriginalIndex(matchEnd, pageDiffs) - originalMatchIdx + 1; matches.push(originalMatchIdx); matchesLength.push(originalQueryLen); } this._pageMatches[pageIndex] = matches; this._pageMatchesLength[pageIndex] = matchesLength; } _calculateWordMatch(query, pageIndex, pageContent, pageDiffs, entireWord) { const matchesWithLength = []; const queryArray = query.match(/\S+/g); for (let i = 0, len = queryArray.length; i < len; i++) { const subquery = queryArray[i]; const subqueryLen = subquery.length; let matchIdx = -subqueryLen; while (true) { matchIdx = pageContent.indexOf(subquery, matchIdx + subqueryLen); if (matchIdx === -1) { break; } if (entireWord && !this._isEntireWord(pageContent, matchIdx, subqueryLen)) { continue; } const originalMatchIdx = getOriginalIndex(matchIdx, pageDiffs), matchEnd = matchIdx + subqueryLen - 1, originalQueryLen = getOriginalIndex(matchEnd, pageDiffs) - originalMatchIdx + 1; matchesWithLength.push({ match: originalMatchIdx, matchLength: originalQueryLen, skipped: false }); } } this._pageMatchesLength[pageIndex] = []; this._pageMatches[pageIndex] = []; this._prepareMatches(matchesWithLength, this._pageMatches[pageIndex], this._pageMatchesLength[pageIndex]); } _calculateMatch(pageIndex) { let pageContent = this._pageContents[pageIndex]; const pageDiffs = this._pageDiffs[pageIndex]; let query = this._query; const { caseSensitive, entireWord, phraseSearch } = this._state; if (query.length === 0) { return; } if (!caseSensitive) { pageContent = pageContent.toLowerCase(); query = query.toLowerCase(); } if (phraseSearch) { this._calculatePhraseMatch(query, pageIndex, pageContent, pageDiffs, entireWord); } else { this._calculateWordMatch(query, pageIndex, pageContent, pageDiffs, entireWord); } if (this._state.highlightAll) { this._updatePage(pageIndex); } if (this._resumePageIdx === pageIndex) { this._resumePageIdx = null; this._nextPageMatch(); } const pageMatchesCount = this._pageMatches[pageIndex].length; if (pageMatchesCount > 0) { this._matchesCountTotal += pageMatchesCount; this._updateUIResultsCount(); } } _extractText() { if (this._extractTextPromises.length > 0) { return; } let promise = Promise.resolve(); for (let i = 0, ii = this._linkService.pagesCount; i < ii; i++) { const extractTextCapability = (0, _pdfjsLib.createPromiseCapability)(); this._extractTextPromises[i] = extractTextCapability.promise; promise = promise.then(() => { return this._pdfDocument.getPage(i + 1).then(pdfPage => { return pdfPage.getTextContent({ normalizeWhitespace: true }); }).then(textContent => { const textItems = textContent.items; const strBuf = []; for (let j = 0, jj = textItems.length; j < jj; j++) { strBuf.push(textItems[j].str); } [this._pageContents[i], this._pageDiffs[i]] = normalize(strBuf.join("")); extractTextCapability.resolve(i); }, reason => { console.error(`Unable to get text content for page ${i + 1}`, reason); this._pageContents[i] = ""; this._pageDiffs[i] = null; extractTextCapability.resolve(i); }); }); } } _updatePage(index) { if (this._scrollMatches && this._selected.pageIdx === index) { this._linkService.page = index + 1; } this._eventBus.dispatch("updatetextlayermatches", { source: this, pageIndex: index }); } _updateAllPages() { this._eventBus.dispatch("updatetextlayermatches", { source: this, pageIndex: -1 }); } _nextMatch() { const previous = this._state.findPrevious; const currentPageIndex = this._linkService.page - 1; const numPages = this._linkService.pagesCount; this._highlightMatches = true; if (this._dirtyMatch) { this._dirtyMatch = false; this._selected.pageIdx = this._selected.matchIdx = -1; this._offset.pageIdx = currentPageIndex; this._offset.matchIdx = null; this._offset.wrapped = false; this._resumePageIdx = null; this._pageMatches.length = 0; this._pageMatchesLength.length = 0; this._matchesCountTotal = 0; this._updateAllPages(); for (let i = 0; i < numPages; i++) { if (this._pendingFindMatches[i] === true) { continue; } this._pendingFindMatches[i] = true; this._extractTextPromises[i].then(pageIdx => { delete this._pendingFindMatches[pageIdx]; this._calculateMatch(pageIdx); }); } } if (this._query === "") { this._updateUIState(FindState.FOUND); return; } if (this._resumePageIdx) { return; } const offset = this._offset; this._pagesToSearch = numPages; if (offset.matchIdx !== null) { const numPageMatches = this._pageMatches[offset.pageIdx].length; if (!previous && offset.matchIdx + 1 < numPageMatches || previous && offset.matchIdx > 0) { offset.matchIdx = previous ? offset.matchIdx - 1 : offset.matchIdx + 1; this._updateMatch(true); return; } this._advanceOffsetPage(previous); } this._nextPageMatch(); } _matchesReady(matches) { const offset = this._offset; const numMatches = matches.length; const previous = this._state.findPrevious; if (numMatches) { offset.matchIdx = previous ? numMatches - 1 : 0; this._updateMatch(true); return true; } this._advanceOffsetPage(previous); if (offset.wrapped) { offset.matchIdx = null; if (this._pagesToSearch < 0) { this._updateMatch(false); return true; } } return false; } _nextPageMatch() { if (this._resumePageIdx !== null) { console.error("There can only be one pending page."); } let matches = null; do { const pageIdx = this._offset.pageIdx; matches = this._pageMatches[pageIdx]; if (!matches) { this._resumePageIdx = pageIdx; break; } } while (!this._matchesReady(matches)); } _advanceOffsetPage(previous) { const offset = this._offset; const numPages = this._linkService.pagesCount; offset.pageIdx = previous ? offset.pageIdx - 1 : offset.pageIdx + 1; offset.matchIdx = null; this._pagesToSearch--; if (offset.pageIdx >= numPages || offset.pageIdx < 0) { offset.pageIdx = previous ? numPages - 1 : 0; offset.wrapped = true; } } _updateMatch(found = false) { let state = FindState.NOT_FOUND; const wrapped = this._offset.wrapped; this._offset.wrapped = false; if (found) { const previousPage = this._selected.pageIdx; this._selected.pageIdx = this._offset.pageIdx; this._selected.matchIdx = this._offset.matchIdx; state = wrapped ? FindState.WRAPPED : FindState.FOUND; if (previousPage !== -1 && previousPage !== this._selected.pageIdx) { this._updatePage(previousPage); } } this._updateUIState(state, this._state.findPrevious); if (this._selected.pageIdx !== -1) { this._scrollMatches = true; this._updatePage(this._selected.pageIdx); } } _onFindBarClose(evt) { const pdfDocument = this._pdfDocument; this._firstPageCapability.promise.then(() => { if (!this._pdfDocument || pdfDocument && this._pdfDocument !== pdfDocument) { return; } if (this._findTimeout) { clearTimeout(this._findTimeout); this._findTimeout = null; } if (this._resumePageIdx) { this._resumePageIdx = null; this._dirtyMatch = true; } this._updateUIState(FindState.FOUND); this._highlightMatches = false; this._updateAllPages(); }); } _requestMatchesCount() { const { pageIdx, matchIdx } = this._selected; let current = 0, total = this._matchesCountTotal; if (matchIdx !== -1) { for (let i = 0; i < pageIdx; i++) { current += this._pageMatches[i]?.length || 0; } current += matchIdx + 1; } if (current < 1 || current > total) { current = total = 0; } return { current, total }; } _updateUIResultsCount() { this._eventBus.dispatch("updatefindmatchescount", { source: this, matchesCount: this._requestMatchesCount() }); } _updateUIState(state, previous) { this._eventBus.dispatch("updatefindcontrolstate", { source: this, state, previous, matchesCount: this._requestMatchesCount(), rawQuery: this._state?.query ?? null }); } } exports.PDFFindController = PDFFindController; /***/ }), /* 16 */ /***/ ((__unused_webpack_module, exports) => { Object.defineProperty(exports, "__esModule", ({ value: true })); exports.getCharacterType = getCharacterType; exports.CharacterType = void 0; const CharacterType = { SPACE: 0, ALPHA_LETTER: 1, PUNCT: 2, HAN_LETTER: 3, KATAKANA_LETTER: 4, HIRAGANA_LETTER: 5, HALFWIDTH_KATAKANA_LETTER: 6, THAI_LETTER: 7 }; exports.CharacterType = CharacterType; function isAlphabeticalScript(charCode) { return charCode < 0x2e80; } function isAscii(charCode) { return (charCode & 0xff80) === 0; } function isAsciiAlpha(charCode) { return charCode >= 0x61 && charCode <= 0x7a || charCode >= 0x41 && charCode <= 0x5a; } function isAsciiDigit(charCode) { return charCode >= 0x30 && charCode <= 0x39; } function isAsciiSpace(charCode) { return charCode === 0x20 || charCode === 0x09 || charCode === 0x0d || charCode === 0x0a; } function isHan(charCode) { return charCode >= 0x3400 && charCode <= 0x9fff || charCode >= 0xf900 && charCode <= 0xfaff; } function isKatakana(charCode) { return charCode >= 0x30a0 && charCode <= 0x30ff; } function isHiragana(charCode) { return charCode >= 0x3040 && charCode <= 0x309f; } function isHalfwidthKatakana(charCode) { return charCode >= 0xff60 && charCode <= 0xff9f; } function isThai(charCode) { return (charCode & 0xff80) === 0x0e00; } function getCharacterType(charCode) { if (isAlphabeticalScript(charCode)) { if (isAscii(charCode)) { if (isAsciiSpace(charCode)) { return CharacterType.SPACE; } else if (isAsciiAlpha(charCode) || isAsciiDigit(charCode) || charCode === 0x5f) { return CharacterType.ALPHA_LETTER; } return CharacterType.PUNCT; } else if (isThai(charCode)) { return CharacterType.THAI_LETTER; } else if (charCode === 0xa0) { return CharacterType.SPACE; } return CharacterType.ALPHA_LETTER; } if (isHan(charCode)) { return CharacterType.HAN_LETTER; } else if (isKatakana(charCode)) { return CharacterType.KATAKANA_LETTER; } else if (isHiragana(charCode)) { return CharacterType.HIRAGANA_LETTER; } else if (isHalfwidthKatakana(charCode)) { return CharacterType.HALFWIDTH_KATAKANA_LETTER; } return CharacterType.ALPHA_LETTER; } /***/ }), /* 17 */ /***/ ((__unused_webpack_module, exports, __webpack_require__) => { Object.defineProperty(exports, "__esModule", ({ value: true })); exports.isDestArraysEqual = isDestArraysEqual; exports.isDestHashesEqual = isDestHashesEqual; exports.PDFHistory = void 0; var _ui_utils = __webpack_require__(4); const HASH_CHANGE_TIMEOUT = 1000; const POSITION_UPDATED_THRESHOLD = 50; const UPDATE_VIEWAREA_TIMEOUT = 1000; function getCurrentHash() { return document.location.hash; } class PDFHistory { constructor({ linkService, eventBus }) { this.linkService = linkService; this.eventBus = eventBus; this._initialized = false; this._fingerprint = ""; this.reset(); this._boundEvents = null; this._isViewerInPresentationMode = false; this.eventBus._on("presentationmodechanged", evt => { this._isViewerInPresentationMode = evt.state !== _ui_utils.PresentationModeState.NORMAL; }); this.eventBus._on("pagesinit", () => { this._isPagesLoaded = false; this.eventBus._on("pagesloaded", evt => { this._isPagesLoaded = !!evt.pagesCount; }, { once: true }); }); } initialize({ fingerprint, resetHistory = false, updateUrl = false }) { if (!fingerprint || typeof fingerprint !== "string") { console.error('PDFHistory.initialize: The "fingerprint" must be a non-empty string.'); return; } if (this._initialized) { this.reset(); } const reInitialized = this._fingerprint !== "" && this._fingerprint !== fingerprint; this._fingerprint = fingerprint; this._updateUrl = updateUrl === true; this._initialized = true; this._bindEvents(); const state = window.history.state; this._popStateInProgress = false; this._blockHashChange = 0; this._currentHash = getCurrentHash(); this._numPositionUpdates = 0; this._uid = this._maxUid = 0; this._destination = null; this._position = null; if (!this._isValidState(state, true) || resetHistory) { const { hash, page, rotation } = this._parseCurrentHash(true); if (!hash || reInitialized || resetHistory) { this._pushOrReplaceState(null, true); return; } this._pushOrReplaceState({ hash, page, rotation }, true); return; } const destination = state.destination; this._updateInternalState(destination, state.uid, true); if (destination.rotation !== undefined) { this._initialRotation = destination.rotation; } if (destination.dest) { this._initialBookmark = JSON.stringify(destination.dest); this._destination.page = null; } else if (destination.hash) { this._initialBookmark = destination.hash; } else if (destination.page) { this._initialBookmark = `page=${destination.page}`; } } reset() { if (this._initialized) { this._pageHide(); this._initialized = false; this._unbindEvents(); } if (this._updateViewareaTimeout) { clearTimeout(this._updateViewareaTimeout); this._updateViewareaTimeout = null; } this._initialBookmark = null; this._initialRotation = null; } push({ namedDest = null, explicitDest, pageNumber }) { if (!this._initialized) { return; } if (namedDest && typeof namedDest !== "string") { console.error("PDFHistory.push: " + `"${namedDest}" is not a valid namedDest parameter.`); return; } else if (!Array.isArray(explicitDest)) { console.error("PDFHistory.push: " + `"${explicitDest}" is not a valid explicitDest parameter.`); return; } else if (!this._isValidPage(pageNumber)) { if (pageNumber !== null || this._destination) { console.error("PDFHistory.push: " + `"${pageNumber}" is not a valid pageNumber parameter.`); return; } } const hash = namedDest || JSON.stringify(explicitDest); if (!hash) { return; } let forceReplace = false; if (this._destination && (isDestHashesEqual(this._destination.hash, hash) || isDestArraysEqual(this._destination.dest, explicitDest))) { if (this._destination.page) { return; } forceReplace = true; } if (this._popStateInProgress && !forceReplace) { return; } this._pushOrReplaceState({ dest: explicitDest, hash, page: pageNumber, rotation: this.linkService.rotation }, forceReplace); if (!this._popStateInProgress) { this._popStateInProgress = true; Promise.resolve().then(() => { this._popStateInProgress = false; }); } } pushPage(pageNumber) { if (!this._initialized) { return; } if (!this._isValidPage(pageNumber)) { console.error(`PDFHistory.pushPage: "${pageNumber}" is not a valid page number.`); return; } if (this._destination?.page === pageNumber) { return; } if (this._popStateInProgress) { return; } this._pushOrReplaceState({ dest: null, hash: `page=${pageNumber}`, page: pageNumber, rotation: this.linkService.rotation }); if (!this._popStateInProgress) { this._popStateInProgress = true; Promise.resolve().then(() => { this._popStateInProgress = false; }); } } pushCurrentPosition() { if (!this._initialized || this._popStateInProgress) { return; } this._tryPushCurrentPosition(); } back() { if (!this._initialized || this._popStateInProgress) { return; } const state = window.history.state; if (this._isValidState(state) && state.uid > 0) { window.history.back(); } } forward() { if (!this._initialized || this._popStateInProgress) { return; } const state = window.history.state; if (this._isValidState(state) && state.uid < this._maxUid) { window.history.forward(); } } get popStateInProgress() { return this._initialized && (this._popStateInProgress || this._blockHashChange > 0); } get initialBookmark() { return this._initialized ? this._initialBookmark : null; } get initialRotation() { return this._initialized ? this._initialRotation : null; } _pushOrReplaceState(destination, forceReplace = false) { const shouldReplace = forceReplace || !this._destination; const newState = { fingerprint: this._fingerprint, uid: shouldReplace ? this._uid : this._uid + 1, destination }; this._updateInternalState(destination, newState.uid); let newUrl; if (this._updateUrl && destination?.hash) { const baseUrl = document.location.href.split("#")[0]; if (!baseUrl.startsWith("file://")) { newUrl = `${baseUrl}#${destination.hash}`; } } if (shouldReplace) { window.history.replaceState(newState, "", newUrl); } else { window.history.pushState(newState, "", newUrl); } } _tryPushCurrentPosition(temporary = false) { if (!this._position) { return; } let position = this._position; if (temporary) { position = Object.assign(Object.create(null), this._position); position.temporary = true; } if (!this._destination) { this._pushOrReplaceState(position); return; } if (this._destination.temporary) { this._pushOrReplaceState(position, true); return; } if (this._destination.hash === position.hash) { return; } if (!this._destination.page && (POSITION_UPDATED_THRESHOLD <= 0 || this._numPositionUpdates <= POSITION_UPDATED_THRESHOLD)) { return; } let forceReplace = false; if (this._destination.page >= position.first && this._destination.page <= position.page) { if (this._destination.dest !== undefined || !this._destination.first) { return; } forceReplace = true; } this._pushOrReplaceState(position, forceReplace); } _isValidPage(val) { return Number.isInteger(val) && val > 0 && val <= this.linkService.pagesCount; } _isValidState(state, checkReload = false) { if (!state) { return false; } if (state.fingerprint !== this._fingerprint) { if (checkReload) { if (typeof state.fingerprint !== "string" || state.fingerprint.length !== this._fingerprint.length) { return false; } const [perfEntry] = performance.getEntriesByType("navigation"); if (perfEntry?.type !== "reload") { return false; } } else { return false; } } if (!Number.isInteger(state.uid) || state.uid < 0) { return false; } if (state.destination === null || typeof state.destination !== "object") { return false; } return true; } _updateInternalState(destination, uid, removeTemporary = false) { if (this._updateViewareaTimeout) { clearTimeout(this._updateViewareaTimeout); this._updateViewareaTimeout = null; } if (removeTemporary && destination?.temporary) { delete destination.temporary; } this._destination = destination; this._uid = uid; this._maxUid = Math.max(this._maxUid, uid); this._numPositionUpdates = 0; } _parseCurrentHash(checkNameddest = false) { const hash = unescape(getCurrentHash()).substring(1); const params = (0, _ui_utils.parseQueryString)(hash); const nameddest = params.nameddest || ""; let page = params.page | 0; if (!this._isValidPage(page) || checkNameddest && nameddest.length > 0) { page = null; } return { hash, page, rotation: this.linkService.rotation }; } _updateViewarea({ location }) { if (this._updateViewareaTimeout) { clearTimeout(this._updateViewareaTimeout); this._updateViewareaTimeout = null; } this._position = { hash: this._isViewerInPresentationMode ? `page=${location.pageNumber}` : location.pdfOpenParams.substring(1), page: this.linkService.page, first: location.pageNumber, rotation: location.rotation }; if (this._popStateInProgress) { return; } if (POSITION_UPDATED_THRESHOLD > 0 && this._isPagesLoaded && this._destination && !this._destination.page) { this._numPositionUpdates++; } if (UPDATE_VIEWAREA_TIMEOUT > 0) { this._updateViewareaTimeout = setTimeout(() => { if (!this._popStateInProgress) { this._tryPushCurrentPosition(true); } this._updateViewareaTimeout = null; }, UPDATE_VIEWAREA_TIMEOUT); } } _popState({ state }) { const newHash = getCurrentHash(), hashChanged = this._currentHash !== newHash; this._currentHash = newHash; if (!state) { this._uid++; const { hash, page, rotation } = this._parseCurrentHash(); this._pushOrReplaceState({ hash, page, rotation }, true); return; } if (!this._isValidState(state)) { return; } this._popStateInProgress = true; if (hashChanged) { this._blockHashChange++; (0, _ui_utils.waitOnEventOrTimeout)({ target: window, name: "hashchange", delay: HASH_CHANGE_TIMEOUT }).then(() => { this._blockHashChange--; }); } const destination = state.destination; this._updateInternalState(destination, state.uid, true); if ((0, _ui_utils.isValidRotation)(destination.rotation)) { this.linkService.rotation = destination.rotation; } if (destination.dest) { this.linkService.goToDestination(destination.dest); } else if (destination.hash) { this.linkService.setHash(destination.hash); } else if (destination.page) { this.linkService.page = destination.page; } Promise.resolve().then(() => { this._popStateInProgress = false; }); } _pageHide() { if (!this._destination || this._destination.temporary) { this._tryPushCurrentPosition(); } } _bindEvents() { if (this._boundEvents) { return; } this._boundEvents = { updateViewarea: this._updateViewarea.bind(this), popState: this._popState.bind(this), pageHide: this._pageHide.bind(this) }; this.eventBus._on("updateviewarea", this._boundEvents.updateViewarea); window.addEventListener("popstate", this._boundEvents.popState); window.addEventListener("pagehide", this._boundEvents.pageHide); } _unbindEvents() { if (!this._boundEvents) { return; } this.eventBus._off("updateviewarea", this._boundEvents.updateViewarea); window.removeEventListener("popstate", this._boundEvents.popState); window.removeEventListener("pagehide", this._boundEvents.pageHide); this._boundEvents = null; } } exports.PDFHistory = PDFHistory; function isDestHashesEqual(destHash, pushHash) { if (typeof destHash !== "string" || typeof pushHash !== "string") { return false; } if (destHash === pushHash) { return true; } const { nameddest } = (0, _ui_utils.parseQueryString)(destHash); if (nameddest === pushHash) { return true; } return false; } function isDestArraysEqual(firstDest, secondDest) { function isEntryEqual(first, second) { if (typeof first !== typeof second) { return false; } if (Array.isArray(first) || Array.isArray(second)) { return false; } if (first !== null && typeof first === "object" && second !== null) { if (Object.keys(first).length !== Object.keys(second).length) { return false; } for (const key in first) { if (!isEntryEqual(first[key], second[key])) { return false; } } return true; } return first === second || Number.isNaN(first) && Number.isNaN(second); } if (!(Array.isArray(firstDest) && Array.isArray(secondDest))) { return false; } if (firstDest.length !== secondDest.length) { return false; } for (let i = 0, ii = firstDest.length; i < ii; i++) { if (!isEntryEqual(firstDest[i], secondDest[i])) { return false; } } return true; } /***/ }), /* 18 */ /***/ ((__unused_webpack_module, exports, __webpack_require__) => { Object.defineProperty(exports, "__esModule", ({ value: true })); exports.PDFLayerViewer = void 0; var _base_tree_viewer = __webpack_require__(12); class PDFLayerViewer extends _base_tree_viewer.BaseTreeViewer { constructor(options) { super(options); this.l10n = options.l10n; this.eventBus._on("resetlayers", this._resetLayers.bind(this)); this.eventBus._on("togglelayerstree", this._toggleAllTreeItems.bind(this)); } reset() { super.reset(); this._optionalContentConfig = null; } _dispatchEvent(layersCount) { this.eventBus.dispatch("layersloaded", { source: this, layersCount }); } _bindLink(element, { groupId, input }) { const setVisibility = () => { this._optionalContentConfig.setVisibility(groupId, input.checked); this.eventBus.dispatch("optionalcontentconfig", { source: this, promise: Promise.resolve(this._optionalContentConfig) }); }; element.onclick = evt => { if (evt.target === input) { setVisibility(); return true; } else if (evt.target !== element) { return true; } input.checked = !input.checked; setVisibility(); return false; }; } async _setNestedName(element, { name = null }) { if (typeof name === "string") { element.textContent = this._normalizeTextContent(name); return; } element.textContent = await this.l10n.get("additional_layers"); element.style.fontStyle = "italic"; } _addToggleButton(div, { name = null }) { super._addToggleButton(div, name === null); } _toggleAllTreeItems() { if (!this._optionalContentConfig) { return; } super._toggleAllTreeItems(); } render({ optionalContentConfig, pdfDocument }) { if (this._optionalContentConfig) { this.reset(); } this._optionalContentConfig = optionalContentConfig || null; this._pdfDocument = pdfDocument || null; const groups = optionalContentConfig?.getOrder(); if (!groups) { this._dispatchEvent(0); return; } const fragment = document.createDocumentFragment(), queue = [{ parent: fragment, groups }]; let layersCount = 0, hasAnyNesting = false; while (queue.length > 0) { const levelData = queue.shift(); for (const groupId of levelData.groups) { const div = document.createElement("div"); div.className = "treeItem"; const element = document.createElement("a"); div.appendChild(element); if (typeof groupId === "object") { hasAnyNesting = true; this._addToggleButton(div, groupId); this._setNestedName(element, groupId); const itemsDiv = document.createElement("div"); itemsDiv.className = "treeItems"; div.appendChild(itemsDiv); queue.push({ parent: itemsDiv, groups: groupId.order }); } else { const group = optionalContentConfig.getGroup(groupId); const input = document.createElement("input"); this._bindLink(element, { groupId, input }); input.type = "checkbox"; input.id = groupId; input.checked = group.visible; const label = document.createElement("label"); label.setAttribute("for", groupId); label.textContent = this._normalizeTextContent(group.name); element.appendChild(input); element.appendChild(label); layersCount++; } levelData.parent.appendChild(div); } } this._finishRendering(fragment, layersCount, hasAnyNesting); } async _resetLayers() { if (!this._optionalContentConfig) { return; } const optionalContentConfig = await this._pdfDocument.getOptionalContentConfig(); this.eventBus.dispatch("optionalcontentconfig", { source: this, promise: Promise.resolve(optionalContentConfig) }); this.render({ optionalContentConfig, pdfDocument: this._pdfDocument }); } } exports.PDFLayerViewer = PDFLayerViewer; /***/ }), /* 19 */ /***/ ((__unused_webpack_module, exports, __webpack_require__) => { Object.defineProperty(exports, "__esModule", ({ value: true })); exports.SimpleLinkService = exports.PDFLinkService = void 0; var _ui_utils = __webpack_require__(4); class PDFLinkService { constructor({ eventBus, externalLinkTarget = null, externalLinkRel = null, externalLinkEnabled = true, ignoreDestinationZoom = false } = {}) { this.eventBus = eventBus; this.externalLinkTarget = externalLinkTarget; this.externalLinkRel = externalLinkRel; this.externalLinkEnabled = externalLinkEnabled; this._ignoreDestinationZoom = ignoreDestinationZoom; this.baseUrl = null; this.pdfDocument = null; this.pdfViewer = null; this.pdfHistory = null; this._pagesRefCache = null; } setDocument(pdfDocument, baseUrl = null) { this.baseUrl = baseUrl; this.pdfDocument = pdfDocument; this._pagesRefCache = Object.create(null); } setViewer(pdfViewer) { this.pdfViewer = pdfViewer; } setHistory(pdfHistory) { this.pdfHistory = pdfHistory; } get pagesCount() { return this.pdfDocument ? this.pdfDocument.numPages : 0; } get page() { return this.pdfViewer.currentPageNumber; } set page(value) { this.pdfViewer.currentPageNumber = value; } get rotation() { return this.pdfViewer.pagesRotation; } set rotation(value) { this.pdfViewer.pagesRotation = value; } navigateTo(dest) { console.error("Deprecated method: `navigateTo`, use `goToDestination` instead."); this.goToDestination(dest); } _goToDestinationHelper(rawDest, namedDest = null, explicitDest) { const destRef = explicitDest[0]; let pageNumber; if (destRef instanceof Object) { pageNumber = this._cachedPageNumber(destRef); if (pageNumber === null) { this.pdfDocument.getPageIndex(destRef).then(pageIndex => { this.cachePageRef(pageIndex + 1, destRef); this._goToDestinationHelper(rawDest, namedDest, explicitDest); }).catch(() => { console.error(`PDFLinkService._goToDestinationHelper: "${destRef}" is not ` + `a valid page reference, for dest="${rawDest}".`); }); return; } } else if (Number.isInteger(destRef)) { pageNumber = destRef + 1; } else { console.error(`PDFLinkService._goToDestinationHelper: "${destRef}" is not ` + `a valid destination reference, for dest="${rawDest}".`); return; } if (!pageNumber || pageNumber < 1 || pageNumber > this.pagesCount) { console.error(`PDFLinkService._goToDestinationHelper: "${pageNumber}" is not ` + `a valid page number, for dest="${rawDest}".`); return; } if (this.pdfHistory) { this.pdfHistory.pushCurrentPosition(); this.pdfHistory.push({ namedDest, explicitDest, pageNumber }); } this.pdfViewer.scrollPageIntoView({ pageNumber, destArray: explicitDest, ignoreDestinationZoom: this._ignoreDestinationZoom }); } async goToDestination(dest) { if (!this.pdfDocument) { return; } let namedDest, explicitDest; if (typeof dest === "string") { namedDest = dest; explicitDest = await this.pdfDocument.getDestination(dest); } else { namedDest = null; explicitDest = await dest; } if (!Array.isArray(explicitDest)) { console.error(`PDFLinkService.goToDestination: "${explicitDest}" is not ` + `a valid destination array, for dest="${dest}".`); return; } this._goToDestinationHelper(dest, namedDest, explicitDest); } goToPage(val) { if (!this.pdfDocument) { return; } const pageNumber = typeof val === "string" && this.pdfViewer.pageLabelToPageNumber(val) || val | 0; if (!(Number.isInteger(pageNumber) && pageNumber > 0 && pageNumber <= this.pagesCount)) { console.error(`PDFLinkService.goToPage: "${val}" is not a valid page.`); return; } if (this.pdfHistory) { this.pdfHistory.pushCurrentPosition(); this.pdfHistory.pushPage(pageNumber); } this.pdfViewer.scrollPageIntoView({ pageNumber }); } getDestinationHash(dest) { if (typeof dest === "string") { if (dest.length > 0) { return this.getAnchorUrl("#" + escape(dest)); } } else if (Array.isArray(dest)) { const str = JSON.stringify(dest); if (str.length > 0) { return this.getAnchorUrl("#" + escape(str)); } } return this.getAnchorUrl(""); } getAnchorUrl(anchor) { return (this.baseUrl || "") + anchor; } setHash(hash) { if (!this.pdfDocument) { return; } let pageNumber, dest; if (hash.includes("=")) { const params = (0, _ui_utils.parseQueryString)(hash); if ("search" in params) { this.eventBus.dispatch("findfromurlhash", { source: this, query: params.search.replace(/"/g, ""), phraseSearch: params.phrase === "true" }); } if ("page" in params) { pageNumber = params.page | 0 || 1; } if ("zoom" in params) { const zoomArgs = params.zoom.split(","); const zoomArg = zoomArgs[0]; const zoomArgNumber = parseFloat(zoomArg); if (!zoomArg.includes("Fit")) { dest = [null, { name: "XYZ" }, zoomArgs.length > 1 ? zoomArgs[1] | 0 : null, zoomArgs.length > 2 ? zoomArgs[2] | 0 : null, zoomArgNumber ? zoomArgNumber / 100 : zoomArg]; } else { if (zoomArg === "Fit" || zoomArg === "FitB") { dest = [null, { name: zoomArg }]; } else if (zoomArg === "FitH" || zoomArg === "FitBH" || zoomArg === "FitV" || zoomArg === "FitBV") { dest = [null, { name: zoomArg }, zoomArgs.length > 1 ? zoomArgs[1] | 0 : null]; } else if (zoomArg === "FitR") { if (zoomArgs.length !== 5) { console.error('PDFLinkService.setHash: Not enough parameters for "FitR".'); } else { dest = [null, { name: zoomArg }, zoomArgs[1] | 0, zoomArgs[2] | 0, zoomArgs[3] | 0, zoomArgs[4] | 0]; } } else { console.error(`PDFLinkService.setHash: "${zoomArg}" is not ` + "a valid zoom value."); } } } if (dest) { this.pdfViewer.scrollPageIntoView({ pageNumber: pageNumber || this.page, destArray: dest, allowNegativeOffset: true }); } else if (pageNumber) { this.page = pageNumber; } if ("pagemode" in params) { this.eventBus.dispatch("pagemode", { source: this, mode: params.pagemode }); } if ("nameddest" in params) { this.goToDestination(params.nameddest); } } else { dest = unescape(hash); try { dest = JSON.parse(dest); if (!Array.isArray(dest)) { dest = dest.toString(); } } catch (ex) {} if (typeof dest === "string" || isValidExplicitDestination(dest)) { this.goToDestination(dest); return; } console.error(`PDFLinkService.setHash: "${unescape(hash)}" is not ` + "a valid destination."); } } executeNamedAction(action) { switch (action) { case "GoBack": if (this.pdfHistory) { this.pdfHistory.back(); } break; case "GoForward": if (this.pdfHistory) { this.pdfHistory.forward(); } break; case "NextPage": this.pdfViewer.nextPage(); break; case "PrevPage": this.pdfViewer.previousPage(); break; case "LastPage": this.page = this.pagesCount; break; case "FirstPage": this.page = 1; break; default: break; } this.eventBus.dispatch("namedaction", { source: this, action }); } cachePageRef(pageNum, pageRef) { if (!pageRef) { return; } const refStr = pageRef.gen === 0 ? `${pageRef.num}R` : `${pageRef.num}R${pageRef.gen}`; this._pagesRefCache[refStr] = pageNum; } _cachedPageNumber(pageRef) { const refStr = pageRef.gen === 0 ? `${pageRef.num}R` : `${pageRef.num}R${pageRef.gen}`; return this._pagesRefCache?.[refStr] || null; } isPageVisible(pageNumber) { return this.pdfViewer.isPageVisible(pageNumber); } isPageCached(pageNumber) { return this.pdfViewer.isPageCached(pageNumber); } } exports.PDFLinkService = PDFLinkService; function isValidExplicitDestination(dest) { if (!Array.isArray(dest)) { return false; } const destLength = dest.length; if (destLength < 2) { return false; } const page = dest[0]; if (!(typeof page === "object" && Number.isInteger(page.num) && Number.isInteger(page.gen)) && !(Number.isInteger(page) && page >= 0)) { return false; } const zoom = dest[1]; if (!(typeof zoom === "object" && typeof zoom.name === "string")) { return false; } let allowNull = true; switch (zoom.name) { case "XYZ": if (destLength !== 5) { return false; } break; case "Fit": case "FitB": return destLength === 2; case "FitH": case "FitBH": case "FitV": case "FitBV": if (destLength !== 3) { return false; } break; case "FitR": if (destLength !== 6) { return false; } allowNull = false; break; default: return false; } for (let i = 2; i < destLength; i++) { const param = dest[i]; if (!(typeof param === "number" || allowNull && param === null)) { return false; } } return true; } class SimpleLinkService { constructor() { this.externalLinkTarget = null; this.externalLinkRel = null; this.externalLinkEnabled = true; this._ignoreDestinationZoom = false; } get pagesCount() { return 0; } get page() { return 0; } set page(value) {} get rotation() { return 0; } set rotation(value) {} async goToDestination(dest) {} goToPage(val) {} getDestinationHash(dest) { return "#"; } getAnchorUrl(hash) { return "#"; } setHash(hash) {} executeNamedAction(action) {} cachePageRef(pageNum, pageRef) {} isPageVisible(pageNumber) { return true; } isPageCached(pageNumber) { return true; } } exports.SimpleLinkService = SimpleLinkService; /***/ }), /* 20 */ /***/ ((__unused_webpack_module, exports, __webpack_require__) => { Object.defineProperty(exports, "__esModule", ({ value: true })); exports.PDFOutlineViewer = void 0; var _pdfjsLib = __webpack_require__(5); var _base_tree_viewer = __webpack_require__(12); var _ui_utils = __webpack_require__(4); class PDFOutlineViewer extends _base_tree_viewer.BaseTreeViewer { constructor(options) { super(options); this.linkService = options.linkService; this.eventBus._on("toggleoutlinetree", this._toggleAllTreeItems.bind(this)); this.eventBus._on("currentoutlineitem", this._currentOutlineItem.bind(this)); this.eventBus._on("pagechanging", evt => { this._currentPageNumber = evt.pageNumber; }); this.eventBus._on("pagesloaded", evt => { this._isPagesLoaded = !!evt.pagesCount; }); this.eventBus._on("sidebarviewchanged", evt => { this._sidebarView = evt.view; }); } reset() { super.reset(); this._outline = null; this._pageNumberToDestHashCapability = null; this._currentPageNumber = 1; this._isPagesLoaded = false; } _dispatchEvent(outlineCount) { this.eventBus.dispatch("outlineloaded", { source: this, outlineCount, enableCurrentOutlineItemButton: outlineCount > 0 && !this._pdfDocument?.loadingParams.disableAutoFetch }); } _bindLink(element, { url, newWindow, dest }) { const { linkService } = this; if (url) { (0, _pdfjsLib.addLinkAttributes)(element, { url, target: newWindow ? _pdfjsLib.LinkTarget.BLANK : linkService.externalLinkTarget, rel: linkService.externalLinkRel, enabled: linkService.externalLinkEnabled }); return; } element.href = linkService.getDestinationHash(dest); element.onclick = evt => { this._updateCurrentTreeItem(evt.target.parentNode); if (dest) { linkService.goToDestination(dest); } return false; }; } _setStyles(element, { bold, italic }) { if (bold) { element.style.fontWeight = "bold"; } if (italic) { element.style.fontStyle = "italic"; } } _addToggleButton(div, { count, items }) { let hidden = false; if (count < 0) { let totalCount = items.length; if (totalCount > 0) { const queue = [...items]; while (queue.length > 0) { const { count: nestedCount, items: nestedItems } = queue.shift(); if (nestedCount > 0 && nestedItems.length > 0) { totalCount += nestedItems.length; queue.push(...nestedItems); } } } if (Math.abs(count) === totalCount) { hidden = true; } } super._addToggleButton(div, hidden); } _toggleAllTreeItems() { if (!this._outline) { return; } super._toggleAllTreeItems(); } render({ outline, pdfDocument }) { if (this._outline) { this.reset(); } this._outline = outline || null; this._pdfDocument = pdfDocument || null; if (!outline) { this._dispatchEvent(0); return; } const fragment = document.createDocumentFragment(); const queue = [{ parent: fragment, items: outline }]; let outlineCount = 0, hasAnyNesting = false; while (queue.length > 0) { const levelData = queue.shift(); for (const item of levelData.items) { const div = document.createElement("div"); div.className = "treeItem"; const element = document.createElement("a"); this._bindLink(element, item); this._setStyles(element, item); element.textContent = this._normalizeTextContent(item.title); div.appendChild(element); if (item.items.length > 0) { hasAnyNesting = true; this._addToggleButton(div, item); const itemsDiv = document.createElement("div"); itemsDiv.className = "treeItems"; div.appendChild(itemsDiv); queue.push({ parent: itemsDiv, items: item.items }); } levelData.parent.appendChild(div); outlineCount++; } } this._finishRendering(fragment, outlineCount, hasAnyNesting); } async _currentOutlineItem() { if (!this._isPagesLoaded) { throw new Error("_currentOutlineItem: All pages have not been loaded."); } if (!this._outline || !this._pdfDocument) { return; } const pageNumberToDestHash = await this._getPageNumberToDestHash(this._pdfDocument); if (!pageNumberToDestHash) { return; } this._updateCurrentTreeItem(null); if (this._sidebarView !== _ui_utils.SidebarView.OUTLINE) { return; } for (let i = this._currentPageNumber; i > 0; i--) { const destHash = pageNumberToDestHash.get(i); if (!destHash) { continue; } const linkElement = this.container.querySelector(`a[href="${destHash}"]`); if (!linkElement) { continue; } this._scrollToCurrentTreeItem(linkElement.parentNode); break; } } async _getPageNumberToDestHash(pdfDocument) { if (this._pageNumberToDestHashCapability) { return this._pageNumberToDestHashCapability.promise; } this._pageNumberToDestHashCapability = (0, _pdfjsLib.createPromiseCapability)(); const pageNumberToDestHash = new Map(), pageNumberNesting = new Map(); const queue = [{ nesting: 0, items: this._outline }]; while (queue.length > 0) { const levelData = queue.shift(), currentNesting = levelData.nesting; for (const { dest, items } of levelData.items) { let explicitDest, pageNumber; if (typeof dest === "string") { explicitDest = await pdfDocument.getDestination(dest); if (pdfDocument !== this._pdfDocument) { return null; } } else { explicitDest = dest; } if (Array.isArray(explicitDest)) { const [destRef] = explicitDest; if (destRef instanceof Object) { pageNumber = this.linkService._cachedPageNumber(destRef); if (!pageNumber) { try { pageNumber = (await pdfDocument.getPageIndex(destRef)) + 1; if (pdfDocument !== this._pdfDocument) { return null; } this.linkService.cachePageRef(pageNumber, destRef); } catch (ex) {} } } else if (Number.isInteger(destRef)) { pageNumber = destRef + 1; } if (Number.isInteger(pageNumber) && (!pageNumberToDestHash.has(pageNumber) || currentNesting > pageNumberNesting.get(pageNumber))) { const destHash = this.linkService.getDestinationHash(dest); pageNumberToDestHash.set(pageNumber, destHash); pageNumberNesting.set(pageNumber, currentNesting); } } if (items.length > 0) { queue.push({ nesting: currentNesting + 1, items }); } } } this._pageNumberToDestHashCapability.resolve(pageNumberToDestHash.size > 0 ? pageNumberToDestHash : null); return this._pageNumberToDestHashCapability.promise; } } exports.PDFOutlineViewer = PDFOutlineViewer; /***/ }), /* 21 */ /***/ ((__unused_webpack_module, exports, __webpack_require__) => { Object.defineProperty(exports, "__esModule", ({ value: true })); exports.PDFPresentationMode = void 0; var _ui_utils = __webpack_require__(4); const DELAY_BEFORE_RESETTING_SWITCH_IN_PROGRESS = 1500; const DELAY_BEFORE_HIDING_CONTROLS = 3000; const ACTIVE_SELECTOR = "pdfPresentationMode"; const CONTROLS_SELECTOR = "pdfPresentationModeControls"; const MOUSE_SCROLL_COOLDOWN_TIME = 50; const PAGE_SWITCH_THRESHOLD = 0.1; const SWIPE_MIN_DISTANCE_THRESHOLD = 50; const SWIPE_ANGLE_THRESHOLD = Math.PI / 6; class PDFPresentationMode { constructor({ container, pdfViewer, eventBus }) { this.container = container; this.pdfViewer = pdfViewer; this.eventBus = eventBus; this.active = false; this.args = null; this.contextMenuOpen = false; this.mouseScrollTimeStamp = 0; this.mouseScrollDelta = 0; this.touchSwipeState = null; } request() { if (this.switchInProgress || this.active || !this.pdfViewer.pagesCount) { return false; } this._addFullscreenChangeListeners(); this._setSwitchInProgress(); this._notifyStateChange(); if (this.container.requestFullscreen) { this.container.requestFullscreen(); } else if (this.container.mozRequestFullScreen) { this.container.mozRequestFullScreen(); } else if (this.container.webkitRequestFullscreen) { this.container.webkitRequestFullscreen(Element.ALLOW_KEYBOARD_INPUT); } else { return false; } this.args = { page: this.pdfViewer.currentPageNumber, previousScale: this.pdfViewer.currentScaleValue }; return true; } _mouseWheel(evt) { if (!this.active) { return; } evt.preventDefault(); const delta = (0, _ui_utils.normalizeWheelEventDelta)(evt); const currentTime = Date.now(); const storedTime = this.mouseScrollTimeStamp; if (currentTime > storedTime && currentTime - storedTime < MOUSE_SCROLL_COOLDOWN_TIME) { return; } if (this.mouseScrollDelta > 0 && delta < 0 || this.mouseScrollDelta < 0 && delta > 0) { this._resetMouseScrollState(); } this.mouseScrollDelta += delta; if (Math.abs(this.mouseScrollDelta) >= PAGE_SWITCH_THRESHOLD) { const totalDelta = this.mouseScrollDelta; this._resetMouseScrollState(); const success = totalDelta > 0 ? this.pdfViewer.previousPage() : this.pdfViewer.nextPage(); if (success) { this.mouseScrollTimeStamp = currentTime; } } } get isFullscreen() { return !!(document.fullscreenElement || document.mozFullScreen || document.webkitIsFullScreen); } _notifyStateChange() { let state = _ui_utils.PresentationModeState.NORMAL; if (this.switchInProgress) { state = _ui_utils.PresentationModeState.CHANGING; } else if (this.active) { state = _ui_utils.PresentationModeState.FULLSCREEN; } this.eventBus.dispatch("presentationmodechanged", { source: this, state, get active() { throw new Error("Deprecated parameter: `active`, please use `state` instead."); }, get switchInProgress() { throw new Error("Deprecated parameter: `switchInProgress`, please use `state` instead."); } }); } _setSwitchInProgress() { if (this.switchInProgress) { clearTimeout(this.switchInProgress); } this.switchInProgress = setTimeout(() => { this._removeFullscreenChangeListeners(); delete this.switchInProgress; this._notifyStateChange(); }, DELAY_BEFORE_RESETTING_SWITCH_IN_PROGRESS); } _resetSwitchInProgress() { if (this.switchInProgress) { clearTimeout(this.switchInProgress); delete this.switchInProgress; } } _enter() { this.active = true; this._resetSwitchInProgress(); this._notifyStateChange(); this.container.classList.add(ACTIVE_SELECTOR); setTimeout(() => { this.pdfViewer.currentPageNumber = this.args.page; this.pdfViewer.currentScaleValue = "page-fit"; }, 0); this._addWindowListeners(); this._showControls(); this.contextMenuOpen = false; window.getSelection().removeAllRanges(); } _exit() { const page = this.pdfViewer.currentPageNumber; this.container.classList.remove(ACTIVE_SELECTOR); setTimeout(() => { this.active = false; this._removeFullscreenChangeListeners(); this._notifyStateChange(); this.pdfViewer.currentScaleValue = this.args.previousScale; this.pdfViewer.currentPageNumber = page; this.args = null; }, 0); this._removeWindowListeners(); this._hideControls(); this._resetMouseScrollState(); this.contextMenuOpen = false; } _mouseDown(evt) { if (this.contextMenuOpen) { this.contextMenuOpen = false; evt.preventDefault(); return; } if (evt.button === 0) { const isInternalLink = evt.target.href && evt.target.classList.contains("internalLink"); if (!isInternalLink) { evt.preventDefault(); if (evt.shiftKey) { this.pdfViewer.previousPage(); } else { this.pdfViewer.nextPage(); } } } } _contextMenu() { this.contextMenuOpen = true; } _showControls() { if (this.controlsTimeout) { clearTimeout(this.controlsTimeout); } else { this.container.classList.add(CONTROLS_SELECTOR); } this.controlsTimeout = setTimeout(() => { this.container.classList.remove(CONTROLS_SELECTOR); delete this.controlsTimeout; }, DELAY_BEFORE_HIDING_CONTROLS); } _hideControls() { if (!this.controlsTimeout) { return; } clearTimeout(this.controlsTimeout); this.container.classList.remove(CONTROLS_SELECTOR); delete this.controlsTimeout; } _resetMouseScrollState() { this.mouseScrollTimeStamp = 0; this.mouseScrollDelta = 0; } _touchSwipe(evt) { if (!this.active) { return; } if (evt.touches.length > 1) { this.touchSwipeState = null; return; } switch (evt.type) { case "touchstart": this.touchSwipeState = { startX: evt.touches[0].pageX, startY: evt.touches[0].pageY, endX: evt.touches[0].pageX, endY: evt.touches[0].pageY }; break; case "touchmove": if (this.touchSwipeState === null) { return; } this.touchSwipeState.endX = evt.touches[0].pageX; this.touchSwipeState.endY = evt.touches[0].pageY; evt.preventDefault(); break; case "touchend": if (this.touchSwipeState === null) { return; } let delta = 0; const dx = this.touchSwipeState.endX - this.touchSwipeState.startX; const dy = this.touchSwipeState.endY - this.touchSwipeState.startY; const absAngle = Math.abs(Math.atan2(dy, dx)); if (Math.abs(dx) > SWIPE_MIN_DISTANCE_THRESHOLD && (absAngle <= SWIPE_ANGLE_THRESHOLD || absAngle >= Math.PI - SWIPE_ANGLE_THRESHOLD)) { delta = dx; } else if (Math.abs(dy) > SWIPE_MIN_DISTANCE_THRESHOLD && Math.abs(absAngle - Math.PI / 2) <= SWIPE_ANGLE_THRESHOLD) { delta = dy; } if (delta > 0) { this.pdfViewer.previousPage(); } else if (delta < 0) { this.pdfViewer.nextPage(); } break; } } _addWindowListeners() { this.showControlsBind = this._showControls.bind(this); this.mouseDownBind = this._mouseDown.bind(this); this.mouseWheelBind = this._mouseWheel.bind(this); this.resetMouseScrollStateBind = this._resetMouseScrollState.bind(this); this.contextMenuBind = this._contextMenu.bind(this); this.touchSwipeBind = this._touchSwipe.bind(this); window.addEventListener("mousemove", this.showControlsBind); window.addEventListener("mousedown", this.mouseDownBind); window.addEventListener("wheel", this.mouseWheelBind, { passive: false }); window.addEventListener("keydown", this.resetMouseScrollStateBind); window.addEventListener("contextmenu", this.contextMenuBind); window.addEventListener("touchstart", this.touchSwipeBind); window.addEventListener("touchmove", this.touchSwipeBind); window.addEventListener("touchend", this.touchSwipeBind); } _removeWindowListeners() { window.removeEventListener("mousemove", this.showControlsBind); window.removeEventListener("mousedown", this.mouseDownBind); window.removeEventListener("wheel", this.mouseWheelBind, { passive: false }); window.removeEventListener("keydown", this.resetMouseScrollStateBind); window.removeEventListener("contextmenu", this.contextMenuBind); window.removeEventListener("touchstart", this.touchSwipeBind); window.removeEventListener("touchmove", this.touchSwipeBind); window.removeEventListener("touchend", this.touchSwipeBind); delete this.showControlsBind; delete this.mouseDownBind; delete this.mouseWheelBind; delete this.resetMouseScrollStateBind; delete this.contextMenuBind; delete this.touchSwipeBind; } _fullscreenChange() { if (this.isFullscreen) { this._enter(); } else { this._exit(); } } _addFullscreenChangeListeners() { this.fullscreenChangeBind = this._fullscreenChange.bind(this); window.addEventListener("fullscreenchange", this.fullscreenChangeBind); window.addEventListener("mozfullscreenchange", this.fullscreenChangeBind); window.addEventListener("webkitfullscreenchange", this.fullscreenChangeBind); } _removeFullscreenChangeListeners() { window.removeEventListener("fullscreenchange", this.fullscreenChangeBind); window.removeEventListener("mozfullscreenchange", this.fullscreenChangeBind); window.removeEventListener("webkitfullscreenchange", this.fullscreenChangeBind); delete this.fullscreenChangeBind; } } exports.PDFPresentationMode = PDFPresentationMode; /***/ }), /* 22 */ /***/ ((__unused_webpack_module, exports, __webpack_require__) => { Object.defineProperty(exports, "__esModule", ({ value: true })); exports.PDFScriptingManager = void 0; var _pdfjsLib = __webpack_require__(5); var _ui_utils = __webpack_require__(4); var _pdf_rendering_queue = __webpack_require__(8); class PDFScriptingManager { constructor({ eventBus, sandboxBundleSrc = null, scriptingFactory = null, docPropertiesLookup = null }) { this._pdfDocument = null; this._pdfViewer = null; this._closeCapability = null; this._destroyCapability = null; this._scripting = null; this._mouseState = Object.create(null); this._pageEventsReady = false; this._ready = false; this._eventBus = eventBus; this._sandboxBundleSrc = sandboxBundleSrc; this._scriptingFactory = scriptingFactory; this._docPropertiesLookup = docPropertiesLookup; } setViewer(pdfViewer) { this._pdfViewer = pdfViewer; } async setDocument(pdfDocument) { if (this._pdfDocument) { await this._destroyScripting(); } this._pdfDocument = pdfDocument; if (!pdfDocument) { return; } const [objects, calculationOrder, docActions] = await Promise.all([pdfDocument.getFieldObjects(), pdfDocument.getCalculationOrderIds(), pdfDocument.getJSActions()]); if (!objects && !docActions) { await this._destroyScripting(); return; } if (pdfDocument !== this._pdfDocument) { return; } this._scripting = this._createScripting(); this._internalEvents.set("updatefromsandbox", event => { if (event?.source !== window) { return; } this._updateFromSandbox(event.detail); }); this._internalEvents.set("dispatcheventinsandbox", event => { this._scripting?.dispatchEventInSandbox(event.detail); }); this._internalEvents.set("pagechanging", ({ pageNumber, previous }) => { if (pageNumber === previous) { return; } this._dispatchPageClose(previous); this._dispatchPageOpen(pageNumber); }); this._internalEvents.set("pagerendered", ({ pageNumber }) => { if (!this._pageOpenPending.has(pageNumber)) { return; } if (pageNumber !== this._pdfViewer.currentPageNumber) { return; } this._dispatchPageOpen(pageNumber); }); this._internalEvents.set("pagesdestroy", async event => { await this._dispatchPageClose(this._pdfViewer.currentPageNumber); await this._scripting?.dispatchEventInSandbox({ id: "doc", name: "WillClose" }); this._closeCapability?.resolve(); }); this._domEvents.set("mousedown", event => { this._mouseState.isDown = true; }); this._domEvents.set("mouseup", event => { this._mouseState.isDown = false; }); for (const [name, listener] of this._internalEvents) { this._eventBus._on(name, listener); } for (const [name, listener] of this._domEvents) { window.addEventListener(name, listener); } try { const docProperties = await this._getDocProperties(); if (pdfDocument !== this._pdfDocument) { return; } await this._scripting.createSandbox({ objects, calculationOrder, appInfo: { platform: navigator.platform, language: navigator.language }, docInfo: { ...docProperties, actions: docActions } }); this._eventBus.dispatch("sandboxcreated", { source: this }); } catch (error) { console.error(`PDFScriptingManager.setDocument: "${error?.message}".`); await this._destroyScripting(); return; } await this._scripting?.dispatchEventInSandbox({ id: "doc", name: "Open" }); await this._dispatchPageOpen(this._pdfViewer.currentPageNumber, true); Promise.resolve().then(() => { if (pdfDocument === this._pdfDocument) { this._ready = true; } }); } async dispatchWillSave(detail) { return this._scripting?.dispatchEventInSandbox({ id: "doc", name: "WillSave" }); } async dispatchDidSave(detail) { return this._scripting?.dispatchEventInSandbox({ id: "doc", name: "DidSave" }); } async dispatchWillPrint(detail) { return this._scripting?.dispatchEventInSandbox({ id: "doc", name: "WillPrint" }); } async dispatchDidPrint(detail) { return this._scripting?.dispatchEventInSandbox({ id: "doc", name: "DidPrint" }); } get mouseState() { return this._mouseState; } get destroyPromise() { return this._destroyCapability?.promise || null; } get ready() { return this._ready; } get _internalEvents() { return (0, _pdfjsLib.shadow)(this, "_internalEvents", new Map()); } get _domEvents() { return (0, _pdfjsLib.shadow)(this, "_domEvents", new Map()); } get _pageOpenPending() { return (0, _pdfjsLib.shadow)(this, "_pageOpenPending", new Set()); } get _visitedPages() { return (0, _pdfjsLib.shadow)(this, "_visitedPages", new Map()); } async _updateFromSandbox(detail) { const isInPresentationMode = this._pdfViewer.isInPresentationMode || this._pdfViewer.isChangingPresentationMode; const { id, command, value } = detail; if (!id) { switch (command) { case "clear": console.clear(); break; case "error": console.error(value); break; case "layout": this._pdfViewer.spreadMode = (0, _ui_utils.apiPageLayoutToSpreadMode)(value); break; case "page-num": this._pdfViewer.currentPageNumber = value + 1; break; case "print": await this._pdfViewer.pagesPromise; this._eventBus.dispatch("print", { source: this }); break; case "println": console.log(value); break; case "zoom": if (isInPresentationMode) { return; } this._pdfViewer.currentScaleValue = value; break; } return; } if (isInPresentationMode) { if (detail.focus) { return; } } const element = document.getElementById(id); if (element) { element.dispatchEvent(new CustomEvent("updatefromsandbox", { detail })); } else { delete detail.id; this._pdfDocument?.annotationStorage.setValue(id, detail); } } async _dispatchPageOpen(pageNumber, initialize = false) { const pdfDocument = this._pdfDocument, visitedPages = this._visitedPages; if (initialize) { this._closeCapability = (0, _pdfjsLib.createPromiseCapability)(); this._pageEventsReady = true; } if (!this._pageEventsReady) { return; } const pageView = this._pdfViewer.getPageView(pageNumber - 1); if (pageView?.renderingState !== _pdf_rendering_queue.RenderingStates.FINISHED) { this._pageOpenPending.add(pageNumber); return; } this._pageOpenPending.delete(pageNumber); const actionsPromise = (async () => { const actions = await (!visitedPages.has(pageNumber) ? pageView.pdfPage?.getJSActions() : null); if (pdfDocument !== this._pdfDocument) { return; } await this._scripting?.dispatchEventInSandbox({ id: "page", name: "PageOpen", pageNumber, actions }); })(); visitedPages.set(pageNumber, actionsPromise); } async _dispatchPageClose(pageNumber) { const pdfDocument = this._pdfDocument, visitedPages = this._visitedPages; if (!this._pageEventsReady) { return; } if (this._pageOpenPending.has(pageNumber)) { return; } const actionsPromise = visitedPages.get(pageNumber); if (!actionsPromise) { return; } visitedPages.set(pageNumber, null); await actionsPromise; if (pdfDocument !== this._pdfDocument) { return; } await this._scripting?.dispatchEventInSandbox({ id: "page", name: "PageClose", pageNumber }); } async _getDocProperties() { if (this._docPropertiesLookup) { return this._docPropertiesLookup(this._pdfDocument); } throw new Error("_getDocProperties: Unable to lookup properties."); } _createScripting() { this._destroyCapability = (0, _pdfjsLib.createPromiseCapability)(); if (this._scripting) { throw new Error("_createScripting: Scripting already exists."); } if (this._scriptingFactory) { return this._scriptingFactory.createScripting({ sandboxBundleSrc: this._sandboxBundleSrc }); } throw new Error("_createScripting: Cannot create scripting."); } async _destroyScripting() { if (!this._scripting) { this._pdfDocument = null; this._destroyCapability?.resolve(); return; } if (this._closeCapability) { await Promise.race([this._closeCapability.promise, new Promise(resolve => { setTimeout(resolve, 1000); })]).catch(reason => {}); this._closeCapability = null; } this._pdfDocument = null; try { await this._scripting.destroySandbox(); } catch (ex) {} for (const [name, listener] of this._internalEvents) { this._eventBus._off(name, listener); } this._internalEvents.clear(); for (const [name, listener] of this._domEvents) { window.removeEventListener(name, listener); } this._domEvents.clear(); this._pageOpenPending.clear(); this._visitedPages.clear(); this._scripting = null; delete this._mouseState.isDown; this._pageEventsReady = false; this._ready = false; this._destroyCapability?.resolve(); } } exports.PDFScriptingManager = PDFScriptingManager; /***/ }), /* 23 */ /***/ ((__unused_webpack_module, exports, __webpack_require__) => { Object.defineProperty(exports, "__esModule", ({ value: true })); exports.PDFSidebar = void 0; var _ui_utils = __webpack_require__(4); var _pdf_rendering_queue = __webpack_require__(8); const UI_NOTIFICATION_CLASS = "pdfSidebarNotification"; class PDFSidebar { constructor({ elements, pdfViewer, pdfThumbnailViewer, eventBus, l10n }) { this.isOpen = false; this.active = _ui_utils.SidebarView.THUMBS; this.isInitialViewSet = false; this.onToggled = null; this.pdfViewer = pdfViewer; this.pdfThumbnailViewer = pdfThumbnailViewer; this.outerContainer = elements.outerContainer; this.viewerContainer = elements.viewerContainer; this.toggleButton = elements.toggleButton; this.thumbnailButton = elements.thumbnailButton; this.outlineButton = elements.outlineButton; this.attachmentsButton = elements.attachmentsButton; this.layersButton = elements.layersButton; this.thumbnailView = elements.thumbnailView; this.outlineView = elements.outlineView; this.attachmentsView = elements.attachmentsView; this.layersView = elements.layersView; this._outlineOptionsContainer = elements.outlineOptionsContainer; this._currentOutlineItemButton = elements.currentOutlineItemButton; this.eventBus = eventBus; this.l10n = l10n; this._addEventListeners(); } reset() { this.isInitialViewSet = false; this._hideUINotification(true); this.switchView(_ui_utils.SidebarView.THUMBS); this.outlineButton.disabled = false; this.attachmentsButton.disabled = false; this.layersButton.disabled = false; this._currentOutlineItemButton.disabled = true; } get visibleView() { return this.isOpen ? this.active : _ui_utils.SidebarView.NONE; } get isThumbnailViewVisible() { return this.isOpen && this.active === _ui_utils.SidebarView.THUMBS; } get isOutlineViewVisible() { return this.isOpen && this.active === _ui_utils.SidebarView.OUTLINE; } get isAttachmentsViewVisible() { return this.isOpen && this.active === _ui_utils.SidebarView.ATTACHMENTS; } get isLayersViewVisible() { return this.isOpen && this.active === _ui_utils.SidebarView.LAYERS; } setInitialView(view = _ui_utils.SidebarView.NONE) { if (this.isInitialViewSet) { return; } this.isInitialViewSet = true; if (view === _ui_utils.SidebarView.NONE || view === _ui_utils.SidebarView.UNKNOWN) { this._dispatchEvent(); return; } if (!this._switchView(view, true)) { this._dispatchEvent(); } } switchView(view, forceOpen = false) { this._switchView(view, forceOpen); } _switchView(view, forceOpen = false) { const isViewChanged = view !== this.active; let shouldForceRendering = false; switch (view) { case _ui_utils.SidebarView.NONE: if (this.isOpen) { this.close(); return true; } return false; case _ui_utils.SidebarView.THUMBS: if (this.isOpen && isViewChanged) { shouldForceRendering = true; } break; case _ui_utils.SidebarView.OUTLINE: if (this.outlineButton.disabled) { return false; } break; case _ui_utils.SidebarView.ATTACHMENTS: if (this.attachmentsButton.disabled) { return false; } break; case _ui_utils.SidebarView.LAYERS: if (this.layersButton.disabled) { return false; } break; default: console.error(`PDFSidebar._switchView: "${view}" is not a valid view.`); return false; } this.active = view; this.thumbnailButton.classList.toggle("toggled", view === _ui_utils.SidebarView.THUMBS); this.outlineButton.classList.toggle("toggled", view === _ui_utils.SidebarView.OUTLINE); this.attachmentsButton.classList.toggle("toggled", view === _ui_utils.SidebarView.ATTACHMENTS); this.layersButton.classList.toggle("toggled", view === _ui_utils.SidebarView.LAYERS); this.thumbnailView.classList.toggle("hidden", view !== _ui_utils.SidebarView.THUMBS); this.outlineView.classList.toggle("hidden", view !== _ui_utils.SidebarView.OUTLINE); this.attachmentsView.classList.toggle("hidden", view !== _ui_utils.SidebarView.ATTACHMENTS); this.layersView.classList.toggle("hidden", view !== _ui_utils.SidebarView.LAYERS); this._outlineOptionsContainer.classList.toggle("hidden", view !== _ui_utils.SidebarView.OUTLINE); if (forceOpen && !this.isOpen) { this.open(); return true; } if (shouldForceRendering) { this._updateThumbnailViewer(); this._forceRendering(); } if (isViewChanged) { this._dispatchEvent(); } return isViewChanged; } open() { if (this.isOpen) { return; } this.isOpen = true; this.toggleButton.classList.add("toggled"); this.toggleButton.setAttribute("aria-expanded", "true"); this.outerContainer.classList.add("sidebarMoving", "sidebarOpen"); if (this.active === _ui_utils.SidebarView.THUMBS) { this._updateThumbnailViewer(); } this._forceRendering(); this._dispatchEvent(); this._hideUINotification(); } close() { if (!this.isOpen) { return; } this.isOpen = false; this.toggleButton.classList.remove("toggled"); this.toggleButton.setAttribute("aria-expanded", "false"); this.outerContainer.classList.add("sidebarMoving"); this.outerContainer.classList.remove("sidebarOpen"); this._forceRendering(); this._dispatchEvent(); } toggle() { if (this.isOpen) { this.close(); } else { this.open(); } } _dispatchEvent() { this.eventBus.dispatch("sidebarviewchanged", { source: this, view: this.visibleView }); } _forceRendering() { if (this.onToggled) { this.onToggled(); } else { this.pdfViewer.forceRendering(); this.pdfThumbnailViewer.forceRendering(); } } _updateThumbnailViewer() { const { pdfViewer, pdfThumbnailViewer } = this; const pagesCount = pdfViewer.pagesCount; for (let pageIndex = 0; pageIndex < pagesCount; pageIndex++) { const pageView = pdfViewer.getPageView(pageIndex); if (pageView?.renderingState === _pdf_rendering_queue.RenderingStates.FINISHED) { const thumbnailView = pdfThumbnailViewer.getThumbnail(pageIndex); thumbnailView.setImage(pageView); } } pdfThumbnailViewer.scrollThumbnailIntoView(pdfViewer.currentPageNumber); } _showUINotification() { this.l10n.get("toggle_sidebar_notification2.title").then(msg => { this.toggleButton.title = msg; }); if (!this.isOpen) { this.toggleButton.classList.add(UI_NOTIFICATION_CLASS); } } _hideUINotification(reset = false) { if (this.isOpen || reset) { this.toggleButton.classList.remove(UI_NOTIFICATION_CLASS); } if (reset) { this.l10n.get("toggle_sidebar.title").then(msg => { this.toggleButton.title = msg; }); } } _addEventListeners() { this.viewerContainer.addEventListener("transitionend", evt => { if (evt.target === this.viewerContainer) { this.outerContainer.classList.remove("sidebarMoving"); } }); this.toggleButton.addEventListener("click", () => { this.toggle(); }); this.thumbnailButton.addEventListener("click", () => { this.switchView(_ui_utils.SidebarView.THUMBS); }); this.outlineButton.addEventListener("click", () => { this.switchView(_ui_utils.SidebarView.OUTLINE); }); this.outlineButton.addEventListener("dblclick", () => { this.eventBus.dispatch("toggleoutlinetree", { source: this }); }); this.attachmentsButton.addEventListener("click", () => { this.switchView(_ui_utils.SidebarView.ATTACHMENTS); }); this.layersButton.addEventListener("click", () => { this.switchView(_ui_utils.SidebarView.LAYERS); }); this.layersButton.addEventListener("dblclick", () => { this.eventBus.dispatch("resetlayers", { source: this }); }); this._currentOutlineItemButton.addEventListener("click", () => { this.eventBus.dispatch("currentoutlineitem", { source: this }); }); const onTreeLoaded = (count, button, view) => { button.disabled = !count; if (count) { this._showUINotification(); } else if (this.active === view) { this.switchView(_ui_utils.SidebarView.THUMBS); } }; this.eventBus._on("outlineloaded", evt => { onTreeLoaded(evt.outlineCount, this.outlineButton, _ui_utils.SidebarView.OUTLINE); if (evt.enableCurrentOutlineItemButton) { this.pdfViewer.pagesPromise.then(() => { this._currentOutlineItemButton.disabled = !this.isInitialViewSet; }); } }); this.eventBus._on("attachmentsloaded", evt => { onTreeLoaded(evt.attachmentsCount, this.attachmentsButton, _ui_utils.SidebarView.ATTACHMENTS); }); this.eventBus._on("layersloaded", evt => { onTreeLoaded(evt.layersCount, this.layersButton, _ui_utils.SidebarView.LAYERS); }); this.eventBus._on("presentationmodechanged", evt => { if (evt.state === _ui_utils.PresentationModeState.NORMAL && this.isThumbnailViewVisible) { this._updateThumbnailViewer(); } }); } } exports.PDFSidebar = PDFSidebar; /***/ }), /* 24 */ /***/ ((__unused_webpack_module, exports) => { Object.defineProperty(exports, "__esModule", ({ value: true })); exports.PDFSidebarResizer = void 0; const SIDEBAR_WIDTH_VAR = "--sidebar-width"; const SIDEBAR_MIN_WIDTH = 200; const SIDEBAR_RESIZING_CLASS = "sidebarResizing"; class PDFSidebarResizer { constructor(options, eventBus, l10n) { this.isRTL = false; this.sidebarOpen = false; this.doc = document.documentElement; this._width = null; this._outerContainerWidth = null; this._boundEvents = Object.create(null); this.outerContainer = options.outerContainer; this.resizer = options.resizer; this.eventBus = eventBus; l10n.getDirection().then(dir => { this.isRTL = dir === "rtl"; }); this._addEventListeners(); } get outerContainerWidth() { return this._outerContainerWidth || (this._outerContainerWidth = this.outerContainer.clientWidth); } _updateWidth(width = 0) { const maxWidth = Math.floor(this.outerContainerWidth / 2); if (width > maxWidth) { width = maxWidth; } if (width < SIDEBAR_MIN_WIDTH) { width = SIDEBAR_MIN_WIDTH; } if (width === this._width) { return false; } this._width = width; this.doc.style.setProperty(SIDEBAR_WIDTH_VAR, `${width}px`); return true; } _mouseMove(evt) { let width = evt.clientX; if (this.isRTL) { width = this.outerContainerWidth - width; } this._updateWidth(width); } _mouseUp(evt) { this.outerContainer.classList.remove(SIDEBAR_RESIZING_CLASS); this.eventBus.dispatch("resize", { source: this }); const _boundEvents = this._boundEvents; window.removeEventListener("mousemove", _boundEvents.mouseMove); window.removeEventListener("mouseup", _boundEvents.mouseUp); } _addEventListeners() { const _boundEvents = this._boundEvents; _boundEvents.mouseMove = this._mouseMove.bind(this); _boundEvents.mouseUp = this._mouseUp.bind(this); this.resizer.addEventListener("mousedown", evt => { if (evt.button !== 0) { return; } this.outerContainer.classList.add(SIDEBAR_RESIZING_CLASS); window.addEventListener("mousemove", _boundEvents.mouseMove); window.addEventListener("mouseup", _boundEvents.mouseUp); }); this.eventBus._on("sidebarviewchanged", evt => { this.sidebarOpen = !!evt?.view; }); this.eventBus._on("resize", evt => { if (evt?.source !== window) { return; } this._outerContainerWidth = null; if (!this._width) { return; } if (!this.sidebarOpen) { this._updateWidth(this._width); return; } this.outerContainer.classList.add(SIDEBAR_RESIZING_CLASS); const updated = this._updateWidth(this._width); Promise.resolve().then(() => { this.outerContainer.classList.remove(SIDEBAR_RESIZING_CLASS); if (updated) { this.eventBus.dispatch("resize", { source: this }); } }); }); } } exports.PDFSidebarResizer = PDFSidebarResizer; /***/ }), /* 25 */ /***/ ((__unused_webpack_module, exports, __webpack_require__) => { Object.defineProperty(exports, "__esModule", ({ value: true })); exports.PDFThumbnailViewer = void 0; var _ui_utils = __webpack_require__(4); var _pdf_thumbnail_view = __webpack_require__(26); var _pdf_rendering_queue = __webpack_require__(8); const THUMBNAIL_SCROLL_MARGIN = -19; const THUMBNAIL_SELECTED_CLASS = "selected"; class PDFThumbnailViewer { constructor({ container, eventBus, linkService, renderingQueue, l10n }) { this.container = container; this.linkService = linkService; this.renderingQueue = renderingQueue; this.l10n = l10n; this.scroll = (0, _ui_utils.watchScroll)(this.container, this._scrollUpdated.bind(this)); this._resetView(); eventBus._on("optionalcontentconfigchanged", () => { this._setImageDisabled = true; }); } _scrollUpdated() { this.renderingQueue.renderHighestPriority(); } getThumbnail(index) { return this._thumbnails[index]; } _getVisibleThumbs() { return (0, _ui_utils.getVisibleElements)({ scrollEl: this.container, views: this._thumbnails }); } scrollThumbnailIntoView(pageNumber) { if (!this.pdfDocument) { return; } const thumbnailView = this._thumbnails[pageNumber - 1]; if (!thumbnailView) { console.error('scrollThumbnailIntoView: Invalid "pageNumber" parameter.'); return; } if (pageNumber !== this._currentPageNumber) { const prevThumbnailView = this._thumbnails[this._currentPageNumber - 1]; prevThumbnailView.div.classList.remove(THUMBNAIL_SELECTED_CLASS); thumbnailView.div.classList.add(THUMBNAIL_SELECTED_CLASS); } const visibleThumbs = this._getVisibleThumbs(); const numVisibleThumbs = visibleThumbs.views.length; if (numVisibleThumbs > 0) { const first = visibleThumbs.first.id; const last = numVisibleThumbs > 1 ? visibleThumbs.last.id : first; let shouldScroll = false; if (pageNumber <= first || pageNumber >= last) { shouldScroll = true; } else { visibleThumbs.views.some(function (view) { if (view.id !== pageNumber) { return false; } shouldScroll = view.percent < 100; return true; }); } if (shouldScroll) { (0, _ui_utils.scrollIntoView)(thumbnailView.div, { top: THUMBNAIL_SCROLL_MARGIN }); } } this._currentPageNumber = pageNumber; } get pagesRotation() { return this._pagesRotation; } set pagesRotation(rotation) { if (!(0, _ui_utils.isValidRotation)(rotation)) { throw new Error("Invalid thumbnails rotation angle."); } if (!this.pdfDocument) { return; } if (this._pagesRotation === rotation) { return; } this._pagesRotation = rotation; for (let i = 0, ii = this._thumbnails.length; i < ii; i++) { this._thumbnails[i].update(rotation); } } cleanup() { for (let i = 0, ii = this._thumbnails.length; i < ii; i++) { if (this._thumbnails[i] && this._thumbnails[i].renderingState !== _pdf_rendering_queue.RenderingStates.FINISHED) { this._thumbnails[i].reset(); } } _pdf_thumbnail_view.TempImageFactory.destroyCanvas(); } _resetView() { this._thumbnails = []; this._currentPageNumber = 1; this._pageLabels = null; this._pagesRotation = 0; this._optionalContentConfigPromise = null; this._pagesRequests = new WeakMap(); this._setImageDisabled = false; this.container.textContent = ""; } setDocument(pdfDocument) { if (this.pdfDocument) { this._cancelRendering(); this._resetView(); } this.pdfDocument = pdfDocument; if (!pdfDocument) { return; } const firstPagePromise = pdfDocument.getPage(1); const optionalContentConfigPromise = pdfDocument.getOptionalContentConfig(); firstPagePromise.then(firstPdfPage => { this._optionalContentConfigPromise = optionalContentConfigPromise; const pagesCount = pdfDocument.numPages; const viewport = firstPdfPage.getViewport({ scale: 1 }); const checkSetImageDisabled = () => { return this._setImageDisabled; }; for (let pageNum = 1; pageNum <= pagesCount; ++pageNum) { const thumbnail = new _pdf_thumbnail_view.PDFThumbnailView({ container: this.container, id: pageNum, defaultViewport: viewport.clone(), optionalContentConfigPromise, linkService: this.linkService, renderingQueue: this.renderingQueue, checkSetImageDisabled, disableCanvasToImageConversion: false, l10n: this.l10n }); this._thumbnails.push(thumbnail); } const firstThumbnailView = this._thumbnails[0]; if (firstThumbnailView) { firstThumbnailView.setPdfPage(firstPdfPage); } const thumbnailView = this._thumbnails[this._currentPageNumber - 1]; thumbnailView.div.classList.add(THUMBNAIL_SELECTED_CLASS); }).catch(reason => { console.error("Unable to initialize thumbnail viewer", reason); }); } _cancelRendering() { for (let i = 0, ii = this._thumbnails.length; i < ii; i++) { if (this._thumbnails[i]) { this._thumbnails[i].cancelRendering(); } } } setPageLabels(labels) { if (!this.pdfDocument) { return; } if (!labels) { this._pageLabels = null; } else if (!(Array.isArray(labels) && this.pdfDocument.numPages === labels.length)) { this._pageLabels = null; console.error("PDFThumbnailViewer_setPageLabels: Invalid page labels."); } else { this._pageLabels = labels; } for (let i = 0, ii = this._thumbnails.length; i < ii; i++) { this._thumbnails[i].setPageLabel(this._pageLabels?.[i] ?? null); } } _ensurePdfPageLoaded(thumbView) { if (thumbView.pdfPage) { return Promise.resolve(thumbView.pdfPage); } if (this._pagesRequests.has(thumbView)) { return this._pagesRequests.get(thumbView); } const promise = this.pdfDocument.getPage(thumbView.id).then(pdfPage => { if (!thumbView.pdfPage) { thumbView.setPdfPage(pdfPage); } this._pagesRequests.delete(thumbView); return pdfPage; }).catch(reason => { console.error("Unable to get page for thumb view", reason); this._pagesRequests.delete(thumbView); }); this._pagesRequests.set(thumbView, promise); return promise; } forceRendering() { const visibleThumbs = this._getVisibleThumbs(); const thumbView = this.renderingQueue.getHighestPriority(visibleThumbs, this._thumbnails, this.scroll.down); if (thumbView) { this._ensurePdfPageLoaded(thumbView).then(() => { this.renderingQueue.renderView(thumbView); }); return true; } return false; } } exports.PDFThumbnailViewer = PDFThumbnailViewer; /***/ }), /* 26 */ /***/ ((__unused_webpack_module, exports, __webpack_require__) => { Object.defineProperty(exports, "__esModule", ({ value: true })); exports.TempImageFactory = exports.PDFThumbnailView = void 0; var _ui_utils = __webpack_require__(4); var _pdfjsLib = __webpack_require__(5); var _pdf_rendering_queue = __webpack_require__(8); const MAX_NUM_SCALING_STEPS = 3; const THUMBNAIL_CANVAS_BORDER_WIDTH = 1; const THUMBNAIL_WIDTH = 98; const TempImageFactory = function TempImageFactoryClosure() { let tempCanvasCache = null; return { getCanvas(width, height) { let tempCanvas = tempCanvasCache; if (!tempCanvas) { tempCanvas = document.createElement("canvas"); tempCanvasCache = tempCanvas; } tempCanvas.width = width; tempCanvas.height = height; tempCanvas.mozOpaque = true; const ctx = tempCanvas.getContext("2d", { alpha: false }); ctx.save(); ctx.fillStyle = "rgb(255, 255, 255)"; ctx.fillRect(0, 0, width, height); ctx.restore(); return tempCanvas; }, destroyCanvas() { const tempCanvas = tempCanvasCache; if (tempCanvas) { tempCanvas.width = 0; tempCanvas.height = 0; } tempCanvasCache = null; } }; }(); exports.TempImageFactory = TempImageFactory; class PDFThumbnailView { constructor({ container, id, defaultViewport, optionalContentConfigPromise, linkService, renderingQueue, checkSetImageDisabled, disableCanvasToImageConversion = false, l10n }) { this.id = id; this.renderingId = "thumbnail" + id; this.pageLabel = null; this.pdfPage = null; this.rotation = 0; this.viewport = defaultViewport; this.pdfPageRotate = defaultViewport.rotation; this._optionalContentConfigPromise = optionalContentConfigPromise || null; this.linkService = linkService; this.renderingQueue = renderingQueue; this.renderTask = null; this.renderingState = _pdf_rendering_queue.RenderingStates.INITIAL; this.resume = null; this._checkSetImageDisabled = checkSetImageDisabled || function () { return false; }; this.disableCanvasToImageConversion = disableCanvasToImageConversion; this.pageWidth = this.viewport.width; this.pageHeight = this.viewport.height; this.pageRatio = this.pageWidth / this.pageHeight; this.canvasWidth = THUMBNAIL_WIDTH; this.canvasHeight = this.canvasWidth / this.pageRatio | 0; this.scale = this.canvasWidth / this.pageWidth; this.l10n = l10n; const anchor = document.createElement("a"); anchor.href = linkService.getAnchorUrl("#page=" + id); this._thumbPageTitle.then(msg => { anchor.title = msg; }); anchor.onclick = function () { linkService.goToPage(id); return false; }; this.anchor = anchor; const div = document.createElement("div"); div.className = "thumbnail"; div.setAttribute("data-page-number", this.id); this.div = div; const ring = document.createElement("div"); ring.className = "thumbnailSelectionRing"; const borderAdjustment = 2 * THUMBNAIL_CANVAS_BORDER_WIDTH; ring.style.width = this.canvasWidth + borderAdjustment + "px"; ring.style.height = this.canvasHeight + borderAdjustment + "px"; this.ring = ring; div.appendChild(ring); anchor.appendChild(div); container.appendChild(anchor); } setPdfPage(pdfPage) { this.pdfPage = pdfPage; this.pdfPageRotate = pdfPage.rotate; const totalRotation = (this.rotation + this.pdfPageRotate) % 360; this.viewport = pdfPage.getViewport({ scale: 1, rotation: totalRotation }); this.reset(); } reset() { this.cancelRendering(); this.renderingState = _pdf_rendering_queue.RenderingStates.INITIAL; this.pageWidth = this.viewport.width; this.pageHeight = this.viewport.height; this.pageRatio = this.pageWidth / this.pageHeight; this.canvasHeight = this.canvasWidth / this.pageRatio | 0; this.scale = this.canvasWidth / this.pageWidth; this.div.removeAttribute("data-loaded"); const ring = this.ring; const childNodes = ring.childNodes; for (let i = childNodes.length - 1; i >= 0; i--) { ring.removeChild(childNodes[i]); } const borderAdjustment = 2 * THUMBNAIL_CANVAS_BORDER_WIDTH; ring.style.width = this.canvasWidth + borderAdjustment + "px"; ring.style.height = this.canvasHeight + borderAdjustment + "px"; if (this.canvas) { this.canvas.width = 0; this.canvas.height = 0; delete this.canvas; } if (this.image) { this.image.removeAttribute("src"); delete this.image; } } update(rotation) { if (typeof rotation !== "undefined") { this.rotation = rotation; } const totalRotation = (this.rotation + this.pdfPageRotate) % 360; this.viewport = this.viewport.clone({ scale: 1, rotation: totalRotation }); this.reset(); } cancelRendering() { if (this.renderTask) { this.renderTask.cancel(); this.renderTask = null; } this.resume = null; } _getPageDrawContext() { const canvas = document.createElement("canvas"); this.canvas = canvas; canvas.mozOpaque = true; const ctx = canvas.getContext("2d", { alpha: false }); const outputScale = (0, _ui_utils.getOutputScale)(ctx); canvas.width = this.canvasWidth * outputScale.sx | 0; canvas.height = this.canvasHeight * outputScale.sy | 0; canvas.style.width = this.canvasWidth + "px"; canvas.style.height = this.canvasHeight + "px"; const transform = outputScale.scaled ? [outputScale.sx, 0, 0, outputScale.sy, 0, 0] : null; return [ctx, transform]; } _convertCanvasToImage() { if (!this.canvas) { return; } if (this.renderingState !== _pdf_rendering_queue.RenderingStates.FINISHED) { return; } const className = "thumbnailImage"; if (this.disableCanvasToImageConversion) { this.canvas.className = className; this._thumbPageCanvas.then(msg => { this.canvas.setAttribute("aria-label", msg); }); this.div.setAttribute("data-loaded", true); this.ring.appendChild(this.canvas); return; } const image = document.createElement("img"); image.className = className; this._thumbPageCanvas.then(msg => { image.setAttribute("aria-label", msg); }); image.style.width = this.canvasWidth + "px"; image.style.height = this.canvasHeight + "px"; image.src = this.canvas.toDataURL(); this.image = image; this.div.setAttribute("data-loaded", true); this.ring.appendChild(image); this.canvas.width = 0; this.canvas.height = 0; delete this.canvas; } draw() { if (this.renderingState !== _pdf_rendering_queue.RenderingStates.INITIAL) { console.error("Must be in new state before drawing"); return Promise.resolve(undefined); } const { pdfPage } = this; if (!pdfPage) { this.renderingState = _pdf_rendering_queue.RenderingStates.FINISHED; return Promise.reject(new Error("pdfPage is not loaded")); } this.renderingState = _pdf_rendering_queue.RenderingStates.RUNNING; const finishRenderTask = async (error = null) => { if (renderTask === this.renderTask) { this.renderTask = null; } if (error instanceof _pdfjsLib.RenderingCancelledException) { return; } this.renderingState = _pdf_rendering_queue.RenderingStates.FINISHED; this._convertCanvasToImage(); if (error) { throw error; } }; const [ctx, transform] = this._getPageDrawContext(); const drawViewport = this.viewport.clone({ scale: this.scale }); const renderContinueCallback = cont => { if (!this.renderingQueue.isHighestPriority(this)) { this.renderingState = _pdf_rendering_queue.RenderingStates.PAUSED; this.resume = () => { this.renderingState = _pdf_rendering_queue.RenderingStates.RUNNING; cont(); }; return; } cont(); }; const renderContext = { canvasContext: ctx, transform, viewport: drawViewport, optionalContentConfigPromise: this._optionalContentConfigPromise }; const renderTask = this.renderTask = pdfPage.render(renderContext); renderTask.onContinue = renderContinueCallback; const resultPromise = renderTask.promise.then(function () { finishRenderTask(null); }, function (error) { finishRenderTask(error); }); resultPromise.finally(() => { const pageCached = this.linkService.isPageCached(this.id); if (pageCached) { return; } this.pdfPage?.cleanup(); }); return resultPromise; } setImage(pageView) { if (this._checkSetImageDisabled()) { return; } if (this.renderingState !== _pdf_rendering_queue.RenderingStates.INITIAL) { return; } const img = pageView.canvas; if (!img) { return; } if (!this.pdfPage) { this.setPdfPage(pageView.pdfPage); } this.renderingState = _pdf_rendering_queue.RenderingStates.FINISHED; const [ctx] = this._getPageDrawContext(); const canvas = ctx.canvas; if (img.width <= 2 * canvas.width) { ctx.drawImage(img, 0, 0, img.width, img.height, 0, 0, canvas.width, canvas.height); this._convertCanvasToImage(); return; } let reducedWidth = canvas.width << MAX_NUM_SCALING_STEPS; let reducedHeight = canvas.height << MAX_NUM_SCALING_STEPS; const reducedImage = TempImageFactory.getCanvas(reducedWidth, reducedHeight); const reducedImageCtx = reducedImage.getContext("2d"); while (reducedWidth > img.width || reducedHeight > img.height) { reducedWidth >>= 1; reducedHeight >>= 1; } reducedImageCtx.drawImage(img, 0, 0, img.width, img.height, 0, 0, reducedWidth, reducedHeight); while (reducedWidth > 2 * canvas.width) { reducedImageCtx.drawImage(reducedImage, 0, 0, reducedWidth, reducedHeight, 0, 0, reducedWidth >> 1, reducedHeight >> 1); reducedWidth >>= 1; reducedHeight >>= 1; } ctx.drawImage(reducedImage, 0, 0, reducedWidth, reducedHeight, 0, 0, canvas.width, canvas.height); this._convertCanvasToImage(); } get _thumbPageTitle() { return this.l10n.get("thumb_page_title", { page: this.pageLabel ?? this.id }); } get _thumbPageCanvas() { return this.l10n.get("thumb_page_canvas", { page: this.pageLabel ?? this.id }); } setPageLabel(label) { this.pageLabel = typeof label === "string" ? label : null; this._thumbPageTitle.then(msg => { this.anchor.title = msg; }); if (this.renderingState !== _pdf_rendering_queue.RenderingStates.FINISHED) { return; } this._thumbPageCanvas.then(msg => { if (this.image) { this.image.setAttribute("aria-label", msg); } else if (this.disableCanvasToImageConversion && this.canvas) { this.canvas.setAttribute("aria-label", msg); } }); } } exports.PDFThumbnailView = PDFThumbnailView; /***/ }), /* 27 */ /***/ ((__unused_webpack_module, exports, __webpack_require__) => { Object.defineProperty(exports, "__esModule", ({ value: true })); exports.PDFViewer = void 0; var _ui_utils = __webpack_require__(4); var _base_viewer = __webpack_require__(28); var _pdfjsLib = __webpack_require__(5); class PDFViewer extends _base_viewer.BaseViewer { get _viewerElement() { return (0, _pdfjsLib.shadow)(this, "_viewerElement", this.viewer); } _scrollIntoView({ pageDiv, pageSpot = null, pageNumber = null }) { if (!pageSpot && !this.isInPresentationMode) { const left = pageDiv.offsetLeft + pageDiv.clientLeft; const right = left + pageDiv.clientWidth; const { scrollLeft, clientWidth } = this.container; if (this._isScrollModeHorizontal || left < scrollLeft || right > scrollLeft + clientWidth) { pageSpot = { left: 0, top: 0 }; } } super._scrollIntoView({ pageDiv, pageSpot, pageNumber }); } _getVisiblePages() { if (this.isInPresentationMode) { return this._getCurrentVisiblePage(); } return super._getVisiblePages(); } _updateHelper(visiblePages) { if (this.isInPresentationMode) { return; } let currentId = this._currentPageNumber; let stillFullyVisible = false; for (const page of visiblePages) { if (page.percent < 100) { break; } if (page.id === currentId && this._scrollMode === _ui_utils.ScrollMode.VERTICAL && this._spreadMode === _ui_utils.SpreadMode.NONE) { stillFullyVisible = true; break; } } if (!stillFullyVisible) { currentId = visiblePages[0].id; } this._setCurrentPageNumber(currentId); } } exports.PDFViewer = PDFViewer; /***/ }), /* 28 */ /***/ ((__unused_webpack_module, exports, __webpack_require__) => { Object.defineProperty(exports, "__esModule", ({ value: true })); exports.BaseViewer = void 0; var _pdfjsLib = __webpack_require__(5); var _ui_utils = __webpack_require__(4); var _pdf_rendering_queue = __webpack_require__(8); var _annotation_layer_builder = __webpack_require__(29); var _l10n_utils = __webpack_require__(30); var _pdf_page_view = __webpack_require__(31); var _pdf_link_service = __webpack_require__(19); var _text_layer_builder = __webpack_require__(32); var _xfa_layer_builder = __webpack_require__(33); const DEFAULT_CACHE_SIZE = 10; function PDFPageViewBuffer(size) { const data = []; this.push = function (view) { const i = data.indexOf(view); if (i >= 0) { data.splice(i, 1); } data.push(view); if (data.length > size) { data.shift().destroy(); } }; this.resize = function (newSize, pagesToKeep) { size = newSize; if (pagesToKeep) { const pageIdsToKeep = new Set(); for (let i = 0, iMax = pagesToKeep.length; i < iMax; ++i) { pageIdsToKeep.add(pagesToKeep[i].id); } (0, _ui_utils.moveToEndOfArray)(data, function (page) { return pageIdsToKeep.has(page.id); }); } while (data.length > size) { data.shift().destroy(); } }; this.has = function (view) { return data.includes(view); }; } function isSameScale(oldScale, newScale) { if (newScale === oldScale) { return true; } if (Math.abs(newScale - oldScale) < 1e-15) { return true; } return false; } class BaseViewer { constructor(options) { if (this.constructor === BaseViewer) { throw new Error("Cannot initialize BaseViewer."); } const viewerVersion = '2.8.335'; if (_pdfjsLib.version !== viewerVersion) { throw new Error(`The API version "${_pdfjsLib.version}" does not match the Viewer version "${viewerVersion}".`); } this._name = this.constructor.name; this.container = options.container; this.viewer = options.viewer || options.container.firstElementChild; if (!(this.container?.tagName.toUpperCase() === "DIV" && this.viewer?.tagName.toUpperCase() === "DIV")) { throw new Error("Invalid `container` and/or `viewer` option."); } if (this.container.offsetParent && getComputedStyle(this.container).position !== "absolute") { throw new Error("The `container` must be absolutely positioned."); } this.eventBus = options.eventBus; this.linkService = options.linkService || new _pdf_link_service.SimpleLinkService(); this.downloadManager = options.downloadManager || null; this.findController = options.findController || null; this._scriptingManager = options.scriptingManager || null; this.removePageBorders = options.removePageBorders || false; this.textLayerMode = Number.isInteger(options.textLayerMode) ? options.textLayerMode : _ui_utils.TextLayerMode.ENABLE; this.imageResourcesPath = options.imageResourcesPath || ""; this.renderInteractiveForms = options.renderInteractiveForms !== false; this.enablePrintAutoRotate = options.enablePrintAutoRotate || false; this.renderer = options.renderer || _ui_utils.RendererType.CANVAS; this.enableWebGL = options.enableWebGL || false; this.useOnlyCssZoom = options.useOnlyCssZoom || false; this.maxCanvasPixels = options.maxCanvasPixels; this.l10n = options.l10n || _l10n_utils.NullL10n; this.enableScripting = options.enableScripting === true && !!this._scriptingManager; this.defaultRenderingQueue = !options.renderingQueue; if (this.defaultRenderingQueue) { this.renderingQueue = new _pdf_rendering_queue.PDFRenderingQueue(); this.renderingQueue.setViewer(this); } else { this.renderingQueue = options.renderingQueue; } this.scroll = (0, _ui_utils.watchScroll)(this.container, this._scrollUpdate.bind(this)); this.presentationModeState = _ui_utils.PresentationModeState.UNKNOWN; this._onBeforeDraw = this._onAfterDraw = null; this._resetView(); if (this.removePageBorders) { this.viewer.classList.add("removePageBorders"); } Promise.resolve().then(() => { this.eventBus.dispatch("baseviewerinit", { source: this }); }); } get pagesCount() { return this._pages.length; } getPageView(index) { return this._pages[index]; } get pageViewsReady() { if (!this._pagesCapability.settled) { return false; } return this._pages.every(function (pageView) { return pageView?.pdfPage; }); } get currentPageNumber() { return this._currentPageNumber; } set currentPageNumber(val) { if (!Number.isInteger(val)) { throw new Error("Invalid page number."); } if (!this.pdfDocument) { return; } if (!this._setCurrentPageNumber(val, true)) { console.error(`${this._name}.currentPageNumber: "${val}" is not a valid page.`); } } _setCurrentPageNumber(val, resetCurrentPageView = false) { if (this._currentPageNumber === val) { if (resetCurrentPageView) { this._resetCurrentPageView(); } return true; } if (!(0 < val && val <= this.pagesCount)) { return false; } const previous = this._currentPageNumber; this._currentPageNumber = val; this.eventBus.dispatch("pagechanging", { source: this, pageNumber: val, pageLabel: this._pageLabels?.[val - 1] ?? null, previous }); if (resetCurrentPageView) { this._resetCurrentPageView(); } return true; } get currentPageLabel() { return this._pageLabels?.[this._currentPageNumber - 1] ?? null; } set currentPageLabel(val) { if (!this.pdfDocument) { return; } let page = val | 0; if (this._pageLabels) { const i = this._pageLabels.indexOf(val); if (i >= 0) { page = i + 1; } } if (!this._setCurrentPageNumber(page, true)) { console.error(`${this._name}.currentPageLabel: "${val}" is not a valid page.`); } } get currentScale() { return this._currentScale !== _ui_utils.UNKNOWN_SCALE ? this._currentScale : _ui_utils.DEFAULT_SCALE; } set currentScale(val) { if (isNaN(val)) { throw new Error("Invalid numeric scale."); } if (!this.pdfDocument) { return; } this._setScale(val, false); } get currentScaleValue() { return this._currentScaleValue; } set currentScaleValue(val) { if (!this.pdfDocument) { return; } this._setScale(val, false); } get pagesRotation() { return this._pagesRotation; } set pagesRotation(rotation) { if (!(0, _ui_utils.isValidRotation)(rotation)) { throw new Error("Invalid pages rotation angle."); } if (!this.pdfDocument) { return; } rotation %= 360; if (rotation < 0) { rotation += 360; } if (this._pagesRotation === rotation) { return; } this._pagesRotation = rotation; const pageNumber = this._currentPageNumber; for (let i = 0, ii = this._pages.length; i < ii; i++) { const pageView = this._pages[i]; pageView.update(pageView.scale, rotation); } if (this._currentScaleValue) { this._setScale(this._currentScaleValue, true); } this.eventBus.dispatch("rotationchanging", { source: this, pagesRotation: rotation, pageNumber }); if (this.defaultRenderingQueue) { this.update(); } } get firstPagePromise() { return this.pdfDocument ? this._firstPageCapability.promise : null; } get onePageRendered() { return this.pdfDocument ? this._onePageRenderedCapability.promise : null; } get pagesPromise() { return this.pdfDocument ? this._pagesCapability.promise : null; } get _viewerElement() { throw new Error("Not implemented: _viewerElement"); } _onePageRenderedOrForceFetch() { if (!this.container.offsetParent || this._getVisiblePages().views.length === 0) { return Promise.resolve(); } return this._onePageRenderedCapability.promise; } setDocument(pdfDocument) { if (this.pdfDocument) { this.eventBus.dispatch("pagesdestroy", { source: this }); this._cancelRendering(); this._resetView(); if (this.findController) { this.findController.setDocument(null); } if (this._scriptingManager) { this._scriptingManager.setDocument(null); } } this.pdfDocument = pdfDocument; if (!pdfDocument) { return; } const isPureXfa = pdfDocument.isPureXfa; const pagesCount = pdfDocument.numPages; const firstPagePromise = pdfDocument.getPage(1); const optionalContentConfigPromise = pdfDocument.getOptionalContentConfig(); this._pagesCapability.promise.then(() => { this.eventBus.dispatch("pagesloaded", { source: this, pagesCount }); }); this._onBeforeDraw = evt => { const pageView = this._pages[evt.pageNumber - 1]; if (!pageView) { return; } this._buffer.push(pageView); }; this.eventBus._on("pagerender", this._onBeforeDraw); this._onAfterDraw = evt => { if (evt.cssTransform || this._onePageRenderedCapability.settled) { return; } this._onePageRenderedCapability.resolve(); this.eventBus._off("pagerendered", this._onAfterDraw); this._onAfterDraw = null; }; this.eventBus._on("pagerendered", this._onAfterDraw); firstPagePromise.then(firstPdfPage => { this._firstPageCapability.resolve(firstPdfPage); this._optionalContentConfigPromise = optionalContentConfigPromise; const scale = this.currentScale; const viewport = firstPdfPage.getViewport({ scale: scale * _ui_utils.CSS_UNITS }); const textLayerFactory = this.textLayerMode !== _ui_utils.TextLayerMode.DISABLE ? this : null; const xfaLayerFactory = isPureXfa ? this : null; for (let pageNum = 1; pageNum <= pagesCount; ++pageNum) { const pageView = new _pdf_page_view.PDFPageView({ container: this._viewerElement, eventBus: this.eventBus, id: pageNum, scale, defaultViewport: viewport.clone(), optionalContentConfigPromise, renderingQueue: this.renderingQueue, textLayerFactory, textLayerMode: this.textLayerMode, annotationLayerFactory: this, xfaLayerFactory, imageResourcesPath: this.imageResourcesPath, renderInteractiveForms: this.renderInteractiveForms, renderer: this.renderer, enableWebGL: this.enableWebGL, useOnlyCssZoom: this.useOnlyCssZoom, maxCanvasPixels: this.maxCanvasPixels, l10n: this.l10n, enableScripting: this.enableScripting }); this._pages.push(pageView); } const firstPageView = this._pages[0]; if (firstPageView) { firstPageView.setPdfPage(firstPdfPage); this.linkService.cachePageRef(1, firstPdfPage.ref); } if (this._spreadMode !== _ui_utils.SpreadMode.NONE) { this._updateSpreadMode(); } this._onePageRenderedOrForceFetch().then(() => { if (this.findController) { this.findController.setDocument(pdfDocument); } if (this.enableScripting) { this._scriptingManager.setDocument(pdfDocument); } if (pdfDocument.loadingParams.disableAutoFetch || pagesCount > 7500) { this._pagesCapability.resolve(); return; } let getPagesLeft = pagesCount - 1; if (getPagesLeft <= 0) { this._pagesCapability.resolve(); return; } for (let pageNum = 2; pageNum <= pagesCount; ++pageNum) { pdfDocument.getPage(pageNum).then(pdfPage => { const pageView = this._pages[pageNum - 1]; if (!pageView.pdfPage) { pageView.setPdfPage(pdfPage); } this.linkService.cachePageRef(pageNum, pdfPage.ref); if (--getPagesLeft === 0) { this._pagesCapability.resolve(); } }, reason => { console.error(`Unable to get page ${pageNum} to initialize viewer`, reason); if (--getPagesLeft === 0) { this._pagesCapability.resolve(); } }); } }); this.eventBus.dispatch("pagesinit", { source: this }); if (this.defaultRenderingQueue) { this.update(); } }).catch(reason => { console.error("Unable to initialize viewer", reason); }); } setPageLabels(labels) { if (!this.pdfDocument) { return; } if (!labels) { this._pageLabels = null; } else if (!(Array.isArray(labels) && this.pdfDocument.numPages === labels.length)) { this._pageLabels = null; console.error(`${this._name}.setPageLabels: Invalid page labels.`); } else { this._pageLabels = labels; } for (let i = 0, ii = this._pages.length; i < ii; i++) { this._pages[i].setPageLabel(this._pageLabels?.[i] ?? null); } } _resetView() { this._pages = []; this._currentPageNumber = 1; this._currentScale = _ui_utils.UNKNOWN_SCALE; this._currentScaleValue = null; this._pageLabels = null; this._buffer = new PDFPageViewBuffer(DEFAULT_CACHE_SIZE); this._location = null; this._pagesRotation = 0; this._optionalContentConfigPromise = null; this._pagesRequests = new WeakMap(); this._firstPageCapability = (0, _pdfjsLib.createPromiseCapability)(); this._onePageRenderedCapability = (0, _pdfjsLib.createPromiseCapability)(); this._pagesCapability = (0, _pdfjsLib.createPromiseCapability)(); this._scrollMode = _ui_utils.ScrollMode.VERTICAL; this._spreadMode = _ui_utils.SpreadMode.NONE; if (this._onBeforeDraw) { this.eventBus._off("pagerender", this._onBeforeDraw); this._onBeforeDraw = null; } if (this._onAfterDraw) { this.eventBus._off("pagerendered", this._onAfterDraw); this._onAfterDraw = null; } this.viewer.textContent = ""; this._updateScrollMode(); } _scrollUpdate() { if (this.pagesCount === 0) { return; } this.update(); } _scrollIntoView({ pageDiv, pageSpot = null, pageNumber = null }) { (0, _ui_utils.scrollIntoView)(pageDiv, pageSpot); } _setScaleUpdatePages(newScale, newValue, noScroll = false, preset = false) { this._currentScaleValue = newValue.toString(); if (isSameScale(this._currentScale, newScale)) { if (preset) { this.eventBus.dispatch("scalechanging", { source: this, scale: newScale, presetValue: newValue }); } return; } for (let i = 0, ii = this._pages.length; i < ii; i++) { this._pages[i].update(newScale); } this._currentScale = newScale; if (!noScroll) { let page = this._currentPageNumber, dest; if (this._location && !(this.isInPresentationMode || this.isChangingPresentationMode)) { page = this._location.pageNumber; dest = [null, { name: "XYZ" }, this._location.left, this._location.top, null]; } this.scrollPageIntoView({ pageNumber: page, destArray: dest, allowNegativeOffset: true }); } this.eventBus.dispatch("scalechanging", { source: this, scale: newScale, presetValue: preset ? newValue : undefined }); if (this.defaultRenderingQueue) { this.update(); } } get _pageWidthScaleFactor() { if (this._spreadMode !== _ui_utils.SpreadMode.NONE && this._scrollMode !== _ui_utils.ScrollMode.HORIZONTAL && !this.isInPresentationMode) { return 2; } return 1; } _setScale(value, noScroll = false) { let scale = parseFloat(value); if (scale > 0) { this._setScaleUpdatePages(scale, value, noScroll, false); } else { const currentPage = this._pages[this._currentPageNumber - 1]; if (!currentPage) { return; } const noPadding = this.isInPresentationMode || this.removePageBorders; let hPadding = noPadding ? 0 : _ui_utils.SCROLLBAR_PADDING; let vPadding = noPadding ? 0 : _ui_utils.VERTICAL_PADDING; if (!noPadding && this._isScrollModeHorizontal) { [hPadding, vPadding] = [vPadding, hPadding]; } const pageWidthScale = (this.container.clientWidth - hPadding) / currentPage.width * currentPage.scale / this._pageWidthScaleFactor; const pageHeightScale = (this.container.clientHeight - vPadding) / currentPage.height * currentPage.scale; switch (value) { case "page-actual": scale = 1; break; case "page-width": scale = pageWidthScale; break; case "page-height": scale = pageHeightScale; break; case "page-fit": scale = Math.min(pageWidthScale, pageHeightScale); break; case "auto": const horizontalScale = (0, _ui_utils.isPortraitOrientation)(currentPage) ? pageWidthScale : Math.min(pageHeightScale, pageWidthScale); scale = Math.min(_ui_utils.MAX_AUTO_SCALE, horizontalScale); break; default: console.error(`${this._name}._setScale: "${value}" is an unknown zoom value.`); return; } this._setScaleUpdatePages(scale, value, noScroll, true); } } _resetCurrentPageView() { if (this.isInPresentationMode) { this._setScale(this._currentScaleValue, true); } const pageView = this._pages[this._currentPageNumber - 1]; this._scrollIntoView({ pageDiv: pageView.div }); } pageLabelToPageNumber(label) { if (!this._pageLabels) { return null; } const i = this._pageLabels.indexOf(label); if (i < 0) { return null; } return i + 1; } scrollPageIntoView({ pageNumber, destArray = null, allowNegativeOffset = false, ignoreDestinationZoom = false }) { if (!this.pdfDocument) { return; } const pageView = Number.isInteger(pageNumber) && this._pages[pageNumber - 1]; if (!pageView) { console.error(`${this._name}.scrollPageIntoView: ` + `"${pageNumber}" is not a valid pageNumber parameter.`); return; } if (this.isInPresentationMode || !destArray) { this._setCurrentPageNumber(pageNumber, true); return; } let x = 0, y = 0; let width = 0, height = 0, widthScale, heightScale; const changeOrientation = pageView.rotation % 180 !== 0; const pageWidth = (changeOrientation ? pageView.height : pageView.width) / pageView.scale / _ui_utils.CSS_UNITS; const pageHeight = (changeOrientation ? pageView.width : pageView.height) / pageView.scale / _ui_utils.CSS_UNITS; let scale = 0; switch (destArray[1].name) { case "XYZ": x = destArray[2]; y = destArray[3]; scale = destArray[4]; x = x !== null ? x : 0; y = y !== null ? y : pageHeight; break; case "Fit": case "FitB": scale = "page-fit"; break; case "FitH": case "FitBH": y = destArray[2]; scale = "page-width"; if (y === null && this._location) { x = this._location.left; y = this._location.top; } else if (typeof y !== "number") { y = pageHeight; } break; case "FitV": case "FitBV": x = destArray[2]; width = pageWidth; height = pageHeight; scale = "page-height"; break; case "FitR": x = destArray[2]; y = destArray[3]; width = destArray[4] - x; height = destArray[5] - y; const hPadding = this.removePageBorders ? 0 : _ui_utils.SCROLLBAR_PADDING; const vPadding = this.removePageBorders ? 0 : _ui_utils.VERTICAL_PADDING; widthScale = (this.container.clientWidth - hPadding) / width / _ui_utils.CSS_UNITS; heightScale = (this.container.clientHeight - vPadding) / height / _ui_utils.CSS_UNITS; scale = Math.min(Math.abs(widthScale), Math.abs(heightScale)); break; default: console.error(`${this._name}.scrollPageIntoView: ` + `"${destArray[1].name}" is not a valid destination type.`); return; } if (!ignoreDestinationZoom) { if (scale && scale !== this._currentScale) { this.currentScaleValue = scale; } else if (this._currentScale === _ui_utils.UNKNOWN_SCALE) { this.currentScaleValue = _ui_utils.DEFAULT_SCALE_VALUE; } } if (scale === "page-fit" && !destArray[4]) { this._scrollIntoView({ pageDiv: pageView.div, pageNumber }); return; } const boundingRect = [pageView.viewport.convertToViewportPoint(x, y), pageView.viewport.convertToViewportPoint(x + width, y + height)]; let left = Math.min(boundingRect[0][0], boundingRect[1][0]); let top = Math.min(boundingRect[0][1], boundingRect[1][1]); if (!allowNegativeOffset) { left = Math.max(left, 0); top = Math.max(top, 0); } this._scrollIntoView({ pageDiv: pageView.div, pageSpot: { left, top }, pageNumber }); } _updateLocation(firstPage) { const currentScale = this._currentScale; const currentScaleValue = this._currentScaleValue; const normalizedScaleValue = parseFloat(currentScaleValue) === currentScale ? Math.round(currentScale * 10000) / 100 : currentScaleValue; const pageNumber = firstPage.id; let pdfOpenParams = "#page=" + pageNumber; pdfOpenParams += "&zoom=" + normalizedScaleValue; const currentPageView = this._pages[pageNumber - 1]; const container = this.container; const topLeft = currentPageView.getPagePoint(container.scrollLeft - firstPage.x, container.scrollTop - firstPage.y); const intLeft = Math.round(topLeft[0]); const intTop = Math.round(topLeft[1]); pdfOpenParams += "," + intLeft + "," + intTop; this._location = { pageNumber, scale: normalizedScaleValue, top: intTop, left: intLeft, rotation: this._pagesRotation, pdfOpenParams }; } _updateHelper(visiblePages) { throw new Error("Not implemented: _updateHelper"); } update() { const visible = this._getVisiblePages(); const visiblePages = visible.views, numVisiblePages = visiblePages.length; if (numVisiblePages === 0) { return; } const newCacheSize = Math.max(DEFAULT_CACHE_SIZE, 2 * numVisiblePages + 1); this._buffer.resize(newCacheSize, visiblePages); this.renderingQueue.renderHighestPriority(visible); this._updateHelper(visiblePages); this._updateLocation(visible.first); this.eventBus.dispatch("updateviewarea", { source: this, location: this._location }); } containsElement(element) { return this.container.contains(element); } focus() { this.container.focus(); } get _isScrollModeHorizontal() { return this.isInPresentationMode ? false : this._scrollMode === _ui_utils.ScrollMode.HORIZONTAL; } get _isContainerRtl() { return getComputedStyle(this.container).direction === "rtl"; } get isInPresentationMode() { return this.presentationModeState === _ui_utils.PresentationModeState.FULLSCREEN; } get isChangingPresentationMode() { return this.presentationModeState === _ui_utils.PresentationModeState.CHANGING; } get isHorizontalScrollbarEnabled() { return this.isInPresentationMode ? false : this.container.scrollWidth > this.container.clientWidth; } get isVerticalScrollbarEnabled() { return this.isInPresentationMode ? false : this.container.scrollHeight > this.container.clientHeight; } _getCurrentVisiblePage() { if (!this.pagesCount) { return { views: [] }; } const pageView = this._pages[this._currentPageNumber - 1]; const element = pageView.div; const view = { id: pageView.id, x: element.offsetLeft + element.clientLeft, y: element.offsetTop + element.clientTop, view: pageView }; return { first: view, last: view, views: [view] }; } _getVisiblePages() { return (0, _ui_utils.getVisibleElements)({ scrollEl: this.container, views: this._pages, sortByVisibility: true, horizontal: this._isScrollModeHorizontal, rtl: this._isScrollModeHorizontal && this._isContainerRtl }); } isPageVisible(pageNumber) { if (!this.pdfDocument) { return false; } if (!(Number.isInteger(pageNumber) && pageNumber > 0 && pageNumber <= this.pagesCount)) { console.error(`${this._name}.isPageVisible: "${pageNumber}" is not a valid page.`); return false; } return this._getVisiblePages().views.some(function (view) { return view.id === pageNumber; }); } isPageCached(pageNumber) { if (!this.pdfDocument || !this._buffer) { return false; } if (!(Number.isInteger(pageNumber) && pageNumber > 0 && pageNumber <= this.pagesCount)) { console.error(`${this._name}.isPageCached: "${pageNumber}" is not a valid page.`); return false; } const pageView = this._pages[pageNumber - 1]; if (!pageView) { return false; } return this._buffer.has(pageView); } cleanup() { for (let i = 0, ii = this._pages.length; i < ii; i++) { if (this._pages[i] && this._pages[i].renderingState !== _pdf_rendering_queue.RenderingStates.FINISHED) { this._pages[i].reset(); } } } _cancelRendering() { for (let i = 0, ii = this._pages.length; i < ii; i++) { if (this._pages[i]) { this._pages[i].cancelRendering(); } } } _ensurePdfPageLoaded(pageView) { if (pageView.pdfPage) { return Promise.resolve(pageView.pdfPage); } if (this._pagesRequests.has(pageView)) { return this._pagesRequests.get(pageView); } const promise = this.pdfDocument.getPage(pageView.id).then(pdfPage => { if (!pageView.pdfPage) { pageView.setPdfPage(pdfPage); } this._pagesRequests.delete(pageView); return pdfPage; }).catch(reason => { console.error("Unable to get page for page view", reason); this._pagesRequests.delete(pageView); }); this._pagesRequests.set(pageView, promise); return promise; } forceRendering(currentlyVisiblePages) { const visiblePages = currentlyVisiblePages || this._getVisiblePages(); const scrollAhead = this._isScrollModeHorizontal ? this.scroll.right : this.scroll.down; const pageView = this.renderingQueue.getHighestPriority(visiblePages, this._pages, scrollAhead); if (pageView) { this._ensurePdfPageLoaded(pageView).then(() => { this.renderingQueue.renderView(pageView); }); return true; } return false; } createTextLayerBuilder(textLayerDiv, pageIndex, viewport, enhanceTextSelection = false, eventBus) { return new _text_layer_builder.TextLayerBuilder({ textLayerDiv, eventBus, pageIndex, viewport, findController: this.isInPresentationMode ? null : this.findController, enhanceTextSelection: this.isInPresentationMode ? false : enhanceTextSelection }); } createAnnotationLayerBuilder(pageDiv, pdfPage, annotationStorage = null, imageResourcesPath = "", renderInteractiveForms = false, l10n = _l10n_utils.NullL10n, enableScripting = false, hasJSActionsPromise = null, mouseState = null) { return new _annotation_layer_builder.AnnotationLayerBuilder({ pageDiv, pdfPage, annotationStorage: annotationStorage || this.pdfDocument?.annotationStorage, imageResourcesPath, renderInteractiveForms, linkService: this.linkService, downloadManager: this.downloadManager, l10n, enableScripting, hasJSActionsPromise: hasJSActionsPromise || this.pdfDocument?.hasJSActions(), mouseState: mouseState || this._scriptingManager?.mouseState }); } createXfaLayerBuilder(pageDiv, pdfPage) { return new _xfa_layer_builder.XfaLayerBuilder({ pageDiv, pdfPage }); } get hasEqualPageSizes() { const firstPageView = this._pages[0]; for (let i = 1, ii = this._pages.length; i < ii; ++i) { const pageView = this._pages[i]; if (pageView.width !== firstPageView.width || pageView.height !== firstPageView.height) { return false; } } return true; } getPagesOverview() { return this._pages.map(pageView => { const viewport = pageView.pdfPage.getViewport({ scale: 1 }); if (!this.enablePrintAutoRotate || (0, _ui_utils.isPortraitOrientation)(viewport)) { return { width: viewport.width, height: viewport.height, rotation: viewport.rotation }; } return { width: viewport.height, height: viewport.width, rotation: (viewport.rotation - 90) % 360 }; }); } get optionalContentConfigPromise() { if (!this.pdfDocument) { return Promise.resolve(null); } if (!this._optionalContentConfigPromise) { return this.pdfDocument.getOptionalContentConfig(); } return this._optionalContentConfigPromise; } set optionalContentConfigPromise(promise) { if (!(promise instanceof Promise)) { throw new Error(`Invalid optionalContentConfigPromise: ${promise}`); } if (!this.pdfDocument) { return; } if (!this._optionalContentConfigPromise) { return; } this._optionalContentConfigPromise = promise; for (const pageView of this._pages) { pageView.update(pageView.scale, pageView.rotation, promise); } this.update(); this.eventBus.dispatch("optionalcontentconfigchanged", { source: this, promise }); } get scrollMode() { return this._scrollMode; } set scrollMode(mode) { if (this._scrollMode === mode) { return; } if (!(0, _ui_utils.isValidScrollMode)(mode)) { throw new Error(`Invalid scroll mode: ${mode}`); } this._scrollMode = mode; this.eventBus.dispatch("scrollmodechanged", { source: this, mode }); this._updateScrollMode(this._currentPageNumber); } _updateScrollMode(pageNumber = null) { const scrollMode = this._scrollMode, viewer = this.viewer; viewer.classList.toggle("scrollHorizontal", scrollMode === _ui_utils.ScrollMode.HORIZONTAL); viewer.classList.toggle("scrollWrapped", scrollMode === _ui_utils.ScrollMode.WRAPPED); if (!this.pdfDocument || !pageNumber) { return; } if (this._currentScaleValue && isNaN(this._currentScaleValue)) { this._setScale(this._currentScaleValue, true); } this._setCurrentPageNumber(pageNumber, true); this.update(); } get spreadMode() { return this._spreadMode; } set spreadMode(mode) { if (this._spreadMode === mode) { return; } if (!(0, _ui_utils.isValidSpreadMode)(mode)) { throw new Error(`Invalid spread mode: ${mode}`); } this._spreadMode = mode; this.eventBus.dispatch("spreadmodechanged", { source: this, mode }); this._updateSpreadMode(this._currentPageNumber); } _updateSpreadMode(pageNumber = null) { if (!this.pdfDocument) { return; } const viewer = this.viewer, pages = this._pages; viewer.textContent = ""; if (this._spreadMode === _ui_utils.SpreadMode.NONE) { for (let i = 0, iMax = pages.length; i < iMax; ++i) { viewer.appendChild(pages[i].div); } } else { const parity = this._spreadMode - 1; let spread = null; for (let i = 0, iMax = pages.length; i < iMax; ++i) { if (spread === null) { spread = document.createElement("div"); spread.className = "spread"; viewer.appendChild(spread); } else if (i % 2 === parity) { spread = spread.cloneNode(false); viewer.appendChild(spread); } spread.appendChild(pages[i].div); } } if (!pageNumber) { return; } if (this._currentScaleValue && isNaN(this._currentScaleValue)) { this._setScale(this._currentScaleValue, true); } this._setCurrentPageNumber(pageNumber, true); this.update(); } _getPageAdvance(currentPageNumber, previous = false) { if (this.isInPresentationMode) { return 1; } switch (this._scrollMode) { case _ui_utils.ScrollMode.WRAPPED: { const { views } = this._getVisiblePages(), pageLayout = new Map(); for (const { id, y, percent, widthPercent } of views) { if (percent === 0 || widthPercent < 100) { continue; } let yArray = pageLayout.get(y); if (!yArray) { pageLayout.set(y, yArray || (yArray = [])); } yArray.push(id); } for (const yArray of pageLayout.values()) { const currentIndex = yArray.indexOf(currentPageNumber); if (currentIndex === -1) { continue; } const numPages = yArray.length; if (numPages === 1) { break; } if (previous) { for (let i = currentIndex - 1, ii = 0; i >= ii; i--) { const currentId = yArray[i], expectedId = yArray[i + 1] - 1; if (currentId < expectedId) { return currentPageNumber - expectedId; } } } else { for (let i = currentIndex + 1, ii = numPages; i < ii; i++) { const currentId = yArray[i], expectedId = yArray[i - 1] + 1; if (currentId > expectedId) { return expectedId - currentPageNumber; } } } if (previous) { const firstId = yArray[0]; if (firstId < currentPageNumber) { return currentPageNumber - firstId + 1; } } else { const lastId = yArray[numPages - 1]; if (lastId > currentPageNumber) { return lastId - currentPageNumber + 1; } } break; } break; } case _ui_utils.ScrollMode.HORIZONTAL: { break; } case _ui_utils.ScrollMode.VERTICAL: { if (this._spreadMode === _ui_utils.SpreadMode.NONE) { break; } const parity = this._spreadMode - 1; if (previous && currentPageNumber % 2 !== parity) { break; } else if (!previous && currentPageNumber % 2 === parity) { break; } const { views } = this._getVisiblePages(), expectedId = previous ? currentPageNumber - 1 : currentPageNumber + 1; for (const { id, percent, widthPercent } of views) { if (id !== expectedId) { continue; } if (percent > 0 && widthPercent === 100) { return 2; } break; } break; } } return 1; } nextPage() { const currentPageNumber = this._currentPageNumber, pagesCount = this.pagesCount; if (currentPageNumber >= pagesCount) { return false; } const advance = this._getPageAdvance(currentPageNumber, false) || 1; this.currentPageNumber = Math.min(currentPageNumber + advance, pagesCount); return true; } previousPage() { const currentPageNumber = this._currentPageNumber; if (currentPageNumber <= 1) { return false; } const advance = this._getPageAdvance(currentPageNumber, true) || 1; this.currentPageNumber = Math.max(currentPageNumber - advance, 1); return true; } } exports.BaseViewer = BaseViewer; /***/ }), /* 29 */ /***/ ((__unused_webpack_module, exports, __webpack_require__) => { Object.defineProperty(exports, "__esModule", ({ value: true })); exports.DefaultAnnotationLayerFactory = exports.AnnotationLayerBuilder = void 0; var _pdfjsLib = __webpack_require__(5); var _l10n_utils = __webpack_require__(30); var _pdf_link_service = __webpack_require__(19); class AnnotationLayerBuilder { constructor({ pageDiv, pdfPage, linkService, downloadManager, annotationStorage = null, imageResourcesPath = "", renderInteractiveForms = true, l10n = _l10n_utils.NullL10n, enableScripting = false, hasJSActionsPromise = null, mouseState = null }) { this.pageDiv = pageDiv; this.pdfPage = pdfPage; this.linkService = linkService; this.downloadManager = downloadManager; this.imageResourcesPath = imageResourcesPath; this.renderInteractiveForms = renderInteractiveForms; this.l10n = l10n; this.annotationStorage = annotationStorage; this.enableScripting = enableScripting; this._hasJSActionsPromise = hasJSActionsPromise; this._mouseState = mouseState; this.div = null; this._cancelled = false; } render(viewport, intent = "display") { return Promise.all([this.pdfPage.getAnnotations({ intent }), this._hasJSActionsPromise]).then(([annotations, hasJSActions = false]) => { if (this._cancelled) { return; } if (annotations.length === 0) { return; } const parameters = { viewport: viewport.clone({ dontFlip: true }), div: this.div, annotations, page: this.pdfPage, imageResourcesPath: this.imageResourcesPath, renderInteractiveForms: this.renderInteractiveForms, linkService: this.linkService, downloadManager: this.downloadManager, annotationStorage: this.annotationStorage, enableScripting: this.enableScripting, hasJSActions, mouseState: this._mouseState }; if (this.div) { _pdfjsLib.AnnotationLayer.update(parameters); } else { this.div = document.createElement("div"); this.div.className = "annotationLayer"; this.pageDiv.appendChild(this.div); parameters.div = this.div; _pdfjsLib.AnnotationLayer.render(parameters); this.l10n.translate(this.div); } }); } cancel() { this._cancelled = true; } hide() { if (!this.div) { return; } this.div.hidden = true; } } exports.AnnotationLayerBuilder = AnnotationLayerBuilder; class DefaultAnnotationLayerFactory { createAnnotationLayerBuilder(pageDiv, pdfPage, annotationStorage = null, imageResourcesPath = "", renderInteractiveForms = true, l10n = _l10n_utils.NullL10n, enableScripting = false, hasJSActionsPromise = null, mouseState = null) { return new AnnotationLayerBuilder({ pageDiv, pdfPage, imageResourcesPath, renderInteractiveForms, linkService: new _pdf_link_service.SimpleLinkService(), l10n, annotationStorage, enableScripting, hasJSActionsPromise, mouseState }); } } exports.DefaultAnnotationLayerFactory = DefaultAnnotationLayerFactory; /***/ }), /* 30 */ /***/ ((__unused_webpack_module, exports) => { Object.defineProperty(exports, "__esModule", ({ value: true })); exports.getL10nFallback = getL10nFallback; exports.NullL10n = void 0; const DEFAULT_L10N_STRINGS = { of_pages: "of {{pagesCount}}", page_of_pages: "({{pageNumber}} of {{pagesCount}})", document_properties_kb: "{{size_kb}} KB ({{size_b}} bytes)", document_properties_mb: "{{size_mb}} MB ({{size_b}} bytes)", document_properties_date_string: "{{date}}, {{time}}", document_properties_page_size_unit_inches: "in", document_properties_page_size_unit_millimeters: "mm", document_properties_page_size_orientation_portrait: "portrait", document_properties_page_size_orientation_landscape: "landscape", document_properties_page_size_name_a3: "A3", document_properties_page_size_name_a4: "A4", document_properties_page_size_name_letter: "Letter", document_properties_page_size_name_legal: "Legal", document_properties_page_size_dimension_string: "{{width}} × {{height}} {{unit}} ({{orientation}})", document_properties_page_size_dimension_name_string: "{{width}} × {{height}} {{unit}} ({{name}}, {{orientation}})", document_properties_linearized_yes: "Yes", document_properties_linearized_no: "No", print_progress_percent: "{{progress}}%", "toggle_sidebar.title": "Toggle Sidebar", "toggle_sidebar_notification2.title": "Toggle Sidebar (document contains outline/attachments/layers)", additional_layers: "Additional Layers", page_landmark: "Page {{page}}", thumb_page_title: "Page {{page}}", thumb_page_canvas: "Thumbnail of Page {{page}}", find_reached_top: "Reached top of document, continued from bottom", find_reached_bottom: "Reached end of document, continued from top", "find_match_count[one]": "{{current}} of {{total}} match", "find_match_count[other]": "{{current}} of {{total}} matches", "find_match_count_limit[one]": "More than {{limit}} match", "find_match_count_limit[other]": "More than {{limit}} matches", find_not_found: "Phrase not found", error_version_info: "PDF.js v{{version}} (build: {{build}})", error_message: "Message: {{message}}", error_stack: "Stack: {{stack}}", error_file: "File: {{file}}", error_line: "Line: {{line}}", rendering_error: "An error occurred while rendering the page.", page_scale_width: "Page Width", page_scale_fit: "Page Fit", page_scale_auto: "Automatic Zoom", page_scale_actual: "Actual Size", page_scale_percent: "{{scale}}%", loading: "Loading…", loading_error: "An error occurred while loading the PDF.", invalid_file_error: "Invalid or corrupted PDF file.", missing_file_error: "Missing PDF file.", unexpected_response_error: "Unexpected server response.", printing_not_supported: "Warning: Printing is not fully supported by this browser.", printing_not_ready: "Warning: The PDF is not fully loaded for printing.", web_fonts_disabled: "Web fonts are disabled: unable to use embedded PDF fonts." }; function getL10nFallback(key, args) { switch (key) { case "find_match_count": key = `find_match_count[${args.total === 1 ? "one" : "other"}]`; break; case "find_match_count_limit": key = `find_match_count_limit[${args.limit === 1 ? "one" : "other"}]`; break; } return DEFAULT_L10N_STRINGS[key] || ""; } function formatL10nValue(text, args) { if (!args) { return text; } return text.replace(/\{\{\s*(\w+)\s*\}\}/g, (all, name) => { return name in args ? args[name] : "{{" + name + "}}"; }); } const NullL10n = { async getLanguage() { return "en-us"; }, async getDirection() { return "ltr"; }, async get(key, args = null, fallback = getL10nFallback(key, args)) { return formatL10nValue(fallback, args); }, async translate(element) {} }; exports.NullL10n = NullL10n; /***/ }), /* 31 */ /***/ ((__unused_webpack_module, exports, __webpack_require__) => { Object.defineProperty(exports, "__esModule", ({ value: true })); exports.PDFPageView = void 0; var _ui_utils = __webpack_require__(4); var _pdfjsLib = __webpack_require__(5); var _l10n_utils = __webpack_require__(30); var _pdf_rendering_queue = __webpack_require__(8); var _viewer_compatibility = __webpack_require__(2); const MAX_CANVAS_PIXELS = _viewer_compatibility.viewerCompatibilityParams.maxCanvasPixels || 16777216; class PDFPageView { constructor(options) { const container = options.container; const defaultViewport = options.defaultViewport; this.id = options.id; this.renderingId = "page" + this.id; this.pdfPage = null; this.pageLabel = null; this.rotation = 0; this.scale = options.scale || _ui_utils.DEFAULT_SCALE; this.viewport = defaultViewport; this.pdfPageRotate = defaultViewport.rotation; this._optionalContentConfigPromise = options.optionalContentConfigPromise || null; this.hasRestrictedScaling = false; this.textLayerMode = Number.isInteger(options.textLayerMode) ? options.textLayerMode : _ui_utils.TextLayerMode.ENABLE; this.imageResourcesPath = options.imageResourcesPath || ""; this.renderInteractiveForms = options.renderInteractiveForms !== false; this.useOnlyCssZoom = options.useOnlyCssZoom || false; this.maxCanvasPixels = options.maxCanvasPixels || MAX_CANVAS_PIXELS; this.eventBus = options.eventBus; this.renderingQueue = options.renderingQueue; this.textLayerFactory = options.textLayerFactory; this.annotationLayerFactory = options.annotationLayerFactory; this.xfaLayerFactory = options.xfaLayerFactory; this.renderer = options.renderer || _ui_utils.RendererType.CANVAS; this.enableWebGL = options.enableWebGL || false; this.l10n = options.l10n || _l10n_utils.NullL10n; this.enableScripting = options.enableScripting === true; this.paintTask = null; this.paintedViewportMap = new WeakMap(); this.renderingState = _pdf_rendering_queue.RenderingStates.INITIAL; this.resume = null; this._renderError = null; this.annotationLayer = null; this.textLayer = null; this.zoomLayer = null; this.xfaLayer = null; const div = document.createElement("div"); div.className = "page"; div.style.width = Math.floor(this.viewport.width) + "px"; div.style.height = Math.floor(this.viewport.height) + "px"; div.setAttribute("data-page-number", this.id); div.setAttribute("role", "region"); this.l10n.get("page_landmark", { page: this.id }).then(msg => { div.setAttribute("aria-label", msg); }); this.div = div; container.appendChild(div); } setPdfPage(pdfPage) { this.pdfPage = pdfPage; this.pdfPageRotate = pdfPage.rotate; const totalRotation = (this.rotation + this.pdfPageRotate) % 360; this.viewport = pdfPage.getViewport({ scale: this.scale * _ui_utils.CSS_UNITS, rotation: totalRotation }); this.reset(); } destroy() { this.reset(); if (this.pdfPage) { this.pdfPage.cleanup(); } } async _renderAnnotationLayer() { let error = null; try { await this.annotationLayer.render(this.viewport, "display"); } catch (ex) { error = ex; } finally { this.eventBus.dispatch("annotationlayerrendered", { source: this, pageNumber: this.id, error }); } } async _renderXfaLayer() { let error = null; try { await this.xfaLayer.render(this.viewport, "display"); } catch (ex) { error = ex; } finally { this.eventBus.dispatch("xfalayerrendered", { source: this, pageNumber: this.id, error }); } } _resetZoomLayer(removeFromDOM = false) { if (!this.zoomLayer) { return; } const zoomLayerCanvas = this.zoomLayer.firstChild; this.paintedViewportMap.delete(zoomLayerCanvas); zoomLayerCanvas.width = 0; zoomLayerCanvas.height = 0; if (removeFromDOM) { this.zoomLayer.remove(); } this.zoomLayer = null; } reset(keepZoomLayer = false, keepAnnotations = false) { this.cancelRendering(keepAnnotations); this.renderingState = _pdf_rendering_queue.RenderingStates.INITIAL; const div = this.div; div.style.width = Math.floor(this.viewport.width) + "px"; div.style.height = Math.floor(this.viewport.height) + "px"; const childNodes = div.childNodes; const currentZoomLayerNode = keepZoomLayer && this.zoomLayer || null; const currentAnnotationNode = keepAnnotations && this.annotationLayer?.div || null; const currentXfaLayerNode = this.xfaLayer?.div || null; for (let i = childNodes.length - 1; i >= 0; i--) { const node = childNodes[i]; if (currentZoomLayerNode === node || currentAnnotationNode === node || currentXfaLayerNode === node) { continue; } div.removeChild(node); } div.removeAttribute("data-loaded"); if (currentAnnotationNode) { this.annotationLayer.hide(); } else if (this.annotationLayer) { this.annotationLayer.cancel(); this.annotationLayer = null; } if (!currentZoomLayerNode) { if (this.canvas) { this.paintedViewportMap.delete(this.canvas); this.canvas.width = 0; this.canvas.height = 0; delete this.canvas; } this._resetZoomLayer(); } if (this.svg) { this.paintedViewportMap.delete(this.svg); delete this.svg; } this.loadingIconDiv = document.createElement("div"); this.loadingIconDiv.className = "loadingIcon"; this.loadingIconDiv.setAttribute("role", "img"); this.l10n.get("loading").then(msg => { this.loadingIconDiv?.setAttribute("aria-label", msg); }); div.appendChild(this.loadingIconDiv); } update(scale, rotation, optionalContentConfigPromise = null) { this.scale = scale || this.scale; if (typeof rotation !== "undefined") { this.rotation = rotation; } if (optionalContentConfigPromise instanceof Promise) { this._optionalContentConfigPromise = optionalContentConfigPromise; } const totalRotation = (this.rotation + this.pdfPageRotate) % 360; this.viewport = this.viewport.clone({ scale: this.scale * _ui_utils.CSS_UNITS, rotation: totalRotation }); if (this.svg) { this.cssTransform(this.svg, true); this.eventBus.dispatch("pagerendered", { source: this, pageNumber: this.id, cssTransform: true, timestamp: performance.now(), error: this._renderError }); return; } let isScalingRestricted = false; if (this.canvas && this.maxCanvasPixels > 0) { const outputScale = this.outputScale; if ((Math.floor(this.viewport.width) * outputScale.sx | 0) * (Math.floor(this.viewport.height) * outputScale.sy | 0) > this.maxCanvasPixels) { isScalingRestricted = true; } } if (this.canvas) { if (this.useOnlyCssZoom || this.hasRestrictedScaling && isScalingRestricted) { this.cssTransform(this.canvas, true); this.eventBus.dispatch("pagerendered", { source: this, pageNumber: this.id, cssTransform: true, timestamp: performance.now(), error: this._renderError }); return; } if (!this.zoomLayer && !this.canvas.hidden) { this.zoomLayer = this.canvas.parentNode; this.zoomLayer.style.position = "absolute"; } } if (this.zoomLayer) { this.cssTransform(this.zoomLayer.firstChild); } this.reset(true, true); } cancelRendering(keepAnnotations = false) { if (this.paintTask) { this.paintTask.cancel(); this.paintTask = null; } this.resume = null; if (this.textLayer) { this.textLayer.cancel(); this.textLayer = null; } if (!keepAnnotations && this.annotationLayer) { this.annotationLayer.cancel(); this.annotationLayer = null; } } cssTransform(target, redrawAnnotations = false) { const width = this.viewport.width; const height = this.viewport.height; const div = this.div; target.style.width = target.parentNode.style.width = div.style.width = Math.floor(width) + "px"; target.style.height = target.parentNode.style.height = div.style.height = Math.floor(height) + "px"; const relativeRotation = this.viewport.rotation - this.paintedViewportMap.get(target).rotation; const absRotation = Math.abs(relativeRotation); let scaleX = 1, scaleY = 1; if (absRotation === 90 || absRotation === 270) { scaleX = height / width; scaleY = width / height; } target.style.transform = `rotate(${relativeRotation}deg) scale(${scaleX}, ${scaleY})`; if (this.textLayer) { const textLayerViewport = this.textLayer.viewport; const textRelativeRotation = this.viewport.rotation - textLayerViewport.rotation; const textAbsRotation = Math.abs(textRelativeRotation); let scale = width / textLayerViewport.width; if (textAbsRotation === 90 || textAbsRotation === 270) { scale = width / textLayerViewport.height; } const textLayerDiv = this.textLayer.textLayerDiv; let transX, transY; switch (textAbsRotation) { case 0: transX = transY = 0; break; case 90: transX = 0; transY = "-" + textLayerDiv.style.height; break; case 180: transX = "-" + textLayerDiv.style.width; transY = "-" + textLayerDiv.style.height; break; case 270: transX = "-" + textLayerDiv.style.width; transY = 0; break; default: console.error("Bad rotation value."); break; } textLayerDiv.style.transform = `rotate(${textAbsRotation}deg) ` + `scale(${scale}) ` + `translate(${transX}, ${transY})`; textLayerDiv.style.transformOrigin = "0% 0%"; } if (redrawAnnotations && this.annotationLayer) { this._renderAnnotationLayer(); } if (this.xfaLayer) { this._renderXfaLayer(); } } get width() { return this.viewport.width; } get height() { return this.viewport.height; } getPagePoint(x, y) { return this.viewport.convertToPdfPoint(x, y); } draw() { if (this.renderingState !== _pdf_rendering_queue.RenderingStates.INITIAL) { console.error("Must be in new state before drawing"); this.reset(); } const { div, pdfPage } = this; if (!pdfPage) { this.renderingState = _pdf_rendering_queue.RenderingStates.FINISHED; if (this.loadingIconDiv) { div.removeChild(this.loadingIconDiv); delete this.loadingIconDiv; } return Promise.reject(new Error("pdfPage is not loaded")); } this.renderingState = _pdf_rendering_queue.RenderingStates.RUNNING; const canvasWrapper = document.createElement("div"); canvasWrapper.style.width = div.style.width; canvasWrapper.style.height = div.style.height; canvasWrapper.classList.add("canvasWrapper"); if (this.annotationLayer?.div) { div.insertBefore(canvasWrapper, this.annotationLayer.div); } else { div.appendChild(canvasWrapper); } let textLayer = null; if (this.textLayerMode !== _ui_utils.TextLayerMode.DISABLE && this.textLayerFactory) { const textLayerDiv = document.createElement("div"); textLayerDiv.className = "textLayer"; textLayerDiv.style.width = canvasWrapper.style.width; textLayerDiv.style.height = canvasWrapper.style.height; if (this.annotationLayer?.div) { div.insertBefore(textLayerDiv, this.annotationLayer.div); } else { div.appendChild(textLayerDiv); } textLayer = this.textLayerFactory.createTextLayerBuilder(textLayerDiv, this.id - 1, this.viewport, this.textLayerMode === _ui_utils.TextLayerMode.ENABLE_ENHANCE, this.eventBus); } this.textLayer = textLayer; let renderContinueCallback = null; if (this.renderingQueue) { renderContinueCallback = cont => { if (!this.renderingQueue.isHighestPriority(this)) { this.renderingState = _pdf_rendering_queue.RenderingStates.PAUSED; this.resume = () => { this.renderingState = _pdf_rendering_queue.RenderingStates.RUNNING; cont(); }; return; } cont(); }; } const finishPaintTask = async (error = null) => { if (paintTask === this.paintTask) { this.paintTask = null; } if (error instanceof _pdfjsLib.RenderingCancelledException) { this._renderError = null; return; } this._renderError = error; this.renderingState = _pdf_rendering_queue.RenderingStates.FINISHED; if (this.loadingIconDiv) { div.removeChild(this.loadingIconDiv); delete this.loadingIconDiv; } this._resetZoomLayer(true); this.eventBus.dispatch("pagerendered", { source: this, pageNumber: this.id, cssTransform: false, timestamp: performance.now(), error: this._renderError }); if (error) { throw error; } }; const paintTask = this.renderer === _ui_utils.RendererType.SVG ? this.paintOnSvg(canvasWrapper) : this.paintOnCanvas(canvasWrapper); paintTask.onRenderContinue = renderContinueCallback; this.paintTask = paintTask; const resultPromise = paintTask.promise.then(function () { return finishPaintTask(null).then(function () { if (textLayer) { const readableStream = pdfPage.streamTextContent({ normalizeWhitespace: true }); textLayer.setTextContentStream(readableStream); textLayer.render(); } }); }, function (reason) { return finishPaintTask(reason); }); if (this.annotationLayerFactory) { if (!this.annotationLayer) { this.annotationLayer = this.annotationLayerFactory.createAnnotationLayerBuilder(div, pdfPage, null, this.imageResourcesPath, this.renderInteractiveForms, this.l10n, this.enableScripting, null, null); } this._renderAnnotationLayer(); } if (this.xfaLayerFactory) { if (!this.xfaLayer) { this.xfaLayer = this.xfaLayerFactory.createXfaLayerBuilder(div, pdfPage); } this._renderXfaLayer(); } div.setAttribute("data-loaded", true); this.eventBus.dispatch("pagerender", { source: this, pageNumber: this.id }); return resultPromise; } paintOnCanvas(canvasWrapper) { const renderCapability = (0, _pdfjsLib.createPromiseCapability)(); const result = { promise: renderCapability.promise, onRenderContinue(cont) { cont(); }, cancel() { renderTask.cancel(); } }; const viewport = this.viewport; const canvas = document.createElement("canvas"); canvas.hidden = true; let isCanvasHidden = true; const showCanvas = function () { if (isCanvasHidden) { canvas.hidden = false; isCanvasHidden = false; } }; canvasWrapper.appendChild(canvas); this.canvas = canvas; canvas.mozOpaque = true; const ctx = canvas.getContext("2d", { alpha: false }); const outputScale = (0, _ui_utils.getOutputScale)(ctx); this.outputScale = outputScale; if (this.useOnlyCssZoom) { const actualSizeViewport = viewport.clone({ scale: _ui_utils.CSS_UNITS }); outputScale.sx *= actualSizeViewport.width / viewport.width; outputScale.sy *= actualSizeViewport.height / viewport.height; outputScale.scaled = true; } if (this.maxCanvasPixels > 0) { const pixelsInViewport = viewport.width * viewport.height; const maxScale = Math.sqrt(this.maxCanvasPixels / pixelsInViewport); if (outputScale.sx > maxScale || outputScale.sy > maxScale) { outputScale.sx = maxScale; outputScale.sy = maxScale; outputScale.scaled = true; this.hasRestrictedScaling = true; } else { this.hasRestrictedScaling = false; } } const sfx = (0, _ui_utils.approximateFraction)(outputScale.sx); const sfy = (0, _ui_utils.approximateFraction)(outputScale.sy); canvas.width = (0, _ui_utils.roundToDivide)(viewport.width * outputScale.sx, sfx[0]); canvas.height = (0, _ui_utils.roundToDivide)(viewport.height * outputScale.sy, sfy[0]); canvas.style.width = (0, _ui_utils.roundToDivide)(viewport.width, sfx[1]) + "px"; canvas.style.height = (0, _ui_utils.roundToDivide)(viewport.height, sfy[1]) + "px"; this.paintedViewportMap.set(canvas, viewport); const transform = !outputScale.scaled ? null : [outputScale.sx, 0, 0, outputScale.sy, 0, 0]; const renderContext = { canvasContext: ctx, transform, viewport: this.viewport, enableWebGL: this.enableWebGL, renderInteractiveForms: this.renderInteractiveForms, optionalContentConfigPromise: this._optionalContentConfigPromise }; const renderTask = this.pdfPage.render(renderContext); renderTask.onContinue = function (cont) { showCanvas(); if (result.onRenderContinue) { result.onRenderContinue(cont); } else { cont(); } }; renderTask.promise.then(function () { showCanvas(); renderCapability.resolve(undefined); }, function (error) { showCanvas(); renderCapability.reject(error); }); return result; } paintOnSvg(wrapper) { let cancelled = false; const ensureNotCancelled = () => { if (cancelled) { throw new _pdfjsLib.RenderingCancelledException(`Rendering cancelled, page ${this.id}`, "svg"); } }; const pdfPage = this.pdfPage; const actualSizeViewport = this.viewport.clone({ scale: _ui_utils.CSS_UNITS }); const promise = pdfPage.getOperatorList().then(opList => { ensureNotCancelled(); const svgGfx = new _pdfjsLib.SVGGraphics(pdfPage.commonObjs, pdfPage.objs, _viewer_compatibility.viewerCompatibilityParams.disableCreateObjectURL); return svgGfx.getSVG(opList, actualSizeViewport).then(svg => { ensureNotCancelled(); this.svg = svg; this.paintedViewportMap.set(svg, actualSizeViewport); svg.style.width = wrapper.style.width; svg.style.height = wrapper.style.height; this.renderingState = _pdf_rendering_queue.RenderingStates.FINISHED; wrapper.appendChild(svg); }); }); return { promise, onRenderContinue(cont) { cont(); }, cancel() { cancelled = true; } }; } setPageLabel(label) { this.pageLabel = typeof label === "string" ? label : null; if (this.pageLabel !== null) { this.div.setAttribute("data-page-label", this.pageLabel); } else { this.div.removeAttribute("data-page-label"); } } } exports.PDFPageView = PDFPageView; /***/ }), /* 32 */ /***/ ((__unused_webpack_module, exports, __webpack_require__) => { Object.defineProperty(exports, "__esModule", ({ value: true })); exports.TextLayerBuilder = exports.DefaultTextLayerFactory = void 0; var _pdfjsLib = __webpack_require__(5); const EXPAND_DIVS_TIMEOUT = 300; class TextLayerBuilder { constructor({ textLayerDiv, eventBus, pageIndex, viewport, findController = null, enhanceTextSelection = false }) { this.textLayerDiv = textLayerDiv; this.eventBus = eventBus; this.textContent = null; this.textContentItemsStr = []; this.textContentStream = null; this.renderingDone = false; this.pageIdx = pageIndex; this.pageNumber = this.pageIdx + 1; this.matches = []; this.viewport = viewport; this.textDivs = []; this.findController = findController; this.textLayerRenderTask = null; this.enhanceTextSelection = enhanceTextSelection; this._onUpdateTextLayerMatches = null; this._bindMouse(); } _finishRendering() { this.renderingDone = true; if (!this.enhanceTextSelection) { const endOfContent = document.createElement("div"); endOfContent.className = "endOfContent"; this.textLayerDiv.appendChild(endOfContent); } this.eventBus.dispatch("textlayerrendered", { source: this, pageNumber: this.pageNumber, numTextDivs: this.textDivs.length }); } render(timeout = 0) { if (!(this.textContent || this.textContentStream) || this.renderingDone) { return; } this.cancel(); this.textDivs = []; const textLayerFrag = document.createDocumentFragment(); this.textLayerRenderTask = (0, _pdfjsLib.renderTextLayer)({ textContent: this.textContent, textContentStream: this.textContentStream, container: textLayerFrag, viewport: this.viewport, textDivs: this.textDivs, textContentItemsStr: this.textContentItemsStr, timeout, enhanceTextSelection: this.enhanceTextSelection }); this.textLayerRenderTask.promise.then(() => { this.textLayerDiv.appendChild(textLayerFrag); this._finishRendering(); this._updateMatches(); }, function (reason) {}); if (!this._onUpdateTextLayerMatches) { this._onUpdateTextLayerMatches = evt => { if (evt.pageIndex === this.pageIdx || evt.pageIndex === -1) { this._updateMatches(); } }; this.eventBus._on("updatetextlayermatches", this._onUpdateTextLayerMatches); } } cancel() { if (this.textLayerRenderTask) { this.textLayerRenderTask.cancel(); this.textLayerRenderTask = null; } if (this._onUpdateTextLayerMatches) { this.eventBus._off("updatetextlayermatches", this._onUpdateTextLayerMatches); this._onUpdateTextLayerMatches = null; } } setTextContentStream(readableStream) { this.cancel(); this.textContentStream = readableStream; } setTextContent(textContent) { this.cancel(); this.textContent = textContent; } _convertMatches(matches, matchesLength) { if (!matches) { return []; } const { textContentItemsStr } = this; let i = 0, iIndex = 0; const end = textContentItemsStr.length - 1; const result = []; for (let m = 0, mm = matches.length; m < mm; m++) { let matchIdx = matches[m]; while (i !== end && matchIdx >= iIndex + textContentItemsStr[i].length) { iIndex += textContentItemsStr[i].length; i++; } if (i === textContentItemsStr.length) { console.error("Could not find a matching mapping"); } const match = { begin: { divIdx: i, offset: matchIdx - iIndex } }; matchIdx += matchesLength[m]; while (i !== end && matchIdx > iIndex + textContentItemsStr[i].length) { iIndex += textContentItemsStr[i].length; i++; } match.end = { divIdx: i, offset: matchIdx - iIndex }; result.push(match); } return result; } _renderMatches(matches) { if (matches.length === 0) { return; } const { findController, pageIdx, textContentItemsStr, textDivs } = this; const isSelectedPage = pageIdx === findController.selected.pageIdx; const selectedMatchIdx = findController.selected.matchIdx; const highlightAll = findController.state.highlightAll; let prevEnd = null; const infinity = { divIdx: -1, offset: undefined }; function beginText(begin, className) { const divIdx = begin.divIdx; textDivs[divIdx].textContent = ""; appendTextToDiv(divIdx, 0, begin.offset, className); } function appendTextToDiv(divIdx, fromOffset, toOffset, className) { const div = textDivs[divIdx]; const content = textContentItemsStr[divIdx].substring(fromOffset, toOffset); const node = document.createTextNode(content); if (className) { const span = document.createElement("span"); span.className = className; span.appendChild(node); div.appendChild(span); return; } div.appendChild(node); } let i0 = selectedMatchIdx, i1 = i0 + 1; if (highlightAll) { i0 = 0; i1 = matches.length; } else if (!isSelectedPage) { return; } for (let i = i0; i < i1; i++) { const match = matches[i]; const begin = match.begin; const end = match.end; const isSelected = isSelectedPage && i === selectedMatchIdx; const highlightSuffix = isSelected ? " selected" : ""; if (isSelected) { findController.scrollMatchIntoView({ element: textDivs[begin.divIdx], pageIndex: pageIdx, matchIndex: selectedMatchIdx }); } if (!prevEnd || begin.divIdx !== prevEnd.divIdx) { if (prevEnd !== null) { appendTextToDiv(prevEnd.divIdx, prevEnd.offset, infinity.offset); } beginText(begin); } else { appendTextToDiv(prevEnd.divIdx, prevEnd.offset, begin.offset); } if (begin.divIdx === end.divIdx) { appendTextToDiv(begin.divIdx, begin.offset, end.offset, "highlight" + highlightSuffix); } else { appendTextToDiv(begin.divIdx, begin.offset, infinity.offset, "highlight begin" + highlightSuffix); for (let n0 = begin.divIdx + 1, n1 = end.divIdx; n0 < n1; n0++) { textDivs[n0].className = "highlight middle" + highlightSuffix; } beginText(end, "highlight end" + highlightSuffix); } prevEnd = end; } if (prevEnd) { appendTextToDiv(prevEnd.divIdx, prevEnd.offset, infinity.offset); } } _updateMatches() { if (!this.renderingDone) { return; } const { findController, matches, pageIdx, textContentItemsStr, textDivs } = this; let clearedUntilDivIdx = -1; for (let i = 0, ii = matches.length; i < ii; i++) { const match = matches[i]; const begin = Math.max(clearedUntilDivIdx, match.begin.divIdx); for (let n = begin, end = match.end.divIdx; n <= end; n++) { const div = textDivs[n]; div.textContent = textContentItemsStr[n]; div.className = ""; } clearedUntilDivIdx = match.end.divIdx + 1; } if (!findController?.highlightMatches) { return; } const pageMatches = findController.pageMatches[pageIdx] || null; const pageMatchesLength = findController.pageMatchesLength[pageIdx] || null; this.matches = this._convertMatches(pageMatches, pageMatchesLength); this._renderMatches(this.matches); } _bindMouse() { const div = this.textLayerDiv; let expandDivsTimer = null; div.addEventListener("mousedown", evt => { if (this.enhanceTextSelection && this.textLayerRenderTask) { this.textLayerRenderTask.expandTextDivs(true); if (expandDivsTimer) { clearTimeout(expandDivsTimer); expandDivsTimer = null; } return; } const end = div.querySelector(".endOfContent"); if (!end) { return; } let adjustTop = evt.target !== div; adjustTop = adjustTop && window.getComputedStyle(end).getPropertyValue("-moz-user-select") !== "none"; if (adjustTop) { const divBounds = div.getBoundingClientRect(); const r = Math.max(0, (evt.pageY - divBounds.top) / divBounds.height); end.style.top = (r * 100).toFixed(2) + "%"; } end.classList.add("active"); }); div.addEventListener("mouseup", () => { if (this.enhanceTextSelection && this.textLayerRenderTask) { expandDivsTimer = setTimeout(() => { if (this.textLayerRenderTask) { this.textLayerRenderTask.expandTextDivs(false); } expandDivsTimer = null; }, EXPAND_DIVS_TIMEOUT); return; } const end = div.querySelector(".endOfContent"); if (!end) { return; } end.style.top = ""; end.classList.remove("active"); }); } } exports.TextLayerBuilder = TextLayerBuilder; class DefaultTextLayerFactory { createTextLayerBuilder(textLayerDiv, pageIndex, viewport, enhanceTextSelection = false, eventBus) { return new TextLayerBuilder({ textLayerDiv, pageIndex, viewport, enhanceTextSelection, eventBus }); } } exports.DefaultTextLayerFactory = DefaultTextLayerFactory; /***/ }), /* 33 */ /***/ ((__unused_webpack_module, exports, __webpack_require__) => { Object.defineProperty(exports, "__esModule", ({ value: true })); exports.XfaLayerBuilder = exports.DefaultXfaLayerFactory = void 0; var _pdfjsLib = __webpack_require__(5); class XfaLayerBuilder { constructor({ pageDiv, pdfPage }) { this.pageDiv = pageDiv; this.pdfPage = pdfPage; this.div = null; this._cancelled = false; } render(viewport, intent = "display") { return this.pdfPage.getXfa().then(xfa => { if (this._cancelled) { return; } const parameters = { viewport: viewport.clone({ dontFlip: true }), div: this.div, xfa, page: this.pdfPage }; if (this.div) { _pdfjsLib.XfaLayer.update(parameters); } else { this.div = document.createElement("div"); this.pageDiv.appendChild(this.div); parameters.div = this.div; _pdfjsLib.XfaLayer.render(parameters); } }); } cancel() { this._cancelled = true; } hide() { if (!this.div) { return; } this.div.hidden = true; } } exports.XfaLayerBuilder = XfaLayerBuilder; class DefaultXfaLayerFactory { createXfaLayerBuilder(pageDiv, pdfPage) { return new XfaLayerBuilder({ pageDiv, pdfPage }); } } exports.DefaultXfaLayerFactory = DefaultXfaLayerFactory; /***/ }), /* 34 */ /***/ ((__unused_webpack_module, exports, __webpack_require__) => { Object.defineProperty(exports, "__esModule", ({ value: true })); exports.SecondaryToolbar = void 0; var _ui_utils = __webpack_require__(4); var _pdf_cursor_tools = __webpack_require__(6); var _pdf_single_page_viewer = __webpack_require__(35); class SecondaryToolbar { constructor(options, mainContainer, eventBus) { this.toolbar = options.toolbar; this.toggleButton = options.toggleButton; this.toolbarButtonContainer = options.toolbarButtonContainer; this.buttons = [{ element: options.presentationModeButton, eventName: "presentationmode", close: true }, { element: options.openFileButton, eventName: "openfile", close: true }, { element: options.printButton, eventName: "print", close: true }, { element: options.downloadButton, eventName: "download", close: true }, { element: options.viewBookmarkButton, eventName: null, close: true }, { element: options.firstPageButton, eventName: "firstpage", close: true }, { element: options.lastPageButton, eventName: "lastpage", close: true }, { element: options.pageRotateCwButton, eventName: "rotatecw", close: false }, { element: options.pageRotateCcwButton, eventName: "rotateccw", close: false }, { element: options.cursorSelectToolButton, eventName: "switchcursortool", eventDetails: { tool: _pdf_cursor_tools.CursorTool.SELECT }, close: true }, { element: options.cursorHandToolButton, eventName: "switchcursortool", eventDetails: { tool: _pdf_cursor_tools.CursorTool.HAND }, close: true }, { element: options.scrollVerticalButton, eventName: "switchscrollmode", eventDetails: { mode: _ui_utils.ScrollMode.VERTICAL }, close: true }, { element: options.scrollHorizontalButton, eventName: "switchscrollmode", eventDetails: { mode: _ui_utils.ScrollMode.HORIZONTAL }, close: true }, { element: options.scrollWrappedButton, eventName: "switchscrollmode", eventDetails: { mode: _ui_utils.ScrollMode.WRAPPED }, close: true }, { element: options.spreadNoneButton, eventName: "switchspreadmode", eventDetails: { mode: _ui_utils.SpreadMode.NONE }, close: true }, { element: options.spreadOddButton, eventName: "switchspreadmode", eventDetails: { mode: _ui_utils.SpreadMode.ODD }, close: true }, { element: options.spreadEvenButton, eventName: "switchspreadmode", eventDetails: { mode: _ui_utils.SpreadMode.EVEN }, close: true }, { element: options.documentPropertiesButton, eventName: "documentproperties", close: true }]; this.items = { firstPage: options.firstPageButton, lastPage: options.lastPageButton, pageRotateCw: options.pageRotateCwButton, pageRotateCcw: options.pageRotateCcwButton }; this.mainContainer = mainContainer; this.eventBus = eventBus; this.opened = false; this.containerHeight = null; this.previousContainerHeight = null; this.reset(); this._bindClickListeners(); this._bindCursorToolsListener(options); this._bindScrollModeListener(options); this._bindSpreadModeListener(options); this.eventBus._on("resize", this._setMaxHeight.bind(this)); this.eventBus._on("baseviewerinit", evt => { if (evt.source instanceof _pdf_single_page_viewer.PDFSinglePageViewer) { this.toolbarButtonContainer.classList.add("hiddenScrollModeButtons", "hiddenSpreadModeButtons"); } else { this.toolbarButtonContainer.classList.remove("hiddenScrollModeButtons", "hiddenSpreadModeButtons"); } }); } get isOpen() { return this.opened; } setPageNumber(pageNumber) { this.pageNumber = pageNumber; this._updateUIState(); } setPagesCount(pagesCount) { this.pagesCount = pagesCount; this._updateUIState(); } reset() { this.pageNumber = 0; this.pagesCount = 0; this._updateUIState(); this.eventBus.dispatch("secondarytoolbarreset", { source: this }); } _updateUIState() { this.items.firstPage.disabled = this.pageNumber <= 1; this.items.lastPage.disabled = this.pageNumber >= this.pagesCount; this.items.pageRotateCw.disabled = this.pagesCount === 0; this.items.pageRotateCcw.disabled = this.pagesCount === 0; } _bindClickListeners() { this.toggleButton.addEventListener("click", this.toggle.bind(this)); for (const { element, eventName, close, eventDetails } of this.buttons) { element.addEventListener("click", evt => { if (eventName !== null) { const details = { source: this }; for (const property in eventDetails) { details[property] = eventDetails[property]; } this.eventBus.dispatch(eventName, details); } if (close) { this.close(); } }); } } _bindCursorToolsListener(buttons) { this.eventBus._on("cursortoolchanged", function ({ tool }) { buttons.cursorSelectToolButton.classList.toggle("toggled", tool === _pdf_cursor_tools.CursorTool.SELECT); buttons.cursorHandToolButton.classList.toggle("toggled", tool === _pdf_cursor_tools.CursorTool.HAND); }); } _bindScrollModeListener(buttons) { function scrollModeChanged({ mode }) { buttons.scrollVerticalButton.classList.toggle("toggled", mode === _ui_utils.ScrollMode.VERTICAL); buttons.scrollHorizontalButton.classList.toggle("toggled", mode === _ui_utils.ScrollMode.HORIZONTAL); buttons.scrollWrappedButton.classList.toggle("toggled", mode === _ui_utils.ScrollMode.WRAPPED); const isScrollModeHorizontal = mode === _ui_utils.ScrollMode.HORIZONTAL; buttons.spreadNoneButton.disabled = isScrollModeHorizontal; buttons.spreadOddButton.disabled = isScrollModeHorizontal; buttons.spreadEvenButton.disabled = isScrollModeHorizontal; } this.eventBus._on("scrollmodechanged", scrollModeChanged); this.eventBus._on("secondarytoolbarreset", evt => { if (evt.source === this) { scrollModeChanged({ mode: _ui_utils.ScrollMode.VERTICAL }); } }); } _bindSpreadModeListener(buttons) { function spreadModeChanged({ mode }) { buttons.spreadNoneButton.classList.toggle("toggled", mode === _ui_utils.SpreadMode.NONE); buttons.spreadOddButton.classList.toggle("toggled", mode === _ui_utils.SpreadMode.ODD); buttons.spreadEvenButton.classList.toggle("toggled", mode === _ui_utils.SpreadMode.EVEN); } this.eventBus._on("spreadmodechanged", spreadModeChanged); this.eventBus._on("secondarytoolbarreset", evt => { if (evt.source === this) { spreadModeChanged({ mode: _ui_utils.SpreadMode.NONE }); } }); } open() { if (this.opened) { return; } this.opened = true; this._setMaxHeight(); this.toggleButton.classList.add("toggled"); this.toggleButton.setAttribute("aria-expanded", "true"); this.toolbar.classList.remove("hidden"); } close() { if (!this.opened) { return; } this.opened = false; this.toolbar.classList.add("hidden"); this.toggleButton.classList.remove("toggled"); this.toggleButton.setAttribute("aria-expanded", "false"); } toggle() { if (this.opened) { this.close(); } else { this.open(); } } _setMaxHeight() { if (!this.opened) { return; } this.containerHeight = this.mainContainer.clientHeight; if (this.containerHeight === this.previousContainerHeight) { return; } this.toolbarButtonContainer.style.maxHeight = `${this.containerHeight - _ui_utils.SCROLLBAR_PADDING}px`; this.previousContainerHeight = this.containerHeight; } } exports.SecondaryToolbar = SecondaryToolbar; /***/ }), /* 35 */ /***/ ((__unused_webpack_module, exports, __webpack_require__) => { Object.defineProperty(exports, "__esModule", ({ value: true })); exports.PDFSinglePageViewer = void 0; var _base_viewer = __webpack_require__(28); var _pdfjsLib = __webpack_require__(5); class PDFSinglePageViewer extends _base_viewer.BaseViewer { constructor(options) { super(options); this.eventBus._on("pagesinit", evt => { this._ensurePageViewVisible(); }); } get _viewerElement() { return (0, _pdfjsLib.shadow)(this, "_viewerElement", this._shadowViewer); } get _pageWidthScaleFactor() { return 1; } _resetView() { super._resetView(); this._previousPageNumber = 1; this._shadowViewer = document.createDocumentFragment(); this._updateScrollDown = null; } _ensurePageViewVisible() { const pageView = this._pages[this._currentPageNumber - 1]; const previousPageView = this._pages[this._previousPageNumber - 1]; const viewerNodes = this.viewer.childNodes; switch (viewerNodes.length) { case 0: this.viewer.appendChild(pageView.div); break; case 1: if (viewerNodes[0] !== previousPageView.div) { throw new Error("_ensurePageViewVisible: Unexpected previously visible page."); } if (pageView === previousPageView) { break; } this._shadowViewer.appendChild(previousPageView.div); this.viewer.appendChild(pageView.div); this.container.scrollTop = 0; break; default: throw new Error("_ensurePageViewVisible: Only one page should be visible at a time."); } this._previousPageNumber = this._currentPageNumber; } _scrollUpdate() { if (this._updateScrollDown) { this._updateScrollDown(); } super._scrollUpdate(); } _scrollIntoView({ pageDiv, pageSpot = null, pageNumber = null }) { if (pageNumber) { this._setCurrentPageNumber(pageNumber); } const scrolledDown = this._currentPageNumber >= this._previousPageNumber; this._ensurePageViewVisible(); this.update(); super._scrollIntoView({ pageDiv, pageSpot, pageNumber }); this._updateScrollDown = () => { this.scroll.down = scrolledDown; this._updateScrollDown = null; }; } _getVisiblePages() { return this._getCurrentVisiblePage(); } _updateHelper(visiblePages) {} get _isScrollModeHorizontal() { return (0, _pdfjsLib.shadow)(this, "_isScrollModeHorizontal", false); } _updateScrollMode() {} _updateSpreadMode() {} _getPageAdvance() { return 1; } } exports.PDFSinglePageViewer = PDFSinglePageViewer; /***/ }), /* 36 */ /***/ ((__unused_webpack_module, exports, __webpack_require__) => { Object.defineProperty(exports, "__esModule", ({ value: true })); exports.Toolbar = void 0; var _ui_utils = __webpack_require__(4); const PAGE_NUMBER_LOADING_INDICATOR = "visiblePageIsLoading"; const SCALE_SELECT_CONTAINER_WIDTH = 140; const SCALE_SELECT_WIDTH = 162; class Toolbar { constructor(options, eventBus, l10n) { this.toolbar = options.container; this.eventBus = eventBus; this.l10n = l10n; this.buttons = [{ element: options.previous, eventName: "previouspage" }, { element: options.next, eventName: "nextpage" }, { element: options.zoomIn, eventName: "zoomin" }, { element: options.zoomOut, eventName: "zoomout" }, { element: options.openFile, eventName: "openfile" }, { element: options.print, eventName: "print" }, { element: options.presentationModeButton, eventName: "presentationmode" }, { element: options.download, eventName: "download" }, { element: options.viewBookmark, eventName: null }]; this.items = { numPages: options.numPages, pageNumber: options.pageNumber, scaleSelectContainer: options.scaleSelectContainer, scaleSelect: options.scaleSelect, customScaleOption: options.customScaleOption, previous: options.previous, next: options.next, zoomIn: options.zoomIn, zoomOut: options.zoomOut }; this._wasLocalized = false; this.reset(); this._bindListeners(); } setPageNumber(pageNumber, pageLabel) { this.pageNumber = pageNumber; this.pageLabel = pageLabel; this._updateUIState(false); } setPagesCount(pagesCount, hasPageLabels) { this.pagesCount = pagesCount; this.hasPageLabels = hasPageLabels; this._updateUIState(true); } setPageScale(pageScaleValue, pageScale) { this.pageScaleValue = (pageScaleValue || pageScale).toString(); this.pageScale = pageScale; this._updateUIState(false); } reset() { this.pageNumber = 0; this.pageLabel = null; this.hasPageLabels = false; this.pagesCount = 0; this.pageScaleValue = _ui_utils.DEFAULT_SCALE_VALUE; this.pageScale = _ui_utils.DEFAULT_SCALE; this._updateUIState(true); this.updateLoadingIndicatorState(); } _bindListeners() { const { pageNumber, scaleSelect } = this.items; const self = this; for (const { element, eventName } of this.buttons) { element.addEventListener("click", evt => { if (eventName !== null) { this.eventBus.dispatch(eventName, { source: this }); } }); } pageNumber.addEventListener("click", function () { this.select(); }); pageNumber.addEventListener("change", function () { self.eventBus.dispatch("pagenumberchanged", { source: self, value: this.value }); }); scaleSelect.addEventListener("change", function () { if (this.value === "custom") { return; } self.eventBus.dispatch("scalechanged", { source: self, value: this.value }); }); scaleSelect.oncontextmenu = _ui_utils.noContextMenuHandler; this.eventBus._on("localized", () => { this._wasLocalized = true; this._adjustScaleWidth(); this._updateUIState(true); }); } _updateUIState(resetNumPages = false) { if (!this._wasLocalized) { return; } const { pageNumber, pagesCount, pageScaleValue, pageScale, items } = this; if (resetNumPages) { if (this.hasPageLabels) { items.pageNumber.type = "text"; } else { items.pageNumber.type = "number"; this.l10n.get("of_pages", { pagesCount }).then(msg => { items.numPages.textContent = msg; }); } items.pageNumber.max = pagesCount; } if (this.hasPageLabels) { items.pageNumber.value = this.pageLabel; this.l10n.get("page_of_pages", { pageNumber, pagesCount }).then(msg => { items.numPages.textContent = msg; }); } else { items.pageNumber.value = pageNumber; } items.previous.disabled = pageNumber <= 1; items.next.disabled = pageNumber >= pagesCount; items.zoomOut.disabled = pageScale <= _ui_utils.MIN_SCALE; items.zoomIn.disabled = pageScale >= _ui_utils.MAX_SCALE; this.l10n.get("page_scale_percent", { scale: Math.round(pageScale * 10000) / 100 }).then(msg => { let predefinedValueFound = false; for (const option of items.scaleSelect.options) { if (option.value !== pageScaleValue) { option.selected = false; continue; } option.selected = true; predefinedValueFound = true; } if (!predefinedValueFound) { items.customScaleOption.textContent = msg; items.customScaleOption.selected = true; } }); } updateLoadingIndicatorState(loading = false) { const pageNumberInput = this.items.pageNumber; pageNumberInput.classList.toggle(PAGE_NUMBER_LOADING_INDICATOR, loading); } async _adjustScaleWidth() { const { items, l10n } = this; const predefinedValuesPromise = Promise.all([l10n.get("page_scale_auto"), l10n.get("page_scale_actual"), l10n.get("page_scale_fit"), l10n.get("page_scale_width")]); let canvas = document.createElement("canvas"); canvas.mozOpaque = true; let ctx = canvas.getContext("2d", { alpha: false }); await _ui_utils.animationStarted; const { fontSize, fontFamily } = getComputedStyle(items.scaleSelect); ctx.font = `${fontSize} ${fontFamily}`; let maxWidth = 0; for (const predefinedValue of await predefinedValuesPromise) { const { width } = ctx.measureText(predefinedValue); if (width > maxWidth) { maxWidth = width; } } const overflow = SCALE_SELECT_WIDTH - SCALE_SELECT_CONTAINER_WIDTH; maxWidth += 2 * overflow; if (maxWidth > SCALE_SELECT_CONTAINER_WIDTH) { items.scaleSelect.style.width = `${maxWidth + overflow}px`; items.scaleSelectContainer.style.width = `${maxWidth}px`; } canvas.width = 0; canvas.height = 0; canvas = ctx = null; } } exports.Toolbar = Toolbar; /***/ }), /* 37 */ /***/ ((__unused_webpack_module, exports) => { Object.defineProperty(exports, "__esModule", ({ value: true })); exports.ViewHistory = void 0; const DEFAULT_VIEW_HISTORY_CACHE_SIZE = 20; class ViewHistory { constructor(fingerprint, cacheSize = DEFAULT_VIEW_HISTORY_CACHE_SIZE) { this.fingerprint = fingerprint; this.cacheSize = cacheSize; this._initializedPromise = this._readFromStorage().then(databaseStr => { const database = JSON.parse(databaseStr || "{}"); let index = -1; if (!Array.isArray(database.files)) { database.files = []; } else { while (database.files.length >= this.cacheSize) { database.files.shift(); } for (let i = 0, ii = database.files.length; i < ii; i++) { const branch = database.files[i]; if (branch.fingerprint === this.fingerprint) { index = i; break; } } } if (index === -1) { index = database.files.push({ fingerprint: this.fingerprint }) - 1; } this.file = database.files[index]; this.database = database; }); } async _writeToStorage() { const databaseStr = JSON.stringify(this.database); localStorage.setItem("pdfjs.history", databaseStr); } async _readFromStorage() { return localStorage.getItem("pdfjs.history"); } async set(name, val) { await this._initializedPromise; this.file[name] = val; return this._writeToStorage(); } async setMultiple(properties) { await this._initializedPromise; for (const name in properties) { this.file[name] = properties[name]; } return this._writeToStorage(); } async get(name, defaultValue) { await this._initializedPromise; const val = this.file[name]; return val !== undefined ? val : defaultValue; } async getMultiple(properties) { await this._initializedPromise; const values = Object.create(null); for (const name in properties) { const val = this.file[name]; values[name] = val !== undefined ? val : properties[name]; } return values; } } exports.ViewHistory = ViewHistory; /***/ }), /* 38 */ /***/ ((__unused_webpack_module, exports, __webpack_require__) => { Object.defineProperty(exports, "__esModule", ({ value: true })); exports.GenericCom = void 0; var _app = __webpack_require__(3); var _preferences = __webpack_require__(39); var _download_manager = __webpack_require__(40); var _genericl10n = __webpack_require__(41); var _generic_scripting = __webpack_require__(43); ; const GenericCom = {}; exports.GenericCom = GenericCom; class GenericPreferences extends _preferences.BasePreferences { async _writeToStorage(prefObj) { localStorage.setItem("pdfjs.preferences", JSON.stringify(prefObj)); } async _readFromStorage(prefObj) { return JSON.parse(localStorage.getItem("pdfjs.preferences")); } } class GenericExternalServices extends _app.DefaultExternalServices { static createDownloadManager(options) { return new _download_manager.DownloadManager(); } static createPreferences() { return new GenericPreferences(); } static createL10n({ locale = "en-US" }) { return new _genericl10n.GenericL10n(locale); } static createScripting({ sandboxBundleSrc }) { return new _generic_scripting.GenericScripting(sandboxBundleSrc); } } _app.PDFViewerApplication.externalServices = GenericExternalServices; /***/ }), /* 39 */ /***/ ((__unused_webpack_module, exports, __webpack_require__) => { Object.defineProperty(exports, "__esModule", ({ value: true })); exports.BasePreferences = void 0; var _app_options = __webpack_require__(1); class BasePreferences { constructor() { if (this.constructor === BasePreferences) { throw new Error("Cannot initialize BasePreferences."); } Object.defineProperty(this, "defaults", { value: Object.freeze({ "cursorToolOnLoad": 0, "defaultZoomValue": "", "disablePageLabels": false, "enablePermissions": false, "enablePrintAutoRotate": true, "enableScripting": true, "enableWebGL": false, "externalLinkTarget": 0, "historyUpdateUrl": false, "ignoreDestinationZoom": false, "pdfBugEnabled": false, "renderer": "canvas", "renderInteractiveForms": true, "sidebarViewOnLoad": -1, "scrollModeOnLoad": -1, "spreadModeOnLoad": -1, "textLayerMode": 1, "useOnlyCssZoom": false, "viewerCssTheme": 0, "viewOnLoad": 0, "disableAutoFetch": false, "disableFontFace": false, "disableRange": false, "disableStream": false }), writable: false, enumerable: true, configurable: false }); this.prefs = Object.create(null); this._initializedPromise = this._readFromStorage(this.defaults).then(prefs => { for (const name in this.defaults) { const prefValue = prefs?.[name]; if (typeof prefValue === typeof this.defaults[name]) { this.prefs[name] = prefValue; } } }); } async _writeToStorage(prefObj) { throw new Error("Not implemented: _writeToStorage"); } async _readFromStorage(prefObj) { throw new Error("Not implemented: _readFromStorage"); } async reset() { await this._initializedPromise; this.prefs = Object.create(null); return this._writeToStorage(this.defaults); } async set(name, value) { await this._initializedPromise; const defaultValue = this.defaults[name]; if (defaultValue === undefined) { throw new Error(`Set preference: "${name}" is undefined.`); } else if (value === undefined) { throw new Error("Set preference: no value is specified."); } const valueType = typeof value; const defaultType = typeof defaultValue; if (valueType !== defaultType) { if (valueType === "number" && defaultType === "string") { value = value.toString(); } else { throw new Error(`Set preference: "${value}" is a ${valueType}, expected a ${defaultType}.`); } } else { if (valueType === "number" && !Number.isInteger(value)) { throw new Error(`Set preference: "${value}" must be an integer.`); } } this.prefs[name] = value; return this._writeToStorage(this.prefs); } async get(name) { await this._initializedPromise; const defaultValue = this.defaults[name], prefValue = this.prefs[name]; if (defaultValue === undefined) { throw new Error(`Get preference: "${name}" is undefined.`); } return prefValue !== undefined ? prefValue : defaultValue; } async getAll() { await this._initializedPromise; const obj = Object.create(null); for (const name in this.defaults) { const prefValue = this.prefs[name]; obj[name] = prefValue !== undefined ? prefValue : this.defaults[name]; } return obj; } } exports.BasePreferences = BasePreferences; /***/ }), /* 40 */ /***/ ((__unused_webpack_module, exports, __webpack_require__) => { Object.defineProperty(exports, "__esModule", ({ value: true })); exports.DownloadManager = void 0; var _pdfjsLib = __webpack_require__(5); var _viewer_compatibility = __webpack_require__(2); ; function download(blobUrl, filename) { const a = document.createElement("a"); if (!a.click) { throw new Error('DownloadManager: "a.click()" is not supported.'); } a.href = blobUrl; a.target = "_parent"; if ("download" in a) { a.download = filename; } (document.body || document.documentElement).appendChild(a); a.click(); a.remove(); } class DownloadManager { constructor() { this._openBlobUrls = new WeakMap(); } downloadUrl(url, filename) { if (!(0, _pdfjsLib.createValidAbsoluteUrl)(url, "http://example.com")) { return; } download(url + "#pdfjs.action=download", filename); } downloadData(data, filename, contentType) { const blobUrl = (0, _pdfjsLib.createObjectURL)(data, contentType, _viewer_compatibility.viewerCompatibilityParams.disableCreateObjectURL); download(blobUrl, filename); } openOrDownloadData(element, data, filename) { const isPdfData = (0, _pdfjsLib.isPdfFile)(filename); const contentType = isPdfData ? "application/pdf" : ""; if (isPdfData && !_viewer_compatibility.viewerCompatibilityParams.disableCreateObjectURL) { let blobUrl = this._openBlobUrls.get(element); if (!blobUrl) { blobUrl = URL.createObjectURL(new Blob([data], { type: contentType })); this._openBlobUrls.set(element, blobUrl); } let viewerUrl; viewerUrl = "?file=" + encodeURIComponent(blobUrl + "#" + filename); try { window.open(viewerUrl); return true; } catch (ex) { console.error(`openOrDownloadData: ${ex}`); URL.revokeObjectURL(blobUrl); this._openBlobUrls.delete(element); } } this.downloadData(data, filename, contentType); return false; } download(blob, url, filename, sourceEventType = "download") { if (_viewer_compatibility.viewerCompatibilityParams.disableCreateObjectURL) { this.downloadUrl(url, filename); return; } const blobUrl = URL.createObjectURL(blob); download(blobUrl, filename); } } exports.DownloadManager = DownloadManager; /***/ }), /* 41 */ /***/ ((__unused_webpack_module, exports, __webpack_require__) => { Object.defineProperty(exports, "__esModule", ({ value: true })); exports.GenericL10n = void 0; __webpack_require__(42); var _l10n_utils = __webpack_require__(30); const webL10n = document.webL10n; class GenericL10n { constructor(lang) { this._lang = lang; this._ready = new Promise((resolve, reject) => { webL10n.setLanguage(lang, () => { resolve(webL10n); }); }); } async getLanguage() { const l10n = await this._ready; return l10n.getLanguage(); } async getDirection() { const l10n = await this._ready; return l10n.getDirection(); } async get(key, args = null, fallback = (0, _l10n_utils.getL10nFallback)(key, args)) { const l10n = await this._ready; return l10n.get(key, args, fallback); } async translate(element) { const l10n = await this._ready; return l10n.translate(element); } } exports.GenericL10n = GenericL10n; /***/ }), /* 42 */ /***/ (() => { document.webL10n = function (window, document, undefined) { var gL10nData = {}; var gTextData = ''; var gTextProp = 'textContent'; var gLanguage = ''; var gMacros = {}; var gReadyState = 'loading'; var gAsyncResourceLoading = true; function getL10nResourceLinks() { return document.querySelectorAll('link[type="application/l10n"]'); } function getL10nDictionary() { var script = document.querySelector('script[type="application/l10n"]'); return script ? JSON.parse(script.innerHTML) : null; } function getTranslatableChildren(element) { return element ? element.querySelectorAll('*[data-l10n-id]') : []; } function getL10nAttributes(element) { if (!element) return {}; var l10nId = element.getAttribute('data-l10n-id'); var l10nArgs = element.getAttribute('data-l10n-args'); var args = {}; if (l10nArgs) { try { args = JSON.parse(l10nArgs); } catch (e) { console.warn('could not parse arguments for #' + l10nId); } } return { id: l10nId, args: args }; } function xhrLoadText(url, onSuccess, onFailure) { onSuccess = onSuccess || function _onSuccess(data) {}; onFailure = onFailure || function _onFailure() {}; var xhr = new XMLHttpRequest(); xhr.open('GET', url, gAsyncResourceLoading); if (xhr.overrideMimeType) { xhr.overrideMimeType('text/plain; charset=utf-8'); } xhr.onreadystatechange = function () { if (xhr.readyState == 4) { if (xhr.status == 200 || xhr.status === 0) { onSuccess(xhr.responseText); } else { onFailure(); } } }; xhr.onerror = onFailure; xhr.ontimeout = onFailure; try { xhr.send(null); } catch (e) { onFailure(); } } function parseResource(href, lang, successCallback, failureCallback) { var baseURL = href.replace(/[^\/]*$/, '') || './'; function evalString(text) { if (text.lastIndexOf('\\') < 0) return text; return text.replace(/\\\\/g, '\\').replace(/\\n/g, '\n').replace(/\\r/g, '\r').replace(/\\t/g, '\t').replace(/\\b/g, '\b').replace(/\\f/g, '\f').replace(/\\{/g, '{').replace(/\\}/g, '}').replace(/\\"/g, '"').replace(/\\'/g, "'"); } function parseProperties(text, parsedPropertiesCallback) { var dictionary = {}; var reBlank = /^\s*|\s*$/; var reComment = /^\s*#|^\s*$/; var reSection = /^\s*\[(.*)\]\s*$/; var reImport = /^\s*@import\s+url\((.*)\)\s*$/i; var reSplit = /^([^=\s]*)\s*=\s*(.+)$/; function parseRawLines(rawText, extendedSyntax, parsedRawLinesCallback) { var entries = rawText.replace(reBlank, '').split(/[\r\n]+/); var currentLang = '*'; var genericLang = lang.split('-', 1)[0]; var skipLang = false; var match = ''; function nextEntry() { while (true) { if (!entries.length) { parsedRawLinesCallback(); return; } var line = entries.shift(); if (reComment.test(line)) continue; if (extendedSyntax) { match = reSection.exec(line); if (match) { currentLang = match[1].toLowerCase(); skipLang = currentLang !== '*' && currentLang !== lang && currentLang !== genericLang; continue; } else if (skipLang) { continue; } match = reImport.exec(line); if (match) { loadImport(baseURL + match[1], nextEntry); return; } } var tmp = line.match(reSplit); if (tmp && tmp.length == 3) { dictionary[tmp[1]] = evalString(tmp[2]); } } } nextEntry(); } function loadImport(url, callback) { xhrLoadText(url, function (content) { parseRawLines(content, false, callback); }, function () { console.warn(url + ' not found.'); callback(); }); } parseRawLines(text, true, function () { parsedPropertiesCallback(dictionary); }); } xhrLoadText(href, function (response) { gTextData += response; parseProperties(response, function (data) { for (var key in data) { var id, prop, index = key.lastIndexOf('.'); if (index > 0) { id = key.substring(0, index); prop = key.substring(index + 1); } else { id = key; prop = gTextProp; } if (!gL10nData[id]) { gL10nData[id] = {}; } gL10nData[id][prop] = data[key]; } if (successCallback) { successCallback(); } }); }, failureCallback); } function loadLocale(lang, callback) { if (lang) { lang = lang.toLowerCase(); } callback = callback || function _callback() {}; clear(); gLanguage = lang; var langLinks = getL10nResourceLinks(); var langCount = langLinks.length; if (langCount === 0) { var dict = getL10nDictionary(); if (dict && dict.locales && dict.default_locale) { console.log('using the embedded JSON directory, early way out'); gL10nData = dict.locales[lang]; if (!gL10nData) { var defaultLocale = dict.default_locale.toLowerCase(); for (var anyCaseLang in dict.locales) { anyCaseLang = anyCaseLang.toLowerCase(); if (anyCaseLang === lang) { gL10nData = dict.locales[lang]; break; } else if (anyCaseLang === defaultLocale) { gL10nData = dict.locales[defaultLocale]; } } } callback(); } else { console.log('no resource to load, early way out'); } gReadyState = 'complete'; return; } var onResourceLoaded = null; var gResourceCount = 0; onResourceLoaded = function () { gResourceCount++; if (gResourceCount >= langCount) { callback(); gReadyState = 'complete'; } }; function L10nResourceLink(link) { var href = link.href; this.load = function (lang, callback) { parseResource(href, lang, callback, function () { console.warn(href + ' not found.'); console.warn('"' + lang + '" resource not found'); gLanguage = ''; callback(); }); }; } for (var i = 0; i < langCount; i++) { var resource = new L10nResourceLink(langLinks[i]); resource.load(lang, onResourceLoaded); } } function clear() { gL10nData = {}; gTextData = ''; gLanguage = ''; } function getPluralRules(lang) { var locales2rules = { 'af': 3, 'ak': 4, 'am': 4, 'ar': 1, 'asa': 3, 'az': 0, 'be': 11, 'bem': 3, 'bez': 3, 'bg': 3, 'bh': 4, 'bm': 0, 'bn': 3, 'bo': 0, 'br': 20, 'brx': 3, 'bs': 11, 'ca': 3, 'cgg': 3, 'chr': 3, 'cs': 12, 'cy': 17, 'da': 3, 'de': 3, 'dv': 3, 'dz': 0, 'ee': 3, 'el': 3, 'en': 3, 'eo': 3, 'es': 3, 'et': 3, 'eu': 3, 'fa': 0, 'ff': 5, 'fi': 3, 'fil': 4, 'fo': 3, 'fr': 5, 'fur': 3, 'fy': 3, 'ga': 8, 'gd': 24, 'gl': 3, 'gsw': 3, 'gu': 3, 'guw': 4, 'gv': 23, 'ha': 3, 'haw': 3, 'he': 2, 'hi': 4, 'hr': 11, 'hu': 0, 'id': 0, 'ig': 0, 'ii': 0, 'is': 3, 'it': 3, 'iu': 7, 'ja': 0, 'jmc': 3, 'jv': 0, 'ka': 0, 'kab': 5, 'kaj': 3, 'kcg': 3, 'kde': 0, 'kea': 0, 'kk': 3, 'kl': 3, 'km': 0, 'kn': 0, 'ko': 0, 'ksb': 3, 'ksh': 21, 'ku': 3, 'kw': 7, 'lag': 18, 'lb': 3, 'lg': 3, 'ln': 4, 'lo': 0, 'lt': 10, 'lv': 6, 'mas': 3, 'mg': 4, 'mk': 16, 'ml': 3, 'mn': 3, 'mo': 9, 'mr': 3, 'ms': 0, 'mt': 15, 'my': 0, 'nah': 3, 'naq': 7, 'nb': 3, 'nd': 3, 'ne': 3, 'nl': 3, 'nn': 3, 'no': 3, 'nr': 3, 'nso': 4, 'ny': 3, 'nyn': 3, 'om': 3, 'or': 3, 'pa': 3, 'pap': 3, 'pl': 13, 'ps': 3, 'pt': 3, 'rm': 3, 'ro': 9, 'rof': 3, 'ru': 11, 'rwk': 3, 'sah': 0, 'saq': 3, 'se': 7, 'seh': 3, 'ses': 0, 'sg': 0, 'sh': 11, 'shi': 19, 'sk': 12, 'sl': 14, 'sma': 7, 'smi': 7, 'smj': 7, 'smn': 7, 'sms': 7, 'sn': 3, 'so': 3, 'sq': 3, 'sr': 11, 'ss': 3, 'ssy': 3, 'st': 3, 'sv': 3, 'sw': 3, 'syr': 3, 'ta': 3, 'te': 3, 'teo': 3, 'th': 0, 'ti': 4, 'tig': 3, 'tk': 3, 'tl': 4, 'tn': 3, 'to': 0, 'tr': 0, 'ts': 3, 'tzm': 22, 'uk': 11, 'ur': 3, 've': 3, 'vi': 0, 'vun': 3, 'wa': 4, 'wae': 3, 'wo': 0, 'xh': 3, 'xog': 3, 'yo': 0, 'zh': 0, 'zu': 3 }; function isIn(n, list) { return list.indexOf(n) !== -1; } function isBetween(n, start, end) { return start <= n && n <= end; } var pluralRules = { '0': function (n) { return 'other'; }, '1': function (n) { if (isBetween(n % 100, 3, 10)) return 'few'; if (n === 0) return 'zero'; if (isBetween(n % 100, 11, 99)) return 'many'; if (n == 2) return 'two'; if (n == 1) return 'one'; return 'other'; }, '2': function (n) { if (n !== 0 && n % 10 === 0) return 'many'; if (n == 2) return 'two'; if (n == 1) return 'one'; return 'other'; }, '3': function (n) { if (n == 1) return 'one'; return 'other'; }, '4': function (n) { if (isBetween(n, 0, 1)) return 'one'; return 'other'; }, '5': function (n) { if (isBetween(n, 0, 2) && n != 2) return 'one'; return 'other'; }, '6': function (n) { if (n === 0) return 'zero'; if (n % 10 == 1 && n % 100 != 11) return 'one'; return 'other'; }, '7': function (n) { if (n == 2) return 'two'; if (n == 1) return 'one'; return 'other'; }, '8': function (n) { if (isBetween(n, 3, 6)) return 'few'; if (isBetween(n, 7, 10)) return 'many'; if (n == 2) return 'two'; if (n == 1) return 'one'; return 'other'; }, '9': function (n) { if (n === 0 || n != 1 && isBetween(n % 100, 1, 19)) return 'few'; if (n == 1) return 'one'; return 'other'; }, '10': function (n) { if (isBetween(n % 10, 2, 9) && !isBetween(n % 100, 11, 19)) return 'few'; if (n % 10 == 1 && !isBetween(n % 100, 11, 19)) return 'one'; return 'other'; }, '11': function (n) { if (isBetween(n % 10, 2, 4) && !isBetween(n % 100, 12, 14)) return 'few'; if (n % 10 === 0 || isBetween(n % 10, 5, 9) || isBetween(n % 100, 11, 14)) return 'many'; if (n % 10 == 1 && n % 100 != 11) return 'one'; return 'other'; }, '12': function (n) { if (isBetween(n, 2, 4)) return 'few'; if (n == 1) return 'one'; return 'other'; }, '13': function (n) { if (isBetween(n % 10, 2, 4) && !isBetween(n % 100, 12, 14)) return 'few'; if (n != 1 && isBetween(n % 10, 0, 1) || isBetween(n % 10, 5, 9) || isBetween(n % 100, 12, 14)) return 'many'; if (n == 1) return 'one'; return 'other'; }, '14': function (n) { if (isBetween(n % 100, 3, 4)) return 'few'; if (n % 100 == 2) return 'two'; if (n % 100 == 1) return 'one'; return 'other'; }, '15': function (n) { if (n === 0 || isBetween(n % 100, 2, 10)) return 'few'; if (isBetween(n % 100, 11, 19)) return 'many'; if (n == 1) return 'one'; return 'other'; }, '16': function (n) { if (n % 10 == 1 && n != 11) return 'one'; return 'other'; }, '17': function (n) { if (n == 3) return 'few'; if (n === 0) return 'zero'; if (n == 6) return 'many'; if (n == 2) return 'two'; if (n == 1) return 'one'; return 'other'; }, '18': function (n) { if (n === 0) return 'zero'; if (isBetween(n, 0, 2) && n !== 0 && n != 2) return 'one'; return 'other'; }, '19': function (n) { if (isBetween(n, 2, 10)) return 'few'; if (isBetween(n, 0, 1)) return 'one'; return 'other'; }, '20': function (n) { if ((isBetween(n % 10, 3, 4) || n % 10 == 9) && !(isBetween(n % 100, 10, 19) || isBetween(n % 100, 70, 79) || isBetween(n % 100, 90, 99))) return 'few'; if (n % 1000000 === 0 && n !== 0) return 'many'; if (n % 10 == 2 && !isIn(n % 100, [12, 72, 92])) return 'two'; if (n % 10 == 1 && !isIn(n % 100, [11, 71, 91])) return 'one'; return 'other'; }, '21': function (n) { if (n === 0) return 'zero'; if (n == 1) return 'one'; return 'other'; }, '22': function (n) { if (isBetween(n, 0, 1) || isBetween(n, 11, 99)) return 'one'; return 'other'; }, '23': function (n) { if (isBetween(n % 10, 1, 2) || n % 20 === 0) return 'one'; return 'other'; }, '24': function (n) { if (isBetween(n, 3, 10) || isBetween(n, 13, 19)) return 'few'; if (isIn(n, [2, 12])) return 'two'; if (isIn(n, [1, 11])) return 'one'; return 'other'; } }; var index = locales2rules[lang.replace(/-.*$/, '')]; if (!(index in pluralRules)) { console.warn('plural form unknown for [' + lang + ']'); return function () { return 'other'; }; } return pluralRules[index]; } gMacros.plural = function (str, param, key, prop) { var n = parseFloat(param); if (isNaN(n)) return str; if (prop != gTextProp) return str; if (!gMacros._pluralRules) { gMacros._pluralRules = getPluralRules(gLanguage); } var index = '[' + gMacros._pluralRules(n) + ']'; if (n === 0 && key + '[zero]' in gL10nData) { str = gL10nData[key + '[zero]'][prop]; } else if (n == 1 && key + '[one]' in gL10nData) { str = gL10nData[key + '[one]'][prop]; } else if (n == 2 && key + '[two]' in gL10nData) { str = gL10nData[key + '[two]'][prop]; } else if (key + index in gL10nData) { str = gL10nData[key + index][prop]; } else if (key + '[other]' in gL10nData) { str = gL10nData[key + '[other]'][prop]; } return str; }; function getL10nData(key, args, fallback) { var data = gL10nData[key]; if (!data) { console.warn('#' + key + ' is undefined.'); if (!fallback) { return null; } data = fallback; } var rv = {}; for (var prop in data) { var str = data[prop]; str = substIndexes(str, args, key, prop); str = substArguments(str, args, key); rv[prop] = str; } return rv; } function substIndexes(str, args, key, prop) { var reIndex = /\{\[\s*([a-zA-Z]+)\(([a-zA-Z]+)\)\s*\]\}/; var reMatch = reIndex.exec(str); if (!reMatch || !reMatch.length) return str; var macroName = reMatch[1]; var paramName = reMatch[2]; var param; if (args && paramName in args) { param = args[paramName]; } else if (paramName in gL10nData) { param = gL10nData[paramName]; } if (macroName in gMacros) { var macro = gMacros[macroName]; str = macro(str, param, key, prop); } return str; } function substArguments(str, args, key) { var reArgs = /\{\{\s*(.+?)\s*\}\}/g; return str.replace(reArgs, function (matched_text, arg) { if (args && arg in args) { return args[arg]; } if (arg in gL10nData) { return gL10nData[arg]; } console.log('argument {{' + arg + '}} for #' + key + ' is undefined.'); return matched_text; }); } function translateElement(element) { var l10n = getL10nAttributes(element); if (!l10n.id) return; var data = getL10nData(l10n.id, l10n.args); if (!data) { console.warn('#' + l10n.id + ' is undefined.'); return; } if (data[gTextProp]) { if (getChildElementCount(element) === 0) { element[gTextProp] = data[gTextProp]; } else { var children = element.childNodes; var found = false; for (var i = 0, l = children.length; i < l; i++) { if (children[i].nodeType === 3 && /\S/.test(children[i].nodeValue)) { if (found) { children[i].nodeValue = ''; } else { children[i].nodeValue = data[gTextProp]; found = true; } } } if (!found) { var textNode = document.createTextNode(data[gTextProp]); element.insertBefore(textNode, element.firstChild); } } delete data[gTextProp]; } for (var k in data) { element[k] = data[k]; } } function getChildElementCount(element) { if (element.children) { return element.children.length; } if (typeof element.childElementCount !== 'undefined') { return element.childElementCount; } var count = 0; for (var i = 0; i < element.childNodes.length; i++) { count += element.nodeType === 1 ? 1 : 0; } return count; } function translateFragment(element) { element = element || document.documentElement; var children = getTranslatableChildren(element); var elementCount = children.length; for (var i = 0; i < elementCount; i++) { translateElement(children[i]); } translateElement(element); } return { get: function (key, args, fallbackString) { var index = key.lastIndexOf('.'); var prop = gTextProp; if (index > 0) { prop = key.substring(index + 1); key = key.substring(0, index); } var fallback; if (fallbackString) { fallback = {}; fallback[prop] = fallbackString; } var data = getL10nData(key, args, fallback); if (data && prop in data) { return data[prop]; } return '{{' + key + '}}'; }, getData: function () { return gL10nData; }, getText: function () { return gTextData; }, getLanguage: function () { return gLanguage; }, setLanguage: function (lang, callback) { loadLocale(lang, function () { if (callback) callback(); }); }, getDirection: function () { var rtlList = ['ar', 'he', 'fa', 'ps', 'ur']; var shortCode = gLanguage.split('-', 1)[0]; return rtlList.indexOf(shortCode) >= 0 ? 'rtl' : 'ltr'; }, translate: translateFragment, getReadyState: function () { return gReadyState; }, ready: function (callback) { if (!callback) { return; } else if (gReadyState == 'complete' || gReadyState == 'interactive') { window.setTimeout(function () { callback(); }); } else if (document.addEventListener) { document.addEventListener('localized', function once() { document.removeEventListener('localized', once); callback(); }); } } }; }(window, document); /***/ }), /* 43 */ /***/ ((__unused_webpack_module, exports, __webpack_require__) => { Object.defineProperty(exports, "__esModule", ({ value: true })); exports.docPropertiesLookup = docPropertiesLookup; exports.GenericScripting = void 0; var _pdfjsLib = __webpack_require__(5); async function docPropertiesLookup(pdfDocument) { const url = "", baseUrl = url.split("#")[0]; let { info, metadata, contentDispositionFilename, contentLength } = await pdfDocument.getMetadata(); if (!contentLength) { const { length } = await pdfDocument.getDownloadInfo(); contentLength = length; } return { ...info, baseURL: baseUrl, filesize: contentLength, filename: contentDispositionFilename || (0, _pdfjsLib.getPdfFilenameFromUrl)(url), metadata: metadata?.getRaw(), authors: metadata?.get("dc:creator"), numPages: pdfDocument.numPages, URL: url }; } class GenericScripting { constructor(sandboxBundleSrc) { this._ready = (0, _pdfjsLib.loadScript)(sandboxBundleSrc, true).then(() => { return window.pdfjsSandbox.QuickJSSandbox(); }); } async createSandbox(data) { const sandbox = await this._ready; sandbox.create(data); } async dispatchEventInSandbox(event) { const sandbox = await this._ready; sandbox.dispatchEvent(event); } async destroySandbox() { const sandbox = await this._ready; sandbox.nukeSandbox(); } } exports.GenericScripting = GenericScripting; /***/ }), /* 44 */ /***/ ((__unused_webpack_module, exports, __webpack_require__) => { Object.defineProperty(exports, "__esModule", ({ value: true })); exports.PDFPrintService = PDFPrintService; var _app = __webpack_require__(3); var _viewer_compatibility = __webpack_require__(2); let activeService = null; let overlayManager = null; function renderPage(activeServiceOnEntry, pdfDocument, pageNumber, size, printResolution, optionalContentConfigPromise) { const scratchCanvas = activeService.scratchCanvas; const PRINT_UNITS = printResolution / 72.0; scratchCanvas.width = Math.floor(size.width * PRINT_UNITS); scratchCanvas.height = Math.floor(size.height * PRINT_UNITS); const ctx = scratchCanvas.getContext("2d"); ctx.save(); ctx.fillStyle = "rgb(255, 255, 255)"; ctx.fillRect(0, 0, scratchCanvas.width, scratchCanvas.height); ctx.restore(); return pdfDocument.getPage(pageNumber).then(function (pdfPage) { const renderContext = { canvasContext: ctx, transform: [PRINT_UNITS, 0, 0, PRINT_UNITS, 0, 0], viewport: pdfPage.getViewport({ scale: 1, rotation: size.rotation }), intent: "print", annotationStorage: pdfDocument.annotationStorage, optionalContentConfigPromise }; return pdfPage.render(renderContext).promise; }); } function PDFPrintService(pdfDocument, pagesOverview, printContainer, printResolution, optionalContentConfigPromise = null, l10n) { this.pdfDocument = pdfDocument; this.pagesOverview = pagesOverview; this.printContainer = printContainer; this._printResolution = printResolution || 150; this._optionalContentConfigPromise = optionalContentConfigPromise || pdfDocument.getOptionalContentConfig(); this.l10n = l10n; this.currentPage = -1; this.scratchCanvas = document.createElement("canvas"); } PDFPrintService.prototype = { layout() { this.throwIfInactive(); const body = document.querySelector("body"); body.setAttribute("data-pdfjsprinting", true); const hasEqualPageSizes = this.pagesOverview.every(function (size) { return size.width === this.pagesOverview[0].width && size.height === this.pagesOverview[0].height; }, this); if (!hasEqualPageSizes) { console.warn("Not all pages have the same size. The printed " + "result may be incorrect!"); } this.pageStyleSheet = document.createElement("style"); const pageSize = this.pagesOverview[0]; this.pageStyleSheet.textContent = "@page { size: " + pageSize.width + "pt " + pageSize.height + "pt;}"; body.appendChild(this.pageStyleSheet); }, destroy() { if (activeService !== this) { return; } this.printContainer.textContent = ""; const body = document.querySelector("body"); body.removeAttribute("data-pdfjsprinting"); if (this.pageStyleSheet) { this.pageStyleSheet.remove(); this.pageStyleSheet = null; } this.scratchCanvas.width = this.scratchCanvas.height = 0; this.scratchCanvas = null; activeService = null; ensureOverlay().then(function () { if (overlayManager.active !== "printServiceOverlay") { return; } overlayManager.close("printServiceOverlay"); }); }, renderPages() { const pageCount = this.pagesOverview.length; const renderNextPage = (resolve, reject) => { this.throwIfInactive(); if (++this.currentPage >= pageCount) { renderProgress(pageCount, pageCount, this.l10n); resolve(); return; } const index = this.currentPage; renderProgress(index, pageCount, this.l10n); renderPage(this, this.pdfDocument, index + 1, this.pagesOverview[index], this._printResolution, this._optionalContentConfigPromise).then(this.useRenderedPage.bind(this)).then(function () { renderNextPage(resolve, reject); }, reject); }; return new Promise(renderNextPage); }, useRenderedPage() { this.throwIfInactive(); const img = document.createElement("img"); const scratchCanvas = this.scratchCanvas; if ("toBlob" in scratchCanvas && !_viewer_compatibility.viewerCompatibilityParams.disableCreateObjectURL) { scratchCanvas.toBlob(function (blob) { img.src = URL.createObjectURL(blob); }); } else { img.src = scratchCanvas.toDataURL(); } const wrapper = document.createElement("div"); wrapper.appendChild(img); this.printContainer.appendChild(wrapper); return new Promise(function (resolve, reject) { img.onload = resolve; img.onerror = reject; }); }, performPrint() { this.throwIfInactive(); return new Promise(resolve => { setTimeout(() => { if (!this.active) { resolve(); return; } print.call(window); setTimeout(resolve, 20); }, 0); }); }, get active() { return this === activeService; }, throwIfInactive() { if (!this.active) { throw new Error("This print request was cancelled or completed."); } } }; const print = window.print; window.print = function () { if (activeService) { console.warn("Ignored window.print() because of a pending print job."); return; } ensureOverlay().then(function () { if (activeService) { overlayManager.open("printServiceOverlay"); } }); try { dispatchEvent("beforeprint"); } finally { if (!activeService) { console.error("Expected print service to be initialized."); ensureOverlay().then(function () { if (overlayManager.active === "printServiceOverlay") { overlayManager.close("printServiceOverlay"); } }); return; } const activeServiceOnEntry = activeService; activeService.renderPages().then(function () { return activeServiceOnEntry.performPrint(); }).catch(function () {}).then(function () { if (activeServiceOnEntry.active) { abort(); } }); } }; function dispatchEvent(eventType) { const event = document.createEvent("CustomEvent"); event.initCustomEvent(eventType, false, false, "custom"); window.dispatchEvent(event); } function abort() { if (activeService) { activeService.destroy(); dispatchEvent("afterprint"); } } function renderProgress(index, total, l10n) { const progressContainer = document.getElementById("printServiceOverlay"); const progress = Math.round(100 * index / total); const progressBar = progressContainer.querySelector("progress"); const progressPerc = progressContainer.querySelector(".relative-progress"); progressBar.value = progress; l10n.get("print_progress_percent", { progress }).then(msg => { progressPerc.textContent = msg; }); } window.addEventListener("keydown", function (event) { if (event.keyCode === 80 && (event.ctrlKey || event.metaKey) && !event.altKey && (!event.shiftKey || window.chrome || window.opera)) { window.print(); event.preventDefault(); if (event.stopImmediatePropagation) { event.stopImmediatePropagation(); } else { event.stopPropagation(); } } }, true); if ("onbeforeprint" in window) { const stopPropagationIfNeeded = function (event) { if (event.detail !== "custom" && event.stopImmediatePropagation) { event.stopImmediatePropagation(); } }; window.addEventListener("beforeprint", stopPropagationIfNeeded); window.addEventListener("afterprint", stopPropagationIfNeeded); } let overlayPromise; function ensureOverlay() { if (!overlayPromise) { overlayManager = _app.PDFViewerApplication.overlayManager; if (!overlayManager) { throw new Error("The overlay manager has not yet been initialized."); } overlayPromise = overlayManager.register("printServiceOverlay", document.getElementById("printServiceOverlay"), abort, true); document.getElementById("printCancel").onclick = abort; } return overlayPromise; } _app.PDFPrintServiceFactory.instance = { supportsPrinting: true, createPrintService(pdfDocument, pagesOverview, printContainer, printResolution, optionalContentConfigPromise, l10n) { if (activeService) { throw new Error("The print service is created and active."); } activeService = new PDFPrintService(pdfDocument, pagesOverview, printContainer, printResolution, optionalContentConfigPromise, l10n); return activeService; } }; /***/ }) /******/ ]); /************************************************************************/ /******/ // The module cache /******/ var __webpack_module_cache__ = {}; /******/ /******/ // The require function /******/ function __webpack_require__(moduleId) { /******/ // Check if module is in cache /******/ var cachedModule = __webpack_module_cache__[moduleId]; /******/ if (cachedModule !== undefined) { /******/ return cachedModule.exports; /******/ } /******/ // Create a new module (and put it into the cache) /******/ var module = __webpack_module_cache__[moduleId] = { /******/ // no module.id needed /******/ // no module.loaded needed /******/ exports: {} /******/ }; /******/ /******/ // Execute the module function /******/ __webpack_modules__[moduleId](module, module.exports, __webpack_require__); /******/ /******/ // Return the exports of the module /******/ return module.exports; /******/ } /******/ /************************************************************************/ var __webpack_exports__ = {}; // This entry need to be wrapped in an IIFE because it need to be isolated against other modules in the chunk. (() => { var exports = __webpack_exports__; Object.defineProperty(exports, "__esModule", ({ value: true })); Object.defineProperty(exports, "PDFViewerApplicationOptions", ({ enumerable: true, get: function () { return _app_options.AppOptions; } })); Object.defineProperty(exports, "PDFViewerApplication", ({ enumerable: true, get: function () { return _app.PDFViewerApplication; } })); var _app_options = __webpack_require__(1); var _app = __webpack_require__(3); const pdfjsVersion = '2.8.335'; const pdfjsBuild = '228adbf67'; window.PDFViewerApplication = _app.PDFViewerApplication; window.PDFViewerApplicationOptions = _app_options.AppOptions; ; ; { __webpack_require__(38); } ; { __webpack_require__(44); } function getViewerConfiguration() { let errorWrapper = null; errorWrapper = { container: document.getElementById("errorWrapper"), errorMessage: document.getElementById("errorMessage"), closeButton: document.getElementById("errorClose"), errorMoreInfo: document.getElementById("errorMoreInfo"), moreInfoButton: document.getElementById("errorShowMore"), lessInfoButton: document.getElementById("errorShowLess") }; return { appContainer: document.body, mainContainer: document.getElementById("viewerContainer"), viewerContainer: document.getElementById("viewer"), eventBus: null, toolbar: { container: document.getElementById("toolbarViewer"), numPages: document.getElementById("numPages"), pageNumber: document.getElementById("pageNumber"), scaleSelectContainer: document.getElementById("scaleSelectContainer"), scaleSelect: document.getElementById("scaleSelect"), customScaleOption: document.getElementById("customScaleOption"), previous: document.getElementById("previous"), next: document.getElementById("next"), zoomIn: document.getElementById("zoomIn"), zoomOut: document.getElementById("zoomOut"), viewFind: document.getElementById("viewFind"), openFile: document.getElementById("openFile"), print: document.getElementById("print"), presentationModeButton: document.getElementById("presentationMode"), download: document.getElementById("download"), viewBookmark: document.getElementById("viewBookmark") }, secondaryToolbar: { toolbar: document.getElementById("secondaryToolbar"), toggleButton: document.getElementById("secondaryToolbarToggle"), toolbarButtonContainer: document.getElementById("secondaryToolbarButtonContainer"), presentationModeButton: document.getElementById("secondaryPresentationMode"), openFileButton: document.getElementById("secondaryOpenFile"), printButton: document.getElementById("secondaryPrint"), downloadButton: document.getElementById("secondaryDownload"), viewBookmarkButton: document.getElementById("secondaryViewBookmark"), firstPageButton: document.getElementById("firstPage"), lastPageButton: document.getElementById("lastPage"), pageRotateCwButton: document.getElementById("pageRotateCw"), pageRotateCcwButton: document.getElementById("pageRotateCcw"), cursorSelectToolButton: document.getElementById("cursorSelectTool"), cursorHandToolButton: document.getElementById("cursorHandTool"), scrollVerticalButton: document.getElementById("scrollVertical"), scrollHorizontalButton: document.getElementById("scrollHorizontal"), scrollWrappedButton: document.getElementById("scrollWrapped"), spreadNoneButton: document.getElementById("spreadNone"), spreadOddButton: document.getElementById("spreadOdd"), spreadEvenButton: document.getElementById("spreadEven"), documentPropertiesButton: document.getElementById("documentProperties") }, sidebar: { outerContainer: document.getElementById("outerContainer"), viewerContainer: document.getElementById("viewerContainer"), toggleButton: document.getElementById("sidebarToggle"), thumbnailButton: document.getElementById("viewThumbnail"), outlineButton: document.getElementById("viewOutline"), attachmentsButton: document.getElementById("viewAttachments"), layersButton: document.getElementById("viewLayers"), thumbnailView: document.getElementById("thumbnailView"), outlineView: document.getElementById("outlineView"), attachmentsView: document.getElementById("attachmentsView"), layersView: document.getElementById("layersView"), outlineOptionsContainer: document.getElementById("outlineOptionsContainer"), currentOutlineItemButton: document.getElementById("currentOutlineItem") }, sidebarResizer: { outerContainer: document.getElementById("outerContainer"), resizer: document.getElementById("sidebarResizer") }, findBar: { bar: document.getElementById("findbar"), toggleButton: document.getElementById("viewFind"), findField: document.getElementById("findInput"), highlightAllCheckbox: document.getElementById("findHighlightAll"), caseSensitiveCheckbox: document.getElementById("findMatchCase"), entireWordCheckbox: document.getElementById("findEntireWord"), findMsg: document.getElementById("findMsg"), findResultsCount: document.getElementById("findResultsCount"), findPreviousButton: document.getElementById("findPrevious"), findNextButton: document.getElementById("findNext") }, passwordOverlay: { overlayName: "passwordOverlay", container: document.getElementById("passwordOverlay"), label: document.getElementById("passwordText"), input: document.getElementById("password"), submitButton: document.getElementById("passwordSubmit"), cancelButton: document.getElementById("passwordCancel") }, documentProperties: { overlayName: "documentPropertiesOverlay", container: document.getElementById("documentPropertiesOverlay"), closeButton: document.getElementById("documentPropertiesClose"), fields: { fileName: document.getElementById("fileNameField"), fileSize: document.getElementById("fileSizeField"), title: document.getElementById("titleField"), author: document.getElementById("authorField"), subject: document.getElementById("subjectField"), keywords: document.getElementById("keywordsField"), creationDate: document.getElementById("creationDateField"), modificationDate: document.getElementById("modificationDateField"), creator: document.getElementById("creatorField"), producer: document.getElementById("producerField"), version: document.getElementById("versionField"), pageCount: document.getElementById("pageCountField"), pageSize: document.getElementById("pageSizeField"), linearized: document.getElementById("linearizedField") } }, errorWrapper, printContainer: document.getElementById("printContainer"), openFileInputName: "fileInput", debuggerScriptPath: "./debugger.js" }; } function webViewerLoad() { const config = getViewerConfiguration(); const event = document.createEvent("CustomEvent"); event.initCustomEvent("webviewerloaded", true, true, { source: window }); try { parent.document.dispatchEvent(event); } catch (ex) { console.error(`webviewerloaded: ${ex}`); document.dispatchEvent(event); } _app.PDFViewerApplication.run(config); } if (document.blockUnblockOnload) { document.blockUnblockOnload(true); } if (document.readyState === "interactive" || document.readyState === "complete") { webViewerLoad(); } else { document.addEventListener("DOMContentLoaded", webViewerLoad, true); } })(); /******/ })() ; //# sourceMappingURL=viewer.js.map ================================================ FILE: lib/tracky-mouse/.gitattributes ================================================ * text=auto ================================================ FILE: lib/tracky-mouse/.gitignore ================================================ private/ dist/ # Blender *.blend[0-9] ################# # Node.js ################# # Logs logs *.log npm-debug.log* yarn-debug.log* yarn-error.log* lerna-debug.log* # Diagnostic reports (https://nodejs.org/api/report.html) report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json # Runtime data pids *.pid *.seed *.pid.lock .DS_Store # Directory for instrumented libs generated by jscoverage/JSCover lib-cov # Coverage directory used by tools like istanbul coverage *.lcov # nyc test coverage .nyc_output # node-waf configuration .lock-wscript # Compiled binary addons (https://nodejs.org/api/addons.html) build/Release # Dependency directories node_modules/ jspm_packages/ # TypeScript v1 declaration files typings/ # TypeScript cache *.tsbuildinfo # Optional npm cache directory .npm # Optional eslint cache .eslintcache # Optional REPL history .node_repl_history # Output of 'npm pack' *.tgz # Yarn Integrity file .yarn-integrity # dotenv environment variables file .env .env.test # parcel-bundler cache (https://parceljs.org/) .cache # next.js build output .next # nuxt.js build output .nuxt # vuepress build output .vuepress/dist # Serverless directories .serverless/ # FuseBox cache .fusebox/ # DynamoDB Local files .dynamodb/ # Webpack .webpack/ # Electron-Forge out/ ################# # Mac OS ################# # General .DS_Store .AppleDouble .LSOverride # Icon must end with two \r Icon # Thumbnails ._* # Files that might appear in the root of a volume .DocumentRevisions-V100 .fseventsd .Spotlight-V100 .TemporaryItems .Trashes .VolumeIcon.icns .com.apple.timemachine.donotpresent # Directories potentially created on remote AFP share .AppleDB .AppleDesktop Network Trash Folder Temporary Items .apdisk ################# # Linux ################# *~ # temporary files which can be created if a process still has a handle open of a deleted file .fuse_hidden* # KDE directory preferences .directory # Linux trash folder which might appear on any partition or disk .Trash-* # .nfs files are created when an open file is removed but is still being accessed .nfs* ################# # Windows ################# # Windows thumbnail cache files Thumbs.db Thumbs.db:encryptable ehthumbs.db ehthumbs_vista.db # Dump file *.stackdump # Folder config file [Dd]esktop.ini # Recycle Bin used on file shares $RECYCLE.BIN/ # Windows Installer files *.cab *.msi *.msix *.msm *.msp # Windows shortcuts *.lnk ================================================ FILE: lib/tracky-mouse/.gitrepo ================================================ ; DO NOT EDIT (unless you know what you are doing) ; ; This subdirectory is a git "subrepo", and this file is maintained by the ; git-subrepo command. See https://github.com/git-commands/git-subrepo#readme ; [subrepo] remote = https://github.com/1j01/tracky-mouse.git branch = v1.2.0 commit = 2cca8048692bef586e6814f04e408c7072525b21 parent = 6ac7bc577041f3933d4cfac31ec995045c9c2056 method = merge cmdver = 0.4.6 ================================================ FILE: lib/tracky-mouse/.vscode/extensions.json ================================================ { "recommendations": [ "nopjmp.fairyfloss", "streetsidesoftware.code-spell-checker" ] } ================================================ FILE: lib/tracky-mouse/.vscode/launch.json ================================================ { // Use IntelliSense to learn about possible attributes. // Hover to view descriptions of existing attributes. // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 "version": "0.2.0", "configurations": [ { // To use this configuration, you must run Chrome with a flag: // google-chrome --remote-debugging-port=9222 http://127.0.0.1:64206 // or for Windows: // start chrome --remote-debugging-port=9222 http://127.0.0.1:64206 // and Chrome must not be running beforehand, as the flag won't apply otherwise. // And you need to have the dev server running: // npm run dev // If you really don't want to close Chrome, you can use a temporary profile. // Assuming cmd.exe and not bash: // mkdir C:\TempChromeProfile // echo {"browser": {"has_seen_welcome_page": true, "default_browser_infobar_last_declined": "13354566465257726"}} > C:\TempChromeProfile\Preferences // start chrome --remote-debugging-port=9222 --user-data-dir="C:\TempChromeProfile" --disable-fre --no-default-browser-check --no-first-run http://127.0.0.1:64206 // Cleanup: // rmdir /s /q C:\TempChromeProfile "type": "chrome", "request": "attach", "name": "Attach to Chrome", "port": 9222, "urlFilter": "http://127.0.0.1:64206/*", "webRoot": "${workspaceFolder}" }, { // https://www.electronjs.org/docs/latest/tutorial/debugging-vscode "name": "Electron: Debug Main Process", "type": "node", "request": "launch", "cwd": "${workspaceFolder}", "runtimeExecutable": "${workspaceFolder}/desktop-app/node_modules/.bin/electron", "windows": { "runtimeExecutable": "${workspaceFolder}/desktop-app/node_modules/.bin/electron.cmd" }, "args": [ "desktop-app" ], "outputCapture": "std" } ] } ================================================ FILE: lib/tracky-mouse/.vscode/settings.json ================================================ { // .----------------------------. // | Filtering | // '----------------------------' // This hides files from the file tree as well as search results. "files.exclude": { "**/node_modules": true, "**/out": true, "**/dist": true, }, // This affects Find In Files (Ctrl+Shift+F) but also Go To File (Ctrl+P) and // the new Quick Search (experimental), which I've been using a lot since it was released. "search.exclude": { "**/images": true, "**/lib": true, "**/out": true, // Symbolic link to the core library, causes duplicate/non-canonical search results. "website/core": true, // The package lock files contain a lot of repetition, and are usually noise in search results. // You can often search with `npm ls` if you want to check if a package is installed, // and what depends on what. "**/package-lock.json": true, }, // Prevent accidental editing. // This can always be overridden with the command "File: Toggle Active Editor Read-only in Session" "files.readonlyInclude": { // Electron Forge output "**/out/**": true, // Built/installed app (sometimes I follow error message links into the built app's code, and end up editing it by mistake) "**/resources/app/**": true, // Node.js "**/node_modules/**": true, "**/package-lock.json": true, }, // .----------------------------. // | Formatting | // '----------------------------' "editor.formatOnSave": true, "editor.insertSpaces": false, "editor.detectIndentation": false, "editor.codeActionsOnSave": { "source.organizeImports": "always", }, "javascript.preferences.importModuleSpecifierEnding": "js", "typescript.preferences.importModuleSpecifierEnding": "js", "html.format.unformattedContentDelimiter": "", // Note: this doesn't apply to "JSON with comments" files, such as this one. That's [jsonc]. "[json]": { // npm respects different indent styles, but always adds a newline at the end of package.json/package-lock.json, // so this avoids ping-ponging changes in git. // This could be applied to all files for consistency, but it may introduce noise if all files aren't formatted at once. "files.insertFinalNewline": true, // Maintaining current indentation for now, but could remove this for consistency. "editor.detectIndentation": true, }, // .----------------------------. // | Theming | // '----------------------------' "workbench.colorTheme": "fairyfloss", "workbench.colorCustomizations": { "[fairyfloss]": { "terminal.ansiMagenta": "#f36aff", // hard to see npm errors otherwise "terminal.ansiBrightMagenta": "#f8adff", // not sure if needed, but figured I'd override the set of magentas } }, // .------------------------- - . // | Uncategorised settings // '------------------------- - . } ================================================ FILE: lib/tracky-mouse/API.md ================================================ # API docs have moved The API documentation has moved to the [core/README.md](./core/README.md) file. ================================================ FILE: lib/tracky-mouse/CHANGELOG.md ================================================ # Changelog All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] No changes here yet. ## [1.2.0] - 2024-12-17 ### Deprecated - `TrackyMouse.cleanupDwellClicking()` is deprecated in favor of calling `dispose()` on the object returned by `TrackyMouse.initDwellClicking()`. ### Changed - The Tracky Mouse UI no longer includes a stats.js performance monitor by default. You can still enable it by passing `{statsJs: true}` to `TrackyMouse.init()` and, if needed, also to `TrackyMouse.loadDependencies()`. ### Added - `TrackyMouse.init()` now returns an object with a `dispose()` method, which you can call to stop head tracking and remove the UI. - The object returned by `TrackyMouse.initDwellClicking()` now has a `dispose()` method as well, which you can use instead of `TrackyMouse.cleanupDwellClicking()`. ### Fixed - `TrackyMouse.cleanupDwellClicking()` now handles multiple dwell clickers, not that I know of any use case for that. ## [1.1.0] - 2024-10-20 ### Added - Start/stop button. This toggles head tracking, and, in the desktop app, dwell clicking as well. In the web library, dwell clicking is set up separately, and is not currently controlled by this button (or the keyboard shortcut F9). - Desktop app now supports dwell clicking. This means you can use Tracky Mouse with lots of software not designed with head tracking in mind. I just played a game of Mahjongg, and it worked well. - Settings are now persisted, both in the desktop app and in the browser. - Desktop app includes menu items for exporting and importing settings. - Desktop app now remembers the window size and position. - Desktop app lets you regain manual control by simply moving the mouse, pausing temporarily, and resuming when you stop moving the mouse. - Friendly error handling for different camera access failure scenarios. - Command line interface to control the desktop app, supporting `--start` and `--stop` to toggle head tracking. - API documentation. - Website at [TrackyMouse.js.org](https://trackymouse.js.org/). - Parameter validation. - `tracky-mouse.js` includes a CommonJS export, untested. I'm only testing script tag usage. I hope to switch to ES modules soon. - `beforeDispatch()`/`afterDispatch()` callbacks for detecting untrusted gestures, outside of an event where you could use `event.isTrusted`. - `beforePointerDownDispatch()`/`afterReleaseDrag()` callbacks for JS Paint to replace accessing global `pointers` array. - `initDwellClicking` returns an object `{paused}` which lets you pause and resume dwell clicking. ### Fixed - Function `average_points` was missing. It existed in JS Paint, the only place I had tested the library, since I was extracting the code from JS Paint. - Similarly, styles for the dwell click indicator and hover halo were missing or not applying. (Since they were provided by CSS in JS Paint, I didn't notice, in my rushed testing.) - The JS assumed the existence of a global `pointer_active` from JS Paint. This has been replaced with `config.isHeld()`. - Missing `facemesh.worker.js` file. - "Mirror" checkbox was too easy to accidentally click due to a large `