texlive[63957] Master: figput (22jul22)

commits+karl at tug.org commits+karl at tug.org
Fri Jul 22 23:48:41 CEST 2022


Revision: 63957
          http://tug.org/svn/texlive?view=revision&revision=63957
Author:   karl
Date:     2022-07-22 23:48:41 +0200 (Fri, 22 Jul 2022)
Log Message:
-----------
figput (22jul22)

Modified Paths:
--------------
    trunk/Master/tlpkg/bin/tlpkg-ctan-check
    trunk/Master/tlpkg/tlpsrc/collection-pictures.tlpsrc

Added Paths:
-----------
    trunk/Master/texmf-dist/doc/latex/figput/
    trunk/Master/texmf-dist/doc/latex/figput/LICENSE.txt
    trunk/Master/texmf-dist/doc/latex/figput/README.md
    trunk/Master/texmf-dist/doc/latex/figput/example/
    trunk/Master/texmf-dist/doc/latex/figput/example/example.pdf
    trunk/Master/texmf-dist/doc/latex/figput/example/example.tex
    trunk/Master/texmf-dist/doc/latex/figput/example/externalcode.js
    trunk/Master/texmf-dist/doc/latex/figput/figput-manual/
    trunk/Master/texmf-dist/doc/latex/figput/figput-manual/figput-manual.pdf
    trunk/Master/texmf-dist/doc/latex/figput/figput-manual/figput-manual.tex
    trunk/Master/texmf-dist/doc/latex/figput/javascript/
    trunk/Master/texmf-dist/doc/latex/figput/javascript/development/
    trunk/Master/texmf-dist/doc/latex/figput/javascript/development/layout.ts
    trunk/Master/texmf-dist/doc/latex/figput/javascript/development/main.ts
    trunk/Master/texmf-dist/doc/latex/figput/javascript/development/tikz.ts
    trunk/Master/texmf-dist/doc/latex/figput/javascript/development/widgets.ts
    trunk/Master/texmf-dist/doc/latex/figput/javascript/figput.html
    trunk/Master/texmf-dist/doc/latex/figput/javascript/layout.js
    trunk/Master/texmf-dist/doc/latex/figput/javascript/main.js
    trunk/Master/texmf-dist/doc/latex/figput/javascript/pdf.js
    trunk/Master/texmf-dist/doc/latex/figput/javascript/pdf.worker.min.js
    trunk/Master/texmf-dist/doc/latex/figput/javascript/pdfjs_license.txt
    trunk/Master/texmf-dist/doc/latex/figput/javascript/release/
    trunk/Master/texmf-dist/doc/latex/figput/javascript/release/figput.html
    trunk/Master/texmf-dist/doc/latex/figput/javascript/release/figput.js
    trunk/Master/texmf-dist/doc/latex/figput/javascript/server.py
    trunk/Master/texmf-dist/doc/latex/figput/javascript/tikz.js
    trunk/Master/texmf-dist/doc/latex/figput/javascript/widgets.js
    trunk/Master/texmf-dist/tex/latex/figput/
    trunk/Master/texmf-dist/tex/latex/figput/figput.sty
    trunk/Master/tlpkg/tlpsrc/figput.tlpsrc

Added: trunk/Master/texmf-dist/doc/latex/figput/LICENSE.txt
===================================================================
--- trunk/Master/texmf-dist/doc/latex/figput/LICENSE.txt	                        (rev 0)
+++ trunk/Master/texmf-dist/doc/latex/figput/LICENSE.txt	2022-07-22 21:48:41 UTC (rev 63957)
@@ -0,0 +1,342 @@
+
+This license applies to everything except pdf.js and pdf.worker.min.js,
+which are under the Apache 2.0 license.
+
+Creative Commons Attribution-ShareAlike 4.0 International Public License
+    https://creativecommons.org/licenses/by-sa/4.0/legalcode
+
+By exercising the Licensed Rights (defined below), You accept and
+agree to be bound by the terms and conditions of this Creative Commons
+Attribution-ShareAlike 4.0 International Public License ("Public
+License"). To the extent this Public License may be interpreted as a
+contract, You are granted the Licensed Rights in consideration of Your
+acceptance of these terms and conditions, and the Licensor grants You
+such rights in consideration of benefits the Licensor receives from
+making the Licensed Material available under these terms and
+conditions.
+
+Section 1 – Definitions.
+
+ a. Adapted Material means material subject to Copyright and Similar
+    Rights that is derived from or based upon the Licensed Material
+    and in which the Licensed Material is translated, altered,
+    arranged, transformed, or otherwise modified in a manner requiring
+    permission under the Copyright and Similar Rights held by the
+    Licensor. For purposes of this Public License, where the Licensed
+    Material is a musical work, performance, or sound recording,
+    Adapted Material is always produced where the Licensed Material is
+    synched in timed relation with a moving image. 
+
+ b. Adapter's License means the license You apply to Your Copyright
+    and Similar Rights in Your contributions to Adapted Material in
+    accordance with the terms and conditions of this Public License.
+    
+ c. BY-SA Compatible License means a license listed at
+    creativecommons.org/compatiblelicenses, approved by Creative
+    Commons as essentially the equivalent of this Public License.
+    
+ d. Copyright and Similar Rights means copyright and/or similar rights
+    closely related to copyright including, without limitation,
+    performance, broadcast, sound recording, and Sui Generis Database
+    Rights, without regard to how the rights are labeled or
+    categorized. For purposes of this Public License, the rights
+    specified in Section 2(b)(1)-(2) are not Copyright and Similar
+    Rights.
+    
+ e. Effective Technological Measures means those measures that, in the
+    absence of proper authority, may not be circumvented under laws
+    fulfilling obligations under Article 11 of the WIPO Copyright
+    Treaty adopted on December 20, 1996, and/or similar international
+    agreements.
+    
+ f. Exceptions and Limitations means fair use, fair dealing, and/or
+    any other exception or limitation to Copyright and Similar Rights
+    that applies to Your use of the Licensed Material.
+    
+ g. License Elements means the license attributes listed in the name
+    of a Creative Commons Public License. The License Elements of this
+    Public License are Attribution and ShareAlike.
+    
+ h. Licensed Material means the artistic or literary work, database,
+    or other material to which the Licensor applied this Public
+    License.
+    
+ i. Licensed Rights means the rights granted to You subject to the
+    terms and conditions of this Public License, which are limited to
+    all Copyright and Similar Rights that apply to Your use of the
+    Licensed Material and that the Licensor has authority to license.
+    
+ j. Licensor means the individual(s) or entity(ies) granting rights
+    under this Public License.
+    
+ k. Share means to provide material to the public by any means or
+    process that requires permission under the Licensed Rights, such
+    as reproduction, public display, public performance, distribution,
+    dissemination, communication, or importation, and to make material
+    available to the public including in ways that members of the
+    public may access the material from a place and at a time
+    individually chosen by them.
+    
+ l. Sui Generis Database Rights means rights other than copyright
+    resulting from Directive 96/9/EC of the European Parliament and of
+    the Council of 11 March 1996 on the legal protection of databases,
+    as amended and/or succeeded, as well as other essentially
+    equivalent rights anywhere in the world.
+    
+ m. You means the individual or entity exercising the Licensed Rights
+    under this Public License. Your has a corresponding meaning.
+    
+Section 2 – Scope.
+
+ a. License grant.
+ 
+     1. Subject to the terms and conditions of this Public License,
+        the Licensor hereby grants You a worldwide, royalty-free,
+        non-sublicensable, non-exclusive, irrevocable license to
+        exercise the Licensed Rights in the Licensed Material to:
+	
+         A. reproduce and Share the Licensed Material, in whole or in
+            part; and
+	    
+         B. produce, reproduce, and Share Adapted Material.
+	    
+     2. Exceptions and Limitations. For the avoidance of doubt, where
+        Exceptions and Limitations apply to Your use, this Public
+        License does not apply, and You do not need to comply with its
+        terms and conditions.
+	
+     3. Term. The term of this Public License is specified in Section
+        6(a).
+	
+     4. Media and formats; technical modifications allowed. The
+        Licensor authorizes You to exercise the Licensed Rights in all
+        media and formats whether now known or hereafter created, and
+        to make technical modifications necessary to do so. The
+        Licensor waives and/or agrees not to assert any right or
+        authority to forbid You from making technical modifications
+        necessary to exercise the Licensed Rights, including technical
+        modifications necessary to circumvent Effective Technological
+        Measures. For purposes of this Public License, simply making
+        modifications authorized by this Section 2(a)(4) never
+        produces Adapted Material.
+	
+     5. Downstream recipients.
+     
+         A. Offer from the Licensor – Licensed Material. Every
+            recipient of the Licensed Material automatically receives
+            an offer from the Licensor to exercise the Licensed Rights
+            under the terms and conditions of this Public License.
+	    
+         B. Additional offer from the Licensor – Adapted
+            Material. Every recipient of Adapted Material from You
+            automatically receives an offer from the Licensor to
+            exercise the Licensed Rights in the Adapted Material under
+            the conditions of the Adapter’s License You apply.
+	    
+         C. No downstream restrictions. You may not offer or impose
+            any additional or different terms or conditions on, or
+            apply any Effective Technological Measures to, the
+            Licensed Material if doing so restricts exercise of the
+            Licensed Rights by any recipient of the Licensed Material.
+	    
+     6. No endorsement. Nothing in this Public License constitutes or
+        may be construed as permission to assert or imply that You
+        are, or that Your use of the Licensed Material is, connected
+        with, or sponsored, endorsed, or granted official status by,
+        the Licensor or others designated to receive attribution as
+        provided in Section 3(a)(1)(A)(i).
+	
+  b. Other rights.
+  
+     1. Moral rights, such as the right of integrity, are not licensed
+        under this Public License, nor are publicity, privacy, and/or
+        other similar personality rights; however, to the extent
+        possible, the Licensor waives and/or agrees not to assert any
+        such rights held by the Licensor to the limited extent
+        necessary to allow You to exercise the Licensed Rights, but
+        not otherwise.
+	
+     2. Patent and trademark rights are not licensed under this Public
+        License.
+	
+     3. To the extent possible, the Licensor waives any right to
+        collect royalties from You for the exercise of the Licensed
+        Rights, whether directly or through a collecting society under
+        any voluntary or waivable statutory or compulsory licensing
+        scheme. In all other cases the Licensor expressly reserves any
+        right to collect such royalties.
+	
+Section 3 – License Conditions.
+
+Your exercise of the Licensed Rights is expressly made subject to the
+following conditions. 
+
+ a. Attribution.
+
+     1. If You Share the Licensed Material (including in modified
+        form), You must:
+	
+         A. retain the following if it is supplied by the Licensor
+            with the Licensed Material:
+	    
+             i. identification of the creator(s) of the Licensed
+                Material and any others designated to receive
+                attribution, in any reasonable manner requested by the
+                Licensor (including by pseudonym if designated);
+		
+            ii. a copyright notice;
+		
+           iii. a notice that refers to this Public License;
+		
+            iv. a notice that refers to the disclaimer of warranties;
+		
+             v. a URI or hyperlink to the Licensed Material to the
+                extent reasonably practicable;
+		
+         B. indicate if You modified the Licensed Material and retain
+            an indication of any previous modifications; and
+	    
+         C. indicate the Licensed Material is licensed under this
+            Public License, and include the text of, or the URI or
+            hyperlink to, this Public License.
+	    
+     2. You may satisfy the conditions in Section 3(a)(1) in any
+        reasonable manner based on the medium, means, and context in
+        which You Share the Licensed Material. For example, it may be
+        reasonable to satisfy the conditions by providing a URI or
+        hyperlink to a resource that includes the required
+        information.
+	
+     3. If requested by the Licensor, You must remove any of the
+        information required by Section 3(a)(1)(A) to the extent
+        reasonably practicable.
+	
+ b. ShareAlike.
+
+    In addition to the conditions in Section 3(a), if You Share
+    Adapted Material You produce, the following conditions also apply.
+    
+     1. The Adapter’s License You apply must be a Creative Commons
+        license with the same License Elements, this version or later,
+        or a BY-SA Compatible License.
+	
+     2. You must include the text of, or the URI or hyperlink to, the
+        Adapter's License You apply. You may satisfy this condition in
+        any reasonable manner based on the medium, means, and context
+        in which You Share Adapted Material.
+	
+     3. You may not offer or impose any additional or different terms
+        or conditions on, or apply any Effective Technological
+        Measures to, Adapted Material that restrict exercise of the
+        rights granted under the Adapter's License You apply.
+	
+Section 4 – Sui Generis Database Rights.
+
+Where the Licensed Rights include Sui Generis Database Rights that
+apply to Your use of the Licensed Material:
+
+ a. for the avoidance of doubt, Section 2(a)(1) grants You the right
+    to extract, reuse, reproduce, and Share all or a substantial
+    portion of the contents of the database;
+    
+ b. if You include all or a substantial portion of the database
+    contents in a database in which You have Sui Generis Database
+    Rights, then the database in which You have Sui Generis Database
+    Rights (but not its individual contents) is Adapted Material,
+    including for purposes of Section 3(b); and
+    
+ c. You must comply with the conditions in Section 3(a) if You Share
+    all or a substantial portion of the contents of the database.
+
+For the avoidance of doubt, this Section 4 supplements and does not
+replace Your obligations under this Public License where the Licensed
+Rights include other Copyright and Similar Rights.
+
+Section 5 – Disclaimer of Warranties and Limitation of Liability.
+
+ a. Unless otherwise separately undertaken by the Licensor, to the
+    extent possible, the Licensor offers the Licensed Material as-is
+    and as-available, and makes no representations or warranties of
+    any kind concerning the Licensed Material, whether express,
+    implied, statutory, or other. This includes, without limitation,
+    warranties of title, merchantability, fitness for a particular
+    purpose, non-infringement, absence of latent or other defects,
+    accuracy, or the presence or absence of errors, whether or not
+    known or discoverable. Where disclaimers of warranties are not
+    allowed in full or in part, this disclaimer may not apply to You.
+    
+ b. To the extent possible, in no event will the Licensor be liable to
+    You on any legal theory (including, without limitation,
+    negligence) or otherwise for any direct, special, indirect,
+    incidental, consequential, punitive, exemplary, or other losses,
+    costs, expenses, or damages arising out of this Public License or
+    use of the Licensed Material, even if the Licensor has been
+    advised of the possibility of such losses, costs, expenses, or
+    damages. Where a limitation of liability is not allowed in full or
+    in part, this limitation may not apply to You.
+
+ c. The disclaimer of warranties and limitation of liability provided
+    above shall be interpreted in a manner that, to the extent
+    possible, most closely approximates an absolute disclaimer and
+    waiver of all liability.
+    
+Section 6 – Term and Termination.
+
+ a. This Public License applies for the term of the Copyright and
+    Similar Rights licensed here. However, if You fail to comply with
+    this Public License, then Your rights under this Public License
+    terminate automatically.
+    
+ b. Where Your right to use the Licensed Material has terminated under
+    Section 6(a), it reinstates:
+    
+     1. automatically as of the date the violation is cured, provided
+        it is cured within 30 days of Your discovery of the violation;
+        or
+	
+     2. upon express reinstatement by the Licensor.
+	
+    For the avoidance of doubt, this Section 6(b) does not affect any
+    right the Licensor may have to seek remedies for Your violations
+    of this Public License.
+    
+ c. For the avoidance of doubt, the Licensor may also offer the
+    Licensed Material under separate terms or conditions or stop
+    distributing the Licensed Material at any time; however, doing so
+    will not terminate this Public License.
+    
+ d. Sections 1, 5, 6, 7, and 8 survive termination of this Public
+    License.
+    
+Section 7 – Other Terms and Conditions.
+
+ a. The Licensor shall not be bound by any additional or different
+    terms or conditions communicated by You unless expressly agreed.
+    
+ b. Any arrangements, understandings, or agreements regarding the
+    Licensed Material not stated herein are separate from and
+    independent of the terms and conditions of this Public License.
+    
+Section 8 – Interpretation.
+
+ a. For the avoidance of doubt, this Public License does not, and
+    shall not be interpreted to, reduce, limit, restrict, or impose
+    conditions on any use of the Licensed Material that could lawfully
+    be made without permission under this Public License.
+    
+ b. To the extent possible, if any provision of this Public License is
+    deemed unenforceable, it shall be automatically reformed to the
+    minimum extent necessary to make it enforceable. If the provision
+    cannot be reformed, it shall be severed from this Public License
+    without affecting the enforceability of the remaining terms and
+    conditions.
+    
+ c. No term or condition of this Public License will be waived and no
+    failure to comply consented to unless expressly agreed to by the
+    Licensor.
+    
+ d. Nothing in this Public License constitutes or may be interpreted
+    as a limitation upon, or waiver of, any privileges and immunities
+    that apply to the Licensor or You, including from the legal
+    processes of any jurisdiction or authority.
+    


Property changes on: trunk/Master/texmf-dist/doc/latex/figput/LICENSE.txt
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: trunk/Master/texmf-dist/doc/latex/figput/README.md
===================================================================
--- trunk/Master/texmf-dist/doc/latex/figput/README.md	                        (rev 0)
+++ trunk/Master/texmf-dist/doc/latex/figput/README.md	2022-07-22 21:48:41 UTC (rev 63957)
@@ -0,0 +1,15 @@
+
+Use JavaScript to add interactive figures to LaTeX documents
+
+See figput-manual.pdf for a detailed overview.
+
+See https://rsfairman.github.io/figput-example/ for a running example.
+
+Suggestions for improvement can be made under "issues" at
+
+https://github.com/rsfairman/figput
+
+and I can be reached directly at rsfairman at yahoo.com.
+
+
+


Property changes on: trunk/Master/texmf-dist/doc/latex/figput/README.md
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: trunk/Master/texmf-dist/doc/latex/figput/example/example.pdf
===================================================================
(Binary files differ)

Index: trunk/Master/texmf-dist/doc/latex/figput/example/example.pdf
===================================================================
--- trunk/Master/texmf-dist/doc/latex/figput/example/example.pdf	2022-07-21 23:49:49 UTC (rev 63956)
+++ trunk/Master/texmf-dist/doc/latex/figput/example/example.pdf	2022-07-22 21:48:41 UTC (rev 63957)

Property changes on: trunk/Master/texmf-dist/doc/latex/figput/example/example.pdf
___________________________________________________________________
Added: svn:mime-type
## -0,0 +1 ##
+application/pdf
\ No newline at end of property
Added: trunk/Master/texmf-dist/doc/latex/figput/example/example.tex
===================================================================
--- trunk/Master/texmf-dist/doc/latex/figput/example/example.tex	                        (rev 0)
+++ trunk/Master/texmf-dist/doc/latex/figput/example/example.tex	2022-07-22 21:48:41 UTC (rev 63957)
@@ -0,0 +1,2342 @@
+
+\documentclass[10pt]{article}
+
+% This file was written to demonstrate this package.
+\usepackage{figput}
+
+% Allows various tweaks to itemize as optional arguments.
+\usepackage{enumitem}
+
+% Allows \verb in footnotes
+\usepackage{fancyvrb}
+
+
+\begin{document}
+
+% Need this for fancyvrb to work.
+\VerbatimFootnotes
+
+
+% Getting this right may involve some experimentation.
+\SetInnerMargin{135pt}
+\SetOuterMargin{135pt}
+
+% Turn this on to show figures or off to save time.
+\NeverSkip
+
+% Some of the \FigPut commands refer to this code.
+\LoadFigureCode{externalcode.js}
+
+
+This document demonstrates some of the features of \textsc{FigPut}. It
+consists of a series of snippets of exposition. There are a few simple
+examples -- B\'ezier curves, the ellipse and diffiusion -- followed by
+a more extended example about gears.
+
+% Much of what follows uses the figput *environment*. This uses the
+% \FigPut *command*. 
+\begin{figure}[b!]
+\FigPut{bezier,175bp}[17bp,22bp,done,skip]
+\caption{A Cubic B\'ezier Curve}
+\label{fig-cubic-bezier}
+\end{figure}
+
+\section{Example: B\'ezier Curves}
+
+B\'ezier curves are a convenient way of defining curves in the
+plane. They can be defined using Bernstein polynomials. The 
+Bernstein polynomials of degree $n$ are defined by
+$$B_i^n(t) = {n \choose i} t^i (1-t)^{n-i},\qquad i=0,\ldots,n.$$
+A cubic B\'ezier curve is a linear combination of the Bernstein
+polynomials of degree 3:
+$$C(t) = \sum_{i=0}^3 p_i B_i^3(t),$$
+where the four $p_i$ are points in the plane and $t$ is limited to
+$[0,1]$. This can be written as the pair of equations $(x(t),y(t))=
+C(t)$, where
+\begin{eqnarray*}
+x(t) &=& x_1\cdot (1-t)^3 + x_2\cdot 3(1-t)^2t + x_3\cdot 3(1-t)t^2 +
+x_4\cdot t^3 \\
+y(t) &=& y_1\cdot (1-t)^3 + y_2\cdot 3(1-t)^2t + y_3\cdot 3(1-t)t^2 +
+y_4\cdot t^3,
+\end{eqnarray*}
+$(x_i,y_i) = p_i$ and the indices on the $p_i$ have been
+shifted. We have $C(0) = p_1$ and $C(1)=p_4$ and the other two points
+act as ``controls.'' See Figure (\ref{fig-cubic-bezier}), noting that
+the line determined by the pair of points controlling each end of the curve is
+tangent to the corresponding end-point of the B\'ezier curve.
+
+\section{Example: Drawing an Ellipse}
+
+One way to define an ellipse is illustrated by Figure
+(\ref{fig-ellipse-draw}). Choose two points, $F_1$ and $F_2$ (the
+{\bf foci}), and fix some $k>0$. The ellipse is then
+the set of points, $P$, satisfying
+$$d(P,F_1) + d(P,F_2) = k,$$
+where $d(A,B)$ is the distance from $A$ to $B$.
+
+The figure makes it clear why this is sometimes refered to as the
+``tacks and string'' definition. Imagine tacking each end of a bit of
+string, of length $k$, to the two foci; then tracing out the ellipse
+by holding a pencil at the limit of what the string will allow as the
+pencil travels about the foci. 
+
+\begin{figure}
+\begin{figput}{elldraw,175bp}[done,skip]
+  function elldraw(ctx) {
+
+  // The length of the string.
+  let k = 150;
+  
+  let yaxis = 85;
+  
+  // Limit these two points to be along the line y = yaxis.
+  let w1 = DraggableDotWidget.register(ctx,125,yaxis,'d1');
+  let w2 = DraggableDotWidget.register(ctx,225,yaxis,'d2');
+
+  // We need a LoopAnimWidget for an animation, even though we never want
+  // see the widget.
+  let numSteps = 1000;
+  let loopw = LoopAnimWidget.register(ctx,-100,100,1.0,
+  false, // hidden
+  numSteps, // steps per loop
+  0, // starting step
+  10, // ms time step
+  false,false,false,false,false, // nothing is visible
+  'loop');
+
+  w1.widgetY = yaxis;
+  w2.widgetY = yaxis;
+  
+  // The origin is the mid-point.
+  let cx = (w1.widgetX + w2.widgetX) / 2;
+  let cy = yaxis;
+
+  // c = distance from foci to center, a = x-radius and b = y-radius.
+  let c = Math.abs(w1.widgetX - cx);
+  let a = k / 2;
+  let b = Math.sqrt(a*a - c*c);
+
+  // The ellipse
+  let p = new FPath();
+  p.ellipse(cx,cy,a,b,0,0,2*Math.PI);
+  ctx.strokeStyle = 'black';
+  ctx.lineWidth = 1.5;
+  ctx.stroke(p);
+
+  // An animation, based on the parameterization p(t) = (a cos(t),b sin(t)).
+  // This based on the eccentric angle, so time won't seem to be
+  // constant, but that's OK. This is easier.
+  let t = 2*Math.PI * loopw.curStep / numSteps;
+  let px = a * Math.cos(t) + cx;
+  let py = b * Math.sin(t) + cy;
+
+  p = new FPath();
+  p.moveTo(cx - c,yaxis);
+  p.lineTo(px,py);
+  p.lineTo(cx + c,yaxis);
+  ctx.lineWidth = 0.4;
+  ctx.stroke(p);
+  
+  // In this case (unlike most others), the widgets must be explicitly drawn.
+  w1.draw(ctx);
+  w2.draw(ctx);
+}    
+\end{figput}
+\caption{Tacks-and-string Ellipse}
+\label{fig-ellipse-draw}
+\end{figure}
+
+\section{Example: Diffusion}
+
+The concept of diffusion is illustrated by Figure
+(\ref{fig-boltzmann}). Statistical mechanics and Boltzmann's equation
+explain concepts like heat transfer and the gas laws by modeling the
+random motion of many particles. These equations may be difficult to grasp,
+but an intuitive understanding is not difficult. At time zero, there
+is some set of particles on the left half of the box, each of which is
+moving with some randomly distributed momentum. The divider is removed
+and, over time, the particles distribute themselves more evenly
+throughout the box.  
+
+\begin{figure}
+\begin{figput}{diffusion,180bp}[0bp,30bp,done,skip]
+function diffusion(ctx) {
+  
+  // This is an open-ended animation.
+  let wanim = OpenAnimWidget.register(ctx,50,-32,1.0,
+    200, // horizontal size
+    true, // visible
+    10, // time step (ms)
+    10000, // decay
+    false, // steps not visible
+    true, // fast/slow visible
+    true, // pause/run visible
+    true, // time bar visible
+    false, // time bar not grabable.
+    'anim');
+
+  // A button for removing the divider.
+  let wbut = ButtonWidget.register(ctx,-85,32,'Open/Restart','but');
+
+  // Draw the enclosing box.
+  let p = new FPath();
+  p.moveTo(1,2);
+  p.lineTo(300,2);
+  p.lineTo(300,178);
+  p.lineTo(1,178);
+  p.closePath();
+  ctx.lineWidth = 3;
+  ctx.fillStyle = 'black';
+  ctx.strokeStyle = 'black';
+  ctx.stroke(p);
+
+  // These define the box for the particles.
+  let boxleft = 5;
+  let boxright = 150;
+  let boxbot = 4;
+  let boxtop = 175;
+  let boxdivider = 145;
+
+  if ((diffusion.started === undefined) || (wbut.resetState === true))
+    {
+      wbut.resetState = false;
+      wanim.curStep = 0;
+      
+      // Allocate 100 dots in the left half of the box.
+      // Each needs a position and direction.
+      diffusion.pos = [];
+      diffusion.dir = [];
+      for (let i = 0; i < 100; i++)
+        {
+          // Position
+          let r = Math.random();
+          let x = boxleft + r*(boxdivider - boxleft - 4);
+
+          r = Math.random();
+          let y = boxbot + r*(boxtop-boxbot)
+          diffusion.pos.push({x: x, y: y});
+
+          // Direction vector. Say each is evenly distributed over
+          // (0,1). That is not physically correct, but that's OK.
+          // To make this better, consider how the balls could bounce
+          // off of each other. That's messy, so I let them pass
+          // through one another, and only consider bouncing off walls.
+          let vx = (Math.random() - 0.50) / 2.0 ;
+          let vy = Math.sqrt(0.25*0.25 - vx*vx);
+          if (Math.random() > 0.50)
+            vy *= -1;
+
+          // Don't let either value be too small. It looks weird.
+          if (Math.abs(vx) < 0.05)
+            {
+              if (vx < 0.0)
+                vx = -0.05;
+              else
+                vx = 0.05;
+            }
+          if (Math.abs(vy) < 0.05)
+            {
+              if (vy < 0.0)
+                vy = -0.05;
+              else
+                vy = 0.05;
+            }
+
+          diffusion.dir.push({x: vx, y: vy});
+        }
+
+      diffusion.started = true;
+    }
+
+    // As noted, we only consider bouncing off walls. Assume that a ball
+    // moves from it's old position to new by the dir vector with each
+    // time step. If that would take the ball outside the rectangle, then
+    // we must consider reflection.
+    let dotR = 3;
+    
+    // Draw the "wall" if it's closed.
+    if (wbut.clickState === false)
+      {
+        p = new FPath();
+        p.moveTo(boxdivider,2);
+	p.lineTo(boxdivider,boxtop + 2);
+	ctx.lineWidth = 3;
+	ctx.stroke(p);
+      }
+    
+    // This depends on whether the wall is up.
+    let rightEdge = boxdivider - 3;
+
+    if (wbut.clickState === true)
+      rightEdge = 299;
+
+    for (let i = 0; i < diffusion.pos.length; i++)
+      {
+        let pold = diffusion.pos[i];
+        let vold = diffusion.dir[i];
+
+        let pnew = {x: pold.x + vold.x, y: pold.y + vold.y};
+        //console.log(i+ ' ' +pnew.y);
+        if (pnew.y < boxbot)
+          {
+            // Bounced off top edge.
+            // If each step takes 1 unit of time, then it hit the edget at
+            // Actually... be sloppy. I'm not really doing physics; I just
+            // want to demonstrate the FigPut system.
+            // The balls are moving slowly, so only allow them to reflect
+            // at the time of the step divisions.
+            diffusion.dir[i].y *= -1;
+          }
+          if (pnew.y > boxtop)
+            {
+              // Bottom edge bounce.
+              diffusion.dir[i].y *= -1;
+            }
+          if (pnew.x < boxleft)
+            // Left edge bounce.
+            diffusion.dir[i].x *= -1;
+          if (pnew.x > rightEdge - 2)
+            // Right edge bounce.
+            diffusion.dir[i].x *= -1;
+
+        // Redo, after taking reflections into account.
+        vold = diffusion.dir[i];
+        pnew = {x: pold.x + vold.x, y: pold.y + vold.y};
+
+        diffusion.pos[i] = pnew;
+
+        p = new FPath();
+        p.ellipse(pnew.x,pnew.y,dotR,dotR,0,0,2*Math.PI);
+        ctx.fill(p);
+      }
+}    
+\end{figput}
+\caption{Diffusion and Boltzmann's Equation}
+\label{fig-boltzmann}
+\end{figure}
+
+\newpage
+
+\section{Example: Gears}
+
+Gears like those in Figure (\ref{fig-gear-toy}) might work after a
+fashion, but it's rare to see such gears in anything other than a
+child's toy. As a rule, gears take the form shown in Figure 
+(\ref{fig-final-gear}). Why? 
+
+\begin{figure}[b!]
+\begin{figput}{badgear,130bp}[done,skip]
+function badgear(ctx) {
+  
+  var path1 = new FPath();
+  
+  let numTeeth = 17;
+  let cx = 70;
+  let cy = 65;
+  let inR = 40;
+  let outR = 50;
+  
+  path1 = new FPath();
+  
+  // A dot at the center.
+  path1.ellipse(cx,cy,2,2,0,0,2*Math.PI);
+  ctx.fillStyle = 'black';
+  ctx.fill(path1);
+  
+  // The teeth of the gear.
+  path1 = new FPath();
+  
+  // One degree, in radians, then 360 and 180 degrees.
+  let d = Math.PI / 180;
+  let d360 = 2 * Math.PI;
+  let d180 = Math.PI;
+  
+  let x = cx + inR * Math.cos(0);
+  let y = cy + inR * Math.sin(0);
+  path1.moveTo(x,y);
+  
+  let deltaA = Math.PI/numTeeth;
+  
+  for (let i = 0; i < numTeeth; i++)
+    {
+      x = cx + inR * Math.cos(2 * i * deltaA + deltaA);
+      y = cy + inR * Math.sin(2 * i * deltaA + deltaA);
+      path1.lineTo(x,y);
+
+      x = cx + outR * Math.cos(2 * i * deltaA + deltaA);
+      y = cy + outR * Math.sin(2 * i * deltaA + deltaA);
+      path1.lineTo(x,y);
+
+      x = cx + outR * Math.cos(2 * i * deltaA + deltaA + deltaA);
+      y = cy + outR * Math.sin(2 * i * deltaA + deltaA + deltaA);
+      path1.lineTo(x,y);
+
+      x = cx + inR * Math.cos(2 * i * deltaA + deltaA + deltaA);
+      y = cy + inR * Math.sin(2 * i * deltaA + deltaA + deltaA);
+      path1.lineTo(x,y);
+    }
+  
+  path1.closePath();
+  ctx.lineWidth = 1.5;
+  ctx.stroke(path1);
+  
+  // Now the triangular teeth.
+  numTeeth = 21;
+  cx = 230;
+  outR = 60;
+  
+  path1 = new FPath();
+  path1.ellipse(cx,cy,2,2,0,0,2*Math.PI);
+  ctx.fill(path1);
+  
+  path1 = new FPath();
+  
+  x = cx + + inR * Math.cos(0);
+  y = cy + inR * Math.sin(0);
+  path1.moveTo(x,y);
+  
+  for (let i = 0; i < numTeeth; i++)
+    {
+      x = cx + outR * Math.cos(i * d360/numTeeth + d180/numTeeth);
+      y = cy + outR * Math.sin(i * d360/numTeeth + d180/numTeeth);
+      path1.lineTo(x,y);
+            
+      x = cx + inR * Math.cos((i+1) * d360/numTeeth);
+      y = cy + inR * Math.sin((i+1) * d360/numTeeth);
+      path1.lineTo(x,y);
+    }
+  path1.closePath();
+  ctx.stroke(path1);
+}
+
+\end{figput}
+\caption{Crude Gear Designs}
+\label{fig-gear-toy}
+\end{figure}
+
+Figure (\ref{fig-gear-spoke}) illustrates the fundamental problem of
+gear design, using a particularly bad design. The ``gears'' here have
+been reduced to something more like spokes. The gear on the right
+rotates counter-clockwise at a constant rate and drives the gear on
+the left. As the gears rotate, the rate of rotation of the gear on the
+left will not be constant; at some positions, the left gear is nearly
+stationary and at other positions, it rotates much faster than the
+gear on the right. In addition, the point of contact slides,
+generating friction and wear. 
+
+\begin{figure}
+\begin{figput}{badspokegear,130bp}[done,skip]
+function badspokegear(ctx) {
+    
+  // Two gear-like pinwheels, where the one on the right drives the one on 
+  // the left. The idea is to show how the rotation surges, and why something
+  // like involvolute gears are needed.
+  //
+  // Modeling this is surprisingly fiddly. There's no need to make this
+  // fully general, for all possible arrangements, and it's not too bad
+  // if we restrict things a bit.
+  // 
+  // In general (too general), suppose that the two sets of spokes have
+  // lengths R1 and R2. Think of the gear on the right driving the
+  // gear on the left, with the gear on the right rotating ccw (under the
+  // usual RH coordinate system). WLOG, assume that the two axles are on the
+  // x-axis. We want to know where the two spokes initially touch "at
+  // the top," but it's actually easier to figure out where the last touch
+  // "at the bottom."
+  //
+  // To simplify, assume that all spokes (on both gears) have the same
+  // length, R. And assume that the centers of these gears are at
+  // (-x,0) and (x,0) so that the centers are 2x appart. Obviously, R > x
+  // for the gears to mesh at all.
+  // 
+  // Since the spokes are all the same length, it's easy to see that
+  // The angle of the RH spoke at the top is alpha above the x-axis when
+  // the spokes initally touch, and alpha below the x-axs when they cease
+  // to touch. Here, alpha is defined by
+  // cos(alpha) = x/R.
+  //
+  // Furthermore, let delta be the angle from spoke to spoke, so the
+  // number of spokes is 2 pi / delta. Assume that both gears have the
+  // same number of spokes. Note that delta must be less than 2 alpha
+  // for the spokes to always be in contact. Ideally, I want delta to be
+  // large enough so that no more than one pair of spokes (one on left and
+  // on on right) is ever in contact. Otherwise, it's more messy since
+  // you'd have to figure out which pair of spokes is doing the driving.
+  // In fact, it looks like I want delta = 2 alpha, or to put it another
+  // way, given delta, it follows that alpha = delta / 2.
+  //
+  // Now, think about what happens as the point of contact goes from the
+  // top, where the spoke barely touch, downward. The point of contact
+  // stays on the top of the left spoke and slides down on the right spoke.
+  // What you have is a triangle on the left with hypoteneuse R, and a 
+  // triangle on the right with hypoteneuse r. We need to determine r.
+  // Let beta be the angle of the right spoke above the x-axis. beta
+  // grows linearly with time, and is fully known...actually, beta
+  // *shrinks* if we think of it as the angle of the right spoke above
+  // the x-axis.  
+  //
+  // Let c be the x-coordinate of the point of contact, and let x1 be
+  // the distance from c to -x (the left axle) and x2 be the distance
+  // from c to +x (the right axle). We must have
+  // R^2 - x1^2 = r^2 - x2^2
+  // since the left and right triangles share the same vertical leg.
+  // And x1 + x2 = 2x by construction. The third equation we need
+  // is cos(beta) = x2/r or x2 = r cos(beta). 
+  // 
+  // Solve these three equations for x1, x2 and r in terms of R and x.
+  // First, use x1 = 2x - x2. Substitute:
+  // R^2 - x1^2 = r^2 - x2^2
+  // R^2 - (2x-x2)^2 = r^2 - x2^2
+  // R^2 - 4x^2 + 4x*x2 - (x2)^2 = r^2 - x2^2
+  // R^2 - 4x^2 + 4x*x2 = r^2
+  //
+  // Now use x2 = r cos(beta) and use C = cos(beta) for brevity:
+  // R^2 - 4x^2 + 4x*x2 = r^2
+  // R^2 - 4x^2 + 4x*(rC) = r^2
+  // r^2 - 4Cx r + 4x^2 - R^2 = 0.
+  // Solve for r by quadatic equation:
+  // r = (1/2) [ 4Cx \pm \sqrt{ 16C^2x^2 - 4(4x^2-R^2) } ]
+  // r = 2Cx \pm \sqrt{ 4C^2x^2 - 4x^2+ R^2 }
+  // r = 2Cx \pm \sqrt{ 4x^2(cos^2(beta) - 1 ) + R^2 }
+  // r = 2Cx \pm \sqrt{ -4x^2 sin^2(beta) + R^2 }
+  //
+  // Aside: note that the discriminant is always postive since R > x.
+  // I'm not sure what the two solutions here might "mean."
+  //
+  // This tells us what is going on from the point when the spokes touch
+  // at the top until you reach the point where they are aligned along the
+  // x-axis. However, we need the angle on the left -- that was the 
+  // whole point. We have angle beta on the right, and we want to know
+  // the angle, gamma, on the left.
+  //
+  // We have cos(gamma) = x1/R, where gamma is measured upwards from the 
+  // x-axis to the spoke in contact on the left gear (like normal).
+  //
+  // Now do something similar as the point of contact goes below the
+  // x-axis. It's the same basic calculation, except that the tip of the
+  // right spoke is in contact somewhere along the left spoke.
+  // Left and right are reversed.
+  //
+  // We still have x1 + x2 = 2x but now R^2 - x2^2 = r^2 - x1^2, and
+  // cos(beta) = x2/R. It's the same basic game. We get.
+  // 
+  // R^2 + 4x^2 - 4x*x2 = r^2
+  // just as before. But now use x2 = R cos(beta) (R, not r) and it's
+  // a simpler problem:
+  // R^2 - 4x^2 + 4x*x2 = r^2
+  // R^2 - 4x^2 + 4x R cos(beta) = r^2
+  // becomes
+  // r = \pm\sqrt{ R^2 - 4x^2 + 4x R cos(beta) }
+  //
+  // BUG: The calculation above treats the spokes as geometric lines, with zero
+  // thickness. Ideally, I should take the width of the lines into account.
+  
+  // The presence of this widget means that this is an animation.
+  // The code here will be called on a regular schedule.
+  let stepsPerRev = 500;
+  let startStep = 0;
+  let timeStep = 20;
+  
+  let w = LoopAnimWidget.register(ctx,
+    -LoopAnimWidget.Radius,LoopAnimWidget.Radius + LoopAnimWidget.TopHeight,0.75,
+    true,stepsPerRev,startStep,timeStep,
+    true,true,true,true,true,"wigname");
+
+  // BUG: I messed up when I wrote this and inadvertantly did all the
+  // measurements to the wrong scale. Thus, I have to undo my mistake.
+  // The real fix is to change all the constants below so that this
+  // scale() isn't necessary.
+  let mistakeT = ctx.getTransform();
+  ctx.scale(0.5,0.5);
+  
+  // The two gears are on opposite sides of this vertical line.
+  let xZero = 300;
+  
+  // You can change the number of teeth, but the surging is most apparent
+  // with four teeth (which is the minimum geometrically possible given
+  // the algebra. Somewhere around 6 or 7 teeth it becomes hard to see. 
+  // BUG: five teeth generates some kind of "jump" in the animation. 
+  // Not sure why.
+  let numTeeth = 4;
+  let spokeLength = 100;
+  
+  // The angle between spokes.
+  let delta = 2*Math.PI/numTeeth;
+  
+  // Spoke radius and thickness.
+  let R = spokeLength;
+  let spokeWidth = 2;
+  
+  // Distance of each spoke axis from the center line.
+  // I want the top pair of spokes to make contact at the same instant 
+  // that the bottom pair of spokes ceases contact. That requires
+  let x = R * Math.cos(delta/2);
+  
+  // Draw the spokes on the right. These are the drivers, so the angle rises
+  // linearly with time.
+  let cx = (xZero + x);
+  let cy = 140;
+  
+  var path1 = new FPath();
+  
+  // A dot at the center, probably not necessary.
+  path1.ellipse(cx,cy,2.0*spokeWidth,2.0*spokeWidth,0,0,2*Math.PI);
+  ctx.fill(path1);
+  
+  // Angle by which the gear has rotated, based on the step of the animation.
+  let rotA = w.curStep * 2 * Math.PI / stepsPerRev;
+  
+  for (let i = 0; i < numTeeth; i++)
+    { 
+      path1 = new FPath();
+      
+      let angle = i*delta + rotA;
+      while (angle < 0)
+        angle += 2 * Math.PI;
+      while (angle > 2*Math.PI)
+        angle -= 2 * Math.PI;
+      
+      path1.moveTo(cx,cy);
+      let x = cx + R * Math.cos(angle);
+      let y = cy + R * Math.sin(angle);
+      path1.lineTo(x,y);
+      
+      ctx.strokeStyle = "black";
+      ctx.lineWidth = spokeWidth;
+      ctx.stroke(path1);
+    }
+  
+  // Now the left, driven, set of spokes.
+  cx = (xZero - x);
+  
+  // Figure out which of the spokes on the right gear is the one in contact
+  // and doing the driving. It's the one whose angle relative to the 
+  // x-axis is between delta/2 above and delta/2 below the axis.
+  // To put it another way, its angle is in the range pi\pm delta/2.
+  // This could have been noted in the loop above.
+  let contactAngle = 0.0;
+  for (let i = 0; i < numTeeth; i++)
+    {
+      let angle = i*delta + rotA;
+      while (angle < 0)
+        angle += 2 * Math.PI;
+      while (angle > 2*Math.PI)
+        angle -= 2 * Math.PI;
+           
+      if ((angle < Math.PI + delta/2) && (angle > Math.PI - delta/2))
+        {
+          contactAngle = angle;
+          break;
+        }
+    }
+  
+  // contactAngle is the angle of the right gear's "contact spoke," but
+  // measured from the right. I want beta (in the notation above), measured
+  // from the left side, to put it in the range [-delta/2,+delta/2].
+  contactAngle = Math.PI - contactAngle;
+  
+  var gamma = 0;
+  if (contactAngle >= 0)
+    {
+      // The point of contact is above the x-axis. Slightly messier case.
+      let beta = contactAngle;
+      let disc = R*R - 4*x*x*Math.sin(beta)*Math.sin(beta);
+      let root = Math.sqrt(disc);
+      
+      // Conceptually, I'm not sure why, but this seems to be the right
+      // choice -- minus, not plus.
+      let r = 2 * Math.cos(beta) * x - root;
+      
+      let x2 = r * Math.cos(beta);
+      let x1 = 2 * x - x2;
+      
+      // I didn't address this in the long comment above, but
+      // (x1,sqrt(R^2-x1^2)) is the end-point of the left spoke in
+      // contact with the right spoke. The angle for this spoke is thus
+      // gamma, where cos(gamma) = x1/R.
+      gamma = Math.acos(x1/R);
+    }
+  else
+    {
+      // The point of contact is below the x-axis, hence the minus to 
+      // make beta positive.
+      let beta = -contactAngle;
+      let disc = R*R + 4*x*x - 4*x*R*Math.cos(beta);
+      let r = Math.sqrt(disc);
+      
+      let x2 = R * Math.cos(beta);
+      let x1 = 2 * x - x2;
+      
+      gamma = 2*Math.PI - Math.acos(x1/r);
+    }
+  
+  // A dot at the center, probably not necessary.
+  path1 = new FPath();
+  path1.ellipse(cx,cy,2.0*spokeWidth,2.0*spokeWidth,0,0,2*Math.PI);
+  ctx.fill(path1);
+  
+  // Draw the left spokes, based on gamma.
+  rotA = -w.curStep * 2 * Math.PI / stepsPerRev;
+  
+  for (let i = 0; i < numTeeth; i++)
+    { 
+      path1 = new FPath();
+      
+      path1.moveTo(cx,cy);
+      let x = cx + R * Math.cos(i*delta + gamma);
+      let y = cy + R * Math.sin(i*delta + gamma);
+
+      path1.lineTo(x,y);
+
+      ctx.lineWidth = spokeWidth;
+      ctx.stroke(path1);
+    }
+  
+  // BUG: Undo the above fix of my scaling mistake.
+  ctx.setTransform(mistakeT);
+}    
+\end{figput}
+\caption{Maybe the Worst Possible Gears?}
+\label{fig-gear-spoke}
+\end{figure}
+
+Understanding how to design gears without the kind of surging motion
+and wear inherent in the gears of Figure (\ref{fig-gear-spoke})
+explains why nearly all modern gears take the form of Figure
+(\ref{fig-final-gear}). The most glaring problem with the
+spoke-like gears is the way their motion varies -- imagine riding in a
+car with a gear-train based on such gears!
+
+Gears typically have what's called \emph{conjugate action},
+meaning that the ratio of their rates of rotation is constant,
+with no surging or lagging. Sometimes this is also called the
+\emph{fundamental law of gearing}, although it would be more accurate
+to call it a ``commonly desired feature,'' rather than a ``law.''
+Arranging the teeth of gears so that they have conjugate action is
+surprisingly tricky.
+
+\subsection{The Involute}
+  
+Figure (\ref{fig-basic-gear-constraints}) shows a cam and a lever-arm
+pushing against each other, causing them to rotate about their
+respective axes. Imagine that the cam rotates counter-clockwise,
+pushing the arm downwards. There are several crucial observations:
+\begin{enumerate}[itemsep=-1pt]
+\item The two curves must be tangent at the point of contact.
+\item The force from one part to the other must be directed along a
+  line perpendicular to the two curves at the point of contact. Call
+  this the \emph{line of action}.
+\item Let $P$ be point where the line of action intersects the line
+  connecting the two centers of rotation. This is called the
+  \emph{pitch point}. The instantaneous ratio of
+  the two rates of rotation is equal to the ratio of the distances
+  from $P$ to each of the centers of rotation.
+\end{enumerate}
+In conclusion, if two gears are to have conjugate action, then the
+pitch point must be fixed.
+
+\begin{figure}
+\begin{figput}{gearconstraints,120bp}[done,skip]
+function gearconstraints(ctx) {
+
+  // A static figure. No widgets.
+  //
+  // I wrote this before I changed the framework to assume a RH coordinates
+  // system. Instead of messing around changing the values below, each path
+  // is reflected and translated, much like a transformation matrix.
+
+  // Cam center.
+  let cax = 250;
+  let cay = 80;
+  let ra = 5;
+
+  let p = new FPath();
+  p.ellipse(cax,cay,ra,ra,0,0,2*Math.PI);
+  ctx.strokeStyle = 'black';
+  ctx.lineWidth = 0.4;
+
+  p = p.reflectX();
+  p = p.translate(new Point2D(0,120));
+  
+  ctx.stroke(p);
+
+  // Cam itself
+
+  // Right upper
+  let cs = 15; // space to right of axis
+  let h1 = 60; // height above 
+  let tan1 = 25; // tightness of tangents
+  let tan2 = 25;
+
+  p = new FPath();
+  p.moveTo(cax+cs,cay);
+  p.bezierCurveTo(cax+cs,cay - tan1,
+    cax-cs + tan2,cay-h1,
+    cax-cs,cay-h1);
+
+  // left upper
+  let h2 = 70; // how far left
+  let t1 = 20; // thickness of arm
+  tan1 = 4;
+  tan2 = 3;
+  p.bezierCurveTo(cax-cs-tan1,cay - h1,
+    cax-cs - h2,cay - h1,
+    cax-cs - h2,cay - h1 + t1);
+
+  // Lower left
+  let h3 = 40; // how far back right
+  p.bezierCurveTo(cax-cs-h2,cay - h1 + t1 + tan2,
+    cax-cs - h2,cay - h1 + 2*t1,
+    cax-cs - h2 + h3,cay - h1 + 2*t1);
+
+  // Inner concave
+  tan1 = 20;
+  tan2 = 20;
+  p.bezierCurveTo(cax-cs-h2 + h3 + tan1,cay - h1 + 2*t1,
+    cax-cs,cay - tan2,
+    cax-cs,cay);
+
+  // lower left below
+  tan1 = 8;
+  tan2 = 8;
+  p.bezierCurveTo(cax-cs,cay + tan1,
+    cax-tan2,cay + cs,
+    cax,cay+cs);
+
+  // lower right below
+  // BUG: It's hard to get these curves to meet smoothly. Need a better 'close'.
+  tan1 = 17;
+  tan2 = 10;
+  p.bezierCurveTo(cax + tan1,cay + cs,
+    cax + cs,cay - tan2,
+    cax + cs,cay);
+
+  ctx.lineWidth = 2.0;
+
+  p = p.reflectX();
+  p = p.translate(new Point2D(0,120));
+  
+  ctx.stroke(p);
+
+  // Now something similar for the long arm.
+  // The easiest way to do this is to draw it horizontal, but rotate all the
+  // points by some angle so that the arm touches the cam.
+  cax = 30
+  cay = 100;
+  
+  p = new FPath();
+  p.ellipse(cax,cay,ra,ra,0,0,2*Math.PI);
+  ctx.strokeStyle = 'black';
+  ctx.lineWidth = 0.4;
+
+  p = p.reflectX();
+  p = p.translate(new Point2D(0,120));
+
+  ctx.stroke(p);
+
+  // top right
+  cs = 12; // half thickness
+  let L = 150; // length
+
+  p = new FPath();
+  tan1 = 10;
+  tan2 = 10;
+  p.moveTo(cax,cay + cs);
+  p.bezierCurveTo(cax + tan1,cay + cs,
+    cax + L - tan2,cay +cs,
+    cax + L,cay + cs);
+
+  // lower right
+  tan1 = 6;
+  tan2 = 6;
+  p.bezierCurveTo(cax + L + tan1,cay +cs,
+    cax + L + cs,cay + tan2,
+    cax + L + cs,cay);
+
+  // upper right
+  p.bezierCurveTo(cax + L + cs,cay - tan1,
+    cax + L + tan2,cay - cs,
+    cax + L,cay - cs);
+
+  // top
+  p.bezierCurveTo(cax + L - tan1,cay - cs,
+    cax + tan2,cay - cs,
+    cax,cay - cs);
+
+  // upper left
+  p.bezierCurveTo(cax - tan1,cay - cs,
+    cax - cs,cay - tan2,
+    cax - cs,cay);
+
+  // lower left to close
+  p.bezierCurveTo(cax - cs,cay + tan1,
+    cax - tan2,cay + cs,
+    cax,cay + cs);
+
+  // Rotate the entire thing
+  let a = -12 * Math.PI / 180; // angle to rotate
+  let p2 = p.rotateAbout(a,new Point2D(cax,cay));
+  
+  ctx.lineWidth = 2.0;
+
+  p2 = p2.reflectX();
+  p2 = p2.translate(new Point2D(0,120));
+
+  ctx.stroke(p2);
+}
+\end{figput}
+\caption{Basic Constraints on Gears}
+\label{fig-basic-gear-constraints}
+\end{figure}
+
+See Figure (\ref{fig-basic-involute}). 
+Imagine a string wrapped around the circle, with one end fixed to the
+circle and a pencil at the other end. As the string unwraps from the
+circle, the pencil traces out a 
+curve called the involute. The line determined by the string is
+obviously tangent to the circle at the point at which it meets the circle. The
+line is also perpendicular to the involute because, at each
+instantaneous point of rotation, the involute is locally an arc of the
+circle formed by the string. For a circle of radius $r$ centered at the
+origin, the involute can be parameterized by $i(t)=(i_x(t),i_y(t))$, where
+\begin{eqnarray*}
+i_x(t) &=& r (\cos t + t \sin t) \\
+i_y(t) &=& r (\sin t - t \cos t)
+\end{eqnarray*}
+As we will see, the notable thing about the involute is that when gear
+teeth take the form of an involute, the pitch point is constant
+throughout the gears' motion. 
+
+\begin{figure}[b!]
+\begin{figput}{basicinvolute,140bp}[done,skip]
+// An extra function to define the involute.
+function invo(t) {
+  
+  // Basically, if you have a circle of radius a, the parametric form is
+  // x(t) = a (cos t + t sin t)
+  // y(t) = a (sin t - t cos t)
+  // The parameterization starts with t = 0, then runs as an angle in radians.
+
+  // These values copied from below.
+  let cx = 160;
+  let cy = 52;
+  let a = 50;
+
+  let c = Math.cos(t);
+  let s = Math.sin(t);
+
+  return new Point2D( cx + a*(c + t*s), cy + a*(s - t*c));  
+}
+
+function basicinvolute(ctx) {
+
+  // A looping animation that draws an involute. The string unwraps
+  // and re-wraps in a loop. Note the doubling of numSteps since I
+  // want back-and-forth action.
+  let numSteps = 100;
+  let loopw = LoopAnimWidget.register(ctx,-30,55,0.85,
+  true, // visible
+  2*numSteps, // steps per loop
+  0, // starting step
+  20, // ms time step
+  //false,false,false,false,false, // nothing is visible
+  true,true,true,true,true, // Everything visible
+  'loop');
+
+  let cx = 160;
+  let cy = 52;
+  let r = 50;
+
+  // circle
+  let p = new FPath();
+  p.ellipse(cx,cy,r,r,0,0,2*Math.PI);
+  ctx.strokeStyle = 'black';
+  ctx.lineWidth = 0.4;
+  ctx.stroke(p);
+
+  // And a dot at the center.
+  p = new FPath();
+  p.ellipse(cx,cy,2,2,0,0,2*Math.PI);
+  ctx.fillStyle = 'black';
+  ctx.fill(p);
+
+  // Draw the involute by converting to a bezier.
+  // The level of ``unwrap'' is determined by the number of steps of
+  // the animation.
+  let t = 2 * Math.abs((loopw.curStep - numSteps) / numSteps);  
+  let segs = Math.ceil(15 * t);
+  p = FPath.parametricToBezier(invo,0,t,segs);
+  ctx.lineWidth = 1.2;
+  ctx.stroke(p);
+
+  // The string goes from the end of the involute to a point tangent
+  // to the circle. So, I have a circle centered at
+  // (c_x,c_y) and a point p = (p_x,p_y) = end-point of involute, and
+  // I want the point on the circle such that the line from the point on
+  // the circle to p is tangent to the circle. The circle is parameterized
+  // by (c_x,c_y) + r(cos a,sin a), (a varies) so the tangent to the circle is
+  // parameterized by r(-sin a,cos a). I need such a tangent vector that points
+  // to p. Let t(a) = r(-sin a,cos a) and c(a) = r(cos a,sin a). I need to
+  // find a such that c(a) + s t(s) = p, for some s. Thus, I need to solve
+  // (c_x + r cos a - s r sin a,c_y + r sin a + s r cos a) = (p_x,p_y)
+  // for a and s (although I don't really care about s). We have
+  // c_x + r cos a - s r sin a = p_x implies
+  // s = ( c_x + r cos a - p_x) / r sin a
+  // Plugging into the other coordinate, we get
+  // p_y = c_y + r sin a + s r cos a
+  // p_y = c_y + r sin a + r cos a ( c_x + r cos a - p_x) / r sin a
+  // p_y = c_y + r sin a + cos a ( c_x + r cos a - p_x) / sin a
+  //
+  // BLAH. That is a mess. Easier is to do it by construction.
+  // We have a circle centered at C and a point P. Let D be the midpoint
+  // of line line CP. The circle about D passing through C and P meets the
+  // circle around C at two points, E and F. The line from C to E (or to F)
+  // is a right angle since the angle is ``inscribed'' in the circle about D.
+  // This is a general fact, that if you take two points that are opposite
+  // each other in a circle (C and P in my example) and *any* other point
+  // on that circle, then the angle formed by the two opposite points and
+  // that other point is a right angle.
+  // If that is a right angle, then the line from P to E (or to F) is tangent
+  // to the circle.
+  //
+  // Moral of the story...We have circle centered at (c_x,c_y) and p=(p_x,p_y),
+  // the end-point of involute. The line from p tangent to the circle is
+  // obtained by defining d=(d_x,d_y) as the midpoint of c and p. The
+  // intersection of the circle around d with the circle around c is the
+  // point in question.
+  //
+  // I've reduced to the problem of finding the points of intersection of two
+  // circles. We have
+  // (x-c_x)^2 + (y-c_y)^2 = r_c^2
+  // (x-d_x)^2 + (y-d_y)^2 = r_d^2
+  // Subtract the second from the first to obtain
+  // (x-c_x)^2 - (x-d_x)^2 + (y-c_y)^2 - (y-d_y)^2 = r_c^2 - r_d^2
+  // Expand and collect:
+  // x^2-2xc_x+c_x^2 - x^2+2xd_x-d_x^2 + y^2-2yc_y+c_y^2 - y^2+2yd_y-d_y^2 =
+  //     r_c^2 - r_d^2
+  // -2xc_x+c_x^2 +2xd_x-d_x^2 - 2yc_y+c_y^2 +2yd_y-d_y^2 = r_c^2 - r_d^2
+  // 2x(d_x-c_x) + 2y(d_y-c_y) + c_x^2 -d_x^2 +c_y^2 -d_y^2 = r_c^2 - r_d^2
+  // 2x(d_x-c_x) + 2y(d_y-c_y) = (r_c^2-r_d^2) + (c_x^2-d_x^2) + (c_y^2 -d_y^2)
+  // Solve for y (say):
+  // y = x(c_x-d_x) / 2(d_y-c_y) +
+  //    [ (r_c^2-r_d^2) + (c_x^2-d_x^2) + (c_y^2 -d_y^2) ] / 2(d_y-c_y)
+  // and plug this back into the original equation for the circle and you
+  // can solve for x. First, write the above eqn for y as
+  // y = x(c_x-d_x) / D + r_m / D
+  //   = [ x(c_x-d_x) + r_m ] / D
+  // where r_m means ``r-mess'' and D is for ``denominator.''
+  // (x-c_x)^2 + (y-c_y)^2 = r_c^2
+  // (x-c_x)^2 + [ ( x(c_x-d_x)+ r_m ) / D - c_y ]^2 = r_c^2
+  // (x-c_x)^2 + ( x(c_x-d_x)+ r_m )^2 / D^2 - c_y ]^2 = r_c^2
+  // Etc. In theory, this is a quadratic in x, but wow.
+  //
+  // That is another mess. Back up a bit, and consider the general case
+  // of the intersection of two circles, c and d.
+  // Let D = distance between centers and P be the point of intersection.
+  // Draw a line between the centers and two triangles, one from center c to
+  // P and then perpendicular to the line betwene centers, and the other
+  // triangle similar, but in circle d. Let E be the point where the
+  // perpendicular leg of the triangles intersects the line between centers.
+  // We have distances a and b, a from center of C to E, and b from center
+  // of d to E. Let h be the height of this perpendicular leg. We have
+  // D = a + b, a^2 + h^2 = r_c^2 and b^2 + h^2 = r_d^2. Solve for a and b.
+  // This is really the same is the big messy thing, but easier to follow.
+  //
+  // FORGET ABOUT THE ABOVE. THIS IS THE WAY TO DO IT.
+  // Back way up to the very begining and reconsider the whole thing with
+  // simpler assuptions. Suppose that the circle is centered at the origin,
+  // so we can ignore (c_x,c_y). Assume also that the point is on the
+  // x-axis so that p = (p_x,p_y) = (p_x,0). Now the circle is
+  // C(a) = r (cos a, sin a)
+  // C'(a) = r (-sin a, cos a).
+  // We want the line through C(a) pointing in the C'(a) direction to
+  // pass through p. That is, we require a solution (in t and a) to
+  // C(a) + t C'(a) = p
+  // r cos a - r t sin a = p_x and r sin a + r t cos a = 0.
+  // So t = - sin a / cos a = - tan a. Then
+  // r cos a + r sin^2 a / cos a = p_x
+  // r cos^2a + r sin^2 a = p_x cos a
+  // r = p_x cos a
+  // THAT we can solve for a. We get this solution, but then have to shift
+  // and rotate. Rotate the entire plane by the angle that p is relative to
+  // the x-axis. Then shift to move the origin of the circle to (c_x,c_y).
+  //
+  // BUG: This entire mess belongs in some geometry module, preferably with
+  // a complete discussion of the math.
+
+  let P = invo(t);
+
+  // This is p_x in the analysis above.
+  let Pd = Math.sqrt((P.x - cx)**2 + (P.y - cy)**2);
+
+  // There are two possible solutions for r = p_x cos a or
+  let a = Math.acos(r/Pd);
+
+  // Now have a solution that's valid for P on the x-axis. Rotate (Pd,0) to P.
+  // This has the effect of rotating C(a) (with the a just determined this
+  // would be the tangent point if P were on the x-axis and C were centered
+  // at the origin) through an angle b, determined by tan b = P_x/P_y.
+  // But we want this relative to (cx,cy), so shift.
+  let b = Math.atan2(P.y-cy,P.x-cx);
+
+  // The point we want is now C(a+b), then translated by (cx,cy).
+  let E = new Point2D(r*Math.cos(a+b)+cx,r*Math.sin(a+b)+cy);
+  
+  p = new FPath();
+  p.moveTo(P.x,P.y);
+  p.lineTo(E.x,E.y);
+  ctx.lineWidth = 0.8;
+  ctx.stroke(p);
+
+}
+\end{figput}
+\caption{The Involute of a Circle}
+\label{fig-basic-involute}
+\end{figure}
+
+Figure (\ref{fig-constant-pp}) shows two disks acting as gears by
+simple friction. The circle of each such disk is 
+called the \emph{pitch circle} (where they come in contact is the
+pitch point). The centers of these disks are joined 
+by the \emph{line of centers}, and the distance between these centers
+is the \emph{center distance}. Now imagine two slightly smaller and
+concentric circles, called the \emph{base circles}. These base circles
+will be used to form involutes, and these involutes will be the
+profiles of the gear teeth.
+
+
+\begin{figure}
+\begin{figput}{constpp,140bp}[done,skip]
+function constpp(ctx) {
+
+  // A static figure, no interaction.
+  let rc = 60;
+  let rd = 40;
+  let y = 70;
+  
+  let c = new Point2D(100,y);
+  let d = new Point2D(c.x + rc+rd,y);
+
+  // Pitch circles
+  let p = new FPath();
+  p.ellipse(c.x,c.y,rc,rc,0,0,2*Math.PI);
+  ctx.strokeStyle = 'black';
+  ctx.lineWidth = 1.5;
+  ctx.stroke(p);
+
+  p = new FPath();
+  p.ellipse(d.x,d.y,rd,rd,0,0,2*Math.PI);
+  ctx.strokeStyle = 'black';
+  ctx.lineWidth = 1.5;
+  ctx.stroke(p);
+
+  // Base circles
+  let s = 0.80;
+  p = new FPath();
+  p.ellipse(c.x,c.y,s*rc,s*rc,0,0,2*Math.PI);
+  ctx.strokeStyle = 'black';
+  ctx.lineWidth = 0.4;
+  ctx.stroke(p);
+
+  p = new FPath();
+  p.ellipse(d.x,d.y,s*rd,s*rd,0,0,2*Math.PI);
+  ctx.strokeStyle = 'black';
+  ctx.lineWidth = 0.4;
+  ctx.stroke(p);
+
+  ctx.font = '10px san-serif';
+  ctx.fillStyle = 'black';
+  
+  drawText(ctx,'base circle', c.x,c.y,-4,0);
+  drawText(ctx,'pitch circle', d.x,c.y+rd+6,0,0);
+}
+\end{figput}
+\caption{Base Circle and Pitch Circle}
+\label{fig-constant-pp}
+\end{figure}
+
+
+\begin{figure}[b!]
+\begin{figput}{moveinvo,200bp}[done,skip]
+// At one point, I was making a small manual adjustment on the figure
+// placement here. I did this by wrapping all the drawing
+// (after the \useasbounding box) with
+// \begin{scope}[shift={(40bp,0bp)}]
+// then \end{scope} just before \end{tikzpicture}
+  
+function moveinvo(ctx) {
+
+  // Similar to above, but don't draw the pitch circles, and only a part
+  // of the base circles is drawn, and they're larger. There is also
+  // a line for the line of action and an animation to show what the
+  // point of contact does over time. OK, so not that similar!
+
+  let numSteps = 1000;
+  let loopw = LoopAnimWidget.register(ctx,-80,100,1.0,
+    true, // not hidden
+    numSteps, // steps per loop
+    0, // starting step
+    10, // ms time step
+    true,true,true,true,true,
+    'loop');
+
+  let rc = 80;
+  let rd = 60;
+  let y = 100;
+  let s = 35;
+  
+  let c = new Point2D(90,y);
+  let d = new Point2D(c.x + rc+rd +s,y);
+
+  // Base circles
+  p = new FPath();
+
+  // I played around, trying to show only portions of the disks so as to
+  // save space, but it doesn't look right. In some ways, that
+  // simplifies things.
+  p.ellipse(c.x,c.y,rc,rc,0,0,2*Math.PI);
+  ctx.strokeStyle = 'black';
+  ctx.lineWidth = 1.0;
+  ctx.stroke(p);
+  
+  p = new FPath();
+  p.ellipse(d.x,d.y,rd,rd,0,0,2*Math.PI);
+  ctx.strokeStyle = 'black';
+  ctx.lineWidth = 1.0;
+  ctx.stroke(p);
+
+  /* I was going to just draw these arcs, but better to do the
+  // whole cirles.
+  //In fact, defer drawing this. I want the entire wedge to turn.
+  // This arc is centered at (0,0).
+  let cVisAngle = 4*Math.PI/8;
+  p = FPath.arcToBezierNEW(rc,-cVisAngle,cVisAngle);
+  p = p.translate(c);
+  ctx.lineWidth = 2.0;
+  ctx.stroke(p);
+  
+  let dVisAngle = 5*Math.PI/8;
+  p = FPath.arcToBezierNEW(rd,dVisAngle,-dVisAngle);
+  p = p.translate(d);
+  ctx.lineWidth = 2.0;
+  ctx.stroke(p);
+  */
+
+  // The line of action.
+  // This involves another calculation of tangent lines. See Graphics Gems I,
+  // p. 7 and Figure 8. Use similar triangles. We have two distances,
+  // x_c and x_d from the respective centers of the circles to the point
+  // where the desired line intersects the line connecting the centers.
+  // We have x_c + x_d = D = distance between centers, and by
+  // similar triangles r_c/x_c = r_d/x_d. A little algebra gives
+  // x_c = r_c D / (r_c + r_d).
+  //
+  // We now have one point that must be on the line, and we go through the
+  // same rigmarole as above to find the line tangent to a circle. The only
+  // difference is that we've chosen the point through which the circle must
+  // pass in such a way that the resulting line will be tangent to both
+  // circles if it's tangent to either of them.
+  //
+  // As above, make the simplifying assumption that circle C is centered
+  // at the origin. Then do a rotate and translate at the end.
+  let D = Math.sqrt((c.x-d.x)**2 + (c.y-d.y)**2);
+  let xc = rc * D / (rc + rd);
+
+  // We are working (for now) as though circle C is centered at the origin.
+  // So this is the point we want.
+  let M = new Point2D(xc,0);
+
+  // As in the earlier case, where I did the involute, we get the tangent.
+  // The difference is that the point is now M, not P, as it was above.
+  let Md = Math.sqrt((M.x - c.x)**2 + (M.y - c.y)**2);
+  let a = Math.acos(rc/Md);
+  let b = Math.atan2(M.y,M.x);
+  let E = new Point2D(rc*Math.cos(-a+b)+c.x,rc*Math.sin(-a+b)+c.y);
+  
+  // The above draws from circle C to the central point M, but I need to
+  // extend the line all the way to the other circle. So I need to know where
+  // this line intersects that circle. Recall that M was found by similar
+  // triangles. The angle of the tangent point relative to the circles' centers
+  // is the same in both cases, although for the circle on the right, we
+  // have to adjust by pi.
+  b += Math.PI;
+  let F = new Point2D(rd*Math.cos(-a+b)+d.x,rd*Math.sin(-a+b)+d.y);
+
+  p = new FPath();
+  p.moveTo(E.x,E.y);
+  p.lineTo(F.x,F.y);
+  ctx.lineWidth = 0.6;
+  ctx.stroke(p);
+  
+  // The above draws the more or less static setup. Now I want to draw a
+  // particular point on the line of action, and let it move as the disks
+  // rotate, tracing out a pair of involutes.
+  //
+  // Use M for the particular point along the line, which is detemined
+  // by t, using a linear parameterization of the line E to F.
+  // This value is what determines the frame of the animation.
+  let t;
+  if (loopw.curStep < numSteps/2)
+    t = 2* loopw.curStep/numSteps;
+  else
+    t = 2 *(numSteps - loopw.curStep)/numSteps;
+  
+  M = new Point2D(E.x + t*(F.x-E.x),E.y + t*(F.y-E.y));
+
+  p = new FPath();
+  p.ellipse(M.x,M.y,1.5,1.5,0,0,2*Math.PI);
+  ctx.fillStyle = 'black';
+  ctx.fill(p);
+
+  // I need to know the total size of the tooth. So I need the value for
+  // t at which the tooth will barely clear the opposing gear. The value
+  // I am looking for has nothing to do with the current point of contact,
+  // and is always the same (which is sort of the point). Scale down the
+  // entire picture and find t for which the distance of involute(t) from
+  // the center of the left disk is equal to the distance between the
+  // edges of the two disks.
+  //
+  // BUG: A common problem is that lines have thickness. If you want line A
+  // to barely touch line B, then thicknesses matter. The strictly correct way
+  // to deal with this is probably to treat lines as filled rectangles (or
+  // quadrilaterals more generally). This general philisophy is one way to
+  // handle stuff like arrowheads. Another way might be to allow stroking
+  // the line on one side of its geometric definition or the other.
+  // I may have mentioned this issue before.
+  // 
+  // See above. rc and rd are the two disks' radii and the centers at c and d.
+  // The distance we care about is d.x-c.x-rd before scaling. Subtract off
+  // a hair to take into account line thicknesses. Scaling then gives:
+  let toothD = (d.x-c.x-rd - 2) / rc;
+
+  // And the value that brings the unit involute out to this distance.
+  let toothT = Numerical.newton(solveToothD,0.5,0,3,toothD,0.00001);
+
+  // For circle C, we have an involute extending out to M.
+  // The standard parameterization of the involute assumes that the point
+  // starts at the x-axis, and that is not true here. The ``point of initial
+  // contact'' with the base circle varies, and that is sort of the point
+  // for gear design. At any rate, the usual parameterization is
+  // x(a) = r (cos a + a sin a)
+  // y(a) = r (sin a - t cos a)
+  // What we need to do is to add some constant to a so as to shift
+  // the involute -- effectively rotate it around the center of the circle.
+  //
+  // The distance from M to E is how much string wraps around the circle C.
+  // This determines the point of initial contact. Let d_M = |M-E|.
+  // When wrapped around the circle, this corresponds to an angle d_M/r_c. 
+  // It wraps from the point E, and that point is at angle -a+b relative to
+  // the x-axis. So the adjustment we need to make is a_M = d_M/r_c +a-b.
+  // There's also a pi adjustment due to LH coordinates.
+  //
+  // In addition, we need to know at what value of a (as argument to the
+  // parameterization) the involute reaches M. THAT is not so easy since it
+  // amounts to inverting the involute. We want to find t such that
+  // involute(t) = M, where M is the point in question. Assuming that (u,v)
+  // is on the involute, and considering the ``standard'' involute, what
+  // we want is t such that
+  // u = cos t + t sin t
+  // v = sin t - t cos t
+  // I don't think there's any good way to do this, and a bit of googling
+  // bears that out. I'm not going to try to be mathematically clever.
+  // Just use Newton's method. So, take the point, M, and "undo" the
+  // transformation to get M relative to the standard involute -- I mean for
+  // a unit circle at the origin.
+  let dM = Math.sqrt((M.x-E.x)**2 + (M.y-E.y)**2);
+  let aM = dM/rc - a + b - Math.PI;
+
+  // Untranslate, unscale and unrotate M.
+  // BUG: This foolishness is why I should have worked with the standard unit
+  // involute throughout. 
+  let unitM = new Point2D(M.x - c.x,M.y-c.y);
+  unitM = new Point2D(unitM.x/rc,unitM.y/rc);
+  unitM.rotateSelf(-aM);
+
+  // Now I want t such that invo2(t).x = unitM.x. I'm using x instead of
+  // y since y varies very little near the circle and I'm afraid that
+  // the root finder won't converge well.
+  // Note that t = 3 is roughly where the derivative changes sign.
+  // That's why it's a good place for bracketing.
+  t = Numerical.newton(solveInvo,0.5,0,3,unitM.x,0.00001);
+
+  // However, we do NOT want to use a value for t larger than toothT
+  // since the tooth would make the tooth magically grow to touch M.
+  if (t > toothT) t = toothT;
+  
+  p = FPath.parametricToBezier(invo2,0,t,30);
+  p = p.rotate(aM);
+  p = p.scale(rc);
+  p = p.translate(c);
+
+  ctx.lineWidth = 1.0;
+  ctx.stroke(p);
+
+  // Now, exactly as above, draw a bit of the involute.
+  p = FPath.parametricToBezier(invo2,t,toothT,30);
+  p = p.rotate(aM);
+  p = p.scale(rc);
+  p = p.translate(c);
+  
+  ctx.lineWidth = 0.4;
+  ctx.stroke(p);
+  
+  // And...what the heck... some spokes to make the rotation
+  // more noticable.
+  p = new FPath();
+  p.moveTo(c.x,c.y);
+  let sp = new Point2D(c.x+rc,c.y);
+  sp = sp.rotateAbout(c,aM);
+  p.lineTo(sp.x,sp.y);
+  ctx.lineWidth = 0.4;
+  ctx.stroke(p);
+
+  // let wedgeRange = cVisAngle / 4;
+  let wedgeRange = Math.PI / 6;
+  for (let i = 0; i < 10; i++)
+    {
+      let a = aM + i*wedgeRange;
+      //if ((a <= cVisAngle) && (a >= -cVisAngle))
+        {
+          p = new FPath();
+          p.moveTo(c.x,c.y);
+          let sp = new Point2D(c.x+rc,c.y);
+          sp = sp.rotateAbout(c,a);
+          p.lineTo(sp.x,sp.y);
+          ctx.lineWidth = 0.4;
+          ctx.stroke(p);
+        }
+
+      a = aM - i*wedgeRange;
+      //if ((a <= cVisAngle) && (a >= -cVisAngle))
+        {
+          p = new FPath();
+          p.moveTo(c.x,c.y);
+          let sp = new Point2D(c.x+rc,c.y);
+          sp = sp.rotateAbout(c,a);
+          p.lineTo(sp.x,sp.y);
+          ctx.lineWidth = 0.4;
+          ctx.stroke(p);
+        }
+    }
+
+  // Now we have to do almost the same thing, but for the right disk.
+  // The twist is that the involute is now flipped relative to the
+  // earlier case because the right disk rotates in the opposite direction.
+  // That is, swap the sign of the y-coordinate, and the x-coordinate too
+  // since the disk is on the right.
+  //
+  // The tooth height is the same on the right side, but the scale is different,
+  // so the value of toothT will be different.
+  toothD = (d.x-c.x-rc - 2) / rd;
+  toothT = Numerical.newton(solveToothD,0.5,0,3,toothD,0.00001);
+  
+  // What we want is for the flipped involute to pass through M, although
+  // it will pass through M at a different value for t. I could work out
+  // this t by finding it numerically. Or, I could use the fact that --
+  // because I know how gears work -- the relative rates of rotion are known.
+  // In fact, because I want the line to change at M, I do need this value
+  // for t. This is more like what happens physically: the motion of the
+  // left disk determines M, which pushes the disk on the right to rotate.
+  //
+  // Redetermine unitM, as above, but relative to the right disk.
+  // Do it afresh to avoid any rounding error.
+  dM = Math.sqrt((M.x-F.x)**2 + (M.y-F.y)**2);
+  aM = dM/rd - a + b - Math.PI;
+  unitM = new Point2D(d.x-M.x ,d.y-M.y);
+  unitM = new Point2D(unitM.x/rd,unitM.y/rd);
+  unitM.rotateSelf(-aM);
+
+  // This is the value for t at which the RH involute passes through M.
+  t = Numerical.newton(solveInvo,0.5,0,3,unitM.x,0.00001);
+  if (t > toothT) t = toothT;
+
+  // Path from disk to M
+  p = FPath.parametricToBezier(invo2,0,t,30);
+  p = p.reflectXY();
+  p = p.rotate(aM);
+  p = p.scale(rd);
+  p = p.translate(d);
+  
+  ctx.lineWidth = 1.0;
+  ctx.stroke(p);
+
+  // Path from M to the tip of the tooth.
+  p = FPath.parametricToBezier(invo2,t,toothT,30);
+  p = p.reflectXY();
+  p = p.rotate(aM);
+  p = p.scale(rd);
+  p = p.translate(d);
+  
+  ctx.lineWidth = 0.4;
+  ctx.stroke(p);
+
+  // And some spokes for visual appeal, as above.
+  // The outer arc first.
+  /*
+  dVisAngle = 5*Math.PI/8;
+  p = FPath.arcToBezier(rd,dVisAngle,-dVisAngle);
+  p = p.rotate(aM);
+  p = p.translate(d);
+  ctx.lineWidth = 2.0;
+  ctx.stroke(p);
+  */
+  
+  // And the spokes.
+  p = new FPath();
+  p.moveTo(d.x,d.y);
+  sp = new Point2D(d.x-rd,d.y);
+  sp = sp.rotateAbout(d,aM);
+  p.lineTo(sp.x,sp.y);
+  ctx.lineWidth = 0.4;
+  ctx.stroke(p);
+
+  // In fact, the angle *spanned* by the arc is two times this.
+  // It's because of the whole LH/RH thing.
+  for (let i = 0; i < 7; i++)
+    {
+      let a = aM + i*wedgeRange;
+      //if ((a <= dVisAngle) && (a >= -dVisAngle))
+        {
+          p = new FPath();
+          p.moveTo(d.x,d.y);
+          let sp = new Point2D(d.x-rd,d.y);
+          sp = sp.rotateAbout(d,a);
+          //sp.x = d.x - (sp.x - d.x);
+          p.lineTo(sp.x,sp.y);
+          ctx.lineWidth = 0.4;
+          ctx.stroke(p);
+        }
+
+      a = aM - i*wedgeRange;
+      p = new FPath();
+      p.moveTo(d.x,d.y);
+      let sp = new Point2D(d.x-rd,d.y);
+      sp = sp.rotateAbout(d,a);
+      p.lineTo(sp.x,sp.y);
+      ctx.lineWidth = 0.4;
+      ctx.stroke(p);
+    }
+}
+
+function solveToothD(t) {
+  let p = invo2(t);
+  return Math.sqrt(p.x**2 + p.y**2);
+}
+
+function solveInvo(t) {
+  return invo2(t).x;
+}
+
+function invo2(t) {
+
+  // Involute, assuming circle of radius 1 centered at the origin.
+  // There is another function called invo(), hence this is invo2().
+  // BUG: This is the way I should have done this above. Generate a standard
+  // involute, then scale and rotate as needed.
+  let c = Math.cos(t);
+  let s = Math.sin(t);
+
+  // Note that y is backwards since LH coordinate system.
+  return new Point2D( c + t*s , - (s - t*c) );
+}
+\end{figput}
+\caption{Rotation Traces Involutes}
+\label{fig-moving-involute}
+\end{figure}
+
+
+Figure (\ref{fig-moving-involute}) shows an enlarged view of the two
+base circles of Figure (\ref{fig-constant-pp}), without the pitch
+circles. Imagine that a piece of string is tightly
+wrapped around one base circle, extends over to the other base circle,
+and is wrapped around it too. As the disks rotate, the string unwinds
+from one base circle and is taken up by the other base circle. There
+is a fixed point on the string that represents the point of
+contact between two teeth. This point traces a path that
+is an involute relative to either circle. These involutes define the
+shape of the mating tooth profiles. The line of action is coincident
+with the string, and the two gears have conjugate action.
+
+A fortunate feature of the involute is that the teeth can be truncated at
+their perimeter, or their widths may be varied, yet the two gears
+still have conjugate action; the teeth come into contact sooner or
+later as they rotate, but the point of contact follows the same line
+of action. If the center distance changes, then the line of action
+also changes, but the tooth form (the involute) remains the same, and
+the gears still have conjugate action, though there will be some
+backlash and additional friction between the teeth.
+
+What remains is the resolution of many practical issues: the interplay
+of gear radius, tooth size, number of teeth and the
+like.
+
+The two main methods of gear specification are
+metric (ISO) and inch (AGMA), and the two systems use slightly different
+fundamental quantities to specify a given gear. These are the basic
+parameters used to specify off-the-shelf gear profiles.
+\begin{small}
+\begin{itemize}[itemsep=-1pt]
+\item $\phi$, pressure angle
+\item $N$, number of teeth
+\item $m$, module (for metric gears)
+\item $p_d$, diametral pitch (for inch gears)
+\end{itemize}
+\end{small}
+
+There are many additional terms and measurements. In fact,
+off-the-shelf gears are typically specified in a way that makes
+various assumptions. Additional parameters that influence 
+gear design are 
+\begin{small}
+\begin{itemize}[itemsep=-1pt]
+\item $p_c$, circular pitch
+\item $d$, pitch diameter
+\item $r_p$, pitch radius
+\item $r_b$, base radius
+\item $a$, addendum
+\item $b$, dedendum
+%\item $C$, center distance
+%\item $r$, pitch radius
+\end{itemize}
+\end{small}
+
+The \emph{pressure angle}, $\phi$, is the angle between the line of
+action and the perpendicular to the line of centers. In Figure
+(\ref{fig-moving-involute}), the pressure angle is roughly $35^\circ$.
+If two gears are to mesh without backlash, then they must use the same
+pressure angle. At one time, $14.5^\circ$ was a commonly used pressure
+angle, but $20^\circ$ is the current standard.
+A more obviously important choice is the number of teeth, $N$. Since
+the number of teeth determines the ratio of any gear train, this is a crucial
+choice, but it raises the question of how to fit $N$ teeth on a given
+gear.
+
+The tooth-to-tooth distance, as measured along the arc of the pitch
+circle, is the \emph{circular pitch}, $p_c$, and the corresponding
+diameter is the \emph{pitch diameter}, $d$. Since $N p_c$ is the
+circumference of the pitch circle, we have
+$$p_c = {\pi d\over N}.$$
+This is the inches or mm per tooth, measured along the circumerence. In
+practice, AGMA gears are specified by the \emph{diametral pitch}, 
+$$p_d = {N\over d}.$$
+This is the teeth per $\pi$ inches, and seems like an odd
+choice, but that's how it's done.
+Metric gears are specified by their \emph{module}, $m$, which is
+stated in millimeters, and is
+$$m = {d\over N} = {1\over p_d}.$$
+The actual tooth-to-tooth distance is thus $\pi m$. 
+The values around which the two systems, ISO and AGMA,
+are standardized are not compatible. For example, a module of $m=4$
+corresponds to a diametral pitch of
+$$p_d = {25.4\over 4} = 6.35,$$
+which is not a standard AGMA size.
+
+The profile of each gear tooth is an involute, and determining the
+involute requires that the base circle be known. See Figure
+(\ref{fig-base-from-pitch}), in which the outer circle is the pitch circle and
+the inner circle is the base circle. Let $r_p$ be the radius of the
+pitch circle, and $r_b$ be the radius of the base circle. Because the
+angle determined by where the line of action meets the base circle is
+equal to the pressure angle, $\phi$, we have
+$$r_b = r_p \cos\phi.$$
+
+\begin{figure}[b!]
+\begin{figput}{baseandpitch,175bp}[done,skip]
+function baseandpitch(ctx) {
+
+  // A static figure, no interaction.
+  let rc = 70;
+  let y = 80;
+
+  let c = new Point2D(130,y);
+
+  // Pitch circle
+  let p = new FPath();
+  p.ellipse(c.x,c.y,rc,rc,0,0,2*Math.PI);
+  ctx.strokeStyle = 'black';
+  ctx.lineWidth = 0.4;
+  ctx.stroke(p);
+
+  // Radius through pitch point
+  let pplen = rc + 50;
+  p = new FPath();
+  p.moveTo(c.x,c.y);
+  p.lineTo(c.x+pplen,c.y);
+  ctx.stroke(p);
+  
+  // Line of action through P and angle phi. Use tan phi = dx / dy
+  // to draw a line through P = (c.x+rc,c.y).
+  let phi = Math.PI / 6;
+  let lenup = 70;
+  let lendown = 50;
+  let tan = Math.tan(phi);
+  p = new FPath();
+  p.moveTo(c.x + rc - lenup * tan,c.y + lenup);
+  p.lineTo(c.x + rc + lendown * tan,c.y - lendown);
+  ctx.stroke(p);
+  
+  // Base circle has radius:
+  let rb = rc * Math.cos(phi);
+  p = new FPath();
+  p.ellipse(c.x,c.y,rb,rb,0,0,2*Math.PI);
+  ctx.strokeStyle = 'black';
+  ctx.lineWidth = 0.4;
+  ctx.stroke(p);
+
+  // Vertical line through P.
+  let vlen = 60;
+  p = new FPath();
+  p.moveTo(c.x+rc,c.y-vlen);
+  p.lineTo(c.x+rc,c.y+vlen);
+  ctx.stroke(p);
+
+  // radial line to where line of action meets base circle.
+  p = new FPath();
+  p.moveTo(c.x,c.y);
+  p.lineTo(c.x + rb*Math.cos(phi),c.y+rb*Math.sin(phi));
+  ctx.stroke(p);
+
+  // Little hash marks to indicate angles have same measure.
+  p = FPath.circArcToBezier(16,0,phi);
+  p = p.translate(c);
+  ctx.stroke(p);
+  
+  p = FPath.circArcToBezier(16,Math.PI/2 - phi,Math.PI/2);
+  p = p.reflectX();
+  p = p.translate(new Point2D(c.x+rc,c.y));
+  ctx.stroke(p);
+}
+
+\end{figput}
+\caption{Base Circle from Pitch Circle}
+\label{fig-base-from-pitch}
+\end{figure}
+
+
+The module or diametral pitch determines the tooth-to-tooth distance,
+but it doesn't determine how much of that space is solid tooth and how
+much is the space between teeth. The ensure that there is no backlash,
+the thickness of each tooth, as measured along the arc of the pitch
+circle, should be equal to the space between teeth -- for practical
+reasons (lubrication), the gap between teeth is often made one or two 
+thousandths of an inch wider than this. Again, these distances are
+\emph{as measured along the arc of the pitch circle}. In practice, it
+is easier to work with the angles subtended by these arcs.
+
+There is one further issue to resolve. See Figure (\ref{fig-teeth-touch}),
+which shows a portion of a base circle and slightly larger pitch
+circle, with an involute. What's needed is the measure of the small
+angle relative to the $x$-axis at which the involute meets the pitch
+circle. The involute is parametrized by 
+$$i(t) = r_b(\cos t + t\sin t,\sin t - t\cos t) = (i_x(t),i_y(t)),$$
+and the involute meets the pitch circle when $|i(t)|^2 = r_p^2$. We have
+\begin{eqnarray*}
+|i(t)|^2 &=& r_b^2\left[(\cos t + t\sin t)^2 + (\sin t - t\cos t)^2\right] \\
+&=& r_b^2\left[\cos^2 t + 2t\cos t\sin t + t^2\sin^2t + 
+  \sin^2 t - 2t\cos t\sin t + t^2\cos^2 t\right] \\
+&=& r_b^2(1 + t^2),
+\end{eqnarray*}
+and $|i(t)| = r_p$ implies that
+$$t = \sqrt{\left({r_p\over r_b}\right)^2-1} = \sqrt{\left({r_p\over
+    r_p\cos\phi}\right)^2-1}\  = \tan\phi.$$
+The angle made by the line through $i(t)$ with the $x$-axis is
+$\alpha$, where\footnote{There
+  seems to be no standard notation for this angle. In fact, I have
+  found no mention of this issue in any common reference, even though it's crucial for
+  determining the profile.} 
+$$\tan\alpha = i_y(t)/i_x(t).$$
+
+\begin{figure}
+\begin{figput}{teethtouch,100bp}[done,skip]
+function teethtouch(ctx) {
+
+  let c = new Point2D(100,20);
+  let rb = 80;
+
+  // Bit of arc on the right. This is the base circle.
+  let span = Math.PI/5;
+  let p = FPath.circArcToBezier(rb,0,span);
+  //p = p.reflectX();
+  p = p.translate(c);
+  ctx.lineWidth = 1.0;
+  ctx.stroke(p);
+
+  // And a slightly larger arc for the pitch circle.
+  let rp = rb + 22;
+  p = FPath.circArcToBezier(rp,0,span);
+  //p = p.reflectX();
+  p = p.translate(c);
+  ctx.lineWidth = 0.4;
+  ctx.stroke(p);
+    
+  // Draw x-axis/radius.
+  let width = 150
+  p = new FPath();
+  p.moveTo(c.x,c.y);
+  p.lineTo(c.x+width,c.y);
+  ctx.lineWidth = 0.4;
+  ctx.stroke(p);
+  
+  // Using the earlier invo2() function for the unit involute.
+  let a = Math.PI/8;
+  let inv = FPath.parametricToBezier(invo2,0,1.5,30);
+  p = inv.reflectX();
+  //p = inv.scale(rb);
+  p = p.scale(rb);
+  p = p.translate(c);
+  ctx.stroke(p);
+
+  // And a line out to the point where the top involute meets the pitch circle.
+  p = new FPath();
+  p.moveTo(c.x,c.y);
+  let t = Math.sqrt((rp/rb)**2 - 1);
+  let q = invo2(t);
+  q = new Point2D(q.x,-q.y);
+  q = new Point2D(q.x*rb,q.y*rb);
+  q = new Point2D(q.x+c.x,q.y+c.y);
+  p.lineTo(q.x,q.y);
+  ctx.lineWidth = 0.4;
+  ctx.stroke(p);
+}
+\end{figput}
+\caption{Angle Subtended by Involutes.}
+\label{fig-teeth-touch}
+\end{figure}
+
+We now have enough information to begin laying out gear
+profiles. Suppose that $\phi$, $N$ and $m$ (or $p_d$) are given. There
+will be $N$ involutes runing one way, and $N$ running the other
+way. Relative to the base circle, the tooth-to-tooth distance subtends
+an angle measuring $2\pi/N$. Half of this is solid tooth, and half is the
+gap between teeth, with an adjustment for $\alpha$. So each solid
+tooth subtends the angle $\pi/N + 2\alpha$, and each gap
+subtends the angle $\pi/N - 2\alpha$. Figure~(\ref{fig-gear-example})
+shows the result for $\phi = 20^\circ$, $N=15$ and $m =4$. 
+
+\begin{figure}
+\begin{figput}{gearexample,120bp}[done,skip]
+function gearexample(ctx) {
+
+  // Note that I may have written this for a LH coordinate system, but
+  // it doesn't matter since it's radially symmetric.
+  
+  // Pressure angle, number of teeth and module.
+  let phi = 20 * Math.PI / 180;
+  let N = 15;
+  let m = 5;
+
+  let c = new Point2D(175,60);
+  let pitchDiam = N * m;
+
+  // Pitch radius and base radius.
+  let rp = pitchDiam / 2;
+  let rb = rp * Math.cos(phi);
+
+  ctx.lineWidth = 0.4;
+
+  // Point along parameterization where involute meets pitch circle.
+  let t = Math.tan(phi);
+
+  // Adjustment to width of the base of the teeth due to the fact that
+  // the teeth are of varying width. Note that the radius of the base circle
+  // doesn't matter.
+  let ipt = invo2(t);
+  let alpha = -Math.atan2(ipt.y,ipt.x);
+
+  ctx.lineWidth = 0.4;
+
+  // Each tooth, at the base, takes 2pi/2N + 2 alpha. The space between
+  // teeth is 2pi/2N - 2 alpha
+  //
+  // We want the x-axis to split a gap between teeth, so the first tooth
+  // starts at (pi/N - 2 alpha) / 2 = pi/2N - alpha.
+  //
+  // Using earlier function for the unit involute.
+  // Note that the angles are all backwards (reversed sign) due to LH coords.
+  
+  let basicInv = FPath.parametricToBezier(invo2,0,1,30);
+  let basicArc = FPath.circArcToBezier(rb,0,Math.PI/N - 2*alpha);
+  basicArc = basicArc.reflectX();
+
+  let angle = -Math.PI / (2*N) + alpha;
+  ctx.strokeStyle='black';
+
+  for (let i = 0; i < N; i++)
+    {
+      // One side of tooth.
+      let inv = basicInv.rotate(angle);
+      inv = inv.scale(rb);
+      inv = inv.translate(c);
+      ctx.stroke(inv);
+
+      // Other side of tooth.
+      angle -= Math.PI / N + 2 * alpha;
+      inv = basicInv.reflectX();
+      inv = inv.rotate(angle);
+      inv = inv.scale(rb);
+      inv = inv.translate(c);
+      ctx.stroke(inv);
+
+      // Gap between teeth.
+      let gap = basicArc.rotate(angle);
+      gap = gap.translate(c);
+      //ctx.strokeStyle='blue';
+      ctx.stroke(gap);
+
+      angle -= Math.PI / N - 2*alpha;
+    }    
+}
+
+\end{figput}
+\caption{Basic Gear Form.}
+\label{fig-gear-example}
+\end{figure}
+
+There is a glaring problem with Figure (\ref{fig-gear-example}): the
+involutes continue beyond the point where the two sides of each tooth
+meet. If the aim is to program a milling machine to cut these profiles,
+then that's not a big deal -- the machine will be cutting a bit of
+air beyond the end of each tooth -- but it would be nice to know
+exactly where the two sides meet. Suppose that a tooth is symmetric
+about the $x$-axis so that the two sides meet at $y=0$. Let $R_\theta$
+be the rotation matrix through angle $\theta$. Then the involute below
+the $x$-axis is parameterized by $R_{-\theta}i(t)$, where $\theta
+= \alpha + \pi/2N$. In particular, we want to find $t$ such that the
+$y$-coordinate of $R_{-\theta}i(t)$ is equal to zero. We have
+\begin{eqnarray*}
+R_{-\theta}\ i(t) &=& \pmatrix{\cos\theta&\sin\theta\cr-\sin\theta&\cos\theta}
+\pmatrix{r_b(\cos t + t\sin t)\cr r_b(\sin t - t\cos t)},
+\end{eqnarray*}
+and we require $t$ such that
+$$-r_b\sin\theta(\cos t + t\sin t) + r_b\cos\theta(\sin t - t\cos t) = 0$$
+or
+$${\sin t - t\cos t\over \cos t + t\sin t} = \tan\theta.$$
+Unfortunately, finding such $t$ requires the use of numerical methods
+of approximation. Making use of something like Newton-Raphson to
+determine $t$, we obtain Figure (\ref{fig-gear-ex-better}).
+
+\begin{figure}
+\begin{figput}{bettergear,120bp}[done,skip]
+function bettergear(ctx) {
+
+  // As above, but the teeth meet properly instead of having ``hair.''
+  
+  // Pressure angle, number of teeth and module.
+  let phi = 20 * Math.PI / 180;
+  let N = 15;
+  let m = 5;
+
+  let c = new Point2D(175,60);
+  let pitchDiam = N * m;
+
+  // Pitch radius and base radius.
+  let rp = pitchDiam / 2;
+  let rb = rp * Math.cos(phi);
+
+  ctx.lineWidth = 0.4;
+  
+  // Point along parameterization where involute meets pitch circle.
+  let t = Math.tan(phi);
+
+  // Adjustment to width of the base of the teeth due to the fact that
+  // the teeth are of varying width. Note that the radius of the base circle
+  // doesn't matter.
+  let ipt = invo2(t);
+  let alpha = -Math.atan2(ipt.y,ipt.x);
+
+  ctx.lineWidth = 0.4;
+
+  // Each tooth, at the base, takes 2pi/2N + 2 alpha. The space between
+  // teeth is 2pi/2N - 2 alpha
+  //
+  // We want the x-axis to split a gap between teeth, so the first tooth
+  // starts at (pi/N - 2 alpha) / 2 = pi/2N - alpha.
+  //
+  // Using earlier function for the unit involute.
+  // Note that the angles are all backwards (reversed sign) due to LH coords.
+  //
+  // We also solve for t so that the teeth meet as they should.
+  let targetV = Math.tan(Math.PI/(2*N) + alpha);
+  let toothT = Numerical.newton(toothMeet,0.3,0,2,targetV,0.00001);
+  
+  let basicInv = FPath.parametricToBezier(invo2,0,toothT,30);
+  let basicArc = FPath.circArcToBezier(rb,0,Math.PI/N - 2*alpha);
+  basicArc = basicArc.reflectX();
+
+  let angle = -Math.PI / (2*N) + alpha;
+  ctx.strokeStyle='black';
+
+  for (let i = 0; i < N; i++)
+    {
+      // One side of tooth.
+      let inv = basicInv.rotate(angle);
+      inv = inv.scale(rb);
+      inv = inv.translate(c);
+      ctx.stroke(inv);
+
+      // Other side of tooth.
+      angle -= Math.PI / N + 2 * alpha;
+      inv = basicInv.reflectX();
+      inv = inv.rotate(angle);
+      inv = inv.scale(rb);
+      inv = inv.translate(c);
+      ctx.stroke(inv);
+
+      // Gap between teeth.
+      let gap = basicArc.rotate(angle);
+      gap = gap.translate(c);
+      //ctx.strokeStyle='blue';
+      ctx.stroke(gap);
+
+      angle -= Math.PI / N - 2*alpha;
+    }
+}
+
+function toothMeet(t) {
+
+  // Used to solve for the t at which the two sides of a tooth meet.
+  let s = Math.sin(t);
+  let c = Math.cos(t);
+  return (s - t*c) / (c + t * s);
+}
+
+\end{figput}
+\caption{Corrected Gear Form.}
+\label{fig-gear-ex-better}
+\end{figure}
+
+Figure (\ref{fig-gear-ex-better}) still doesn't look quite
+right. Gears don't typically have such pointy-ended teeth, and the gaps
+between the teeth don't seem deep enough in Figure
+(\ref{fig-gear-ex-better}). There are two more parameters to adjust
+for this: the \emph{addendum}, $a$, and \emph{dedendum}, $b$. The
+addendum is the distance above the pitch circle to which the teeth
+extend; when a tooth reaches a radius of $r_p + a$, it is truncated
+and given a flat top (the so-called \emph{top land}). The dedendum is
+the depth below the pitch circle to which the gap between teeth is
+cut; so the gaps are cut to a radius of $r_p -b$ (forming the
+so-called \emph{bottom land}). While the parameters $a$ and $b$ could
+take any value, they have been standardized to
+$$a = m\qquad{\rm and}\qquad b = 1.25\ m.$$
+Under the AGMA system (inches), these are
+$$a = 1/p_d\qquad{\rm and}\qquad b = 1.25/p_d.$$
+Teeth have been standardized this way because the tips of pointy-ended
+teeth are prone to burring, while cutting the gaps more deeply allows
+for fuller engagement of the teeth. Figure (\ref{fig-gear-with-add-ded})
+shows the same gear as in Figure (\ref{fig-gear-ex-better}), but with
+the addendum and dedendum circles.
+
+\begin{figure}[b!]
+\begin{figput}{gearaddded,120bp}[done,skip]
+function gearaddded(ctx) {
+
+  // As above, but with (or without when interactive) the various circles.
+  
+  // A button for show/hide the extra circles.
+  let wbut = ButtonWidget.register(ctx,-80,10,'Show/Hide','but');
+  
+  // Pressure angle, number of teeth and module.
+  let phi = 20 * Math.PI / 180;
+  let N = 15;
+  let m = 5;
+
+  let c = new Point2D(175,60);
+  let pitchDiam = N * m;
+
+  // Pitch radius and base radius.
+  let rp = pitchDiam / 2;
+  let rb = rp * Math.cos(phi);
+
+  ctx.lineWidth = 0.4;
+
+  if (wbut.clickState === true)
+    {
+      // Pitch circle.
+      p = new FPath();
+      p.ellipse(c.x,c.y,rp,rp,0,0,2*Math.PI);
+      ctx.stroke(p);
+
+      // Addendum
+      radd = rp + m;
+      p = new FPath();
+      p.ellipse(c.x,c.y,radd,radd,0,0,2*Math.PI);
+      ctx.stroke(p);
+
+      // Dedendum
+      rded = rp - 1.25* m;
+      p = new FPath();
+      p.ellipse(c.x,c.y,rded,rded,0,0,2*Math.PI);
+      ctx.stroke(p);
+    }
+
+
+  // Point along parameterization where involute meets pitch circle.
+  let t = Math.tan(phi);
+
+  // Adjustment to width of the base of the teeth due to the fact that
+  // the teeth are of varying width. Note that the radius of the base circle
+  // doesn't matter.
+  let ipt = invo2(t);
+  let alpha = -Math.atan2(ipt.y,ipt.x);
+
+  ctx.lineWidth = 0.4;
+
+  // Each tooth, at the base, takes 2pi/2N + 2 alpha. The space between
+  // teeth is 2pi/2N - 2 alpha
+  //
+  // We want the x-axis to split a gap between teeth, so the first tooth
+  // starts at (pi/N - 2 alpha) / 2 = pi/2N - alpha.
+  //
+  // Using earlier function for the unit involute.
+  // Note that the angles are all backwards (reversed sign) due to LH coords.
+  //
+  // We also solve for t so that the teeth meet as they should.
+  let targetV = Math.tan(Math.PI/(2*N) + alpha);
+  let toothT = Numerical.newton(toothMeet,0.3,0,2,targetV,0.00001);
+  
+  let basicInv = FPath.parametricToBezier(invo2,0,toothT,30);
+  let basicArc = FPath.circArcToBezier(rb,0,Math.PI/N - 2*alpha);
+  basicArc = basicArc.reflectX();
+
+  let angle = -Math.PI / (2*N) + alpha;
+  ctx.strokeStyle='black';
+
+  for (let i = 0; i < N; i++)
+    {
+      // One side of tooth.
+      let inv = basicInv.rotate(angle);
+      inv = inv.scale(rb);
+      inv = inv.translate(c);
+      ctx.stroke(inv);
+
+      // Other side of tooth.
+      angle -= Math.PI / N + 2 * alpha;
+      inv = basicInv.reflectX();
+      inv = inv.rotate(angle);
+      inv = inv.scale(rb);
+      inv = inv.translate(c);
+      ctx.stroke(inv);
+
+      // Gap between teeth.
+      let gap = basicArc.rotate(angle);
+      gap = gap.translate(c);
+      //ctx.strokeStyle='blue';
+      ctx.stroke(gap);
+
+      angle -= Math.PI / N - 2*alpha;
+    }
+}
+
+\end{figput}
+\caption{Gear with Addedenum and Dedendum Circles.}
+\label{fig-gear-with-add-ded}
+\end{figure}
+
+It is now possible to specify the standard tooth profile for a gear
+with arbitrary parameters, as in Figure ({\ref{fig-final-gear}). The
+value for $t$ to which the parameterization of the involute extends
+must be adjusted. Instead of extending out to the value of $t_0$ for
+which 
+$${\sin t_0 - t_0\cos t_0\over \cos t_0 + t_0\sin t_0} = \tan\theta,$$
+$t$ must be chosen so that $|i(t)| = r_p + a$. This is simpler to
+determine since $\theta$ no longer plays a role. As in an earlier
+calculation, we must have
+\begin{eqnarray*}
+(r_p+a)^2 &=& |i(t)|^2 \\
+&=& r_b^2(1+t^2)
+\end{eqnarray*}
+or
+$$t\ =\ \sqrt{\left({r_p+a\over r_b}\right)^2 - 1}\ =\ 
+\sqrt{\left({r_p+a\over r_p\cos\phi}\right)^2 - 1}.$$
+Of course, $a$ can't be chosen to produce a value for $t$ larger than $t_0$.
+
+When drawing gears with a given addendum, it can be useful to know the
+angle subtended by the top land. As noted above, the angle subtended
+relative to the base circle by each tooth is $\pi/N + 2\alpha$. Let
+$t_d$ be the value for $t$ at which the top land begins. Each
+side of the tooth, from the base circle to the top land subtends the
+angle $\beta$, where $\tan\beta = i_y(t_d)/i_x(t_d)$. The top land
+thus subtends the angle $\pi/N + 2\alpha - 2\beta$.
+
+\begin{figure}
+\begin{figput}{gearfinal,200bp}[done,skip]
+function gearfinal(ctx) {
+
+  // As above, but allow the user to tweak the settings. Further, we use the
+  // standard values for addendum and dedendum. This changes the way the
+  // involutes and gaps are drawn.
+  //
+  // BUG: There's some problem here of a mathematical or graphical nature.
+  // If I lift the restrictions on the inputs, things go haywire at
+  // the extremes.
+  
+  // Default pressure angle, number of teeth and module.
+  let phi = 20 * Math.PI / 180;
+  let N = 15;
+  let m = 5;
+
+  // Let the user change these.
+  let leftInput = -50;
+  let toothInput = NumberInputWidget.register(ctx,leftInput,20,15,"tooth");
+  N = parseInt(toothInput.getValue());
+  if (N < 4)
+    {
+      toothInput.theWidget.value = 4;
+      N = 4;
+    }
+  if (N > 30)
+    {
+      toothInput.theWidget.value = 30;
+      N = 30;
+    }
+    
+  let paInput = NumberInputWidget.register(ctx,leftInput,35,20,"pa");
+  phi = parseFloat(paInput.getValue());
+  if (phi > 25)
+    {
+      paInput.theWidget.value = 25;
+      phi = 25;
+    }      
+  if (phi < 5)
+    {
+      paInput.theWidget.value = 5;
+      phi = 5;
+    }
+  phi = phi * Math.PI / 180;
+
+  let moduleInput = NumberInputWidget.register(ctx,leftInput,50,5,"mod");
+  m = parseFloat(moduleInput.getValue());
+  if (m > 6)
+    {
+      moduleInput.theWidget.value = 6;
+      m = 6;
+    }
+  if (m < 1)
+    {
+      moduleInput.theWidget.value = 1;
+      m = 1;
+    }
+
+  let leftText = -120;
+  let upText = 30;
+  ctx.font = '10px san-serif';
+  ctx.fillStyle = 'black';
+  drawTextBrowserOnly(ctx,'Tooth Count',leftText,35-upText);
+  drawTextBrowserOnly(ctx,'Pressure Angle',leftText,50-upText);
+  drawTextBrowserOnly(ctx,'Module',leftText,65-upText);
+  
+  // Addendum and dedendum.
+  // BUG: I could let the user adjust these too.
+  let a = m;
+  let b = 1.25 * m;
+  
+  let c = new Point2D(150,100);
+  let pitchDiam = N * m;
+
+  // Pitch radius and base radius.
+  let rp = pitchDiam / 2;
+  let rb = rp * Math.cos(phi);
+
+  ctx.lineWidth = 0.4;
+
+  // Center of gear.
+  let p = new FPath();
+  p.ellipse(c.x,c.y,1.5,1.5,0,0,2*Math.PI);
+  ctx.fill(p);
+
+  // Point along parameterization where involute meets pitch circle.
+  let t = Math.tan(phi);
+
+  // Adjustment to width of the base of the teeth due to the fact that
+  // the teeth are of varying width. Note that the radius of the base circle
+  // doesn't matter.
+  let ipt = invo2(t);
+  let alpha = -Math.atan2(ipt.y,ipt.x);
+
+  // Determine the maximum value for t. This is the point at which the
+  // sides of a tooth meet. It determines the maximum possible value
+  // for the addendum.
+  let targetV = Math.tan(Math.PI/(2*N) + alpha);
+  let maxT = Numerical.newton(toothMeet,0.3,0,2,targetV,0.00001);
+
+  // Now the value of t determined by the addendum.
+  let T = Math.sqrt(((rp + a)/rb)**2 - 1);
+  if (T > maxT)
+    T = maxT;
+
+  // These are the parts of the gear profile. There's a tricky thing here in
+  // that the arc subtended by the top land must be determined.
+  // The arc subtended by half a tooth (out to maxT) is known to be
+  // pi/(2N) + alpha, but the involute now spans a smaller angle and the top
+  // land makes up the difference. This smaller angle is determined by
+  // invo(T), and the angle is beta such that
+  // tan(beta) = y(T)/x(T).
+  let basicInv = FPath.parametricToBezier(invo2,0,T,30);
+  let basicBot = FPath.circArcToBezier(rp-b,0,Math.PI/N - 2*alpha);
+
+  ipt = invo2(T);
+  let beta = -Math.atan2(ipt.y,ipt.x);
+  let basicTop = FPath.circArcToBezier(rp+a,0,Math.PI/N + 2*alpha - 2*beta);
+
+  // Due to LH coordinates.
+  basicTop = basicTop.reflectX();
+  basicBot = basicBot.reflectX();
+
+  // Add a radial line on each side of basicInv so that the tooth reaches
+  // the dedendum circle.
+  basicInv = basicInv.scale(rb);
+  basicInv.frontLineTo(rp-b,0);
+
+  let angle = -Math.PI / (2*N) + alpha;
+  ctx.strokeStyle='black';
+
+  for (let i = 0; i < N; i++)
+    {
+      // One side of tooth.
+      let inv = basicInv.rotate(angle);
+      inv = inv.translate(c);
+      ctx.stroke(inv);
+
+      // Arc of top land.
+      let top = basicTop.rotate(angle - beta);
+      top = top.translate(c);
+      ctx.stroke(top);
+      
+      // Other side of tooth.
+      angle -= Math.PI / N + 2 * alpha;
+      inv = basicInv.reflectX();
+      inv = inv.rotate(angle);
+      inv = inv.translate(c);
+      ctx.stroke(inv);
+
+      // Gap between teeth.
+      let gap = basicBot.rotate(angle);
+      gap = gap.translate(c);
+      ctx.stroke(gap);
+
+      angle -= Math.PI / N - 2*alpha;
+    }
+}
+\end{figput}
+\caption{Standard Gear Profile.}
+\label{fig-final-gear}
+\end{figure}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+\end{document}
+
+


Property changes on: trunk/Master/texmf-dist/doc/latex/figput/example/example.tex
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: trunk/Master/texmf-dist/doc/latex/figput/example/externalcode.js
===================================================================
--- trunk/Master/texmf-dist/doc/latex/figput/example/externalcode.js	                        (rev 0)
+++ trunk/Master/texmf-dist/doc/latex/figput/example/externalcode.js	2022-07-22 21:48:41 UTC (rev 63957)
@@ -0,0 +1,89 @@
+
+// This file demonstrates two things: how to use an external js
+// file, and use of the DraggableDrawWidget.
+
+// Functions passed to DraggableDrawWidgets
+
+function getRawSquare() {
+  
+  // The 'radius' of a square.
+  let r = 3;
+  let p = new FPath();
+  p.moveTo(-r,-r);
+  p.lineTo(r,-r);
+  p.lineTo(r,r);
+  p.lineTo(-r,r);
+  p.closePath();
+
+  return p;
+}
+
+function drawSquareDot(ctx) {
+
+  let p = getRawSquare();
+  ctx.fillStyle='red';
+  ctx.fill(p);
+  return p;
+}
+
+function drawSquareDotSelect(ctx) {
+
+  let p = getRawSquare();
+  ctx.fillStyle='green';
+  ctx.fill(p);
+  return p;
+}
+
+function squareLocationOK(x,y,w,ha,hb) {
+
+  // A bit of padding so that we don't leave "crumbs" around the edges.
+  let pad = 5;
+  
+  if (x < pad) return false;
+  if (x > w - pad) return false;
+
+  // Note the minus sign. We need to compare to y, which may be negative.
+  if (y < -hb + pad ) return false;
+  if (y > ha - pad ) return false;
+  return true;
+}
+
+
+// The top-level figure-drawing function.
+
+function bezier(ctx) {
+    
+  let w1 = DraggableDotWidget.register(ctx,70,165,'d1');
+  let w2 = DraggableDrawWidget.register(ctx,30,115,
+    drawSquareDot,drawSquareDotSelect,squareLocationOK,'d2');
+  let w3 = DraggableDrawWidget.register(ctx,120,25,
+    drawSquareDot,drawSquareDotSelect,squareLocationOK,'d3');
+  let w4 = DraggableDotWidget.register(ctx,270,105,'d4');
+
+  let p = new FPath();
+
+  // Straight lines from point to point.
+  p.moveTo(w1.widgetX,w1.widgetY);
+  p.lineTo(w2.widgetX,w2.widgetY);
+  p.lineTo(w3.widgetX,w3.widgetY);
+  p.lineTo(w4.widgetX,w4.widgetY);
+  ctx.strokeStyle = 'black';
+  ctx.lineWidth = 0.4;
+  ctx.stroke(p);
+
+  // Bezier curve determined by these points.
+  p = new FPath();
+  p.moveTo(w1.widgetX,w1.widgetY);
+  p.bezierCurveTo(w2.widgetX,w2.widgetY,
+    w3.widgetX,w3.widgetY,w4.widgetX,w4.widgetY);
+  ctx.strokeStyle = 'blue';
+  ctx.lineWidth = 1.5;
+  ctx.stroke(p);
+
+  // In this case (unlike most others), the widgets must be explicitly drawn.
+  w1.draw(ctx);
+  w2.draw(ctx);
+  w3.draw(ctx);
+  w4.draw(ctx);
+}
+

Added: trunk/Master/texmf-dist/doc/latex/figput/figput-manual/figput-manual.pdf
===================================================================
(Binary files differ)

Index: trunk/Master/texmf-dist/doc/latex/figput/figput-manual/figput-manual.pdf
===================================================================
--- trunk/Master/texmf-dist/doc/latex/figput/figput-manual/figput-manual.pdf	2022-07-21 23:49:49 UTC (rev 63956)
+++ trunk/Master/texmf-dist/doc/latex/figput/figput-manual/figput-manual.pdf	2022-07-22 21:48:41 UTC (rev 63957)

Property changes on: trunk/Master/texmf-dist/doc/latex/figput/figput-manual/figput-manual.pdf
___________________________________________________________________
Added: svn:mime-type
## -0,0 +1 ##
+application/pdf
\ No newline at end of property
Added: trunk/Master/texmf-dist/doc/latex/figput/figput-manual/figput-manual.tex
===================================================================
--- trunk/Master/texmf-dist/doc/latex/figput/figput-manual/figput-manual.tex	                        (rev 0)
+++ trunk/Master/texmf-dist/doc/latex/figput/figput-manual/figput-manual.tex	2022-07-22 21:48:41 UTC (rev 63957)
@@ -0,0 +1,857 @@
+
+\documentclass[10pt]{article}
+
+% Allows various tweaks to itemize as optional arguments.
+\usepackage{enumitem}
+
+% Gives the proof environment, with a box for QED.
+\usepackage{amsthm}
+
+% Needed for things like pmatrix.
+\usepackage{amsmath}
+
+% This allows footnotes from within array environment.
+\usepackage{footnote}
+\makesavenoteenv{array}
+
+% To adjust font sizes more easily.
+\usepackage{relsize}
+
+% This allows \verb in footnotes
+\usepackage{fancyvrb}
+
+% This allows me to say 
+% \begin{figure}[H]
+% to mean ``here, and don't argue.'' Note the captial 'H'.
+\usepackage{float}
+
+% This is the modern thing to do, but the manual is 1300 pages!
+\usepackage{tikz}
+\usepackage{pgfplots}
+
+
+\begin{document}
+
+% Need this for fancyvrb to work.
+\VerbatimFootnotes
+
+% So that I don't have to type this all the time.
+\newcommand{\figput}{\textsc{FigPut}}
+
+
+\begin{center}
+  {\Large \figput}
+  
+  Interactive Figures for \LaTeX
+
+  \verb=https://github.com/rsfairman/figput=
+
+  Randall Fairman
+
+  Version 0.90, July 21, 2022
+\end{center}
+
+\vskip 0.2cm
+
+The \textsc{FigPut} system allows \LaTeX\ to produce interactive
+figures. The system produces a static PDF file, as usual; in addition,
+the document can be viewed with an Internet browser and the figures
+become interactive. See the prototype in {\tt example/example.tex}
+to clarify what follows.\footnote{The version available on CTAN
+includes only what is strictly necessary to rebuild the document from
+scratch: {\tt example.tex} and {\tt exteernalcode.js}. The repository at {\tt
+  github} includes all the files that result from the build process,
+and are necessary to view the PDF in  either static or interactive
+form.} To view this example in its fully interactive form, see
+\verb=rsfairman.github.io/figput-example/=.
+
+% For some reason \textsc doesn't work within \section
+\section{Why \normalfont\scshape{FigPut}}
+
+There are many ways to produce figures in \LaTeX: MetaPost, TikZ,
+PSTricks, XY-pic, {\tt graphics}, {\tt picture}, and more. Creating
+technical figures is often an exercise in programming, and none of
+these is based on a commonly used programming
+language. \textsc{FigPut} is based on JavaScript (JS), which is
+probably the most widely used language today. Moreover,
+\figput\ allows figures to be animated and/or interactive.
+
+Aside from the fact that figures are specified with
+JavaScript, the system is normal \LaTeX. An important feature is that
+the two forms of the document -- static PDF and interactive -- look 
+identical, with the same pagination and formatting. The reader can
+move between the printed version and the interactive version without
+needing to reorient. 
+
+% For some reason \textsc doesn't work within \section
+\section{Using \normalfont\scshape{FigPut}}
+
+Here's a list of all the commands available in \figput:
+\begin{verbatim}
+\begin{figput} ... \end{figput}
+\FigPut
+\SetInnerMargin
+\SetOuterMargin
+\NeverSkip
+\AllowSkip
+\LoadFigureCode
+\end{verbatim}
+
+\subsection{The \LaTeX\ Side}
+
+Interactive figures are specified with the {\tt figput}
+environment or the \verb=\FigPut= command. The full form of the
+environment specification is
+\vskip 0.2cm
+
+\noindent\verb=\begin{figput}{<fig_name>,<fig_ht>}[=\emph{optional arguments}\verb=]=
+
+\noindent\verb=  <JavaScript code>=
+
+\noindent\verb=\end{figput}=
+\vskip 0.2cm
+
+\noindent There are two mandatory arguments: \verb=<fig_name>= and
+\verb=<fig_ht>=. Every figure must have a unique name. This name is
+unrelated to any \verb=\label= or other identifier used for
+the figure. The \verb=<fig_ht>= is the height of the figure, expressed
+like other \LaTeX\ lengths in {\tt pt}, {\tt cm}, \emph{etc}. The
+figure is allocated this much vertical space on the page. The
+remaining optional arguments are discussed below.
+
+The {\tt <JavaScript code>} is used to draw the figure, and the only
+requirement is that it be given as
+\begin{verbatim}
+function <fig_name>(ctx) {
+  ...
+}
+\end{verbatim}
+The name of the JS function must match the figure name given to the
+{\tt figput} environment -- that's how the browser finds the correct
+JS function to draw a particular figure. The {\tt ctx} argument
+is required; it's the ``rendering context'' used for
+drawing.\footnote{\label{page-ctx} A variable of this type is commonly obtained in
+JavaScript by something like \vspace{-1.5mm}
+\begin{verbatim}
+let canvas = document.getElementById('where-drawing-happens');
+let ctx = canvas.getContext('2d');
+\end{verbatim}
+\vspace{-1.5mm} The full name for this type is {\tt
+  CanvasRenderingContext2D}.}
+
+All of the JS functions for the various figures share the same
+name-space, and it is perfectly acceptable to share functions between
+figures or to define helper functions within a figure's
+environment. If many figures use the same {\tt drawDoodad()}
+function, then that function should appear with only a single figure, and
+it will be available to all of them. 
+
+Use \verb=\SetInnerMargin= and \verb=\SetOuterMargin= to set the inner and outer
+margins (which may differ in a book that has left and right
+pages). The figure will be rendered within a rectangle that is set in
+from the left margin by the given amount. For example, you might say
+\begin{verbatim}
+\SetInnerMargin{150pt}
+\SetOuterMargin{150pt}
+\end{verbatim}
+so that the left edge of the figure is {\tt 150pt} from the left edge
+of the paper. These values can be changed before every figure, if that
+is appropriate.
+
+The coordinate system used within the JS code is based on big points ({\tt
+  bp}), with the origin at the lower-left corner of the
+figure. The $y$-coordinate increases as you move \emph{up} the page.
+The $y$-axis is offset from the edge of the page by the
+value given to \verb=\SetInnerMargin= or \verb=\SetOuterMargin=.
+
+There is no need to begin the drawing by erasing the drawing
+area. That's done automatically.
+
+\subsubsection*{Optional Arguments}
+
+The arguments to {\tt figput} in {\tt []}, are optional. The first two
+of these arguments are \label{ht-above-below}
+\begin{verbatim}
+ht_above, ht_below 
+\end{verbatim}
+If these arguments appear, then they must both appear, they must be
+the first two arguments, and they must be given in that order (above,
+then below); furthermore, they must include a unit specification, like {\tt
+  bp}. An interactive figure may need a bit of extra clearance 
+for an animation or space for widgets that aren't part of the
+figure itself. The static version of the document always uses
+\verb=<fig_ht>= for the figure height, while the interactive form adds
+this optional amount of space above and below the figure. If
+\verb=ht_below= is non-zero, then the $y$-axis is \verb=ht_below=
+above the bottom of the figure when drawn interactively.
+
+The remaining optional arguments may appear in any order and function
+as boolean flags:
+
+\begin{itemize}[itemsep=-1pt,leftmargin=2cm]
+  \item[{\tt nostatic}] Use this when the figure is to be shown only
+    when the document is viewed interactively. No figure will appear
+    in the PDF. Almost certainly, the mandatory \verb=fig_ht= argument
+    should be zero. The sum of \verb=ht_above= and \verb=ht_below= is
+    used for the height of the interactive figure.
+  \item[{\tt done}] indicates to the browser that the {\tt .tikz}
+    should not be updated.
+  \item[{\tt skip}] TikZ files can be large and take a long time to
+    process. When this is set, the TikZ file won't be loaded and the
+    figure will appear with a default ``not available'' message.
+\end{itemize}
+
+When the composition of a figure is complete, it often makes sense to
+turn on the {\tt done} and {\tt skip} flags. Using {\tt skip} saves
+time, and {\tt done} prevents inadvertent overwriting of a {\tt .tikz}
+file that you're happy with. However, to see the complete output, with
+your figures, you would have to go back and tediously remove all of
+the {\tt skip} flags. Use \verb=\NeverSkip= to avoid that tedium and
+disable all the {\tt skip} 
+flags that occur until the next \verb=\AllowSkip=. 
+
+\subsection*{The {\tt \textbackslash FigPut} Command}
+
+\verb=\FigPut= takes exactly the same arguments as the {\tt figput}
+environment, but the JS code must appear in an external file. The
+location of this external file is indicated with
+\verb=\LoadFigureCode=. If the code is found in {\tt mydrawcode.js},
+then
+\begin{verbatim}
+\LoadFigureCode{mydrawcode.js}
+\end{verbatim}
+must appear somewhere in the {\tt .tex} file.
+
+It is often easier to use an external file to consolidate the drawing
+code in fewer files (or a single file). Not only
+does it make the {\tt .tex} file shorter and easier to navigate, but it
+allows the use of programming tools tailored to JS. For instance,
+the code could be written in TypeScript and compiled to JS. On the other
+hand, if the code for the figures is brief, then it may be clearer and more
+direct to use the {\tt figput} environment so that the code is in the
+{\tt .tex} file. 
+
+\subsubsection*{Additional Remarks}
+
+There is no explicit provision in \textsc{FigPut} for changing the
+body of the text based on whether the document is to be viewed statically
+or interactively. This is intentional. The aim is for the text and its
+layout to be \emph{identical} in the two scenarios. However, it would
+be relatively straightforward to set up a couple of commands like
+\begin{verbatim}
+\newcommand{\statictext}[1]{#1}
+\newcommand{\intereactivetext}[1]{ }
+\end{verbatim}
+In the above example, anything that appears in \verb=\statictext{}=
+will pass through to the \LaTeX\ document, while everything in
+\verb=\interactivetext{}= will be ignored. Swap these two definitions
+depending on whether the document is being compiled for interactive or
+static reading.
+
+\subsection{Workflow}
+
+There are several phases to composing and releasing a document. The
+first phase is a loop through writing the \LaTeX, compiling it, viewing
+the output in a browser and generating TikZ, until the document is
+done. Everything in the first phase is local to your machine. The
+second phase is posting the result to a public-facing website. The
+first phase is discussed here; see Section \ref{sec-distributing} for
+the second phase.
+
+\subsubsection*{Setup}
+
+The functionality of \figput\ is given by {\tt figput.sty}. It
+requires the following packages: {\tt zref}, {\tt xsim}, {\tt tikz}
+and {\tt verbatim}.
+
+A typical arrangement is to have a {\tt javascript}
+directory with the files for the browser side of the framework, and a
+\LaTeX\ directory where the document is written in the usual way. The {\tt 
+  javascript} directory contains the JS files and the one HTML file needed
+to provide the browser front-end, and you'll also find {\tt server.py}.
+This Python script runs a local server so that your browser can
+open and view the document being written.\footnote{This requires
+Python 3 -- although that's probably obvious these days.} In principle, it's no
+different than a normal web-server, but it is tailored in several
+ways to the task at hand. To invoke this server, use the command-line
+to go to the {\tt javascript} directory and type
+\begin{verbatim}
+python server.py directory/nameof.pdf [port_num]
+\end{verbatim}
+The {\tt directory/nameof.pdf} argument is required and should be the
+path from the current ({\tt javascript}) directory to the PDF being
+generated by \LaTeX. Often, this will be something like
+\begin{verbatim}
+../../latex_area/num_theory/hairy_math.pdf
+\end{verbatim}
+The optional \verb=port_num= argument indicates the TCP/IP port on which the
+server will listen. It defaults to 8000. In principle, any integer in
+the range $[0,2^{16})$ could appear here, but certain values are
+restricted and others may already be in use. Stick to values
+in the range 8000-8100, and you should be safe.\footnote{See
+\verb=en.wikipedia.org/wiki/List_of_TCP_and_UDP_port_numbers=}
+
+By using different port numbers, it's possible to run several servers
+at once, so that multiple documents can be viewed and edited at the
+same time. Once the server is running, point your browser to
+\verb=localhost:8000= (or whatever \verb=port_num= you've chosen) to
+load the document.
+
+As stated, {\tt server.py} differs from a normal web-server in certain
+ways. This is done to make it easier to work with a document while it
+is being written. Once the document is complete, it can be served by a
+normal web-server.
+
+\subsubsection*{Additional Files}
+
+There are two additional directories in the {\tt javascript} directory:
+{\tt development} and {\tt release}. \figput\ was written in
+TypeScript, and the {\tt .ts} files are in {\tt development}. Even if
+you don't want to modify the system, the TypeScript files are easier
+to follow than the JavaScript files, and are the first place to look to
+clarify how the system works internally. There are four files:
+\begin{itemize}[itemsep=-1pt,leftmargin=1cm]
+\item{\tt main.ts} is the main entry-point for the program. This is
+  unlikely to interest anyone who wants to simply use \figput.
+\item{\tt layout.ts} handles page layout -- also uninteresting to most people.
+\item{\tt widgets.ts} has the code for the various widgets. If widgets
+  aren't acting the way you expect, then look here.
+\item{\tt tikz.ts} handles lower-level geometry, and conversion from
+  JS to TikZ. Look here for details about the {\tt Point2D} and
+  {\tt FPath} classes.
+\end{itemize}
+
+Two files found in the {\tt javascript} directory are {\tt
+  pdf.worker.min.js} and {\tt pdf.js}. These are the source files for
+Mozilla's pdf.js library. The complete project can be found at
+\verb=github.com/mozilla/pdf.js=. The files are included here because,
+when developing a \LaTeX\ document on your local machine, it would be
+pointless (and slow) to download these files every time an updated
+version of your document is loaded.
+
+The {\tt release} directory contains the files to be used when the
+document is released to a public-facing website. As noted above, {\tt
+  server.py} works differently than a normal web-server. The release
+process is discussed in more detail in Section \ref{sec-distributing}.
+
+\subsubsection*{From JavaScript to TikZ}
+
+Once the server is running, a browser can view documents created with
+\figput, but the figures will not be visible in
+the PDF document until a TikZ file is provided. The \emph{Get TikZ}
+button in the browser window generates the TikZ files. The server
+will save these files to the same directory as the PDF file. Note that
+a TikZ file will only be generated if the figure has been scrolled
+into view (or nearly into view) since the document was loaded.
+
+Because TikZ files can take time to load, it's often useful to
+compose the figures one (or a few) at a time. Apply the optional
+{\tt done} argument for any figures that are complete, and the
+\emph{Get TikZ} button will not generate TikZ files for them. You may
+want a particular frame from an animation; once you have the right
+frame, it would be frustrating to accidentally overwrite it in the course of 
+working on some other figure. Using {\tt done} prevents that from happening.
+
+\subsection{JavaScript Drawing}
+
+In most respects, any JS code can be used with FigPut, but it must be
+possible to translate the JS drawing commands to TikZ, and that leads
+to certain requirements. In a nutshell, all drawing must be done using a
+class that is very similar to JS's built-in {\tt Path2D} class. 
+
+If this is too restrictive, then it is possible to side-step the
+requirement with a bit of extra effort. If you use JS drawing commands
+that are off-limits, like {\tt drawImage()}, then the interactive version
+will work fine, but you'll have to find some other way to generate the
+figure for inclusion in the static PDF. Any of the usual methods of
+generating figures for \LaTeX\ documents will work, but now the two
+versions, interactive and static, are generated from different
+source-code.
+
+Earlier, in a footnote on p. \pageref{page-ctx}, it was a stated that
+the {\tt ctx} argument to your drawing function has the standard JS type, {\tt
+  CanvasRenderingContext2D}. That's not always true. Any drawing
+done \emph{to the browser} is \emph{precisely} an object of this
+type. If you only care about seeing your document within the browser
+framework, and you don't care about generating figures for a
+standalone {\tt .pdf} file, then that's all you need to know. Draw
+with JS however you like. 
+
+To produce TikZ output, the built-in {\tt CanvasRenderingContext2D}
+must be ``spoofed.'' All of the drawing commands that normally go to
+the built-in JS browser code go to \figput's {\tt CTX} class
+instead, where they are converted to TikZ output.
+This class implements a sub-set of the full list of drawing
+commands normally available. The permitted commands are
+\begin{verbatim}
+  ctx.fill()
+  ctx.stroke()
+  ctx.lineWidth
+\end{verbatim}
+These work almost as they normally do. The {\tt lineWidth} is the
+thickness of any paths, and can be thought of as being in \TeX's {\tt
+  bp} units. The {\tt fill()} and {\tt stroke()} commands normally
+take a JS {\tt Path2D} object, but you should pass an object of type
+{\tt FPath} instead.
+
+The methods of {\tt FPath} listed below are exactly like those found
+in {\tt Path2D}. They add a new segment to an existing {\tt FPath},
+obtained with {\tt new}. See any JS resource for an explanation. 
+\begin{itemize}[itemsep=-1pt,leftmargin=*]
+\item {\tt closePath()}
+\item {\tt moveTo()}
+\item {\tt lineTo()}
+\item {\tt bezierCurveTo()}
+\item {\tt ellipse()}
+\end{itemize}
+And these methods of {\tt FPath} are new -- they have no counterpart
+in {\tt Path2D}.
+\begin{itemize}[itemsep=-1pt,leftmargin=*]
+\item {\tt addPath(p)} appends the {\tt FPath}, {\tt p}, to an
+  existing {\tt FPath}. 
+\item {\tt translate(p)} translates an {\tt FPath} by the given {\tt Point2D}.
+\item {\tt rotate(angle)} rotates an {\tt FPath} by the given angle,
+  in radians.
+\item {\tt scale(s)} scales an {\tt FPath} by the given factor
+  (relative to the origin).
+\item {\tt reflectX()} reflects an {\tt FPath} across the $x$-axis.
+\item {\tt reflectXY()} reflects an {\tt FPath} across the $x$ and $y$-axis.
+\item {\tt rotateAbout(angle,p)} rotates a given {\tt FPath} about the
+  given {\tt Point2D} by the given angle.
+
+The methods above apply to an existing {\tt FPath} and return a new {\tt FPath}.
+\item {\tt parametricToBezier(f,t0,t1,n)} converts a parametric
+  function, {\tt f(t)}, to a path consisting of {\tt n} B\'ezier
+  curves as   {\tt t} runs from {\tt t0} to {\tt t1}. The function
+  must be defined to return {\tt Point2D} objects.
+
+This is a static method, so it returns a new {\tt FPath} that is unrelated to any existing {\tt FPath} objects.
+\end{itemize}
+There are several additional methods in {\tt FPath} that may be
+useful, but they haven't yet been tested well enough to mention
+here (and they may change in the future). See the source code if
+you're adventurous. 
+
+Several of the methods above mention the {\tt Point2D} class, and it's what you would expect. Use
+\begin{verbatim}
+  new Point2D(x,y);
+\end{verbatim}
+to create these objects. There's a long list of methods defined in the
+class: {\tt translate()}, {\tt rotate()}, {\tt length()},
+\emph{etc}. See the source code for a complete list. 
+
+Text is drawn in a way that is further from how it's normally done in
+JS. Instead of calling {\tt ctx.fillText()}, there are three top-level
+functions (not part of any class) for drawing text:
+\begin{verbatim}
+  drawText(ctx,txt,x,y,dx,dy);
+  drawTextBrowserOnly(ctx,txt,x,y,dx,dy);
+  drawTextTikZOnly(ctx,txt,x,y,dx,dy);
+\end{verbatim}
+The arguments are the same in the three cases, but the first function will draw
+text to both the browser window and the TikZ, while the other two will
+draw the text to only one destination or the other. The {\tt ctx} is
+the same as the argument to your drawing function, {\tt txt} is the
+string to be drawn, {\tt x,y} is the location of the text \emph{for
+the browser}, relative to the lower-left corner of the
+bounding-box. When the text is drawn to TikZ, it is drawn at {\tt
+  x+dx,y+dy}. Because the fonts used in the browser and in TikZ differ
+slightly, sometimes it's necessary to tweak the TikZ placement. Setting
+\begin{verbatim}
+  ctx.font = '10px san-serif';
+\end{verbatim}
+sets the browser font to something very close the default font used
+by TikZ, but it's not a perfect match.  The {\tt dx} and {\tt dy}
+arguments are optional and default to {\tt 0}.
+
+As a bonus, the static method, {\tt Numerical.newton()}, can be used to
+solve $f(x) = y$ for $x$, given $y$. It's a naive implementation of Newton-Raphson.
+
+\subsection{JavaScript Widgets}
+
+The foregoing framework could be used an an alternative to TikZ,
+PSTricks, MetaPost, \emph{etc.}, if your aim is strictly static
+output. To make the figures interactive, there must be some means to
+accept user input -- widgets.
+
+All widgets have a static {\tt register()} method. Do not use {\tt
+  new} to create widgets! Registering a widget has the effect of
+making it available for user input, and drawing it too (with one
+exception). The arguments to these {\tt register()} methods vary with
+the widget, but the first argument is always the {\tt ctx} known to
+the drawing function, and the last argument is always a {\tt name} (a
+string). One drawing could have several widgets of the same kind and
+{\tt name} is used to distinguish 
+them. So, if a particular drawing has three buttons, then they could
+be created/registered with
+\begin{verbatim}
+let b1 = ButtonWidget.register(ctx,...,"first");
+let b2 = ButtonWidget.register(ctx,...,"second");
+let b3 = ButtonWidget.register(ctx,...,"third");
+\end{verbatim}
+These names only need to be unique within a single drawing and one
+type of widget. So, in the example above, two {\tt
+  DraggableDotWidget}s could be registered in the same drawing as
+the {\tt ButtonWidget}s with
+\begin{verbatim}
+let dd1 = DraggableDotWidget.register(ctx,...,"first");
+let dd2 = DraggableDotWidget.register(ctx,...,"second");
+\end{verbatim}
+
+\subsubsection{\tt ButtonWidget}
+
+These are registered with 
+\begin{verbatim}
+ButtonWidget.register(ctx,x,y,text,name);
+\end{verbatim}
+The {\tt x,y} argument is the location of the button, relative to the
+lower-left corner. The {\tt text} is what is shown as the message
+within the button. Buttons work by calling back to your drawing code
+whenever they are clicked. Every time the button is clicked, the
+entire drawing function is executed.
+
+There are two useful fields of {\tt ButtonWidget}. If {\tt b} is a
+{\tt ButtonWidget}, then {\tt b.clickState} toggles between {\tt true} and {\tt
+  false} with every click of the button, while {\tt b.resetState} is
+set to {\tt true} whenever the button is clicked -- and remains {\tt
+  true} until your drawing code resets it.
+
+\subsubsection{\tt NumberInputWidget}
+
+This is similar to {\tt ButtonWidget}, and is used to input single
+numbers. It's registered with 
+\begin{verbatim}
+NumberInputWidget.register(ctx,x,y,v,name);
+\end{verbatim}
+The {\tt v} argument is the initial numerical value shown in the
+widget. Whenever the user changes this value, the widget calls back
+and executes the entire drawing function. To obtain this value, call
+{\tt getValue()} on the relevant widget. Because this widget relies
+on HTML, {\tt getValue()} returns a string. It may be necessary to
+call the JS {\tt parseFloat()} or {\tt parseInt()} functions on this
+value. 
+
+\subsubsection{\tt DraggableDotWidget}
+
+A ``draggable dot'' is a small dot that can be grabbed by the mouse
+and moved around. They're registered with
+\begin{verbatim}
+DraggableDotWidget.register(ctx,x,y,name);
+\end{verbatim}
+To determine where the user has moved a dot, refer to the widget's
+{\tt widgetX} and {\tt widgetY} fields. 
+
+Most widgets are used ``off to the side'' and wouldn't normally
+interfere with the way the figure is drawn, but these dots are typically
+used as part of the drawing itself. The order in which dots are drawn
+may matter. Sometimes a dot should be drawn first, so that other
+elements of the figure may be drawn over it; and sometimes a dot
+should be drawn last so that nothing can obscure it. For this
+reason, unlike other widgets, registering the widget does not also
+draw the widget. An explicit call to the widget's {\tt
+  draw(ctx)} method must be made to draw the dot.
+
+\subsubsection{\tt DraggableDrawWidget}
+
+This is similar to {\tt DraggableDotWidget}, but it has no default
+drawing behavior. The user must provide functions to specify what is
+to be drawn. So it can also be a draggable polygon, or a draggable
+anything-you-can-draw. Register these with
+\begin{verbatim}
+DraggableDrawWidget.register(ctx,x,y,
+    drawFcn,drawSelFcn,testPosFcn,
+    name);
+\end{verbatim}
+The {\tt drawFcn} must be defined to take the {\tt ctx} as the sole
+argument. It can draw whatever it wants, noting that the origin is
+shifted so that drawing should typically take place relative to {\tt
+  (0,0)}, not {\tt (widgetX,widgetY)}. In most cases, this means
+that the drawing code is independent of where the item is on the
+page. {\tt drawFcn} must return an {\tt FPath} object to indicate
+the ``clickable area'' for the item. For example, if what is being
+drawn is a small square, then the function might be defined as
+\begin{verbatim}
+function drawSquare(ctx) {
+  let p = new FPath();
+  // p.lineTo, moveTo, etc., to make a square.
+  ctx.fillPath(p);
+  return p;
+}
+\end{verbatim}
+The value returned is noted, and any click in the interior of the path
+-- as determined by the JS function {\tt isPointInPath()} -- 
+is taken to be a valid click on the object, to select it and drag it around.
+
+The {\tt drawSelFcn} argument to {\tt register} is identical to the
+{\tt drawFcn} argument, but it is called to draw the item when it is
+``selected.'' Often, the only difference between the two functions
+will be the color used to draw the item.
+
+The {\tt testPosFcn} argument is used to determine whether a
+particular location for the item is acceptable. For example, an item
+could be limited to a particular region. This is called every time the
+mouse is moved, after the item has been selected, up until the mouse
+button is released. The function takes five arguments and returns a
+boolean. The five arguments are the proposed {\tt x,y} position (the
+mouse location), followed by the width of the drawing area, then the
+height above and below the $x$-axis, where the width is equal to the
+text width. Return {\tt true} if the 
+proposed {\tt x,y} is acceptable; {\tt false} otherwise. At a minimum,
+the function should typically check that {\tt x,y} is inside the
+figure rectangle.
+
+\subsubsection{\tt LoopAnimWidget}
+
+This widget and the next one ({\tt OpenAnimWidget}) are for
+animations, and work similarly. A {\tt LoopAnimWidget} is used for
+animations that run in a repeating loop. There are many arguments to
+register them.
+\begin{verbatim}
+LoopAnimWidget.register(ctx,x,y,scale,visWidget,
+    steps,start,timeStep,
+    visSteps,visFastSlow,visPauseRun,visCircle,triGrab,
+    name);
+\end{verbatim}
+The {\tt x,y} values are the location of the center of the circle that
+is the primary element of the widget. The widget can be made larger or
+smaller by changing the {\tt scale} -- a value of {\tt 1.0} makes the
+circle 40~{\tt bp} in radius. The {\tt visWidget} argument is a
+boolean; set it to {\tt false} to run an animation without
+showing the user this widget.
+
+{\tt steps} is the integral number of steps that make up one loop of
+the animation. {\tt start} is the step on which the animation
+starts -- so that the animation starts with the {\tt start}-th
+frame. {\tt timeStep} is the number of milliseconds between
+frames. Unless the machine is \emph{very} fast, anything less than
+{\tt 10} for {\tt timeStep} is probably pointless, and a setting of
+{\tt 50} or {\tt 75} is more reasonable considering the human eye.
+
+The next group of arguments -- {\tt visSteps} through {\tt triGrab} -- are
+all booleans. They determine whether certain parts of the widget are
+visible. {\tt visSteps} shows or hides an area above the circle that
+can be used to change the number of steps taken per frame. The user
+can use this control to skip frames of the animation. {\tt
+  visFastSlow} is for some ``sideways chevrons,'' in an area below the circle,
+that allow the user to change the number of milliseconds per
+frame. {\tt vsPauseRun} is for a pause/run control below the
+circle. {\tt visCircle} is for the entire circle. The circle has a
+small grabable triangle to indicate which frame is being shown; use
+{\tt triGrab} to show or hide the triangle.
+
+To draw a particular frame from your drawing function, refer to the
+{\tt curStep} field of the object. This will be a value in the range
+from 0 to the {\tt steps} argument to {\tt register()}. 
+
+\subsubsection{\tt OpenAnimWidget}
+
+This widget is for open-ended animations that don't run in a loop,
+but continue ``forever.'' Whereas {\tt LoopAnimWidget} indicates the
+frame being viewed relative to a circle, {\tt OpenAnimWidget} uses a
+bar, something like a scroll-bar. Registration is similar to
+{\tt LoopAnimWidget}: 
+\begin{verbatim}
+OpenAnimWidget.register(ctx,x,y,scale,width,visWidget,
+    timeStep,decay,
+    visSteps,visFastSlow,visPauseRun,visBar,barGrab,
+    name);
+\end{verbatim}
+The {\tt ctx}, {\tt x}, {\tt y}, {\tt scale} and {\tt visWidget}
+arguments are as for {\tt LoopAnimWidget}. {\tt width} sets the width
+of the bar, in {\tt bp}.
+
+{\tt timeStep} is in milliseconds, as for {\tt LoopAnimWidget}. The
+{\tt decay} is used to adjust the rate of travel of the ``thumb'' along the
+bar as the animation progresses. Since the animation is potentially
+infinite, the thumb moves quickly early in the animation, then moves
+more and more slowly, so that it never quite reaches the end of the
+bar. The position of the thumb is given by
+$$1 - {1\over (1+{\tt decay})^s},$$
+expressed as a fraction of the bar's total length, where $s$ is the
+frame count (\emph{i.e.}, {\tt curStep}). A reasonable setting for {\tt
+  decay} is something in the range of $10^3$ to $10^6$, although it
+will depend on the animation. 
+
+The arguments from {\tt visSteps} to {\tt barGrab} are all boolean and
+control which controls that make up the widget are visible. They're
+like their counterparts in {\tt LoopAnimWidget}, except that {\tt
+  OpenAnimWidget} uses a bar instead of a circle.
+
+\section{Distributing a Complete Document}
+\label{sec-distributing}
+
+The PDF document is no different than any other PDF, and can be
+distributed in the usual ways. When moving the document in interactive
+form to a public-facing website, a few steps are necessary.
+
+See the {\tt javascript/release} directory. It has two files: {\tt
+  figput.html} and {\tt figput.js}. The {\tt .js} file is just the
+four files used for the local version ({\tt main.js}, \emph{etc}.),
+consolidated to a single file and minified. These two files must
+appear on the web-server in the same directory as the various files
+that make up your document.
+
+{\tt figput.html} is only a few lines long, and there are two
+important changes that must be made. See the line that reads
+\vskip 0.2cm
+\noindent\verb!<body onload="doOpenDocument('unknown1',unknowny)" id="mainbody">!
+\vskip 0.2cm
+\noindent Change {\tt unknown1} to your document's name, \emph{without} the
+{\tt .pdf} suffix. If the document was generated from {\tt
+example.tex}, then {\tt unknown1} should be changed to {\tt example}.
+Second, change {\tt unknowny} to {\tt 0}. When the document is
+opened, this is the vertical position, in {\tt bp}, at which the document is
+opened. Setting {\tt unknonwy} to {\tt 0} means that the document
+will open at the top of the first page. Of course, it's possible
+that you want the document to open at some other location, in which
+case use some other value for {\tt unknowny}.
+
+The server needs {\tt figput.html} (after the modifications
+above), {\tt figput.js}, and the files that make up your
+document. These files consist of the {\tt .pdf} file, the {\tt .fig.aux}
+file, any {\tt .js} files referred to by \verb=\LoadFigureCode=, plus
+any {\tt .fjs} files generated by your document. The server does not
+need the {\tt .tikz} files. 
+
+\section{Code Internals}
+
+An understanding of this section isn't necessary to use \figput; it's
+here to provide a bit of background for anyone who wants to improve
+or modify the framework. Most of \figput\ is in TypeScript, which
+should make it easier to follow.
+
+Throughout the various files that make up the system are
+{\tt BUG} annotations. These are not bugs \emph{per se}, but are more
+like infelicities, opportunities for improvement, or to draw attention
+to something confusing or problematic. If you want to contribute to
+\figput, then these are a good place to start.
+
+\subsection{\tt figput.sty}
+
+The {\tt .sty} file is well-commented and should be
+self-explanatory. However, I am far from an expert in \LaTeX3
+programming. Here is a high-level list of ways in which it might be
+possible to improve things.
+
+\begin{itemize}[itemsep=-1pt,leftmargin=*]
+\item {\tt figput.sty} is written for \LaTeX3. The entire thing might
+  be simpler if it were in Lua\TeX.
+\item The ability to explicitly specify the inner and outer margins
+  used by \figput\ (with \verb=\SetInnerMargin= and
+  \verb=SetOuterMargin=) is useful, but it would often suffice to
+  default to the margins used by \LaTeX. How can those values be
+  obtained?
+\item Someone who is more expert in \LaTeX3 could improve the code's
+  clarity and brevity.
+\item It would be nice if \figput\ could create figures within a {\tt
+  minipage}, but that would require extensive changes to both the
+  \LaTeX\ and browser code.
+\end{itemize}
+
+\subsubsection*{A Quirk}
+
+\LaTeX\ on Windows has a quirk. \TeX\ will not write to a
+file whose type is executable. Thus, it won't write to
+a {\tt .pl} file (Perl), {\tt .py} (Python) file, \emph{etc.},
+depending on how the machine is set up. \figput\ creates
+JavaScript files, which are typically saved as {\tt .js} files, and
+these may be seen as executable by Windows. Fortunately,
+browsers doesn't care what the suffix is, so \figput\ uses
+{\tt .jfs} as the suffix.  
+ 
+This limitation on the file name suffix applies to \verb=\write=, but
+not to \verb=\write18=. \TeX\ is limited in this way to prevent
+accidental errors and for security. One solution might be to have the
+package write files using an acceptable suffix, then change the
+suffix with \verb=\write18=, which does not have this
+limitation. However, to use \verb=\write18= this way, \LaTeX\ would
+have to be invoked with something like
+\begin{verbatim}
+pdflatex -shell-escape
+\end{verbatim}
+which would be annoying. 
+
+\subsection{\tt server.py}
+
+The server is a simple thing, so there's not much to say. It
+would be nice if it were written in a compiled language so
+that the user doesn't need to install Python.
+
+\subsection{Browser Code}
+
+This part is written in TypeScript (TS), which is essentially JS with
+type annotations. It must be translated 
+to JS for the browser to run it, but TS code is easier to follow, and
+the type information heads off many programming errors.
+
+Although the program is (to my knowledge!) bug-free in the usual
+sense, there are plenty of {\tt BUG} annotations to draw attention to
+places where the code could be improved. Some of the higher-level
+possibilities for improvement are noted below.
+\begin{itemize}[itemsep=-1pt,leftmargin=*]
+\item \figput\ relies on the {\tt pdf.js} library for rendering
+  PDFs. The result is not as crisp as I would like. It's unclear
+  whether the problem is with the library itself, or how it is being
+  used. Someone who knows that library well may be able to improve the
+  output. Maybe a different library would work better.
+\item Most of the widgets do not rely on the DOM, but {\tt
+  NumberInputWidget} and {\tt ButtonWidget} are based on the built-in
+  DOM elements. It would be nice if these didn't use the DOM.
+\item Many additional widgets could be created.
+\item Adjust the font used for figures in the browser to make it more
+  nearly identical to what appears in the PDF. 
+\item Color is entirely neglected on the \LaTeX\ end of \figput. Browser output
+  can be colored arbitrarily (with {\tt ctx.fillStyle} or {\tt
+    ctx.strokeStyle}, as usual), but the TikZ output is limited to
+  black and white. 
+\item Double-buffer everything. Animations seem to run fine,
+  without any noticeable flicker, but double-buffering \emph{all}
+  drawing would put an end to any concerns about flicker.
+\item Animations should be turned off and stop generating events when
+  they are scrolled out of view. This would save CPU cycles, which may
+  matter for documents with many animations.
+\end{itemize}
+
+\noindent And some items that are more ambitious...
+\begin{itemize}[itemsep=-1pt,leftmargin=*]
+\item Allow figures to be set within a {\tt minipage} (mentioned above).
+\item Double-clicking a figure (or something) could enlarge the figure
+  to give more room for interaction.
+\item Come up with a scheme so that the code that draws a figure could
+  be made part of the document. For certain topics, the code that
+  draws a figure can be as instructive as the figure itself.
+\item Extend the framework somehow so that it can be used within an
+  IDE. Code that's mathematically-oriented is difficult to
+  document within source code using simple text. It would be easier to
+  understand if it's explained as \LaTeX\ output that appears 
+  in the source code, rather than in a separate document.
+\item Extend the framework to allow inclusion of snippets of
+  \LaTeX\ output in standard HTML documents. Things like KaTeX and
+  MathJax are convenient, but incomplete relative to \LaTeX.
+\end{itemize}
+
+\newpage
+
+\subsection*{Version History}
+
+\begin{itemize}[itemsep = -3pt]
+\item{0.90} -- July 21, 2022. I've been using this, privately, for
+  several months. Numerous improvements and extensions are possible,
+  but it definitely works.
+\end{itemize}
+
+
+\vskip 0.3cm
+\hrule
+\vskip 0.3cm
+
+
+Thanks to Dan Pratt for insights regarding TypeScript, and
+improvements to the code.
+
+Several people on {\tt tex.stackexchange} very
+patiently answered numerous questions. Thank you.
+
+
+
+\end{document}


Property changes on: trunk/Master/texmf-dist/doc/latex/figput/figput-manual/figput-manual.tex
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: trunk/Master/texmf-dist/doc/latex/figput/javascript/development/layout.ts
===================================================================
--- trunk/Master/texmf-dist/doc/latex/figput/javascript/development/layout.ts	                        (rev 0)
+++ trunk/Master/texmf-dist/doc/latex/figput/javascript/development/layout.ts	2022-07-22 21:48:41 UTC (rev 63957)
@@ -0,0 +1,654 @@
+/*
+Code for page layout. The idea is a bit like Java Swing (or a zillion other
+similar setups), but stripped down to only what I need. In particular, the
+Panels are assumed to be stacked vertically.
+
+Everything is accessed through FullPanel, which consists of a list of
+PagePanel objects. These are stacked vertically, and each one contains at 
+least one PDFPanel, and may contain FigurePanels. In the lingo of something 
+like Java, it would be better to think of PagePanel as a Container or a Box 
+since it's used for layout and doesn't directly do anything other than pass 
+things to its sub-parts. 
+
+*/
+
+
+// This class is the only thing that should be touched by code outside
+// this file. FullPanel.init() is called to set up page layout.  Everything
+// is static since there is only one window/canvas.
+
+class FullPanel {
+  
+  // The full document consists of a list of PagePanel objects.
+  // thePages[i] is the i-th page, counting from zero.
+  public static thePages : PagePanel[] = [];
+  
+  // The width of the widest page of the entire document. Don't access
+  // this directly; use getFullWidth().
+  private static totalWidth : number = -1;
+  
+  
+  static init(specList : PageData[]) {
+    
+    // Add all the pages to this document. specList is PDFDocument.pageSpecs. 
+    // Each element of specList corresponds to page.
+    // Call this once, when the program starts, to set up the page layout.
+    let cumV = 0;
+    for (let i = 0; i < specList.length; i++)
+      {
+        let pp = new PagePanel(i,specList[i],cumV);
+        this.thePages[i] = pp;
+        cumV += pp.h;
+      }
+  }
+  
+  static async renderAll( height : number ) {
+    
+    // Render every PagePanel in FullPanel.thePages.
+    
+    // Internal to this function, the height should be in "page pixels," 
+    // meaning the number of pixels tall the destination canvas is at the 
+    // current zoom ratio of the offsreen pages.
+    height = height / PDFDocument.getZoom();
+    
+    // Because of the use of promises by pdf.js, rendering is broken into
+    // two steps: pre-render and the actual rendering. Pre-rendering
+    // generates a bunch of promises (the pages rendered offscreen) and
+    // rendering can't be done until those promises resolve.
+    let ps = [];
+    for (let i = 0; i < this.thePages.length; i++)
+      {
+        let p = this.thePages[i].preRender(height);
+        ps.push(p); 
+      }
+    
+    // Don't return until this is done! 
+    await Promise.all(ps);
+      
+    for (let i = 0; i < this.thePages.length; i++)
+      this.thePages[i].render(height);
+        
+    // Eliminate any excess pages from the buffer of offscreen pages.
+    // Do this after copying out, just in case there *is* some weird
+    // problem with race conditions.
+    PDFDocument.trimBuffer(); 
+  }
+  
+  static totalHeight() : number {
+    
+    // Return the total height of all pages. This is used to set up 
+    // the scroll bars.
+    let answer = 0;
+    for (let i = 0; i < this.thePages.length; i++)
+      answer += this.thePages[i].h;
+      
+    return answer;
+  }
+  
+  static getFullWidth() : number {
+    
+    // Return the width of the widest page. Most of the time, the pages of
+    // a document all have the same width, but they might not in some
+    // rare case. This is needed to center things left/right in the window.
+    if (this.totalWidth > 0)
+      return this.totalWidth;
+    
+    // Need to calculate it for the first time.
+    for (let i = 0; i < this.thePages.length; i++)
+      {
+        let pp = this.thePages[i];
+        if (pp.w > this.totalWidth)
+          this.totalWidth = pp.w;
+      }
+    
+    return this.totalWidth;
+  }
+  
+  static mouseDown(x : number , y : number ) : void {
+    
+    // (x,y) is in pdf points, relative to the  entire document.
+    // So y will be a huge number if it's on the umpteeth page.
+    
+    // To save CPU, I could start off by checking whether x is in 
+    // [0,pageWidth] and return if it is not, but the user might want to
+    // place controls outside the page. This is unlikely, but possible.
+    
+    // Whoever had focus loses it. It may be taken up by some other widget
+    // (or the same widget again), but nobody has focus by default.
+    WidgetManager.focusOwner = null;
+    
+    // Figure out which page this is and hand it off.
+    let i = 0; 
+    for ( ; i < this.thePages.length; i++)
+      {
+        if (this.thePages[i].v > y)
+          {
+            // Found the first and only page this could be. It was the
+            // page previous to this one.
+            i -= 1;
+            break;
+          }
+      }
+    
+    // If we got here then it had to be the very last page.
+    if (i === this.thePages.length)
+      i = this.thePages.length - 1;
+    
+    // Safety check:
+    if ((i == this.thePages.length) || (i < 0))
+     return;
+    
+    this.thePages[i].mouseDown(x,y);
+  }
+  
+  static mouseMove(x : number , y : number ) : void {
+    
+    // As above. However, these are only of interest if some widget
+    // "owns" the mouse -- something was clicked on so that motion
+    // could mean something.
+    if (WidgetManager.mouseOwner === null)
+      return;
+    
+    // Although we know exactly which widget will ultimately get this
+    // event, it's easier to let this pass through the layout hierarchy,
+    // just as for mouseDown(), so that the coordinates are properly adjusted.
+    // BUG: Not DRY.
+    let i = 0; 
+    for ( ; i < this.thePages.length; i++)
+      {
+        if (this.thePages[i].v > y)
+          {
+            i -= 1;
+            break;
+          }
+      }
+    
+    if (i === this.thePages.length)
+      i = this.thePages.length - 1;
+      
+    if ((i == this.thePages.length) || (i < 0))
+     return;
+    
+    this.thePages[i].mouseMove(x,y);
+  }
+  
+  static mouseUp(x : number , y : number ) : void {
+    
+    // The big issue here is that the mouse was released so that ownership 
+    // is once again up for grabs. In addition, certain widgets will want
+    // to know where the mouse was released. Buttons are a good example.
+    // You could have mouse-down on the button, then the user moves the
+    // mouse out of the button and releases it; the button should only be
+    // "clicked" if the mouse was released over the button.
+    //
+    // An annoying thing here is that the *only* widget that could care about
+    // this (at least, as designed) is the one that owns the mouse-down.
+    // As above, we want the event to pass through the layout hierarchy
+    // so that (x,y) is adjusted for the right frame, but the ultimate
+    // *consumer* of the event may not even be on the page where the
+    // mouse-up occured.
+    // BUG: Not DRY.
+    if (WidgetManager.mouseOwner === null)
+      return;
+      
+    let i = 0; 
+    for ( ; i < this.thePages.length; i++)
+      {
+        if (this.thePages[i].v > y)
+          {
+            i -= 1;
+            break;
+          }
+      }
+    
+    if (i === this.thePages.length)
+      i = this.thePages.length - 1;
+      
+    if ((i == this.thePages.length) || (i < 0))
+     return;
+    
+    this.thePages[i].mouseUp(x,y);
+    
+    // Whatever happened above, the mouse is now up for grabs.
+    WidgetManager.mouseOwner = null;
+  }
+  
+}
+
+
+// A PagePanel is the top-level thing, just under the canvas. Each
+// PagePanel makes up a single page of the printed document. There's
+// a list of them in FullPanel. It includes references to the PDFPanel 
+// and FigurePanel objects that it contains.
+
+class PagePanel {
+  
+  // Every panel has a vertical position within the entire document and height,
+  // in pdf pts. The vertical postion, v, is the top of the page, so the page
+  // extends from v to v+h. The caller must ensure that the Panels stack up
+  // correctly since there is no real page layout.
+  //
+  // In some ways the height, h, is redundant since it could be worked
+  // out from the heights of the individual sub-parts. In fact (see below)
+  // it *is* worked out by the constuctor, but it's easier to do it once
+  // and be done with it. This is the height of the page, as rendered,
+  // taking into account any mismatch due to extra "padding" in the figures
+  // (if there is any, and there often is not).
+  v = 0;
+  w = 0;
+  h = 0;
+  
+  // page number, counting from zero.
+  pageNum = 0;
+  
+  // The SubPanels that make up this PagePanel.
+  parts : SubPanel[] = [];
+  
+
+  constructor(pageNum : number , pageSpec : PageData , v : number) {
+    
+    // This implicitly applies to the global (because everything is static)
+    // PDFDocument. pageNum is which page this is, counting from zero.
+    // pageSpec has the info about how the page breaks into pieces and the
+    // relevant figures. v is where this page lies in the entire vertical 
+    // list of pages.
+    this.w = pageSpec.pageWidth;
+    this.v = v;
+    this.pageNum = pageNum;
+    
+    // Create the PDFPanels and FigurePanels in this PagePanel.
+    let s = pageSpec;
+    if (s.insertPoint.length == 0)
+      {
+        // There are no figures on this page.
+        let p = new PDFPanel(pageNum,this.v,0,0,this.v,this.w,s.pageHeight);
+        this.h = s.pageHeight;
+        this.parts = [p];
+      }
+    else
+      {
+        // There are figures.
+        let srcV = 0;
+        let destV = 0;
+        let totalV = v;
+        for (let j = 0; j < s.insertPoint.length; j++)
+          {
+            // Bit of pdf above figure.
+            let p = new PDFPanel(pageNum,this.v,srcV,destV,totalV,this.w,
+                s.insertPoint[j]-srcV);
+            destV += s.insertPoint[j]-srcV;
+            totalV += s.insertPoint[j]-srcV;
+            
+            let f = new FigurePanel( this.v , destV , totalV , this.w ,
+                      s.deleteHeight[j] + s.aboveHeight[j] + s.belowHeight[j] ,
+                      s.aboveHeight[j] , s.belowHeight[j] , s.leftMargin , 
+                      s.textWidth , s.drawFcn[j] );
+            
+            srcV = s.insertPoint[j] + s.deleteHeight[j];
+            destV += s.deleteHeight[j] + s.aboveHeight[j] + s.belowHeight[j];
+            totalV += s.deleteHeight[j] + s.aboveHeight[j] + s.belowHeight[j];
+            
+            this.parts.push(p);
+            this.parts.push(f);
+          }
+         
+        // And the bit of pdf below the last figure on the page.
+        let p = new PDFPanel(pageNum,this.v,srcV,destV,totalV,
+            this.w,s.pageHeight - srcV);
+        this.parts.push(p);
+        
+        this.h = destV + s.pageHeight - srcV
+      }
+  }
+  
+  async preRender( height : number ) {
+    
+    // This renders the underlying page of pdf. It returns a promise
+    // so that the caller can wait for the promise to resolve before
+    // attempting to copy from the rendered page.
+    //
+    // The vpos is where the top of the ctx should be relative to the entire
+    // document, in pdf pts, and height is how much is visible, in rendered
+    // page pixels.
+    // The first question is whether any of this page is visible.
+    let vpos = window.scrollY;
+    if (this.v + this.h < vpos)
+      // Entire page is above the visible area.
+      return;
+    if (this.v > vpos + height)
+      // Entire page is below the visible area.
+      return;
+    
+    // Got here, so some portion of the page is visible.
+    await PDFDocument.render(this.pageNum);
+  }
+  
+  render( height : number ) : void {
+    
+    // Render every SubPanel of the current PagePanel.
+    
+    // BUG: Before returning, turn off any of these animations that are
+    // definitely not visible.
+    let vpos = window.scrollY;
+    if (this.v + this.h < vpos)
+      return;
+    if (this.v > vpos + height)
+      return;
+    
+    // Got here, so some portion of the page is visible. From here on, 
+    // render everything, whether it's actually visible or not.
+    let ctx = ctxTopLevelAdjust();
+    
+    // Call the parts of the page. These could be PDFPanel or FigurePanel
+    // objects.
+    for (let i = 0; i < this.parts.length; i++)
+      this.parts[i].render();
+    
+    // BUG: I don't like this use of zoom here. Maybe no choice?
+    let z = PDFDocument.getZoom();
+    
+    // Put a rectangle aroud the entire page. I'm not 100% convinced that
+    // I like this.
+    ctx.strokeStyle = "black";
+    ctx.strokeRect(0,0,this.w*z,this.h*z);
+  }
+  
+  mouseDown(x : number , y : number ) : void {
+    
+    // Mouse clicked on this page.
+    
+    // y is given relative to the entire document; make it page-relative.
+    y -= this.v;
+    
+    // Only clicks on a figure could be of interest.
+    for (let i = 0; i < this.parts.length; i++)
+      {
+        // Either a PDFPanel or a FigurePanel.
+        let p = this.parts[i];
+        if (p instanceof PDFPanel)
+          continue;
+        
+        // p must be a FigurePanel.
+        if ((p.destV <= y) && (y <= p.destV + p.h))
+          return p.mouseDown(x,y);
+      }
+  }
+  
+  mouseMove(x : number , y : number ) : void {
+    
+    // As above. Note that this event could go to the "wrong" figure,
+    // but that's OK. Also, if the mouse is over a PDFPanel, and not
+    // a figure, then the event dies here, which is also OK.
+    y -= this.v;
+    
+    for (let i = 0; i < this.parts.length; i++)
+      {
+        let p = this.parts[i];
+        if (p instanceof PDFPanel)
+          continue;
+       
+        if ((p.destV <= y) && (y <= p.destV + p.h))
+          p.mouseMove(x,y);
+      } 
+  }
+  
+  mouseUp(x : number , y : number ) : void {
+    
+    // As above, but the event can't be allowed to die. The owning widget
+    // must hear about the mouse up. At the same time, we can't just
+    // inform the widget directly of the mouse up since we also need to
+    // pass the correct coordinates. 
+    y -= this.v;
+    
+    for (let i = 0; i < this.parts.length; i++)
+      {
+        let p = this.parts[i];
+        
+        // This is different than above since *somebody* must take the event,
+        // and the relevant widget must hear about it. If the event is over
+        // a PDFPanel, then tell the widget using crazy coordinates. It 
+        // doesn't matter exactly where the mouse was released; it only 
+        // matters that it wasn't released anywhere near the widget.
+        if ((p.destV <= y) && (y <= p.destV + p.h))
+          {
+            if (p instanceof PDFPanel)
+              WidgetManager.mouseOwner ! .mouseUp(10000000000000,10000000000000);
+            else
+              // Over a figure.
+              p.mouseUp(x,y);
+          }   
+      }
+  }
+}
+
+
+// A PagePanel consists of one or more SubPanels.
+
+abstract class SubPanel {
+  
+  // The vertical position and height within a page, with zero being at the
+  // top, and measured in pdf points. This height, h, is the total height.
+  // There's no ambiguity to this height for PDFPanel subclasses, but for
+  // FigurePanel subclasses, it is the sum of the latex height 
+  // (PageData.deleteHeight), plus any additional padding as given in 
+  // PageData.aboveHeight/belowHeight.
+  destV = 0;
+  h = 0;
+  w = 0;
+  
+  // The position of this panel within the entire document.
+  // The only reason for this is the possible use of HTML DOM elements
+  // as widgets within a figure. I would prefer not to use those at all,
+  // but sometimes it's easier. See the NumberInputWidget for one example.
+  totalV = 0;
+  
+  
+  constructor(v : number , totalV : number , w : number , h : number ) {
+    this.destV = v;
+    this.totalV = totalV;
+    this.w = w;
+    this.h = h;
+  }
+  
+  // Will be filled in by sub-class.
+  public render( ) : void { 
+    console.log("Error: called SubPanel.render()!");
+  }
+  public mouseDown(x : number , y : number ) : void {
+    console.log("Error: called SubPanel.mouseDown()!");
+  }
+  public mouseMove(x : number , y : number ) : void {
+    console.log("Error: called SubPanel.mouseMove()!");
+  }
+  public mouseUp(x : number , y : number ) : void {
+    console.log("Error: called SubPanel.mouseUp()!");
+  }
+  
+}
+
+
+// Used for portions of a page consisting of rendered pdf.
+
+class PDFPanel extends SubPanel {
+  
+  // The page numbers start at zero and positions are given in pdf points.
+  pageNum = 0;
+  srcV = 0;
+
+  // BUG: I think I can fold this in elsewhere. It's the same as PagePanel.v.
+  offsetV = 0;
+  
+  constructor(pageNum : number , offsetV : number , srcV : number , destV : number , 
+        totalV : number , w : number , h : number ) {
+    
+    // The pageNum is given relative to the global PDFDocument. The srcV
+    // and destV are locations relative to the page (in pdf points, with the
+    // top of the page at v=0) and h is the height of this piece, which
+    // is the same for src and dest.
+    super(destV,totalV,w,h);
+    this.pageNum = pageNum;
+    this.srcV = srcV;
+    this.offsetV = offsetV;
+  }  
+  
+  render( ) : void {
+    
+    // Render a portion of the current page. 
+
+    let theCanvas = PDFDocument.getCanvas(this.pageNum) ;
+    if (theCanvas === null)
+      {
+        // I'm sure how this happens, but it does occasionally.
+        // It doesn't cause any noticable problems. It seems to happen
+        // if you move the scroll thumb too fast.
+        return;
+      }
+    
+    // BUG: I don't like this use of zoom here. Maybe no choice?
+    let z = PDFDocument.getZoom();
+
+    let ctx = ctxTopLevelAdjust();
+
+    // Adjust for scroll bar.
+    ctx.translate(0,(this.offsetV - window.scrollY) * z);
+
+    // Arguments here: 
+    // the source image (or canvas),
+    // the source (x,y),
+    // the source (width,height),
+    // the destination (x,y),
+    // the destination (width,height),
+    // It's confusing because optional things typically come after
+    // required things, but not here somehow.
+    ctx.drawImage(theCanvas,
+        0,this.srcV * z,theCanvas.width,this.h * z,
+        0,this.destV*z,theCanvas.width,this.h*z);
+  }
+}
+
+class FigurePanel extends SubPanel {
+  
+  // Function name, as a string.
+  drawFcn : AugmentedDrawingFunction;
+
+  // Page's v position. This is the position of the page on which
+  // this figure appears relative to the entire document.
+  pageV : number = 0;
+  
+  // This margin is the location of the left edge of the text, as
+  // reported by latex.
+  margin = 0;
+  
+  // Also from Latex (via figures.aux). This I have more confidence in.
+  textWidth = 0;
+  
+  // The height in SubPanel.h is the total height of the figure, including
+  // any padding above or below. The origin used for the figure occurs at
+  // a y-value that is PageData.belowHeight *above* the total height.
+  // lowerPadding is equal to PageData.belowHeight for this figure.
+  lowerPadding = 0;
+  upperPadding = 0;
+  
+
+  constructor(pageV : number, destV : number , totalV : number , w : number , h : number ,
+        upperPadding : number , lowerPadding : number , margin : number ,
+        textWidth : number , drawFcn : AugmentedDrawingFunction) {
+    
+    // As for PDFPanel, plus the margin is the amount by which to shift the 
+    // drawing to the right so that the origin is in line with the text.The 
+    // drawFcn is the function provided through Latex.
+    // This is just the name of the function, as a string.
+    super(destV,totalV,w,h);
+    this.pageV = pageV;
+    this.upperPadding = upperPadding;
+    this.lowerPadding = lowerPadding;
+    this.margin = margin;
+    this.textWidth = textWidth;
+    this.drawFcn = drawFcn;
+  }
+  
+  render( ) : void {
+    
+    // Save this for widgets and animations to use.
+    let ctx = ctxTopLevelAdjust();
+
+    let z = PDFDocument.getZoom();
+    ctx.translate(0,(this.pageV - window.scrollY) * z);
+
+    // Erase the full width of the page. this.w is the correct width,
+    // but the origin will be shifted for drawing. So, erase, then 
+    // return the origin to where it was and start over.
+    
+    // Shift to where the figure appears and erase.
+    ctx.translate(0,this.destV * z);
+    ctx.scale(z,z);
+    
+    // The small adjustment here is to prevent erasing the rectangle
+    // that encloses the entire page.
+    ctx.clearRect(1,0,this.w-2,this.h);
+    
+    // Return to the orginal t-matrix, then shift down and right before
+    // drawing the figure (and widgets).
+    // What we want is for the origin to be at the lower-right and
+    // right-handed, adjusted upwards by this.lowerPadding too.
+    ctx = ctxTopLevelAdjust();
+    ctx.translate(0,(this.pageV - window.scrollY) * z);
+    ctx.translate(this.margin * z,(this.destV + this.h - this.lowerPadding) * z);
+    ctx.scale(1,-1);
+    ctx.scale(z,z);
+
+    // Tack this FigurePanel onto the underlying figure-drawing code.
+    // The first time the figure is rendered, this is set, and it's re-set
+    // to the same value with every subsequent call. That seems like 
+    // pointless extra work, but it gets the job done.
+    this.drawFcn.figurePanelClass = this;
+    this.drawFcn(ctx);
+  }
+
+  mouseDown(x : number , y : number ) : void {
+    
+    // (x,y) is in pdf points, relative to the top-left of the page.
+    
+    // Adjust to be relative to the figure, but still LH, relative
+    // to the top of the figure.
+    y -= this.destV;
+    x -= this.margin;
+
+    // y is now given relative to the top edge of the figure, getting
+    // larger as you go *down* the page.
+    
+    // Convert y to be RH relative to the correct origin, taking
+    // any padding into account. This is confusing. At this stage,
+    // y is the distance below the figure's top edge. Call that y0.
+    // We want the distance above the lower padding (if any); call
+    // that y1. The distance above the lower *edge* of the figure 
+    // is this.h - y0, and from this we subtract the padding.
+    y = (this.h - y) - this.lowerPadding;
+    
+    // Pass to the relevant widget.
+    WidgetManager.mouseDown(this.drawFcn,x,y);
+  }
+  
+  mouseMove(x : number , y : number ) : void {
+    
+    // As above.
+    y -= this.destV;
+    x -= this.margin;
+    
+    y = (this.h - this.lowerPadding) - y;
+    
+    WidgetManager.mouseMove(this.drawFcn,x,y);
+  }
+  
+  mouseUp(x : number , y : number ) : void {
+    
+    // As above.
+    y -= this.destV;
+    x -= this.margin;
+    
+    y = (this.h - this.lowerPadding) - y;
+    
+    WidgetManager.mouseUp(this.drawFcn,x,y);
+  }
+}
+

Added: trunk/Master/texmf-dist/doc/latex/figput/javascript/development/main.ts
===================================================================
--- trunk/Master/texmf-dist/doc/latex/figput/javascript/development/main.ts	                        (rev 0)
+++ trunk/Master/texmf-dist/doc/latex/figput/javascript/development/main.ts	2022-07-22 21:48:41 UTC (rev 63957)
@@ -0,0 +1,1086 @@
+/* 
+
+Main entry point for all the js code behind the browser interface.
+ 
+This has the initialization code, to load the pdf and the data specifying 
+how figures are drawn and laid out, plus the top-level stuff to direct 
+events to the proper place for handling.
+
+The same code is used for developing the document, and for serving it
+from a public-facing website, with a few changes. Look for "PUBLIC FACING"
+annotations. Note also that it would be possible to strip considerably
+more code away for the public-facing version, but there's no pressing
+reason to do it -- the savings would be tiny -- and it could lead to
+an error of some kind due to unforeseen dependencies on the deleted
+code.
+
+*/
+
+
+// In rare cases, I need to know the browser. Note it first, before doing
+// anything else. This userAgent is a longish bit of blather specifying
+// the browser, and the easiest way to deal with it is to check whether
+// certain strings appear.
+
+var theBrowser = function() {
+  
+  let blah = navigator.userAgent;
+  
+  if (blah.indexOf("Firefox") > -1)
+    return "Firefox";
+  
+  // MS Edge is also "Chrome," at least for my purposes.
+  if (blah.indexOf("Chrome") > -1) 
+    return "Chrome";
+  
+  // Assume "Chrome" as the default.
+  console.log("MAKING DEFAULT 'CHROME' ASSUMPTION ABOUT THE BROWSWER!!!");
+  return "Chrome";
+}(); 
+
+
+// JS has poor to non-existent facilities for dealing with thread scheduling.
+// In a lot of JS code that doesn't matter, but the pdf.js library, on which
+// this entire thing rests, makes heavy use of Promises and workers. Fortunately, 
+// there's a simple way of managing this. 
+//
+// To use this, the caller says
+// await sleep(100);
+// and the "await" is crucial. This works because setTimeout() takes a 
+// function to run, and some amount of time to wait before running that
+// function. 
+//
+// This isn't a satisfying solution because it requires "await."
+// For that reason it can only be used in async functions.
+
+function sleep(ms : number) : Promise<unknown> {
+  
+  // ms is milliseconds, not microseconds. 
+  return new Promise(resolve => setTimeout(resolve,ms));
+}
+
+
+// Some semi-bogus stuff to quiet the ts compiler...
+
+// This makes the external library known to tsc.
+declare var pdfjsLib : any;
+
+// And this provides the properties known to pdfjs that belong to a pdf. 
+// I had hoped to define a blank type, and have done with it, but we need 
+// access to certain fields. This provides the type information that
+// pdf.js lacks -- or at least the minimal information that I need.
+type LoadedPDF = {
+  numPages : number;
+  getPage : (n : number) => Promise<any>;
+};
+
+// This is less bogus. It's the type of the functions called to draw the figures.
+// These functions have an added property that points to the
+// correct FigurePanel widget. See the layout code. 
+// Declaring these types serves to warn the programmer what's ahead. It also
+// provides tsc with the information it needs to prevent certain mistakes.
+type BaseDrawingFunction = (ctx : CanvasRenderingContext2D | CTX) => void;
+type AugmentedDrawingFunction = BaseDrawingFunction & { figurePanelClass : FigurePanel | null; };
+
+
+function getAugmentedFunction(fcnName : string ) : AugmentedDrawingFunction {
+  
+  // This converts from a function name, as specified by the user in their latex
+  // document to the internally more useful AugmentedDrawingFunction. Doing this
+  // kind of conversion feels icky, but any alternative I've come up with requires
+  // that the person using FigPut know more than the absolute minimum about what's
+  // behind the curtain.
+  //
+  // References to these functions come into the program at two points. First, when
+  // the document is loaded, a list of the relevant drawing functions is provided
+  // by latex. Second, when the user creates widgets within his drawings, these 
+  // widgets must belong to a particular drawing and the function (or its name, as
+  // a string) is used as the key under which the widget is filed.
+  
+  // BUG: This double-cast and use of 'any' is horrible, but is there
+  // anything better?
+  return <AugmentedDrawingFunction> <unknown> window[ fcnName as any ];
+}
+
+
+// Data related to the document pages and figures. Each page
+// has one of these in PDFDocument.pageSpecs. This is all
+// static data once the document has been loaded.
+
+// BUG: Should this be a type? An interface?
+
+class PageData {
+  
+  // Note that pageHeight is the height of a *printed* page. If the page
+  // has a figure whose height is different than the deleted height, then
+  // the page height, as rendered, will be different than this value.
+  // Also, the margins and textWidth are only valid when there is a
+  // figure to render since they come from figures.aux.
+  // For reference, 8.5 x 11 inch paper is 612 x 792 pts; 
+  // A4 paper is 8.27 x 11.69 inch or 595.44 x 841.68 pts.
+  // However, it seems that latex sometimes produces slightly different
+  // dimensions of what must be A4 paper.
+  pageHeight : number = 0;
+  pageWidth : number = 0;
+  leftMargin : number = 0;
+  rightMargin : number = 0;
+  textWidth : number = 0;
+  
+  // These arrays have one entry for each interactive figure on the page.
+  // insertPoint is the position, from the top, at which the figure is
+  // inserted. deleteHeight is how much of the latex doc is omitted, and
+  // above/belowHeight is how much room to leave in the browser window for
+  // the figure. name is the name of the function to call to draw the
+  // figure, done is whether to generate new tikz
+  insertPoint : number[] = [];
+  deleteHeight : number[] = [];
+  aboveHeight : number[] = [];
+  belowHeight : number[] = [];
+  name : string[] = [];
+  done : boolean[] = [];
+  
+  // For each figure, there is a corresponding function (that will be
+  // augmented with a drawing target). These values make the name values
+  // given above conceptually redundant.
+  drawFcn : AugmentedDrawingFunction[] = [];
+}
+
+
+// Everything related to the pdf document is here. Its main purpose is 
+// to handle off-screen rendering. It's all static since there can only be
+// one pdf open at a time. It does include data about how to lay out the 
+// figures, but none of the code that does it.
+//
+// I tried making this a module, but really no advantage over a class,
+// and definitely some disadvantages.
+
+class PDFDocument {
+  
+  // The document, as returned by pdfjsLib.getDocument.
+  private static pdf : LoadedPDF;
+  
+  // Total number of pages in the above document.
+  public static numberOfPages = 0;
+  
+  // This is the scale at which to to render the pages offscreen. Setting
+  // this equal to 1 means that each px of the off-screen canvas is 1 pdf
+  // point. 
+  private static zoom : number = 1;
+    
+  // Information about the layout, one for each page.
+  public static pageSpecs : PageData[] = [];
+  
+  // The fields below are a temporary buffer of pages rendered offscreen.
+  // This speeds up the process so that we aren't re-rendering pages.
+  // My original intent was for these arrays to have no more than 
+  // pageBufSize entries, but the way async/promise works makes that
+  // difficult (impossible?). I want render() to render a given page
+  // to an offscreen canvas and store that canvas here, which means
+  // that all these calls to render() share the variables below.
+  // Each call to render() is, unavoidably, in a different thread, and
+  // that means that they are all trying to manipulate these varaibles
+  // in an order that is unpredictable. The only way that I can see to
+  // make this happen in a predicatable way is for each page to have
+  // its own canvas. It's OK for render() to put things into its designated
+  // spot in an array, but it can't touch anything that some other invocation
+  // of render might touch.
+  //
+  // This is wasteful, but I see no other way to do it without using
+  // a mutex. It's not that bad since we're talking about a few bytes for 
+  // every page, but still annoying.
+  //
+  // Aside: JS does have the Atomics object, as of ECMA 2017, and it 
+  // might (?) be possible to use that somehow as a way to synchronize
+  // threads, but I'd rather not mess with it.
+  
+  
+  // The total number of pages that may be held. This needs to be at least 
+  // as large as the number of pages that may be visible at one time if you
+  // zoom all the way out, plus a couple extra due to possible problems
+  // resulting from race conditions that I can't (?) avoid.
+  private static pageBufSize : number = 6;
+  
+  // This holds a copy of page to be copied to the screen. Every page has 
+  // its own entry, although all but (at most) pageBufSize will be null.
+  private static theCanvases : (HTMLCanvasElement | null)[] = [];
+  
+  // The renderCount is how many times we've rendered any page. It's used like
+  // a time since I have no confidence in window.performance.now, which is
+  // supposed to return the current time in nanoseconds. Every time a page
+  // is asked to be rendered, this value increments, and is stored in
+  // pageAge[i], where i is the index of the page rendered. It may not 
+  // actually be rendered if it would be a re-render, but the time is updated.
+  // We need this to flush older pages from the buffer when there are too many.
+  // 
+  // NOTE: This variable is shared by the various invocations of render()
+  // and something like
+  // ++renderCount
+  // is not an atomic operation. The way I am using this, the fact that
+  // the value of renderCount may be incorrect isn't a disaster. It can
+  // only be wrong by a few steps. This is why pageBufSize is bumped up to be a
+  // little larger than strictly necessary. Worst case, things are re-rendered 
+  // and you waste some CPU.
+  private static renderCount : number = 0;
+  
+  // One of these for each page, indexed by page number. Holds the value
+  // or renderCount at the time when the page was rendered (or re-rendered).
+  private static pageAge : number[] = [];
+  
+  
+  public static async setPDF(thePDF : LoadedPDF) {
+    
+    // Take the newly loaded pdf and note some of it's stats.
+    // Once this is loaded, thePDF never needs to be accessed again
+    // from outside this class.
+    this.pdf = thePDF;
+    
+    this.numberOfPages = thePDF.numPages;
+  
+    // It seems that pdfjs counts pages from one, not zero.
+    for (let i = 1; i <= this.numberOfPages; i++)
+      {
+        await thePDF.getPage(i).then(function(page) {
+          
+          // Note the i-1 here since I want arrays to start at zero.
+          PDFDocument.pageSpecs[i-1] = new PageData();
+          PDFDocument.pageSpecs[i-1].pageWidth = page.view[2];
+          PDFDocument.pageSpecs[i-1].pageHeight = page.view[3];
+          
+          // Make sure that the shared buffer arrays are all fully allocated.
+          PDFDocument.theCanvases[i-1] = null;
+          PDFDocument.pageAge[i-1] = 0;
+        });
+      }
+  }
+  
+  public static isLoaded() : boolean {
+    if (this.pdf === null)
+      return false;
+    else
+      return true;
+  }
+  
+  public static getZoom() : number {
+    return this.zoom;
+  }
+  
+  public static setZoom(z : number) : void {
+    
+    this.zoom = z;
+    this.flushBuffer();
+  }
+  
+  public static getCanvas(n : number) {
+    
+    // Return the canvas for page number n (counting from zero). 
+    // This assumes that the canvas is available due to a previous
+    // call to render(n) -- which must have resolved by the time this
+    // method is called.
+    
+    // BUG: This shouldn't happen, but maybe I should create a fake
+    // blank canvas anyway.
+    if (this.theCanvases[n] === null)
+      console.log("ERROR! Canvas for page missing: " +n);
+      
+    return this.theCanvases[n];
+  }
+  
+  public static async render(n : number ) {
+    
+    // Render page n offscreen, where the pages are counted from zero.
+    
+    // See if the page is already there.
+    if (PDFDocument.theCanvases[n] !== null)
+      return;
+    
+    // Note the +1 here since pdf.js counts pages from 1, not zero.
+    let thePage = await PDFDocument.pdf.getPage(n + 1);
+    
+    let newCanvas : HTMLCanvasElement = document.createElement('canvas');
+    PDFDocument.theCanvases[n] = newCanvas;
+    PDFDocument.pageAge[n] = PDFDocument.renderCount;
+    ++PDFDocument.renderCount;
+    
+    let offctx = newCanvas.getContext('2d');
+    let viewport = thePage.getViewport(PDFDocument.zoom);
+    
+    newCanvas.width = viewport.width;
+    newCanvas.height = viewport.height;
+    
+    await thePage.render({
+      canvasContext: offctx,
+      viewport: viewport
+    });
+  }
+  
+  public static trimBuffer() : void {
+    
+    // Call this periodically, like after making a series of calls to
+    // render(), to remove excess canvases from the buffer arrays.
+    // Due to the risk of race conditions -- which I think is minimal --
+    // it's best not to call this until reaching a point at which it 
+    // doesn't matter if *all* the offscreen canvases are deleted (although
+    // that outcome would be inefficient). The unlikely possiblitity of
+    // problems due to race conditions is why this is not part of render().
+    let ctot = 0;
+    for (let i = 0; i < PDFDocument.numberOfPages; i++)
+      {
+        if (PDFDocument.theCanvases[i] !== null)
+          ++ctot;
+      }
+    
+    // Delete excess offscreen canvases.
+    while (ctot > PDFDocument.pageBufSize)
+      {
+        PDFDocument.removeOldestPage();
+        --ctot;
+      }
+  }
+  
+  private static removeOldestPage() : void {
+    
+    // Remove the oldest single canvas from this.theCanvases.
+    let oldestIndex = -1;
+    let oldestAge = this.pageAge[0];
+    for (let i = 0; i < this.numberOfPages; i++)
+      {
+        if (this.theCanvases[i] === null)
+          continue;
+        
+        if (this.pageAge[i] < oldestAge)
+          {
+            oldestAge= this.pageAge[i];
+            oldestIndex = i;
+          }
+      }
+    this.theCanvases[oldestIndex] = null;
+  }
+  
+  public static flushBuffer() : void {
+    
+    // Removes all offscreen canvases in the buffer. This is needed, e.g.,
+    // when resizing so that you don't use a canvas of the wrong scale.
+    for (let i = 0; i < this.numberOfPages; i++)
+      this.theCanvases[i] = null;
+  }
+}
+
+
+// A class for scheduling event handling. 
+//
+// Everything is static because there is only one of these for all events. 
+// It is used to mediate the event loop so that everything happens 
+// syncrhonously, even when async functions are involved. It is used for 
+// things like scroll and mouse-down events; it is also used for animations, 
+// which are created by certain widgets.
+//
+// The idea is that you call getID() to get your ticket (like at the
+// butcher's). Then call await waitMyTurn() until the butcher is ready.
+// The 'await' is crucial! Then call allDone() to thank the butcher and 
+// leave so that he can take the next customer.
+//
+// For this to work properly, calls to getID() must be made outside
+// of async functions. Otherwise the IDs could get out of order.
+//
+// BUG: I could use this in a DRY-er way. Define a method called
+// getInLine() that takes the function to be invoked. Have getInLine()
+// call getID(), waitMyTurn(), run the job, then call allDone().
+//
+// BUG: It may be that someone who is more expert in JS could use
+// Promises somehow to make this scheme unnecessary. OTOH, this may
+// be easier to understand and use than something more clever.
+class Events {
+  
+  // A count of events that have come in. Each event gets its own unique
+  // ID by calling getID().
+  private static count : number = 0;
+  
+  // The ID number of the event whose handling was most recently completed.
+  private static complete : number = -1;
+  
+  public static getID() {
+    let answer = this.count;
+    this.count++;
+    return answer;
+  }
+  
+  public static async waitMyTurn(id : number) {
+    while (id !== Events.complete + 1)
+      await sleep(5);
+  }
+  
+  public static allDone(id : number) {
+    Events.complete = id;
+  }
+}
+
+
+async function doOpenDocument(latexName : string , scrollPos : number ) {
+  
+  // Called when the body of the page loads (onload).
+  // latexName is the base of the name of the pdf. Thus, latexName.pdf
+  // is what is to be opened. The scrollPos value is the position on the
+  // page. This is provided by doBeforeUnload(), noted by the server, and
+  // given back in the course of the reload.
+  
+  // The "Get TikZ" button is fixed, and it is always on top.
+  // PUBLIC FACING: Comment this block of code out when running serving from a 
+  // public-facing website. There's no reason to provide this "Get TikZ" button 
+  // and the server won't now how to handle the resulting messages.
+  
+  let fmenu = document.createElement("button");
+  fmenu.style.position = "fixed";
+  fmenu.style.display = "block";
+  fmenu.style.left = "0px";
+  fmenu.style.top = "0px";
+  fmenu.style.width = "80px";
+  fmenu.style.height = "18px";
+  fmenu.style.fontSize = "10px";
+  fmenu.textContent = "Get TikZ";
+  fmenu.style.zIndex = "99";
+  fmenu.onclick = doTikzClick;
+  document.body.appendChild(fmenu);
+  
+
+  let theCanvas = <HTMLCanvasElement> document.getElementById("pdf_renderer")!;
+  theCanvas.style.position = "fixed";
+  
+  // It might happen that the program starts with some level of zoom.
+  PDFDocument.setZoom(window.devicePixelRatio);
+  
+  // So that the canvas exactly fills the window.
+  adjustCanvas();
+  
+  // Mouse events are registered on the canvas rather than the document
+  // (as is done for resize and scroll), but I'm not sure there's any 
+  // practical difference since the canvas is the whole document.
+  // Note that this does *not* listen for onclick events. In a few cases,
+  // they might be a more natural choice (like for buttons), but they make
+  // things like coloring a "halfway clicked" widget difficult.
+  // Note that this does not distinguish between left, right and middle
+  // buttons; a click is a click.
+  // Also, the mouseup listener is registered on the window, not the canvas,
+  // so that we hear about mouse-ups even when they happen outside the
+  // browswer window entirely.
+  theCanvas.addEventListener("mousedown",doMouseDown);
+  theCanvas.addEventListener("mousemove",doMouseMove);
+  theCanvas.addEventListener("mouseup",doMouseUp);
+  
+  // I considered registering listeners for mouseenter/mouseleave, but
+  // they're not needed.
+  
+  /*
+  BUG: I have not tested this much on touch devices. Everything
+  works fine on some phones, but not on others. It's a hard to imagine
+  people trying to use this on a phone, but I should test on things
+  like iPads.
+  theCanvas.addEventListener("touchstart",doTouchDown);
+  theCanvas.addEventListener("touchend",doTouchUp); 
+  theCanvas.addEventListener("touchmove",doTouchMove);
+  */
+ 
+  // Open the pdf and digest figures.aux.
+  await getDocumentData(latexName);
+  
+  // Create the various Panel objects that make up the document as a whole.
+  // This does the "page layout."
+  FullPanel.init(PDFDocument.pageSpecs);
+  
+  // Now that page layout is done, set the range for the scroll bars on 
+  // the browswer window.
+  adjustScrollBars();
+  
+  // When reloading, we don't want things to move back to the top of
+  // the first page.
+  window.scrollTo(0 , scrollPos);
+  
+  // Render for the very first time.
+  fullRender();
+}
+
+async function getDocumentData(latexName : string) {
+   
+  // This opens and digests the data files and the pdf itself. 
+  let thePDF : LoadedPDF = await pdfjsLib.getDocument(latexName+ '.pdf');
+  await PDFDocument.setPDF(thePDF);
+  
+  // Open and digest figures.aux.
+  let fname = latexName + ".fig.aux";
+  
+  // fetch() is the new XMLHttpRequest(), which has been deprecated.
+  // Thanks to Dan Pratt for pointing that out.
+  let fetchPromise = await fetch(fname);
+  let allText = await fetchPromise.text();
+  await getFigureInfo(allText);
+}
+
+async function syncLoad(scriptName : string) {
+  
+  // Load the script with the given name and append to the DOM, and
+  // don't return until the load is complete. So this should typically
+  // be called with 'await'.
+  // 
+  // Thanks to Dan Pratt for this tidy solution. This works because the
+  // promise can't resolve (either way) until appendChild() completes
+  // because you can't resolve or reject until the code is loaded
+  // or fails to load. Note that the 'once' argument means that the function
+  // is called once, then flushed. That's exactly what I want so that they
+  // don't hang around and consume resources.
+  let theCode = document.createElement("script");
+  theCode.type = "application/javascript";
+  theCode.src = scriptName;
+
+  var p = new Promise((resolve, reject) => {
+    theCode.addEventListener("load", resolve, { once: true});
+    theCode.addEventListener("error", reject, { once: true});
+  });
+
+  document.body.appendChild(theCode);
+
+  await p;
+}
+
+async function getFigureInfo(textBody : string) {
+  
+  // textBody is the complete contents of the .aux file. Parse it and
+  // use the data to fill in PDFDocument.PageSpecs.
+  let lines = textBody.split('\n');
+  
+  for (let i = 0; i < lines.length; i++)
+    {
+      if (lines[i].length < 2)
+        // Last line might be blank.
+        break;
+      
+      var parts = lines[i].split(' ');
+      
+      if (parts[0] === "load")
+        {
+          // Load a single .js file and move on.
+          await syncLoad(parts[1]);
+          continue;
+        }
+      
+      var pnum = parseInt(parts[0]);
+      var innerMargin = parseFloat(parts[1]);
+      var outerMargin = parseFloat(parts[2]);
+      var textWidth = parseFloat(parts[3]);
+      var vpos = parseFloat(parts[4]);
+      var hLatex = parseFloat(parts[5]);
+      var hAbove = parseFloat(parts[6]);
+      var hBelow = parseFloat(parts[7]);
+      var name : string = parts[8];
+      
+      // Careful: JS weirdness means that Boolean(parts[9]) is ALWAYS true 
+      // (unless parts[9] is empty).
+      var done : boolean = (parts[9] === 'true');
+      var externLoad : boolean = (parts[10] === 'true');
+     
+      // Page numbers should start at zero (not 1 as reported by latex).
+      pnum -= 1;
+      
+      // Load the JS now, if necessary.
+      // NOTE: In earlier versions, up to v23, I looked to either a
+      // .js file or an .fjs file. Individual files are now assumed
+      // to be .fjs files. This is much simpler.
+      if (externLoad === true)
+        await syncLoad(name + ".fjs");
+      
+      // NOTE: This assumes that the relevant function has been loaded,
+      // perhaps as an external file from \LoadFigureCode.
+      let augFcn : AugmentedDrawingFunction = getAugmentedFunction( name );
+      if (typeof augFcn === "undefined")
+        alert(name + " not found. Is the function name correct?");
+      
+      // Note this for the future.
+      augFcn.figurePanelClass = null;
+      PDFDocument.pageSpecs[pnum].drawFcn.push(augFcn);
+      
+      // Copy the remaining fields over.
+      
+      // Adjust the vertical position to be given relative to the top
+      // of the page, rather than the bottom.
+      vpos = PDFDocument.pageSpecs[pnum].pageHeight - vpos;
+      
+      // If there are multiple figures on a particular page, then this
+      // is redundant, but harmless.
+      if (pnum % 2 === 0)
+        {
+          PDFDocument.pageSpecs[pnum].leftMargin = innerMargin;
+          PDFDocument.pageSpecs[pnum].rightMargin = outerMargin;
+        }
+      else
+        {
+          PDFDocument.pageSpecs[pnum].leftMargin = outerMargin;
+          PDFDocument.pageSpecs[pnum].rightMargin = innerMargin;
+        }
+      PDFDocument.pageSpecs[pnum].textWidth = textWidth;
+      
+      // The per-figure data.
+      PDFDocument.pageSpecs[pnum].insertPoint.push(vpos);
+      PDFDocument.pageSpecs[pnum].deleteHeight.push(hLatex);
+      PDFDocument.pageSpecs[pnum].aboveHeight.push(hAbove);
+      PDFDocument.pageSpecs[pnum].belowHeight.push(hBelow);
+      PDFDocument.pageSpecs[pnum].name.push(name);
+      PDFDocument.pageSpecs[pnum].done.push(done);
+    }
+  
+  // Make sure that all the figure names are distinct.
+  for (let i = 0; i < PDFDocument.numberOfPages; i++)
+    {
+      // Loop over each figure on the current page.
+      for (let fig = 0; fig < PDFDocument.pageSpecs[i].name.length; fig++)
+        {
+          let curName = PDFDocument.pageSpecs[i].name[fig];
+        
+          // See if this name matches a name on any other page/figure.
+          // Consider the current page first.
+          for (let subfig = fig + 1; subfig < PDFDocument.pageSpecs[i].name.length; subfig++)
+            {
+              if (curName === PDFDocument.pageSpecs[i].name[subfig])
+                {
+                  alert("The figure name " +curName+ " is used more than once.");
+                  throw new Error();
+                }
+            }
+          
+          // Continue with all the remaining pages.
+          for (let j = i + 1; j < PDFDocument.numberOfPages; j++)
+            {
+              for (let subfig = 0; subfig < PDFDocument.pageSpecs[j].name.length; subfig++)
+                {
+                  if (curName === PDFDocument.pageSpecs[j].name[subfig])
+                    {
+                      alert("The figure name " +curName+ " is used more than once.");
+                      throw new Error();
+                    }
+                }
+            }
+        }
+    }
+}
+
+function adjustScrollBars() : void {
+  
+  // Based on the page size and document length, adjust the range of the 
+  // browswer's scroll bars.
+  var body = <HTMLElement> document.getElementById("mainbody");
+  
+  // I don't see any way to set the range of the scroll bar directly, so
+  // I'm fooling the browser to think that it has a body of a certain
+  // height, in px, when the body is really no bigger than the visible
+  // area of the window. What I want is a height such that, when the scroll
+  // bar is at the bottom, the lower edge of the last page is barely visible
+  // in the bottom of the window.
+  //
+  // There was some mental debate about whether it's better to let the
+  // bottom of the last page scroll up beyond the bottom of the window, but
+  // this is easier to program, and it's probably more natural for most people.
+  let totHeight = FullPanel.totalHeight();
+  let visHeight = document.documentElement.clientHeight;
+  body.style.height = totHeight + "px";
+  
+  // The horizontal scroll bar is expressed in terms of pdf pts. This is
+  // simpler than above since I don't want to be able to scroll so that the 
+  // right edge of the document is barely off the window; I want to be able 
+  // to scroll just far enough so that the right edge of the document meets 
+  // the right edge of the window. The size of the window becomes irrelevant
+  // (i.e., the browser deals with it).
+  // However, we do need to know whether a scroll bar is needed at all, 
+  // so we can't totally ignore the visible width.
+  let visWidth = document.documentElement.clientWidth;
+  let totWidth = FullPanel.getFullWidth();
+  
+  if (visWidth > totWidth)
+    {
+      // No need for horizontal scroll. It seems like "0px" works, but "0 px"
+      // does not. Maybe the space causes a (silent) parse error?
+      body.style.width = "0px";
+      return;
+    }
+    
+  body.style.width = totWidth + "px";
+}
+
+function ctxTopLevelAdjust( ) : CanvasRenderingContext2D {
+
+  // Each function should call this before doing any drawing.
+  // Rendering is done relative to the ctx (obviously) with the t-matrix
+  // adjusted accordingly. This brings the t-matrix from being the 
+  // identity to being relative to the entire document.
+  //
+  // In earlier versions, the ctx was being passed around and adjusted
+  // as the layout manager descended to a particular portion of the document.
+  // In some ways that is the cleaner and more modular way to do things,
+  // but it can be confusing because the adjustments to the t-matrix aren't
+  // done in a central place.
+  var canvas = <HTMLCanvasElement> document.getElementById("pdf_renderer");
+  let ctx : CanvasRenderingContext2D = canvas.getContext('2d') ! ;
+
+  ctx.resetTransform(); 
+
+  // Center the document. Rather than mess with CSS to center the canvas, 
+  // leave the canvas at the size of the entire window, and shift the origin 
+  // so the document is rendered in the center of the canvas.
+  //
+  // However, if the window is smaller than the document, then we do
+  // NOT want to center the document. If we did center it, then it would
+  // be impossible to scroll over to the left since we can't have "negative
+  // scroll;" window.scrollX is always non-negative (unfortunately).
+  let visWidth = document.documentElement.clientWidth;
+  let totWidth = FullPanel.getFullWidth();
+  let z = PDFDocument.getZoom();
+  if (visWidth > totWidth)
+    {
+      // No horizontal scroll bar. Center it.
+      let canvasCenter = canvas.width / 2;
+      let docCenter = FullPanel.getFullWidth() / 2;
+      docCenter *= PDFDocument.getZoom();
+      
+      ctx.translate(canvasCenter - docCenter,0);
+    }
+  else
+    { 
+      // Shift according to the horizontal scroll bar, leaving the document
+      // against the left edge. Note the scaling by the zoom factor so
+      // as to be consistent with the above.
+      ctx.translate(-window.scrollX * PDFDocument.getZoom(),0);
+    }
+
+  return ctx;
+}
+
+async function fullRender() {
+
+  // Render all the pages of the pdf, together with the figures.
+  var canvas = <HTMLCanvasElement> document.getElementById("pdf_renderer");
+  
+  // This shouldn't be necessary, but do it as a fail-safe.
+  var ctx = <CanvasRenderingContext2D> canvas.getContext('2d');
+  ctx.resetTransform();
+  
+  let visWidth = document.documentElement.clientWidth;
+  
+  let z = PDFDocument.getZoom();
+  
+  // BUG: Could lead to flicker? It is necessary to clear everything
+  // because widgets could be drawn outside the page. I suppose that I could
+  // only erase the area outside the pages, which would reduce any flicker.
+  // I really don't want to double-buffer everything if it can be avoided.
+  // It may be the only solution. The problem is that, if a widget extends 
+  // outside the page, and is animated (like LoopAnimWidget) so that it's
+  // drawn as part of an animation, then you must erase the entire page to
+  // avoid "leftovers," and *that* requires that you redraw the entire 
+  // document (or what is visible) with every frame of an animation.
+  //
+  // BUG: So the correct solution is double-buffering everything, but I don't 
+  // feel that it's pressing. For now, either restrict any widgets to 
+  // draw within a page or accept that it might leave spoogey leftovers.
+  ctx.clearRect(0,0,visWidth*z,document.documentElement.clientHeight*z);
+
+  await FullPanel.renderAll(canvas.height);
+}
+
+function adjustCanvas() : void {
+  
+  // Call when the window has been zoomed or re-sized.
+  // 
+  // canvas has two different dimensions: canvas.style.width and height, and 
+  // canvas.width and height. The style values determine the size of the canvas 
+  // on the screen -- so-called ""CSS styling." The straight values (no style)
+  // are the number of px in the canvas. By keeping the style values constant and
+  // varying the straight values, you can have more or less resolution for the
+  // canvas, EVEN WHEN ZOOMED IN.
+  //
+  // The bottom line is that if we adjust the straight pixel sizes, then
+  // we can always have one px for every physical pixel -- up to the accuracy
+  // of window.devicePixelRatio.
+  //
+  // BUG: Check for things with super high pixel density, like phones. I
+  // think the devicePixelRatio is somehow wrong for those. It may not matter.
+  var canvas = <HTMLCanvasElement> document.getElementById("pdf_renderer") ;
+  
+  // Adjust the visible width to match the window size. 
+  //
+  // NOTE: For debugging, it can be helpful to subtract off a bit from these
+  // values, like 1, 10 or 50, depending. In earlier versions, there was
+  // also a bit of CSS in the html that put a visible rectangle around the canvas.
+  //canvas.style.width = (document.documentElement.clientWidth - 50) + "px";
+  //canvas.style.height = (document.documentElement.clientHeight - 50) + "px";
+  canvas.style.width = document.documentElement.clientWidth + "px";
+  canvas.style.height = document.documentElement.clientHeight + "px";
+  
+  // The visible width of the canvas has just been fixed. Now change the
+  // number of px so that the number of px per inch on the screen varies with
+  // the level of browser zoom. There seems to be no means of direct access 
+  // to the phyical pixels of the monitor, but this is close, and may be 
+  // exactly equivalent in many situations.
+  canvas.width = document.documentElement.clientWidth * window.devicePixelRatio;
+  canvas.height = document.documentElement.clientHeight * window.devicePixelRatio;
+}
+
+async function doScrollGuts(id : number) {
+  
+  // Wait for any active event handler to finish and then wait until it is
+  // the turn of current id to run.
+  await Events.waitMyTurn(id);
+  
+  await fullRender();
+  
+  // Give your ticket to the butcher so that he can take the next customer.
+  Events.allDone(id);
+}
+
+function doScroll() : void {
+  
+  // Scroll events are registered below to call this function.
+  // It redraws the contents of the main canvas.
+  
+  // This appears to be called when the page is opened, before almost
+  // anything else, so return until page initialization is complete.
+  if (PDFDocument.isLoaded() == false)
+    return;
+    
+  // Get a unique ID for this event.
+  // This must be done outside any async function to ensure proper order.
+  let id = Events.getID();
+  
+  doScrollGuts(id);
+}
+
+async function doResizeGuts(id : number) {
+  
+  // As with scrolling, wait for any earlier event handler to complete.
+  await Events.waitMyTurn(id);
+  
+  // None of the buffered offscreen canvases are valid anymore.
+  // In theory, I could test for whether this was merely a window
+  // resize and not a zoom, but it's not worth fooling with.
+  PDFDocument.flushBuffer();
+   
+  console.log("ratio: " + window.devicePixelRatio);
+  
+  // The other thing that needs to be adjusted is the zoom level
+  // used when rendering the pdfs. 
+  adjustCanvas();
+  
+  // Here is the magic. Effectively, this value is now the level of zoom.
+  // If you take out this line, and leave PDFDocument.zoom always equal to
+  // default value of 1, then zooming does nothing, although the mismatch
+  // between the resolution of the off-screen canvas and the resolution on
+  // the screen can make things blurry or blocky.
+  PDFDocument.setZoom(window.devicePixelRatio);
+  
+  // If the size of the window changed, then this needs to be adjusted too.
+  // This must be done after adjustCanvas().
+  adjustScrollBars();
+  
+  // Render the pages too.
+  await fullRender();
+  
+  // Final bit of scheduling magic.
+  Events.allDone(id);
+}
+
+function doResize() : void {
+  
+  // This is called whenever the user zooms and also if the
+  // entire broswer window is resized.
+  let id = Events.getID();
+  doResizeGuts(id); 
+}
+
+async function mouseDownGuts(id : number , x : number , y : number ) {
+  
+  // (x,y) is the location of the mouse click, in pdf points, but
+  // relative to the window.
+  await Events.waitMyTurn(id);
+  
+  // Just as we have to tweak the t-matrix to determine where to draw things, 
+  // we need to do something similar to figure out where (x,y) is on the page.
+  // The difference is that the ctx.translate() operations become adjustments 
+  // to x and y.
+  let visWidth = document.documentElement.clientWidth;
+  let totWidth = FullPanel.getFullWidth();
+  let canvas = <HTMLCanvasElement> document.getElementById("pdf_renderer");
+  
+  if (visWidth > totWidth)
+    {
+      // No horizontal scroll bar. The document is centered.
+      let canvasCenter = canvas.width / 2;
+      let docCenter = FullPanel.getFullWidth() / 2;
+      canvasCenter = canvasCenter / PDFDocument.getZoom();
+      
+      x = x - (canvasCenter - docCenter);
+    }
+  else
+    { 
+      // Shift according to the horizontal scroll bar.
+      x = x + window.scrollX;
+    }
+  
+  // Fix up the y-coordinate too.
+  y = y + window.scrollY;
+  
+  FullPanel.mouseDown(x,y);
+  
+  // Don't forget!
+  Events.allDone(id);
+}
+
+function doMouseDown(e : MouseEvent) : void {
+  
+  // This is an event like any other, so the usual scheduling rigmarole.
+  let id = Events.getID();
+  mouseDownGuts(id,e.x,e.y);
+}
+
+async function mouseMoveGuts(id : number , x : number , y : number ) {
+  
+  // As above.
+  // BUG: Common code. Not DRY.
+  await Events.waitMyTurn(id);
+  
+  // As for mouse-down.
+  let visWidth = document.documentElement.clientWidth;
+  let totWidth = FullPanel.getFullWidth();
+  let canvas = <HTMLCanvasElement> document.getElementById("pdf_renderer");
+  
+  if (visWidth > totWidth)
+    {
+      // No horizontal scroll bar. The document is centered.
+      let canvasCenter = canvas.width / 2;
+      let docCenter = FullPanel.getFullWidth() / 2;
+      canvasCenter = canvasCenter / PDFDocument.getZoom();
+      
+      x = x - (canvasCenter - docCenter);
+    }
+  else
+    { 
+      // Shift according to the horizontal scroll bar.
+      x = x + window.scrollX;
+    }
+  
+  // Fix up the y-coordinate too.
+  y = y + window.scrollY;
+  FullPanel.mouseMove(x,y);
+  
+  // Don't forget!
+  Events.allDone(id);
+}
+
+function doMouseMove(e : MouseEvent) :void {
+  
+  // As above.
+  let id = Events.getID();
+  mouseMoveGuts(id,e.x,e.y);
+}
+
+async function mouseUpGuts(id : number , x : number , y : number ) {
+  
+  // As above.
+  // BUG: Common code. Not DRY.
+  await Events.waitMyTurn(id);
+  
+  let visWidth = document.documentElement.clientWidth;
+  let totWidth = FullPanel.getFullWidth();
+  let canvas = <HTMLCanvasElement> document.getElementById("pdf_renderer");
+  
+  if (visWidth > totWidth)
+    {
+      // No horizontal scroll bar. The document is centered.
+      let canvasCenter = canvas.width / 2;
+      let docCenter = FullPanel.getFullWidth() / 2;
+      canvasCenter = canvasCenter / PDFDocument.getZoom();
+      
+      x = x - (canvasCenter - docCenter);
+    }
+  else
+    { 
+      // Shift according to the horizontal scroll bar.
+      x = x + window.scrollX;
+    }
+  
+  // Fix up the y-coordinate too.
+  y = y + window.scrollY;
+  FullPanel.mouseUp(x,y);
+  
+  // Don't forget!
+  Events.allDone(id);
+}
+
+function doMouseUp(e : MouseEvent ) : void {
+  
+  // As above. 
+  let id = Events.getID();
+  mouseUpGuts(id,e.x,e.y);
+}
+
+function doTikzClick() : void {
+  
+  // Tikz button was clicked. Generate output file(s).
+  // 
+  // Cycle over every figure and let it generate tikz data.
+  for (let pi = 0; pi < PDFDocument.pageSpecs.length; pi++)
+    {
+      let pd = PDFDocument.pageSpecs[pi] !;
+      if (pd.name.length === 0)
+        // No figures on this page.
+        continue;
+      
+      for (let fi = 0; fi < pd.name.length; fi++)
+        { 
+          if (pd.done[fi] == true)
+            // User said to skip this one.
+            continue;
+          
+          let theFcn : AugmentedDrawingFunction = pd.drawFcn[fi];
+          
+          if (theFcn.figurePanelClass === null)
+            // Hasn't been loaded, because was never visible.
+            continue;
+          
+          let ctx = new CTX(pd.name[fi]);
+          theFcn(ctx);
+          ctx.close();
+        }
+    }
+}
+
+
+function doBeforeUnload(e : Event) {
+  
+  // This is *very* non-standard. Pass a made-up WHERE message with the position
+  // on the document.
+  // BUG: This only informs the server of the vertical scroll position.
+  // Dealing with horizontal scroll would be more painful. See fullRender()
+  // and adjustScrollBars().
+  // If *everything* were double-buffered, then this would be a bit easier.
+  let req = new XMLHttpRequest();
+  
+  // We don't care about the second argument. In a POST this would be
+  // something like a file name. The third argument, 'false', forces the request
+  // to be handled synchronously. If it's done async, then the unload proceeds
+  // and completes before this task finishes.
+  req.open("WHERE","bogus", false );
+    
+  req.setRequestHeader("Content-Type","text/plain;charset=UTF-8");
+  
+  // Send the postion as the message. It could probaby be sent instead of
+  // 'bogus' above, and this could be blank.
+  let msg = window.scrollY.toString();
+  
+  // BUG: Firefox generates "Uncaught DOMException: A network error occurred."
+  // on this. It might be that XMLHttpRequest is deprecated?
+  req.send(msg);
+}
+
+// Register additional event handlers. The main (and only) canvas had 
+// listeners registered for mouse events in doOpenDocument().
+document.addEventListener('scroll',doScroll);
+window.addEventListener('resize', doResize);
+
+// PUBLIC FACING: Comment this out. It's doing something *very* non-standard,
+// and any normal web-server will choke on it.
+window.addEventListener('beforeunload',doBeforeUnload);
+

Added: trunk/Master/texmf-dist/doc/latex/figput/javascript/development/tikz.ts
===================================================================
--- trunk/Master/texmf-dist/doc/latex/figput/javascript/development/tikz.ts	                        (rev 0)
+++ trunk/Master/texmf-dist/doc/latex/figput/javascript/development/tikz.ts	2022-07-22 21:48:41 UTC (rev 63957)
@@ -0,0 +1,1419 @@
+/*
+Code necessary to output tikz for figures. It spoofs the normal canvas
+drawing code so that the output comes here, and is then converted to 
+tizk output.
+
+One problem with JS is that there is no path interator. You can't obtain 
+the segments that make up an entire path. I don't see any way around this 
+other than writing my own wrapper around Path2D. It might be possible to
+somehow hack the internals of Path2D, but that would be brittle, even if 
+it works.
+
+BUG: The long-term solution is to eliminate use of the JS Path2D class,
+but it's not possible to entirely eliminate it since it's the only way to
+draw to the browser window. What I *could* do is sub-class
+CanvasRenderingContext2D so that this sub-class take my own path class
+objects and converts them to Path2D for drawing. Another hurdle is 
+isPointInPath(), which is used in a few places. I could provide a separate 
+implementation of that, but it's fiddly. isPointInStroke() is a bit harder.
+
+BUG: It's tempting to come up with a framework under which a "path"
+is closer to our intuition of something that can be drawn as a continuous
+thing, without lifting your pencil. Then, have a second-order thing that
+may hold several of these continuous paths. Intuitively one wants a "path"
+to have a clear start-point and end-point, but you also need to be able
+to handle things like winding number for multiple paths when filling.
+
+BUG: There are many cases where you might want the online version to be
+different from what is printed. I just gave the example of filling a path,
+and color is similar. There's lots of things that might make sense on a
+computer screen, but wouldn't work well on printed paper.
+
+*/
+
+
+// Turns out that Point used to be part of js, but was deprecated, and
+// seems not to exist any longer.
+
+class Point2D {
+
+  private _x : number;
+  private _y : number;
+
+  constructor(x : number,y : number) {
+    this._x = x;
+    this._y = y;
+  }
+
+  public toString() : string {
+
+    // May be handy for debugging.
+    return "( " + this._x.toFixed(2) + "," + this._y.toFixed(2) + ")";
+  }
+  
+  public get x() : number {
+    return this._x;
+  }
+
+  public get y() : number {
+    return this._y;
+  }
+
+  public copy() : Point2D {
+    return new Point2D( this._x , this._y );
+  }
+  
+  public negate() : Point2D {
+    // return -this.
+    return new Point2D(-this._x,-this.y);
+  }
+  
+  public negateSelf() : void {
+  
+    this._x = -this.x;
+    this._y = -this.y;
+  }
+  
+  public minus(p : Point2D) : Point2D {
+    
+    // return this - p. Redunant since it's just a form of translation.
+    return new Point2D( this._x - p.x  , this._y - p.y );
+  }
+  
+  public minusSelf(p : Point2D) : void {
+    
+    this._x -= p._x;
+    this._y -= p._y;
+  }
+
+  public translate2(u : number, v : number) : Point2D {
+    return new Point2D( u + this._x , v + this._y );
+  }
+
+  public translate(p : Point2D) : Point2D {
+    return new Point2D( p.x + this._x , p.y + this._y );
+  }
+
+  public translateSelf2(u : number, v : number) : void {
+
+    this._x += u;
+    this._y += v;
+  }
+
+  public translateSelf(p : Point2D) : void {
+
+    this._x += p.x;
+    this._y += p.y;
+  }
+
+  public scale(s : number) : Point2D {
+    return new Point2D( s * this._x , s * this._y );
+  }
+
+  public scaleSelf(s : number) : void {
+
+    // As above, but it's done in-place rather than returning a copy.
+    this._x *= s
+    this._y *= s;
+  }
+  
+  public rotate(theta : number) : Point2D {
+
+    // Apply rotation matrix in the usual (RH) way. theta in radians.
+    let c = Math.cos(theta);
+    let s = Math.sin(theta);
+    return new Point2D ( 
+      c * this._x - s * this._y ,
+      s * this._x + c * this._y
+    );
+  }
+  
+  public rotateSelf(theta : number) : void {
+    
+    let c = Math.cos(theta);
+    let s = Math.sin(theta);
+    
+    let u = c * this._x - s * this._y ;
+    let v = s * this._x + c * this._y ; 
+
+    this._x = u;
+    this._y = v;
+  }
+  
+  public rotateAbout(c : Point2D , theta : number ) : Point2D {
+    
+    // Rotate this about c by angle theta, returning the result.
+    let answer = new Point2D(this.x - c.x , this.y - c.y );
+    answer = answer.rotate( theta );
+    answer._x += c.x;
+    answer._y += c.y;
+    return answer;
+  }
+  
+  public dot(a : Point2D) : number {
+
+    // Return this dot a.
+    return a.x * this._x + a.y * this._y;
+  }
+
+  public length() : number {
+    return Math.sqrt(this._x**2 + this._y**2);
+  }
+
+  public static dot(a: Point2D , b : Point2D) : number {
+    // This looks like Java-style overloading, but it's not. One dot()
+    // is static and the other is not.
+    return a.dot(b);
+  }
+
+  public angleBetween( a : Point2D ) : number {
+
+    // Return angle between this and a, based on
+    // this dot a = |this| |a| cos angle
+    // This is the angle between the two, without any orientation.
+    let cos = this.dot(a) / (this.length() * a.length() );
+    return Math.acos(cos);
+  }
+  
+  public cliffordBetween( a : Point2D) : number {
+    
+    // The "clifford angle," which is like angleBetween(), but it takes
+    // orientation into account. The angle is given relative to ("from") this.
+    return Math.atan2( this.x * a.y - a.x * this.y ,
+      this.x * a.x + this.y * a.y );
+  }
+}
+
+// Used for a function of the form f(t) = ( x(t) , y(t) ).
+type Parametric2DFunction = (t : number) => Point2D;
+
+// BUG: Really, these should be based on Point2D. E.g., bezier should be three Point2D objects.
+type CloseSegment = {};
+
+type MoveToSegment = {
+  x : number;
+  y : number;
+}
+
+type LineToSegment = {
+  x : number;
+  y : number;
+}
+
+type BezierToSegment = {
+  cx1 : number;
+  cy1 : number;
+  cx2 : number;
+  cy2 : number;
+  x : number;
+  y : number;
+}
+
+type QuadToSegment = {
+  cx : number;
+  cy : number;
+  x : number;
+  y : number;
+}
+
+type ArcSegment = {
+  x : number;
+  y : number;
+  r : number; 
+  a0 : number;
+  a1 : number;
+  ccw : boolean;
+}
+
+type ArcToSegment = {
+  x1 : number;
+  y1 : number;
+  x2 : number;
+  y2 : number;
+  r : number; 
+}
+
+type EllipseSegment = {
+  x : number;
+  y : number;
+  rx : number; 
+  ry : number;
+  rot : number;
+  a0 : number;
+  a1 : number;
+  ccw : boolean;
+}
+
+type RectSegment = {
+  x : number;
+  y : number;
+  w : number; 
+  h : number;
+}
+
+type SegmentData = CloseSegment | MoveToSegment | LineToSegment | BezierToSegment |
+        ArcSegment | ArcToSegment | EllipseSegment | RectSegment;
+
+        
+// Almost everything here is static because this is essentially a factory for the
+// various segment types.
+
+class PathSegment {
+  
+  // The various kinds of segment.
+  // I'm being sloppy about typing here since the use is uncomplicated and
+  // private. Some kind of enumerated type would be better in the abstract.
+  
+  // BUG: I should get rid of anything after the QUADRATIC type. The
+  // mathematically clean way to do this is to convert *everything* to beziers,
+  // including ellipses. In fact (?) is a quadratic just a cubic where the
+  // control points coincide? If so, I could get rid of QUADRATIC too.
+  static readonly MOVE_TO = 1;
+  static readonly LINE_TO = 2;
+  static readonly BEZIER = 3;
+  static readonly QUADRATIC = 4;
+  static readonly ARC = 5;
+  static readonly ARC_TO = 6;
+  static readonly ELLIPSE = 7;
+  static readonly RECT = 8;
+  static readonly CLOSE = 9;
+  static readonly UNKNOWN = -1
+  
+  // One of the values above.
+  public type = PathSegment.UNKNOWN;
+  
+  // The relevant data.
+  // BUG: change variable name to seg.
+  s : SegmentData;
+    
+  private constructor(kind : number , d : SegmentData) {
+    this.type = kind;
+    this.s = d;
+  }
+  
+  static getClose() : PathSegment {
+    let d : CloseSegment = {};
+    return new PathSegment(PathSegment.CLOSE,d);
+  }
+  
+  static getMoveTo(x : number , y : number ) : PathSegment {
+    let d : MoveToSegment = { x : x , y : y };
+    return new PathSegment(PathSegment.MOVE_TO,d);
+  }
+  
+  static getLineTo( x : number, y : number ) : PathSegment {
+    let d : LineToSegment = {x : x , y : y }
+    return new PathSegment(PathSegment.LINE_TO,d);
+  }
+  
+  static getBezier(cx1 : number , cy1 : number , cx2 : number , cy2 : number ,
+        x  : number , y : number ) : PathSegment {
+    let d : BezierToSegment = 
+        {cx1 : cx1 , cy1 : cy1 , cx2 : cx2 , cy2 : cy2 , x : x , y : y};
+    return new PathSegment(PathSegment.BEZIER, d );
+  }
+  
+  static getQuadratic(cx : number , cy : number , x : number , y : number ) : PathSegment {
+    let d : QuadToSegment = { cx : cx , cy : cy , x : x , y : y };
+    return new PathSegment(PathSegment.QUADRATIC , d );
+  }
+  
+  static getArc(x : number , y : number , r  : number , a0 : number , a1 : number ,
+           ccw : boolean) : PathSegment {
+    let d : ArcSegment = { x : x , y : y , r : r , a0 : a0 , a1 : a1 , ccw : ccw };
+    return new PathSegment(PathSegment.ARC , d );
+  }
+  
+  static getArcTo(x1 : number , y1 : number , x2 : number , y2 : number ,
+         r : number ) : PathSegment {
+    let d : ArcToSegment = { x1 : x1 , y1 : y1 , x2 : x2 , y2 : y2 , r : r };
+    return new PathSegment(PathSegment.ARC_TO , d );
+  }
+  
+  static getEllipse(x : number , y : number , rx : number , ry : number , rot : number ,
+          a0 : number , a1 : number , ccw : boolean ) : PathSegment {
+    // BUG: If I convert everything to bezier, then many of these static
+    // methods can be eliminated.
+    // YES. THIS IS A BAD IDEA IN EVERY WAY. ONLY BEZIER CURVES SHOULD
+    // BE ALLOWED INTERNALLY.
+    // OTOH, there are certain shapes, like an ellipse or rectangle, that
+    // should be treated as a single unitary thing.
+    // What I should probably do is sub-class FPath for these. Interally, they
+    // can be represented as a messy bezier thing, but that would be hidden from the user.
+    // At the same time, one might want to add an ellipse or rect to an existing path to
+    // obtain various fill effects. So, the ellipse sub-class will need something like
+    // a toFPath() method so that it can be added to a normal FPath.
+    let d : EllipseSegment = { x : x , y : y , rx : rx , ry : ry , rot : rot , a0 : a0 ,
+              a1 : a1 , ccw : ccw };
+    return new PathSegment(PathSegment.ELLIPSE , d );
+  }
+  
+  static getRect(x : number , y : number , w : number , h : number ) : PathSegment {
+    let d : RectSegment = { x : x , y : y , w : w , h : h };
+    return new PathSegment(PathSegment.RECT , d );
+  }
+  
+}
+
+
+// BUG: Add some flags so that things could be drawn or not drawn based
+// on whether the output is going to tikz or to the screen. 
+
+class FPath extends Path2D {
+  
+  // An array of PathSegments.
+  segs : PathSegment[] = [];
+  
+  
+  constructor() {
+    super();
+  }
+  
+  addPath(p : FPath ) : void {
+    
+    // Append the elements of p to this. 
+    for (let i = 0; i < p.segs.length; i++)
+      this.segs.push(p.segs[i]);
+  }
+  
+  closePath () : void {
+    super.closePath();
+    this.segs.push(PathSegment.getClose());
+  }
+  
+  moveTo(x : number , y : number) : void {
+    super.moveTo(x,y);
+    this.segs.push(PathSegment.getMoveTo(x,y));
+  }
+  
+  frontLineTo(x : number , y : number ) : void {
+    
+    // To tack a line segment to the *begining* of an existing path.
+    // This assumes that segs[0] is a moveTo() -- as I think (?) it must be
+    // in any reasonable case. 
+    // So, you start with a path that looks like
+    // moveTo(a,b) ...whatever
+    // and it becomes
+    // moveTo(x,y) lineTo(a,b) ...whatever.
+    // You're basically drawing as usual, but "from the wrong end."
+    let s = this.segs[0];
+    if (s.type != PathSegment.MOVE_TO)
+      console.log("ERROR: frontLineTo() doesn't start with moveTo(): " +s.type);
+    
+    let newfirst = PathSegment.getMoveTo(x,y);
+    
+    // Convert the initial moveto to a lineto.
+    // In fact, this is sort of pointless, and is only done this way to respect
+    // the type-checker. It's (x,y) whether it's a lineto or a moveto.
+    let m = <MoveToSegment> s.s;
+    let newsecond = PathSegment.getLineTo(m.x,m.y);
+    
+    this.segs[0] = newsecond;
+    this.segs.unshift(newfirst);
+  }
+  
+  lineTo(x : number , y : number ) : void {
+    super.lineTo(x,y);
+    this.segs.push(PathSegment.getLineTo(x,y));
+  }
+  
+  bezierCurveTo(cx1 : number , cy1 : number , cx2 : number , cy2 : number ,
+         x : number , y : number ) : void {
+    super.bezierCurveTo(cx1,cy1,cx2,cy2,x,y);
+    this.segs.push(PathSegment.getBezier(cx1,cy1,cx2,cy2,x,y));
+  }
+  
+  quadraticCurveTo(cx : number , cy : number , x : number , y : number ) : void {
+    super.quadraticCurveTo(cx,cy,x,y);
+    this.segs.push(PathSegment.getQuadratic(cx,cy,x,y));
+  }
+  
+  translate(p : Point2D) : FPath {
+    
+    // Translate this entire path by the given point.
+    
+    // BUG: Not implemented for every possible type of segment.
+    
+    let answer = new FPath();
+    for (let i = 0; i < this.segs.length; i++)
+      {
+        let s = this.segs[i];
+        if (s.type == PathSegment.MOVE_TO)
+          {
+            let m = <MoveToSegment> s.s;
+            answer.moveTo(m.x + p.x,m.y + p.y);
+          }
+        else if (s.type == PathSegment.LINE_TO)
+          {
+            let m = <LineToSegment> s.s;
+            answer.lineTo(m.x + p.x,m.y + p.y);
+          }
+        else if (s.type == PathSegment.BEZIER)
+          {
+            let m = <BezierToSegment> s.s;
+            answer.bezierCurveTo( m.cx1 + p.x , m.cy1 + p.y ,
+                m.cx2 + p.x , m.cy2 + p.y , m.x + p.x , m.y + p.y );
+          }
+        else if (s.type == PathSegment.ELLIPSE)
+          {
+            let m = <EllipseSegment> s.s;
+            answer.ellipse(m.x+p.x,m.y+p.y , m.rx, m.ry, m.rot , m.a0 , m.a1 , m.ccw);
+          }
+        else
+          {
+            console.log("whatever translattion you want, it's not done.");
+          }
+      }
+    
+    return answer;
+  }
+  
+  rotate( a : number ) : FPath {
+    
+    // Rotate this entire path about the origin and return the result.
+    
+    // BUG: I have only implemented this for bezier curves and lines.
+    // Expanding this probably doesn't make sense until I settle on a
+    // framework to more fully replace Path2D.
+    
+    let answer = new FPath();
+    for (let i = 0; i < this.segs.length; i++)
+      {
+        let s = this.segs[i];
+        if (s.type == PathSegment.MOVE_TO)
+          {
+            let m = <MoveToSegment> s.s;
+            let p = new Point2D( m.x , m.y ).rotate( a );
+            answer.moveTo(p.x,p.y);
+          }
+        else if (s.type == PathSegment.LINE_TO)
+          {
+            let m = <LineToSegment> s.s;
+            let p = new Point2D( m.x , m.y ).rotate( a );
+            answer.lineTo(p.x , p.y);
+          }
+        else if (s.type == PathSegment.BEZIER)
+          {
+            let m = <BezierToSegment> s.s;
+            let c1 = new Point2D( m.cx1 , m.cy1 ).rotate( a );
+            let c2 = new Point2D( m.cx2 , m.cy2 ).rotate( a );
+            let e = new Point2D( m.x , m.y ).rotate( a );
+            answer.bezierCurveTo(c1.x,c1.y,c2.x,c2.y,e.x,e.y);
+          } 
+        else
+          {
+            console.log("whatever rotation you want, it's not done.");
+          }
+      }
+    
+    return answer;
+  }
+  
+  scale( r : number ) : FPath {
+    
+    // Scale this entire path about the origin and return the result.
+    
+    // BUG: I have only implemented this for bezier curves and lines.
+    
+    let answer = new FPath();
+    for (let i = 0; i < this.segs.length; i++)
+      {
+        let s = this.segs[i];
+        if (s.type == PathSegment.MOVE_TO)
+          {
+            let m = <MoveToSegment> s.s;
+            let p = new Point2D( r * m.x , r * m.y );
+            answer.moveTo(p.x,p.y);
+          }
+        else if (s.type == PathSegment.LINE_TO)
+          {
+            let m = <LineToSegment> s.s;
+            
+            // BUG:
+            console.log("scale not done for lines");
+          }
+        else if (s.type == PathSegment.BEZIER)
+          {
+            let m = <BezierToSegment> s.s;
+            let c1 = new Point2D( r * m.cx1 , r* m.cy1 );
+            let c2 = new Point2D( r * m.cx2 , r * m.cy2 );
+            let p = new Point2D( r * m.x , r * m.y );
+            answer.bezierCurveTo(c1.x,c1.y,c2.x,c2.y,p.x,p.y);
+          } 
+        else
+          {
+            console.log("whatever scale you want, it's not done.");
+          }
+      }
+    
+    return answer;
+  }
+  
+  reflectX() : FPath {
+    
+    // Reflect this entire path about the x-axis and return the result.
+    
+    // BUG: not implemented for every case.
+    
+    let answer = new FPath();
+    for (let i = 0; i < this.segs.length; i++)
+      {
+        let s = this.segs[i];
+        if (s.type == PathSegment.MOVE_TO)
+          {
+            let m = <MoveToSegment> s.s;
+            let p = new Point2D( m.x , -m.y );
+            answer.moveTo(p.x,p.y);
+          }
+        else if (s.type == PathSegment.LINE_TO)
+          {
+            let m = <LineToSegment> s.s;
+            let p = new Point2D( m.x , -m.y);
+            answer.lineTo(p.x,p.y);
+          }
+        else if (s.type == PathSegment.BEZIER)
+          {
+            let m = <BezierToSegment> s.s;
+            let c1 = new Point2D( m.cx1 , -m.cy1 );
+            let c2 = new Point2D( m.cx2 , -m.cy2 );
+            let p = new Point2D( m.x , -m.y );
+            answer.bezierCurveTo(c1.x,c1.y,c2.x,c2.y,p.x,p.y);
+          } 
+        else if (s.type == PathSegment.ELLIPSE)
+          {
+            let m = <EllipseSegment> s.s;
+            answer.ellipse(m.x,-m.y,m.rx,m.ry,m.rot,m.a0,m.a1,m.ccw);
+          }
+        else
+          {
+            console.log("whatever reflect you want, it's not done.");
+          }
+      }
+    
+    return answer;
+  }
+  
+  reflectXY() : FPath {
+    
+    // Reflect this entire path about the x-axis AND y-axis.
+    
+    // BUG: not implemented for every case.
+    // BUG: Also, what about reflectY()?
+    
+    let answer = new FPath();
+    for (let i = 0; i < this.segs.length; i++)
+      {
+        let s = this.segs[i];
+        if (s.type == PathSegment.MOVE_TO)
+          {
+            let m = <MoveToSegment> s.s;
+            let p = new Point2D( -m.x , -m.y );
+            answer.moveTo(p.x,p.y);
+          }
+        else if (s.type == PathSegment.LINE_TO)
+          {
+            let m = <LineToSegment> s.s;
+            // BUG:
+            console.log("reflect not done for lines");
+          }
+        else if (s.type == PathSegment.BEZIER)
+          {
+            let m = <BezierToSegment> s.s;
+            let c1 = new Point2D( -m.cx1 , -m.cy1 );
+            let c2 = new Point2D( -m.cx2 , -m.cy2 );
+            let p = new Point2D( -m.x , -m.y );
+            answer.bezierCurveTo(c1.x,c1.y,c2.x,c2.y,p.x,p.y);
+          } 
+        else
+          {
+            console.log("whatever reflect you want, it's not done.");
+          }
+      }
+    
+    return answer;
+  }
+  
+  rotateAbout(a : number , p : Point2D ) : FPath {
+  
+    // Rotate this entire path about p and return the result.
+    let t1 = this.translate(new Point2D(-p.x,-p.y));
+    let t2 = t1.rotate(a);
+    return t2.translate(p);
+  }
+  
+  
+  static arcToBezierNEW( r : number , a0 : number , a1 : number ) : FPath {
+    
+    // Generate a series of bezier curves to represent an arc. The result
+    // represents an arc of a circle of radius r, centered 
+    // at (0,0), going from angle a0 to a1, in radians. 
+    
+    // Each step should subtend no more than pi/4 radians. Most of the
+    // time pi/2 would be accurate enough, but pi/4 is better, and not that 
+    // much extra work.
+    let totalAngle = a1 - a0;
+    if (totalAngle < 0)
+      totalAngle += 2*Math.PI;
+    
+    let numCurves = Math.ceil(4 * totalAngle / Math.PI);
+    
+    let subtend = totalAngle / numCurves;
+    
+    // See the manual for where this comes from. It's the crucial constant
+    // for approximating arcs of circles by cubics.
+    let k = (4/3) * Math.tan(subtend/4);
+    
+    // Everything is built out of a single arc for a circle of radius r,
+    // going cw, starting at (1,0) and angle subtend.
+    let s = Math.sin(subtend);
+    let c = Math.cos(subtend);
+    
+    let p1 = new Point2D (r,0);
+    let p2 = new Point2D (r,r*k);
+    let p3 = new Point2D (r*(c+k*s),r*(s-k*c));
+    let p4 = new Point2D (r*c,r*s);
+    
+    // The arc determined by the p_i above must be rotated to create
+    // a series of sub-arcs to get the total arc we want.
+    let answer = new FPath();
+    
+    answer.moveTo(p1.x,p1.y);
+    for (let i = 0; i < numCurves; i++)
+      {
+        answer.bezierCurveTo(p2.x,p2.y,p3.x,p3.y,p4.x,p4.y);
+        
+        p2.rotateSelf(subtend);
+        p3.rotateSelf(subtend);
+        p4.rotateSelf(subtend);
+      }
+    
+    // Rotate the entire thing so that it starts at a0.
+    answer = answer.rotate(a0);
+    
+    return answer;
+  }
+  
+  arc(x : number , y : number , r : number , a0 : number , a1 : number , ccw : boolean) : void {
+    
+    // BUG: I am pretty sure this isn't right. There are things about 
+    // being cw/cww and things like that. It needs to be tested.
+    
+    // A circular arc, centered at (x,y) and radius r, from angle
+    // a0 to angle a1 (in radians), going cw or ccw. Like ellipse, this 
+    // is basically independent of the surrounding segments. Actually,
+    // the documentation I've found is a little vague on this point, 
+    // but it looks like that is how it works.
+    //
+    // Another issue is the fact that these angles, a0 and a1, may
+    // have "extra" multiples of 2pi in them and whether a1>a0.
+    // The first thing this does is reduce the angles to be in [0,2pi).
+    //
+    // The whole cw versus ccw issue amounts to whether you're getting
+    // the "large" arc or the "small" arc. If a1 > a0, then the ccw arc
+    // is the small arc and the cw arc is the large arc. If a1 < a0,
+    // then the ccw arc is the large arc and the cw arc is the small arc.
+    // To untangle this, assume that the arc will be treated ccw, and
+    // swap a1 and a0, if necessary, to make that the case.
+    //
+    // Finally, there's the issue of what cw and ccw mean when in
+    // left or right handed coordinate systems. Ugh.
+    //
+    // See 
+    // https://pomax.github.io/bezierinfo/#circles_cubic
+    // for an explanation of the math, which is just HS algrbra.
+    // 
+    // 
+    // BUG: Seems like this is a special case of an arc of an ellipse.
+    
+    if (ccw === undefined)
+      ccw = false;
+    
+    // Reduce angles to be in [0,2pi).
+    while (a0 < 0)
+      a0 += 2*Math.PI;
+    while (a1 < 0)
+      a1 += 2*Math.PI;
+    
+    while (a0 >= 2*Math.PI)
+      a0 -= 2*Math.PI;
+    while (a1 >= 2*Math.PI)
+      a1 -= 2*Math.PI;
+    
+    // If the user asked for cw, then swap the angles so that we only
+    // need to consider the ccw case below.
+    if (ccw === true)
+      {
+        let temp = a1;
+        a1 = a0;
+        a0 = temp;
+      }
+    
+    // Get the various arcs for a circle centered at zero.
+    let arcs = FPath.arcToBezierNEW(r,a0,a1);
+    
+    // Translate them all by (x,y).
+    arcs = arcs.translate(new Point2D(x,y));
+    
+    this.addPath(arcs);
+  }
+  
+  ellipse(x : number , y : number , rx : number , ry : number , rot : number ,
+        a0 : number , a1 : number , ccw : boolean) : void {
+    
+    // BUG: Long-term, the right thing to do here is convert it (internally)
+    // to a series of bezier curves.
+    if (ccw === undefined)
+      ccw = false;
+    super.ellipse(x,y,rx,ry,rot,a0,a1,ccw);
+    this.segs.push(PathSegment.getEllipse(x,y,rx,ry,rot,a0,a1,ccw));
+  }
+  
+  rect(x : number , y : number , w : number , h : number ) : void {
+    
+    // BUG: As above, make into a series of line segments. This one is easy.
+    super.rect(x,y,w,h);
+    this.segs.push(PathSegment.getRect(x,y,w,h));
+  }
+  
+  static circArcToBezier(r : number , a0 : number , a1 : number ) : FPath {
+    
+    // Return a series of n bezier curves for a circle of radius r, extending
+    // from r(cos a0,sin a0) to r (cos a1,sin a1).
+    //  
+    // BUG: This should really be part of ellipse().
+    
+    let answer = FPath.arcToBezierNEW(r,a0,a1);
+      
+    return answer;
+  }
+  
+  static parametricToBezier(f : Parametric2DFunction , 
+        t0 : number , t1 : number ,n : number) : FPath {
+    
+    // Given a 2D parametric curve, f(t) = x(t),y(t)), this returns a bezier
+    // approximation from t=t0 to t=t1 by taking n time-steps. Obviously,
+    // f must be a function returning f.x and f.y. 
+    //
+    // This works by sampling f (n+1) times, plus n times at the in
+    // between points, and fitting a Bezier to each trio of points. It
+    // follows the notes in the "main" manual. This is a hard problem -- or
+    // a messy one. There are various strategies. The one used here is to
+    // choose the tangent at the intermediate point (which I call B) to be
+    // parallel to the line between the two end-points of the Bezier segment.
+    // This is relatively straightforward, but one problem with this is that
+    // the slopes where these segments meet need not be the same -- the
+    // resulting curve is not G_1. I'm pretty sure that I worked out a method
+    // once that was based (somehow?) on the way MetaPost works, but it's
+    // complicated and messy and uses complex numbers.
+    let p = new FPath();
+    
+    let p1 : Point2D = f(t0);
+    p.moveTo(p1.x,p1.y);
+    
+    for (let i = 0; i < n; i++)
+      { 
+        let p4 : Point2D = f(t0 + (i+1)*(t1-t0)/n);
+        let B = f(t0 + (i+0.5)*(t1-t0)/n);
+        
+        // Work out an appropriate value for t based on relative distances.
+        let d1 = Math.sqrt((B.x-p1.x)**2 + (B.y-p1.y)**2);
+        let d2 = Math.sqrt((B.x-p4.x)**2 + (B.y-p4.y)**2);
+        let t = d1 / (d1+d2);
+        
+        // The p4 to p1 vector:
+        let V = new Point2D(p4.x - p1.x,p4.y-p1.y);
+        
+        // e1 = B - (1-t)(p4-p1)/3 and e2 = B + t(p4-p1)/3.
+        let e1 = new Point2D(B.x - (1-t)*V.x/3,B.y - (1-t)*V.y/3);
+        let e2 = new Point2D(B.x + t*V.x/3,B.y +t*V.y/3);
+        
+        // Run de Casteljau's algorithm backwards. I call this alpha too,
+        // but r is a better name since it's a ratio.
+        let r = 1 - 1 / (t**3 + (1-t)**3);
+        let u = (1-r)*(1-t)**3;
+        let C = new Point2D(p1.x*u + p4.x*(1-u),p1.y*u + p4.y*(1-u));
+        let A = new Point2D(B.x + (C.x-B.x)/r,B.y + (C.y-B.y)/r);
+        let v1 = new Point2D((e1.x - A.x*t)/(1-t),(e1.y - A.y*t)/(1-t));
+        let v2 = new Point2D((e2.x - A.x*(1-t))/t,(e2.y - A.y*(1-t))/t);
+        let p2 = new Point2D((v1.x - p1.x*(1-t))/t,(v1.y - p1.y*(1-t))/t);
+        let p3 = new Point2D((v2.x - p4.x*t)/(1-t),(v2.y - p4.y*t)/(1-t));
+        
+        p.bezierCurveTo(p2.x,p2.y,p3.x,p3.y,p4.x,p4.y);
+        
+        p1 = p4.copy();
+      }
+    
+    return p;
+  }
+}
+
+// Text is a special case because it expects a LH coordinate system, but 
+// everything else is set up for a RH coordinate system. The end-user
+// shouldn't make a direct call to ctx.fillText(). If he does, then the
+// the text will be upside-down. So, call this instead.
+//
+// Getting the placement of the js to match the placement of the tikz exactly
+// is difficult because they're using two different fonts. So the tikz
+// is drawn at (x+dx,y+dy). The dx and dy are optional and default to zero.
+//
+// BUG: I *could* create a class, something like FPath, to handle all drawing 
+// of text, which may be more natural to the user. But I would probably have 
+// to extend CanvasRenderingContext2D somehow and use that everywhere, not 
+// just when creating TikZ. For now, this is a sufficient solution.
+// Another approach would be to overwrite the existing 
+// CanvasRenderingContext2D.fillText method to call the function below.
+// In some ways, that's the "right" thing to do, but my gut is that
+// it could lead to various problems and make the code generally brittle.
+
+function drawText(ctx : CanvasRenderingContext2D, txt : string, 
+      x : number , y : number , dx = 0 , dy = 0) : void {
+  
+  let saveT = ctx.getTransform();
+  
+  if (ctx instanceof CTX)
+    {
+      // Don't fool around. Just write it to the .tikz file.
+      // BUG: The ts compiler complains about this, but it works fine.
+      ctx.fillText(txt , x + dx , y + dy );
+      ctx.setTransform(saveT);
+      return;
+    }
+  
+  // Get the measurements -- all we really care about is the baseline. 
+  // Transform the ctx so that the horizontal line at y becomes the 
+  // origin, flip the scale, and draw at (x,0).
+  //
+  // Recapitulating the info on MDN, we care about m.actualBoundingBoxAscent
+  // and m.actualBoundBoxDescent, which give distances from ctx.textBaseline
+  // to the relevant side of the bounding box of the text. The baseline 
+  // defaults to the 'alphabetic' setting, which puts the baseline just
+  // under where you normally draw the letter -- B sits on the baseline,
+  // while p hangs below it.
+  let m : TextMetrics = ctx.measureText(txt);
+  
+  ctx.translate(0,y);
+  ctx.scale(1,-1);
+  ctx.textBaseline = 'bottom';
+  ctx.fillText(txt , x , 0 );
+  
+  ctx.setTransform(saveT);
+}
+
+// As above, but these to draw the text in only one scenario or
+// the other. This could be handled with boolean arguments to the
+// above, but this seems clearer for the user.
+function drawTextBrowserOnly(ctx : CanvasRenderingContext2D | CTX, txt : string, 
+      x : number , y : number , dx = 0 , dy = 0) : void {
+
+  if (ctx instanceof CTX)
+    // Skip it.
+    return;
+  
+  drawText(ctx,txt,x,y,dx,dy);
+}
+
+function drawTextTikZOnly(ctx : CanvasRenderingContext2D | CTX, txt : string, 
+  x : number , y : number , dx = 0 , dy = 0) : void {
+
+  if (ctx instanceof CTX)
+    ctx.fillText(txt , x + dx , y + dy );
+}
+
+
+// This is to act much like the object returned from 
+// canvas.getContext('2d').
+// Only a few elements of the standard context class are needed.
+// I purposely did *not* make this extend CanvasRenderingContext2D.
+// By not extending, you can't accidentally make use of some feature
+// of the normal ctx framework and have it silently fail.
+// 
+// This is one major difference. Each time you want to render a figure,
+// you need a new one of these since the tikz text goes out to a file
+// with a different name. In principle, it would be possible to allow
+// reusing these, but there's no value in allowing for that. 
+
+// I had hoped not to need to deal with transformation matricies, and
+// just (implicitly) use the identity matrix. However, certain things
+// are easier for the user if they are permitted. See
+// www.alanzucconi.com/2016/02/10/tranfsormation-matrix
+// for a brief summary of how these work.
+// 
+// Think of the matrix as R in the upper left, for rotation etc, and 
+// (tx,ty,1) in the right column for translation, with M as the overall
+// matrix. The bottom row is always (0 0 1). If the user gives (x y) as
+// some position relative to M, then the "real" position is M(x y 1).
+// By "real" I mean that position relative to the identity matrix.
+//
+// BUG: I think I am doing this the wrong way. As things stand, I store
+// the thing the user does (the path and any points or whatever that
+// specify) in terms given by the user. Then I convert those values to
+// their "unadjusted" values when written to tikz output. Instead, I should
+// convert things as they come in. For one thing, as things stand, if
+// the user adjusts the t-matrix as things are drawn, it would mess up
+// everything. This would also side-step certain questions like what
+// a shear transformation should mean for something like an ellipse. If
+// we correct things as just described, then an ellipse is an ellipse,
+// and it is not shear-transformed, although the points where ellipse
+// is located would be shear-transformed.
+//
+// BUG: Add a flag, like CTX.paper, and set is to true here.
+// That way, the rendering process can output something different on paper.
+// This flag will be undefined when run in a browser.
+  
+class CTX {
+  
+  // Transformation matrix.
+  // BUG: Try to get rid of this. I think that, now that all drawing is
+  // done with a RH system, this is unnecessary. Everything related to
+  // tmatrix is private and I think it's effectively unused.
+  private tmatrix = [[1,0,0],[0,1,0],[0,0,1]]; 
+  
+  // BUG: This is *not* the right way to do things, but it's easier.
+  // The problem is in scaling lengths, which are not points. This is a
+  // particular problem with radii. The proper solution is to work this value
+  // out from the tmatrix, but that's messy.
+  // This is why things like ellipses should be treated as beziers.
+  private netScale = 1.0;
+  
+  // To allow the user to set the linewidth. Otherwise, tikz uses a 
+  // default value of 0.4pt. Tikz has certained named line widths, like
+  // 'semithick' and 'ultra thin' but I don't care about those. It's better
+  // to stick with numerical values to be consistent with js.
+  // This name matches what's used in a "normal" ctx.
+  // The way to specify line width in tikz is as an option to \draw:
+  // \draw[line width = 1mm]  ...whatever...
+  // for example.
+  lineWidth = 1.0;
+  
+  // File name (without the '.tizk') for the figure.
+  figureName = "";
+  
+  // This holds the output as it is generated.
+  tikzstr = "";
+  
+  
+  constructor(name : string) {
+    
+    // Provide the name of the figure whose tikz is being generated.
+    // This goes to a file, which is fiddly with js. The contents of the
+    // file will be sent to the server, and it is assumed that the server
+    // knows what to do. A normal HTTP server will choke on it (really,
+    // it will just ignore it).
+    //
+    // As each call to stroke(),  fill(), and so forth is made, the corresponding
+    // tikz is noted.  When all these are calls are done, call close() to write it out.
+    this.figureName = name; 
+    this.tikzstr = ""; 
+    
+    // The tikz file needs a bit of a heading. 
+    this.tikzstr += "\\begin{tikzpicture}\n";
+
+    // And everything is clipped to the permitted drawing area. To obtain
+    // that area, we need to look at the figure specification.
+    let myFunc : AugmentedDrawingFunction = getAugmentedFunction ( name );
+    let fpc : FigurePanel = myFunc.figurePanelClass !;
+    
+    // Neither one really seems to give the right thing.
+    // Maybe use \clip as an option to 
+    // \begin{tikzpicture}[\clip something?]
+    //this.tikzstr += "\\clip (0bp,0bp) rectangle (" +fpc.textWidth+ 
+    //    "bp," + fpc.h+ "bp);\n";
+    this.tikzstr += "\\useasboundingbox (0bp,0bp) rectangle (" +fpc.textWidth.toFixed(2)+ 
+        "bp," + (fpc.h - fpc.lowerPadding - fpc.upperPadding).toFixed(2)+ "bp);\n";
+  }
+ 
+  close() {
+    
+    // Finalize the tikz specification, and write it out.
+    // 
+    // Note that, under Firefox, this generates an error on the console:
+    //
+    // XML Parsing Error: no root element found
+    // Location: http://localhost:8000/geartest01.tikz
+    // Line Number 1, Column 1:
+    //
+    // or whatever the file name is that's saved. Apparently this is a
+    // "known issue" (aka, a bug) with Firefox. No such message appears
+    // with MS Edge. It works the same either way.
+    this.tikzstr += "\\end{tikzpicture}\n";
+    
+    // BUG: No doubt there is a more modern fetch() way to do this.
+    let req = new XMLHttpRequest();
+    
+    // This is *really* not the standard way to do things.
+    // Pass the file name to save under, then the text to save.
+    // I *should* be passing some cgi script that takes input, but
+    // I've tweaked the http server so that it's non-standard,
+    // and does what I want instead of what it is supposed to do.
+    let fname = this.figureName + ".tikz";
+    req.open("POST",fname);
+    
+    // I have no idea whether this is really necessary.
+    req.setRequestHeader("Content-Type","text/plain;charset=UTF-8");
+    
+    req.send(this.tikzstr);
+  }
+  
+  private static clone3x3Matrix(m : number[][]) : number[][] {
+    
+    // JS seems not to have a standard way of creating a copy of a matrix.
+    // This does it for a 3x3 matrix and returns the result.
+    let a : number[][] = [];
+    a[0] = [];
+    a[0][0] = m[0][0];
+    a[0][1] = m[0][1];
+    a[0][2] = m[0][2];
+    
+    a[1] = [];
+    a[1][0] = m[1][0];
+    a[1][1] = m[1][1];
+    a[1][2] = m[1][2];
+    
+    a[2] = [];
+    a[2][0] = m[2][0];
+    a[2][1] = m[2][1];
+    a[2][2] = m[2][2];
+    
+    return a;
+  }
+  
+  private getTransform()  : number[][] {
+    return CTX.clone3x3Matrix(this.tmatrix);
+  }
+  
+  private setTransform(t : number[][]) : void {
+    this.tmatrix = CTX.clone3x3Matrix(t);
+  }
+  
+  private translate(tx : number , ty : number ) : void {
+    
+    // Adjust the transformation matrix. Going forward, this will have the
+    // effect of converting (x,y) to (tx + x,ty+y) whenever the user
+    // refers to (x,y).  
+    this.tmatrix[0][2] += tx;
+    this.tmatrix[1][2] += ty;
+  }
+  
+  private scale(sx : number , sy : number ) : void {
+    
+    // Scale the transformation matrix.
+    // Let S = diag(sx,sy,1). The new t-matrix is the old t-matrix times S.
+    // 
+    // BUG: I am not sure. Maybe it should be S times old t-matrix, and
+    // I have the order wrong. For the time being it doesn't matter since
+    // every case I care about has sx=sy and the matrices commute in that
+    // special case.
+    this.tmatrix[0][0] *= sx;
+    this.tmatrix[0][1] *= sy;
+    
+    this.tmatrix[1][0] *= sx;
+    this.tmatrix[1][1] *= sy;
+    
+    // Track this here too.
+    // BUG: This assumes that sx = xy.
+    this.netScale *= sx;
+  }
+  
+  private applyTMatrix(x : number , y : number ) : {x : number , y : number } {
+    
+    // Return tmatrix times (x,y). As a matrix operation, this is
+    // tmatrix x (x y 1), but we only return the first two entries.
+    let ax = this.tmatrix[0][0] * x + this.tmatrix[0][1] * y + this.tmatrix[0][2];
+    let ay = this.tmatrix[1][0] * x + this.tmatrix[1][1] * y + this.tmatrix[1][2];
+    
+    return {x: ax, y: ay};   
+  }
+  
+  handlePath(path : FPath ) : void {
+    
+    // Called by either fill() or stroke().
+    var segs = path.segs;
+    
+    for (let i = 0; i < segs.length; i++)
+      {
+        // s is a PathSegment object.
+        let s = segs[i];
+        
+        if (s.type == PathSegment.MOVE_TO)
+          {
+            let m = <MoveToSegment> s.s;
+            let t = this.applyTMatrix(m.x,m.y);
+            //this.tikzstr += "(" +s.x+ "pt, " + s.y+ "pt) ";
+            this.tikzstr += "(" +t.x.toFixed(2)+ "bp, " + t.y.toFixed(2)+ "bp) ";
+          }
+        else if (s.type == PathSegment.LINE_TO)
+          {
+            // Lines are drawn with the tikz \draw command. It takes the form
+            // \draw [options] (x1,y1) -- (x2,y2);
+            // Note that I include "bp" for the dimensions. I think that tikz
+            // defaults to cm if no dimension is given, so I should specify 
+            // something. Note also that I use bp, not pt.
+            // 
+            // BUG: I am not sure whether the tikz point is 72ppi or 72.27 ppi
+            // to match latex.
+            // 
+            // BUG: For the time being, I will ignore these options, but they 
+            // can be things like fill or dashed, or to set the color or line
+            // width, and probably a mess of other stuff. 
+            let m = <LineToSegment> s.s;
+            let t = this.applyTMatrix(m.x,m.y);
+            this.tikzstr += "-- (" +t.x.toFixed(2)+ "bp, " + t.y.toFixed(2)+ "bp) ";
+          }
+        else if (s.type == PathSegment.BEZIER)
+          {
+            // The sources I found aren't very explicit about exactly how
+            // this is implemented. I assume it's done in the usual way.
+            // We have
+            // P(t) = B(3,0)*CP + B(3,1)*P1 + B(3,2)*P2 + B(3,3)*P3,
+            // where t\in [0,1] and B are the usual Bernstein polynomials (the
+            // functions of t):
+            // B(n,m) = C(n,m) t^m (1-t)^(n-m),
+            // and C is the choice function.
+            
+            // See also the tikz/pgf manual (v3.1.9a), p. 156, for the output.
+            // However the manual is wrong, or not clear. Use 'and' between
+            // the control points.
+            //
+            // The gist is that CP is fixed point where the curve starts;
+            // it's implicit for both Java and tikz. P1 and P2 are the control
+            // points and P3 is where the curve terminates. Fortunately this
+            // matches up nicely with the tikz syntax.
+            let m = <BezierToSegment> s.s;
+            let t1 = this.applyTMatrix( m.cx1 , m.cy1);
+            let t2 = this.applyTMatrix( m.cx2 , m.cy2);
+            let t3 = this.applyTMatrix( m.x , m.y);
+            
+            this.tikzstr += 
+              ".. controls (" +t1.x.toFixed(2)+ "bp, " +t1.y.toFixed(2)+ "bp) and (" +
+                t2.x.toFixed(2)+ "bp, " +t2.y.toFixed(2)+ "bp) .. (" +
+                t3.x.toFixed(2)+ "bp, " +t3.y.toFixed(2)+ "bp)";
+          }
+        else if (s.type == PathSegment.QUADRATIC)
+          {
+            // BUG: Put this back.
+            console.log("quadratic does not work");
+            // Tikz has this too (whew). Oddly, it's part of the pgf stuff.
+            // Everything else is drawn with \draw (or \fill), but this
+            // uses \pgfpathquadraticcurveto. I'm not sure if that matters,
+            // and I hope that you can mix these freely in the middle of 
+            // a \draw command. The tikz/pgf manual isn't very clear on
+            // mixing these. 
+            // BUG: I wonder if I should be using commands like \pgflineto, 
+            // \pgfcurveto, and so forth, throughout what I've done.
+            // See the tikz/pgf manul (v3.1.9a), p. 1095.
+            //
+            // BUG: I'm going to code this hoping that it works, but I suspect
+            // that it will not, and will need to go back and change to 
+            // something other than \draw or \fill to start with.
+            // Maybe I need to define an entire path and then \draw or \fill 
+            // it? It looks like you define that path, then say
+            // \pgfusepath{fill} or whatever.
+            // 
+            // BUG: Maybe I could convert this to a cubic here and avoid this
+            // entire messy issue?
+            //
+            // NOTE: pgf has some nice commands for drawing only *part* of 
+            // a Bezier curve. See p. 1097 for \pgfpathcurvebetweentime.
+            
+            // BUG: Maybe I'll be lucky and this is never called.
+            // I think (?) it must be that the only time this type of
+            // segment ever arises is if the user users a QuadCurve2D, which
+            // seems (?) unlikely.
+            /*
+            let t1 = this.applyTMatrix(s.cx,s.cy);
+            let t2 = this.applyTMatrix(s.x,s.y);
+            
+            //this.tikzstr += 
+            //  "\\pgfpathquadraticcurveto {\\pgfpoint{" +
+            //    s.cx+ "pt}{" +x.cy+ "pt}}{\\pgfpoint{" +
+            //    s.x+ "pt}{" +s.y+ "pt}}";
+            this.tikzstr += 
+              "\\pgfpathquadraticcurveto {\\pgfpoint{" +
+                t1.x+ "bp}{" +t1.y+ "bp}}{\\pgfpoint{" +
+                t2.x+ "bp}{" +t2.y+ "bp}}";
+              */
+          }
+        else if (s.type == PathSegment.ARC)
+          {
+            console.log("arc");
+            // This is a circular arc of a circle
+            // centered at (x,y) over a given range of angles (cw or ccw).
+            //
+            // BUG: For the remaining cases, I may need to do something
+            // special. It's not clear exactly what the browser is doing
+            // with these. Are they converted, internally, to bezier
+            // curves or are they somehow rendered more directly. 
+            
+            this.tikzstr += "no arc implemented"; 
+          }
+        else if (s.type == PathSegment.ARC_TO)
+          {
+            console.log("arc to not done");
+            // This is essentially a bezier curve.
+            // You have two control points and a radius. It is not
+            // clear exactly how it works.
+            
+            this.tikzstr += "no arcTo implemented";
+          }
+        else if (s.type == PathSegment.ELLIPSE)
+          {
+            // BUG: This will only draw a complete ellipse, not an arc of
+            // an ellipse.
+            // BUG: The foolishness with netScale is another reason not
+            // to allow an ellipse type. If an ellipse were really a series
+            // of bezier curves, then this would be a non-issue.
+            let m = <EllipseSegment> s.s;
+            
+            let c = this.applyTMatrix( m.x , m.y );
+            
+            //console.log(s.x+ "," +s.y+ " becomes " +c.x+ " " +c.y);
+            
+            //this.tikzstr += "(" +c.x+ "pt," +c.y+ 
+            //  "pt) ellipse [x radius=" +s.rx*this.netScale+ 
+            //  "pt,y radius =" + s.ry*this.netScale+ "pt]";
+            
+            this.tikzstr += "(" +c.x.toFixed(2)+ "bp," +c.y.toFixed(2)+ 
+              "bp) ellipse [x radius=" + (m.rx * this.netScale).toFixed(2)+ 
+              "bp,y radius =" + (m.ry * this.netScale).toFixed(2)+ "bp]";
+          }
+        else if (s.type == PathSegment.RECT)
+          {
+            console.log("rect not done");
+            this.tikzstr += "no rect implemented";
+          }
+        else if (s.type == PathSegment.CLOSE)
+          {
+            this.tikzstr += "-- cycle";
+          }
+        else
+          {
+            console.log("unknown FPath: " +s.type);
+          }
+      }
+     
+    this.tikzstr += ";\n";
+  }
+
+  stroke(path : FPath ) : void {
+    
+    let segs = path.segs;
+    if (segs.length === 0)
+      return;
+    
+    this.tikzstr += "\\draw[line width=" +this.lineWidth.toFixed(2)+ "bp] ";
+    
+    this.handlePath(path);
+  }
+  
+  fill(path : FPath ) : void {
+    
+    let segs = path.segs;
+    if (segs.length === 0)
+      return;
+    
+    this.tikzstr += "\\fill ";
+    
+    this.handlePath(path);
+  }
+  
+  fillText(s : string , x : number , y : number ) : void {
+    
+    // BUG: This is now done with top-level functions now and shouldn't
+    // be called (or callable) by outside code.
+    // 
+    // BUG: I have my doubts about including this one. It needs to be done
+    // *somehow*, but I am concerned about a mismatch between the JS
+    // font and the fonts used by latex.
+    // 
+    // BUG: I am ignoring the ctx.font setting. It does seem that if you
+    // set it to '10px san-serif' you get something reasonable for the
+    // browswer that doesn't look too different than latex.
+    //
+    // BUG: This is so fussy that I suspect that any drawing that is at
+    // all tricky will require that the user provide different placement for
+    // text on the browser and text on the page. Getting things to match
+    // up *exactly* may be impossible. 
+    
+    let t = this.applyTMatrix(x,y);
+    // I had this as 'anchor=south west', but 'base west' seems closer
+    // to what latex does. 
+    // BUG: It's all a mystery.
+    this.tikzstr += 
+      "\\node [anchor=base west] at (" +t.x.toFixed(2)+ "pt, " +t.y.toFixed(2)+ "pt) {" +s+ "};\n";
+     
+    
+  }
+  
+}
+
+
+
+// A grab-bag of numerical techniques.
+// BUG: This doesn't really belong in this file.
+
+type FunctionRealtoReal = ( x : number ) => number;
+
+class Numerical {
+  
+  static newton(f : FunctionRealtoReal , g : number, a : number , b : number ,
+    y : number , e : number ) : number {
+    
+    // Given a function, f, and an initial guess, g, bracketed between a and b,
+    // for the argument to f, and a target value, y, this returns x such that
+    // f(x) = y to within error, e.
+    //  
+    // A crude off-the-cuff implementation of Newton-Raphson.
+    // This will only work in the tamest situations.
+    //
+    // Recall that the idea is that
+    // f(x0 + dx) ~ f(x0) + f'(x0) dx
+    // We want y = f(x + dx) and that is approximately equivalent to
+    // y = f(x0) + f'(x0) dx or dx = ( y - f(x0) ) / f'(x0)
+    // so that x0 becomes x1 = x0 + dx = x0 + ( y - f(x0) ) / f'(x0)
+    //
+    // NOTE: I had hoped to avoid the need to bracket entirely, and for
+    // some functions (and sufficiently good initial guesses), you could,
+    // but it's too easy for the algorithm to get lost among local extrema
+    // if there is no bracket.
+    //
+    // In fact, here is a good example of why bracketing is needed.
+    // Let f = cos x + x sin x, which happens to be the x-coordinate for
+    // the parameterization of the unit involute. Suppose that you want
+    // to find x for which f(x) = 1.5, and you start off with a guess of
+    // x = 0.5. The slope of f at 0.5 is small so that Newton-Raphson
+    // sends x1 to a value that is beyond the inflection point near x = 3.
+    // At that point things go haywire.
+    
+    let x0 = g;
+    let y0 = f(x0);
+    
+    let i = 0;
+    
+    while (Math.abs(y-y0) > e)
+      { 
+        let fplus = f(x0+e);
+        let fminus = f(x0-e);
+        let fprime = (fplus - fminus) / (2*e);
+        
+        let dx = (y - y0) / fprime;
+        let x1 = x0 + dx;
+        
+        // Make sure we haven't passed a bracket. Just subdivide if we have.
+        if (x1 > b)
+          x1 = (x1-x0)/2;
+        if (x1 < a)
+          x1 = (x0-x1)/2; 
+        
+        x0 = x1;
+        y0 = f(x0);
+        
+        // Don't allow an infinite loop
+        ++i;
+        if (i > 100)
+          return x0;
+      }
+    
+    return x0;
+  } 
+ 
+} 

Added: trunk/Master/texmf-dist/doc/latex/figput/javascript/development/widgets.ts
===================================================================
--- trunk/Master/texmf-dist/doc/latex/figput/javascript/development/widgets.ts	                        (rev 0)
+++ trunk/Master/texmf-dist/doc/latex/figput/javascript/development/widgets.ts	2022-07-22 21:48:41 UTC (rev 63957)
@@ -0,0 +1,2908 @@
+/*
+Widget management code.
+
+Typically, widget management is done with a tightly siloed hierarchy, with
+widgets in containers, which are in containers, etc. There is a hierarchy 
+like that here (though rather flat since I don't need much), but there's also 
+a global registry of widgets alongside the hierarchy. This makes widgets 
+easier to work with for the author of the latex document.
+
+I've also avoided any kind of clever abstraction around the widget concept.
+This can mean that there's a certain amount of boilerplate (not DRY), but
+it also means that things aren't tangled up. Widgets can be individually
+modified without worries about side-effects.
+
+All widgets use a register() method rather than a constructor. This
+is because the user should be able to specify a widget repeatedly
+without actually creating a new one every time it's specified. 
+
+So, the user should say something like
+let w = RandomWidgetType.register(arguments);
+to create a widget from the drawing code. If register() has never been
+called for the particular widget, then a new widget *is* created and
+a reference to it is placed in global storage. If this widget was created
+earlier, then the reference to it is taken from global storage and returned.
+So, register() is something like an object factory, but it won't make the 
+same object more than once.
+
+Every widget is distinguished by its type and the (name of the) figure it 
+belongs to. In addition, if a figure has several widgets of the same type,
+then the user must provide an optional name for that particular widget. For
+example, if there are three ButtonWidgets for a given figure, then they
+might be created by
+let b1 = ButtonWidget.register(whatever,"first");
+let b2 = ButtonWidget.register(whatever,"second");
+let b3 = ButtonWidget.register(whatever,"third"); 
+
+-------------------------
+
+One of the ticklish issues is how to associate widgets with their
+figures. In most languages, this problem is solved by explicitly using
+"this" somehow. In Java, you might say something like
+new Widget(this);
+to indicate that the owner of the widget is the class from which the widget 
+was constructed. I would rather not do that because it's the kind of 
+boilerplate arcana that the user shouldn't have to think about.
+
+JS provides a couple of ways to determine who made a call to a particular
+function. The easiest way is like this
+
+function example() {
+  let caller = example.caller.name;
+  console.log(caller);
+} 
+
+This should print the name of the function that invoked example().
+
+Another way is very easy to do, but it's been deprecated. See 
+https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/caller
+Even though it is deprecated, every browser supports it, according to the
+above link. Also, my guess is that this is very commonly used since
+it's so handy. They won't be getting rid of it any time soon.
+
+If they do get rid of caller.name, then another way to obtain this
+information is by creating a bogus Error and examining the call stack:
+
+function example() {
+  
+  let stack = new Error().stack;
+  let caller = stack.split('\n')[1].trim();
+  
+  // caller is now inforamtion about the function calling this one,
+  // including the file name and a bunch of other stuff I don't care about.
+  // I just want to know the name of the function.
+  // It *appears* (but not extensively tested) that the function name
+  // occurs before the first '@'.;
+  let callingFcn = caller.split('@')[0];
+  console.log(callingFcn);
+}
+
+I wanted to use caller.name, even though it is deprecated, because it is
+so much easier. Unfortunately, it is not allowed in strict mode.
+Since everything that appears within a class is strict, that makes its use
+awkward. I tried to get around this by defining a top-level function (outside
+any class) that does nothing but return the value I want, but that doesn't
+work either. It seems like, as soon as you enter a class, the data you want
+is stripped off (or something). Also, now that I've moved to TypeScript any
+violation of "strict" is even harder. Since I'll have to define a seperate class
+anyway, go ahead and use the Error-based approach.
+
+To top it off, the method via generating an Error is sensitive to the
+broswer because different browsers format this information differently.
+
+-------------------
+
+BUG: Future Widgets...?
+
+Because LoopWidget takes such a crazy number of options, it would be nice
+to have several widgets that merely call LoopWidget. This wouldn't really
+be any different, but would simplify things for the user. Basically, these
+would have a reduced set of arguments to register() and just hand everything
+off to LoopWidget. They would be a mere glue skeleton. Same goes for 
+OpenAnimWidget.
+
+Image Building Widget
+  For something like (say) a Mandelbrot set. This takes time to generate
+  and you might want to draw it in an open-ended way. It's not reasonable
+  to allow the user to move through time and see the state of the image
+  at different time steps. The widget should store an off-screen image
+  and making the animation "run faster" would mean calling it more frequently
+  so that it can do more calculation. So it would use some of the same
+  animation infrastructure, but in a different way. The most that makes
+  sense here is a pause/run (to reduce computational load) and something
+  to increase or decrease the load. This would often be something for which
+  it does not make sense to generate tikz. Any JS rendering of a mandelbrot
+  set (say) would be terrible for inclusion in a book. You'd generate a
+  printed figure like that in some other way, even if an on-line animation
+  would be instructive. 
+
+Various restrictions on how a DraggableDot can be moved would be handy.
+Restricting to a particular line or arc wouldn't be hard, but restricting to
+fall on a given Path2D would be hard. The JS implementation of Path2D is 
+poor, and I would need to reimplement the entire thing from the 
+ground up. I might need to do some of that anyway for the best tikz output 
+(I did some stuff along those lines already).
+
+Draggable Line
+  Similar to Draggable dot. In fact, it's not clear that this needs its own
+  widget. A line is determined by two points, so the user could use a
+  draggable dot and just draw the line himself. The only advantage I can
+  see to a draggable *line* is that the user could mouse-down on any
+  portion of the line. In fact, that could be done with DraggableDot since
+  the "dot" could be an entire line.
+
+Scroll bar for number selection.
+  Similar to a spinner, but the user drags a dot along a line.
+  Not clear whether a numerical value should appear.
+  
+Checkboxes and Radio buttons
+  Gack
+  
+Drop-down menu
+  Stuff like this gets more fiddly. If you have a drop-down menu and
+  it has a vertical scroll bar for multiple selections, then it's even worse.
+
+*/
+
+
+// There is only one of these, so everything is static. It manages all
+// the widgets in the program. 
+
+class WidgetManager {
+  
+  // All the widgets known to the program.
+  // Each of these is an instance of the Widget class.
+  // BUG: I could get rid of this and just use theWidgets. It's redundant,
+  // and theWidgets is actually easier.
+  // BUG: Yes, get rid of this.
+  static theList : Widget[] = [];
+  
+  // Also a complete list of all widgets, but indexed by the figure
+  // to which the widget belongs. This makes it easier to pass events
+  // to the proper recipent. So this is a hash map taking a figure name
+  // (as a string) to an array of Widget objects.
+  static theWidgets : Map<AugmentedDrawingFunction,Widget[]> = new Map();
+  
+  // This is BOGUS. Certain path operations require a CanvasRenderingContext2D, 
+  // even when the question is one of pure abstract geometry, like 
+  // isPointInPath(), and the only way to get one of these is from a canvas. 
+  // Using the visible canvas and ctx for this is prone to all kinds of misuse
+  // and mistakes, so create a bogus ctx here.
+  // BUG: The long-term solution is not to rely on js for this at all. Write
+  // my own code for Bezier curves and the like. I'm partway there already.
+  static bogusCanvas : HTMLCanvasElement = document.createElement('canvas');
+  static bogusCtx : CanvasRenderingContext2D = WidgetManager.bogusCanvas.getContext('2d') !;
+  
+  // Whether a widget "owns" a recent mouse-down event. This is needed
+  // for things like dragging. If this is null, then the next mouse-down
+  // is up for grabs. Otherwise, it points to the relevant Widget object.
+  static mouseOwner : Widget | null = null;
+  
+  // This isn't being used yet, but it will be needed to handle keyboard
+  // events. The idea is that a widget ""takes ownership" of a mouse-down
+  // with mouseOwner, and that widget is the same one that has focus for
+  // any future keyboard events too. The only real difference is that
+  // focusOwner is "stickier." This goes to null whenever a user clicks
+  // on something other than a widget.
+  static focusOwner = null;
+  
+  
+  static register(w : Widget) : void {
+    
+    this.theList.push(w);
+    
+    if ( WidgetManager.theWidgets.has(w.betterOwner) )
+      WidgetManager.theWidgets.get(w.betterOwner) ! .push(w);
+    else
+      WidgetManager.theWidgets.set(w.betterOwner,[w]);
+  }
+  
+  static knownWidget(o : string , t : string , n : string) : Widget | null {
+    
+    // If there is a widget with the given owner (o), type (t) and name(n)
+    // in theList, then return it; return null otherwise.
+    // BUG: Using a string as owner feels particularly bad.
+    for (let i = 0; i < this.theList.length; i++)
+      {
+        let curW = this.theList[i];
+        
+        if (o !== curW.owner)
+          continue;
+        if (t !== curW.type)
+          continue;
+        if (n === curW.name)
+          return curW;
+      }
+    
+    return null;
+  }
+  
+  static mouseDown(theFig : AugmentedDrawingFunction , x : number , y : number ) : void {
+    
+    // theFig should match one of the Widget object's owner fields.
+    // (x,y) is given relative to he origin of the figure.
+    if (WidgetManager.theWidgets.has(theFig) === false)
+      return;
+    
+    // The only thing to do here is to pass the event to each widget and
+    // see if it wants it. I suppose that I *could* store the area for
+    // each widget, and do an initial test here, but this is easier. 
+    let wlist : Widget[] = WidgetManager.theWidgets.get(theFig) !;
+    
+    for (let i = 0; i < wlist.length; i++)
+      {
+        if (wlist[i].mouseDown(x,y) === true)
+          // First come, first serve.
+          return;
+      }
+  }
+  
+  static mouseMove(theFig : AugmentedDrawingFunction , x : number , y : number ) : void {
+    
+    // As above.
+    if (WidgetManager.mouseOwner === null)
+      return;
+    
+    if (WidgetManager.theWidgets.has(theFig) === false)
+      return;
+    
+    // We only accept mouse moves if the mouse is on the figure that
+    // "owns" the mouse event.
+    if (WidgetManager.mouseOwner.betterOwner !== theFig)
+      return;
+    
+    WidgetManager.mouseOwner.mouseMove(x,y);
+  }
+  
+  static mouseUp(theFig : AugmentedDrawingFunction , x : number , y : number ) : void {
+    
+    // As above.
+    if (WidgetManager.mouseOwner === null)
+      return;
+    
+    if (WidgetManager.theWidgets.has(theFig) === false)
+      return;
+    
+    if (WidgetManager.mouseOwner.betterOwner !== theFig)
+      // Mouse was released over *a* figure, but not the figure with
+      // the owning widget. Tell the correct widget about the release, using
+      // bogus coordinates so that the mouse-up is sure to be off the widget.
+      WidgetManager.mouseOwner.mouseUp(10000000000000,10000000000000);
+    
+    //console.log("up up");
+    WidgetManager.mouseOwner.mouseUp(x,y);
+  }
+}
+
+
+function getCaller() : string {
+  
+  // Irritating function to get around strict mode. See the comment at the
+  // top of the file. I want the caller of the thing that calls this.
+  //
+  // BUG: I was never entirely happy with this, and now that it depends
+  // on the particular browser, I am even less happy about it. It's a
+  // question of the lesser of two evils: this function or requiring
+  // the user to provide a boilerplate 'this' or the like.
+   
+  let stack : string = new Error().stack !;
+  
+  // The exact format of the information in stack depends on the particular
+  // browser. Firefox produces something like this:
+  // 
+  // getCaller at http://localhost:8000/widgets.js:375:15
+  // register at http://localhost:8000/widgets.js:1557:18
+  // geartest01 at http://localhost:8000/geartest01.js:142:26
+  // render at http://localhost:8000/layout.js:628:11
+  // renderFrame at http://localhost:8000/widgets.js:538:13
+  // etc.
+  //
+  // While MS Edge/Chrome produces
+  // 
+  // Error
+  //  at getCaller (widgets.js:375:15)
+  //  at Function.register (widgets.js:1557:18)
+  //  at geartest01 (geartest01.js:142:26)
+  //  at FigurePanel.render (layout.js:628:5)
+  //  etc.
+  //
+  // Depending on the Browser, stack needs to be parsed differently.
+  // theBrowser was defined in main.js. 
+ 
+  // The digit value (e.g., '2') indicates how many steps back in the the
+  // stack to go.
+  if (theBrowser === "Firefox")
+    {
+      let caller = stack.split('\n')[2].trim();
+      
+      // caller is now information about a function in the call stack,
+      // including the file name and a bunch of other stuff I don't care about.
+      // I just want to know the name of the function.
+      // The function name occurs before the first '@'.
+      let callingFcn = caller.split('@')[0];
+      return callingFcn;
+    }
+  else if (theBrowser === "Chrome")
+    {
+      let caller = stack.split('\n')[3].trim();
+      
+      // Here, space-deliminting works better.
+      let callingFcn = caller.split(' ')[1];
+        
+      // But this may return something like 'FigurePanel.bezier'; what I want
+      // is just 'bezier'.
+      if (callingFcn.indexOf('.') > -1) 
+        callingFcn = callingFcn.split('.')[1];
+      
+      return callingFcn;
+    }
+  else
+   {
+    console.log("IMPOSSIBLE ERROR DUE TO UNKNOWN BROWSER TYPE!!!");
+    return "";
+   } 
+}
+
+
+
+// Base class for all widgets. No code outside this file should
+// ever access this class directly. It's not abstract because there
+// are certain actions common to every case in the constructor.
+
+class Widget {
+  
+  // Every widget is owned by a particular figure. The "owner" is
+  // the name of the figure function, just as in latex.
+  // BUG: Change this to the AugmentedDrawingFunction. Thus, get rid
+  // of this and use betterOwner.
+  owner : string = "";
+  
+  betterOwner : AugmentedDrawingFunction;
+  
+  // JS isn't very good about types, so it's clearer to tag sub-classes with
+  // the name of that sub-class rather than mess with typeof or whatever.
+  // This should be "LoopWidget" or whatever the name is of the sub-class.
+  type : string = "";
+  
+  // Name to distinguish this widget from all others of the same
+  // type that belong to the same figure. So, the triple (owner,type,name)
+  // fully distinguishes this Widget from all others.
+  //
+  // In principle, this variable could have been avoided as a user-provided
+  // value and he wouldn't have to come up with an 'extra' name for the widget,
+  // but it wouldn't be easy. The WidgetManager (or something) would have to
+  // come up with a unique ID and *that* would require that the user invoke
+  // something like a "starting to create widgets" and "done creating widgets"
+  // commands. Overall, this seems less fussy for him.
+  name : string = ""; 
+  
+  // The (x,y) is where the widget should be drawn relative to the
+  // rectangle of the figure. Often, widgetX will be negative to put the
+  // widget in the margin of the page.
+  // It's tempting to call these fields x and y, but it would
+  // be easy to accidentally reuse those names.
+  widgetX = 0;
+  widgetY = 0;
+  
+  // To scale the drawing of a widget up or down.
+  scale = 1.0;
+  
+  // Occassionally, it may make sense to hide a widget. This is different 
+  // than being non-visible because the widget is off-screen. If the 
+  // widget has hide == true, then it is *never* shown. For example, the
+  // way animations work, you have to have an animation widget to run the 
+  // animation, even if you don't want to see the widget.
+  hide : boolean = true;
+  
+  
+  constructor(owner : string , type : string , x : number , y : number , scale : number , 
+        hide : boolean , name : string ) {
+    
+    // Due to the fact that this tracks the owner of the widget, and how
+    // it is done, it is IMPORTANT that no sub-class has its own constructor.
+    this.owner = owner;
+    this.type = type;
+    this.widgetX = x;
+    this.widgetY = y;
+    this.scale = scale;
+    this.hide = hide;
+    this.name = name;
+    this.betterOwner = getAugmentedFunction(owner);
+    
+    // When a widget is contructed it must be registered in a global list.
+    WidgetManager.register(this);
+  }
+  
+  draw(ctx : CanvasRenderingContext2D) : void {
+    // Every sub-class must implement this method. 
+    console.log("Called Widget.draw()!!!");
+  }
+  
+  // BUG: These methods that are "never" supposed to be called
+  // will be called for the widgets based on the DOM, like ButtonWidget.
+  // That's fine -- don't panic! I want to get rid of these DOM-based
+  // widgets anyway. DOM = cesspool.
+  mouseDown(x : number , y : number ) : boolean {
+    // Every sub-class must implement this method.
+    // Return true iff the widget wants to "take ownership" of this event. 
+    console.log("Called Widget.mouseDown()!!! " +this.name);
+    return false;
+  }
+  
+  mouseMove(x : number , y : number ) : void {
+    // As above, but returns nothing. 
+    console.log("Called Widget.mouseMove()!!!");
+  }
+  
+  mouseUp(x : number , y : number ) : void {
+    // As above, but returns nothing. 
+    console.log("Called Widget.mouseUp()!!!");
+  }
+}
+
+
+// Animations require some infrastructure.
+// BUG: Maybe this stuff should be in AnimationWidget.
+
+function doAnimation(theWidget : AnimationWidget) : void {
+  
+  // This is called to render a frame of an animation. It is generated via 
+  // the usual event-loop, so we schedule it just as we do for things like
+  // mouse-downs and scroll events.
+  // theWidget is the one that "runs" the animation, like a LoopWidget.
+  let id = Events.getID();
+  doAnimationGuts(id,theWidget);
+}
+
+async function doAnimationGuts(id : number , theWidget : AnimationWidget ) {
+  
+  // Scheduling is handled in a way similar to doScroll() in main.ts.
+  await Events.waitMyTurn(id);
+  
+  await renderFrame(theWidget);
+  
+  // Advance to the next frame.
+  theWidget.curStep += theWidget.stepsPerFrame;
+  theWidget.advanceFrame();
+  
+  // Don't forget this or the program is bricked!
+  Events.allDone(id);
+}
+
+async function renderFrame(theWidget : Widget ) {
+  
+  // Calls the code to render the relevant figure. It renders the *entire*
+  // figure, widget and all.
+  //
+  // NOTE: This is used for animations, but it is also used to ensure
+  // that any change to a widget (and resulting changes to a figure)
+  // is shown.
+  //
+  // BUG: It's tempting to mention this in the user manual since users might
+  // find it useful. OTOH, that shouldn't be encouraged, and this is the kind
+  // of thing that might change in a later version.
+  
+  // The "owner" is the function (from the latex document) that created
+  // theWidget.
+  let myFunc : AugmentedDrawingFunction = getAugmentedFunction( theWidget.owner );
+  let fpc : FigurePanel = myFunc.figurePanelClass !;
+  
+  // This is generally synchronous, but it doesn't hurt anything to tack an 
+  // async on here. Maybe somebody will write one that *is* asynchronous.
+  await fpc.render();
+}
+
+function getFigureRect(theWidget : Widget ) : { w : number , ha : number , hb : number } {
+
+// Returns the width and height of the rectangle of the widget.
+// The height is in two parts: the height above the x-axis, and the height
+// below the x-axis.
+// The units are pdf points, and the width is relative to the left
+// margin. So the width matches the usual coordinate system for drawing
+// the figure, and this width is equal to the text width, as reported
+// by latex. So x in the range [0,width] should be limited to the area
+// below the text.
+let myFunc : AugmentedDrawingFunction = getAugmentedFunction( theWidget.owner );
+let fpc : FigurePanel = myFunc.figurePanelClass ! ;
+
+let answer = { w: fpc.textWidth, ha : fpc.h - fpc.lowerPadding , hb : fpc.lowerPadding };
+return answer;
+}
+
+// Base class for widgets that run animations. See LoopAnimWidget and
+// OpenAnimWidget. There is a fair amount of overlap between the two types
+// of animation class, and it is tempting to pull more stuff up to this level for
+// DRY reasons, but it seems cleaner and clearer to limit this to what's needed 
+// to run the animations with doAnimation() and related functions.
+
+abstract class AnimationWidget extends Widget {
+  
+  // Animations run as a series of frames, and this is the frame being displayed.
+  // This value may be open-ended or it may "loop back" so that animation repeats.
+  curStep = 0;
+  
+  // How much to advance the above with each frame -- an integer. Animations 
+  // can be made to run faster by increasing this value, thereby skipping frames.
+  stepsPerFrame = 1;
+  
+  // The process id for the call to setInterval().
+  animID = 0;
+  
+  advanceFrame() : void {
+    // This is why the class is abstract. It moves curStep to the next frame,
+    // however that should be done for the particular animation.
+    console.log("Calling abstract AnimationWidget.advanceFrame()!");
+  }
+}
+
+// A LoopWidget is to be used when an animiation runs in a repeating loop.
+// You must have one of these for an animation to run, even if the widget
+// itself is invisible. 
+
+class LoopAnimWidget extends AnimationWidget {
+  
+  // These are useful to the user to help properly place things.
+  // These values are given with scale equal to 1, and are worked
+  // out from the actual drawing code.
+  // The TopHeight is the amount above the circle that is used for the 
+  // time-step controls, and BottomHeight is the amount used for the 
+  // faster/slower, pause/run contols. If you don't want the circle at 
+  // all, then it's a little awkward to work out placement, but it works.
+  // There is some imprecision here due to line thickneses, but very close.
+  static Radius = 41.5;
+  static TopHeight = 24.5;
+  static BottomHeight = 21.0;
+  
+  // When things are "selected," draw them in this color.
+  static sColor = "blue";
+  
+  // These are as passed to register(). See that method for a description.
+  // They really shouldn't be touched outside this class. The boolean values
+  // are whether certain elements of the widget are visible (and hence
+  // available for interaction).
+  steps = 100;
+  start = 0;
+  timeStep = 20;
+  visSteps = true;
+  visFastSlow = true;
+  visPauseRun = true;
+  visCircle = true;
+  triGrab = true;
+  
+  // This stuff is very much private.
+  
+  // These are stored when the figure is drawn so that mouse events can find 
+  // what was clicked more easily. It's simpler than recalculating with 
+  // every event.
+  pCircle : Path2D | null = null;
+  pUpStep : Path2D | null = null;
+  pDownStep : Path2D | null = null;
+  pFaster : Path2D | null = null;
+  pSlower : Path2D | null = null;
+  pPauseRun : Path2D | null = null;
+  
+  // The states of various parts of the widget; e.g., whether the pause
+  // or run icon is present, whether a part is "half-way clicked,"" etc.
+  // I'm using 'a' for 'active' and 's' for 'selected.'
+  // 
+  // BUG: If I want to get *really* fancy, then I need another set of
+  // flags to indicate that the mouse *was* clicked on something, so it
+  // is "selected," but the user moved the mouse away from the item without
+  // a mouse-up, so that selected item should be drawn in normal color, not
+  // the highlighted color (sColor). If the mouse is moved back over the
+  // selected item, then the color can go back to being the selection color.
+  aRunning = true;
+  sCircle = false;
+  sPauseRun = false;
+  sFaster = false;
+  sSlower = false;
+  sUpStep = false;
+  sDownStep = false;
+  
+  
+  static register(ctx : CanvasRenderingContext2D , x : number , y : number , scale : number ,
+    visWidget : boolean , steps : number , start : number , timeStep : number , 
+    visSteps : boolean, visFastSlow : boolean , visPauseRun : boolean , visCircle : boolean , 
+    triGrab : boolean , name : string ) : LoopAnimWidget {
+    
+    // BUG: Add an argument for the size of the steps so that
+    // curStep can be incremented by more than 1?
+    
+    // This is used something like a constructor. It either creates a new
+    // LoopWidget and returns it, or returns one that was created earlier. 
+    
+    // Many of these arguments are the same as for Widget.constructor().
+    // In addition, we have
+    // * ctx is assumed to have a t-matrix prepared to properly draw
+    //   the widget. 
+    // * steps is the number of steps required to form a loop -- when it 
+    //   "rolls over" or the "steps per revolution."
+    // * start is the starting step, which will usually be zero. 
+    // * timeStep, in milliseconds, is the time from frame to frame.
+    //   It seems like anything less than about 10ms is pointless.
+    //   My guess (?) is that the rate of event generation is throttled
+    //   somehow. It could be that my various layers of management are
+    //   slowing things down, but I don't think so. 10ms is an eternity
+    //   on modern hardware. The eye can only follow about 20 frames per
+    //   second, at most, or 50ms per frame, so this is no big deal.
+    // * visWidget is whether the widget is visible at all -- same as the
+    //   vis argument to Widget.construtor().
+    // * visSteps is whether the time step controls (at the top) are visible.
+    // * visFastSlow is whether the faster/slower controls are visible (at
+    //   the bottom)
+    // * visPauseRun is whether the pause/run controls are visible
+    // * visCircle is for the circle (with triangular indicator).
+    // * triGrab is whether the user is allowed to grab the indicator
+    //   triangle and control the animation by dragging it. The indicator
+    //   triangle is always there, but it might not be grabable.
+    //   Note that if visCircle == false, then triGrab is implicitly false
+    //   since the triangle isn't visible either.
+    // * name is as in Widget.constructor()
+    //
+    // There appears to be a tacit assumption that time is measured in
+    // integer steps, but fractional values are fine. So they aren't really
+    // time "steps," but more like time increments.
+    // 
+    // BUG: Maybe I should have different classes for some of these choices.
+    // There are just too many. These could all use (internally) the
+    // same class, just not with such a crazy number of options.
+    
+    // Instead of messing with LoopWidget.name or something, be explicit.
+    let type = "LoopWidget";
+    
+    // Something like this line must appear with every regester() method
+    // for each widget.
+    let caller : string = getCaller();
+    
+    // I am forcing the type here, but if the wrong type is returned,
+    // then there are bigger problems.
+    let w : LoopAnimWidget = <LoopAnimWidget> WidgetManager.knownWidget(caller,type,name);
+    
+    if (w != null)
+      {
+        // Widget is known, but it needs to be drawn too.
+        w.draw(ctx);
+        return w;
+      }
+    
+    // Got here, so this widget is not already known, and must be created.
+    // This class has NO construtor, by design, so this falls through to the
+    // super-class Widget constructor.
+    // Careful: Internally, I use an "is hidden" flag, but the user passes in
+    // an "is visible" flag.
+    // BUG: Change the names to be consistent.
+    w = new LoopAnimWidget(caller,type,x,y,scale,!visWidget,name);
+    
+    // Now the additional stuff. This is what would be in a constructor
+    // if this class had one.
+    w.steps = steps;
+    w.start = start;
+    w.timeStep = timeStep;
+    w.visSteps = visSteps;
+    w.visFastSlow = visFastSlow;
+    w.visPauseRun = visPauseRun;
+    w.visCircle = visCircle;
+    w.triGrab = triGrab;
+    
+    w.curStep = w.start;
+    
+    // Note the existence of this widget for the future.
+    WidgetManager.register(w);
+    
+    // This is a special case because it's an animiation. The animation
+    // needs to be scheduled. It may make sense not to call setInterval()
+    // immediately; rather, it may be better to call setTimeout() so that
+    // setInterval() is called after a brief pause. It depends on how these
+    // two work. Try an immediate call; it *should* be fine.
+    w.animID = setInterval(doAnimation,w.timeStep,w);
+    
+    // Before returning the widget, it must be drawn.
+    w.draw(ctx);
+    
+    return w;
+  }
+  
+  advanceFrame() : void {
+    
+    // This kind of animation repeats.
+    this.curStep += this.stepsPerFrame;
+    if (this.curStep >= this.steps)
+      this.curStep -= this.steps;
+  }
+  
+  draw(ctx : CanvasRenderingContext2D) : void {
+    
+    // This is drawn with (0,0) at the center of the circle. The ctx must be
+    // shifted and scaled based on where the user wants the widget relative 
+    // to the larger drawing area.
+    if (this.hide === true)
+      return;
+    
+    // Don't attempt to draw to a tikz file.
+    if (ctx instanceof CTX)
+      return;
+    
+    let saveT = ctx.getTransform();
+    ctx.translate(this.widgetX,this.widgetY);
+    ctx.scale(this.scale,this.scale);
+    
+    var p = new Path2D();
+    
+    // These values determine where the entire drawing is. (cx,cy) is the
+    // center of the circular thing, with radius r.
+    // In unscaled terms, it's clear that cx should equal r to make the
+    // widget but up against x = 0. It's messier for the y-coordinate and you
+    // need to work backwards from what the values defined below. The total 
+    // height is 2r (the circle), plus circWidth (circle line thickness),
+    // plus 2 * arrowHeight (the go fast/go slow things). Then we need to
+    // add the stuff on the top: upperGap, plus stepHeight, plus stepThick.
+    // This is silly and probably confusing to the user. Just place the 
+    // widget relative to the center of the circle. In other words, set 
+    // (cx,cy) = (0,0). The user just needs adjust accordingly, and
+    // exactly what he wants to do will be influenced by whether the upper
+    // and lower sub-controls are present. 
+    var r = 40;
+    var cx = 0;
+    var cy = 0;
+    var circWidth = 3;
+    
+    if (this.visCircle == true)
+      {
+        // Draw the circle. (cx,cy) is center r and r are the two axes of the 
+        // elipse. 0 is that the ellipse isn't rotated, and the last two are
+        // the start and end angle.
+        p.ellipse(cx,cy,r,r,0,0,2*Math.PI);
+        
+        // Note this circle for reference by mouse events.
+        this.pCircle = new Path2D(p);
+        
+        ctx.lineWidth = circWidth;
+        
+        if (this.sCircle == true)
+          ctx.strokeStyle = LoopAnimWidget.sColor;
+        else
+          ctx.strokeStyle = "black";
+        
+        ctx.stroke(p);
+        
+        ctx.lineWidth = 1;
+    
+        // A little triangle to point to the location within the animation loop.
+        // This value is in radians, in [0,2pi).
+        
+        // Location of indicator triangle around the perimeter of the circle.
+        // Minus so that it travels clock-wise, which seems to be our natural expectation.
+        var loc = -2*Math.PI * this.curStep / this.steps;
+        
+        var triHeight = 10;
+        
+        // This is half the full angle at the outer point.
+        var triAngle = Math.PI/20;
+        
+        p = new Path2D();
+        
+        var x = cx + (r-circWidth/2) * Math.cos(loc);
+        var y = cy + (r-circWidth/2) * Math.sin(loc);
+        p.moveTo(x,y);
+        
+        x = cx + (r-triHeight) * Math.cos(loc + triAngle);
+        y = cy + (r-triHeight) * Math.sin(loc + triAngle);
+        p.lineTo(x,y);
+        
+        x = cx + (r-triHeight) * Math.cos(loc - triAngle);
+        y = cy + (r-triHeight) * Math.sin(loc - triAngle);
+        p.lineTo(x,y);
+        
+        p.closePath();
+        
+        ctx.strokeStyle = "red";
+        ctx.stroke(p);
+        ctx.strokeStyle = "black";
+      }
+    
+    // Next, some controls at the bottom for going faster/slower and
+    // pausing/running.
+    // First, a pair of '>' for going faster.
+    let arrowOffset = 18;
+    let lowerGap = 6;
+    let arrowHeight = 7;
+    let arrowDepth = 4;
+    let arrowPairSpace = 3;
+    let arrowThick = 1.25;
+    
+    if (this.visFastSlow === true)
+      {
+        ctx.lineWidth = arrowThick;
+        
+        if (this.sFaster == true)
+          ctx.strokeStyle = LoopAnimWidget.sColor;
+        else
+          ctx.strokeStyle = "black";
+          
+        p = new Path2D();
+        p.moveTo(cx + arrowOffset,cy - r - circWidth/2 - lowerGap);
+        p.lineTo(cx + arrowOffset + arrowDepth,
+                 cy - r - circWidth/2 - lowerGap - arrowHeight);
+        p.lineTo(cx + arrowOffset,
+                 cy - r - circWidth/2 - lowerGap - 2*arrowHeight);
+        ctx.stroke(p);           
+        
+        // You can't just shift a path. Needs to be rebuilt.
+        // BUG: I need to add that ability to my FPath class.
+        // Maybe I have already?
+        p = new Path2D();
+        p.moveTo(cx + arrowOffset + arrowPairSpace,cy - r - circWidth/2 - lowerGap);
+        p.lineTo(cx + arrowOffset + arrowDepth + arrowPairSpace,
+                 cy - r - circWidth/2 - lowerGap - arrowHeight);
+        p.lineTo(cx + arrowOffset + arrowPairSpace,
+                 cy - r - circWidth/2 - lowerGap - 2*arrowHeight);
+        ctx.stroke(p);
+        
+        // A rectangle for the clickable area.
+        this.pFaster = new Path2D();
+        this.pFaster.rect(cx + arrowOffset - arrowThick,cy - r - circWidth/2 - lowerGap - 2*arrowHeight,
+              arrowPairSpace + arrowDepth + 2*arrowThick,2*arrowHeight);
+        
+        // ctx.strokeStyle = 'green';
+        // ctx.stroke(this.pFaster);
+              
+        // Same idea: '<' to go slower.
+        if (this.sSlower == true)
+          ctx.strokeStyle = LoopAnimWidget.sColor;
+        else
+          ctx.strokeStyle = "black";
+        
+        p = new Path2D();
+        p.moveTo(cx - arrowOffset,cy - r - circWidth/2 - lowerGap);
+        p.lineTo(cx - arrowOffset - arrowDepth,
+                 cy - r - circWidth/2 - lowerGap - arrowHeight);
+        p.lineTo(cx - arrowOffset,
+                 cy - r - circWidth/2 - lowerGap - 2*arrowHeight);
+        ctx.stroke(p);
+        
+        p = new Path2D();
+        p.moveTo(cx - arrowOffset - arrowPairSpace,cy - r - circWidth/2 - lowerGap);
+        p.lineTo(cx - arrowOffset - arrowDepth - arrowPairSpace,
+                 cy - r - circWidth/2 - lowerGap - arrowHeight);
+        p.lineTo(cx - arrowOffset - arrowPairSpace,
+                 cy - r - circWidth/2 - lowerGap - 2*arrowHeight);
+        ctx.stroke(p);
+        
+        // And the clickable area.
+        this.pSlower = new Path2D();
+        this.pSlower.rect(
+            cx - arrowOffset - arrowPairSpace - arrowDepth - arrowThick,
+            cy - r - circWidth/2 - lowerGap - 2*arrowHeight,
+            arrowPairSpace + arrowDepth + 2*arrowThick,2*arrowHeight);
+            
+        // ctx.strokeStyle = 'green';
+        // ctx.stroke(this.pSlower);
+      }
+    
+    ctx.lineWidth = 1;
+    
+    if (this.visPauseRun === true)
+      {
+        // A || or triangle for pause or run.
+        let pauseSpace = 3.25;
+        let pauseThick = 1.5;
+        let pauseHeight = 2 * arrowHeight;
+        
+        let runThick = 1.5;
+        let runLeftRight = 5;
+        let runHeight = 2 * arrowHeight;
+            
+        if (this.sPauseRun == true)
+          ctx.strokeStyle = LoopAnimWidget.sColor;
+        else
+          ctx.strokeStyle = "black";
+              
+        if (this.aRunning === true)
+          {
+            // The animation is running, so show || to allow pausing.
+            ctx.lineWidth = pauseThick;
+              
+            p = new Path2D();
+            p.moveTo(cx + pauseSpace,cy - r - circWidth/2 - lowerGap);
+            p.lineTo(cx + pauseSpace,cy - r - circWidth/2 - lowerGap - pauseHeight);
+            ctx.stroke(p);
+            
+            p = new Path2D();
+            p.moveTo(cx - pauseSpace,cy - r - circWidth/2 - lowerGap);
+            p.lineTo(cx - pauseSpace,cy - r - circWidth/2 - lowerGap - pauseHeight);
+            ctx.stroke(p);
+            
+            ctx.lineWidth = 1;
+          }
+        else
+          {
+            // Animation is paused, so show triangle to run it again.
+            ctx.lineWidth = runThick;
+            
+            p = new Path2D();
+            p.moveTo(cx - runLeftRight,cy - r - circWidth/2 - lowerGap);
+            p.lineTo(cx - runLeftRight,cy - r - circWidth/2 - lowerGap - runHeight);
+            p.lineTo(cx + runLeftRight,cy - r - circWidth/2 - lowerGap - runHeight/2);
+            p.closePath();
+            ctx.stroke(p);
+          }
+        
+        // Either way (paused or running), we need the clickable area.
+        // This area is too generous for the "run" triangle, because
+        // I use the same rectangle for "pause" and "run," but no big deal.
+        this.pPauseRun = new Path2D();
+        this.pPauseRun.rect(cx - runLeftRight - runThick,
+          cy - r - circWidth/2 - lowerGap - runHeight - runThick,
+            2*runLeftRight + 2*runThick,runHeight + 2*runThick);
+        
+        // ctx.strokeStyle = "blue";
+        // ctx.lineWidth = 0.5;
+        // ctx.stroke(this.pPauseRun);
+        // ctx.strokeStyle = "black";
+      }
+    
+    ctx.lineWidth = 1;
+    
+    // Now some symbols above the circle for adjusting the step size.
+    
+    if (this.visSteps === true)
+      {
+        // Up and down arrows.
+        let stepSpace = 20;
+        let stepThick = 2.0;
+        let upperGap = 8;
+        let stepHeight = 15;
+        let stepArrowHeight = 8;
+        let stepArrowWidth = 5;
+        
+        ctx.lineWidth = stepThick;
+        
+        if (this.sDownStep == true)
+          {
+            ctx.strokeStyle = LoopAnimWidget.sColor;
+            ctx.fillStyle = LoopAnimWidget.sColor;
+          }
+        else
+          {
+            ctx.strokeStyle = "black";
+            ctx.fillStyle = "black";
+          }
+          
+        // Vertical line
+        p = new Path2D();
+        p.moveTo(cx - stepSpace,cy + r + circWidth/2 + upperGap);
+        p.lineTo(cx - stepSpace,cy + r + circWidth/2 + upperGap + stepHeight);
+        ctx.stroke(p);
+        
+        // Arrow head
+        p = new Path2D();
+        p.moveTo(cx - stepSpace,
+            cy + r + circWidth/2 + upperGap - stepThick);
+        p.lineTo(cx - stepSpace + stepArrowWidth,
+            cy + r + circWidth/2 + upperGap + stepArrowHeight - stepThick);
+        p.lineTo(cx - stepSpace - stepArrowWidth,
+            cy + r + circWidth/2 + upperGap + stepArrowHeight - stepThick);
+        p.closePath();
+        ctx.fill(p);
+        
+        // Clickable area for down arrow.
+        this.pDownStep = new Path2D();
+        this.pDownStep.rect(cx - stepSpace - stepArrowWidth,
+            cy + r + circWidth/2 + upperGap - stepThick,
+            2*stepArrowWidth,stepHeight + stepThick);
+        
+        // ctx.strokeStyle = "blue";
+        // ctx.lineWidth = 0.5;
+        // ctx.stroke(this.pDownStep);
+        // ctx.strokeStyle = "black";
+        // ctx.lineWidth = stepThick;
+        
+        // Again, to the right, arrow head up.
+        if (this.sUpStep == true)
+          {
+            ctx.strokeStyle = LoopAnimWidget.sColor;
+            ctx.fillStyle = LoopAnimWidget.sColor;
+          }
+        else
+          {
+            ctx.strokeStyle = "black";
+            ctx.fillStyle = "black";
+          }
+          
+        p = new Path2D();
+        p.moveTo(cx + stepSpace,cy + r + circWidth/2 + upperGap);
+        p.lineTo(cx + stepSpace,cy + r + circWidth/2 + upperGap + stepHeight);
+        ctx.stroke(p);
+        
+        p = new Path2D();
+        p.moveTo(cx + stepSpace,
+            cy + r + circWidth/2 + upperGap + stepHeight + stepThick);
+        p.lineTo(cx + stepSpace + stepArrowWidth,
+            cy + r + circWidth/2 + upperGap + stepHeight - stepArrowHeight + stepThick);
+        p.lineTo(cx + stepSpace - stepArrowWidth,
+            cy + r + circWidth/2 + upperGap + stepHeight - stepArrowHeight + stepThick);
+        p.closePath();
+        ctx.fill(p);
+        
+        // Clickable area for up arrow.
+        this.pUpStep = new Path2D();
+        this.pUpStep.rect(cx + stepSpace - stepArrowWidth,
+            cy + r + circWidth/2 + upperGap,
+            2*stepArrowWidth,stepHeight + stepThick);
+        
+        // ctx.strokeStyle = "blue";
+        // ctx.lineWidth = 0.5;
+        // ctx.stroke(this.pUpStep);
+        // ctx.strokeStyle = "black";
+        
+        ctx.lineWidth = 1;
+        
+        // A little step icon.
+        ctx.strokeStyle = "black";
+        ctx.fillStyle = "black";
+        stepThick = 1.5;
+        let stepSize = 6;
+        
+        ctx.lineWidth = stepThick;
+        
+        // Steps made as one path, starting at upper-left
+        p = new Path2D();
+        p.moveTo(cx - stepSize,cy + r + circWidth/2 + upperGap + 2*stepSize);
+        p.lineTo(cx,cy + r + circWidth/2 + upperGap + 2*stepSize);
+        p.lineTo(cx,cy + r + circWidth/2 + upperGap + stepSize);
+        p.lineTo(cx + stepSize,cy + r + circWidth/2 + upperGap + stepSize);
+        p.lineTo(cx + stepSize,cy + r + circWidth/2 + upperGap);
+        ctx.stroke(p);
+      }
+    
+    ctx.lineWidth = 1;
+    
+    // Used this to verify the constants. The rectangle barely encloses
+    // the widget.
+    //ctx.strokeRect(
+    //  -LoopWidget.Radius,-LoopWidget.Radius - LoopWidget.TopHeight,
+    //  2*LoopWidget.Radius,
+    //  2*LoopWidget.Radius + LoopWidget.TopHeight + LoopWidget.BottomHeight);
+    
+    ctx.setTransform(saveT);
+  }
+  
+  mouseDown(x : number , y : number ) : boolean {
+    
+    // (x,y) is given in coordinates relative to the owning figure.
+    // Return true iff these coordinates apply to this widget.
+    if (this.hide === true)
+      return false;
+    
+    // Adjust coordinates relative to what the draw() methods uses.
+    // This way we can compare (x,y) to what is on the screen.
+    x -= this.widgetX;
+    y -= this.widgetY;
+    x /= this.scale;
+    y /= this.scale;
+    
+    // The widget also has a scale, which must be taken into account.
+    WidgetManager.bogusCtx.resetTransform();
+    
+    // There is isPointInPath() and isPointInStroke().
+    // It seems that isPointInPath() works on an abstract geometric basis;
+    // the lineWidth of the ctx doesn't matter. OTOH, isPointInStroke()
+    // is affected by the lineWidth -- as it must be to work in any
+    // reasonable way.
+    //
+    // Note also that isPointInPath() defaults to the non-zero winding rule.
+    // Pass "evenodd" as the final argument for that winding rule.
+    
+    // Check the pause/run area first since it should be "on top of"
+    // the circle area.
+    if (this.pPauseRun !== null)
+      {
+        let isin = WidgetManager.bogusCtx.isPointInPath(this.pPauseRun,x,y);
+        if (isin === true)
+          {
+            this.sPauseRun = true;
+            WidgetManager.mouseOwner = this;
+            renderFrame(this);
+            return true;
+          }
+      }
+    
+    // And the run faster area.
+    if (this.pFaster !== null)
+      {
+        let isin = WidgetManager.bogusCtx.isPointInPath(this.pFaster,x,y);
+        if (isin === true)
+          {
+            this.sFaster = true;
+            WidgetManager.mouseOwner = this;
+            renderFrame(this);
+            return true;
+          }
+      }
+      
+    // The run slower area.
+    if (this.pSlower !== null)
+      {
+        let isin = WidgetManager.bogusCtx.isPointInPath(this.pSlower,x,y);
+        if (isin === true)
+          {
+            this.sSlower = true;
+            WidgetManager.mouseOwner = this;
+            renderFrame(this);
+            return true;
+          }
+      }
+      
+    // The longer step area.
+    if (this.pUpStep !== null)
+      {
+        let isin = WidgetManager.bogusCtx.isPointInPath(this.pUpStep,x,y);
+        if (isin === true)
+          {
+            this.sUpStep = true;
+            WidgetManager.mouseOwner = this;
+            renderFrame(this);
+            return true;
+          }
+      }
+    
+    // The shorter step area.  
+    if (this.pDownStep !== null)
+      {
+        let isin = WidgetManager.bogusCtx.isPointInPath(this.pDownStep,x,y);
+        if (isin === true)
+          {
+            this.sDownStep = true;
+            WidgetManager.mouseOwner = this;
+            renderFrame(this);
+            return true;
+          }
+      }
+    
+    // Last thing to check since it should be "underneath" everything.
+    if (this.pCircle !== null)
+      { 
+        // If the user clicked near the circle, then set the indicator and 
+        // current step to that position. Be generous with the clickable area.
+        WidgetManager.bogusCtx.lineWidth = 15;
+        let isin = WidgetManager.bogusCtx.isPointInStroke(this.pCircle,x,y);
+        
+        if (isin === true)
+          {
+            // Act on this click and take ownership for future draggging.
+            // Want an angle in [0,2pi].
+            this.sCircle = true;
+            
+            // Again, minus since clockwise.
+            let alpha = -Math.atan2(y,x);
+            if (alpha < 0)
+              alpha += 2*Math.PI;
+            
+            this.curStep = Math.floor(this.steps * alpha / (2*Math.PI));
+            
+            WidgetManager.mouseOwner = this;
+            
+            // The appearance of the widget has changed.
+            renderFrame(this);
+    
+            return true;
+          }
+      }
+      
+    return false;
+  }
+  
+  mouseMove(x : number , y : number ) : void {
+    
+    // As above.
+    if (this.hide === true)
+      return;
+    
+    x -= this.widgetX;
+    y -= this.widgetY;
+    x /= this.scale;
+    y /= this.scale;
+    WidgetManager.bogusCtx.resetTransform();
+    
+    if (this.sCircle === true)
+      {
+        // What I will do it check that the mouse is "close enough" to the 
+        // circle, but it can be a *long* ways away.
+        WidgetManager.bogusCtx.lineWidth = 40;
+        let isin = WidgetManager.bogusCtx.isPointInStroke(this.pCircle !,x,y);
+        
+        if (isin == false)
+          return;
+        
+        // Minus to make clockwise.
+        let alpha = -Math.atan2(y,x);
+        if (alpha < 0)
+          alpha += 2*Math.PI;
+        
+        this.curStep = Math.floor(this.steps * alpha / (2*Math.PI));
+        
+        // The appearance of the widget may have changed.
+        renderFrame(this);
+      }
+    
+    // BUG: I might (?) want colors to change based on what the mouse
+    // is over. See the BUG comment that goes with aRunning, sCircle, etc.,
+    // at the top of the class.
+  }
+  
+  mouseUp(x : number , y : number ) : void {
+    
+    // As above.
+    if (this.hide === true)
+      return;
+    
+    x -= this.widgetX;
+    y -= this.widgetY;
+    x /= this.scale;
+    y /= this.scale;
+    WidgetManager.bogusCtx.resetTransform();
+    
+    // The mouse is up, so nothing can remain selected. In most cases,
+    // releasing the mouse over the selected item means that something
+    // must be done since the "button" was properly pressed.
+    this.sCircle = false;
+    
+    if (this.sPauseRun)
+      {
+        // Did they *release* the mouse over the pause/run area?
+        let isin = WidgetManager.bogusCtx.isPointInPath(this.pPauseRun ! ,x,y);
+        if (isin === true)
+          { 
+            // Start/stop the animation.
+            if (this.aRunning === true)
+              // Currently running. Pause it.
+              clearInterval(this.animID);
+            else
+              // Currently paused. Restart it.
+              this.animID = setInterval(doAnimation,this.timeStep,this);
+            
+            // Change the pause/run icon too.
+            if (this.aRunning === true)
+              this.aRunning = false;
+            else
+              this.aRunning = true;
+          }
+          
+        this.sPauseRun = false;
+      }
+    
+    if (this.sFaster === true)
+      {
+        let isin = WidgetManager.bogusCtx.isPointInPath(this.pFaster ! ,x,y);
+        if (isin === true)
+          {
+            // Make the animation run a bit faster by reducing the frame-to-
+            // frame time step -- the animation speed. This could be done in
+            // a lot of different ways, by using a factor of 1.4 seems about
+            // right.
+            this.timeStep /= 1.4;
+            if (this.timeStep < 1)
+              this.timeStep = 1;
+            
+            // Stop the animation and restart it at the new speed,
+            // but only if it is currently running. It restarts always, but
+            // don't try to halt it if it's not running.
+            if (this.aRunning === true)
+              clearInterval(this.animID);
+            
+            this.animID = setInterval(doAnimation,this.timeStep,this);
+            this.aRunning = true;
+          }
+        
+        this.sFaster = false;
+      }
+    
+    if (this.sSlower === true)
+      {
+        // Just as above, but make it go slower.
+        let isin = WidgetManager.bogusCtx.isPointInPath(this.pSlower ! ,x,y);
+        if (isin === true)
+          {
+            this.timeStep *= 1.4;
+            
+            // More than a second per frame is silly.
+            if (this.timeStep > 1000)
+              this.timeStep = 1000;
+            
+            if (this.aRunning === true)
+              clearInterval(this.animID);
+            
+            this.animID = setInterval(doAnimation,this.timeStep,this);
+            this.aRunning = true;
+          }
+        
+        this.sSlower = false;
+      }
+    
+    if (this.sUpStep === true)
+      {
+        // Make the number of time increments per frame larger.
+        let isin = WidgetManager.bogusCtx.isPointInPath(this.pUpStep ! ,x,y);
+        if (isin === true)
+          { 
+            // Use a smaller ratio here. Conceptually, it seems like
+            // this should be an integer, but it really doesn't have to be.
+            this.stepsPerFrame *= 1.25;
+            
+            // Fewer than 3 frames per cycle seems silly. For most animations,
+            // you'd proably want at least 10 or 20, at a minimum.
+            if (this.stepsPerFrame > this.steps / 3)
+              this.stepsPerFrame = this.steps / 3;
+          }
+        
+        this.sUpStep = false;
+      }
+      
+    if (this.sDownStep === true)
+      {
+        // As above.
+        let isin = WidgetManager.bogusCtx.isPointInPath(this.pDownStep ! ,x,y);
+        if (isin === true)
+          { 
+            this.stepsPerFrame /= 1.25;
+            
+            // I am tempted to put a lower bound on this, but it's 'not
+            // absolutely necessary.
+          }
+        
+        this.sDownStep = false;
+      }
+    
+    // The appearance of the widget may have changed.
+    renderFrame(this);
+    
+  }
+}
+
+
+// An OpenAnimWidget is for an open-ended animation that doesn't loop back
+// on itself and repeat. In many respects, it's similar to a LoopWidget.
+// It looks different because it's a long bar, sort of like a scroll bar.
+// It's so similar that there are minimal (for me) comments. See
+// LoopWidgets for certain details.
+
+class OpenAnimWidget extends AnimationWidget {
+  
+  // These are useful to the user to help properly place things.
+  // The widget is placed based on the lower-left corner, and the
+  // user can specify the width. The BarHeight is the height of the
+  // bar portion -- it's essentially the radius of the indicator dot --
+  // and ControlsHeight is for the controls.
+  static BarHeight = 6.0;
+  static ControlsHeight = 20.0;
+  
+  // This is useful to help the user place stuff above the control.
+  static TotalHeight = 32.0;
+  
+  
+  // When things are "selected," draw them in this color.
+  static sColor = "blue";
+  
+  // These things are important to the animation drawing code, and are
+  // meant to be public(ish).
+  
+  // These are as passed to register().
+  barLength = 100;
+  timeStep = 25;
+  decay = 1.0001;
+  visSteps = true;
+  visFastSlow = true;
+  visPauseRun = true;
+  visBar = true;
+  barGrab = true;
+  
+  // As for LoopWidth, width modest changes:
+  
+  // Clickable areas:
+  pBar : Path2D | null = null;
+  pDot : Path2D | null = null;
+  pFaster : Path2D | null = null;
+  pSlower : Path2D | null = null;
+  pPauseRun : Path2D | null = null;
+  pUpStep : Path2D | null = null;
+  pDownStep : Path2D | null = null;
+  
+  // States of parts:
+  // 
+  // BUG: If I want to get *really* fancy, then I need another set of
+  // flags to indicate that the mouse *was* clicked on something, so it
+  // is "selected," but the user moved the mouse away from the item without
+  // a mouse-up, so that selected item should be drawn in normal color, not
+  // the highlighted color (sColor). If the mouse is moved back over the
+  // selected item, then the color can go back to being the selection color.
+  aRunning = true;
+  sDot = false;
+  sFaster = false;
+  sSlower = false;
+  sPauseRun = false;
+  sUpStep = false;
+  sDownStep = false;
+  
+  
+  static register(ctx : CanvasRenderingContext2D , x : number , y : number ,scale : number ,
+    width : number , visWidget : boolean , timeStep : number , decay : number ,
+    visSteps : boolean , visFastSlow : boolean , visPauseRun : boolean ,visBar : boolean ,
+    barGrab : boolean , name : string ) : OpenAnimWidget {
+    
+    // This is used something like a constructor. It either creates a new
+    // LoopWidget and returns it, or returns one that was created earlier. 
+    
+    // Many of these arguments are the same as for Widget.constructor().
+    // In addition, we have
+    // * ctx is assumed to have a t-matrix prepared to properly draw
+    //   the widget. 
+    // * width is the length of the indicator bar. If you want both the
+    //   controls (time steps and fast/slow), then this should be at least
+    //   200 so that the controls don't stick out. Of course, this is the
+    //   unscaled size, and you can make the entire thing smaller with the
+    //   scale argument.
+    // * timeStep, in milliseconds, is the time from frame to frame.
+    // * decay is complicated. The value of this.curStep must be mapped to 
+    //   the linear bar, which is not infinite.
+    //   We need a map from [0,infty) to [0,width). Define
+    //   f(s) =  1 - 1/a^s
+    //   This maps [0,infty) to [0,1), provided that a > 1. Then
+    //   g(s) = w f(s)
+    //   is the function we want. But what about a? The closer a is to 1,
+    //   the faster g(s) will approach w. Typically, you'll want a to be
+    //   something like 1.001 or 1.0001, depending on the number of steps
+    //   in your animation. The decay argment determines a:
+    //   a = 1 + 1/decay, so you'll usually want decay to be somewhere in the
+    //   range from 100 to (maybe) 100,000. It depends how big the steps
+    //   are and how long you want the animiation to run. For comparison, 
+    //   decay = 1,000 puts f(2000) = 0.86 and f(5000) = 0.99, while 
+    //   decay =  10,000 puts f(2000) = 0.18, f(5000) = 0.39, 
+    //   f(20,000) = 0.86. You can also work backwards. If you want 
+    //   f(n) = x, where x is in [0,1), like x = 85%, then you want 
+    //   1 / (1 + 1/a)^n = x, or
+    //   a = 1 / [ x^(1/n) - 1 ]
+    //   That's not so informative, but you can write it as 
+    //   a = 1 / [ exp(-ln(x)/n) - 1 ]
+    //   If we take x \approx 0.86 so that ln(x) = -0.15 (exactly), then
+    //   a = 1 / [ exp(-0.15/n) - 1 ]
+    //   Plug in the value for n at which you want to have reached the
+    //   86% level, and you get a.
+    //   For brevity, in the code, I use this.decay as the value, a,
+    //   discussed above. 
+    //   BUG: I feel like I made an algebra mistake, but that's the idea.
+    // * visWidget is whether the widget is visible at all -- same as the
+    //   vis argument to Widget.construtor().
+    // * visSteps is whether the time step controls (at the right) are visible.
+    // * visFastSlow is whether the faster/slower controls are visible (at
+    //   the left)
+    // * visPauseRun is whether the pause/run controls are visible.
+    // * visBar is for the progress bar (with dot indicator).
+    // * barGrab is whether the user is allowed to grab the dot indicator
+    //   triangle and control the animation by dragging it.
+    // * name is as in Widget.constructor()
+    // 
+    // BUG: Maybe I should have different classes for some of these choices.
+    // There are just too many. These could all use (internally) the
+    // same class, just not with such a crazy number of options.
+    
+    
+    // As for LoopWidget.
+    let type = "OpenAnimWidget";
+    let caller = getCaller();
+    
+    let w : OpenAnimWidget = <OpenAnimWidget> WidgetManager.knownWidget(caller,type,name);
+    
+    if (w != null)
+      {
+        w.draw(ctx);
+        return w;
+      }
+    
+    // Got here, so this widget is not already known, and must be created.
+    w = new OpenAnimWidget(caller,type,x,y,scale,!visWidget,name);
+    
+    // Adjust the length for the scale so that if the user asks for
+    // a bar that is X px long, he gets it. So, the scale adjusts the size
+    // of the "bits", not the total size.
+    w.barLength = width / scale;
+    w.timeStep = timeStep;
+    w.visSteps = visSteps;
+    w.visFastSlow = visFastSlow;
+    w.visPauseRun = visPauseRun;
+    w.visBar = visBar;
+    w.barGrab = barGrab;
+    
+    // For internal use, we convert the given decay to the value we use
+    // for exponentiation.
+    w.decay = 1 + 1/decay;
+    
+    // Note the existence of this widget for the future.
+    WidgetManager.register(w);
+    
+    // This is a special case because it's an animiation, as with LoopWidget.
+    w.animID = setInterval(doAnimation,w.timeStep,w);
+    
+    // Before returning the widget, it must be drawn.
+    w.draw(ctx);
+    
+    return w;
+  }
+  
+  advanceFrame() : void {
+    
+    // This animation is open-ended; curStep grows without limit (up to 
+    // E500 or whatever it is).
+    this.curStep += this.stepsPerFrame;
+  }
+  
+  draw(ctx : CanvasRenderingContext2D ) : void {
+    
+    // This is drawn with (0,0) at the lower-right corner.
+    if (this.hide === true)
+      return;
+    
+    // Don't draw the widget to a tikz file.
+    if (ctx instanceof CTX)
+      return;
+    
+    let saveT = ctx.getTransform();
+    ctx.translate(this.widgetX,this.widgetY);
+    ctx.scale(this.scale,this.scale);
+    
+    var p = new Path2D();
+    
+    if (this.visBar == true)
+      {
+        // These *could* be made accessible to the user, but we already
+        // have a heap of arguments to create this thing.
+        let indDotRadius = 5.0;
+        let barThick = 3.0;
+        let indDotThick = 2.0;
+        
+        // Draw the indicator bar and dot.
+        // Bar first.
+        p.moveTo(0,indDotRadius + OpenAnimWidget.ControlsHeight);
+        p.lineTo(this.barLength,indDotRadius + OpenAnimWidget.ControlsHeight);
+        
+        // Note this circle for reference by mouse events.
+        if (this.barGrab === true)
+          this.pBar = new Path2D(p);
+        
+        ctx.lineWidth = barThick;
+        
+        ctx.stroke(p);
+        
+        // Now the dot.
+        p = new Path2D();
+        
+        let dx = Math.pow(this.decay,this.curStep);
+        
+        dx = this.barLength * (1 - 1/dx);
+        p.ellipse(dx,indDotRadius + OpenAnimWidget.ControlsHeight,
+          indDotRadius,indDotRadius,0,0,2*Math.PI);
+        
+        if (this.barGrab === true)
+          this.pDot = new Path2D(p);
+        
+        if (this.sDot == true)
+          ctx.fillStyle = OpenAnimWidget.sColor;
+        else
+          ctx.fillStyle = "red";
+        
+        ctx.fill(p);
+        
+        ctx.lineWidth = indDotThick;
+        ctx.strokeStyle = "black";
+        ctx.stroke(p);
+      }
+    
+    // There may be controls under the bar for faster/slower, pause/run
+    // and larger/smaller steps. Whatever of these is present, they should be
+    // centered, which is a pain. The total width of the pause/run controls
+    // is 40.5, obtained by checking the size of the box necessary to
+    // exactly enclose the controls. Height of that box is 14. I've set
+    // things up so that the height of the "step size" controls is also 14,
+    // and the width of that part is 32. These *could* be expressed in
+    // terms of the various constants defined below, but hard-coding is
+    // easier.
+    // These controls are drawn relative to their individual centers,
+    // so the shifting is done relative to those centers and their widths.
+    let pauseRunWidth = 40;
+    let stepsWidth = 32;
+    let intraGap = 8;
+    
+    // Here (compared to LoopWidget), I use cx and cy to shift the parts
+    // of the control down and right. The right-shift is used for centering
+    // Changing the t-matrix of ctx would work too.
+    let cy = OpenAnimWidget.BarHeight - 4;
+    let cx = this.barLength / 2;
+    
+    // We position the right bit, based on whether the left bit is present.
+    if (this.visSteps === true)
+      cx += intraGap + (pauseRunWidth / 2);
+    
+    // Used for both fast/slow "chevrons" and for up/down arrows.
+    let arrowHeight = 7;
+    
+    if (this.visFastSlow === true)
+      {
+        
+        // I made this a little tighter than for LoopWidget.
+        let arrowOffset = 12;//18;
+        let arrowDepth = 4;
+        let arrowPairSpace = 3;
+        let arrowThick = 1.25;
+    
+        // First, a pair of '>' for going faster.
+        ctx.lineWidth = arrowThick;
+        
+        if (this.sFaster == true)
+          ctx.strokeStyle = OpenAnimWidget.sColor;
+        else
+          ctx.strokeStyle = "black";
+          
+        p = new Path2D();
+        p.moveTo(cx + arrowOffset, cy);
+        p.lineTo(cx + arrowOffset + arrowDepth,cy + arrowHeight);
+        p.lineTo(cx + arrowOffset,cy + 2*arrowHeight);
+        ctx.stroke(p);           
+        
+        // You can't just shift a path. Needs to be rebuilt.
+        p = new Path2D();
+        p.moveTo(cx + arrowOffset + arrowPairSpace,cy);
+        p.lineTo(cx + arrowOffset + arrowDepth + arrowPairSpace,
+                 cy + arrowHeight);
+        p.lineTo(cx + arrowOffset + arrowPairSpace,cy + 2*arrowHeight);
+        ctx.stroke(p);
+        
+        // A rectangle for the clickable area.
+        this.pFaster = new Path2D();
+        this.pFaster.rect(cx + arrowOffset - arrowThick,cy,
+              arrowPairSpace + arrowDepth + 2*arrowThick,2*arrowHeight);
+        
+        /*
+        // BUG: testing
+        ctx.strokeStyle = "green";
+        ctx.lineWidth = 0.5;
+        ctx.stroke(this.pFaster);
+        ctx.strokeStyle = "black";
+        ctx.lineWidth = arrowThick;
+        */
+        
+        // Same idea: '<' to go slower.
+        if (this.sSlower == true)
+          ctx.strokeStyle = LoopAnimWidget.sColor;
+        else
+          ctx.strokeStyle = "black";
+        
+        p = new Path2D();
+        p.moveTo(cx - arrowOffset,cy);
+        p.lineTo(cx - arrowOffset - arrowDepth,cy + arrowHeight);
+        p.lineTo(cx - arrowOffset,cy + 2*arrowHeight);
+        ctx.stroke(p);           
+        
+        p = new Path2D();
+        p.moveTo(cx - arrowOffset - arrowPairSpace,cy);
+        p.lineTo(cx - arrowOffset - arrowDepth - arrowPairSpace,cy + arrowHeight);
+        p.lineTo(cx - arrowOffset - arrowPairSpace,cy + 2*arrowHeight);
+        ctx.stroke(p);
+        
+        // And the clickable area.
+        this.pSlower = new Path2D();
+        this.pSlower.rect(cx - arrowOffset - arrowPairSpace - arrowDepth - arrowThick,
+            cy,arrowPairSpace + arrowDepth + 2*arrowThick,2*arrowHeight);
+        
+        /*
+        // BUG: testing
+        ctx.strokeStyle = "yellow";
+        ctx.lineWidth = 0.5;
+        ctx.stroke(this.pSlower);
+        ctx.strokeStyle = "black";
+        */
+        
+        /*
+        // BUG: test box around entire thing.
+        p = new Path2D();
+        p.rect(cx - arrowOffset - arrowPairSpace - arrowDepth - arrowThick,cy,
+            2*(arrowOffset + arrowPairSpace + arrowDepth + arrowThick),
+            2*arrowHeight);
+        
+        //let temp = 2*(arrowOffset + arrowPairSpace + arrowDepth + arrowThick);
+        //console.log("val: " +temp);
+        
+        ctx.strokeStyle = "red";
+        ctx.stroke(p);
+        */
+        
+        ctx.strokeStyle = "black";
+      }
+    
+    ctx.lineWidth = 1;
+    
+    if (this.visPauseRun === true)
+      {
+        // A || or triangle for pause or run.
+        
+        let pauseSpace = 3.25;
+        let pauseThick = 1.5;
+        let pauseHeight = 2 * arrowHeight;
+        
+        let runThick = 1.5;
+        let runLeftRight = 5;
+        let runHeight = 2 * arrowHeight;
+            
+        if (this.sPauseRun == true)
+          ctx.strokeStyle = LoopAnimWidget.sColor;
+        else
+          ctx.strokeStyle = "black";
+              
+        if (this.aRunning === true)
+          {
+            // The animation is running, so show || to allow pausing.
+            ctx.lineWidth = pauseThick;
+              
+            p = new Path2D();
+            p.moveTo(cx + pauseSpace,cy);
+            p.lineTo(cx + pauseSpace,cy + pauseHeight);
+            ctx.stroke(p);
+            
+            p = new Path2D();
+            p.moveTo(cx - pauseSpace,cy);
+            p.lineTo(cx - pauseSpace,cy + pauseHeight);
+            ctx.stroke(p);
+            
+            ctx.lineWidth = 1;
+          }
+        else
+          {
+            // Animation is paused, so show triangle to run it again.
+            ctx.lineWidth = runThick;
+            
+            p = new Path2D();
+            p.moveTo(cx - runLeftRight,cy);
+            p.lineTo(cx - runLeftRight,cy + runHeight);
+            p.lineTo(cx + runLeftRight,cy + runHeight/2);
+            p.closePath();
+            ctx.stroke(p);
+          }
+        
+        // Either way (paused or running), we need the clickable area.
+        // This area is too generous for the "run" triangle, because
+        // I use the same rectangle for "pause" and "run," but no big deal.
+        this.pPauseRun = new Path2D();
+        this.pPauseRun.rect(cx - runLeftRight - runThick,
+          cy - runThick,2*runLeftRight + 2*runThick,runHeight + 2*runThick);
+        
+        /*
+        // BUG: testing
+        ctx.strokeStyle = "blue";
+        ctx.lineWidth = 0.5;
+        ctx.stroke(this.pPauseRun);
+        ctx.strokeStyle = "black";
+        */
+      }
+    
+    // And position the left controls, based on whether the ones on
+    // the right are present.
+    cy += 12.5;
+    cx = this.barLength / 2;
+    if ((this.visPauseRun === true) || (this.visFastSlow === true))
+      cx -= intraGap + stepsWidth/2;
+    
+    ctx.lineWidth = 1;
+    
+    // Symbols for adjusting the step size.
+    if (this.visSteps === true)
+      {
+        // Up and down arrows. This is a little smaller than for LoopWidget,
+        // so that the height matches the paure/run controls. I also
+        // tightened up the spacing a bit.
+        // Note that I am also using stepThick as a proxy for adjustment
+        // of the fact that the tip of the arrow head is a little tall. 
+        let stepSpace = 12;
+        let stepThick = 2.0;
+        let stepHeight = 12.5;
+        let stepArrowHeight = 5.0;
+        let stepArrowWidth = 4.0;
+        
+        ctx.lineWidth = stepThick;
+        
+        if (this.sDownStep === true)
+          {
+            ctx.strokeStyle = OpenAnimWidget.sColor;
+            ctx.fillStyle = OpenAnimWidget.sColor;
+          }
+        else
+          {
+            ctx.strokeStyle = "black";
+            ctx.fillStyle = "black";
+          }
+          
+        // Vertical line
+        p = new Path2D();
+        p.moveTo(cx - stepSpace,cy);
+        p.lineTo(cx - stepSpace,cy- stepHeight);
+        ctx.stroke(p);
+        
+        // Arrow head
+        p = new Path2D();
+        p.moveTo(cx - stepSpace,cy + stepThick);
+        p.lineTo(cx - stepSpace + stepArrowWidth,cy - stepArrowHeight + stepThick);
+        p.lineTo(cx - stepSpace - stepArrowWidth,cy - stepArrowHeight + stepThick);
+        p.closePath();
+        ctx.fill(p);
+        
+        // Clickable area for down arrow.
+        this.pDownStep = new Path2D();
+        this.pDownStep.rect(cx - stepSpace - stepArrowWidth,cy - stepHeight,
+            2*stepArrowWidth,stepHeight + stepThick);
+        
+        /*
+        // BUG: testing
+        ctx.strokeStyle = "blue";
+        ctx.lineWidth = 0.5;
+        ctx.stroke(this.pDownStep);
+        ctx.strokeStyle = "black";
+        ctx.lineWidth = stepThick;
+        */
+        
+        // Again, to the right, arrow head up.
+        if (this.sUpStep === true)
+          {
+            ctx.strokeStyle = OpenAnimWidget.sColor;
+            ctx.fillStyle = OpenAnimWidget.sColor;
+          }
+        else
+          {
+            ctx.strokeStyle = "black";
+            ctx.fillStyle = "black";
+          }
+          
+        p = new Path2D();
+        p.moveTo(cx + stepSpace,cy + stepThick);
+        p.lineTo(cx + stepSpace,cy + stepThick - stepHeight);
+        ctx.stroke(p);
+        
+        p = new Path2D();
+        p.moveTo(cx + stepSpace,cy - stepHeight);
+        p.lineTo(cx + stepSpace + stepArrowWidth,
+            cy - stepHeight + stepArrowHeight);
+        p.lineTo(cx + stepSpace - stepArrowWidth,
+            cy - stepHeight + stepArrowHeight);
+        p.closePath();
+        ctx.fill(p);
+        
+        // Clickable area for up arrow.
+        this.pUpStep = new Path2D();
+        this.pUpStep.rect(cx + stepSpace - stepArrowWidth,
+            cy - stepHeight,
+            2*stepArrowWidth,stepHeight + stepThick);
+        
+        /*
+        // BUG: testing
+        ctx.strokeStyle = "blue";
+        ctx.lineWidth = 0.5;
+        ctx.stroke(this.pUpStep);
+        ctx.strokeStyle = "black";
+        */
+        
+        ctx.lineWidth = 1;
+        
+        // A little step icon.
+        ctx.strokeStyle = "black";
+        ctx.fillStyle = "black";
+        stepThick = 1.5;
+        let stepSize = 5;
+        
+        ctx.lineWidth = stepThick;
+        
+        // Steps made as one path, starting at upper-left
+        p = new Path2D();
+        p.moveTo(cx - stepSize,cy - 2*stepSize);
+        p.lineTo(cx,cy - 2*stepSize);
+        p.lineTo(cx,cy - stepSize);
+        p.lineTo(cx + stepSize,cy - stepSize);
+        p.lineTo(cx + stepSize,cy);
+        ctx.stroke(p);
+        
+        /*
+        // BUG: Testing box around it all.
+        p = new Path2D();
+        p.rect(cx - stepSpace - stepArrowWidth,cy - stepHeight,
+          2*(stepSpace + stepArrowWidth),
+          stepHeight + stepThick);
+        
+        ctx.strokeStyle = "red";
+        ctx.lineWidth = 0.5;
+        ctx.stroke(p);
+        
+        //let temp = 2*(stepSpace + stepArrowWidth);
+        //let temp = stepHeight + stepThick;
+        //console.log("val: " + temp);
+        */
+        
+        ctx.strokeStyle = "black";
+        
+      }
+    
+    ctx.lineWidth = 1;
+    
+    ctx.setTransform(saveT);
+  }
+  
+  mouseDown( x : number , y : number ) : boolean {
+    
+    // (x,y) is given in coordinates relative to the owning figure.
+    // Return true iff these coordinates apply to this widget.
+    // BUG: This is almost identical to LoopWidget. DRY?
+    if (this.hide === true)
+      return false;
+    
+    // Adjust coordinates relative to what the draw() methods uses.
+    x -= this.widgetX;
+    y -= this.widgetY;
+    x /= this.scale;
+    y /= this.scale;
+    
+    // The widget also has a scale, which must be taken into account.
+    WidgetManager.bogusCtx.resetTransform();
+    
+    // The run faster area.
+    if (this.pFaster !== null)
+      {
+        let isin = WidgetManager.bogusCtx.isPointInPath(this.pFaster,x,y);
+        if (isin === true)
+          {
+            this.sFaster = true;
+            WidgetManager.mouseOwner = this;
+            renderFrame(this);
+            return true;
+          }
+      }
+      
+    // The run slower area.
+    if (this.pSlower !== null)
+      {
+        let isin = WidgetManager.bogusCtx.isPointInPath(this.pSlower,x,y);
+        if (isin === true)
+          {
+            this.sSlower = true;
+            WidgetManager.mouseOwner = this;
+            renderFrame(this);
+            return true;
+          }
+      }
+      
+    
+    // The pause/run area.
+    if (this.pPauseRun !== null)
+      {
+        let isin = WidgetManager.bogusCtx.isPointInPath(this.pPauseRun,x,y);
+        if (isin === true)
+          {
+            this.sPauseRun = true;
+            WidgetManager.mouseOwner = this;
+            renderFrame(this);
+            return true;
+          }
+      }
+    
+    // The longer step area.
+    if (this.pUpStep !== null)
+      {
+        let isin = WidgetManager.bogusCtx.isPointInPath(this.pUpStep,x,y);
+        if (isin === true)
+          {
+            this.sUpStep = true;
+            WidgetManager.mouseOwner = this;
+            renderFrame(this);
+            return true;
+          }
+      }
+    
+    // The shorter step area.  
+    if (this.pDownStep !== null)
+      {
+        let isin = WidgetManager.bogusCtx.isPointInPath(this.pDownStep,x,y);
+        if (isin === true)
+          {
+            this.sDownStep = true;
+            WidgetManager.mouseOwner = this;
+            renderFrame(this);
+            return true;
+          }
+      }
+    
+    // Last thing to check since it should be "underneath" everything,
+    // although I don't think there's the same kind of overlap that
+    // there was for LoopWidget.
+    if (this.pDot !== null)
+      { 
+        // See whether the user clicked on or near the dot. He must click
+        // on the dot, not at some random point along the bar.
+        WidgetManager.bogusCtx.lineWidth = 2;
+        let isin = WidgetManager.bogusCtx.isPointInStroke(this.pDot,x,y);
+        if (isin === false)
+          isin = WidgetManager.bogusCtx.isPointInPath(this.pDot,x,y);
+          
+        if (isin === true)
+          {
+            this.sDot = true;
+            
+            // Move the dot (slightly) so that it is centered at (x,y).
+            // We don't actually "move the dot;" instead we adjust
+            // this.curStep to put the dot where we want it. That is, we
+            // invert g(s) = w (1-1/a^s). See the discussion, in register(), 
+            // of this function. We have
+            // x = w (1 - 1/a^s)
+            // a^s = w / (w - x)
+            // s = log_a [ w / (w - x) ]
+            // And recall that log_a (z) = ln(z) / ln(a).
+            let ratio = this.barLength / (this.barLength - x);
+            let s = Math.log(ratio) / Math.log(this.decay);
+            if (s < 0)
+              s = 0;
+            this.curStep = s;
+            
+            WidgetManager.mouseOwner = this;
+            
+            renderFrame(this);
+    
+            return true;
+          }
+      }
+      
+    return false;
+  }
+  
+  mouseMove( x : number , y : number ) : void {
+    
+    // As above.
+    if (this.hide === true)
+      return;
+    
+    x -= this.widgetX;
+    y -= this.widgetY;
+    x /= this.scale;
+    y /= this.scale;
+    
+    WidgetManager.bogusCtx.resetTransform();
+    
+    if (this.sDot === true)
+      {
+        // What I will do it check that the mouse is "close enough" to the 
+        // bar, but it can be a long ways away.
+        WidgetManager.bogusCtx.lineWidth = 20;
+        let isin = WidgetManager.bogusCtx.isPointInStroke(this.pBar !,x,y);
+        
+        if (isin == false)
+          return;
+        
+        let ratio = this.barLength / (this.barLength - x);
+        let s = Math.log(ratio) / Math.log(this.decay);
+        if (s < 0)
+          s = 0;
+        this.curStep = s;
+        
+        // The appearance of the widget may have changed.
+        renderFrame(this);
+      }
+    
+    // BUG: I might (?) want colors to change based on what the mouse
+    // is over. See the BUG comment that goes with aRunning, sCircle, etc.,
+    // at the top of the class.
+  }
+  
+  mouseUp( x : number , y : number ) : void {
+    
+    // As above.
+    if (this.hide === true)
+      return;
+    
+    x -= this.widgetX;
+    y -= this.widgetY;
+    x /= this.scale;
+    y /= this.scale;
+    WidgetManager.bogusCtx.resetTransform();
+    
+    // The mouse is up, so nothing can remain selected. In most cases,
+    // releasing the mouse over the selected item means that something
+    // must be done since the "button" was properly pressed.
+    this.sDot = false;
+    
+    if (this.sFaster === true)
+      {
+        let isin = WidgetManager.bogusCtx.isPointInPath(this.pFaster ! ,x,y);
+        if (isin === true)
+          {
+            this.timeStep /= 1.4;
+            if (this.timeStep < 1)
+              this.timeStep = 1;
+            
+            // Stop the animation and restart it at the new speed
+            if (this.aRunning === true)
+              clearInterval(this.animID);
+            
+            this.animID = setInterval(doAnimation,this.timeStep,this);
+            this.aRunning = true;
+          }
+        
+        this.sFaster = false;
+      }
+    
+    if (this.sSlower === true)
+      {
+        // Just as above, but make it go slower.
+        let isin = WidgetManager.bogusCtx.isPointInPath(this.pSlower ! ,x,y);
+        if (isin === true)
+          {
+            this.timeStep *= 1.4;
+            
+            // More than a second per frame is silly.
+            if (this.timeStep > 1000)
+              this.timeStep = 1000;
+            
+            if (this.aRunning === true)
+              clearInterval(this.animID);
+            
+            this.animID = setInterval(doAnimation,this.timeStep,this);
+            this.aRunning = true;
+          }
+        
+        this.sSlower = false;
+      }
+    
+    if (this.sPauseRun)
+      {
+        // Did they *release* the mouse over the pause/run area?
+        let isin = WidgetManager.bogusCtx.isPointInPath(this.pPauseRun ! ,x,y);
+        if (isin === true)
+          { 
+            // Start/stop the animation.
+            if (this.aRunning === true)
+              // Currently running. Pause it.
+              clearInterval(this.animID);
+            else
+              // Currently paused. Restart it.
+              this.animID = setInterval(doAnimation,this.timeStep,this);
+            
+            // Change the pause/run icon too.
+            if (this.aRunning === true)
+              this.aRunning = false;
+            else
+              this.aRunning = true;
+          }
+          
+        this.sPauseRun = false;
+      }
+     
+    if (this.sUpStep === true)
+      {
+        // Make the number of time increments per frame larger.
+        let isin = WidgetManager.bogusCtx.isPointInPath(this.pUpStep ! ,x,y);
+        if (isin === true)
+          { 
+            // Use a smaller ratio here. Conceptually, it seems like
+            // this should be an integer, but it really doesn't have to be.
+            // Unlike LoopWidget, there's no upper limit on the number
+            // of steps per frame.
+            this.stepsPerFrame *= 1.25;
+          }
+        
+        this.sUpStep = false;
+      }
+      
+    if (this.sDownStep === true)
+      {
+        // As above.
+        let isin = WidgetManager.bogusCtx.isPointInPath(this.pDownStep ! ,x,y);
+        if (isin === true)
+          this.stepsPerFrame /= 1.25;
+        
+        this.sDownStep = false;
+      }
+    
+    // The appearance of the widget may have changed.
+    renderFrame(this);
+  }
+}
+
+
+// This is to allow dragging points around. After the much more complicated
+// animation widgets, this is a lot easier. One difference is that dots
+// are not drawn automatically; the user must call the widget's draw()
+// method. This is because the order of drawing may matter -- what should
+// be on top?
+// 
+// At one point, this was more flexible, but -- see DraggableDrawWidget below 
+// -- it seems better to keep this widget simple (just dots).
+
+class DraggableDotWidget extends Widget {
+  
+  // When things are "selected," draw them in this color.
+  static sColor = "blue";
+  
+  // The clickable area for the dot, and whether it is selected.
+  // pDot : Path2D | null = null;
+  pDot : FPath | null = null;
+  selected = false;
+  
+  // The default radius of a dot.
+  dotRadius = 3.0;
+  
+  
+  static register(ctx : CanvasRenderingContext2D , x : number , y : number ,
+        name : string ) : DraggableDotWidget {
+    
+    // As with other widgets. Note that there is no scale since it doesn't
+    // make sense here.
+    let type = "DraggableDotWidget";
+    let caller = getCaller();
+    let w = <DraggableDotWidget> WidgetManager.knownWidget(caller,type,name);
+    
+    if (w != null)
+      {
+        return w;
+      }
+    
+    // Got here, so this widget is not already known, and must be created.
+    // The 'false' here means that we always assume the dot is visible. Leting
+    // this be invisible would be pointless, although it is hidable by
+    // directly changing the Widget.hide field.
+    w = new DraggableDotWidget(caller,type,x,y,1.0,false,name);
+    
+    // Note the existence of this widget for the future.
+    WidgetManager.register(w);
+    
+    // Note that we do *not* draw this widget here.
+    
+    return w;
+  }
+  
+  draw(ctx : CanvasRenderingContext2D ) : void {
+    
+    // Because these widgets might be drawn for tikz output, this uses
+    // FPath instead of Path2D.
+    //
+    // BUG: As a rule, I don't think people will want most widgets (like
+    // LoopWidget) to be drawn to the paper version, but I suppose it should
+    // be possible. *I* would like it for documentation purposes.
+    
+    if (this.hide === true)
+      return;
+    
+    // Adjusting the coordinates this way feels a little weird, but it's
+    // how the other widgets work, and it's actually easier.
+    let saveT = ctx.getTransform();
+    ctx.translate(this.widgetX,this.widgetY);
+    ctx.scale(this.scale,this.scale);
+    
+    // BUG: Somehow, sometimes using FPath puts hair on these dots??
+    // It looks like it happens where the segments meet. There's probably
+    // some algebra mistake. Either that or the JS implementation of
+    // bezier curves sucks. For now, I do not use bezier curves, and
+    // leave it as an ellipse internally.
+    let p = new FPath();
+    //let p = new Path2D();
+    
+    let r = this.dotRadius;
+    
+    p.ellipse(0,0,r,r,0,0,2*Math.PI,true);
+    
+    //this.pDot = new Path2D(p);
+    // this.pDot = new FPath(p);
+    this.pDot = p;
+    
+    if (this.selected === true)
+      ctx.fillStyle = DraggableDotWidget.sColor;
+    else
+      ctx.fillStyle = "red";
+    
+    ctx.fill(p);
+    
+    ctx.setTransform(saveT);
+  }
+  
+  mouseDown(x: number , y : number ) : boolean {
+
+    if (this.hide === true)
+      return false;
+      
+    // Adjust coordinates relative to what the draw() methods uses.
+    x -= this.widgetX;
+    y -= this.widgetY;
+    x /= this.scale;
+    y /= this.scale;
+    
+    // The widget also has a scale, which must be taken into account.
+    WidgetManager.bogusCtx.resetTransform();
+    
+    if (this.pDot !== null)
+      {
+        let isin = WidgetManager.bogusCtx.isPointInPath(this.pDot,x,y);
+        if (isin === true)
+          {
+            this.selected = true;
+            WidgetManager.mouseOwner = this;
+            renderFrame(this);
+            return true;
+          }
+      }
+    
+    return false;
+  }
+  
+  mouseMove(x : number , y : number ) : void {
+    
+    // As above.
+    if (this.hide === true)
+      return;
+    
+    // Restrict to be within the figure area, at the least.
+    // By default (the code here, not this.drawSelFcn, whatever that might
+    // do), the dot doesn't get "lost," but it can be drawn partially outside
+    // the figure proper, leaving "crumbs" that aren't erased until you 
+    // scroll the page.
+    let wh = getFigureRect(this);
+    
+    // Rrestrict to the entire figure rectangle, tightened up a bit.
+    wh.w -= 2 * this.dotRadius;
+    wh.ha -= 2 * this.dotRadius;
+    wh.hb -= 2 * this.dotRadius;
+    
+    // Note the minus with hb. The "height below" is a postive value, but
+    // we are comparing to a potentially negative y.
+    if (x <= this.dotRadius) return;
+    if (x >= wh.w) return;
+    if (y <= -wh.hb) return;
+    if (y >= wh.ha) return;
+    
+    if (this.selected === true)
+      {
+        this.widgetX = x;
+        this.widgetY = y;
+        
+        renderFrame(this);
+      }
+  }
+  
+  mouseUp( x : number , y : number ) : void {
+    
+    if (this.hide === true)
+      return;
+    
+    // This is more round-about because of the possibility that the
+    // mouse-up occured outside the figure area. We need to reach
+    // the renderFrame() line whatever happens.
+    if (this.selected === true)
+      { 
+        this.selected = false;
+    
+        let wh = getFigureRect(this);
+        
+        wh.w -= 2 * this.dotRadius;
+        wh.ha -= 2 * this.dotRadius;
+        wh.hb -= 2 * this.dotRadius;
+        
+        // Note the minus with hb. The "height below" is a postive value, but
+        // we are comparing to a potentially negative y.
+        if ((x > this.dotRadius) && (x < wh.w) &&
+            // (y > this.dotRadius) && (y < wh.h))
+            (y > -wh.hb) && (y < wh.ha))
+          { 
+            this.widgetX = x;
+            this.widgetY = y;
+          }
+            
+        renderFrame(this);
+      }
+  }
+}
+
+
+// This is almost idential to DraggableDotWidget, except that
+// there is no default drawing behavior. The user must provide it.
+// 
+// Maybe...
+// * The user might want dots to be drawn in different ways, like a solid
+//   circle, an open circle with or without a fill of some other color, or 
+//   even a square "dot." 
+// * The motion of the point, when dragging, needs to be restricted to a 
+//   limited path or region. By default, the point is limited to the entire
+//   figure area, but that may not suffice.
+// * To address the two previous points, register() takes functions
+//   for drawing the "dot" (which need not be a dot at all), depending
+//   on whether the dot is to be drawn in selected form or unselected form.
+
+type SimpleDrawFunction = (ctx : CanvasRenderingContext2D) => FPath;
+type AcceptedDrawLocationFunction = (x : number, y : number, w : number ,
+          ha : number , hb : number) => boolean;
+
+class DraggableDrawWidget extends Widget {
+  
+  // When things are "selected," draw them in this color.
+  static sColor = "blue";
+  
+  // The clickable area for the "dot" (which could have any shape)
+  // and whether it is selected.
+  pDot : FPath | null = null;
+  selected = false;
+  
+  // The user must provide these functions.
+  // Note the litle cheat to make the ts compiler shut its yapper.
+  drawFcn : SimpleDrawFunction = null as any;
+  drawSelFcn : SimpleDrawFunction = null as any;
+  testPosFcn : AcceptedDrawLocationFunction = null as any;
+  
+  
+  static register(ctx : CanvasRenderingContext2D , x : number , y : number ,
+        drawFcn : SimpleDrawFunction, drawSelFcn : SimpleDrawFunction,
+        testPosFcn : AcceptedDrawLocationFunction , name : string ) : DraggableDrawWidget{
+    
+    // The drawFcn should be defined to draw whatevever it wants.
+    // It should take the ctx as the sole argument, and return a path
+    // such that a click in the path (using ctx.isPointInPath()).
+    //
+    // The drawSelFcn is similar, but is used for drawing when the
+    // item is selected -- so that the user can change the color or
+    // whatever.
+    //
+    // The testPosFcn receives (x,y) as an argument, along with the (w,h)
+    // of the figure area (in pdf points) and should return
+    // true (point is acceptable) or false (not acceptable).
+    
+    let type = "DraggableDrawWidget";
+    let caller = getCaller();
+    let w = <DraggableDrawWidget> WidgetManager.knownWidget(caller,type,name);
+          
+    if (w != null)
+      {
+        return w;
+      }
+    
+    // Got here, so this widget is not already known, and must be created.
+    // The 'false' here means that we always assume the dot is visible. Leting
+    // this be invisible would be pointless, although it is hidable by
+    // directly changing the Widget.hide field.
+    w = new DraggableDrawWidget(caller,type,x,y,1.0,false,name);
+    
+    w.drawFcn = drawFcn;
+    w.drawSelFcn = drawSelFcn;
+    w.testPosFcn = testPosFcn;
+   
+    // Note the existence of this widget for the future.
+    WidgetManager.register(w);
+    
+    return w;
+  }
+  
+  draw(ctx : CanvasRenderingContext2D ) : void {
+    
+    // Because these widgets might be drawn for tikz output, this uses
+    // FPath instead of Path2D.
+    //
+    // BUG: As a rule, I don't think people will want most widgets (like
+    // LoopWidget) to be drawn to the paper version, but I suppose it should
+    // be possible. *I* would like it for documentation purposes.
+    if (this.hide === true)
+      return;
+    
+    // Adjusting the coordinates this way feels a little weird, but it's
+    // how the other widgets work, and it's actually easier.
+    let saveT = ctx.getTransform();
+    ctx.translate(this.widgetX,this.widgetY);
+    ctx.scale(this.scale,this.scale);
+    
+    if (this.selected === true)
+      this.pDot = this.drawSelFcn(ctx); 
+    else
+      this.pDot = this.drawFcn(ctx);
+    
+    ctx.setTransform(saveT);
+  }
+  
+  mouseDown(x: number , y : number ) : boolean {
+    
+    //console.log("dot down");
+    
+    if (this.hide === true)
+      return false;
+      
+    // Adjust coordinates relative to what the draw() methods uses.
+    x -= this.widgetX;
+    y -= this.widgetY;
+    x /= this.scale;
+    y /= this.scale;
+    
+    WidgetManager.bogusCtx.resetTransform();
+    
+    if (this.pDot !== null)
+      {
+        let isin = WidgetManager.bogusCtx.isPointInPath(this.pDot,x,y);
+        if (isin === true)
+          {
+            this.selected = true;
+            WidgetManager.mouseOwner = this;
+            renderFrame(this);
+            return true;
+          }
+      }
+    
+    return false;
+  }
+  
+  mouseMove(x : number , y : number ) : void {
+    
+    // As above.
+    if (this.hide === true)
+      return;
+    
+    // Restrict to be within the figure area, at the least.
+    // By default (the code here, not this.drawSelFcn, whatever that might
+    // do), the dot doesn't get "lost," but it can be drawn partially outside
+    // the figure proper, leaving "crumbs" that aren't erased until you 
+    // scroll the page.
+    let wh = getFigureRect(this);
+    
+    if (this.testPosFcn(x,y,wh.w,wh.ha,wh.hb) === false)
+      return;
+    
+    if (this.selected === true)
+      {
+        this.widgetX = x;
+        this.widgetY = y;
+        
+        renderFrame(this);
+      }
+  }
+  
+  mouseUp( x : number , y : number ) : void {
+    
+    if (this.hide === true)
+      return;
+    
+    // This is more round-about because of the possibility that the
+    // mouse-up occured outside the figure area. We need to reach
+    // the renderFrame() line whatever happens.
+    if (this.selected === true)
+      { 
+        this.selected = false;
+    
+        let wh = getFigureRect(this);
+        
+        if (this.testPosFcn(x,y,wh.w,wh.ha,wh.hb) === true)
+          {
+            this.widgetX = x;
+            this.widgetY = y;
+          }
+            
+        renderFrame(this);
+      }
+  }
+  
+}
+
+
+// A numerical value widget. This uses an HTML <input type = "number">
+// thing by putting it on top of the canvas. Using HTML this way is not the
+// direction I want to go, but I do want to see if it's feasible and what's
+// involved. Certain widgets that already exist in HTML are probably not
+// worth building from scratch as "pure canvas" widgets.  Also, this
+// allows me to delay dealing with keyboard events.
+//
+// The idea is to put the HTML widget on top of the canvas, with absolute
+// placement.
+//
+// NOTE: Firefox generates a warning about "ansynchronous panning." Somehow
+// it sees that I'm doing something tricky and warns about it. As far as I
+// can tell, I'm not doing anything likely to be deprecated or problematic
+// in the future. Edge doesn't complain.
+
+class NumberInputWidget extends Widget {
+  
+  // An HTML <input type = "number"> thing. This is the HTML DOM element,
+  // like from document.getElementById() or createElement("input").
+  theWidget : HTMLInputElement | null = null;
+  
+  
+  static register( ctx : CanvasRenderingContext2D , x : number , y : number ,
+        v : number , name : string ) : NumberInputWidget {
+    
+    // Even fewer arguments than usual.
+    // v = initial value;
+    let type = "NumberInputWidget";
+    let caller = getCaller();
+    let w = <NumberInputWidget> WidgetManager.knownWidget(caller,type,name);
+    
+    if (w != null)
+      {
+        w.draw(ctx);
+        return w;
+      }
+    
+    // Got here, so this widget is not already known, and must be created.
+    w = new NumberInputWidget(caller,type,x,y,1.0,false,name);
+    
+    // Note the existence of this widget for the future.
+    WidgetManager.register(w);
+    
+    // The usual syntax for this within HTML is
+    // <input type="number" id="something" name="whatever" min="10" max="100">
+    // There are some other possible settings too. See
+    // https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/number
+    // 
+    // BUG: There's some funny business here that I don't like at all. 
+    // These DOM elements are placed relative to the body as a whole,
+    // not the canvas. So, I need to know where the figure containing
+    // this widget falls on the entire document. The body height is adjusted
+    // when I tweak the scroll bars (mainbody.style.height and width),
+    // and the widget needs to be placed relative to that.
+    //
+    // As a result, every time the user zooms (or resizes the window),
+    // every widget placed in the DOM this way needs to be repositioned.
+    // One reasonable way to deal with that is to recalculate the position
+    // every time draw() is called. 
+    //
+    // So this isn't really a BUG; it works as intended. But using
+    // HTML this way is an entirely different (and unpleasant) approach.
+    
+    w.theWidget = document.createElement("input");
+    w.theWidget.setAttribute("type","number");
+    w.theWidget.value = v.toString();
+    
+    w.theWidget.style.position = "absolute";
+    w.theWidget.style.display = "block";
+    w.theWidget.style.left = 400+"px";
+    w.theWidget.style.top = 900+"px";
+    w.theWidget.style.width = 50+"px";
+    w.theWidget.style.height = 10+"px";
+    w.theWidget.style.zIndex = "99";
+    
+    document.body.appendChild(w.theWidget);
+    
+    // The owner will want to redraw it's figure when this changes.
+    w.theWidget.onchange = function() {
+      
+      // console.log("change");
+      
+      let myFunc : AugmentedDrawingFunction = getAugmentedFunction( w.owner );
+      let fpc : FigurePanel = myFunc.figurePanelClass !;
+      fpc.render( );
+      };
+    
+    // Before returning the widget, it must be drawn.
+    w.draw(ctx);
+    
+    return w;
+  }
+  
+  getValue() {
+    
+    // Return the numerical value.
+    //
+    // BUG: This seems to return a string -- whatever is in the field.
+    // The caller will typically need to do parseInt() or parseFloat()
+    // on the result. If this widget were better, then it would know
+    // what it's supposed to return and limit the possible things it can hold.
+        
+    // BUG: I should probably have getter functions for everything in
+    // all widgets instead of having the user access fields directly.
+    // So, define LoopWidget.getCurStep(), etc.
+    // It doesn't *really* matter, but it makes it clearer to the user
+    // what he's supposed to have access to.
+    return this.theWidget ! .value;
+  }
+  
+  draw(ctx : CanvasRenderingContext2D ) : void {
+    
+    // This widget is really an HTML DOM element, so this function doesn't
+    // actually draw the widget. It repositions the element in the DOM.
+    // See the discussion in register().
+    
+    // BUG: make accessing this information a function, like I did 
+    // for getFigureRect().
+    
+    let myFunc : AugmentedDrawingFunction = getAugmentedFunction( this.owner );
+    let fpc : FigurePanel = myFunc.figurePanelClass !;
+    let totalV = fpc.totalV;
+    
+    // The vertical position is relatively easy, but the horizontal position
+    // requires a calculation similar to fullRender() since the page
+    // is centered. Also, the vertical position must be given in LH coordinates
+    // relative to the entire document.
+    // BUG: Make this calculation a function used in main.js too.
+    // Can I combine with what's done for mouse events there too?
+    // In fact, this is more like the mouse calculation than like fullRender().
+    let vpos = fpc.totalV + fpc.h - this.widgetY;
+    // let vpos = totalV + this.widgetY;
+    
+    
+    // BUG: I don't like reaching into the DOM this way to get the canvas,
+    // but what is the alternative?
+    let hpos = this.widgetX;
+    let canvas = <HTMLCanvasElement> document.getElementById("pdf_renderer");
+    let visWidth = document.documentElement.clientWidth;
+    let totWidth = FullPanel.getFullWidth();
+    
+    if (visWidth > totWidth)
+      {
+        // No horizontal scroll bar. Center it.
+        let canvasCenter = canvas.width / 2;
+        let docCenter = FullPanel.getFullWidth() / 2;
+        canvasCenter = canvasCenter / PDFDocument.getZoom();
+        
+        hpos = hpos + (canvasCenter - docCenter);
+      }
+    else
+      { 
+        // Shift according to the horizontal scroll bar.
+        hpos = hpos - window.scrollX;
+      }
+    
+    hpos += fpc.margin;
+    
+    //console.log("wid at " +hpos+ " " +vpos);
+    
+    // Don't forget the stupid "px"!  
+    this.theWidget ! .style.top = vpos +"px";
+    this.theWidget  ! .style.left = hpos +"px";
+  }
+}
+
+// Another DOM-based widget. A simple button.
+
+class ButtonWidget extends Widget {
+  
+  // An HTML <input type = "button"> thing. 
+  theWidget : HTMLButtonElement | null = null;
+  
+  // Sometimes you want to treat the button as a boolean
+  // Each time the button is clicked, this toggles.
+  clickState = false;
+
+  // And this is set to true whenever the button is clicked.
+  resetState = false;
+  
+  static register(ctx : CanvasRenderingContext2D , x : number , y : number ,
+    text : string , name : string ) : Widget {
+    
+    // Even fewer arguments than usual.
+    let type = "ButtonWidget";
+    let caller = getCaller();
+    let w = <ButtonWidget> WidgetManager.knownWidget(caller,type,name);
+    
+    if (w != null)
+      {
+        w.draw(ctx);
+        return w;
+      }
+    
+    // Got here, so this widget is not already known, and must be created.
+    w = new ButtonWidget(caller,type,x,y,1.0,false,name);
+    
+    // Note the existence of this widget for the future.
+    WidgetManager.register(w);
+    
+    // The usual syntax for this within HTML is
+    // <button type="button" id="something" name="whatever">
+    // 
+    // BUG: There's some funny business here that I don't like at all. 
+    // These DOM elements are placed relative to the body as a whole,
+    // not the canvas. So, I need to know where the figure containing
+    // this widget falls on the entire document. The body height is adjusted
+    // when I tweak the scroll bars (mainbody.style.height and width),
+    // and the widget needs to be placed relative to that.
+    //
+    // As a result, every time the user zooms (or resizes the window),
+    // every widget placed in the DOM this way needs to be repositioned.
+    // One reasonable way to deal with that is to recalculate the position
+    // every time draw() is called. 
+    //
+    // So this isn't really a BUG; it works as intended. But using
+    // HTML this way is an entirely different (and unpleasant) approach.
+    
+    w.theWidget = document.createElement("button");
+    w.theWidget.setAttribute("type","button");
+    w.theWidget.style.fontSize = "10px";
+    w.theWidget.textContent = text;
+    
+    w.theWidget.style.position = "absolute";
+    w.theWidget.style.display = "block";
+    w.theWidget.style.left = 400+"px";
+    w.theWidget.style.top = 900+"px";
+    //w.theWidget.style.width = 100+"px"; // Width automatic, based on text.
+    w.theWidget.style.height = 18+"px";
+    w.theWidget.style.zIndex = "99";
+    
+    document.body.appendChild(w.theWidget);
+    
+    // Need to hear about clicks....
+    // BUG: I would have thought that this would work, but I don't think that
+    // the doClick() method is seeing the correct class instance or something.
+    //w.theWidget.addEventListener('click',w.doClick,false);
+    
+    // Instead, define the action here.
+    w.theWidget.addEventListener('click',() => {
+      
+    if (w.clickState === false)
+      w.clickState = true;
+    else
+      {
+        w.clickState = false;
+        w.resetState = true;
+      }
+    
+    
+    // If the figure is part of an animation, then it will be drawn taking
+    // into account this click in the next frame. If the figure is *not*
+    // an animation, then we need to refresh.
+    let myFunc : AugmentedDrawingFunction = getAugmentedFunction( w.owner );
+    let fpc : FigurePanel = myFunc.figurePanelClass !;
+    fpc.render();
+    },false);
+    
+    // Before returning the widget, it must be drawn.
+    w.draw(ctx);
+    
+    return w;
+  }
+  
+  doClick() {
+    // BUG: This doesn't work. See above.
+    if (this.clickState === false)
+      this.clickState = true;
+    else
+      this.clickState = false;
+    
+    //console.log("swapped click");
+  }
+
+  draw( ctx : CanvasRenderingContext2D ) : void {
+    
+    // This widget is really an HTML DOM element, so this function doesn't
+    // actually draw the widget. It repositions the element in the DOM.
+    // See the discussion in register().
+    
+    let myFunc : AugmentedDrawingFunction = getAugmentedFunction( this.owner );
+    let fpc : FigurePanel = myFunc.figurePanelClass !;
+    
+    // The horizontal position requires a calculation similar to fullRender()
+    // since the page is centered and the vertical position must be given
+    // in LH coordinates relative to the entire document.
+    // BUG: Make this calculation a function used in main.js too.
+    // Can I combine with what's done for mouse events there too?
+    // In fact, this is more like the mouse calculation than like fullRender().
+    let vpos = fpc.totalV + fpc.h - this.widgetY;
+    
+    let hpos = this.widgetX;
+    // BUG: Again, with the DOM access.
+    let canvas = <HTMLCanvasElement> document.getElementById("pdf_renderer");
+    let visWidth = document.documentElement.clientWidth;
+    let totWidth = FullPanel.getFullWidth();
+    
+    if (visWidth > totWidth)
+      {
+        // No horizontal scroll bar. Center it.
+        let canvasCenter = canvas.width / 2;
+        let docCenter = FullPanel.getFullWidth() / 2;
+        canvasCenter = canvasCenter / PDFDocument.getZoom();
+        
+        hpos = hpos + (canvasCenter - docCenter);
+      }
+    else
+      { 
+        // Shift according to the horizontal scroll bar.
+        hpos = hpos - window.scrollX;
+      }
+    
+    hpos += fpc.margin;
+    
+    // It seems that these must be placed using style.top, not style.bottom.
+    // The clientHeight seems to be the height of the text in the button,
+    // which style.height is the actually button. Don't forget the stupid "px"! 
+    let w : HTMLButtonElement = this.theWidget ! ;
+    w.style.top = (vpos - parseInt(w.style.height , 10) ) +"px";
+    w.style.left = hpos +"px";
+  }
+}
+

Added: trunk/Master/texmf-dist/doc/latex/figput/javascript/figput.html
===================================================================
--- trunk/Master/texmf-dist/doc/latex/figput/javascript/figput.html	                        (rev 0)
+++ trunk/Master/texmf-dist/doc/latex/figput/javascript/figput.html	2022-07-22 21:48:41 UTC (rev 63957)
@@ -0,0 +1,42 @@
+
+<!doctype html>
+
+<html lang="en">
+<head>
+  <meta charset="utf-8">
+  <title>FigPut Viewer</title>
+
+  <!-- The pdf.js stuff, from Mozilla. -->
+  <script src="pdf.js"></script>
+  <script src="pdf.worker.min.js"></script>
+
+  <!-- FigPut code -->
+  <script src="layout.js"></script>
+  <script src="tikz.js"></script>
+  <script src="widgets.js"></script>
+  <script src="main.js"></script>
+
+  <style>
+    /* Put the canvas right up to the edge of the visible area of the window. */
+    body {
+      padding: 0;
+      margin: 0;
+    }
+  </style>
+</head>
+
+
+<!-- 
+Note that 'unknown1' will be changed to the project's name as this file 
+is being served. If the pdf generated by LaTeX is called math.pdf, then 
+'unknown1' will become 'math'.
+BEWARE: This works by replacing every occurence of 'unknown1' in this file,
+so don't use 'unknown1' for anything else.
+The same basic thing is going on with unknowny, but it is used for scroll
+position
+--> 
+<body onload="doOpenDocument('unknown1',unknowny)" id="mainbody">
+  <canvas id="pdf_renderer"></canvas>
+</body>
+</html>
+


Property changes on: trunk/Master/texmf-dist/doc/latex/figput/javascript/figput.html
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: trunk/Master/texmf-dist/doc/latex/figput/javascript/layout.js
===================================================================
--- trunk/Master/texmf-dist/doc/latex/figput/javascript/layout.js	                        (rev 0)
+++ trunk/Master/texmf-dist/doc/latex/figput/javascript/layout.js	2022-07-22 21:48:41 UTC (rev 63957)
@@ -0,0 +1,489 @@
+"use strict";
+/*
+Code for page layout. The idea is a bit like Java Swing (or a zillion other
+similar setups), but stripped down to only what I need. In particular, the
+Panels are assumed to be stacked vertically.
+
+Everything is accessed through FullPanel, which consists of a list of
+PagePanel objects. These are stacked vertically, and each one contains at
+least one PDFPanel, and may contain FigurePanels. In the lingo of something
+like Java, it would be better to think of PagePanel as a Container or a Box
+since it's used for layout and doesn't directly do anything other than pass
+things to its sub-parts.
+
+*/
+// This class is the only thing that should be touched by code outside
+// this file. FullPanel.init() is called to set up page layout.  Everything
+// is static since there is only one window/canvas.
+class FullPanel {
+    static init(specList) {
+        // Add all the pages to this document. specList is PDFDocument.pageSpecs. 
+        // Each element of specList corresponds to page.
+        // Call this once, when the program starts, to set up the page layout.
+        let cumV = 0;
+        for (let i = 0; i < specList.length; i++) {
+            let pp = new PagePanel(i, specList[i], cumV);
+            this.thePages[i] = pp;
+            cumV += pp.h;
+        }
+    }
+    static async renderAll(height) {
+        // Render every PagePanel in FullPanel.thePages.
+        // Internal to this function, the height should be in "page pixels," 
+        // meaning the number of pixels tall the destination canvas is at the 
+        // current zoom ratio of the offsreen pages.
+        height = height / PDFDocument.getZoom();
+        // Because of the use of promises by pdf.js, rendering is broken into
+        // two steps: pre-render and the actual rendering. Pre-rendering
+        // generates a bunch of promises (the pages rendered offscreen) and
+        // rendering can't be done until those promises resolve.
+        let ps = [];
+        for (let i = 0; i < this.thePages.length; i++) {
+            let p = this.thePages[i].preRender(height);
+            ps.push(p);
+        }
+        // Don't return until this is done! 
+        await Promise.all(ps);
+        for (let i = 0; i < this.thePages.length; i++)
+            this.thePages[i].render(height);
+        // Eliminate any excess pages from the buffer of offscreen pages.
+        // Do this after copying out, just in case there *is* some weird
+        // problem with race conditions.
+        PDFDocument.trimBuffer();
+    }
+    static totalHeight() {
+        // Return the total height of all pages. This is used to set up 
+        // the scroll bars.
+        let answer = 0;
+        for (let i = 0; i < this.thePages.length; i++)
+            answer += this.thePages[i].h;
+        return answer;
+    }
+    static getFullWidth() {
+        // Return the width of the widest page. Most of the time, the pages of
+        // a document all have the same width, but they might not in some
+        // rare case. This is needed to center things left/right in the window.
+        if (this.totalWidth > 0)
+            return this.totalWidth;
+        // Need to calculate it for the first time.
+        for (let i = 0; i < this.thePages.length; i++) {
+            let pp = this.thePages[i];
+            if (pp.w > this.totalWidth)
+                this.totalWidth = pp.w;
+        }
+        return this.totalWidth;
+    }
+    static mouseDown(x, y) {
+        // (x,y) is in pdf points, relative to the  entire document.
+        // So y will be a huge number if it's on the umpteeth page.
+        // To save CPU, I could start off by checking whether x is in 
+        // [0,pageWidth] and return if it is not, but the user might want to
+        // place controls outside the page. This is unlikely, but possible.
+        // Whoever had focus loses it. It may be taken up by some other widget
+        // (or the same widget again), but nobody has focus by default.
+        WidgetManager.focusOwner = null;
+        // Figure out which page this is and hand it off.
+        let i = 0;
+        for (; i < this.thePages.length; i++) {
+            if (this.thePages[i].v > y) {
+                // Found the first and only page this could be. It was the
+                // page previous to this one.
+                i -= 1;
+                break;
+            }
+        }
+        // If we got here then it had to be the very last page.
+        if (i === this.thePages.length)
+            i = this.thePages.length - 1;
+        // Safety check:
+        if ((i == this.thePages.length) || (i < 0))
+            return;
+        this.thePages[i].mouseDown(x, y);
+    }
+    static mouseMove(x, y) {
+        // As above. However, these are only of interest if some widget
+        // "owns" the mouse -- something was clicked on so that motion
+        // could mean something.
+        if (WidgetManager.mouseOwner === null)
+            return;
+        // Although we know exactly which widget will ultimately get this
+        // event, it's easier to let this pass through the layout hierarchy,
+        // just as for mouseDown(), so that the coordinates are properly adjusted.
+        // BUG: Not DRY.
+        let i = 0;
+        for (; i < this.thePages.length; i++) {
+            if (this.thePages[i].v > y) {
+                i -= 1;
+                break;
+            }
+        }
+        if (i === this.thePages.length)
+            i = this.thePages.length - 1;
+        if ((i == this.thePages.length) || (i < 0))
+            return;
+        this.thePages[i].mouseMove(x, y);
+    }
+    static mouseUp(x, y) {
+        // The big issue here is that the mouse was released so that ownership 
+        // is once again up for grabs. In addition, certain widgets will want
+        // to know where the mouse was released. Buttons are a good example.
+        // You could have mouse-down on the button, then the user moves the
+        // mouse out of the button and releases it; the button should only be
+        // "clicked" if the mouse was released over the button.
+        //
+        // An annoying thing here is that the *only* widget that could care about
+        // this (at least, as designed) is the one that owns the mouse-down.
+        // As above, we want the event to pass through the layout hierarchy
+        // so that (x,y) is adjusted for the right frame, but the ultimate
+        // *consumer* of the event may not even be on the page where the
+        // mouse-up occured.
+        // BUG: Not DRY.
+        if (WidgetManager.mouseOwner === null)
+            return;
+        let i = 0;
+        for (; i < this.thePages.length; i++) {
+            if (this.thePages[i].v > y) {
+                i -= 1;
+                break;
+            }
+        }
+        if (i === this.thePages.length)
+            i = this.thePages.length - 1;
+        if ((i == this.thePages.length) || (i < 0))
+            return;
+        this.thePages[i].mouseUp(x, y);
+        // Whatever happened above, the mouse is now up for grabs.
+        WidgetManager.mouseOwner = null;
+    }
+}
+// The full document consists of a list of PagePanel objects.
+// thePages[i] is the i-th page, counting from zero.
+FullPanel.thePages = [];
+// The width of the widest page of the entire document. Don't access
+// this directly; use getFullWidth().
+FullPanel.totalWidth = -1;
+// A PagePanel is the top-level thing, just under the canvas. Each
+// PagePanel makes up a single page of the printed document. There's
+// a list of them in FullPanel. It includes references to the PDFPanel 
+// and FigurePanel objects that it contains.
+class PagePanel {
+    constructor(pageNum, pageSpec, v) {
+        // Every panel has a vertical position within the entire document and height,
+        // in pdf pts. The vertical postion, v, is the top of the page, so the page
+        // extends from v to v+h. The caller must ensure that the Panels stack up
+        // correctly since there is no real page layout.
+        //
+        // In some ways the height, h, is redundant since it could be worked
+        // out from the heights of the individual sub-parts. In fact (see below)
+        // it *is* worked out by the constuctor, but it's easier to do it once
+        // and be done with it. This is the height of the page, as rendered,
+        // taking into account any mismatch due to extra "padding" in the figures
+        // (if there is any, and there often is not).
+        this.v = 0;
+        this.w = 0;
+        this.h = 0;
+        // page number, counting from zero.
+        this.pageNum = 0;
+        // The SubPanels that make up this PagePanel.
+        this.parts = [];
+        // This implicitly applies to the global (because everything is static)
+        // PDFDocument. pageNum is which page this is, counting from zero.
+        // pageSpec has the info about how the page breaks into pieces and the
+        // relevant figures. v is where this page lies in the entire vertical 
+        // list of pages.
+        this.w = pageSpec.pageWidth;
+        this.v = v;
+        this.pageNum = pageNum;
+        // Create the PDFPanels and FigurePanels in this PagePanel.
+        let s = pageSpec;
+        if (s.insertPoint.length == 0) {
+            // There are no figures on this page.
+            let p = new PDFPanel(pageNum, this.v, 0, 0, this.v, this.w, s.pageHeight);
+            this.h = s.pageHeight;
+            this.parts = [p];
+        }
+        else {
+            // There are figures.
+            let srcV = 0;
+            let destV = 0;
+            let totalV = v;
+            for (let j = 0; j < s.insertPoint.length; j++) {
+                // Bit of pdf above figure.
+                let p = new PDFPanel(pageNum, this.v, srcV, destV, totalV, this.w, s.insertPoint[j] - srcV);
+                destV += s.insertPoint[j] - srcV;
+                totalV += s.insertPoint[j] - srcV;
+                let f = new FigurePanel(this.v, destV, totalV, this.w, s.deleteHeight[j] + s.aboveHeight[j] + s.belowHeight[j], s.aboveHeight[j], s.belowHeight[j], s.leftMargin, s.textWidth, s.drawFcn[j]);
+                srcV = s.insertPoint[j] + s.deleteHeight[j];
+                destV += s.deleteHeight[j] + s.aboveHeight[j] + s.belowHeight[j];
+                totalV += s.deleteHeight[j] + s.aboveHeight[j] + s.belowHeight[j];
+                this.parts.push(p);
+                this.parts.push(f);
+            }
+            // And the bit of pdf below the last figure on the page.
+            let p = new PDFPanel(pageNum, this.v, srcV, destV, totalV, this.w, s.pageHeight - srcV);
+            this.parts.push(p);
+            this.h = destV + s.pageHeight - srcV;
+        }
+    }
+    async preRender(height) {
+        // This renders the underlying page of pdf. It returns a promise
+        // so that the caller can wait for the promise to resolve before
+        // attempting to copy from the rendered page.
+        //
+        // The vpos is where the top of the ctx should be relative to the entire
+        // document, in pdf pts, and height is how much is visible, in rendered
+        // page pixels.
+        // The first question is whether any of this page is visible.
+        let vpos = window.scrollY;
+        if (this.v + this.h < vpos)
+            // Entire page is above the visible area.
+            return;
+        if (this.v > vpos + height)
+            // Entire page is below the visible area.
+            return;
+        // Got here, so some portion of the page is visible.
+        await PDFDocument.render(this.pageNum);
+    }
+    render(height) {
+        // Render every SubPanel of the current PagePanel.
+        // BUG: Before returning, turn off any of these animations that are
+        // definitely not visible.
+        let vpos = window.scrollY;
+        if (this.v + this.h < vpos)
+            return;
+        if (this.v > vpos + height)
+            return;
+        // Got here, so some portion of the page is visible. From here on, 
+        // render everything, whether it's actually visible or not.
+        let ctx = ctxTopLevelAdjust();
+        // Call the parts of the page. These could be PDFPanel or FigurePanel
+        // objects.
+        for (let i = 0; i < this.parts.length; i++)
+            this.parts[i].render();
+        // BUG: I don't like this use of zoom here. Maybe no choice?
+        let z = PDFDocument.getZoom();
+        // Put a rectangle aroud the entire page. I'm not 100% convinced that
+        // I like this.
+        ctx.strokeStyle = "black";
+        ctx.strokeRect(0, 0, this.w * z, this.h * z);
+    }
+    mouseDown(x, y) {
+        // Mouse clicked on this page.
+        // y is given relative to the entire document; make it page-relative.
+        y -= this.v;
+        // Only clicks on a figure could be of interest.
+        for (let i = 0; i < this.parts.length; i++) {
+            // Either a PDFPanel or a FigurePanel.
+            let p = this.parts[i];
+            if (p instanceof PDFPanel)
+                continue;
+            // p must be a FigurePanel.
+            if ((p.destV <= y) && (y <= p.destV + p.h))
+                return p.mouseDown(x, y);
+        }
+    }
+    mouseMove(x, y) {
+        // As above. Note that this event could go to the "wrong" figure,
+        // but that's OK. Also, if the mouse is over a PDFPanel, and not
+        // a figure, then the event dies here, which is also OK.
+        y -= this.v;
+        for (let i = 0; i < this.parts.length; i++) {
+            let p = this.parts[i];
+            if (p instanceof PDFPanel)
+                continue;
+            if ((p.destV <= y) && (y <= p.destV + p.h))
+                p.mouseMove(x, y);
+        }
+    }
+    mouseUp(x, y) {
+        // As above, but the event can't be allowed to die. The owning widget
+        // must hear about the mouse up. At the same time, we can't just
+        // inform the widget directly of the mouse up since we also need to
+        // pass the correct coordinates. 
+        y -= this.v;
+        for (let i = 0; i < this.parts.length; i++) {
+            let p = this.parts[i];
+            // This is different than above since *somebody* must take the event,
+            // and the relevant widget must hear about it. If the event is over
+            // a PDFPanel, then tell the widget using crazy coordinates. It 
+            // doesn't matter exactly where the mouse was released; it only 
+            // matters that it wasn't released anywhere near the widget.
+            if ((p.destV <= y) && (y <= p.destV + p.h)) {
+                if (p instanceof PDFPanel)
+                    WidgetManager.mouseOwner.mouseUp(10000000000000, 10000000000000);
+                else
+                    // Over a figure.
+                    p.mouseUp(x, y);
+            }
+        }
+    }
+}
+// A PagePanel consists of one or more SubPanels.
+class SubPanel {
+    constructor(v, totalV, w, h) {
+        // The vertical position and height within a page, with zero being at the
+        // top, and measured in pdf points. This height, h, is the total height.
+        // There's no ambiguity to this height for PDFPanel subclasses, but for
+        // FigurePanel subclasses, it is the sum of the latex height 
+        // (PageData.deleteHeight), plus any additional padding as given in 
+        // PageData.aboveHeight/belowHeight.
+        this.destV = 0;
+        this.h = 0;
+        this.w = 0;
+        // The position of this panel within the entire document.
+        // The only reason for this is the possible use of HTML DOM elements
+        // as widgets within a figure. I would prefer not to use those at all,
+        // but sometimes it's easier. See the NumberInputWidget for one example.
+        this.totalV = 0;
+        this.destV = v;
+        this.totalV = totalV;
+        this.w = w;
+        this.h = h;
+    }
+    // Will be filled in by sub-class.
+    render() {
+        console.log("Error: called SubPanel.render()!");
+    }
+    mouseDown(x, y) {
+        console.log("Error: called SubPanel.mouseDown()!");
+    }
+    mouseMove(x, y) {
+        console.log("Error: called SubPanel.mouseMove()!");
+    }
+    mouseUp(x, y) {
+        console.log("Error: called SubPanel.mouseUp()!");
+    }
+}
+// Used for portions of a page consisting of rendered pdf.
+class PDFPanel extends SubPanel {
+    constructor(pageNum, offsetV, srcV, destV, totalV, w, h) {
+        // The pageNum is given relative to the global PDFDocument. The srcV
+        // and destV are locations relative to the page (in pdf points, with the
+        // top of the page at v=0) and h is the height of this piece, which
+        // is the same for src and dest.
+        super(destV, totalV, w, h);
+        // The page numbers start at zero and positions are given in pdf points.
+        this.pageNum = 0;
+        this.srcV = 0;
+        // BUG: I think I can fold this in elsewhere. It's the same as PagePanel.v.
+        this.offsetV = 0;
+        this.pageNum = pageNum;
+        this.srcV = srcV;
+        this.offsetV = offsetV;
+    }
+    render() {
+        // Render a portion of the current page. 
+        let theCanvas = PDFDocument.getCanvas(this.pageNum);
+        if (theCanvas === null) {
+            // I'm sure how this happens, but it does occasionally.
+            // It doesn't cause any noticable problems. It seems to happen
+            // if you move the scroll thumb too fast.
+            return;
+        }
+        // BUG: I don't like this use of zoom here. Maybe no choice?
+        let z = PDFDocument.getZoom();
+        let ctx = ctxTopLevelAdjust();
+        // Adjust for scroll bar.
+        ctx.translate(0, (this.offsetV - window.scrollY) * z);
+        // Arguments here: 
+        // the source image (or canvas),
+        // the source (x,y),
+        // the source (width,height),
+        // the destination (x,y),
+        // the destination (width,height),
+        // It's confusing because optional things typically come after
+        // required things, but not here somehow.
+        ctx.drawImage(theCanvas, 0, this.srcV * z, theCanvas.width, this.h * z, 0, this.destV * z, theCanvas.width, this.h * z);
+    }
+}
+class FigurePanel extends SubPanel {
+    constructor(pageV, destV, totalV, w, h, upperPadding, lowerPadding, margin, textWidth, drawFcn) {
+        // As for PDFPanel, plus the margin is the amount by which to shift the 
+        // drawing to the right so that the origin is in line with the text.The 
+        // drawFcn is the function provided through Latex.
+        // This is just the name of the function, as a string.
+        super(destV, totalV, w, h);
+        // Page's v position. This is the position of the page on which
+        // this figure appears relative to the entire document.
+        this.pageV = 0;
+        // This margin is the location of the left edge of the text, as
+        // reported by latex.
+        this.margin = 0;
+        // Also from Latex (via figures.aux). This I have more confidence in.
+        this.textWidth = 0;
+        // The height in SubPanel.h is the total height of the figure, including
+        // any padding above or below. The origin used for the figure occurs at
+        // a y-value that is PageData.belowHeight *above* the total height.
+        // lowerPadding is equal to PageData.belowHeight for this figure.
+        this.lowerPadding = 0;
+        this.upperPadding = 0;
+        this.pageV = pageV;
+        this.upperPadding = upperPadding;
+        this.lowerPadding = lowerPadding;
+        this.margin = margin;
+        this.textWidth = textWidth;
+        this.drawFcn = drawFcn;
+    }
+    render() {
+        // Save this for widgets and animations to use.
+        let ctx = ctxTopLevelAdjust();
+        let z = PDFDocument.getZoom();
+        ctx.translate(0, (this.pageV - window.scrollY) * z);
+        // Erase the full width of the page. this.w is the correct width,
+        // but the origin will be shifted for drawing. So, erase, then 
+        // return the origin to where it was and start over.
+        // Shift to where the figure appears and erase.
+        ctx.translate(0, this.destV * z);
+        ctx.scale(z, z);
+        // The small adjustment here is to prevent erasing the rectangle
+        // that encloses the entire page.
+        ctx.clearRect(1, 0, this.w - 2, this.h);
+        // Return to the orginal t-matrix, then shift down and right before
+        // drawing the figure (and widgets).
+        // What we want is for the origin to be at the lower-right and
+        // right-handed, adjusted upwards by this.lowerPadding too.
+        ctx = ctxTopLevelAdjust();
+        ctx.translate(0, (this.pageV - window.scrollY) * z);
+        ctx.translate(this.margin * z, (this.destV + this.h - this.lowerPadding) * z);
+        ctx.scale(1, -1);
+        ctx.scale(z, z);
+        // Tack this FigurePanel onto the underlying figure-drawing code.
+        // The first time the figure is rendered, this is set, and it's re-set
+        // to the same value with every subsequent call. That seems like 
+        // pointless extra work, but it gets the job done.
+        this.drawFcn.figurePanelClass = this;
+        this.drawFcn(ctx);
+    }
+    mouseDown(x, y) {
+        // (x,y) is in pdf points, relative to the top-left of the page.
+        // Adjust to be relative to the figure, but still LH, relative
+        // to the top of the figure.
+        y -= this.destV;
+        x -= this.margin;
+        // y is now given relative to the top edge of the figure, getting
+        // larger as you go *down* the page.
+        // Convert y to be RH relative to the correct origin, taking
+        // any padding into account. This is confusing. At this stage,
+        // y is the distance below the figure's top edge. Call that y0.
+        // We want the distance above the lower padding (if any); call
+        // that y1. The distance above the lower *edge* of the figure 
+        // is this.h - y0, and from this we subtract the padding.
+        y = (this.h - y) - this.lowerPadding;
+        // Pass to the relevant widget.
+        WidgetManager.mouseDown(this.drawFcn, x, y);
+    }
+    mouseMove(x, y) {
+        // As above.
+        y -= this.destV;
+        x -= this.margin;
+        y = (this.h - this.lowerPadding) - y;
+        WidgetManager.mouseMove(this.drawFcn, x, y);
+    }
+    mouseUp(x, y) {
+        // As above.
+        y -= this.destV;
+        x -= this.margin;
+        y = (this.h - this.lowerPadding) - y;
+        WidgetManager.mouseUp(this.drawFcn, x, y);
+    }
+}

Added: trunk/Master/texmf-dist/doc/latex/figput/javascript/main.js
===================================================================
--- trunk/Master/texmf-dist/doc/latex/figput/javascript/main.js	                        (rev 0)
+++ trunk/Master/texmf-dist/doc/latex/figput/javascript/main.js	2022-07-22 21:48:41 UTC (rev 63957)
@@ -0,0 +1,833 @@
+"use strict";
+/*
+
+Main entry point for all the js code behind the browser interface.
+ 
+This has the initialization code, to load the pdf and the data specifying
+how figures are drawn and laid out, plus the top-level stuff to direct
+events to the proper place for handling.
+
+The same code is used for developing the document, and for serving it
+from a public-facing website, with a few changes. Look for "PUBLIC FACING"
+annotations. Note also that it would be possible to strip considerably
+more code away for the public-facing version, but there's no pressing
+reason to do it -- the savings would be tiny -- and it could lead to
+an error of some kind due to unforeseen dependencies on the deleted
+code.
+
+*/
+// In rare cases, I need to know the browser. Note it first, before doing
+// anything else. This userAgent is a longish bit of blather specifying
+// the browser, and the easiest way to deal with it is to check whether
+// certain strings appear.
+var theBrowser = function () {
+    let blah = navigator.userAgent;
+    if (blah.indexOf("Firefox") > -1)
+        return "Firefox";
+    // MS Edge is also "Chrome," at least for my purposes.
+    if (blah.indexOf("Chrome") > -1)
+        return "Chrome";
+    // Assume "Chrome" as the default.
+    console.log("MAKING DEFAULT 'CHROME' ASSUMPTION ABOUT THE BROWSWER!!!");
+    return "Chrome";
+}();
+// JS has poor to non-existent facilities for dealing with thread scheduling.
+// In a lot of JS code that doesn't matter, but the pdf.js library, on which
+// this entire thing rests, makes heavy use of Promises and workers. Fortunately, 
+// there's a simple way of managing this. 
+//
+// To use this, the caller says
+// await sleep(100);
+// and the "await" is crucial. This works because setTimeout() takes a 
+// function to run, and some amount of time to wait before running that
+// function. 
+//
+// This isn't a satisfying solution because it requires "await."
+// For that reason it can only be used in async functions.
+function sleep(ms) {
+    // ms is milliseconds, not microseconds. 
+    return new Promise(resolve => setTimeout(resolve, ms));
+}
+function getAugmentedFunction(fcnName) {
+    // This converts from a function name, as specified by the user in their latex
+    // document to the internally more useful AugmentedDrawingFunction. Doing this
+    // kind of conversion feels icky, but any alternative I've come up with requires
+    // that the person using FigPut know more than the absolute minimum about what's
+    // behind the curtain.
+    //
+    // References to these functions come into the program at two points. First, when
+    // the document is loaded, a list of the relevant drawing functions is provided
+    // by latex. Second, when the user creates widgets within his drawings, these 
+    // widgets must belong to a particular drawing and the function (or its name, as
+    // a string) is used as the key under which the widget is filed.
+    // BUG: This double-cast and use of 'any' is horrible, but is there
+    // anything better?
+    return window[fcnName];
+}
+// Data related to the document pages and figures. Each page
+// has one of these in PDFDocument.pageSpecs. This is all
+// static data once the document has been loaded.
+// BUG: Should this be a type? An interface?
+class PageData {
+    constructor() {
+        // Note that pageHeight is the height of a *printed* page. If the page
+        // has a figure whose height is different than the deleted height, then
+        // the page height, as rendered, will be different than this value.
+        // Also, the margins and textWidth are only valid when there is a
+        // figure to render since they come from figures.aux.
+        // For reference, 8.5 x 11 inch paper is 612 x 792 pts; 
+        // A4 paper is 8.27 x 11.69 inch or 595.44 x 841.68 pts.
+        // However, it seems that latex sometimes produces slightly different
+        // dimensions of what must be A4 paper.
+        this.pageHeight = 0;
+        this.pageWidth = 0;
+        this.leftMargin = 0;
+        this.rightMargin = 0;
+        this.textWidth = 0;
+        // These arrays have one entry for each interactive figure on the page.
+        // insertPoint is the position, from the top, at which the figure is
+        // inserted. deleteHeight is how much of the latex doc is omitted, and
+        // above/belowHeight is how much room to leave in the browser window for
+        // the figure. name is the name of the function to call to draw the
+        // figure, done is whether to generate new tikz
+        this.insertPoint = [];
+        this.deleteHeight = [];
+        this.aboveHeight = [];
+        this.belowHeight = [];
+        this.name = [];
+        this.done = [];
+        // For each figure, there is a corresponding function (that will be
+        // augmented with a drawing target). These values make the name values
+        // given above conceptually redundant.
+        this.drawFcn = [];
+    }
+}
+// Everything related to the pdf document is here. Its main purpose is 
+// to handle off-screen rendering. It's all static since there can only be
+// one pdf open at a time. It does include data about how to lay out the 
+// figures, but none of the code that does it.
+//
+// I tried making this a module, but really no advantage over a class,
+// and definitely some disadvantages.
+class PDFDocument {
+    static async setPDF(thePDF) {
+        // Take the newly loaded pdf and note some of it's stats.
+        // Once this is loaded, thePDF never needs to be accessed again
+        // from outside this class.
+        this.pdf = thePDF;
+        this.numberOfPages = thePDF.numPages;
+        // It seems that pdfjs counts pages from one, not zero.
+        for (let i = 1; i <= this.numberOfPages; i++) {
+            await thePDF.getPage(i).then(function (page) {
+                // Note the i-1 here since I want arrays to start at zero.
+                PDFDocument.pageSpecs[i - 1] = new PageData();
+                PDFDocument.pageSpecs[i - 1].pageWidth = page.view[2];
+                PDFDocument.pageSpecs[i - 1].pageHeight = page.view[3];
+                // Make sure that the shared buffer arrays are all fully allocated.
+                PDFDocument.theCanvases[i - 1] = null;
+                PDFDocument.pageAge[i - 1] = 0;
+            });
+        }
+    }
+    static isLoaded() {
+        if (this.pdf === null)
+            return false;
+        else
+            return true;
+    }
+    static getZoom() {
+        return this.zoom;
+    }
+    static setZoom(z) {
+        this.zoom = z;
+        this.flushBuffer();
+    }
+    static getCanvas(n) {
+        // Return the canvas for page number n (counting from zero). 
+        // This assumes that the canvas is available due to a previous
+        // call to render(n) -- which must have resolved by the time this
+        // method is called.
+        // BUG: This shouldn't happen, but maybe I should create a fake
+        // blank canvas anyway.
+        if (this.theCanvases[n] === null)
+            console.log("ERROR! Canvas for page missing: " + n);
+        return this.theCanvases[n];
+    }
+    static async render(n) {
+        // Render page n offscreen, where the pages are counted from zero.
+        // See if the page is already there.
+        if (PDFDocument.theCanvases[n] !== null)
+            return;
+        // Note the +1 here since pdf.js counts pages from 1, not zero.
+        let thePage = await PDFDocument.pdf.getPage(n + 1);
+        let newCanvas = document.createElement('canvas');
+        PDFDocument.theCanvases[n] = newCanvas;
+        PDFDocument.pageAge[n] = PDFDocument.renderCount;
+        ++PDFDocument.renderCount;
+        let offctx = newCanvas.getContext('2d');
+        let viewport = thePage.getViewport(PDFDocument.zoom);
+        newCanvas.width = viewport.width;
+        newCanvas.height = viewport.height;
+        await thePage.render({
+            canvasContext: offctx,
+            viewport: viewport
+        });
+    }
+    static trimBuffer() {
+        // Call this periodically, like after making a series of calls to
+        // render(), to remove excess canvases from the buffer arrays.
+        // Due to the risk of race conditions -- which I think is minimal --
+        // it's best not to call this until reaching a point at which it 
+        // doesn't matter if *all* the offscreen canvases are deleted (although
+        // that outcome would be inefficient). The unlikely possiblitity of
+        // problems due to race conditions is why this is not part of render().
+        let ctot = 0;
+        for (let i = 0; i < PDFDocument.numberOfPages; i++) {
+            if (PDFDocument.theCanvases[i] !== null)
+                ++ctot;
+        }
+        // Delete excess offscreen canvases.
+        while (ctot > PDFDocument.pageBufSize) {
+            PDFDocument.removeOldestPage();
+            --ctot;
+        }
+    }
+    static removeOldestPage() {
+        // Remove the oldest single canvas from this.theCanvases.
+        let oldestIndex = -1;
+        let oldestAge = this.pageAge[0];
+        for (let i = 0; i < this.numberOfPages; i++) {
+            if (this.theCanvases[i] === null)
+                continue;
+            if (this.pageAge[i] < oldestAge) {
+                oldestAge = this.pageAge[i];
+                oldestIndex = i;
+            }
+        }
+        this.theCanvases[oldestIndex] = null;
+    }
+    static flushBuffer() {
+        // Removes all offscreen canvases in the buffer. This is needed, e.g.,
+        // when resizing so that you don't use a canvas of the wrong scale.
+        for (let i = 0; i < this.numberOfPages; i++)
+            this.theCanvases[i] = null;
+    }
+}
+// Total number of pages in the above document.
+PDFDocument.numberOfPages = 0;
+// This is the scale at which to to render the pages offscreen. Setting
+// this equal to 1 means that each px of the off-screen canvas is 1 pdf
+// point. 
+PDFDocument.zoom = 1;
+// Information about the layout, one for each page.
+PDFDocument.pageSpecs = [];
+// The fields below are a temporary buffer of pages rendered offscreen.
+// This speeds up the process so that we aren't re-rendering pages.
+// My original intent was for these arrays to have no more than 
+// pageBufSize entries, but the way async/promise works makes that
+// difficult (impossible?). I want render() to render a given page
+// to an offscreen canvas and store that canvas here, which means
+// that all these calls to render() share the variables below.
+// Each call to render() is, unavoidably, in a different thread, and
+// that means that they are all trying to manipulate these varaibles
+// in an order that is unpredictable. The only way that I can see to
+// make this happen in a predicatable way is for each page to have
+// its own canvas. It's OK for render() to put things into its designated
+// spot in an array, but it can't touch anything that some other invocation
+// of render might touch.
+//
+// This is wasteful, but I see no other way to do it without using
+// a mutex. It's not that bad since we're talking about a few bytes for 
+// every page, but still annoying.
+//
+// Aside: JS does have the Atomics object, as of ECMA 2017, and it 
+// might (?) be possible to use that somehow as a way to synchronize
+// threads, but I'd rather not mess with it.
+// The total number of pages that may be held. This needs to be at least 
+// as large as the number of pages that may be visible at one time if you
+// zoom all the way out, plus a couple extra due to possible problems
+// resulting from race conditions that I can't (?) avoid.
+PDFDocument.pageBufSize = 6;
+// This holds a copy of page to be copied to the screen. Every page has 
+// its own entry, although all but (at most) pageBufSize will be null.
+PDFDocument.theCanvases = [];
+// The renderCount is how many times we've rendered any page. It's used like
+// a time since I have no confidence in window.performance.now, which is
+// supposed to return the current time in nanoseconds. Every time a page
+// is asked to be rendered, this value increments, and is stored in
+// pageAge[i], where i is the index of the page rendered. It may not 
+// actually be rendered if it would be a re-render, but the time is updated.
+// We need this to flush older pages from the buffer when there are too many.
+// 
+// NOTE: This variable is shared by the various invocations of render()
+// and something like
+// ++renderCount
+// is not an atomic operation. The way I am using this, the fact that
+// the value of renderCount may be incorrect isn't a disaster. It can
+// only be wrong by a few steps. This is why pageBufSize is bumped up to be a
+// little larger than strictly necessary. Worst case, things are re-rendered 
+// and you waste some CPU.
+PDFDocument.renderCount = 0;
+// One of these for each page, indexed by page number. Holds the value
+// or renderCount at the time when the page was rendered (or re-rendered).
+PDFDocument.pageAge = [];
+// A class for scheduling event handling. 
+//
+// Everything is static because there is only one of these for all events. 
+// It is used to mediate the event loop so that everything happens 
+// syncrhonously, even when async functions are involved. It is used for 
+// things like scroll and mouse-down events; it is also used for animations, 
+// which are created by certain widgets.
+//
+// The idea is that you call getID() to get your ticket (like at the
+// butcher's). Then call await waitMyTurn() until the butcher is ready.
+// The 'await' is crucial! Then call allDone() to thank the butcher and 
+// leave so that he can take the next customer.
+//
+// For this to work properly, calls to getID() must be made outside
+// of async functions. Otherwise the IDs could get out of order.
+//
+// BUG: I could use this in a DRY-er way. Define a method called
+// getInLine() that takes the function to be invoked. Have getInLine()
+// call getID(), waitMyTurn(), run the job, then call allDone().
+//
+// BUG: It may be that someone who is more expert in JS could use
+// Promises somehow to make this scheme unnecessary. OTOH, this may
+// be easier to understand and use than something more clever.
+class Events {
+    static getID() {
+        let answer = this.count;
+        this.count++;
+        return answer;
+    }
+    static async waitMyTurn(id) {
+        while (id !== Events.complete + 1)
+            await sleep(5);
+    }
+    static allDone(id) {
+        Events.complete = id;
+    }
+}
+// A count of events that have come in. Each event gets its own unique
+// ID by calling getID().
+Events.count = 0;
+// The ID number of the event whose handling was most recently completed.
+Events.complete = -1;
+async function doOpenDocument(latexName, scrollPos) {
+    // Called when the body of the page loads (onload).
+    // latexName is the base of the name of the pdf. Thus, latexName.pdf
+    // is what is to be opened. The scrollPos value is the position on the
+    // page. This is provided by doBeforeUnload(), noted by the server, and
+    // given back in the course of the reload.
+    // The "Get TikZ" button is fixed, and it is always on top.
+    // PUBLIC FACING: Comment this block of code out when running serving from a 
+    // public-facing website. There's no reason to provide this "Get TikZ" button 
+    // and the server won't now how to handle the resulting messages.
+    let fmenu = document.createElement("button");
+    fmenu.style.position = "fixed";
+    fmenu.style.display = "block";
+    fmenu.style.left = "0px";
+    fmenu.style.top = "0px";
+    fmenu.style.width = "80px";
+    fmenu.style.height = "18px";
+    fmenu.style.fontSize = "10px";
+    fmenu.textContent = "Get TikZ";
+    fmenu.style.zIndex = "99";
+    fmenu.onclick = doTikzClick;
+    document.body.appendChild(fmenu);
+    let theCanvas = document.getElementById("pdf_renderer");
+    theCanvas.style.position = "fixed";
+    // It might happen that the program starts with some level of zoom.
+    PDFDocument.setZoom(window.devicePixelRatio);
+    // So that the canvas exactly fills the window.
+    adjustCanvas();
+    // Mouse events are registered on the canvas rather than the document
+    // (as is done for resize and scroll), but I'm not sure there's any 
+    // practical difference since the canvas is the whole document.
+    // Note that this does *not* listen for onclick events. In a few cases,
+    // they might be a more natural choice (like for buttons), but they make
+    // things like coloring a "halfway clicked" widget difficult.
+    // Note that this does not distinguish between left, right and middle
+    // buttons; a click is a click.
+    // Also, the mouseup listener is registered on the window, not the canvas,
+    // so that we hear about mouse-ups even when they happen outside the
+    // browswer window entirely.
+    theCanvas.addEventListener("mousedown", doMouseDown);
+    theCanvas.addEventListener("mousemove", doMouseMove);
+    theCanvas.addEventListener("mouseup", doMouseUp);
+    // I considered registering listeners for mouseenter/mouseleave, but
+    // they're not needed.
+    /*
+    BUG: I have not tested this much on touch devices. Everything
+    works fine on some phones, but not on others. It's a hard to imagine
+    people trying to use this on a phone, but I should test on things
+    like iPads.
+    theCanvas.addEventListener("touchstart",doTouchDown);
+    theCanvas.addEventListener("touchend",doTouchUp);
+    theCanvas.addEventListener("touchmove",doTouchMove);
+    */
+    // Open the pdf and digest figures.aux.
+    await getDocumentData(latexName);
+    // Create the various Panel objects that make up the document as a whole.
+    // This does the "page layout."
+    FullPanel.init(PDFDocument.pageSpecs);
+    // Now that page layout is done, set the range for the scroll bars on 
+    // the browswer window.
+    adjustScrollBars();
+    // When reloading, we don't want things to move back to the top of
+    // the first page.
+    window.scrollTo(0, scrollPos);
+    // Render for the very first time.
+    fullRender();
+}
+async function getDocumentData(latexName) {
+    // This opens and digests the data files and the pdf itself. 
+    let thePDF = await pdfjsLib.getDocument(latexName + '.pdf');
+    await PDFDocument.setPDF(thePDF);
+    // Open and digest figures.aux.
+    let fname = latexName + ".fig.aux";
+    // fetch() is the new XMLHttpRequest(), which has been deprecated.
+    // Thanks to Dan Pratt for pointing that out.
+    let fetchPromise = await fetch(fname);
+    let allText = await fetchPromise.text();
+    await getFigureInfo(allText);
+}
+async function syncLoad(scriptName) {
+    // Load the script with the given name and append to the DOM, and
+    // don't return until the load is complete. So this should typically
+    // be called with 'await'.
+    // 
+    // Thanks to Dan Pratt for this tidy solution. This works because the
+    // promise can't resolve (either way) until appendChild() completes
+    // because you can't resolve or reject until the code is loaded
+    // or fails to load. Note that the 'once' argument means that the function
+    // is called once, then flushed. That's exactly what I want so that they
+    // don't hang around and consume resources.
+    let theCode = document.createElement("script");
+    theCode.type = "application/javascript";
+    theCode.src = scriptName;
+    var p = new Promise((resolve, reject) => {
+        theCode.addEventListener("load", resolve, { once: true });
+        theCode.addEventListener("error", reject, { once: true });
+    });
+    document.body.appendChild(theCode);
+    await p;
+}
+async function getFigureInfo(textBody) {
+    // textBody is the complete contents of the .aux file. Parse it and
+    // use the data to fill in PDFDocument.PageSpecs.
+    let lines = textBody.split('\n');
+    for (let i = 0; i < lines.length; i++) {
+        if (lines[i].length < 2)
+            // Last line might be blank.
+            break;
+        var parts = lines[i].split(' ');
+        if (parts[0] === "load") {
+            // Load a single .js file and move on.
+            await syncLoad(parts[1]);
+            continue;
+        }
+        var pnum = parseInt(parts[0]);
+        var innerMargin = parseFloat(parts[1]);
+        var outerMargin = parseFloat(parts[2]);
+        var textWidth = parseFloat(parts[3]);
+        var vpos = parseFloat(parts[4]);
+        var hLatex = parseFloat(parts[5]);
+        var hAbove = parseFloat(parts[6]);
+        var hBelow = parseFloat(parts[7]);
+        var name = parts[8];
+        // Careful: JS weirdness means that Boolean(parts[9]) is ALWAYS true 
+        // (unless parts[9] is empty).
+        var done = (parts[9] === 'true');
+        var externLoad = (parts[10] === 'true');
+        // Page numbers should start at zero (not 1 as reported by latex).
+        pnum -= 1;
+        // Load the JS now, if necessary.
+        // NOTE: In earlier versions, up to v23, I looked to either a
+        // .js file or an .fjs file. Individual files are now assumed
+        // to be .fjs files. This is much simpler.
+        if (externLoad === true)
+            await syncLoad(name + ".fjs");
+        // NOTE: This assumes that the relevant function has been loaded,
+        // perhaps as an external file from \LoadFigureCode.
+        let augFcn = getAugmentedFunction(name);
+        if (typeof augFcn === "undefined")
+            alert(name + " not found. Is the function name correct?");
+        // Note this for the future.
+        augFcn.figurePanelClass = null;
+        PDFDocument.pageSpecs[pnum].drawFcn.push(augFcn);
+        // Copy the remaining fields over.
+        // Adjust the vertical position to be given relative to the top
+        // of the page, rather than the bottom.
+        vpos = PDFDocument.pageSpecs[pnum].pageHeight - vpos;
+        // If there are multiple figures on a particular page, then this
+        // is redundant, but harmless.
+        if (pnum % 2 === 0) {
+            PDFDocument.pageSpecs[pnum].leftMargin = innerMargin;
+            PDFDocument.pageSpecs[pnum].rightMargin = outerMargin;
+        }
+        else {
+            PDFDocument.pageSpecs[pnum].leftMargin = outerMargin;
+            PDFDocument.pageSpecs[pnum].rightMargin = innerMargin;
+        }
+        PDFDocument.pageSpecs[pnum].textWidth = textWidth;
+        // The per-figure data.
+        PDFDocument.pageSpecs[pnum].insertPoint.push(vpos);
+        PDFDocument.pageSpecs[pnum].deleteHeight.push(hLatex);
+        PDFDocument.pageSpecs[pnum].aboveHeight.push(hAbove);
+        PDFDocument.pageSpecs[pnum].belowHeight.push(hBelow);
+        PDFDocument.pageSpecs[pnum].name.push(name);
+        PDFDocument.pageSpecs[pnum].done.push(done);
+    }
+    // Make sure that all the figure names are distinct.
+    for (let i = 0; i < PDFDocument.numberOfPages; i++) {
+        // Loop over each figure on the current page.
+        for (let fig = 0; fig < PDFDocument.pageSpecs[i].name.length; fig++) {
+            let curName = PDFDocument.pageSpecs[i].name[fig];
+            // See if this name matches a name on any other page/figure.
+            // Consider the current page first.
+            for (let subfig = fig + 1; subfig < PDFDocument.pageSpecs[i].name.length; subfig++) {
+                if (curName === PDFDocument.pageSpecs[i].name[subfig]) {
+                    alert("The figure name " + curName + " is used more than once.");
+                    throw new Error();
+                }
+            }
+            // Continue with all the remaining pages.
+            for (let j = i + 1; j < PDFDocument.numberOfPages; j++) {
+                for (let subfig = 0; subfig < PDFDocument.pageSpecs[j].name.length; subfig++) {
+                    if (curName === PDFDocument.pageSpecs[j].name[subfig]) {
+                        alert("The figure name " + curName + " is used more than once.");
+                        throw new Error();
+                    }
+                }
+            }
+        }
+    }
+}
+function adjustScrollBars() {
+    // Based on the page size and document length, adjust the range of the 
+    // browswer's scroll bars.
+    var body = document.getElementById("mainbody");
+    // I don't see any way to set the range of the scroll bar directly, so
+    // I'm fooling the browser to think that it has a body of a certain
+    // height, in px, when the body is really no bigger than the visible
+    // area of the window. What I want is a height such that, when the scroll
+    // bar is at the bottom, the lower edge of the last page is barely visible
+    // in the bottom of the window.
+    //
+    // There was some mental debate about whether it's better to let the
+    // bottom of the last page scroll up beyond the bottom of the window, but
+    // this is easier to program, and it's probably more natural for most people.
+    let totHeight = FullPanel.totalHeight();
+    let visHeight = document.documentElement.clientHeight;
+    body.style.height = totHeight + "px";
+    // The horizontal scroll bar is expressed in terms of pdf pts. This is
+    // simpler than above since I don't want to be able to scroll so that the 
+    // right edge of the document is barely off the window; I want to be able 
+    // to scroll just far enough so that the right edge of the document meets 
+    // the right edge of the window. The size of the window becomes irrelevant
+    // (i.e., the browser deals with it).
+    // However, we do need to know whether a scroll bar is needed at all, 
+    // so we can't totally ignore the visible width.
+    let visWidth = document.documentElement.clientWidth;
+    let totWidth = FullPanel.getFullWidth();
+    if (visWidth > totWidth) {
+        // No need for horizontal scroll. It seems like "0px" works, but "0 px"
+        // does not. Maybe the space causes a (silent) parse error?
+        body.style.width = "0px";
+        return;
+    }
+    body.style.width = totWidth + "px";
+}
+function ctxTopLevelAdjust() {
+    // Each function should call this before doing any drawing.
+    // Rendering is done relative to the ctx (obviously) with the t-matrix
+    // adjusted accordingly. This brings the t-matrix from being the 
+    // identity to being relative to the entire document.
+    //
+    // In earlier versions, the ctx was being passed around and adjusted
+    // as the layout manager descended to a particular portion of the document.
+    // In some ways that is the cleaner and more modular way to do things,
+    // but it can be confusing because the adjustments to the t-matrix aren't
+    // done in a central place.
+    var canvas = document.getElementById("pdf_renderer");
+    let ctx = canvas.getContext('2d');
+    ctx.resetTransform();
+    // Center the document. Rather than mess with CSS to center the canvas, 
+    // leave the canvas at the size of the entire window, and shift the origin 
+    // so the document is rendered in the center of the canvas.
+    //
+    // However, if the window is smaller than the document, then we do
+    // NOT want to center the document. If we did center it, then it would
+    // be impossible to scroll over to the left since we can't have "negative
+    // scroll;" window.scrollX is always non-negative (unfortunately).
+    let visWidth = document.documentElement.clientWidth;
+    let totWidth = FullPanel.getFullWidth();
+    let z = PDFDocument.getZoom();
+    if (visWidth > totWidth) {
+        // No horizontal scroll bar. Center it.
+        let canvasCenter = canvas.width / 2;
+        let docCenter = FullPanel.getFullWidth() / 2;
+        docCenter *= PDFDocument.getZoom();
+        ctx.translate(canvasCenter - docCenter, 0);
+    }
+    else {
+        // Shift according to the horizontal scroll bar, leaving the document
+        // against the left edge. Note the scaling by the zoom factor so
+        // as to be consistent with the above.
+        ctx.translate(-window.scrollX * PDFDocument.getZoom(), 0);
+    }
+    return ctx;
+}
+async function fullRender() {
+    // Render all the pages of the pdf, together with the figures.
+    var canvas = document.getElementById("pdf_renderer");
+    // This shouldn't be necessary, but do it as a fail-safe.
+    var ctx = canvas.getContext('2d');
+    ctx.resetTransform();
+    let visWidth = document.documentElement.clientWidth;
+    let z = PDFDocument.getZoom();
+    // BUG: Could lead to flicker? It is necessary to clear everything
+    // because widgets could be drawn outside the page. I suppose that I could
+    // only erase the area outside the pages, which would reduce any flicker.
+    // I really don't want to double-buffer everything if it can be avoided.
+    // It may be the only solution. The problem is that, if a widget extends 
+    // outside the page, and is animated (like LoopAnimWidget) so that it's
+    // drawn as part of an animation, then you must erase the entire page to
+    // avoid "leftovers," and *that* requires that you redraw the entire 
+    // document (or what is visible) with every frame of an animation.
+    //
+    // BUG: So the correct solution is double-buffering everything, but I don't 
+    // feel that it's pressing. For now, either restrict any widgets to 
+    // draw within a page or accept that it might leave spoogey leftovers.
+    ctx.clearRect(0, 0, visWidth * z, document.documentElement.clientHeight * z);
+    await FullPanel.renderAll(canvas.height);
+}
+function adjustCanvas() {
+    // Call when the window has been zoomed or re-sized.
+    // 
+    // canvas has two different dimensions: canvas.style.width and height, and 
+    // canvas.width and height. The style values determine the size of the canvas 
+    // on the screen -- so-called ""CSS styling." The straight values (no style)
+    // are the number of px in the canvas. By keeping the style values constant and
+    // varying the straight values, you can have more or less resolution for the
+    // canvas, EVEN WHEN ZOOMED IN.
+    //
+    // The bottom line is that if we adjust the straight pixel sizes, then
+    // we can always have one px for every physical pixel -- up to the accuracy
+    // of window.devicePixelRatio.
+    //
+    // BUG: Check for things with super high pixel density, like phones. I
+    // think the devicePixelRatio is somehow wrong for those. It may not matter.
+    var canvas = document.getElementById("pdf_renderer");
+    // Adjust the visible width to match the window size. 
+    //
+    // NOTE: For debugging, it can be helpful to subtract off a bit from these
+    // values, like 1, 10 or 50, depending. In earlier versions, there was
+    // also a bit of CSS in the html that put a visible rectangle around the canvas.
+    //canvas.style.width = (document.documentElement.clientWidth - 50) + "px";
+    //canvas.style.height = (document.documentElement.clientHeight - 50) + "px";
+    canvas.style.width = document.documentElement.clientWidth + "px";
+    canvas.style.height = document.documentElement.clientHeight + "px";
+    // The visible width of the canvas has just been fixed. Now change the
+    // number of px so that the number of px per inch on the screen varies with
+    // the level of browser zoom. There seems to be no means of direct access 
+    // to the phyical pixels of the monitor, but this is close, and may be 
+    // exactly equivalent in many situations.
+    canvas.width = document.documentElement.clientWidth * window.devicePixelRatio;
+    canvas.height = document.documentElement.clientHeight * window.devicePixelRatio;
+}
+async function doScrollGuts(id) {
+    // Wait for any active event handler to finish and then wait until it is
+    // the turn of current id to run.
+    await Events.waitMyTurn(id);
+    await fullRender();
+    // Give your ticket to the butcher so that he can take the next customer.
+    Events.allDone(id);
+}
+function doScroll() {
+    // Scroll events are registered below to call this function.
+    // It redraws the contents of the main canvas.
+    // This appears to be called when the page is opened, before almost
+    // anything else, so return until page initialization is complete.
+    if (PDFDocument.isLoaded() == false)
+        return;
+    // Get a unique ID for this event.
+    // This must be done outside any async function to ensure proper order.
+    let id = Events.getID();
+    doScrollGuts(id);
+}
+async function doResizeGuts(id) {
+    // As with scrolling, wait for any earlier event handler to complete.
+    await Events.waitMyTurn(id);
+    // None of the buffered offscreen canvases are valid anymore.
+    // In theory, I could test for whether this was merely a window
+    // resize and not a zoom, but it's not worth fooling with.
+    PDFDocument.flushBuffer();
+    console.log("ratio: " + window.devicePixelRatio);
+    // The other thing that needs to be adjusted is the zoom level
+    // used when rendering the pdfs. 
+    adjustCanvas();
+    // Here is the magic. Effectively, this value is now the level of zoom.
+    // If you take out this line, and leave PDFDocument.zoom always equal to
+    // default value of 1, then zooming does nothing, although the mismatch
+    // between the resolution of the off-screen canvas and the resolution on
+    // the screen can make things blurry or blocky.
+    PDFDocument.setZoom(window.devicePixelRatio);
+    // If the size of the window changed, then this needs to be adjusted too.
+    // This must be done after adjustCanvas().
+    adjustScrollBars();
+    // Render the pages too.
+    await fullRender();
+    // Final bit of scheduling magic.
+    Events.allDone(id);
+}
+function doResize() {
+    // This is called whenever the user zooms and also if the
+    // entire broswer window is resized.
+    let id = Events.getID();
+    doResizeGuts(id);
+}
+async function mouseDownGuts(id, x, y) {
+    // (x,y) is the location of the mouse click, in pdf points, but
+    // relative to the window.
+    await Events.waitMyTurn(id);
+    // Just as we have to tweak the t-matrix to determine where to draw things, 
+    // we need to do something similar to figure out where (x,y) is on the page.
+    // The difference is that the ctx.translate() operations become adjustments 
+    // to x and y.
+    let visWidth = document.documentElement.clientWidth;
+    let totWidth = FullPanel.getFullWidth();
+    let canvas = document.getElementById("pdf_renderer");
+    if (visWidth > totWidth) {
+        // No horizontal scroll bar. The document is centered.
+        let canvasCenter = canvas.width / 2;
+        let docCenter = FullPanel.getFullWidth() / 2;
+        canvasCenter = canvasCenter / PDFDocument.getZoom();
+        x = x - (canvasCenter - docCenter);
+    }
+    else {
+        // Shift according to the horizontal scroll bar.
+        x = x + window.scrollX;
+    }
+    // Fix up the y-coordinate too.
+    y = y + window.scrollY;
+    FullPanel.mouseDown(x, y);
+    // Don't forget!
+    Events.allDone(id);
+}
+function doMouseDown(e) {
+    // This is an event like any other, so the usual scheduling rigmarole.
+    let id = Events.getID();
+    mouseDownGuts(id, e.x, e.y);
+}
+async function mouseMoveGuts(id, x, y) {
+    // As above.
+    // BUG: Common code. Not DRY.
+    await Events.waitMyTurn(id);
+    // As for mouse-down.
+    let visWidth = document.documentElement.clientWidth;
+    let totWidth = FullPanel.getFullWidth();
+    let canvas = document.getElementById("pdf_renderer");
+    if (visWidth > totWidth) {
+        // No horizontal scroll bar. The document is centered.
+        let canvasCenter = canvas.width / 2;
+        let docCenter = FullPanel.getFullWidth() / 2;
+        canvasCenter = canvasCenter / PDFDocument.getZoom();
+        x = x - (canvasCenter - docCenter);
+    }
+    else {
+        // Shift according to the horizontal scroll bar.
+        x = x + window.scrollX;
+    }
+    // Fix up the y-coordinate too.
+    y = y + window.scrollY;
+    FullPanel.mouseMove(x, y);
+    // Don't forget!
+    Events.allDone(id);
+}
+function doMouseMove(e) {
+    // As above.
+    let id = Events.getID();
+    mouseMoveGuts(id, e.x, e.y);
+}
+async function mouseUpGuts(id, x, y) {
+    // As above.
+    // BUG: Common code. Not DRY.
+    await Events.waitMyTurn(id);
+    let visWidth = document.documentElement.clientWidth;
+    let totWidth = FullPanel.getFullWidth();
+    let canvas = document.getElementById("pdf_renderer");
+    if (visWidth > totWidth) {
+        // No horizontal scroll bar. The document is centered.
+        let canvasCenter = canvas.width / 2;
+        let docCenter = FullPanel.getFullWidth() / 2;
+        canvasCenter = canvasCenter / PDFDocument.getZoom();
+        x = x - (canvasCenter - docCenter);
+    }
+    else {
+        // Shift according to the horizontal scroll bar.
+        x = x + window.scrollX;
+    }
+    // Fix up the y-coordinate too.
+    y = y + window.scrollY;
+    FullPanel.mouseUp(x, y);
+    // Don't forget!
+    Events.allDone(id);
+}
+function doMouseUp(e) {
+    // As above. 
+    let id = Events.getID();
+    mouseUpGuts(id, e.x, e.y);
+}
+function doTikzClick() {
+    // Tikz button was clicked. Generate output file(s).
+    // 
+    // Cycle over every figure and let it generate tikz data.
+    for (let pi = 0; pi < PDFDocument.pageSpecs.length; pi++) {
+        let pd = PDFDocument.pageSpecs[pi];
+        if (pd.name.length === 0)
+            // No figures on this page.
+            continue;
+        for (let fi = 0; fi < pd.name.length; fi++) {
+            if (pd.done[fi] == true)
+                // User said to skip this one.
+                continue;
+            let theFcn = pd.drawFcn[fi];
+            if (theFcn.figurePanelClass === null)
+                // Hasn't been loaded, because was never visible.
+                continue;
+            let ctx = new CTX(pd.name[fi]);
+            theFcn(ctx);
+            ctx.close();
+        }
+    }
+}
+function doBeforeUnload(e) {
+    // This is *very* non-standard. Pass a made-up WHERE message with the position
+    // on the document.
+    // BUG: This only informs the server of the vertical scroll position.
+    // Dealing with horizontal scroll would be more painful. See fullRender()
+    // and adjustScrollBars().
+    // If *everything* were double-buffered, then this would be a bit easier.
+    let req = new XMLHttpRequest();
+    // We don't care about the second argument. In a POST this would be
+    // something like a file name. The third argument, 'false', forces the request
+    // to be handled synchronously. If it's done async, then the unload proceeds
+    // and completes before this task finishes.
+    req.open("WHERE", "bogus", false);
+    req.setRequestHeader("Content-Type", "text/plain;charset=UTF-8");
+    // Send the postion as the message. It could probaby be sent instead of
+    // 'bogus' above, and this could be blank.
+    let msg = window.scrollY.toString();
+    // BUG: Firefox generates "Uncaught DOMException: A network error occurred."
+    // on this. It might be that XMLHttpRequest is deprecated?
+    req.send(msg);
+}
+// Register additional event handlers. The main (and only) canvas had 
+// listeners registered for mouse events in doOpenDocument().
+document.addEventListener('scroll', doScroll);
+window.addEventListener('resize', doResize);
+// PUBLIC FACING: Comment this out. It's doing something *very* non-standard,
+// and any normal web-server will choke on it.
+window.addEventListener('beforeunload', doBeforeUnload);

Added: trunk/Master/texmf-dist/doc/latex/figput/javascript/pdf.js
===================================================================
--- trunk/Master/texmf-dist/doc/latex/figput/javascript/pdf.js	                        (rev 0)
+++ trunk/Master/texmf-dist/doc/latex/figput/javascript/pdf.js	2022-07-22 21:48:41 UTC (rev 63957)
@@ -0,0 +1 @@
+!function (e, t) { "object" == typeof exports && "object" == typeof module ? module.exports = t() : "function" == typeof define && define.amd ? define("pdfjs-dist/build/pdf", [], t) : "object" == typeof exports ? exports["pdfjs-dist/build/pdf"] = t() : e["pdfjs-dist/build/pdf"] = e.pdfjsLib = t() }(this, function () { return function (e) { var t = {}; function r(n) { if (t[n]) return t[n].exports; var i = t[n] = { i: n, l: !1, exports: {} }; return e[n].call(i.exports, i, i.exports, r), i.l = !0, i.exports } return r.m = e, r.c = t, r.d = function (e, t, n) { r.o(e, t) || Object.defineProperty(e, t, { enumerable: !0, get: n }) }, r.r = function (e) { "undefined" != typeof Symbol && Symbol.toStringTag && Object.defineProperty(e, Symbol.toStringTag, { value: "Module" }), Object.defineProperty(e, "__esModule", { value: !0 }) }, r.t = function (e, t) { if (1 & t && (e = r(e)), 8 & t) return e; if (4 & t && "object" == typeof e && e && e.__esModule) return e; var n = Object.create(null); if (r.r(n), Object.defineProperty(n, "default", { enumerable: !0, value: e }), 2 & t && "string" != typeof e) for (var i in e) r.d(n, i, function (t) { return e[t] }.bind(null, i)); return n }, r.n = function (e) { var t = e && e.__esModule ? function () { return e.default } : function () { return e }; return r.d(t, "a", t), t }, r.o = function (e, t) { return Object.prototype.hasOwnProperty.call(e, t) }, r.p = "", r(r.s = 0) }([function (e, t, r) { "use strict"; var n = r(1), i = r(129), a = r(145), o = r(146), s = r(130), u = r(147), l = r(135), c = r(132); if (r(4)()) { var h = r(148).PDFNodeStream; i.setPDFNetworkStreamFactory(function (e) { return new h(e) }) } else if ("undefined" != typeof Response && "body" in Response.prototype && "undefined" != typeof ReadableStream) { var d = r(151).PDFFetchStream; i.setPDFNetworkStreamFactory(function (e) { return new d(e) }) } else { var f = r(152).PDFNetworkStream; i.setPDFNetworkStreamFactory(function (e) { return new f(e) }) } t.build = i.build, t.version = i.version, t.getDo!
 cument = i.getDocument, t.LoopbackPort = i.LoopbackPort, t.PDFDataRangeTransport = i.PDFDataRangeTransport, t.PDFWorker = i.PDFWorker, t.renderTextLayer = a.renderTextLayer, t.AnnotationLayer = o.AnnotationLayer, t.createPromiseCapability = n.createPromiseCapability, t.PasswordResponses = n.PasswordResponses, t.InvalidPDFException = n.InvalidPDFException, t.MissingPDFException = n.MissingPDFException, t.SVGGraphics = u.SVGGraphics, t.NativeImageDecoding = n.NativeImageDecoding, t.CMapCompressionType = n.CMapCompressionType, t.PermissionFlag = n.PermissionFlag, t.UnexpectedResponseException = n.UnexpectedResponseException, t.OPS = n.OPS, t.VerbosityLevel = n.VerbosityLevel, t.UNSUPPORTED_FEATURES = n.UNSUPPORTED_FEATURES, t.createValidAbsoluteUrl = n.createValidAbsoluteUrl, t.createObjectURL = n.createObjectURL, t.removeNullCharacters = n.removeNullCharacters, t.shadow = n.shadow, t.Util = n.Util, t.ReadableStream = n.ReadableStream, t.URL = n.URL, t.RenderingCancelledException = s.RenderingCancelledException, t.getFilenameFromUrl = s.getFilenameFromUrl, t.LinkTarget = s.LinkTarget, t.addLinkAttributes = s.addLinkAttributes, t.loadScript = s.loadScript, t.GlobalWorkerOptions = l.GlobalWorkerOptions, t.apiCompatibilityParams = c.apiCompatibilityParams }, function (e, t, r) { "use strict"; Object.defineProperty(t, "__esModule", { value: !0 }), t.unreachable = t.warn = t.utf8StringToString = t.stringToUTF8String = t.stringToPDFString = t.stringToBytes = t.string32 = t.shadow = t.setVerbosityLevel = t.URL = t.ReadableStream = t.removeNullCharacters = t.readUint32 = t.readUint16 = t.readInt8 = t.log2 = t.isEvalSupported = t.isLittleEndian = t.createValidAbsoluteUrl = t.isSameOrigin = t.isSpace = t.isString = t.isNum = t.isEmptyObj = t.isBool = t.isArrayBuffer = t.info = t.getVerbosityLevel = t.getLookupTableFactory = t.getInheritableProperty = t.deprecated = t.createObjectURL = t.createPromiseCapability = t.bytesToString = t.assert = t.arraysToBytes = t.arrayByteLength = t.FormatError = t.XRefParseException = t.toRoma!
 nNumerals = t.Util = t.UnknownErrorException = t.UnexpectedResponseException = t.TextRenderingMode = t.StreamType = t.PermissionFlag = t.PasswordResponses = t.PasswordException = t.NativeImageDecoding = t.MissingPDFException = t.MissingDataException = t.InvalidPDFException = t.AbortException = t.CMapCompressionType = t.ImageKind = t.FontType = t.AnnotationType = t.AnnotationFlag = t.AnnotationFieldFlag = t.AnnotationBorderStyleType = t.UNSUPPORTED_FEATURES = t.VerbosityLevel = t.OPS = t.IDENTITY_MATRIX = t.FONT_IDENTITY_MATRIX = void 0; var n = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (e) { return typeof e } : function (e) { return e && "function" == typeof Symbol && e.constructor === Symbol && e !== Symbol.prototype ? "symbol" : typeof e }; r(2); var i = r(125), a = r(127), o = { ERRORS: 0, WARNINGS: 1, INFOS: 5 }, s = o.WARNINGS; function u(e) { s >= o.WARNINGS && console.log("Warning: " + e) } function l(e) { throw new Error(e) } function c(e, t) { e || l(t) } var h = function () { function e(e, t) { this.name = "PasswordException", this.message = e, this.code = t } return e.prototype = new Error, e.constructor = e, e }(), d = function () { function e(e, t) { this.name = "UnknownErrorException", this.message = e, this.details = t } return e.prototype = new Error, e.constructor = e, e }(), f = function () { function e(e) { this.name = "InvalidPDFException", this.message = e } return e.prototype = new Error, e.constructor = e, e }(), p = function () { function e(e) { this.name = "MissingPDFException", this.message = e } return e.prototype = new Error, e.constructor = e, e }(), v = function () { function e(e, t) { this.name = "UnexpectedResponseException", this.message = e, this.status = t } return e.prototype = new Error, e.constructor = e, e }(), m = function () { function e(e, t) { this.begin = e, this.end = t, this.message = "Missing data [" + e + ", " + t + ")" } return e.prototype = new Error, e.prototype.name = "MissingDataException", e.constructor = e, e }(), g = funct!
 ion () { function e(e) { this.message = e } return e.prototype = new Error, e.prototype.name = "XRefParseException", e.constructor = e, e }(), y = function () { function e(e) { this.message = e } return e.prototype = new Error, e.prototype.name = "FormatError", e.constructor = e, e }(), b = function () { function e(e) { this.name = "AbortException", this.message = e } return e.prototype = new Error, e.constructor = e, e }(), _ = /\x00/g; function A(e) { c("string" == typeof e, "Invalid argument for stringToBytes"); for (var t = e.length, r = new Uint8Array(t), n = 0; n < t; ++n)r[n] = 255 & e.charCodeAt(n); return r } function S(e) { return void 0 !== e.length ? e.length : (c(void 0 !== e.byteLength), e.byteLength) } var w = function () { function e() { } var t = ["rgb(", 0, ",", 0, ",", 0, ")"]; return e.makeCssRgb = function (e, r, n) { return t[1] = e, t[3] = r, t[5] = n, t.join("") }, e.transform = function (e, t) { return [e[0] * t[0] + e[2] * t[1], e[1] * t[0] + e[3] * t[1], e[0] * t[2] + e[2] * t[3], e[1] * t[2] + e[3] * t[3], e[0] * t[4] + e[2] * t[5] + e[4], e[1] * t[4] + e[3] * t[5] + e[5]] }, e.applyTransform = function (e, t) { return [e[0] * t[0] + e[1] * t[2] + t[4], e[0] * t[1] + e[1] * t[3] + t[5]] }, e.applyInverseTransform = function (e, t) { var r = t[0] * t[3] - t[1] * t[2]; return [(e[0] * t[3] - e[1] * t[2] + t[2] * t[5] - t[4] * t[3]) / r, (-e[0] * t[1] + e[1] * t[0] + t[4] * t[1] - t[5] * t[0]) / r] }, e.getAxialAlignedBoundingBox = function (t, r) { var n = e.applyTransform(t, r), i = e.applyTransform(t.slice(2, 4), r), a = e.applyTransform([t[0], t[3]], r), o = e.applyTransform([t[2], t[1]], r); return [Math.min(n[0], i[0], a[0], o[0]), Math.min(n[1], i[1], a[1], o[1]), Math.max(n[0], i[0], a[0], o[0]), Math.max(n[1], i[1], a[1], o[1])] }, e.inverseTransform = function (e) { var t = e[0] * e[3] - e[1] * e[2]; return [e[3] / t, -e[1] / t, -e[2] / t, e[0] / t, (e[2] * e[5] - e[4] * e[3]) / t, (e[4] * e[1] - e[5] * e[0]) / t] }, e.apply3dTransform = function (e, t) { return [e[0] * t[0] + !
 e[1] * t[1] + e[2] * t[2], e[3] * t[0] + e[4] * t[1] + e[5] * t[2], e[6] * t[0] + e[7] * t[1] + e[8] * t[2]] }, e.singularValueDecompose2dScale = function (e) { var t = [e[0], e[2], e[1], e[3]], r = e[0] * t[0] + e[1] * t[2], n = e[0] * t[1] + e[1] * t[3], i = e[2] * t[0] + e[3] * t[2], a = e[2] * t[1] + e[3] * t[3], o = (r + a) / 2, s = Math.sqrt((r + a) * (r + a) - 4 * (r * a - i * n)) / 2, u = o + s || 1, l = o - s || 1; return [Math.sqrt(u), Math.sqrt(l)] }, e.normalizeRect = function (e) { var t = e.slice(0); return e[0] > e[2] && (t[0] = e[2], t[2] = e[0]), e[1] > e[3] && (t[1] = e[3], t[3] = e[1]), t }, e.intersect = function (t, r) { function n(e, t) { return e - t } var i = [t[0], t[2], r[0], r[2]].sort(n), a = [t[1], t[3], r[1], r[3]].sort(n), o = []; return t = e.normalizeRect(t), r = e.normalizeRect(r), (i[0] === t[0] && i[1] === r[0] || i[0] === r[0] && i[1] === t[0]) && (o[0] = i[1], o[2] = i[2], (a[0] === t[1] && a[1] === r[1] || a[0] === r[1] && a[1] === t[1]) && (o[1] = a[1], o[3] = a[2], o)) }, e }(), k = ["", "C", "CC", "CCC", "CD", "D", "DC", "DCC", "DCCC", "CM", "", "X", "XX", "XXX", "XL", "L", "LX", "LXX", "LXXX", "XC", "", "I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX"]; var P = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 728, 711, 710, 729, 733, 731, 730, 732, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8226, 8224, 8225, 8230, 8212, 8211, 402, 8260, 8249, 8250, 8722, 8240, 8222, 8220, 8221, 8216, 8217, 8218, 8482, 64257, 64258, 321, 338, 352, 376, 381, 305, 322, 339, 353, 382, 0, 8364]; var x, C = (x = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=", function (e, t) { if (!(arguments.length > 2 && void 0 !== arguments[2] && arguments[2]) && a.URL.createObjectURL) { var r = new Blob([e], { type!
 : t }); return a.URL.createObjectURL(r) } for (var n = "data:" + t + ";base64,", i = 0, o = e.length; i < o; i += 3) { var s = 255 & e[i], u = 255 & e[i + 1], l = 255 & e[i + 2]; n += x[s >> 2] + x[(3 & s) << 4 | u >> 4] + x[i + 1 < o ? (15 & u) << 2 | l >> 6 : 64] + x[i + 2 < o ? 63 & l : 64] } return n }); t.FONT_IDENTITY_MATRIX = [.001, 0, 0, .001, 0, 0], t.IDENTITY_MATRIX = [1, 0, 0, 1, 0, 0], t.OPS = { dependency: 1, setLineWidth: 2, setLineCap: 3, setLineJoin: 4, setMiterLimit: 5, setDash: 6, setRenderingIntent: 7, setFlatness: 8, setGState: 9, save: 10, restore: 11, transform: 12, moveTo: 13, lineTo: 14, curveTo: 15, curveTo2: 16, curveTo3: 17, closePath: 18, rectangle: 19, stroke: 20, closeStroke: 21, fill: 22, eoFill: 23, fillStroke: 24, eoFillStroke: 25, closeFillStroke: 26, closeEOFillStroke: 27, endPath: 28, clip: 29, eoClip: 30, beginText: 31, endText: 32, setCharSpacing: 33, setWordSpacing: 34, setHScale: 35, setLeading: 36, setFont: 37, setTextRenderingMode: 38, setTextRise: 39, moveText: 40, setLeadingMoveText: 41, setTextMatrix: 42, nextLine: 43, showText: 44, showSpacedText: 45, nextLineShowText: 46, nextLineSetSpacingShowText: 47, setCharWidth: 48, setCharWidthAndBounds: 49, setStrokeColorSpace: 50, setFillColorSpace: 51, setStrokeColor: 52, setStrokeColorN: 53, setFillColor: 54, setFillColorN: 55, setStrokeGray: 56, setFillGray: 57, setStrokeRGBColor: 58, setFillRGBColor: 59, setStrokeCMYKColor: 60, setFillCMYKColor: 61, shadingFill: 62, beginInlineImage: 63, beginImageData: 64, endInlineImage: 65, paintXObject: 66, markPoint: 67, markPointProps: 68, beginMarkedContent: 69, beginMarkedContentProps: 70, endMarkedContent: 71, beginCompat: 72, endCompat: 73, paintFormXObjectBegin: 74, paintFormXObjectEnd: 75, beginGroup: 76, endGroup: 77, beginAnnotations: 78, endAnnotations: 79, beginAnnotation: 80, endAnnotation: 81, paintJpegXObject: 82, paintImageMaskXObject: 83, paintImageMaskXObjectGroup: 84, paintImageXObject: 85, paintInlineImageXObject: 86, paintInlineImageXObjectGroup: 87, paintImageXO!
 bjectRepeat: 88, paintImageMaskXObjectRepeat: 89, paintSolidColorImageMask: 90, constructPath: 91 }, t.VerbosityLevel = o, t.UNSUPPORTED_FEATURES = { unknown: "unknown", forms: "forms", javaScript: "javaScript", smask: "smask", shadingPattern: "shadingPattern", font: "font" }, t.AnnotationBorderStyleType = { SOLID: 1, DASHED: 2, BEVELED: 3, INSET: 4, UNDERLINE: 5 }, t.AnnotationFieldFlag = { READONLY: 1, REQUIRED: 2, NOEXPORT: 4, MULTILINE: 4096, PASSWORD: 8192, NOTOGGLETOOFF: 16384, RADIO: 32768, PUSHBUTTON: 65536, COMBO: 131072, EDIT: 262144, SORT: 524288, FILESELECT: 1048576, MULTISELECT: 2097152, DONOTSPELLCHECK: 4194304, DONOTSCROLL: 8388608, COMB: 16777216, RICHTEXT: 33554432, RADIOSINUNISON: 33554432, COMMITONSELCHANGE: 67108864 }, t.AnnotationFlag = { INVISIBLE: 1, HIDDEN: 2, PRINT: 4, NOZOOM: 8, NOROTATE: 16, NOVIEW: 32, READONLY: 64, LOCKED: 128, TOGGLENOVIEW: 256, LOCKEDCONTENTS: 512 }, t.AnnotationType = { TEXT: 1, LINK: 2, FREETEXT: 3, LINE: 4, SQUARE: 5, CIRCLE: 6, POLYGON: 7, POLYLINE: 8, HIGHLIGHT: 9, UNDERLINE: 10, SQUIGGLY: 11, STRIKEOUT: 12, STAMP: 13, CARET: 14, INK: 15, POPUP: 16, FILEATTACHMENT: 17, SOUND: 18, MOVIE: 19, WIDGET: 20, SCREEN: 21, PRINTERMARK: 22, TRAPNET: 23, WATERMARK: 24, THREED: 25, REDACT: 26 }, t.FontType = { UNKNOWN: 0, TYPE1: 1, TYPE1C: 2, CIDFONTTYPE0: 3, CIDFONTTYPE0C: 4, TRUETYPE: 5, CIDFONTTYPE2: 6, TYPE3: 7, OPENTYPE: 8, TYPE0: 9, MMTYPE1: 10 }, t.ImageKind = { GRAYSCALE_1BPP: 1, RGB_24BPP: 2, RGBA_32BPP: 3 }, t.CMapCompressionType = { NONE: 0, BINARY: 1, STREAM: 2 }, t.AbortException = b, t.InvalidPDFException = f, t.MissingDataException = m, t.MissingPDFException = p, t.NativeImageDecoding = { NONE: "none", DECODE: "decode", DISPLAY: "display" }, t.PasswordException = h, t.PasswordResponses = { NEED_PASSWORD: 1, INCORRECT_PASSWORD: 2 }, t.PermissionFlag = { PRINT: 4, MODIFY_CONTENTS: 8, COPY: 16, MODIFY_ANNOTATIONS: 32, FILL_INTERACTIVE_FORMS: 256, COPY_FOR_ACCESSIBILITY: 512, ASSEMBLE: 1024, PRINT_HIGH_QUALITY: 2048 }, t.StreamType = { UNKNOWN: 0, FLATE: 1, LZW!
 : 2, DCT: 3, JPX: 4, JBIG: 5, A85: 6, AHX: 7, CCF: 8, RL: 9 }, t.TextRenderingMode = { FILL: 0, STROKE: 1, FILL_STROKE: 2, INVISIBLE: 3, FILL_ADD_TO_PATH: 4, STROKE_ADD_TO_PATH: 5, FILL_STROKE_ADD_TO_PATH: 6, ADD_TO_PATH: 7, FILL_STROKE_MASK: 3, ADD_TO_PATH_FLAG: 4 }, t.UnexpectedResponseException = v, t.UnknownErrorException = d, t.Util = w, t.toRomanNumerals = function (e) { var t = arguments.length > 1 && void 0 !== arguments[1] && arguments[1]; c(Number.isInteger(e) && e > 0, "The number should be a positive integer."); for (var r = void 0, n = []; e >= 1e3;)e -= 1e3, n.push("M"); r = e / 100 | 0, e %= 100, n.push(k[r]), r = e / 10 | 0, e %= 10, n.push(k[10 + r]), n.push(k[20 + e]); var i = n.join(""); return t ? i.toLowerCase() : i }, t.XRefParseException = g, t.FormatError = y, t.arrayByteLength = S, t.arraysToBytes = function (e) { if (1 === e.length && e[0] instanceof Uint8Array) return e[0]; var t, r, n, i = 0, a = e.length; for (t = 0; t < a; t++)i += n = S(r = e[t]); var o = 0, s = new Uint8Array(i); for (t = 0; t < a; t++)(r = e[t]) instanceof Uint8Array || (r = "string" == typeof r ? A(r) : new Uint8Array(r)), n = r.byteLength, s.set(r, o), o += n; return s }, t.assert = c, t.bytesToString = function (e) { c(null !== e && "object" === (void 0 === e ? "undefined" : n(e)) && void 0 !== e.length, "Invalid argument for bytesToString"); var t = e.length; if (t < 8192) return String.fromCharCode.apply(null, e); for (var r = [], i = 0; i < t; i += 8192) { var a = Math.min(i + 8192, t), o = e.subarray(i, a); r.push(String.fromCharCode.apply(null, o)) } return r.join("") }, t.createPromiseCapability = function () { var e = {}; return e.promise = new Promise(function (t, r) { e.resolve = t, e.reject = r }), e }, t.createObjectURL = C, t.deprecated = function (e) { console.log("Deprecated API usage: " + e) }, t.getInheritableProperty = function (e) { for (var t = e.dict, r = e.key, n = e.getArray, i = void 0 !== n && n, a = e.stopWhenFound, o = void 0 === a || a, s = 0, l = void 0; t;) { var c = i ? t.getArray!
 (r) : t.get(r); if (void 0 !== c) { if (o) return c; l || (l = []), l.push(c) } if (++s > 100) { u('getInheritableProperty: maximum loop count exceeded for "' + r + '"'); break } t = t.get("Parent") } return l }, t.getLookupTableFactory = function (e) { var t; return function () { return e && (t = Object.create(null), e(t), e = null), t } }, t.getVerbosityLevel = function () { return s }, t.info = function (e) { s >= o.INFOS && console.log("Info: " + e) }, t.isArrayBuffer = function (e) { return "object" === (void 0 === e ? "undefined" : n(e)) && null !== e && void 0 !== e.byteLength }, t.isBool = function (e) { return "boolean" == typeof e }, t.isEmptyObj = function (e) { for (var t in e) return !1; return !0 }, t.isNum = function (e) { return "number" == typeof e }, t.isString = function (e) { return "string" == typeof e }, t.isSpace = function (e) { return 32 === e || 9 === e || 13 === e || 10 === e }, t.isSameOrigin = function (e, t) { try { var r = new a.URL(e); if (!r.origin || "null" === r.origin) return !1 } catch (e) { return !1 } var n = new a.URL(t, r); return r.origin === n.origin }, t.createValidAbsoluteUrl = function (e, t) { if (!e) return null; try { var r = t ? new a.URL(e, t) : new a.URL(e); if (function (e) { if (!e) return !1; switch (e.protocol) { case "http:": case "https:": case "ftp:": case "mailto:": case "tel:": return !0; default: return !1 } }(r)) return r } catch (e) { } return null }, t.isLittleEndian = function () { var e = new Uint8Array(4); return e[0] = 1, 1 === new Uint32Array(e.buffer, 0, 1)[0] }, t.isEvalSupported = function () { try { return new Function(""), !0 } catch (e) { return !1 } }, t.log2 = function (e) { return e <= 0 ? 0 : Math.ceil(Math.log2(e)) }, t.readInt8 = function (e, t) { return e[t] << 24 >> 24 }, t.readUint16 = function (e, t) { return e[t] << 8 | e[t + 1] }, t.readUint32 = function (e, t) { return (e[t] << 24 | e[t + 1] << 16 | e[t + 2] << 8 | e[t + 3]) >>> 0 }, t.removeNullCharacters = function (e) { return "string" != typeof e ? (u("The argument for r!
 emoveNullCharacters must be a string."), e) : e.replace(_, "") }, t.ReadableStream = i.ReadableStream, t.URL = a.URL, t.setVerbosityLevel = function (e) { Number.isInteger(e) && (s = e) }, t.shadow = function (e, t, r) { return Object.defineProperty(e, t, { value: r, enumerable: !0, configurable: !0, writable: !1 }), r }, t.string32 = function (e) { return String.fromCharCode(e >> 24 & 255, e >> 16 & 255, e >> 8 & 255, 255 & e) }, t.stringToBytes = A, t.stringToPDFString = function (e) { var t, r = e.length, n = []; if ("\xFE" === e[0] && "\xFF" === e[1]) for (t = 2; t < r; t += 2)n.push(String.fromCharCode(e.charCodeAt(t) << 8 | e.charCodeAt(t + 1))); else for (t = 0; t < r; ++t) { var i = P[e.charCodeAt(t)]; n.push(i ? String.fromCharCode(i) : e.charAt(t)) } return n.join("") }, t.stringToUTF8String = function (e) { return decodeURIComponent(escape(e)) }, t.utf8StringToString = function (e) { return unescape(encodeURIComponent(e)) }, t.warn = u, t.unreachable = l }, function (e, t, r) { "use strict"; var n = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (e) { return typeof e } : function (e) { return e && "function" == typeof Symbol && e.constructor === Symbol && e !== Symbol.prototype ? "symbol" : typeof e }, i = r(3); if (!i._pdfjsCompatibilityChecked) { i._pdfjsCompatibilityChecked = !0; var a = r(4), o = "object" === ("undefined" == typeof window ? "undefined" : n(window)) && "object" === ("undefined" == typeof document ? "undefined" : n(document)); !i.btoa && a() && (i.btoa = function (e) { return Buffer.from(e, "binary").toString("base64") }), !i.atob && a() && (i.atob = function (e) { return Buffer.from(e, "base64").toString("binary") }), o && ("currentScript" in document || Object.defineProperty(document, "currentScript", { get: function () { var e = document.getElementsByTagName("script"); return e[e.length - 1] }, enumerable: !0, configurable: !0 })), o && void 0 === Element.prototype.remove && (Element.prototype.remove = function () { this.parentNode && this.parentNode!
 .removeChild(this) }), function () { if (o && !a() && !1 !== document.createElement("div").classList.toggle("test", 0)) { var e = DOMTokenList.prototype.toggle; DOMTokenList.prototype.toggle = function (t) { if (arguments.length > 1) { var r = !!arguments[1]; return this[r ? "add" : "remove"](t), r } return e(t) } } }(), String.prototype.includes || r(5), Array.prototype.includes || r(33), Object.assign || r(42), Math.log2 || (Math.log2 = r(52)), Number.isNaN || (Number.isNaN = r(54)), Number.isInteger || (Number.isInteger = r(56)), i.Promise || (i.Promise = r(59)), i.WeakMap || (i.WeakMap = r(94)), String.codePointAt || (String.codePointAt = r(111)), String.fromCodePoint || (String.fromCodePoint = r(113)), i.Symbol || r(115), Object.values || (Object.values = r(122)) } }, function (e, t, r) { "use strict"; e.exports = "undefined" != typeof window && window.Math === Math ? window : "undefined" != typeof global && global.Math === Math ? global : "undefined" != typeof self && self.Math === Math ? self : {} }, function (e, t, r) { "use strict"; var n = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (e) { return typeof e } : function (e) { return e && "function" == typeof Symbol && e.constructor === Symbol && e !== Symbol.prototype ? "symbol" : typeof e }; e.exports = function () { return "object" === ("undefined" == typeof process ? "undefined" : n(process)) && process + "" == "[object process]" } }, function (e, t, r) { "use strict"; r(6), e.exports = r(9).String.includes }, function (e, t, r) { "use strict"; var n = r(7), i = r(25); n(n.P + n.F * r(32)("includes"), "String", { includes: function (e) { return !!~i(this, e, "includes").indexOf(e, arguments.length > 1 ? arguments[1] : void 0) } }) }, function (e, t, r) { "use strict"; var n = r(8), i = r(9), a = r(10), o = r(20), s = r(23), u = function e(t, r, u) { var l, c, h, d, f = t & e.F, p = t & e.G, v = t & e.P, m = t & e.B, g = p ? n : t & e.S ? n[r] || (n[r] = {}) : (n[r] || {}).prototype, y = p ? i : i[r] || (i[r] = {}), b = !
 y.prototype || (y.prototype = {}); for (l in p && (u = r), u) h = ((c = !f && g && void 0 !== g[l]) ? g : u)[l], d = m && c ? s(h, n) : v && "function" == typeof h ? s(Function.call, h) : h, g && o(g, l, h, t & e.U), y[l] != h && a(y, l, d), v && b[l] != h && (b[l] = h) }; n.core = i, u.F = 1, u.G = 2, u.S = 4, u.P = 8, u.B = 16, u.W = 32, u.U = 64, u.R = 128, e.exports = u }, function (e, t, r) { "use strict"; var n = e.exports = "undefined" != typeof window && window.Math == Math ? window : "undefined" != typeof self && self.Math == Math ? self : Function("return this")(); "number" == typeof __g && (__g = n) }, function (e, t, r) { "use strict"; var n = e.exports = { version: "2.5.7" }; "number" == typeof __e && (__e = n) }, function (e, t, r) { "use strict"; var n = r(11), i = r(19); e.exports = r(15) ? function (e, t, r) { return n.f(e, t, i(1, r)) } : function (e, t, r) { return e[t] = r, e } }, function (e, t, r) { "use strict"; var n = r(12), i = r(14), a = r(18), o = Object.defineProperty; t.f = r(15) ? Object.defineProperty : function (e, t, r) { if (n(e), t = a(t, !0), n(r), i) try { return o(e, t, r) } catch (e) { } if ("get" in r || "set" in r) throw TypeError("Accessors not supported!"); return "value" in r && (e[t] = r.value), e } }, function (e, t, r) { "use strict"; var n = r(13); e.exports = function (e) { if (!n(e)) throw TypeError(e + " is not an object!"); return e } }, function (e, t, r) { "use strict"; var n = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (e) { return typeof e } : function (e) { return e && "function" == typeof Symbol && e.constructor === Symbol && e !== Symbol.prototype ? "symbol" : typeof e }; e.exports = function (e) { return "object" === (void 0 === e ? "undefined" : n(e)) ? null !== e : "function" == typeof e } }, function (e, t, r) { "use strict"; e.exports = !r(15) && !r(16)(function () { return 7 != Object.defineProperty(r(17)("div"), "a", { get: function () { return 7 } }).a }) }, function (e, t, r) { "use strict"; e.exports = !r(16)(!
 function () { return 7 != Object.defineProperty({}, "a", { get: function () { return 7 } }).a }) }, function (e, t, r) { "use strict"; e.exports = function (e) { try { return !!e() } catch (e) { return !0 } } }, function (e, t, r) { "use strict"; var n = r(13), i = r(8).document, a = n(i) && n(i.createElement); e.exports = function (e) { return a ? i.createElement(e) : {} } }, function (e, t, r) { "use strict"; var n = r(13); e.exports = function (e, t) { if (!n(e)) return e; var r, i; if (t && "function" == typeof (r = e.toString) && !n(i = r.call(e))) return i; if ("function" == typeof (r = e.valueOf) && !n(i = r.call(e))) return i; if (!t && "function" == typeof (r = e.toString) && !n(i = r.call(e))) return i; throw TypeError("Can't convert object to primitive value") } }, function (e, t, r) { "use strict"; e.exports = function (e, t) { return { enumerable: !(1 & e), configurable: !(2 & e), writable: !(4 & e), value: t } } }, function (e, t, r) { "use strict"; var n = r(8), i = r(10), a = r(21), o = r(22)("src"), s = Function.toString, u = ("" + s).split("toString"); r(9).inspectSource = function (e) { return s.call(e) }, (e.exports = function (e, t, r, s) { var l = "function" == typeof r; l && (a(r, "name") || i(r, "name", t)), e[t] !== r && (l && (a(r, o) || i(r, o, e[t] ? "" + e[t] : u.join(String(t)))), e === n ? e[t] = r : s ? e[t] ? e[t] = r : i(e, t, r) : (delete e[t], i(e, t, r))) })(Function.prototype, "toString", function () { return "function" == typeof this && this[o] || s.call(this) }) }, function (e, t, r) { "use strict"; var n = {}.hasOwnProperty; e.exports = function (e, t) { return n.call(e, t) } }, function (e, t, r) { "use strict"; var n = 0, i = Math.random(); e.exports = function (e) { return "Symbol(".concat(void 0 === e ? "" : e, ")_", (++n + i).toString(36)) } }, function (e, t, r) { "use strict"; var n = r(24); e.exports = function (e, t, r) { if (n(e), void 0 === t) return e; switch (r) { case 1: return function (r) { return e.call(t, r) }; case 2: return function (r, n) { return e.c!
 all(t, r, n) }; case 3: return function (r, n, i) { return e.call(t, r, n, i) } }return function () { return e.apply(t, arguments) } } }, function (e, t, r) { "use strict"; e.exports = function (e) { if ("function" != typeof e) throw TypeError(e + " is not a function!"); return e } }, function (e, t, r) { "use strict"; var n = r(26), i = r(31); e.exports = function (e, t, r) { if (n(t)) throw TypeError("String#" + r + " doesn't accept regex!"); return String(i(e)) } }, function (e, t, r) { "use strict"; var n = r(13), i = r(27), a = r(28)("match"); e.exports = function (e) { var t; return n(e) && (void 0 !== (t = e[a]) ? !!t : "RegExp" == i(e)) } }, function (e, t, r) { "use strict"; var n = {}.toString; e.exports = function (e) { return n.call(e).slice(8, -1) } }, function (e, t, r) { "use strict"; var n = r(29)("wks"), i = r(22), a = r(8).Symbol, o = "function" == typeof a; (e.exports = function (e) { return n[e] || (n[e] = o && a[e] || (o ? a : i)("Symbol." + e)) }).store = n }, function (e, t, r) { "use strict"; var n = r(9), i = r(8), a = i["__core-js_shared__"] || (i["__core-js_shared__"] = {}); (e.exports = function (e, t) { return a[e] || (a[e] = void 0 !== t ? t : {}) })("versions", []).push({ version: n.version, mode: r(30) ? "pure" : "global", copyright: "\xA9 2018 Denis Pushkarev (zloirock.ru)" }) }, function (e, t, r) { "use strict"; e.exports = !1 }, function (e, t, r) { "use strict"; e.exports = function (e) { if (void 0 == e) throw TypeError("Can't call method on  " + e); return e } }, function (e, t, r) { "use strict"; var n = r(28)("match"); e.exports = function (e) { var t = /./; try { "/./"[e](t) } catch (r) { try { return t[n] = !1, !"/./"[e](t) } catch (e) { } } return !0 } }, function (e, t, r) { "use strict"; r(34), e.exports = r(9).Array.includes }, function (e, t, r) { "use strict"; var n = r(7), i = r(35)(!0); n(n.P, "Array", { includes: function (e) { return i(this, e, arguments.length > 1 ? arguments[1] : void 0) } }), r(41)("includes") }, function (e, t, r) { "use strict"; var n = r!
 (36), i = r(38), a = r(40); e.exports = function (e) { return function (t, r, o) { var s, u = n(t), l = i(u.length), c = a(o, l); if (e && r != r) { for (; l > c;)if ((s = u[c++]) != s) return !0 } else for (; l > c; c++)if ((e || c in u) && u[c] === r) return e || c || 0; return !e && -1 } } }, function (e, t, r) { "use strict"; var n = r(37), i = r(31); e.exports = function (e) { return n(i(e)) } }, function (e, t, r) { "use strict"; var n = r(27); e.exports = Object("z").propertyIsEnumerable(0) ? Object : function (e) { return "String" == n(e) ? e.split("") : Object(e) } }, function (e, t, r) { "use strict"; var n = r(39), i = Math.min; e.exports = function (e) { return e > 0 ? i(n(e), 9007199254740991) : 0 } }, function (e, t, r) { "use strict"; var n = Math.ceil, i = Math.floor; e.exports = function (e) { return isNaN(e = +e) ? 0 : (e > 0 ? i : n)(e) } }, function (e, t, r) { "use strict"; var n = r(39), i = Math.max, a = Math.min; e.exports = function (e, t) { return (e = n(e)) < 0 ? i(e + t, 0) : a(e, t) } }, function (e, t, r) { "use strict"; var n = r(28)("unscopables"), i = Array.prototype; void 0 == i[n] && r(10)(i, n, {}), e.exports = function (e) { i[n][e] = !0 } }, function (e, t, r) { "use strict"; r(43), e.exports = r(9).Object.assign }, function (e, t, r) { "use strict"; var n = r(7); n(n.S + n.F, "Object", { assign: r(44) }) }, function (e, t, r) { "use strict"; var n = r(45), i = r(49), a = r(50), o = r(51), s = r(37), u = Object.assign; e.exports = !u || r(16)(function () { var e = {}, t = {}, r = Symbol(), n = "abcdefghijklmnopqrst"; return e[r] = 7, n.split("").forEach(function (e) { t[e] = e }), 7 != u({}, e)[r] || Object.keys(u({}, t)).join("") != n }) ? function (e, t) { for (var r = o(e), u = arguments.length, l = 1, c = i.f, h = a.f; u > l;)for (var d, f = s(arguments[l++]), p = c ? n(f).concat(c(f)) : n(f), v = p.length, m = 0; v > m;)h.call(f, d = p[m++]) && (r[d] = f[d]); return r } : u }, function (e, t, r) { "use strict"; var n = r(46), i = r(48); e.exports = Object.keys || functi!
 on (e) { return n(e, i) } }, function (e, t, r) { "use strict"; var n = r(21), i = r(36), a = r(35)(!1), o = r(47)("IE_PROTO"); e.exports = function (e, t) { var r, s = i(e), u = 0, l = []; for (r in s) r != o && n(s, r) && l.push(r); for (; t.length > u;)n(s, r = t[u++]) && (~a(l, r) || l.push(r)); return l } }, function (e, t, r) { "use strict"; var n = r(29)("keys"), i = r(22); e.exports = function (e) { return n[e] || (n[e] = i(e)) } }, function (e, t, r) { "use strict"; e.exports = "constructor,hasOwnProperty,isPrototypeOf,propertyIsEnumerable,toLocaleString,toString,valueOf".split(",") }, function (e, t, r) { "use strict"; t.f = Object.getOwnPropertySymbols }, function (e, t, r) { "use strict"; t.f = {}.propertyIsEnumerable }, function (e, t, r) { "use strict"; var n = r(31); e.exports = function (e) { return Object(n(e)) } }, function (e, t, r) { "use strict"; r(53), e.exports = r(9).Math.log2 }, function (e, t, r) { "use strict"; var n = r(7); n(n.S, "Math", { log2: function (e) { return Math.log(e) / Math.LN2 } }) }, function (e, t, r) { "use strict"; r(55), e.exports = r(9).Number.isNaN }, function (e, t, r) { "use strict"; var n = r(7); n(n.S, "Number", { isNaN: function (e) { return e != e } }) }, function (e, t, r) { "use strict"; r(57), e.exports = r(9).Number.isInteger }, function (e, t, r) { "use strict"; var n = r(7); n(n.S, "Number", { isInteger: r(58) }) }, function (e, t, r) { "use strict"; var n = r(13), i = Math.floor; e.exports = function (e) { return !n(e) && isFinite(e) && i(e) === e } }, function (e, t, r) { "use strict"; r(60), r(62), r(72), r(75), r(92), r(93), e.exports = r(9).Promise }, function (e, t, r) { "use strict"; var n = r(61), i = {}; i[r(28)("toStringTag")] = "z", i + "" != "[object z]" && r(20)(Object.prototype, "toString", function () { return "[object " + n(this) + "]" }, !0) }, function (e, t, r) { "use strict"; var n = r(27), i = r(28)("toStringTag"), a = "Arguments" == n(function () { return arguments }()); e.exports = function (e) { var t, r, o; return void 0 === e !
 ? "Undefined" : null === e ? "Null" : "string" == typeof (r = function (e, t) { try { return e[t] } catch (e) { } }(t = Object(e), i)) ? r : a ? n(t) : "Object" == (o = n(t)) && "function" == typeof t.callee ? "Arguments" : o } }, function (e, t, r) { "use strict"; var n = r(63)(!0); r(64)(String, "String", function (e) { this._t = String(e), this._i = 0 }, function () { var e, t = this._t, r = this._i; return r >= t.length ? { value: void 0, done: !0 } : (e = n(t, r), this._i += e.length, { value: e, done: !1 }) }) }, function (e, t, r) { "use strict"; var n = r(39), i = r(31); e.exports = function (e) { return function (t, r) { var a, o, s = String(i(t)), u = n(r), l = s.length; return u < 0 || u >= l ? e ? "" : void 0 : (a = s.charCodeAt(u)) < 55296 || a > 56319 || u + 1 === l || (o = s.charCodeAt(u + 1)) < 56320 || o > 57343 ? e ? s.charAt(u) : a : e ? s.slice(u, u + 2) : o - 56320 + (a - 55296 << 10) + 65536 } } }, function (e, t, r) { "use strict"; var n = r(30), i = r(7), a = r(20), o = r(10), s = r(65), u = r(66), l = r(70), c = r(71), h = r(28)("iterator"), d = !([].keys && "next" in [].keys()), f = function () { return this }; e.exports = function (e, t, r, p, v, m, g) { u(r, t, p); var y, b, _, A = function (e) { if (!d && e in P) return P[e]; switch (e) { case "keys": case "values": return function () { return new r(this, e) } }return function () { return new r(this, e) } }, S = t + " Iterator", w = "values" == v, k = !1, P = e.prototype, x = P[h] || P["@@iterator"] || v && P[v], C = x || A(v), R = v ? w ? A("entries") : C : void 0, E = "Array" == t && P.entries || x; if (E && (_ = c(E.call(new e))) !== Object.prototype && _.next && (l(_, S, !0), n || "function" == typeof _[h] || o(_, h, f)), w && x && "values" !== x.name && (k = !0, C = function () { return x.call(this) }), n && !g || !d && !k && P[h] || o(P, h, C), s[t] = C, s[S] = f, v) if (y = { values: w ? C : A("values"), keys: m ? C : A("keys"), entries: R }, g) for (b in y) b in P || a(P, b, y[b]); else i(i.P + i.F * (d || k), t, y); return y!
  } }, function (e, t, r) { "use strict"; e.exports = {} }, function (e, t, r) { "use strict"; var n = r(67), i = r(19), a = r(70), o = {}; r(10)(o, r(28)("iterator"), function () { return this }), e.exports = function (e, t, r) { e.prototype = n(o, { next: i(1, r) }), a(e, t + " Iterator") } }, function (e, t, r) { "use strict"; var n = r(12), i = r(68), a = r(48), o = r(47)("IE_PROTO"), s = function () { }, u = function () { var e, t = r(17)("iframe"), n = a.length; for (t.style.display = "none", r(69).appendChild(t), t.src = "javascript:", (e = t.contentWindow.document).open(), e.write("<script>document.F=Object<\/script>"), e.close(), u = e.F; n--;)delete u.prototype[a[n]]; return u() }; e.exports = Object.create || function (e, t) { var r; return null !== e ? (s.prototype = n(e), r = new s, s.prototype = null, r[o] = e) : r = u(), void 0 === t ? r : i(r, t) } }, function (e, t, r) { "use strict"; var n = r(11), i = r(12), a = r(45); e.exports = r(15) ? Object.defineProperties : function (e, t) { i(e); for (var r, o = a(t), s = o.length, u = 0; s > u;)n.f(e, r = o[u++], t[r]); return e } }, function (e, t, r) { "use strict"; var n = r(8).document; e.exports = n && n.documentElement }, function (e, t, r) { "use strict"; var n = r(11).f, i = r(21), a = r(28)("toStringTag"); e.exports = function (e, t, r) { e && !i(e = r ? e : e.prototype, a) && n(e, a, { configurable: !0, value: t }) } }, function (e, t, r) { "use strict"; var n = r(21), i = r(51), a = r(47)("IE_PROTO"), o = Object.prototype; e.exports = Object.getPrototypeOf || function (e) { return e = i(e), n(e, a) ? e[a] : "function" == typeof e.constructor && e instanceof e.constructor ? e.constructor.prototype : e instanceof Object ? o : null } }, function (e, t, r) { "use strict"; for (var n = r(73), i = r(45), a = r(20), o = r(8), s = r(10), u = r(65), l = r(28), c = l("iterator"), h = l("toStringTag"), d = u.Array, f = { CSSRuleList: !0, CSSStyleDeclaration: !1, CSSValueList: !1, ClientRectList: !1, DOMRectList: !1, DOMStringList: !1, DOMTokenList: !0,!
  DataTransferItemList: !1, FileList: !1, HTMLAllCollection: !1, HTMLCollection: !1, HTMLFormElement: !1, HTMLSelectElement: !1, MediaList: !0, MimeTypeArray: !1, NamedNodeMap: !1, NodeList: !0, PaintRequestList: !1, Plugin: !1, PluginArray: !1, SVGLengthList: !1, SVGNumberList: !1, SVGPathSegList: !1, SVGPointList: !1, SVGStringList: !1, SVGTransformList: !1, SourceBufferList: !1, StyleSheetList: !0, TextTrackCueList: !1, TextTrackList: !1, TouchList: !1 }, p = i(f), v = 0; v < p.length; v++) { var m, g = p[v], y = f[g], b = o[g], _ = b && b.prototype; if (_ && (_[c] || s(_, c, d), _[h] || s(_, h, g), u[g] = d, y)) for (m in n) _[m] || a(_, m, n[m], !0) } }, function (e, t, r) { "use strict"; var n = r(41), i = r(74), a = r(65), o = r(36); e.exports = r(64)(Array, "Array", function (e, t) { this._t = o(e), this._i = 0, this._k = t }, function () { var e = this._t, t = this._k, r = this._i++; return !e || r >= e.length ? (this._t = void 0, i(1)) : i(0, "keys" == t ? r : "values" == t ? e[r] : [r, e[r]]) }, "values"), a.Arguments = a.Array, n("keys"), n("values"), n("entries") }, function (e, t, r) { "use strict"; e.exports = function (e, t) { return { value: t, done: !!e } } }, function (e, t, r) { "use strict"; var n, i, a, o, s = r(30), u = r(8), l = r(23), c = r(61), h = r(7), d = r(13), f = r(24), p = r(76), v = r(77), m = r(81), g = r(82).set, y = r(84)(), b = r(85), _ = r(86), A = r(87), S = r(88), w = u.TypeError, k = u.process, P = k && k.versions, x = P && P.v8 || "", C = u.Promise, R = "process" == c(k), E = function () { }, T = i = b.f, O = !!function () { try { var e = C.resolve(1), t = (e.constructor = {})[r(28)("species")] = function (e) { e(E, E) }; return (R || "function" == typeof PromiseRejectionEvent) && e.then(E) instanceof t && 0 !== x.indexOf("6.6") && -1 === A.indexOf("Chrome/66") } catch (e) { } }(), I = function (e) { var t; return !(!d(e) || "function" != typeof (t = e.then)) && t }, F = function (e, t) { if (!e._n) { e._n = !0; var r = e._c; y(function () { for (var n = e._v, i = 1 == e!
 ._s, a = 0, o = function (t) { var r, a, o, s = i ? t.ok : t.fail, u = t.resolve, l = t.reject, c = t.domain; try { s ? (i || (2 == e._h && M(e), e._h = 1), !0 === s ? r = n : (c && c.enter(), r = s(n), c && (c.exit(), o = !0)), r === t.promise ? l(w("Promise-chain cycle")) : (a = I(r)) ? a.call(r, u, l) : u(r)) : l(n) } catch (e) { c && !o && c.exit(), l(e) } }; r.length > a;)o(r[a++]); e._c = [], e._n = !1, t && !e._h && L(e) }) } }, L = function (e) { g.call(u, function () { var t, r, n, i = e._v, a = j(e); if (a && (t = _(function () { R ? k.emit("unhandledRejection", i, e) : (r = u.onunhandledrejection) ? r({ promise: e, reason: i }) : (n = u.console) && n.error && n.error("Unhandled promise rejection", i) }), e._h = R || j(e) ? 2 : 1), e._a = void 0, a && t.e) throw t.v }) }, j = function (e) { return 1 !== e._h && 0 === (e._a || e._c).length }, M = function (e) { g.call(u, function () { var t; R ? k.emit("rejectionHandled", e) : (t = u.onrejectionhandled) && t({ promise: e, reason: e._v }) }) }, D = function (e) { var t = this; t._d || (t._d = !0, (t = t._w || t)._v = e, t._s = 2, t._a || (t._a = t._c.slice()), F(t, !0)) }, N = function e(t) { var r, n = this; if (!n._d) { n._d = !0, n = n._w || n; try { if (n === t) throw w("Promise can't be resolved itself"); (r = I(t)) ? y(function () { var i = { _w: n, _d: !1 }; try { r.call(t, l(e, i, 1), l(D, i, 1)) } catch (e) { D.call(i, e) } }) : (n._v = t, n._s = 1, F(n, !1)) } catch (e) { D.call({ _w: n, _d: !1 }, e) } } }; O || (C = function (e) { p(this, C, "Promise", "_h"), f(e), n.call(this); try { e(l(N, this, 1), l(D, this, 1)) } catch (e) { D.call(this, e) } }, (n = function (e) { this._c = [], this._a = void 0, this._s = 0, this._d = !1, this._v = void 0, this._h = 0, this._n = !1 }).prototype = r(89)(C.prototype, { then: function (e, t) { var r = T(m(this, C)); return r.ok = "function" != typeof e || e, r.fail = "function" == typeof t && t, r.domain = R ? k.domain : void 0, this._c.push(r), this._a && this._a.push(r), this._s && F(this, !1), r.promise !
 }, catch: function (e) { return this.then(void 0, e) } }), a = function () { var e = new n; this.promise = e, this.resolve = l(N, e, 1), this.reject = l(D, e, 1) }, b.f = T = function (e) { return e === C || e === o ? new a(e) : i(e) }), h(h.G + h.W + h.F * !O, { Promise: C }), r(70)(C, "Promise"), r(90)("Promise"), o = r(9).Promise, h(h.S + h.F * !O, "Promise", { reject: function (e) { var t = T(this); return (0, t.reject)(e), t.promise } }), h(h.S + h.F * (s || !O), "Promise", { resolve: function (e) { return S(s && this === o ? C : this, e) } }), h(h.S + h.F * !(O && r(91)(function (e) { C.all(e).catch(E) })), "Promise", { all: function (e) { var t = this, r = T(t), n = r.resolve, i = r.reject, a = _(function () { var r = [], a = 0, o = 1; v(e, !1, function (e) { var s = a++, u = !1; r.push(void 0), o++, t.resolve(e).then(function (e) { u || (u = !0, r[s] = e, --o || n(r)) }, i) }), --o || n(r) }); return a.e && i(a.v), r.promise }, race: function (e) { var t = this, r = T(t), n = r.reject, i = _(function () { v(e, !1, function (e) { t.resolve(e).then(r.resolve, n) }) }); return i.e && n(i.v), r.promise } }) }, function (e, t, r) { "use strict"; e.exports = function (e, t, r, n) { if (!(e instanceof t) || void 0 !== n && n in e) throw TypeError(r + ": incorrect invocation!"); return e } }, function (e, t, r) { "use strict"; var n = r(23), i = r(78), a = r(79), o = r(12), s = r(38), u = r(80), l = {}, c = {}, h = e.exports = function (e, t, r, h, d) { var f, p, v, m, g = d ? function () { return e } : u(e), y = n(r, h, t ? 2 : 1), b = 0; if ("function" != typeof g) throw TypeError(e + " is not iterable!"); if (a(g)) { for (f = s(e.length); f > b; b++)if ((m = t ? y(o(p = e[b])[0], p[1]) : y(e[b])) === l || m === c) return m } else for (v = g.call(e); !(p = v.next()).done;)if ((m = i(v, y, p.value, t)) === l || m === c) return m }; h.BREAK = l, h.RETURN = c }, function (e, t, r) { "use strict"; var n = r(12); e.exports = function (e, t, r, i) { try { return i ? t(n(r)[0], r[1]) : t(r) } catch (t) { var a = e.re!
 turn; throw void 0 !== a && n(a.call(e)), t } } }, function (e, t, r) { "use strict"; var n = r(65), i = r(28)("iterator"), a = Array.prototype; e.exports = function (e) { return void 0 !== e && (n.Array === e || a[i] === e) } }, function (e, t, r) { "use strict"; var n = r(61), i = r(28)("iterator"), a = r(65); e.exports = r(9).getIteratorMethod = function (e) { if (void 0 != e) return e[i] || e["@@iterator"] || a[n(e)] } }, function (e, t, r) { "use strict"; var n = r(12), i = r(24), a = r(28)("species"); e.exports = function (e, t) { var r, o = n(e).constructor; return void 0 === o || void 0 == (r = n(o)[a]) ? t : i(r) } }, function (e, t, r) { "use strict"; var n, i, a, o = r(23), s = r(83), u = r(69), l = r(17), c = r(8), h = c.process, d = c.setImmediate, f = c.clearImmediate, p = c.MessageChannel, v = c.Dispatch, m = 0, g = {}, y = function () { var e = +this; if (g.hasOwnProperty(e)) { var t = g[e]; delete g[e], t() } }, b = function (e) { y.call(e.data) }; d && f || (d = function (e) { for (var t = [], r = 1; arguments.length > r;)t.push(arguments[r++]); return g[++m] = function () { s("function" == typeof e ? e : Function(e), t) }, n(m), m }, f = function (e) { delete g[e] }, "process" == r(27)(h) ? n = function (e) { h.nextTick(o(y, e, 1)) } : v && v.now ? n = function (e) { v.now(o(y, e, 1)) } : p ? (a = (i = new p).port2, i.port1.onmessage = b, n = o(a.postMessage, a, 1)) : c.addEventListener && "function" == typeof postMessage && !c.importScripts ? (n = function (e) { c.postMessage(e + "", "*") }, c.addEventListener("message", b, !1)) : n = "onreadystatechange" in l("script") ? function (e) { u.appendChild(l("script")).onreadystatechange = function () { u.removeChild(this), y.call(e) } } : function (e) { setTimeout(o(y, e, 1), 0) }), e.exports = { set: d, clear: f } }, function (e, t, r) { "use strict"; e.exports = function (e, t, r) { var n = void 0 === r; switch (t.length) { case 0: return n ? e() : e.call(r); case 1: return n ? e(t[0]) : e.call(r, t[0]); case 2: return n ? e(t[0], t[1]) : e.call!
 (r, t[0], t[1]); case 3: return n ? e(t[0], t[1], t[2]) : e.call(r, t[0], t[1], t[2]); case 4: return n ? e(t[0], t[1], t[2], t[3]) : e.call(r, t[0], t[1], t[2], t[3]) }return e.apply(r, t) } }, function (e, t, r) { "use strict"; var n = r(8), i = r(82).set, a = n.MutationObserver || n.WebKitMutationObserver, o = n.process, s = n.Promise, u = "process" == r(27)(o); e.exports = function () { var e, t, r, l = function () { var n, i; for (u && (n = o.domain) && n.exit(); e;) { i = e.fn, e = e.next; try { i() } catch (n) { throw e ? r() : t = void 0, n } } t = void 0, n && n.enter() }; if (u) r = function () { o.nextTick(l) }; else if (!a || n.navigator && n.navigator.standalone) if (s && s.resolve) { var c = s.resolve(void 0); r = function () { c.then(l) } } else r = function () { i.call(n, l) }; else { var h = !0, d = document.createTextNode(""); new a(l).observe(d, { characterData: !0 }), r = function () { d.data = h = !h } } return function (n) { var i = { fn: n, next: void 0 }; t && (t.next = i), e || (e = i, r()), t = i } } }, function (e, t, r) { "use strict"; var n = r(24); e.exports.f = function (e) { return new function (e) { var t, r; this.promise = new e(function (e, n) { if (void 0 !== t || void 0 !== r) throw TypeError("Bad Promise constructor"); t = e, r = n }), this.resolve = n(t), this.reject = n(r) }(e) } }, function (e, t, r) { "use strict"; e.exports = function (e) { try { return { e: !1, v: e() } } catch (e) { return { e: !0, v: e } } } }, function (e, t, r) { "use strict"; var n = r(8).navigator; e.exports = n && n.userAgent || "" }, function (e, t, r) { "use strict"; var n = r(12), i = r(13), a = r(85); e.exports = function (e, t) { if (n(e), i(t) && t.constructor === e) return t; var r = a.f(e); return (0, r.resolve)(t), r.promise } }, function (e, t, r) { "use strict"; var n = r(20); e.exports = function (e, t, r) { for (var i in t) n(e, i, t[i], r); return e } }, function (e, t, r) { "use strict"; var n = r(8), i = r(11), a = r(15), o = r(28)("species"); e.exports = function (e) { var t = n!
 [e]; a && t && !t[o] && i.f(t, o, { configurable: !0, get: function () { return this } }) } }, function (e, t, r) { "use strict"; var n = r(28)("iterator"), i = !1; try { var a = [7][n](); a.return = function () { i = !0 }, Array.from(a, function () { throw 2 }) } catch (e) { } e.exports = function (e, t) { if (!t && !i) return !1; var r = !1; try { var a = [7], o = a[n](); o.next = function () { return { done: r = !0 } }, a[n] = function () { return o }, e(a) } catch (e) { } return r } }, function (e, t, r) { "use strict"; var n = r(7), i = r(9), a = r(8), o = r(81), s = r(88); n(n.P + n.R, "Promise", { finally: function (e) { var t = o(this, i.Promise || a.Promise), r = "function" == typeof e; return this.then(r ? function (r) { return s(t, e()).then(function () { return r }) } : e, r ? function (r) { return s(t, e()).then(function () { throw r }) } : e) } }) }, function (e, t, r) { "use strict"; var n = r(7), i = r(85), a = r(86); n(n.S, "Promise", { try: function (e) { var t = i.f(this), r = a(e); return (r.e ? t.reject : t.resolve)(r.v), t.promise } }) }, function (e, t, r) { "use strict"; r(60), r(72), r(95), r(107), r(109), e.exports = r(9).WeakMap }, function (e, t, r) { "use strict"; var n, i = r(96)(0), a = r(20), o = r(100), s = r(44), u = r(101), l = r(13), c = r(16), h = r(102), d = o.getWeak, f = Object.isExtensible, p = u.ufstore, v = {}, m = function (e) { return function () { return e(this, arguments.length > 0 ? arguments[0] : void 0) } }, g = { get: function (e) { if (l(e)) { var t = d(e); return !0 === t ? p(h(this, "WeakMap")).get(e) : t ? t[this._i] : void 0 } }, set: function (e, t) { return u.def(h(this, "WeakMap"), e, t) } }, y = e.exports = r(103)("WeakMap", m, g, u, !0, !0); c(function () { return 7 != (new y).set((Object.freeze || Object)(v), 7).get(v) }) && (s((n = u.getConstructor(m, "WeakMap")).prototype, g), o.NEED = !0, i(["delete", "has", "get", "set"], function (e) { var t = y.prototype, r = t[e]; a(t, e, function (t, i) { if (l(t) && !f(t)) { this._f || (this._f = new n); var !
 a = this.._f[e](t, i); return "set" == e ? this : a } return r.call(this, t, i) }) })) }, function (e, t, r) { "use strict"; var n = r(23), i = r(37), a = r(51), o = r(38), s = r(97); e.exports = function (e, t) { var r = 1 == e, u = 2 == e, l = 3 == e, c = 4 == e, h = 6 == e, d = 5 == e || h, f = t || s; return function (t, s, p) { for (var v, m, g = a(t), y = i(g), b = n(s, p, 3), _ = o(y.length), A = 0, S = r ? f(t, _) : u ? f(t, 0) : void 0; _ > A; A++)if ((d || A in y) && (m = b(v = y[A], A, g), e)) if (r) S[A] = m; else if (m) switch (e) { case 3: return !0; case 5: return v; case 6: return A; case 2: S.push(v) } else if (c) return !1; return h ? -1 : l || c ? c : S } } }, function (e, t, r) { "use strict"; var n = r(98); e.exports = function (e, t) { return new (n(e))(t) } }, function (e, t, r) { "use strict"; var n = r(13), i = r(99), a = r(28)("species"); e.exports = function (e) { var t; return i(e) && ("function" != typeof (t = e.constructor) || t !== Array && !i(t.prototype) || (t = void 0), n(t) && null === (t = t[a]) && (t = void 0)), void 0 === t ? Array : t } }, function (e, t, r) { "use strict"; var n = r(27); e.exports = Array.isArray || function (e) { return "Array" == n(e) } }, function (e, t, r) { "use strict"; var n = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (e) { return typeof e } : function (e) { return e && "function" == typeof Symbol && e.constructor === Symbol && e !== Symbol.prototype ? "symbol" : typeof e }, i = r(22)("meta"), a = r(13), o = r(21), s = r(11).f, u = 0, l = Object.isExtensible || function () { return !0 }, c = !r(16)(function () { return l(Object.preventExtensions({})) }), h = function (e) { s(e, i, { value: { i: "O" + ++u, w: {} } }) }, d = e.exports = { KEY: i, NEED: !1, fastKey: function (e, t) { if (!a(e)) return "symbol" == (void 0 === e ? "undefined" : n(e)) ? e : ("string" == typeof e ? "S" : "P") + e; if (!o(e, i)) { if (!l(e)) return "F"; if (!t) return "E"; h(e) } return e[i].i }, getWeak: function (e, t) { if (!o(e, i)) { i!
 f (!l(e)) return !0; if (!t) return !1; h(e) } return e[i].w }, onFreeze: function (e) { return c && d.NEED && l(e) && !o(e, i) && h(e), e } } }, function (e, t, r) { "use strict"; var n = r(89), i = r(100).getWeak, a = r(12), o = r(13), s = r(76), u = r(77), l = r(96), c = r(21), h = r(102), d = l(5), f = l(6), p = 0, v = function (e) { return e._l || (e._l = new m) }, m = function () { this.a = [] }, g = function (e, t) { return d(e.a, function (e) { return e[0] === t }) }; m.prototype = { get: function (e) { var t = g(this, e); if (t) return t[1] }, has: function (e) { return !!g(this, e) }, set: function (e, t) { var r = g(this, e); r ? r[1] = t : this.a.push([e, t]) }, delete: function (e) { var t = f(this.a, function (t) { return t[0] === e }); return ~t && this.a.splice(t, 1), !!~t } }, e.exports = { getConstructor: function (e, t, r, a) { var l = e(function (e, n) { s(e, l, t, "_i"), e._t = t, e._i = p++, e._l = void 0, void 0 != n && u(n, r, e[a], e) }); return n(l.prototype, { delete: function (e) { if (!o(e)) return !1; var r = i(e); return !0 === r ? v(h(this, t)).delete(e) : r && c(r, this._i) && delete r[this._i] }, has: function (e) { if (!o(e)) return !1; var r = i(e); return !0 === r ? v(h(this, t)).has(e) : r && c(r, this._i) } }), l }, def: function (e, t, r) { var n = i(a(t), !0); return !0 === n ? v(e).set(t, r) : n[e._i] = r, e }, ufstore: v } }, function (e, t, r) { "use strict"; var n = r(13); e.exports = function (e, t) { if (!n(e) || e._t !== t) throw TypeError("Incompatible receiver, " + t + " required!"); return e } }, function (e, t, r) { "use strict"; var n = r(8), i = r(7), a = r(20), o = r(89), s = r(100), u = r(77), l = r(76), c = r(13), h = r(16), d = r(91), f = r(70), p = r(104); e.exports = function (e, t, r, v, m, g) { var y = n[e], b = y, _ = m ? "set" : "add", A = b && b.prototype, S = {}, w = function (e) { var t = A[e]; a(A, e, "delete" == e ? function (e) { return !(g && !c(e)) && t.call(this, 0 === e ? 0 : e) } : "has" == e ? function (e) { return !(g && !c(e)) && t.cal!
 l(this, 0 === e ? 0 : e) } : "get" == e ? function (e) { return g && !c(e) ? void 0 : t.call(this, 0 === e ? 0 : e) } : "add" == e ? function (e) { return t.call(this, 0 === e ? 0 : e), this } : function (e, r) { return t.call(this, 0 === e ? 0 : e, r), this }) }; if ("function" == typeof b && (g || A.forEach && !h(function () { (new b).entries().next() }))) { var k = new b, P = k[_](g ? {} : -0, 1) != k, x = h(function () { k.has(1) }), C = d(function (e) { new b(e) }), R = !g && h(function () { for (var e = new b, t = 5; t--;)e[_](t, t); return !e.has(-0) }); C || ((b = t(function (t, r) { l(t, b, e); var n = p(new y, t, b); return void 0 != r && u(r, m, n[_], n), n })).prototype = A, A.constructor = b), (x || R) && (w("delete"), w("has"), m && w("get")), (R || P) && w(_), g && A.clear && delete A.clear } else b = v.getConstructor(t, e, m, _), o(b.prototype, r), s.NEED = !0; return f(b, e), S[e] = b, i(i.G + i.W + i.F * (b != y), S), g || v.setStrong(b, e, m), b } }, function (e, t, r) { "use strict"; var n = r(13), i = r(105).set; e.exports = function (e, t, r) { var a, o = t.constructor; return o !== r && "function" == typeof o && (a = o.prototype) !== r.prototype && n(a) && i && i(e, a), e } }, function (e, t, r) { "use strict"; var n = r(13), i = r(12), a = function (e, t) { if (i(e), !n(t) && null !== t) throw TypeError(t + ": can't set as prototype!") }; e.exports = { set: Object.setPrototypeOf || ("__proto__" in {} ? function (e, t, n) { try { (n = r(23)(Function.call, r(106).f(Object.prototype, "__proto__").set, 2))(e, []), t = !(e instanceof Array) } catch (e) { t = !0 } return function (e, r) { return a(e, r), t ? e.__proto__ = r : n(e, r), e } }({}, !1) : void 0), check: a } }, function (e, t, r) { "use strict"; var n = r(50), i = r(19), a = r(36), o = r(18), s = r(21), u = r(14), l = Object.getOwnPropertyDescriptor; t.f = r(15) ? l : function (e, t) { if (e = a(e), t = o(t, !0), u) try { return l(e, t) } catch (e) { } if (s(e, t)) return i(!n.f.call(e, t), e[t]) } }, function (e, t, r) { "use stric!
 t"; r(108)("WeakMap") }, function (e, t, r) { "use strict"; var n = r(7); e.exports = function (e) { n(n.S, e, { of: function () { for (var e = arguments.length, t = new Array(e); e--;)t[e] = arguments[e]; return new this(t) } }) } }, function (e, t, r) { "use strict"; r(110)("WeakMap") }, function (e, t, r) { "use strict"; var n = r(7), i = r(24), a = r(23), o = r(77); e.exports = function (e) { n(n.S, e, { from: function (e) { var t, r, n, s, u = arguments[1]; return i(this), (t = void 0 !== u) && i(u), void 0 == e ? new this : (r = [], t ? (n = 0, s = a(u, arguments[2], 2), o(e, !1, function (e) { r.push(s(e, n++)) })) : o(e, !1, r.push, r), new this(r)) } }) } }, function (e, t, r) { "use strict"; r(112), e.exports = r(9).String.codePointAt }, function (e, t, r) { "use strict"; var n = r(7), i = r(63)(!1); n(n.P, "String", { codePointAt: function (e) { return i(this, e) } }) }, function (e, t, r) { "use strict"; r(114), e.exports = r(9).String.fromCodePoint }, function (e, t, r) { "use strict"; var n = r(7), i = r(40), a = String.fromCharCode, o = String.fromCodePoint; n(n.S + n.F * (!!o && 1 != o.length), "String", { fromCodePoint: function (e) { for (var t, r = [], n = arguments.length, o = 0; n > o;) { if (t = +arguments[o++], i(t, 1114111) !== t) throw RangeError(t + " is not a valid code point"); r.push(t < 65536 ? a(t) : a(55296 + ((t -= 65536) >> 10), t % 1024 + 56320)) } return r.join("") } }) }, function (e, t, r) { "use strict"; r(116), r(60), e.exports = r(9).Symbol }, function (e, t, r) { "use strict"; var n = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (e) { return typeof e } : function (e) { return e && "function" == typeof Symbol && e.constructor === Symbol && e !== Symbol.prototype ? "symbol" : typeof e }, i = r(8), a = r(21), o = r(15), s = r(7), u = r(20), l = r(100).KEY, c = r(16), h = r(29), d = r(70), f = r(22), p = r(28), v = r(117), m = r(118), g = r(119), y = r(99), b = r(12), _ = r(13), A = r(36), S = r(18), w = r(19), k = r(67), P = r(120), x = r(106!
 ), C = r(11), R = r(45), E = x.f, T = C.f, O = P.f, I = i.Symbol, F = i.JSON, L = F && F.stringify, j = p("_hidden"), M = p("toPrimitive"), D = {}.propertyIsEnumerable, N = h("symbol-registry"), q = h("symbols"), W = h("op-symbols"), U = Object.prototype, B = "function" == typeof I, z = i.QObject, G = !z || !z.prototype || !z.prototype.findChild, H = o && c(function () { return 7 != k(T({}, "a", { get: function () { return T(this, "a", { value: 7 }).a } })).a }) ? function (e, t, r) { var n = E(U, t); n && delete U[t], T(e, t, r), n && e !== U && T(U, t, n) } : T, X = function (e) { var t = q[e] = k(I.prototype); return t._k = e, t }, Y = B && "symbol" == n(I.iterator) ? function (e) { return "symbol" == (void 0 === e ? "undefined" : n(e)) } : function (e) { return e instanceof I }, V = function (e, t, r) { return e === U && V(W, t, r), b(e), t = S(t, !0), b(r), a(q, t) ? (r.enumerable ? (a(e, j) && e[j][t] && (e[j][t] = !1), r = k(r, { enumerable: w(0, !1) })) : (a(e, j) || T(e, j, w(1, {})), e[j][t] = !0), H(e, t, r)) : T(e, t, r) }, Q = function (e, t) { b(e); for (var r, n = g(t = A(t)), i = 0, a = n.length; a > i;)V(e, r = n[i++], t[r]); return e }, K = function (e) { var t = D.call(this, e = S(e, !0)); return !(this === U && a(q, e) && !a(W, e)) && (!(t || !a(this, e) || !a(q, e) || a(this, j) && this[j][e]) || t) }, J = function (e, t) { if (e = A(e), t = S(t, !0), e !== U || !a(q, t) || a(W, t)) { var r = E(e, t); return !r || !a(q, t) || a(e, j) && e[j][t] || (r.enumerable = !0), r } }, Z = function (e) { for (var t, r = O(A(e)), n = [], i = 0; r.length > i;)a(q, t = r[i++]) || t == j || t == l || n.push(t); return n }, $ = function (e) { for (var t, r = e === U, n = O(r ? W : A(e)), i = [], o = 0; n.length > o;)!a(q, t = n[o++]) || r && !a(U, t) || i.push(q[t]); return i }; B || (u((I = function () { if (this instanceof I) throw TypeError("Symbol is not a constructor!"); var e = f(arguments.length > 0 ? arguments[0] : void 0); return o && G && H(U, e, { configurable: !0, set: function t(r) { this === U!
  && t.call(W, r), a(this, j) && a(this[j], e) && (this[j][e] = !1), H(this, e, w(1, r)) } }), X(e) }).prototype, "toString", function () { return this._k }), x.f = J, C.f = V, r(121).f = P.f = Z, r(50).f = K, r(49).f = $, o && !r(30) && u(U, "propertyIsEnumerable", K, !0), v.f = function (e) { return X(p(e)) }), s(s.G + s.W + s.F * !B, { Symbol: I }); for (var ee = "hasInstance,isConcatSpreadable,iterator,match,replace,search,species,split,toPrimitive,toStringTag,unscopables".split(","), te = 0; ee.length > te;)p(ee[te++]); for (var re = R(p.store), ne = 0; re.length > ne;)m(re[ne++]); s(s.S + s.F * !B, "Symbol", { for: function (e) { return a(N, e += "") ? N[e] : N[e] = I(e) }, keyFor: function (e) { if (!Y(e)) throw TypeError(e + " is not a symbol!"); for (var t in N) if (N[t] === e) return t }, useSetter: function () { G = !0 }, useSimple: function () { G = !1 } }), s(s.S + s.F * !B, "Object", { create: function (e, t) { return void 0 === t ? k(e) : Q(k(e), t) }, defineProperty: V, defineProperties: Q, getOwnPropertyDescriptor: J, getOwnPropertyNames: Z, getOwnPropertySymbols: $ }), F && s(s.S + s.F * (!B || c(function () { var e = I(); return "[null]" != L([e]) || "{}" != L({ a: e }) || "{}" != L(Object(e)) })), "JSON", { stringify: function (e) { for (var t, r, n = [e], i = 1; arguments.length > i;)n.push(arguments[i++]); if (r = t = n[1], (_(t) || void 0 !== e) && !Y(e)) return y(t) || (t = function (e, t) { if ("function" == typeof r && (t = r.call(this, e, t)), !Y(t)) return t }), n[1] = t, L.apply(F, n) } }), I.prototype[M] || r(10)(I.prototype, M, I.prototype.valueOf), d(I, "Symbol"), d(Math, "Math", !0), d(i.JSON, "JSON", !0) }, function (e, t, r) { "use strict"; t.f = r(28) }, function (e, t, r) { "use strict"; var n = r(8), i = r(9), a = r(30), o = r(117), s = r(11).f; e.exports = function (e) { var t = i.Symbol || (i.Symbol = a ? {} : n.Symbol || {}); "_" == e.charAt(0) || e in t || s(t, e, { value: o.f(e) }) } }, function (e, t, r) { "use strict"; var n = r(45), i = r(49), a = r(50); e.exports = f!
 unction (e) { var t = n(e), r = i.f; if (r) for (var o, s = r(e), u = a.f, l = 0; s.length > l;)u.call(e, o = s[l++]) && t.push(o); return t } }, function (e, t, r) { "use strict"; var n = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (e) { return typeof e } : function (e) { return e && "function" == typeof Symbol && e.constructor === Symbol && e !== Symbol.prototype ? "symbol" : typeof e }, i = r(36), a = r(121).f, o = {}.toString, s = "object" == ("undefined" == typeof window ? "undefined" : n(window)) && window && Object.getOwnPropertyNames ? Object.getOwnPropertyNames(window) : []; e.exports.f = function (e) { return s && "[object Window]" == o.call(e) ? function (e) { try { return a(e) } catch (e) { return s.slice() } }(e) : a(i(e)) } }, function (e, t, r) { "use strict"; var n = r(46), i = r(48).concat("length", "prototype"); t.f = Object.getOwnPropertyNames || function (e) { return n(e, i) } }, function (e, t, r) { "use strict"; r(123), e.exports = r(9).Object.values }, function (e, t, r) { "use strict"; var n = r(7), i = r(124)(!1); n(n.S, "Object", { values: function (e) { return i(e) } }) }, function (e, t, r) { "use strict"; var n = r(45), i = r(36), a = r(50).f; e.exports = function (e) { return function (t) { for (var r, o = i(t), s = n(o), u = s.length, l = 0, c = []; u > l;)a.call(o, r = s[l++]) && c.push(e ? [r, o[r]] : o[r]); return c } } }, function (e, t, r) { "use strict"; var n = !1; if ("undefined" != typeof ReadableStream) try { new ReadableStream({ start: function (e) { e.close() } }), n = !0 } catch (e) { } t.ReadableStream = n ? ReadableStream : r(126).ReadableStream }, function (e, t, r) { "use strict"; var n = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (e) { return typeof e } : function (e) { return e && "function" == typeof Symbol && e.constructor === Symbol && e !== Symbol.prototype ? "symbol" : typeof e }; !function (e, t) { for (var r in t) e[r] = t[r] }(t, function (e) { var t = {}; function r(n) { if (t[n]) return !
 t[n].exports; var i = t[n] = { i: n, l: !1, exports: {} }; return e[n].call(i.exports, i, i.exports, r), i.l = !0, i.exports } return r.m = e, r.c = t, r.i = function (e) { return e }, r.d = function (e, t, n) { r.o(e, t) || Object.defineProperty(e, t, { configurable: !1, enumerable: !0, get: n }) }, r.n = function (e) { var t = e && e.__esModule ? function () { return e.default } : function () { return e }; return r.d(t, "a", t), t }, r.o = function (e, t) { return Object.prototype.hasOwnProperty.call(e, t) }, r.p = "", r(r.s = 7) }([function (e, t, r) { var i = "function" == typeof Symbol && "symbol" === n(Symbol.iterator) ? function (e) { return void 0 === e ? "undefined" : n(e) } : function (e) { return e && "function" == typeof Symbol && e.constructor === Symbol && e !== Symbol.prototype ? "symbol" : void 0 === e ? "undefined" : n(e) }, a = r(1).assert; function o(e) { return "string" == typeof e || "symbol" === (void 0 === e ? "undefined" : i(e)) } function s(e, t, r) { if ("function" != typeof e) throw new TypeError("Argument is not a function"); return Function.prototype.apply.call(e, t, r) } t.typeIsObject = function (e) { return "object" === (void 0 === e ? "undefined" : i(e)) && null !== e || "function" == typeof e }, t.createDataProperty = function (e, r, n) { a(t.typeIsObject(e)), Object.defineProperty(e, r, { value: n, writable: !0, enumerable: !0, configurable: !0 }) }, t.createArrayFromList = function (e) { return e.slice() }, t.ArrayBufferCopy = function (e, t, r, n, i) { new Uint8Array(e).set(new Uint8Array(r, n, i), t) }, t.CreateIterResultObject = function (e, t) { a("boolean" == typeof t); var r = {}; return Object.defineProperty(r, "value", { value: e, enumerable: !0, writable: !0, configurable: !0 }), Object.defineProperty(r, "done", { value: t, enumerable: !0, writable: !0, configurable: !0 }), r }, t.IsFiniteNonNegativeNumber = function (e) { return !Number.isNaN(e) && (e !== 1 / 0 && !(e < 0)) }, t.InvokeOrNoop = function (e, t, r) { a(void 0 !== e), a(o(t)), a(Array.isArray(r)); var n !
 = e[t]; if (void 0 !== n) return s(n, e, r) }, t.PromiseInvokeOrNoop = function (e, r, n) { a(void 0 !== e), a(o(r)), a(Array.isArray(n)); try { return Promise.resolve(t.InvokeOrNoop(e, r, n)) } catch (e) { return Promise.reject(e) } }, t.PromiseInvokeOrPerformFallback = function (e, t, r, n, i) { a(void 0 !== e), a(o(t)), a(Array.isArray(r)), a(Array.isArray(i)); var u = void 0; try { u = e[t] } catch (e) { return Promise.reject(e) } if (void 0 === u) return n.apply(null, i); try { return Promise.resolve(s(u, e, r)) } catch (e) { return Promise.reject(e) } }, t.TransferArrayBuffer = function (e) { return e.slice() }, t.ValidateAndNormalizeHighWaterMark = function (e) { if (e = Number(e), Number.isNaN(e) || e < 0) throw new RangeError("highWaterMark property of a queuing strategy must be non-negative and non-NaN"); return e }, t.ValidateAndNormalizeQueuingStrategy = function (e, r) { if (void 0 !== e && "function" != typeof e) throw new TypeError("size property of a queuing strategy must be a function"); return { size: e, highWaterMark: r = t.ValidateAndNormalizeHighWaterMark(r) } } }, function (e, t, r) { function n(e) { this.name = "AssertionError", this.message = e || "", this.stack = (new Error).stack } n.prototype = Object.create(Error.prototype), n.prototype.constructor = n, e.exports = { rethrowAssertionErrorRejection: function (e) { e && e.constructor === n && setTimeout(function () { throw e }, 0) }, AssertionError: n, assert: function (e, t) { if (!e) throw new n(t) } } }, function (e, t, r) { var n = function () { function e(e, t) { for (var r = 0; r < t.length; r++) { var n = t[r]; n.enumerable = n.enumerable || !1, n.configurable = !0, "value" in n && (n.writable = !0), Object.defineProperty(e, n.key, n) } } return function (t, r, n) { return r && e(t.prototype, r), n && e(t, n), t } }(); function i(e, t) { if (!(e instanceof t)) throw new TypeError("Cannot call a class as a function") } var a = r(0), o = a.InvokeOrNoop, s = a.PromiseInvokeOrNoop, u = a.ValidateAndNormalizeQueuingStrategy, l = a.typ!
 eIsObject, c = r(1), h = c.assert, d = c.rethrowAssertionErrorRejection, f = r(3), p = f.DequeueValue, v = f.EnqueueValueWithSize, m = f.PeekQueueValue, g = f.ResetQueue, y = function () { function e() { var t = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {}, r = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : {}, n = r.size, a = r.highWaterMark, o = void 0 === a ? 1 : a; if (i(this, e), this._state = "writable", this._storedError = void 0, this._writer = void 0, this._writableStreamController = void 0, this._writeRequests = [], this._inFlightWriteRequest = void 0, this._closeRequest = void 0, this._inFlightCloseRequest = void 0, this._pendingAbortRequest = void 0, this._backpressure = !1, void 0 !== t.type) throw new RangeError("Invalid type is specified"); this._writableStreamController = new N(this, t, n, o), this._writableStreamController.__startSteps() } return n(e, [{ key: "abort", value: function (e) { return !1 === _(this) ? Promise.reject(G("abort")) : !0 === A(this) ? Promise.reject(new TypeError("Cannot abort a stream that already has a writer")) : S(this, e) } }, { key: "getWriter", value: function () { if (!1 === _(this)) throw G("getWriter"); return b(this) } }, { key: "locked", get: function () { if (!1 === _(this)) throw G("locked"); return A(this) } }]), e }(); function b(e) { return new O(e) } function _(e) { return !!l(e) && !!Object.prototype.hasOwnProperty.call(e, "_writableStreamController") } function A(e) { return h(!0 === _(e), "IsWritableStreamLocked should only be used on known writable streams"), void 0 !== e._writer } function S(e, t) { var r = e._state; if ("closed" === r) return Promise.resolve(void 0); if ("errored" === r) return Promise.reject(e._storedError); var n = new TypeError("Requested to abort"); if (void 0 !== e._pendingAbortRequest) return Promise.reject(n); h("writable" === r || "erroring" === r, "state must be writable or erroring"); var i = !1; "erroring" === r && (i = !0, t = void 0); var a = new Promise(function (r, n) { e._pen!
 dingAbortRequest = { _resolve: r, _reject: n, _reason: t, _wasAlreadyErroring: i } }); return !1 === i && k(e, n), a } function w(e, t) { var r = e._state; "writable" !== r ? (h("erroring" === r), P(e)) : k(e, t) } function k(e, t) { h(void 0 === e._storedError, "stream._storedError === undefined"), h("writable" === e._state, "state must be writable"); var r = e._writableStreamController; h(void 0 !== r, "controller must not be undefined"), e._state = "erroring", e._storedError = t; var n = e._writer; void 0 !== n && j(n, t), !1 === R(e) && !0 === r._started && P(e) } function P(e) { h("erroring" === e._state, "stream._state === erroring"), h(!1 === R(e), "WritableStreamHasOperationMarkedInFlight(stream) === false"), e._state = "errored", e._writableStreamController.__errorSteps(); for (var t = e._storedError, r = 0; r < e._writeRequests.length; r++) { e._writeRequests[r]._reject(t) } if (e._writeRequests = [], void 0 !== e._pendingAbortRequest) { var n = e._pendingAbortRequest; if (e._pendingAbortRequest = void 0, !0 === n._wasAlreadyErroring) return n._reject(t), void E(e); e._writableStreamController.__abortSteps(n._reason).then(function () { n._resolve(), E(e) }, function (t) { n._reject(t), E(e) }) } else E(e) } function x(e) { h(void 0 !== e._inFlightCloseRequest), e._inFlightCloseRequest._resolve(void 0), e._inFlightCloseRequest = void 0; var t = e._state; h("writable" === t || "erroring" === t), "erroring" === t && (e._storedError = void 0, void 0 !== e._pendingAbortRequest && (e._pendingAbortRequest._resolve(), e._pendingAbortRequest = void 0)), e._state = "closed"; var r = e._writer; void 0 !== r && function (e) { h(void 0 !== e._closedPromise_resolve, "writer._closedPromise_resolve !== undefined"), h(void 0 !== e._closedPromise_reject, "writer._closedPromise_reject !== undefined"), h("pending" === e._closedPromiseState, "writer._closedPromiseState is pending"), e._closedPromise_resolve(void 0), e._closedPromise_resolve = void 0, e._closedPromise_reject = void 0, e._closedPromiseState = "resolved" }(r)!
 , h(void 0 === e._pendingAbortRequest, "stream._pendingAbortRequest === undefined"), h(void 0 === e._storedError, "stream._storedError === undefined") } function C(e) { return void 0 !== e._closeRequest || void 0 !== e._inFlightCloseRequest } function R(e) { return void 0 !== e._inFlightWriteRequest || void 0 !== e._inFlightCloseRequest } function E(e) { h("errored" === e._state, '_stream_.[[state]] is `"errored"`'), void 0 !== e._closeRequest && (h(void 0 === e._inFlightCloseRequest), e._closeRequest._reject(e._storedError), e._closeRequest = void 0); var t = e._writer; void 0 !== t && (V(t, e._storedError), t._closedPromise.catch(function () { })) } function T(e, t) { h("writable" === e._state), h(!1 === C(e)); var r = e._writer; void 0 !== r && t !== e._backpressure && (!0 === t ? function (e) { h(void 0 === e._readyPromise_resolve, "writer._readyPromise_resolve === undefined"), h(void 0 === e._readyPromise_reject, "writer._readyPromise_reject === undefined"), e._readyPromise = new Promise(function (t, r) { e._readyPromise_resolve = t, e._readyPromise_reject = r }), e._readyPromiseState = "pending" }(r) : (h(!1 === t), J(r))), e._backpressure = t } e.exports = { AcquireWritableStreamDefaultWriter: b, IsWritableStream: _, IsWritableStreamLocked: A, WritableStream: y, WritableStreamAbort: S, WritableStreamDefaultControllerError: z, WritableStreamDefaultWriterCloseWithErrorPropagation: function (e) { var t = e._ownerWritableStream; h(void 0 !== t); var r = t._state; if (!0 === C(t) || "closed" === r) return Promise.resolve(); if ("errored" === r) return Promise.reject(t._storedError); return h("writable" === r || "erroring" === r), F(e) }, WritableStreamDefaultWriterRelease: M, WritableStreamDefaultWriterWrite: D, WritableStreamCloseQueuedOrInFlight: C }; var O = function () { function e(t) { if (i(this, e), !1 === _(t)) throw new TypeError("WritableStreamDefaultWriter can only be constructed with a WritableStream instance"); if (!0 === A(t)) throw new TypeError("This stream has already been locked for exclusive!
  writing by another writer"); this._ownerWritableStream = t, t._writer = this; var r, n = t._state; if ("writable" === n) !1 === C(t) && !0 === t._backpressure ? ((r = this)._readyPromise = new Promise(function (e, t) { r._readyPromise_resolve = e, r._readyPromise_reject = t }), r._readyPromiseState = "pending") : K(this), Y(this); else if ("erroring" === n) Q(this, t._storedError), this._readyPromise.catch(function () { }), Y(this); else if ("closed" === n) K(this), function (e) { e._closedPromise = Promise.resolve(void 0), e._closedPromise_resolve = void 0, e._closedPromise_reject = void 0, e._closedPromiseState = "resolved" }(this); else { h("errored" === n, "state must be errored"); var a = t._storedError; Q(this, a), this._readyPromise.catch(function () { }), function (e, t) { e._closedPromise = Promise.reject(t), e._closedPromise_resolve = void 0, e._closedPromise_reject = void 0, e._closedPromiseState = "rejected" }(this, a), this._closedPromise.catch(function () { }) } } return n(e, [{ key: "abort", value: function (e) { return !1 === I(this) ? Promise.reject(H("abort")) : void 0 === this._ownerWritableStream ? Promise.reject(X("abort")) : function (e, t) { var r = e._ownerWritableStream; return h(void 0 !== r), S(r, t) }(this, e) } }, { key: "close", value: function () { if (!1 === I(this)) return Promise.reject(H("close")); var e = this._ownerWritableStream; return void 0 === e ? Promise.reject(X("close")) : !0 === C(e) ? Promise.reject(new TypeError("cannot close an already-closing stream")) : F(this) } }, { key: "releaseLock", value: function () { if (!1 === I(this)) throw H("releaseLock"); var e = this._ownerWritableStream; void 0 !== e && (h(void 0 !== e._writer), M(this)) } }, { key: "write", value: function (e) { return !1 === I(this) ? Promise.reject(H("write")) : void 0 === this._ownerWritableStream ? Promise.reject(X("write to")) : D(this, e) } }, { key: "closed", get: function () { return !1 === I(this) ? Promise.reject(H("closed")) : this._closedPromise } }, { key: "desiredSize", get: functi!
 on () { if (!1 === I(this)) throw H("desiredSize"); if (void 0 === this._ownerWritableStream) throw X("desiredSize"); return function (e) { var t = e._ownerWritableStream, r = t._state; if ("errored" === r || "erroring" === r) return null; if ("closed" === r) return 0; return q(t._writableStreamController) }(this) } }, { key: "ready", get: function () { return !1 === I(this) ? Promise.reject(H("ready")) : this._readyPromise } }]), e }(); function I(e) { return !!l(e) && !!Object.prototype.hasOwnProperty.call(e, "_ownerWritableStream") } function F(e) { var t = e._ownerWritableStream; h(void 0 !== t); var r = t._state; if ("closed" === r || "errored" === r) return Promise.reject(new TypeError("The stream (in " + r + " state) is not in the writable state and cannot be closed")); h("writable" === r || "erroring" === r), h(!1 === C(t)); var n, i = new Promise(function (e, r) { var n = { _resolve: e, _reject: r }; t._closeRequest = n }); return !0 === t._backpressure && "writable" === r && J(e), n = t._writableStreamController, v(n, "close", 0), W(n), i } function L(e, t) { "pending" === e._closedPromiseState ? V(e, t) : function (e, t) { h(void 0 === e._closedPromise_resolve, "writer._closedPromise_resolve === undefined"), h(void 0 === e._closedPromise_reject, "writer._closedPromise_reject === undefined"), h("pending" !== e._closedPromiseState, "writer._closedPromiseState is not pending"), e._closedPromise = Promise.reject(t), e._closedPromiseState = "rejected" }(e, t), e._closedPromise.catch(function () { }) } function j(e, t) { "pending" === e._readyPromiseState ? function (e, t) { h(void 0 !== e._readyPromise_resolve, "writer._readyPromise_resolve !== undefined"), h(void 0 !== e._readyPromise_reject, "writer._readyPromise_reject !== undefined"), e._readyPromise_reject(t), e._readyPromise_resolve = void 0, e._readyPromise_reject = void 0, e._readyPromiseState = "rejected" }(e, t) : function (e, t) { h(void 0 === e._readyPromise_resolve, "writer._readyPromise_resolve === undefined"), h(void 0 === e._readyPromise_re!
 ject, "writer._readyPromise_reject === undefined"), e._readyPromise = Promise.reject(t), e._readyPromiseState = "rejected" }(e, t), e._readyPromise.catch(function () { }) } function M(e) { var t = e._ownerWritableStream; h(void 0 !== t), h(t._writer === e); var r = new TypeError("Writer was released and can no longer be used to monitor the stream's closedness"); j(e, r), L(e, r), t._writer = void 0, e._ownerWritableStream = void 0 } function D(e, t) { var r = e._ownerWritableStream; h(void 0 !== r); var n = r._writableStreamController, i = function (e, t) { var r = e._strategySize; if (void 0 === r) return 1; try { return r(t) } catch (t) { return U(e, t), 1 } }(n, t); if (r !== e._ownerWritableStream) return Promise.reject(X("write to")); var a = r._state; if ("errored" === a) return Promise.reject(r._storedError); if (!0 === C(r) || "closed" === a) return Promise.reject(new TypeError("The stream is closing or closed and cannot be written to")); if ("erroring" === a) return Promise.reject(r._storedError); h("writable" === a); var o = function (e) { return h(!0 === A(e)), h("writable" === e._state), new Promise(function (t, r) { var n = { _resolve: t, _reject: r }; e._writeRequests.push(n) }) }(r); return function (e, t, r) { var n = { chunk: t }; try { v(e, n, r) } catch (t) { return void U(e, t) } var i = e._controlledWritableStream; if (!1 === C(i) && "writable" === i._state) { var a = B(e); T(i, a) } W(e) }(n, t, i), o } var N = function () { function e(t, r, n, a) { if (i(this, e), !1 === _(t)) throw new TypeError("WritableStreamDefaultController can only be constructed with a WritableStream instance"); if (void 0 !== t._writableStreamController) throw new TypeError("WritableStreamDefaultController instances can only be created by the WritableStream constructor"); this._controlledWritableStream = t, this._underlyingSink = r, this._queue = void 0, this._queueTotalSize = void 0, g(this), this._started = !1; var o = u(n, a); this._strategySize = o.size, this._strategyHWM = o.highWaterMark, T(t, B(this)) } retu!
 rn n(e, [{ key: "error", value: function (e) { if (!1 === function (e) { if (!l(e)) return !1; if (!Object.prototype.hasOwnProperty.call(e, "_underlyingSink")) return !1; return !0 }(this)) throw new TypeError("WritableStreamDefaultController.prototype.error can only be used on a WritableStreamDefaultController"); "writable" === this._controlledWritableStream._state && z(this, e) } }, { key: "__abortSteps", value: function (e) { return s(this._underlyingSink, "abort", [e]) } }, { key: "__errorSteps", value: function () { g(this) } }, { key: "__startSteps", value: function () { var e = this, t = o(this._underlyingSink, "start", [this]), r = this._controlledWritableStream; Promise.resolve(t).then(function () { h("writable" === r._state || "erroring" === r._state), e._started = !0, W(e) }, function (t) { h("writable" === r._state || "erroring" === r._state), e._started = !0, w(r, t) }).catch(d) } }]), e }(); function q(e) { return e._strategyHWM - e._queueTotalSize } function W(e) { var t = e._controlledWritableStream; if (!1 !== e._started && void 0 === t._inFlightWriteRequest) { var r = t._state; if ("closed" !== r && "errored" !== r) if ("erroring" !== r) { if (0 !== e._queue.length) { var n = m(e); "close" === n ? function (e) { var t = e._controlledWritableStream; (function (e) { h(void 0 === e._inFlightCloseRequest), h(void 0 !== e._closeRequest), e._inFlightCloseRequest = e._closeRequest, e._closeRequest = void 0 })(t), p(e), h(0 === e._queue.length, "queue must be empty once the final write record is dequeued"), s(e._underlyingSink, "close", []).then(function () { x(t) }, function (e) { !function (e, t) { h(void 0 !== e._inFlightCloseRequest), e._inFlightCloseRequest._reject(t), e._inFlightCloseRequest = void 0, h("writable" === e._state || "erroring" === e._state), void 0 !== e._pendingAbortRequest && (e._pendingAbortRequest._reject(t), e._pendingAbortRequest = void 0), w(e, t) }(t, e) }).catch(d) }(e) : function (e, t) { var r = e._controlledWritableStream; (function (e) { h(void 0 === e._inFlightWriteReq!
 uest, "there must be no pending write request"), h(0 !== e._writeRequests.length, "writeRequests must not be empty"), e._inFlightWriteRequest = e._writeRequests.shift() })(r), s(e._underlyingSink, "write", [t, e]).then(function () { !function (e) { h(void 0 !== e._inFlightWriteRequest), e._inFlightWriteRequest._resolve(void 0), e._inFlightWriteRequest = void 0 }(r); var t = r._state; if (h("writable" === t || "erroring" === t), p(e), !1 === C(r) && "writable" === t) { var n = B(e); T(r, n) } W(e) }, function (e) { !function (e, t) { h(void 0 !== e._inFlightWriteRequest), e._inFlightWriteRequest._reject(t), e._inFlightWriteRequest = void 0, h("writable" === e._state || "erroring" === e._state), w(e, t) }(r, e) }).catch(d) }(e, n.chunk) } } else P(t) } } function U(e, t) { "writable" === e._controlledWritableStream._state && z(e, t) } function B(e) { return q(e) <= 0 } function z(e, t) { var r = e._controlledWritableStream; h("writable" === r._state), k(r, t) } function G(e) { return new TypeError("WritableStream.prototype." + e + " can only be used on a WritableStream") } function H(e) { return new TypeError("WritableStreamDefaultWriter.prototype." + e + " can only be used on a WritableStreamDefaultWriter") } function X(e) { return new TypeError("Cannot " + e + " a stream using a released writer") } function Y(e) { e._closedPromise = new Promise(function (t, r) { e._closedPromise_resolve = t, e._closedPromise_reject = r, e._closedPromiseState = "pending" }) } function V(e, t) { h(void 0 !== e._closedPromise_resolve, "writer._closedPromise_resolve !== undefined"), h(void 0 !== e._closedPromise_reject, "writer._closedPromise_reject !== undefined"), h("pending" === e._closedPromiseState, "writer._closedPromiseState is pending"), e._closedPromise_reject(t), e._closedPromise_resolve = void 0, e._closedPromise_reject = void 0, e._closedPromiseState = "rejected" } function Q(e, t) { e._readyPromise = Promise.reject(t), e._readyPromise_resolve = void 0, e._readyPromise_reject = void 0, e._readyPromiseState = "rejected" }!
  function K(e) { e._readyPromise = Promise.resolve(void 0), e._readyPromise_resolve = void 0, e._readyPromise_reject = void 0, e._readyPromiseState = "fulfilled" } function J(e) { h(void 0 !== e._readyPromise_resolve, "writer._readyPromise_resolve !== undefined"), h(void 0 !== e._readyPromise_reject, "writer._readyPromise_reject !== undefined"), e._readyPromise_resolve(void 0), e._readyPromise_resolve = void 0, e._readyPromise_reject = void 0, e._readyPromiseState = "fulfilled" } }, function (e, t, r) { var n = r(0).IsFiniteNonNegativeNumber, i = r(1).assert; t.DequeueValue = function (e) { i("_queue" in e && "_queueTotalSize" in e, "Spec-level failure: DequeueValue should only be used on containers with [[queue]] and [[queueTotalSize]]."), i(e._queue.length > 0, "Spec-level failure: should never dequeue from an empty queue."); var t = e._queue.shift(); return e._queueTotalSize -= t.size, e._queueTotalSize < 0 && (e._queueTotalSize = 0), t.value }, t.EnqueueValueWithSize = function (e, t, r) { if (i("_queue" in e && "_queueTotalSize" in e, "Spec-level failure: EnqueueValueWithSize should only be used on containers with [[queue]] and [[queueTotalSize]]."), r = Number(r), !n(r)) throw new RangeError("Size must be a finite, non-NaN, non-negative number."); e._queue.push({ value: t, size: r }), e._queueTotalSize += r }, t.PeekQueueValue = function (e) { return i("_queue" in e && "_queueTotalSize" in e, "Spec-level failure: PeekQueueValue should only be used on containers with [[queue]] and [[queueTotalSize]]."), i(e._queue.length > 0, "Spec-level failure: should never peek at an empty queue."), e._queue[0].value }, t.ResetQueue = function (e) { i("_queue" in e && "_queueTotalSize" in e, "Spec-level failure: ResetQueue should only be used on containers with [[queue]] and [[queueTotalSize]]."), e._queue = [], e._queueTotalSize = 0 } }, function (e, t, r) { var n = function () { function e(e, t) { for (var r = 0; r < t.length; r++) { var n = t[r]; n.enumerable = n.enumerable || !1, n.configurable = !0, "value" in n && !
 (n.writable = !0), Object.defineProperty(e, n.key, n) } } return function (t, r, n) { return r && e(t.prototype, r), n && e(t, n), t } }(); function i(e, t) { if (!(e instanceof t)) throw new TypeError("Cannot call a class as a function") } var a = r(0), o = a.ArrayBufferCopy, s = a.CreateIterResultObject, u = a.IsFiniteNonNegativeNumber, l = a.InvokeOrNoop, c = a.PromiseInvokeOrNoop, h = a.TransferArrayBuffer, d = a.ValidateAndNormalizeQueuingStrategy, f = a.ValidateAndNormalizeHighWaterMark, p = r(0), v = p.createArrayFromList, m = p.createDataProperty, g = p.typeIsObject, y = r(1), b = y.assert, _ = y.rethrowAssertionErrorRejection, A = r(3), S = A.DequeueValue, w = A.EnqueueValueWithSize, k = A.ResetQueue, P = r(2), x = P.AcquireWritableStreamDefaultWriter, C = P.IsWritableStream, R = P.IsWritableStreamLocked, E = P.WritableStreamAbort, T = P.WritableStreamDefaultWriterCloseWithErrorPropagation, O = P.WritableStreamDefaultWriterRelease, I = P.WritableStreamDefaultWriterWrite, F = P.WritableStreamCloseQueuedOrInFlight, L = function () { function e() { var t = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {}, r = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : {}, n = r.size, a = r.highWaterMark; i(this, e), this._state = "readable", this._reader = void 0, this._storedError = void 0, this._disturbed = !1, this._readableStreamController = void 0; var o = t.type; if ("bytes" === String(o)) void 0 === a && (a = 0), this._readableStreamController = new de(this, t, a); else { if (void 0 !== o) throw new RangeError("Invalid type is specified"); void 0 === a && (a = 1), this._readableStreamController = new ne(this, t, n, a) } } return n(e, [{ key: "cancel", value: function (e) { return !1 === M(this) ? Promise.reject(Ee("cancel")) : !0 === D(this) ? Promise.reject(new TypeError("Cannot cancel a stream that already has a reader")) : U(this, e) } }, { key: "getReader", value: function () { var e = (arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {}).mode; if (!1 === !
 M(this)) throw Ee("getReader"); if (void 0 === e) return j(this); if ("byob" === (e = String(e))) return new K(this); throw new RangeError("Invalid mode is specified") } }, { key: "pipeThrough", value: function (e, t) { var r = e.writable, n = e.readable; return function (e) { try { Promise.prototype.then.call(e, void 0, function () { }) } catch (e) { } }(this.pipeTo(r, t)), n } }, { key: "pipeTo", value: function (e) { var t = this, r = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : {}, n = r.preventClose, i = r.preventAbort, a = r.preventCancel; if (!1 === M(this)) return Promise.reject(Ee("pipeTo")); if (!1 === C(e)) return Promise.reject(new TypeError("ReadableStream.prototype.pipeTo's first argument must be a WritableStream")); if (n = Boolean(n), i = Boolean(i), a = Boolean(a), !0 === D(this)) return Promise.reject(new TypeError("ReadableStream.prototype.pipeTo cannot be used on a locked ReadableStream")); if (!0 === R(e)) return Promise.reject(new TypeError("ReadableStream.prototype.pipeTo cannot be used on a locked WritableStream")); var o = j(this), s = x(e), u = !1, l = Promise.resolve(); return new Promise(function (r, c) { var h, d, f; if (m(t, o._closedPromise, function (t) { !1 === i ? g(function () { return E(e, t) }, !0, t) : y(!0, t) }), m(e, s._closedPromise, function (e) { !1 === a ? g(function () { return U(t, e) }, !0, e) : y(!0, e) }), h = t, d = o._closedPromise, f = function () { !1 === n ? g(function () { return T(s) }) : y() }, "closed" === h._state ? f() : d.then(f).catch(_), !0 === F(e) || "closed" === e._state) { var p = new TypeError("the destination writable stream closed before all data could be piped to it"); !1 === a ? g(function () { return U(t, p) }, !0, p) : y(!0, p) } function v() { var e = l; return l.then(function () { return e !== l ? v() : void 0 }) } function m(e, t, r) { "errored" === e._state ? r(e._storedError) : t.catch(r).catch(_) } function g(t, r, n) { function i() { t().then(function () { return b(r, n) }, function (e) { return b(!0, e) }).catc!
 h(_) } !0 !== u && (u = !0, "writable" === e._state && !1 === F(e) ? v().then(i) : i()) } function y(t, r) { !0 !== u && (u = !0, "writable" === e._state && !1 === F(e) ? v().then(function () { return b(t, r) }).catch(_) : b(t, r)) } function b(e, t) { O(s), te(o), e ? c(t) : r(void 0) } (function e() { return l = Promise.resolve(), !0 === u ? Promise.resolve() : s._readyPromise.then(function () { return re(o).then(function (e) { var t = e.value; !0 !== e.done && (l = I(s, t).catch(function () { })) }) }).then(e) })().catch(function (e) { l = Promise.resolve(), _(e) }) }) } }, { key: "tee", value: function () { if (!1 === M(this)) throw Ee("tee"); var e = N(this, !1); return v(e) } }, { key: "locked", get: function () { if (!1 === M(this)) throw Ee("locked"); return D(this) } }]), e }(); function j(e) { return new Q(e) } function M(e) { return !!g(e) && !!Object.prototype.hasOwnProperty.call(e, "_readableStreamController") } function D(e) { return b(!0 === M(e), "IsReadableStreamLocked should only be used on known readable streams"), void 0 !== e._reader } function N(e, t) { b(!0 === M(e)), b("boolean" == typeof t); var r = j(e), n = { closedOrErrored: !1, canceled1: !1, canceled2: !1, reason1: void 0, reason2: void 0 }; n.promise = new Promise(function (e) { n._resolve = e }); var i = function () { return function e() { var t = e._reader, r = e._branch1, n = e._branch2, i = e._teeState; return re(t).then(function (e) { b(g(e)); var t = e.value, a = e.done; if (b("boolean" == typeof a), !0 === a && !1 === i.closedOrErrored && (!1 === i.canceled1 && oe(r), !1 === i.canceled2 && oe(n), i.closedOrErrored = !0), !0 !== i.closedOrErrored) { var o = t, s = t; !1 === i.canceled1 && se(r, o), !1 === i.canceled2 && se(n, s) } }) } }(); i._reader = r, i._teeState = n, i._cloneForBranch2 = t; var a = function () { return function e(t) { var r = e._stream, n = e._teeState; n.canceled1 = !0; n.reason1 = t; if (!0 === n.canceled2) { var i = v([n.reason1, n.reason2]), a = U(r, i); n._resolve(a) } return n.promise } }(); a._str!
 eam = e, a._teeState = n; var o = function () { return function e(t) { var r = e._stream, n = e._teeState; n.canceled2 = !0; n.reason2 = t; if (!0 === n.canceled1) { var i = v([n.reason1, n.reason2]), a = U(r, i); n._resolve(a) } return n.promise } }(); o._stream = e, o._teeState = n; var s = Object.create(Object.prototype); m(s, "pull", i), m(s, "cancel", a); var u = new L(s), l = Object.create(Object.prototype); m(l, "pull", i), m(l, "cancel", o); var c = new L(l); return i._branch1 = u._readableStreamController, i._branch2 = c._readableStreamController, r._closedPromise.catch(function (e) { !0 !== n.closedOrErrored && (ue(i._branch1, e), ue(i._branch2, e), n.closedOrErrored = !0) }), [u, c] } function q(e) { return b(!0 === J(e._reader)), b("readable" === e._state || "closed" === e._state), new Promise(function (t, r) { var n = { _resolve: t, _reject: r }; e._reader._readIntoRequests.push(n) }) } function W(e) { return b(!0 === Z(e._reader)), b("readable" === e._state), new Promise(function (t, r) { var n = { _resolve: t, _reject: r }; e._reader._readRequests.push(n) }) } function U(e, t) { return e._disturbed = !0, "closed" === e._state ? Promise.resolve(void 0) : "errored" === e._state ? Promise.reject(e._storedError) : (B(e), e._readableStreamController.__cancelSteps(t).then(function () { })) } function B(e) { b("readable" === e._state), e._state = "closed"; var t = e._reader; if (void 0 !== t) { if (!0 === Z(t)) { for (var r = 0; r < t._readRequests.length; r++) { (0, t._readRequests[r]._resolve)(s(void 0, !0)) } t._readRequests = [] } !function (e) { b(void 0 !== e._closedPromise_resolve), b(void 0 !== e._closedPromise_reject), e._closedPromise_resolve(void 0), e._closedPromise_resolve = void 0, e._closedPromise_reject = void 0 }(t) } } function z(e, t) { b(!0 === M(e), "stream must be ReadableStream"), b("readable" === e._state, "state must be readable"), e._state = "errored", e._storedError = t; var r = e._reader; if (void 0 !== r) { if (!0 === Z(r)) { for (var n = 0; n < r._readRequests.length; n++) {!
  r._readRequests[n]._reject(t) } r._readRequests = [] } else { b(J(r), "reader must be ReadableStreamBYOBReader"); for (var i = 0; i < r._readIntoRequests.length; i++) { r._readIntoRequests[i]._reject(t) } r._readIntoRequests = [] } Ie(r, t), r._closedPromise.catch(function () { }) } } function G(e, t, r) { var n = e._reader; b(n._readRequests.length > 0), n._readRequests.shift()._resolve(s(t, r)) } function H(e) { return e._reader._readIntoRequests.length } function X(e) { return e._reader._readRequests.length } function Y(e) { var t = e._reader; return void 0 !== t && !1 !== J(t) } function V(e) { var t = e._reader; return void 0 !== t && !1 !== Z(t) } e.exports = { ReadableStream: L, IsReadableStreamDisturbed: function (e) { return b(!0 === M(e), "IsReadableStreamDisturbed should only be used on known readable streams"), e._disturbed }, ReadableStreamDefaultControllerClose: oe, ReadableStreamDefaultControllerEnqueue: se, ReadableStreamDefaultControllerError: ue, ReadableStreamDefaultControllerGetDesiredSize: ce }; var Q = function () { function e(t) { if (i(this, e), !1 === M(t)) throw new TypeError("ReadableStreamDefaultReader can only be constructed with a ReadableStream instance"); if (!0 === D(t)) throw new TypeError("This stream has already been locked for exclusive reading by another reader"); $(this, t), this._readRequests = [] } return n(e, [{ key: "cancel", value: function (e) { return !1 === Z(this) ? Promise.reject(Oe("cancel")) : void 0 === this._ownerReadableStream ? Promise.reject(Te("cancel")) : ee(this, e) } }, { key: "read", value: function () { return !1 === Z(this) ? Promise.reject(Oe("read")) : void 0 === this._ownerReadableStream ? Promise.reject(Te("read from")) : re(this) } }, { key: "releaseLock", value: function () { if (!1 === Z(this)) throw Oe("releaseLock"); if (void 0 !== this._ownerReadableStream) { if (this._readRequests.length > 0) throw new TypeError("Tried to release a reader lock when that reader has pending read() calls un-settled"); te(this) } } }, { key: "closed", get: fu!
 nction () { return !1 === Z(this) ? Promise.reject(Oe("closed")) : this._closedPromise } }]), e }(), K = function () { function e(t) { if (i(this, e), !M(t)) throw new TypeError("ReadableStreamBYOBReader can only be constructed with a ReadableStream instance given a byte source"); if (!1 === fe(t._readableStreamController)) throw new TypeError("Cannot construct a ReadableStreamBYOBReader for a stream not constructed with a byte source"); if (D(t)) throw new TypeError("This stream has already been locked for exclusive reading by another reader"); $(this, t), this._readIntoRequests = [] } return n(e, [{ key: "cancel", value: function (e) { return J(this) ? void 0 === this._ownerReadableStream ? Promise.reject(Te("cancel")) : ee(this, e) : Promise.reject(Fe("cancel")) } }, { key: "read", value: function (e) { return J(this) ? void 0 === this._ownerReadableStream ? Promise.reject(Te("read from")) : ArrayBuffer.isView(e) ? 0 === e.byteLength ? Promise.reject(new TypeError("view must have non-zero byteLength")) : function (e, t) { var r = e._ownerReadableStream; if (b(void 0 !== r), r._disturbed = !0, "errored" === r._state) return Promise.reject(r._storedError); return function (e, t) { var r = e._controlledReadableStream, n = 1; t.constructor !== DataView && (n = t.constructor.BYTES_PER_ELEMENT); var i = t.constructor, a = { buffer: t.buffer, byteOffset: t.byteOffset, byteLength: t.byteLength, bytesFilled: 0, elementSize: n, ctor: i, readerType: "byob" }; if (e._pendingPullIntos.length > 0) return a.buffer = h(a.buffer), e._pendingPullIntos.push(a), q(r); if ("closed" === r._state) { var o = new t.constructor(a.buffer, a.byteOffset, 0); return Promise.resolve(s(o, !0)) } if (e._queueTotalSize > 0) { if (!0 === _e(e, a)) { var u = ye(a); return Se(e), Promise.resolve(s(u, !1)) } if (!0 === e._closeRequested) { var l = new TypeError("Insufficient bytes to fill elements in the given buffer"); return Ce(e, l), Promise.reject(l) } } a.buffer = h(a.buffer), e._pendingPullIntos.push(a); var c = q(r); return ve(e), c }(r._r!
 eadableStreamController, t) }(this, e) : Promise.reject(new TypeError("view must be an array buffer view")) : Promise.reject(Fe("read")) } }, { key: "releaseLock", value: function () { if (!J(this)) throw Fe("releaseLock"); if (void 0 !== this._ownerReadableStream) { if (this._readIntoRequests.length > 0) throw new TypeError("Tried to release a reader lock when that reader has pending read() calls un-settled"); te(this) } } }, { key: "closed", get: function () { return J(this) ? this._closedPromise : Promise.reject(Fe("closed")) } }]), e }(); function J(e) { return !!g(e) && !!Object.prototype.hasOwnProperty.call(e, "_readIntoRequests") } function Z(e) { return !!g(e) && !!Object.prototype.hasOwnProperty.call(e, "_readRequests") } function $(e, t) { e._ownerReadableStream = t, t._reader = e, "readable" === t._state ? function (e) { e._closedPromise = new Promise(function (t, r) { e._closedPromise_resolve = t, e._closedPromise_reject = r }) }(e) : "closed" === t._state ? function (e) { e._closedPromise = Promise.resolve(void 0), e._closedPromise_resolve = void 0, e._closedPromise_reject = void 0 }(e) : (b("errored" === t._state, "state must be errored"), function (e, t) { e._closedPromise = Promise.reject(t), e._closedPromise_resolve = void 0, e._closedPromise_reject = void 0 }(e, t._storedError), e._closedPromise.catch(function () { })) } function ee(e, t) { var r = e._ownerReadableStream; return b(void 0 !== r), U(r, t) } function te(e) { b(void 0 !== e._ownerReadableStream), b(e._ownerReadableStream._reader === e), "readable" === e._ownerReadableStream._state ? Ie(e, new TypeError("Reader was released and can no longer be used to monitor the stream's closedness")) : function (e, t) { b(void 0 === e._closedPromise_resolve), b(void 0 === e._closedPromise_reject), e._closedPromise = Promise.reject(t) }(e, new TypeError("Reader was released and can no longer be used to monitor the stream's closedness")), e._closedPromise.catch(function () { }), e._ownerReadableStream._reader = void 0, e._ownerReadableStream = void!
  0 } function re(e) { var t = e._ownerReadableStream; return b(void 0 !== t), t._disturbed = !0, "closed" === t._state ? Promise.resolve(s(void 0, !0)) : "errored" === t._state ? Promise.reject(t._storedError) : (b("readable" === t._state), t._readableStreamController.__pullSteps()) } var ne = function () { function e(t, r, n, a) { if (i(this, e), !1 === M(t)) throw new TypeError("ReadableStreamDefaultController can only be constructed with a ReadableStream instance"); if (void 0 !== t._readableStreamController) throw new TypeError("ReadableStreamDefaultController instances can only be created by the ReadableStream constructor"); this._controlledReadableStream = t, this._underlyingSource = r, this._queue = void 0, this._queueTotalSize = void 0, k(this), this._started = !1, this._closeRequested = !1, this._pullAgain = !1, this._pulling = !1; var o = d(n, a); this._strategySize = o.size, this._strategyHWM = o.highWaterMark; var s = this, u = l(r, "start", [this]); Promise.resolve(u).then(function () { s._started = !0, b(!1 === s._pulling), b(!1 === s._pullAgain), ae(s) }, function (e) { le(s, e) }).catch(_) } return n(e, [{ key: "close", value: function () { if (!1 === ie(this)) throw Le("close"); if (!0 === this._closeRequested) throw new TypeError("The stream has already been closed; do not close it again!"); var e = this._controlledReadableStream._state; if ("readable" !== e) throw new TypeError("The stream (in " + e + " state) is not in the readable state and cannot be closed"); oe(this) } }, { key: "enqueue", value: function (e) { if (!1 === ie(this)) throw Le("enqueue"); if (!0 === this._closeRequested) throw new TypeError("stream is closed or draining"); var t = this._controlledReadableStream._state; if ("readable" !== t) throw new TypeError("The stream (in " + t + " state) is not in the readable state and cannot be enqueued to"); return se(this, e) } }, { key: "error", value: function (e) { if (!1 === ie(this)) throw Le("error"); var t = this._controlledReadableStream; if ("readable" !== t._state) throw ne!
 w TypeError("The stream is " + t._state + " and so cannot be errored"); ue(this, e) } }, { key: "__cancelSteps", value: function (e) { return k(this), c(this._underlyingSource, "cancel", [e]) } }, { key: "__pullSteps", value: function () { var e = this._controlledReadableStream; if (this._queue.length > 0) { var t = S(this); return !0 === this._closeRequested && 0 === this._queue.length ? B(e) : ae(this), Promise.resolve(s(t, !1)) } var r = W(e); return ae(this), r } }, { key: "desiredSize", get: function () { if (!1 === ie(this)) throw Le("desiredSize"); return ce(this) } }]), e }(); function ie(e) { return !!g(e) && !!Object.prototype.hasOwnProperty.call(e, "_underlyingSource") } function ae(e) { !1 !== function (e) { var t = e._controlledReadableStream; if ("closed" === t._state || "errored" === t._state) return !1; if (!0 === e._closeRequested) return !1; if (!1 === e._started) return !1; if (!0 === D(t) && X(t) > 0) return !0; if (ce(e) > 0) return !0; return !1 }(e) && (!0 !== e._pulling ? (b(!1 === e._pullAgain), e._pulling = !0, c(e._underlyingSource, "pull", [e]).then(function () { if (e._pulling = !1, !0 === e._pullAgain) return e._pullAgain = !1, ae(e) }, function (t) { le(e, t) }).catch(_)) : e._pullAgain = !0) } function oe(e) { var t = e._controlledReadableStream; b(!1 === e._closeRequested), b("readable" === t._state), e._closeRequested = !0, 0 === e._queue.length && B(t) } function se(e, t) { var r = e._controlledReadableStream; if (b(!1 === e._closeRequested), b("readable" === r._state), !0 === D(r) && X(r) > 0) G(r, t, !1); else { var n = 1; if (void 0 !== e._strategySize) { var i = e._strategySize; try { n = i(t) } catch (t) { throw le(e, t), t } } try { w(e, t, n) } catch (t) { throw le(e, t), t } } ae(e) } function ue(e, t) { var r = e._controlledReadableStream; b("readable" === r._state), k(e), z(r, t) } function le(e, t) { "readable" === e._controlledReadableStream._state && ue(e, t) } function ce(e) { var t = e._controlledReadableStream._state; return "errored" === t ? null : "closed" ===!
  t ? 0 : e._strategyHWM - e._queueTotalSize } var he = function () { function e(t, r) { i(this, e), this._associatedReadableByteStreamController = t, this._view = r } return n(e, [{ key: "respond", value: function (e) { if (!1 === pe(this)) throw je("respond"); if (void 0 === this._associatedReadableByteStreamController) throw new TypeError("This BYOB request has been invalidated"); !function (e, t) { if (t = Number(t), !1 === u(t)) throw new RangeError("bytesWritten must be a finite"); b(e._pendingPullIntos.length > 0), Pe(e, t) }(this._associatedReadableByteStreamController, e) } }, { key: "respondWithNewView", value: function (e) { if (!1 === pe(this)) throw je("respond"); if (void 0 === this._associatedReadableByteStreamController) throw new TypeError("This BYOB request has been invalidated"); if (!ArrayBuffer.isView(e)) throw new TypeError("You can only respond with array buffer views"); !function (e, t) { b(e._pendingPullIntos.length > 0); var r = e._pendingPullIntos[0]; if (r.byteOffset + r.bytesFilled !== t.byteOffset) throw new RangeError("The region specified by view does not match byobRequest"); if (r.byteLength !== t.byteLength) throw new RangeError("The buffer of view has different capacity than byobRequest"); r.buffer = t.buffer, Pe(e, t.byteLength) }(this._associatedReadableByteStreamController, e) } }, { key: "view", get: function () { return this._view } }]), e }(), de = function () { function e(t, r, n) { if (i(this, e), !1 === M(t)) throw new TypeError("ReadableByteStreamController can only be constructed with a ReadableStream instance given a byte source"); if (void 0 !== t._readableStreamController) throw new TypeError("ReadableByteStreamController instances can only be created by the ReadableStream constructor given a byte source"); this._controlledReadableStream = t, this._underlyingByteSource = r, this._pullAgain = !1, this._pulling = !1, me(this), this._queue = this._queueTotalSize = void 0, k(this), this._closeRequested = !1, this._started = !1, this._strategyHWM = f(n); var a = r.autoA!
 llocateChunkSize; if (void 0 !== a && (!1 === Number.isInteger(a) || a <= 0)) throw new RangeError("autoAllocateChunkSize must be a positive integer"); this._autoAllocateChunkSize = a, this._pendingPullIntos = []; var o = this, s = l(r, "start", [this]); Promise.resolve(s).then(function () { o._started = !0, b(!1 === o._pulling), b(!1 === o._pullAgain), ve(o) }, function (e) { "readable" === t._state && Ce(o, e) }).catch(_) } return n(e, [{ key: "close", value: function () { if (!1 === fe(this)) throw Me("close"); if (!0 === this._closeRequested) throw new TypeError("The stream has already been closed; do not close it again!"); var e = this._controlledReadableStream._state; if ("readable" !== e) throw new TypeError("The stream (in " + e + " state) is not in the readable state and cannot be closed"); !function (e) { var t = e._controlledReadableStream; if (b(!1 === e._closeRequested), b("readable" === t._state), e._queueTotalSize > 0) return void (e._closeRequested = !0); if (e._pendingPullIntos.length > 0) { var r = e._pendingPullIntos[0]; if (r.bytesFilled > 0) { var n = new TypeError("Insufficient bytes to fill elements in the given buffer"); throw Ce(e, n), n } } B(t) }(this) } }, { key: "enqueue", value: function (e) { if (!1 === fe(this)) throw Me("enqueue"); if (!0 === this._closeRequested) throw new TypeError("stream is closed or draining"); var t = this._controlledReadableStream._state; if ("readable" !== t) throw new TypeError("The stream (in " + t + " state) is not in the readable state and cannot be enqueued to"); if (!ArrayBuffer.isView(e)) throw new TypeError("You can only enqueue array buffer views when using a ReadableByteStreamController"); !function (e, t) { var r = e._controlledReadableStream; b(!1 === e._closeRequested), b("readable" === r._state); var n = t.buffer, i = t.byteOffset, a = t.byteLength, o = h(n); if (!0 === V(r)) if (0 === X(r)) be(e, o, i, a); else { b(0 === e._queue.length); var s = new Uint8Array(o, i, a); G(r, s, !1) } else !0 === Y(r) ? (be(e, o, i, a), ke(e)) : (b(!1 === D!
 (r), "stream must not be locked"), be(e, o, i, a)) }(this, e) } }, { key: "error", value: function (e) { if (!1 === fe(this)) throw Me("error"); var t = this._controlledReadableStream; if ("readable" !== t._state) throw new TypeError("The stream is " + t._state + " and so cannot be errored"); Ce(this, e) } }, { key: "__cancelSteps", value: function (e) { this._pendingPullIntos.length > 0 && (this._pendingPullIntos[0].bytesFilled = 0); return k(this), c(this._underlyingByteSource, "cancel", [e]) } }, { key: "__pullSteps", value: function () { var e = this._controlledReadableStream; if (b(!0 === V(e)), this._queueTotalSize > 0) { b(0 === X(e)); var t = this._queue.shift(); this._queueTotalSize -= t.byteLength, Se(this); var r = void 0; try { r = new Uint8Array(t.buffer, t.byteOffset, t.byteLength) } catch (e) { return Promise.reject(e) } return Promise.resolve(s(r, !1)) } var n = this._autoAllocateChunkSize; if (void 0 !== n) { var i = void 0; try { i = new ArrayBuffer(n) } catch (e) { return Promise.reject(e) } var a = { buffer: i, byteOffset: 0, byteLength: n, bytesFilled: 0, elementSize: 1, ctor: Uint8Array, readerType: "default" }; this._pendingPullIntos.push(a) } var o = W(e); return ve(this), o } }, { key: "byobRequest", get: function () { if (!1 === fe(this)) throw Me("byobRequest"); if (void 0 === this._byobRequest && this._pendingPullIntos.length > 0) { var e = this._pendingPullIntos[0], t = new Uint8Array(e.buffer, e.byteOffset + e.bytesFilled, e.byteLength - e.bytesFilled); this._byobRequest = new he(this, t) } return this._byobRequest } }, { key: "desiredSize", get: function () { if (!1 === fe(this)) throw Me("desiredSize"); return Re(this) } }]), e }(); function fe(e) { return !!g(e) && !!Object.prototype.hasOwnProperty.call(e, "_underlyingByteSource") } function pe(e) { return !!g(e) && !!Object.prototype.hasOwnProperty.call(e, "_associatedReadableByteStreamController") } function ve(e) { !1 !== function (e) { var t = e._controlledReadableStream; if ("readable" !== t._state) return !1; if (!0 === e._!
 closeRequested) return !1; if (!1 === e._started) return !1; if (!0 === V(t) && X(t) > 0) return !0; if (!0 === Y(t) && H(t) > 0) return !0; if (Re(e) > 0) return !0; return !1 }(e) && (!0 !== e._pulling ? (b(!1 === e._pullAgain), e._pulling = !0, c(e._underlyingByteSource, "pull", [e]).then(function () { e._pulling = !1, !0 === e._pullAgain && (e._pullAgain = !1, ve(e)) }, function (t) { "readable" === e._controlledReadableStream._state && Ce(e, t) }).catch(_)) : e._pullAgain = !0) } function me(e) { we(e), e._pendingPullIntos = [] } function ge(e, t) { b("errored" !== e._state, "state must not be errored"); var r = !1; "closed" === e._state && (b(0 === t.bytesFilled), r = !0); var n = ye(t); "default" === t.readerType ? G(e, n, r) : (b("byob" === t.readerType), function (e, t, r) { var n = e._reader; b(n._readIntoRequests.length > 0), n._readIntoRequests.shift()._resolve(s(t, r)) }(e, n, r)) } function ye(e) { var t = e.bytesFilled, r = e.elementSize; return b(t <= e.byteLength), b(t % r == 0), new e.ctor(e.buffer, e.byteOffset, t / r) } function be(e, t, r, n) { e._queue.push({ buffer: t, byteOffset: r, byteLength: n }), e._queueTotalSize += n } function _e(e, t) { var r = t.elementSize, n = t.bytesFilled - t.bytesFilled % r, i = Math.min(e._queueTotalSize, t.byteLength - t.bytesFilled), a = t.bytesFilled + i, s = a - a % r, u = i, l = !1; s > n && (u = s - t.bytesFilled, l = !0); for (var c = e._queue; u > 0;) { var h = c[0], d = Math.min(u, h.byteLength), f = t.byteOffset + t.bytesFilled; o(t.buffer, f, h.buffer, h.byteOffset, d), h.byteLength === d ? c.shift() : (h.byteOffset += d, h.byteLength -= d), e._queueTotalSize -= d, Ae(e, d, t), u -= d } return !1 === l && (b(0 === e._queueTotalSize, "queue must be empty"), b(t.bytesFilled > 0), b(t.bytesFilled < t.elementSize)), l } function Ae(e, t, r) { b(0 === e._pendingPullIntos.length || e._pendingPullIntos[0] === r), we(e), r.bytesFilled += t } function Se(e) { b("readable" === e._controlledReadableStream._state), 0 === e._queueTotalSize && !0 === e._closeR!
 equested ? B(e._controlledReadableStream) : ve(e) } function we(e) { void 0 !== e._byobRequest && (e._byobRequest._associatedReadableByteStreamController = void 0, e._byobRequest._view = void 0, e._byobRequest = void 0) } function ke(e) { for (b(!1 === e._closeRequested); e._pendingPullIntos.length > 0;) { if (0 === e._queueTotalSize) return; var t = e._pendingPullIntos[0]; !0 === _e(e, t) && (xe(e), ge(e._controlledReadableStream, t)) } } function Pe(e, t) { var r = e._pendingPullIntos[0], n = e._controlledReadableStream; if ("closed" === n._state) { if (0 !== t) throw new TypeError("bytesWritten must be 0 when calling respond() on a closed stream"); !function (e, t) { t.buffer = h(t.buffer), b(0 === t.bytesFilled, "bytesFilled must be 0"); var r = e._controlledReadableStream; if (!0 === Y(r)) for (; H(r) > 0;)ge(r, xe(e)) }(e, r) } else b("readable" === n._state), function (e, t, r) { if (r.bytesFilled + t > r.byteLength) throw new RangeError("bytesWritten out of range"); if (Ae(e, t, r), !(r.bytesFilled < r.elementSize)) { xe(e); var n = r.bytesFilled % r.elementSize; if (n > 0) { var i = r.byteOffset + r.bytesFilled, a = r.buffer.slice(i - n, i); be(e, a, 0, a.byteLength) } r.buffer = h(r.buffer), r.bytesFilled -= n, ge(e._controlledReadableStream, r), ke(e) } }(e, t, r) } function xe(e) { var t = e._pendingPullIntos.shift(); return we(e), t } function Ce(e, t) { var r = e._controlledReadableStream; b("readable" === r._state), me(e), k(e), z(r, t) } function Re(e) { var t = e._controlledReadableStream._state; return "errored" === t ? null : "closed" === t ? 0 : e._strategyHWM - e._queueTotalSize } function Ee(e) { return new TypeError("ReadableStream.prototype." + e + " can only be used on a ReadableStream") } function Te(e) { return new TypeError("Cannot " + e + " a stream using a released reader") } function Oe(e) { return new TypeError("ReadableStreamDefaultReader.prototype." + e + " can only be used on a ReadableStreamDefaultReader") } function Ie(e, t) { b(void 0 !== e._closedPromise_resolve), b(void 0 !
 !== e._closedPromise_reject), e._closedPromise_reject(t), e._closedPromise_resolve = void 0, e._closedPromise_reject = void 0 } function Fe(e) { return new TypeError("ReadableStreamBYOBReader.prototype." + e + " can only be used on a ReadableStreamBYOBReader") } function Le(e) { return new TypeError("ReadableStreamDefaultController.prototype." + e + " can only be used on a ReadableStreamDefaultController") } function je(e) { return new TypeError("ReadableStreamBYOBRequest.prototype." + e + " can only be used on a ReadableStreamBYOBRequest") } function Me(e) { return new TypeError("ReadableByteStreamController.prototype." + e + " can only be used on a ReadableByteStreamController") } }, function (e, t, r) { var n = r(6), i = r(4), a = r(2); t.TransformStream = n.TransformStream, t.ReadableStream = i.ReadableStream, t.IsReadableStreamDisturbed = i.IsReadableStreamDisturbed, t.ReadableStreamDefaultControllerClose = i.ReadableStreamDefaultControllerClose, t.ReadableStreamDefaultControllerEnqueue = i.ReadableStreamDefaultControllerEnqueue, t.ReadableStreamDefaultControllerError = i.ReadableStreamDefaultControllerError, t.ReadableStreamDefaultControllerGetDesiredSize = i.ReadableStreamDefaultControllerGetDesiredSize, t.AcquireWritableStreamDefaultWriter = a.AcquireWritableStreamDefaultWriter, t.IsWritableStream = a.IsWritableStream, t.IsWritableStreamLocked = a.IsWritableStreamLocked, t.WritableStream = a.WritableStream, t.WritableStreamAbort = a.WritableStreamAbort, t.WritableStreamDefaultControllerError = a.WritableStreamDefaultControllerError, t.WritableStreamDefaultWriterCloseWithErrorPropagation = a.WritableStreamDefaultWriterCloseWithErrorPropagation, t.WritableStreamDefaultWriterRelease = a.WritableStreamDefaultWriterRelease, t.WritableStreamDefaultWriterWrite = a.WritableStreamDefaultWriterWrite }, function (e, t, r) { var n = function () { function e(e, t) { for (var r = 0; r < t.length; r++) { var n = t[r]; n.enumerable = n.enumerable || !1, n.configurable = !0, "value" in n && (n.writable = !0), Object.defi!
 neProperty(e, n.key, n) } } return function (t, r, n) { return r && e(t.prototype, r), n && e(t, n), t } }(); function i(e, t) { if (!(e instanceof t)) throw new TypeError("Cannot call a class as a function") } var a = r(1).assert, o = r(0), s = o.InvokeOrNoop, u = o.PromiseInvokeOrPerformFallback, l = o.PromiseInvokeOrNoop, c = o.typeIsObject, h = r(4), d = h.ReadableStream, f = h.ReadableStreamDefaultControllerClose, p = h.ReadableStreamDefaultControllerEnqueue, v = h.ReadableStreamDefaultControllerError, m = h.ReadableStreamDefaultControllerGetDesiredSize, g = r(2), y = g.WritableStream, b = g.WritableStreamDefaultControllerError; function _(e, t) { if (!0 === e._errored) throw new TypeError("TransformStream is already errored"); if (!0 === e._readableClosed) throw new TypeError("Readable side is already closed"); var r = e._readableController; try { p(r, t) } catch (t) { throw e._readableClosed = !0, S(e, t), e._storedError } !0 === m(r) <= 0 && !1 === e._backpressure && P(e, !0) } function A(e) { a(!1 === e._errored), a(!1 === e._readableClosed); try { f(e._readableController) } catch (e) { a(!1) } e._readableClosed = !0 } function S(e, t) { !1 === e._errored && w(e, t) } function w(e, t) { a(!1 === e._errored), e._errored = !0, e._storedError = t, !1 === e._writableDone && b(e._writableController, t), !1 === e._readableClosed && v(e._readableController, t) } function k(e) { return a(void 0 !== e._backpressureChangePromise, "_backpressureChangePromise should have been initialized"), !1 === e._backpressure ? Promise.resolve() : (a(!0 === e._backpressure, "_backpressure should have been initialized"), e._backpressureChangePromise) } function P(e, t) { a(e._backpressure !== t, "TransformStreamSetBackpressure() should be called only when backpressure is changed"), void 0 !== e._backpressureChangePromise && e._backpressureChangePromise_resolve(t), e._backpressureChangePromise = new Promise(function (t) { e._backpressureChangePromise_resolve = t }), e._backpressureChangePromise.then(function (e) { a(e !== t, "_ba!
 ckpressureChangePromise should be fulfilled only when backpressure is changed") }), e._backpressure = t } function x(e, t) { return _(t._controlledTransformStream, e), Promise.resolve() } function C(e) { return !!c(e) && !!Object.prototype.hasOwnProperty.call(e, "_controlledTransformStream") } function R(e) { return !!c(e) && !!Object.prototype.hasOwnProperty.call(e, "_transformStreamController") } var E = function () { function e(t, r) { i(this, e), this._transformStream = t, this._startPromise = r } return n(e, [{ key: "start", value: function (e) { var t = this._transformStream; return t._writableController = e, this._startPromise.then(function () { return k(t) }) } }, { key: "write", value: function (e) { return function (e, t) { a(!1 === e._errored), a(!1 === e._transforming), a(!1 === e._backpressure), e._transforming = !0; var r = e._transformer, n = e._transformStreamController; return u(r, "transform", [t, n], x, [t, n]).then(function () { return e._transforming = !1, k(e) }, function (t) { return S(e, t), Promise.reject(t) }) }(this._transformStream, e) } }, { key: "abort", value: function () { var e = this._transformStream; e._writableDone = !0, w(e, new TypeError("Writable side aborted")) } }, { key: "close", value: function () { var e = this._transformStream; return a(!1 === e._transforming), e._writableDone = !0, l(e._transformer, "flush", [e._transformStreamController]).then(function () { return !0 === e._errored ? Promise.reject(e._storedError) : (!1 === e._readableClosed && A(e), Promise.resolve()) }).catch(function (t) { return S(e, t), Promise.reject(e._storedError) }) } }]), e }(), T = function () { function e(t, r) { i(this, e), this._transformStream = t, this._startPromise = r } return n(e, [{ key: "start", value: function (e) { var t = this._transformStream; return t._readableController = e, this._startPromise.then(function () { return a(void 0 !== t._backpressureChangePromise, "_backpressureChangePromise should have been initialized"), !0 === t._backpressure ? Promise.resolve() : (a(!1 ==!
 = t._backpressure, "_backpressure should have been initialized"), t._backpressureChangePromise) }) } }, { key: "pull", value: function () { var e = this._transformStream; return a(!0 === e._backpressure, "pull() should be never called while _backpressure is false"), a(void 0 !== e._backpressureChangePromise, "_backpressureChangePromise should have been initialized"), P(e, !1), e._backpressureChangePromise } }, { key: "cancel", value: function () { var e = this._transformStream; e._readableClosed = !0, w(e, new TypeError("Readable side canceled")) } }]), e }(), O = function () { function e(t) { if (i(this, e), !1 === R(t)) throw new TypeError("TransformStreamDefaultController can only be constructed with a TransformStream instance"); if (void 0 !== t._transformStreamController) throw new TypeError("TransformStreamDefaultController instances can only be created by the TransformStream constructor"); this._controlledTransformStream = t } return n(e, [{ key: "enqueue", value: function (e) { if (!1 === C(this)) throw F("enqueue"); _(this._controlledTransformStream, e) } }, { key: "close", value: function () { if (!1 === C(this)) throw F("close"); !function (e) { if (!0 === e._errored) throw new TypeError("TransformStream is already errored"); if (!0 === e._readableClosed) throw new TypeError("Readable side is already closed"); A(e) }(this._controlledTransformStream) } }, { key: "error", value: function (e) { if (!1 === C(this)) throw F("error"); !function (e, t) { if (!0 === e._errored) throw new TypeError("TransformStream is already errored"); w(e, t) }(this._controlledTransformStream, e) } }, { key: "desiredSize", get: function () { if (!1 === C(this)) throw F("desiredSize"); var e = this._controlledTransformStream._readableController; return m(e) } }]), e }(), I = function () { function e() { var t = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {}; i(this, e), this._transformer = t; var r = t.readableStrategy, n = t.writableStrategy; this._transforming = !1, this._errored = !1, this._storedError!
  = void 0, this._writableController = void 0, this._readableController = void 0, this._transformStreamController = void 0, this._writableDone = !1, this._readableClosed = !1, this._backpressure = void 0, this._backpressureChangePromise = void 0, this._backpressureChangePromise_resolve = void 0, this._transformStreamController = new O(this); var o = void 0, u = new Promise(function (e) { o = e }), l = new T(this, u); this._readable = new d(l, r); var c = new E(this, u); this._writable = new y(c, n), a(void 0 !== this._writableController), a(void 0 !== this._readableController), P(this, m(this._readableController) <= 0); var h = this, f = s(t, "start", [h._transformStreamController]); o(f), u.catch(function (e) { !1 === h._errored && (h._errored = !0, h._storedError = e) }) } return n(e, [{ key: "readable", get: function () { if (!1 === R(this)) throw L("readable"); return this._readable } }, { key: "writable", get: function () { if (!1 === R(this)) throw L("writable"); return this._writable } }]), e }(); function F(e) { return new TypeError("TransformStreamDefaultController.prototype." + e + " can only be used on a TransformStreamDefaultController") } function L(e) { return new TypeError("TransformStream.prototype." + e + " can only be used on a TransformStream") } e.exports = { TransformStream: I } }, function (e, t, r) { e.exports = r(5) }])) }, function (e, t, r) { "use strict"; var n = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (e) { return typeof e } : function (e) { return e && "function" == typeof Symbol && e.constructor === Symbol && e !== Symbol.prototype ? "symbol" : typeof e }, i = !1; try { if ("function" == typeof URL && "object" === n(URL.prototype) && "origin" in URL.prototype) { var a = new URL("b", "http://a"); a.pathname = "c%20d", i = "http://a/c%20d" === a.href } } catch (e) { } if (i) t.URL = URL; else { var o = r(128).URL, s = r(3).URL; s && (o.createObjectURL = function (e) { return s.createObjectURL.apply(s, arguments) }, o.revokeObjectURL = function (e) {!
  s.revokeObjectURL(e) }), t.URL = o } }, function (e, t, r) { "use strict"; !function () { var e = Object.create(null); e.ftp = 21, e.file = 0, e.gopher = 70, e.http = 80, e.https = 443, e.ws = 80, e.wss = 443; var r = Object.create(null); function n(t) { return void 0 !== e[t] } function i() { d.call(this), this._isInvalid = !0 } function a(e) { return "" === e && i.call(this), e.toLowerCase() } function o(e) { var t = e.charCodeAt(0); return t > 32 && t < 127 && -1 === [34, 35, 60, 62, 63, 96].indexOf(t) ? e : encodeURIComponent(e) } function s(e) { var t = e.charCodeAt(0); return t > 32 && t < 127 && -1 === [34, 35, 60, 62, 96].indexOf(t) ? e : encodeURIComponent(e) } r["%2e"] = ".", r[".%2e"] = "..", r["%2e."] = "..", r["%2e%2e"] = ".."; var u, l = /[a-zA-Z]/, c = /[a-zA-Z0-9\+\-\.]/; function h(t, h, d) { function f(e) { b.push(e) } var p = h || "scheme start", v = 0, m = "", g = !1, y = !1, b = []; e: for (; (t[v - 1] !== u || 0 === v) && !this._isInvalid;) { var _ = t[v]; switch (p) { case "scheme start": if (!_ || !l.test(_)) { if (h) { f("Invalid scheme."); break e } m = "", p = "no scheme"; continue } m += _.toLowerCase(), p = "scheme"; break; case "scheme": if (_ && c.test(_)) m += _.toLowerCase(); else { if (":" !== _) { if (h) { if (_ === u) break e; f("Code point not allowed in scheme: " + _); break e } m = "", v = 0, p = "no scheme"; continue } if (this._scheme = m, m = "", h) break e; n(this._scheme) && (this._isRelative = !0), p = "file" === this._scheme ? "relative" : this._isRelative && d && d._scheme === this._scheme ? "relative or authority" : this._isRelative ? "authority first slash" : "scheme data" } break; case "scheme data": "?" === _ ? (this._query = "?", p = "query") : "#" === _ ? (this._fragment = "#", p = "fragment") : _ !== u && "\t" !== _ && "\n" !== _ && "\r" !== _ && (this._schemeData += o(_)); break; case "no scheme": if (d && n(d._scheme)) { p = "relative"; continue } f("Missing scheme."), i.call(this); break; case "relative or authority": if ("/" !== _ || "/" !== t[v + 1]) { !
 f("Expected /, got: " + _), p = "relative"; continue } p = "authority ignore slashes"; break; case "relative": if (this._isRelative = !0, "file" !== this._scheme && (this._scheme = d._scheme), _ === u) { this._host = d._host, this._port = d._port, this._path = d._path.slice(), this._query = d._query, this._username = d._username, this._password = d._password; break e } if ("/" === _ || "\\" === _) "\\" === _ && f("\\ is an invalid code point."), p = "relative slash"; else if ("?" === _) this._host = d._host, this._port = d._port, this._path = d._path.slice(), this._query = "?", this._username = d._username, this._password = d._password, p = "query"; else { if ("#" !== _) { var A = t[v + 1], S = t[v + 2]; ("file" !== this._scheme || !l.test(_) || ":" !== A && "|" !== A || S !== u && "/" !== S && "\\" !== S && "?" !== S && "#" !== S) && (this._host = d._host, this._port = d._port, this._username = d._username, this._password = d._password, this._path = d._path.slice(), this._path.pop()), p = "relative path"; continue } this._host = d._host, this._port = d._port, this._path = d._path.slice(), this._query = d._query, this._fragment = "#", this._username = d._username, this._password = d._password, p = "fragment" } break; case "relative slash": if ("/" !== _ && "\\" !== _) { "file" !== this._scheme && (this._host = d._host, this._port = d._port, this._username = d._username, this._password = d._password), p = "relative path"; continue } "\\" === _ && f("\\ is an invalid code point."), p = "file" === this._scheme ? "file host" : "authority ignore slashes"; break; case "authority first slash": if ("/" !== _) { f("Expected '/', got: " + _), p = "authority ignore slashes"; continue } p = "authority second slash"; break; case "authority second slash": if (p = "authority ignore slashes", "/" !== _) { f("Expected '/', got: " + _); continue } break; case "authority ignore slashes": if ("/" !== _ && "\\" !== _) { p = "authority"; continue } f("Expected authority, got: " + _); break; case "authority": if ("@" === _) { g && (f(!
 "@ already seen."), m += "%40"), g = !0; for (var w = 0; w < m.length; w++) { var k = m[w]; if ("\t" !== k && "\n" !== k && "\r" !== k) if (":" !== k || null !== this._password) { var P = o(k); null !== this._password ? this._password += P : this._username += P } else this._password = ""; else f("Invalid whitespace in authority.") } m = "" } else { if (_ === u || "/" === _ || "\\" === _ || "?" === _ || "#" === _) { v -= m.length, m = "", p = "host"; continue } m += _ } break; case "file host": if (_ === u || "/" === _ || "\\" === _ || "?" === _ || "#" === _) { 2 !== m.length || !l.test(m[0]) || ":" !== m[1] && "|" !== m[1] ? 0 === m.length ? p = "relative path start" : (this._host = a.call(this, m), m = "", p = "relative path start") : p = "relative path"; continue } "\t" === _ || "\n" === _ || "\r" === _ ? f("Invalid whitespace in file host.") : m += _; break; case "host": case "hostname": if (":" !== _ || y) { if (_ === u || "/" === _ || "\\" === _ || "?" === _ || "#" === _) { if (this._host = a.call(this, m), m = "", p = "relative path start", h) break e; continue } "\t" !== _ && "\n" !== _ && "\r" !== _ ? ("[" === _ ? y = !0 : "]" === _ && (y = !1), m += _) : f("Invalid code point in host/hostname: " + _) } else if (this._host = a.call(this, m), m = "", p = "port", "hostname" === h) break e; break; case "port": if (/[0-9]/.test(_)) m += _; else { if (_ === u || "/" === _ || "\\" === _ || "?" === _ || "#" === _ || h) { if ("" !== m) { var x = parseInt(m, 10); x !== e[this._scheme] && (this._port = x + ""), m = "" } if (h) break e; p = "relative path start"; continue } "\t" === _ || "\n" === _ || "\r" === _ ? f("Invalid code point in port: " + _) : i.call(this) } break; case "relative path start": if ("\\" === _ && f("'\\' not allowed in path."), p = "relative path", "/" !== _ && "\\" !== _) continue; break; case "relative path": var C; if (_ !== u && "/" !== _ && "\\" !== _ && (h || "?" !== _ && "#" !== _)) "\t" !== _ && "\n" !== _ && "\r" !== _ && (m += o(_)); else "\\" === _ && f("\\ not allowed in relative!
  path."), (C = r[m.toLowerCase()]) && (m = C), ".." === m ? (this._path.pop(), "/" !== _ && "\\" !== _ && this._path.push("")) : "." === m && "/" !== _ && "\\" !== _ ? this._path.push("") : "." !== m && ("file" === this._scheme && 0 === this._path.length && 2 === m.length && l.test(m[0]) && "|" === m[1] && (m = m[0] + ":"), this._path.push(m)), m = "", "?" === _ ? (this._query = "?", p = "query") : "#" === _ && (this._fragment = "#", p = "fragment"); break; case "query": h || "#" !== _ ? _ !== u && "\t" !== _ && "\n" !== _ && "\r" !== _ && (this._query += s(_)) : (this._fragment = "#", p = "fragment"); break; case "fragment": _ !== u && "\t" !== _ && "\n" !== _ && "\r" !== _ && (this._fragment += _) }v++ } } function d() { this._scheme = "", this._schemeData = "", this._username = "", this._password = null, this._host = "", this._port = "", this._path = [], this._query = "", this._fragment = "", this._isInvalid = !1, this._isRelative = !1 } function f(e, t) { void 0 === t || t instanceof f || (t = new f(String(t))), this._url = e, d.call(this); var r = e.replace(/^[ \t\r\n\f]+|[ \t\r\n\f]+$/g, ""); h.call(this, r, null, t) } f.prototype = { toString: function () { return this.href }, get href() { if (this._isInvalid) return this._url; var e = ""; return "" === this._username && null === this._password || (e = this._username + (null !== this._password ? ":" + this._password : "") + "@"), this.protocol + (this._isRelative ? "//" + e + this.host : "") + this.pathname + this._query + this._fragment }, set href(e) { d.call(this), h.call(this, e) }, get protocol() { return this._scheme + ":" }, set protocol(e) { this._isInvalid || h.call(this, e + ":", "scheme start") }, get host() { return this._isInvalid ? "" : this._port ? this._host + ":" + this._port : this._host }, set host(e) { !this._isInvalid && this._isRelative && h.call(this, e, "host") }, get hostname() { return this._host }, set hostname(e) { !this._isInvalid && this._isRelative && h.call(this, e, "hostname") }, get port() { return this._port }, set port(!
 e) { !this._isInvalid && this._isRelative && h.call(this, e, "port") }, get pathname() { return this._isInvalid ? "" : this._isRelative ? "/" + this._path.join("/") : this._schemeData }, set pathname(e) { !this._isInvalid && this._isRelative && (this._path = [], h.call(this, e, "relative path start")) }, get search() { return this._isInvalid || !this._query || "?" === this._query ? "" : this._query }, set search(e) { !this._isInvalid && this._isRelative && (this._query = "?", "?" === e[0] && (e = e.slice(1)), h.call(this, e, "query")) }, get hash() { return this._isInvalid || !this._fragment || "#" === this._fragment ? "" : this._fragment }, set hash(e) { this._isInvalid || (this._fragment = "#", "#" === e[0] && (e = e.slice(1)), h.call(this, e, "fragment")) }, get origin() { var e; if (this._isInvalid || !this._scheme) return ""; switch (this._scheme) { case "data": case "file": case "javascript": case "mailto": return "null"; case "blob": try { return new f(this._schemeData).origin || "null" } catch (e) { } return "null" }return (e = this.host) ? this._scheme + "://" + e : "" } }, t.URL = f }() }, function (e, t, r) { "use strict"; Object.defineProperty(t, "__esModule", { value: !0 }), t.build = t.version = t.setPDFNetworkStreamFactory = t.PDFPageProxy = t.PDFDocumentProxy = t.PDFWorker = t.PDFDataRangeTransport = t.LoopbackPort = t.getDocument = void 0; var n, i = function () { return function (e, t) { if (Array.isArray(e)) return e; if (Symbol.iterator in Object(e)) return function (e, t) { var r = [], n = !0, i = !1, a = void 0; try { for (var o, s = e[Symbol.iterator](); !(n = (o = s.next()).done) && (r.push(o.value), !t || r.length !== t); n = !0); } catch (e) { i = !0, a = e } finally { try { !n && s.return && s.return() } finally { if (i) throw a } } return r }(e, t); throw new TypeError("Invalid attempt to destructure non-iterable instance") } }(), a = function () { function e(e, t) { for (var r = 0; r < t.length; r++) { var n = t[r]; n.enumerable = n.enumerable || !1, n.configurable = !0, "value" in n!
  && (n.writable = !0), Object.defineProperty(e, n.key, n) } } return function (t, r, n) { return r && e(t.prototype, r), n && e(t, n), t } }(), o = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (e) { return typeof e } : function (e) { return e && "function" == typeof Symbol && e.constructor === Symbol && e !== Symbol.prototype ? "symbol" : typeof e }, s = r(1), u = r(130), l = r(131), c = r(132), h = r(133), d = r(3), f = (n = d) && n.__esModule ? n : { default: n }, p = r(135), v = r(136), m = r(141), g = r(143), y = r(144); function b(e, t) { if (!(e instanceof t)) throw new TypeError("Cannot call a class as a function") } var _ = 65536, A = !1, S = void 0, w = null, k = !1; "undefined" == typeof window ? (A = !0, void 0 === require.ensure && (require.ensure = require("node-ensure")), k = !0) : "undefined" != typeof require && "function" == typeof require.ensure && (k = !0), "undefined" != typeof requirejs && requirejs.toUrl && (S = requirejs.toUrl("pdfjs-dist/build/pdf.worker.js")); var P, x = "undefined" != typeof requirejs && requirejs.load; if (w = k ? function () { return new Promise(function (e, t) { require.ensure([], function () { try { var r; r = require("./pdf.worker.js"), e(r.WorkerMessageHandler) } catch (e) { t(e) } }, t, "pdfjsWorker") }) } : x ? function () { return new Promise(function (e, t) { requirejs(["pdfjs-dist/build/pdf.worker"], function (r) { try { e(r.WorkerMessageHandler) } catch (e) { t(e) } }, t) }) } : null, !S && "undefined" != typeof document) { var C = document.currentScript && document.currentScript.src; C && (S = C.replace(/(\.(?:min\.)?js)(\?.*)?$/i, ".worker$1$2")) } var R = function () { var e = 0; function t() { this._capability = (0, s.createPromiseCapability)(), this._transport = null, this._worker = null, this.docId = "d" + e++, this.destroyed = !1, this.onPassword = null, this.onProgress = null, this.onUnsupportedFeature = null } return t.prototype = { get promise() { return this._capability.promise }, destroy: function () { var e = this!
 ; return this.destroyed = !0, (this._transport ? this._transport.destroy() : Promise.resolve()).then(function () { e._transport = null, e._worker && (e._worker.destroy(), e._worker = null) }) }, then: function (e, t) { return this.promise.then.apply(this.promise, arguments) } }, t }(), E = function () { function e(t, r) { b(this, e), this.length = t, this.initialData = r, this._rangeListeners = [], this._progressListeners = [], this._progressiveReadListeners = [], this._readyCapability = (0, s.createPromiseCapability)() } return a(e, [{ key: "addRangeListener", value: function (e) { this._rangeListeners.push(e) } }, { key: "addProgressListener", value: function (e) { this._progressListeners.push(e) } }, { key: "addProgressiveReadListener", value: function (e) { this._progressiveReadListeners.push(e) } }, { key: "onDataRange", value: function (e, t) { var r = !0, n = !1, i = void 0; try { for (var a, o = this._rangeListeners[Symbol.iterator](); !(r = (a = o.next()).done); r = !0) { (0, a.value)(e, t) } } catch (e) { n = !0, i = e } finally { try { !r && o.return && o.return() } finally { if (n) throw i } } } }, { key: "onDataProgress", value: function (e) { var t = this; this._readyCapability.promise.then(function () { var r = !0, n = !1, i = void 0; try { for (var a, o = t._progressListeners[Symbol.iterator](); !(r = (a = o.next()).done); r = !0) { (0, a.value)(e) } } catch (e) { n = !0, i = e } finally { try { !r && o.return && o.return() } finally { if (n) throw i } } }) } }, { key: "onDataProgressiveRead", value: function (e) { var t = this; this._readyCapability.promise.then(function () { var r = !0, n = !1, i = void 0; try { for (var a, o = t._progressiveReadListeners[Symbol.iterator](); !(r = (a = o.next()).done); r = !0) { (0, a.value)(e) } } catch (e) { n = !0, i = e } finally { try { !r && o.return && o.return() } finally { if (n) throw i } } }) } }, { key: "transportReady", value: function () { this._readyCapability.resolve() } }, { key: "requestDataRange", value: function (e, t) { (0, s.unreachable)("!
 Abstract method PDFDataRangeTransport.requestDataRange") } }, { key: "abort", value: function () { } }]), e }(), T = function () { function e(t, r, n) { b(this, e), this.loadingTask = n, this._pdfInfo = t, this._transport = r } return a(e, [{ key: "getPage", value: function (e) { return this._transport.getPage(e) } }, { key: "getPageIndex", value: function (e) { return this._transport.getPageIndex(e) } }, { key: "getDestinations", value: function () { return this._transport.getDestinations() } }, { key: "getDestination", value: function (e) { return this._transport.getDestination(e) } }, { key: "getPageLabels", value: function () { return this._transport.getPageLabels() } }, { key: "getPageMode", value: function () { return this._transport.getPageMode() } }, { key: "getAttachments", value: function () { return this._transport.getAttachments() } }, { key: "getJavaScript", value: function () { return this._transport.getJavaScript() } }, { key: "getOutline", value: function () { return this._transport.getOutline() } }, { key: "getPermissions", value: function () { return this._transport.getPermissions() } }, { key: "getMetadata", value: function () { return this._transport.getMetadata() } }, { key: "getData", value: function () { return this._transport.getData() } }, { key: "getDownloadInfo", value: function () { return this._transport.downloadInfoCapability.promise } }, { key: "getStats", value: function () { return this._transport.getStats() } }, { key: "cleanup", value: function () { this._transport.startCleanup() } }, { key: "destroy", value: function () { return this.loadingTask.destroy() } }, { key: "numPages", get: function () { return this._pdfInfo.numPages } }, { key: "fingerprint", get: function () { return this._pdfInfo.fingerprint } }, { key: "loadingParams", get: function () { return this._transport.loadingParams } }]), e }(), O = function () { function e(e, t, r) { var n = arguments.length > 3 && void 0 !== arguments[3] && arguments[3]; this.pageIndex = e, this._pageInfo = t, this.transport = r, this.!
 _stats = n ? new u.StatTimer : u.DummyStatTimer, this._pdfBug = n, this.commonObjs = r.commonObjs, this.objs = new j, this.cleanupAfterRender = !1, this.pendingCleanup = !1, this.intentStates = Object.create(null), this.destroyed = !1 } return e.prototype = { get pageNumber() { return this.pageIndex + 1 }, get rotate() { return this._pageInfo.rotate }, get ref() { return this._pageInfo.ref }, get userUnit() { return this._pageInfo.userUnit }, get view() { return this._pageInfo.view }, getViewport: function (e) { var t = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : this.rotate, r = arguments.length > 2 && void 0 !== arguments[2] && arguments[2]; return new u.PageViewport({ viewBox: this.view, scale: e, rotation: t, dontFlip: r }) }, getAnnotations: function (e) { var t = e && e.intent || null; return this.annotationsPromise && this.annotationsIntent === t || (this.annotationsPromise = this.transport.getAnnotations(this.pageIndex, t), this.annotationsIntent = t), this.annotationsPromise }, render: function (e) { var t = this, r = this._stats; r.time("Overall"), this.pendingCleanup = !1; var n = "print" === e.intent ? "print" : "display", i = e.canvasFactory || new u.DOMCanvasFactory, a = new y.WebGLContext({ enable: e.enableWebGL }); this.intentStates[n] || (this.intentStates[n] = Object.create(null)); var o = this.intentStates[n]; o.displayReadyCapability || (o.receivingOperatorList = !0, o.displayReadyCapability = (0, s.createPromiseCapability)(), o.operatorList = { fnArray: [], argsArray: [], lastChunk: !1 }, r.time("Page Request"), this.transport.messageHandler.send("RenderPageRequest", { pageIndex: this.pageNumber - 1, intent: n, renderInteractiveForms: !0 === e.renderInteractiveForms })); var l = function (e) { var n = o.renderTasks.indexOf(c); n >= 0 && o.renderTasks.splice(n, 1), t.cleanupAfterRender && (t.pendingCleanup = !0), t._tryCleanup(), e ? c.capability.reject(e) : c.capability.resolve(), r.timeEnd("Rendering"), r.timeEnd("Overall") }, c = new D(l, e, this.objs, this.commonObjs,!
  o.operatorList, this.pageNumber, i, a, this._pdfBug); c.useRequestAnimationFrame = "print" !== n, o.renderTasks || (o.renderTasks = []), o.renderTasks.push(c); var h = c.task; return o.displayReadyCapability.promise.then(function (e) { t.pendingCleanup ? l() : (r.time("Rendering"), c.initializeGraphics(e), c.operatorListChanged()) }).catch(l), h }, getOperatorList: function () { this.intentStates.oplist || (this.intentStates.oplist = Object.create(null)); var e, t = this.intentStates.oplist; return t.opListReadCapability || ((e = {}).operatorListChanged = function () { if (t.operatorList.lastChunk) { t.opListReadCapability.resolve(t.operatorList); var r = t.renderTasks.indexOf(e); r >= 0 && t.renderTasks.splice(r, 1) } }, t.receivingOperatorList = !0, t.opListReadCapability = (0, s.createPromiseCapability)(), t.renderTasks = [], t.renderTasks.push(e), t.operatorList = { fnArray: [], argsArray: [], lastChunk: !1 }, this._stats.time("Page Request"), this.transport.messageHandler.send("RenderPageRequest", { pageIndex: this.pageIndex, intent: "oplist" })), t.opListReadCapability.promise }, streamTextContent: function () { var e = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {}; return this.transport.messageHandler.sendWithStream("GetTextContent", { pageIndex: this.pageNumber - 1, normalizeWhitespace: !0 === e.normalizeWhitespace, combineTextItems: !0 !== e.disableCombineTextItems }, { highWaterMark: 100, size: function (e) { return e.items.length } }) }, getTextContent: function (e) { e = e || {}; var t = this.streamTextContent(e); return new Promise(function (e, r) { var n = t.getReader(), i = { items: [], styles: Object.create(null) }; !function t() { n.read().then(function (r) { var n, a = r.value; r.done ? e(i) : (Object.assign(i.styles, a.styles), (n = i.items).push.apply(n, function (e) { if (Array.isArray(e)) { for (var t = 0, r = Array(e.length); t < e.length; t++)r[t] = e[t]; return r } return Array.from(e) }(a.items)), t()) }, r) }() }) }, _destroy: function () { this.destroyed = !0, t!
 his.transport.pageCache[this.pageIndex] = null; var e = []; return Object.keys(this.intentStates).forEach(function (t) { "oplist" !== t && this.intentStates[t].renderTasks.forEach(function (t) { var r = t.capability.promise.catch(function () { }); e.push(r), t.cancel() }) }, this), this.objs.clear(), this.annotationsPromise = null, this.pendingCleanup = !1, Promise.all(e) }, cleanup: function () { var e = arguments.length > 0 && void 0 !== arguments[0] && arguments[0]; this.pendingCleanup = !0, this._tryCleanup(e) }, _tryCleanup: function () { var e = arguments.length > 0 && void 0 !== arguments[0] && arguments[0]; this.pendingCleanup && !Object.keys(this.intentStates).some(function (e) { var t = this.intentStates[e]; return 0 !== t.renderTasks.length || t.receivingOperatorList }, this) && (Object.keys(this.intentStates).forEach(function (e) { delete this.intentStates[e] }, this), this.objs.clear(), this.annotationsPromise = null, e && this._stats instanceof u.StatTimer && (this._stats = new u.StatTimer), this.pendingCleanup = !1) }, _startRenderPage: function (e, t) { var r = this.intentStates[t]; r.displayReadyCapability && r.displayReadyCapability.resolve(e) }, _renderPageChunk: function (e, t) { var r, n, i = this.intentStates[t]; for (r = 0, n = e.length; r < n; r++)i.operatorList.fnArray.push(e.fnArray[r]), i.operatorList.argsArray.push(e.argsArray[r]); for (i.operatorList.lastChunk = e.lastChunk, r = 0; r < i.renderTasks.length; r++)i.renderTasks[r].operatorListChanged(); e.lastChunk && (i.receivingOperatorList = !1, this._tryCleanup()) }, get stats() { return this._stats instanceof u.StatTimer ? this._stats : null } }, e }(), I = function () { function e() { var t = !(arguments.length > 0 && void 0 !== arguments[0]) || arguments[0]; b(this, e), this._listeners = [], this._defer = t, this._deferred = Promise.resolve(void 0) } return a(e, [{ key: "postMessage", value: function (e, t) { var r = this; if (this._defer) { var n = new WeakMap, i = { data: function e(r) { if ("object" !== (void 0 === r ? "undefi!
 ned" : o(r)) || null === r) return r; if (n.has(r)) return n.get(r); var i, a; if ((a = r.buffer) && (0, s.isArrayBuffer)(a)) { var u = t && t.includes(a); return i = r === a ? r : u ? new r.constructor(a, r.byteOffset, r.byteLength) : new r.constructor(r), n.set(r, i), i } for (var l in i = Array.isArray(r) ? [] : {}, n.set(r, i), r) { for (var c, h = r; !(c = Object.getOwnPropertyDescriptor(h, l));)h = Object.getPrototypeOf(h); void 0 !== c.value && "function" != typeof c.value && (i[l] = e(c.value)) } return i }(e) }; this._deferred.then(function () { r._listeners.forEach(function (e) { e.call(this, i) }, r) }) } else this._listeners.forEach(function (t) { t.call(this, { data: e }) }, this) } }, { key: "addEventListener", value: function (e, t) { this._listeners.push(t) } }, { key: "removeEventListener", value: function (e, t) { var r = this._listeners.indexOf(t); this._listeners.splice(r, 1) } }, { key: "terminate", value: function () { this._listeners = [] } }]), e }(), F = function () { var e = 0; function t() { if (p.GlobalWorkerOptions.workerSrc) return p.GlobalWorkerOptions.workerSrc; if (void 0 !== S) return S; throw new Error('No "GlobalWorkerOptions.workerSrc" specified.') } function r() { try { if ("undefined" != typeof window) return window.pdfjsWorker && window.pdfjsWorker.WorkerMessageHandler } catch (e) { } return null } var n = void 0; var i = new WeakMap; function a() { var e = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {}, t = e.name, r = void 0 === t ? null : t, n = e.port, a = void 0 === n ? null : n, o = e.postMessageTransfers, u = void 0 === o || o, l = e.verbosity, c = void 0 === l ? (0, s.getVerbosityLevel)() : l; if (a && i.has(a)) throw new Error("Cannot use more than one PDFWorker per port"); if (this.name = r, this.destroyed = !1, this.postMessageTransfers = !1 !== u, this.verbosity = c, this._readyCapability = (0, s.createPromiseCapability)(), this._port = null, this._webWorker = null, this._messageHandler = null, a) return i.set(a, this), void this._initializ!
 eFromPort(a); this._initialize() } return a.prototype = { get promise() { return this._readyCapability.promise }, get port() { return this._port }, get messageHandler() { return this._messageHandler }, _initializeFromPort: function (e) { this._port = e, this._messageHandler = new v.MessageHandler("main", "worker", e), this._messageHandler.on("ready", function () { }), this._readyCapability.resolve() }, _initialize: function () { var e, n, i = this; if ("undefined" != typeof Worker && !A && !r()) { var a = t(); try { (0, s.isSameOrigin)(window.location.href, a) || (e = new s.URL(a, window.location).href, n = "importScripts('" + e + "');", a = s.URL.createObjectURL(new Blob([n]))); var o = new Worker(a), u = new v.MessageHandler("main", "worker", o), l = function () { o.removeEventListener("error", c), u.destroy(), o.terminate(), i.destroyed ? i._readyCapability.reject(new Error("Worker was destroyed")) : i._setupFakeWorker() }, c = function () { i._webWorker || l() }; o.addEventListener("error", c), u.on("test", function (e) { o.removeEventListener("error", c), i.destroyed ? l() : e && e.supportTypedArray ? (i._messageHandler = u, i._port = o, i._webWorker = o, e.supportTransfers || (i.postMessageTransfers = !1), i._readyCapability.resolve(), u.send("configure", { verbosity: i.verbosity })) : (i._setupFakeWorker(), u.destroy(), o.terminate()) }), u.on("ready", function (e) { if (o.removeEventListener("error", c), i.destroyed) l(); else try { h() } catch (e) { i._setupFakeWorker() } }); var h = function () { var e = new Uint8Array([i.postMessageTransfers ? 255 : 0]); try { u.send("test", e, [e.buffer]) } catch (t) { (0, s.info)("Cannot use postMessage transfers"), e[0] = 0, u.send("test", e) } }; return void h() } catch (e) { (0, s.info)("The worker has been disabled.") } } this._setupFakeWorker() }, _setupFakeWorker: function () { var i = this; A || ((0, s.warn)("Setting up fake worker."), A = !0), function () { if (n) return n.promise; n = (0, s.createPromiseCapability)(); var e = r(); return e ? (n.resolve(e), !
 n.promise) : ((w || function () { return (0, u.loadScript)(t()).then(function () { return window.pdfjsWorker.WorkerMessageHandler }) })().then(n.resolve, n.reject), n.promise) }().then(function (t) { if (i.destroyed) i._readyCapability.reject(new Error("Worker was destroyed")); else { var r = new I; i._port = r; var n = "fake" + e++, a = new v.MessageHandler(n + "_worker", n, r); t.setup(a, r); var o = new v.MessageHandler(n, n + "_worker", r); i._messageHandler = o, i._readyCapability.resolve() } }).catch(function (e) { i._readyCapability.reject(new Error('Setting up fake worker failed: "' + e.message + '".')) }) }, destroy: function () { this.destroyed = !0, this._webWorker && (this._webWorker.terminate(), this._webWorker = null), i.delete(this._port), this._port = null, this._messageHandler && (this._messageHandler.destroy(), this._messageHandler = null) } }, a.fromPort = function (e) { if (!e || !e.port) throw new Error("PDFWorker.fromPort - invalid method signature."); return i.has(e.port) ? i.get(e.port) : new a(e) }, a.getWorkerSrc = function () { return t() }, a }(), L = function () { function e(t, r, n, i) { b(this, e), this.messageHandler = t, this.loadingTask = r, this.commonObjs = new j, this.fontLoader = new l.FontLoader(r.docId), this._params = i, this.CMapReaderFactory = new i.CMapReaderFactory({ baseUrl: i.cMapUrl, isCompressed: i.cMapPacked }), this.destroyed = !1, this.destroyCapability = null, this._passwordCapability = null, this._networkStream = n, this._fullReader = null, this._lastProgress = null, this.pageCache = [], this.pagePromises = [], this.downloadInfoCapability = (0, s.createPromiseCapability)(), this.setupMessageHandler() } return a(e, [{ key: "destroy", value: function () { var e = this; if (this.destroyCapability) return this.destroyCapability.promise; this.destroyed = !0, this.destroyCapability = (0, s.createPromiseCapability)(), this._passwordCapability && this._passwordCapability.reject(new Error("Worker was destroyed during onPassword callback")); var t = []; this.pageCache.!
 forEach(function (e) { e && t.push(e._destroy()) }), this.pageCache = [], this.pagePromises = []; var r = this.messageHandler.sendWithPromise("Terminate", null); return t.push(r), Promise.all(t).then(function () { e.fontLoader.clear(), e._networkStream && e._networkStream.cancelAllRequests(), e.messageHandler && (e.messageHandler.destroy(), e.messageHandler = null), e.destroyCapability.resolve() }, this.destroyCapability.reject), this.destroyCapability.promise } }, { key: "setupMessageHandler", value: function () { var e = this.messageHandler, t = this.loadingTask; e.on("GetReader", function (e, t) { var r = this; (0, s.assert)(this._networkStream), this._fullReader = this._networkStream.getFullReader(), this._fullReader.onProgress = function (e) { r._lastProgress = { loaded: e.loaded, total: e.total } }, t.onPull = function () { r._fullReader.read().then(function (e) { var r = e.value; e.done ? t.close() : ((0, s.assert)((0, s.isArrayBuffer)(r)), t.enqueue(new Uint8Array(r), 1, [r])) }).catch(function (e) { t.error(e) }) }, t.onCancel = function (e) { r._fullReader.cancel(e) } }, this), e.on("ReaderHeadersReady", function (e) { var r = this, n = (0, s.createPromiseCapability)(), i = this._fullReader; return i.headersReady.then(function () { i.isStreamingSupported && i.isRangeSupported || (r._lastProgress && t.onProgress && t.onProgress(r._lastProgress), i.onProgress = function (e) { t.onProgress && t.onProgress({ loaded: e.loaded, total: e.total }) }), n.resolve({ isStreamingSupported: i.isStreamingSupported, isRangeSupported: i.isRangeSupported, contentLength: i.contentLength }) }, n.reject), n.promise }, this), e.on("GetRangeReader", function (e, t) { (0, s.assert)(this._networkStream); var r = this._networkStream.getRangeReader(e.begin, e.end); t.onPull = function () { r.read().then(function (e) { var r = e.value; e.done ? t.close() : ((0, s.assert)((0, s.isArrayBuffer)(r)), t.enqueue(new Uint8Array(r), 1, [r])) }).catch(function (e) { t.error(e) }) }, t.onCancel = function (e) { r.cancel(e) } }, this), e.on!
 ("GetDoc", function (e) { var r = e.pdfInfo; this.numPages = r.numPages, this.pdfDocument = new T(r, this, t), t._capability.resolve(this.pdfDocument) }, this), e.on("PasswordRequest", function (e) { var r = this; if (this._passwordCapability = (0, s.createPromiseCapability)(), t.onPassword) { try { t.onPassword(function (e) { r._passwordCapability.resolve({ password: e }) }, e.code) } catch (e) { this._passwordCapability.reject(e) } } else this._passwordCapability.reject(new s.PasswordException(e.message, e.code)); return this._passwordCapability.promise }, this), e.on("PasswordException", function (e) { t._capability.reject(new s.PasswordException(e.message, e.code)) }, this), e.on("InvalidPDF", function (e) { t._capability.reject(new s.InvalidPDFException(e.message)) }, this), e.on("MissingPDF", function (e) { t._capability.reject(new s.MissingPDFException(e.message)) }, this), e.on("UnexpectedResponse", function (e) { t._capability.reject(new s.UnexpectedResponseException(e.message, e.status)) }, this), e.on("UnknownError", function (e) { t._capability.reject(new s.UnknownErrorException(e.message, e.details)) }, this), e.on("DataLoaded", function (e) { t.onProgress && t.onProgress({ loaded: e.length, total: e.length }), this.downloadInfoCapability.resolve(e) }, this), e.on("StartRenderPage", function (e) { if (!this.destroyed) { var t = this.pageCache[e.pageIndex]; t._stats.timeEnd("Page Request"), t._startRenderPage(e.transparency, e.intent) } }, this), e.on("RenderPageChunk", function (e) { this.destroyed || this.pageCache[e.pageIndex]._renderPageChunk(e.operatorList, e.intent) }, this), e.on("commonobj", function (e) { var t = this; if (!this.destroyed) { var r = i(e, 3), n = r[0], a = r[1], o = r[2]; if (!this.commonObjs.hasData(n)) switch (a) { case "Font": var u = this._params; if ("error" in o) { var c = o.error; (0, s.warn)("Error during font loading: " + c), this.commonObjs.resolve(n, c); break } var h = null; u.pdfBug && f.default.FontInspector && f.default.FontInspector.enabled && (h = { registerF!
 ont: function (e, t) { f.default.FontInspector.fontAdded(e, t) } }); var d = new l.FontFaceObject(o, { isEvalSupported: u.isEvalSupported, disableFontFace: u.disableFontFace, ignoreErrors: u.ignoreErrors, onUnsupportedFeature: this._onUnsupportedFeature.bind(this), fontRegistry: h }); this.fontLoader.bind([d], function (e) { t.commonObjs.resolve(n, d) }); break; case "FontPath": this.commonObjs.resolve(n, o); break; default: throw new Error("Got unknown common object type " + a) } } }, this), e.on("obj", function (e) { if (!this.destroyed) { var t = i(e, 4), r = t[0], n = t[1], a = t[2], o = t[3], s = this.pageCache[n]; if (!s.objs.hasData(r)) switch (a) { case "JpegStream": return new Promise(function (e, t) { var r = new Image; r.onload = function () { e(r) }, r.onerror = function () { t(new Error("Error during JPEG image loading")) }, r.src = o }).then(function (e) { s.objs.resolve(r, e) }); case "Image": s.objs.resolve(r, o); o && "data" in o && o.data.length > 8e6 && (s.cleanupAfterRender = !0); break; default: throw new Error("Got unknown object type " + a) } } }, this), e.on("DocProgress", function (e) { this.destroyed || t.onProgress && t.onProgress({ loaded: e.loaded, total: e.total }) }, this), e.on("PageError", function (e) { if (!this.destroyed) { var t = this.pageCache[e.pageNum - 1].intentStates[e.intent]; if (!t.displayReadyCapability) throw new Error(e.error); if (t.displayReadyCapability.reject(e.error), t.operatorList) { t.operatorList.lastChunk = !0; for (var r = 0; r < t.renderTasks.length; r++)t.renderTasks[r].operatorListChanged() } } }, this), e.on("UnsupportedFeature", this._onUnsupportedFeature, this), e.on("JpegDecode", function (e) { if (this.destroyed) return Promise.reject(new Error("Worker was destroyed")); if ("undefined" == typeof document) return Promise.reject(new Error('"document" is not defined.')); var t = i(e, 2), r = t[0], n = t[1]; return 3 !== n && 1 !== n ? Promise.reject(new Error("Only 3 components or 1 component can be returned")) : new Promise(function (e, t) { var i!
  = new Image; i.onload = function () { var t = i.width, r = i.height, a = t * r, o = 4 * a, s = new Uint8ClampedArray(a * n), u = document.createElement("canvas"); u.width = t, u.height = r; var l = u.getContext("2d"); l.drawImage(i, 0, 0); var c = l.getImageData(0, 0, t, r).data; if (3 === n) for (var h = 0, d = 0; h < o; h += 4, d += 3)s[d] = c[h], s[d + 1] = c[h + 1], s[d + 2] = c[h + 2]; else if (1 === n) for (var f = 0, p = 0; f < o; f += 4, p++)s[p] = c[f]; e({ data: s, width: t, height: r }) }, i.onerror = function () { t(new Error("JpegDecode failed to load image")) }, i.src = r }) }, this), e.on("FetchBuiltInCMap", function (e) { return this.destroyed ? Promise.reject(new Error("Worker was destroyed")) : this.CMapReaderFactory.fetch({ name: e.name }) }, this) } }, { key: "_onUnsupportedFeature", value: function (e) { var t = e.featureId; this.destroyed || this.loadingTask.onUnsupportedFeature && this.loadingTask.onUnsupportedFeature(t) } }, { key: "getData", value: function () { return this.messageHandler.sendWithPromise("GetData", null) } }, { key: "getPage", value: function (e) { var t = this; if (!Number.isInteger(e) || e <= 0 || e > this.numPages) return Promise.reject(new Error("Invalid page request")); var r = e - 1; if (r in this.pagePromises) return this.pagePromises[r]; var n = this.messageHandler.sendWithPromise("GetPage", { pageIndex: r }).then(function (e) { if (t.destroyed) throw new Error("Transport destroyed"); var n = new O(r, e, t, t._params.pdfBug); return t.pageCache[r] = n, n }); return this.pagePromises[r] = n, n } }, { key: "getPageIndex", value: function (e) { return this.messageHandler.sendWithPromise("GetPageIndex", { ref: e }).catch(function (e) { return Promise.reject(new Error(e)) }) } }, { key: "getAnnotations", value: function (e, t) { return this.messageHandler.sendWithPromise("GetAnnotations", { pageIndex: e, intent: t }) } }, { key: "getDestinations", value: function () { return this.messageHandler.sendWithPromise("GetDestinations", null) } }, { key: "getDestination", va!
 lue: function (e) { return "string" != typeof e ? Promise.reject(new Error("Invalid destination request.")) : this.messageHandler.sendWithPromise("GetDestination", { id: e }) } }, { key: "getPageLabels", value: function () { return this.messageHandler.sendWithPromise("GetPageLabels", null) } }, { key: "getPageMode", value: function () { return this.messageHandler.sendWithPromise("GetPageMode", null) } }, { key: "getAttachments", value: function () { return this.messageHandler.sendWithPromise("GetAttachments", null) } }, { key: "getJavaScript", value: function () { return this.messageHandler.sendWithPromise("GetJavaScript", null) } }, { key: "getOutline", value: function () { return this.messageHandler.sendWithPromise("GetOutline", null) } }, { key: "getPermissions", value: function () { return this.messageHandler.sendWithPromise("GetPermissions", null) } }, { key: "getMetadata", value: function () { var e = this; return this.messageHandler.sendWithPromise("GetMetadata", null).then(function (t) { return { info: t[0], metadata: t[1] ? new m.Metadata(t[1]) : null, contentDispositionFilename: e._fullReader ? e._fullReader.filename : null } }) } }, { key: "getStats", value: function () { return this.messageHandler.sendWithPromise("GetStats", null) } }, { key: "startCleanup", value: function () { var e = this; this.messageHandler.sendWithPromise("Cleanup", null).then(function () { for (var t = 0, r = e.pageCache.length; t < r; t++) { var n = e.pageCache[t]; n && n.cleanup() } e.commonObjs.clear(), e.fontLoader.clear() }) } }, { key: "loadingParams", get: function () { var e = this._params; return (0, s.shadow)(this, "loadingParams", { disableAutoFetch: e.disableAutoFetch, disableCreateObjectURL: e.disableCreateObjectURL, disableFontFace: e.disableFontFace, nativeImageDecoderSupport: e.nativeImageDecoderSupport }) } }]), e }(), j = function () { function e() { this.objs = Object.create(null) } return e.prototype = { ensureObj: function (e) { if (this.objs[e]) return this.objs[e]; var t = { capability: (0, s.createPromi!
 seCapability)(), data: null, resolved: !1 }; return this.objs[e] = t, t }, get: function (e, t) { if (t) return this.ensureObj(e).capability.promise.then(t), null; var r = this.objs[e]; if (!r || !r.resolved) throw new Error("Requesting object that isn't resolved yet " + e); return r.data }, resolve: function (e, t) { var r = this.ensureObj(e); r.resolved = !0, r.data = t, r.capability.resolve(t) }, isResolved: function (e) { var t = this.objs; return !!t[e] && t[e].resolved }, hasData: function (e) { return this.isResolved(e) }, getData: function (e) { var t = this.objs; return t[e] && t[e].resolved ? t[e].data : null }, clear: function () { this.objs = Object.create(null) } }, e }(), M = function () { function e(e) { this._internalRenderTask = e, this.onContinue = null } return e.prototype = { get promise() { return this._internalRenderTask.capability.promise }, cancel: function () { this._internalRenderTask.cancel() }, then: function (e, t) { return this.promise.then.apply(this.promise, arguments) } }, e }(), D = function () { var e = new WeakMap; function t(e, t, r, n, i, a, o, u) { var l = arguments.length > 8 && void 0 !== arguments[8] && arguments[8]; this.callback = e, this.params = t, this.objs = r, this.commonObjs = n, this.operatorListIdx = null, this.operatorList = i, this.pageNumber = a, this.canvasFactory = o, this.webGLContext = u, this._pdfBug = l, this.running = !1, this.graphicsReadyCallback = null, this.graphicsReady = !1, this.useRequestAnimationFrame = !1, this.cancelled = !1, this.capability = (0, s.createPromiseCapability)(), this.task = new M(this), this._continueBound = this._continue.bind(this), this._scheduleNextBound = this._scheduleNext.bind(this), this._nextBound = this._next.bind(this), this._canvas = t.canvasContext.canvas } return t.prototype = { initializeGraphics: function (t) { if (!this.cancelled) { if (this._canvas) { if (e.has(this._canvas)) throw new Error("Cannot use the same canvas during multiple render() operations. Use different canvas or ensure previous operations we!
 re cancelled or completed."); e.set(this._canvas, this) } this._pdfBug && f.default.StepperManager && f.default.StepperManager.enabled && (this.stepper = f.default.StepperManager.create(this.pageNumber - 1), this.stepper.init(this.operatorList), this.stepper.nextBreakPoint = this.stepper.getNextBreakPoint()); var r = this.params; this.gfx = new h.CanvasGraphics(r.canvasContext, this.commonObjs, this.objs, this.canvasFactory, this.webGLContext, r.imageLayer), this.gfx.beginDrawing({ transform: r.transform, viewport: r.viewport, transparency: t, background: r.background }), this.operatorListIdx = 0, this.graphicsReady = !0, this.graphicsReadyCallback && this.graphicsReadyCallback() } }, cancel: function () { this.running = !1, this.cancelled = !0, this._canvas && e.delete(this._canvas), this.callback(new u.RenderingCancelledException("Rendering cancelled, page " + this.pageNumber, "canvas")) }, operatorListChanged: function () { this.graphicsReady ? (this.stepper && this.stepper.updateOperatorList(this.operatorList), this.running || this._continue()) : this.graphicsReadyCallback || (this.graphicsReadyCallback = this._continueBound) }, _continue: function () { this.running = !0, this.cancelled || (this.task.onContinue ? this.task.onContinue(this._scheduleNextBound) : this._scheduleNext()) }, _scheduleNext: function () { var e = this; this.useRequestAnimationFrame && "undefined" != typeof window ? window.requestAnimationFrame(function () { e._nextBound().catch(e.callback) }) : Promise.resolve().then(this._nextBound).catch(this.callback) }, _next: function () { var t = this; return new Promise(function () { t.cancelled || (t.operatorListIdx = t.gfx.executeOperatorList(t.operatorList, t.operatorListIdx, t._continueBound, t.stepper), t.operatorListIdx === t.operatorList.argsArray.length && (t.running = !1, t.operatorList.lastChunk && (t.gfx.endDrawing(), t._canvas && e.delete(t._canvas), t.callback()))) }) } }, t }(); t.version = "2.0.943", t.build = "dc98bf76", t.getDocument = function (e) { var t, r = new R; if ("str!
 ing" == typeof e) t = { url: e }; else if ((0, s.isArrayBuffer)(e)) t = { data: e }; else if (e instanceof E) t = { range: e }; else { if ("object" !== (void 0 === e ? "undefined" : o(e))) throw new Error("Invalid parameter in getDocument, need either Uint8Array, string or a parameter object"); if (!e.url && !e.data && !e.range) throw new Error("Invalid parameter object: need either .data, .range or .url"); t = e } var n = Object.create(null), i = null, a = null; for (var l in t) if ("url" !== l || "undefined" == typeof window) if ("range" !== l) if ("worker" !== l) if ("data" !== l || t[l] instanceof Uint8Array) n[l] = t[l]; else { var h = t[l]; if ("string" == typeof h) n[l] = (0, s.stringToBytes)(h); else if ("object" !== (void 0 === h ? "undefined" : o(h)) || null === h || isNaN(h.length)) { if (!(0, s.isArrayBuffer)(h)) throw new Error("Invalid PDF binary data: either typed array, string or array-like object is expected in the data property."); n[l] = new Uint8Array(h) } else n[l] = new Uint8Array(h) } else a = t[l]; else i = t[l]; else n[l] = new s.URL(t[l], window.location).href; n.rangeChunkSize = n.rangeChunkSize || _, n.CMapReaderFactory = n.CMapReaderFactory || u.DOMCMapReaderFactory, n.ignoreErrors = !0 !== n.stopAtErrors, n.pdfBug = !0 === n.pdfBug; var d = Object.values(s.NativeImageDecoding); if (void 0 !== n.nativeImageDecoderSupport && d.includes(n.nativeImageDecoderSupport) || (n.nativeImageDecoderSupport = c.apiCompatibilityParams.nativeImageDecoderSupport || s.NativeImageDecoding.DECODE), Number.isInteger(n.maxImageSize) || (n.maxImageSize = -1), "boolean" != typeof n.isEvalSupported && (n.isEvalSupported = !0), "boolean" != typeof n.disableFontFace && (n.disableFontFace = c.apiCompatibilityParams.disableFontFace || !1), "boolean" != typeof n.disableRange && (n.disableRange = !1), "boolean" != typeof n.disableStream && (n.disableStream = !1), "boolean" != typeof n.disableAutoFetch && (n.disableAutoFetch = !1), "boolean" != typeof n.disableCreateObjectURL && (n.disableCreateObjectURL = c.apiCo!
 mpatibilityParams.disableCreateObjectURL || !1), (0, s.setVerbosityLevel)(n.verbosity), !a) { var f = { postMessageTransfers: n.postMessageTransfers, verbosity: n.verbosity }, m = p.GlobalWorkerOptions.workerPort; m ? (f.port = m, a = F.fromPort(f)) : a = new F(f), r._worker = a } var y = r.docId; return a.promise.then(function () { if (r.destroyed) throw new Error("Loading aborted"); return function (e, t, r, n) { return e.destroyed ? Promise.reject(new Error("Worker was destroyed")) : (r && (t.length = r.length, t.initialData = r.initialData), e.messageHandler.sendWithPromise("GetDocRequest", { docId: n, apiVersion: "2.0.943", source: { data: t.data, url: t.url, password: t.password, disableAutoFetch: t.disableAutoFetch, rangeChunkSize: t.rangeChunkSize, length: t.length }, maxImageSize: t.maxImageSize, disableFontFace: t.disableFontFace, disableCreateObjectURL: t.disableCreateObjectURL, postMessageTransfers: e.postMessageTransfers, docBaseUrl: t.docBaseUrl, nativeImageDecoderSupport: t.nativeImageDecoderSupport, ignoreErrors: t.ignoreErrors, isEvalSupported: t.isEvalSupported }).then(function (t) { if (e.destroyed) throw new Error("Worker was destroyed"); return t })) }(a, n, i, y).then(function (e) { if (r.destroyed) throw new Error("Loading aborted"); var t = void 0; i ? t = new g.PDFDataTransportStream({ length: n.length, initialData: n.initialData, disableRange: n.disableRange, disableStream: n.disableStream }, i) : n.data || (t = P({ url: n.url, length: n.length, httpHeaders: n.httpHeaders, withCredentials: n.withCredentials, rangeChunkSize: n.rangeChunkSize, disableRange: n.disableRange, disableStream: n.disableStream })); var o = new v.MessageHandler(y, e, a.port); o.postMessageTransfers = a.postMessageTransfers; var s = new L(o, r, t, n); r._transport = s, o.send("Ready", null) }) }).catch(r._capability.reject), r }, t.LoopbackPort = I, t.PDFDataRangeTransport = E, t.PDFWorker = F, t.PDFDocumentProxy = T, t.PDFPageProxy = O, t.setPDFNetworkStreamFactory = function (e) { P = e }, t.version = "2.0.943",!
  t.build = "dc98bf76" }, function (e, t, r) { "use strict"; Object.defineProperty(t, "__esModule", { value: !0 }), t.loadScript = t.DummyStatTimer = t.StatTimer = t.DOMSVGFactory = t.DOMCMapReaderFactory = t.DOMCanvasFactory = t.DEFAULT_LINK_REL = t.LinkTarget = t.getFilenameFromUrl = t.addLinkAttributes = t.RenderingCancelledException = t.PageViewport = void 0; var n = function () { function e(e, t) { for (var r = 0; r < t.length; r++) { var n = t[r]; n.enumerable = n.enumerable || !1, n.configurable = !0, "value" in n && (n.writable = !0), Object.defineProperty(e, n.key, n) } } return function (t, r, n) { return r && e(t.prototype, r), n && e(t, n), t } }(), i = r(1); function a(e, t) { if (!(e instanceof t)) throw new TypeError("Cannot call a class as a function") } var o = "noopener noreferrer nofollow", s = "http://www.w3.org/2000/svg", u = function () { function e() { a(this, e) } return n(e, [{ key: "create", value: function (e, t) { if (e <= 0 || t <= 0) throw new Error("invalid canvas size"); var r = document.createElement("canvas"), n = r.getContext("2d"); return r.width = e, r.height = t, { canvas: r, context: n } } }, { key: "reset", value: function (e, t, r) { if (!e.canvas) throw new Error("canvas is not specified"); if (t <= 0 || r <= 0) throw new Error("invalid canvas size"); e.canvas.width = t, e.canvas.height = r } }, { key: "destroy", value: function (e) { if (!e.canvas) throw new Error("canvas is not specified"); e.canvas.width = 0, e.canvas.height = 0, e.canvas = null, e.context = null } }]), e }(), l = function () { function e(t) { var r = t.baseUrl, n = void 0 === r ? null : r, i = t.isCompressed, o = void 0 !== i && i; a(this, e), this.baseUrl = n, this.isCompressed = o } return n(e, [{ key: "fetch", value: function (e) { var t = this, r = e.name; return this.baseUrl ? r ? new Promise(function (e, n) { var a = t.baseUrl + r + (t.isCompressed ? ".bcmap" : ""), o = new XMLHttpRequest; o.open("GET", a, !0), t.isCompressed && (o.responseType = "arraybuffer"), o.onreadystatechange = function (!
 ) { if (o.readyState === XMLHttpRequest.DONE) { if (200 === o.status || 0 === o.status) { var r = void 0; if (t.isCompressed && o.response ? r = new Uint8Array(o.response) : !t.isCompressed && o.responseText && (r = (0, i.stringToBytes)(o.responseText)), r) return void e({ cMapData: r, compressionType: t.isCompressed ? i.CMapCompressionType.BINARY : i.CMapCompressionType.NONE }) } n(new Error("Unable to load " + (t.isCompressed ? "binary " : "") + "CMap at: " + a)) } }, o.send(null) }) : Promise.reject(new Error("CMap name must be specified.")) : Promise.reject(new Error('The CMap "baseUrl" parameter must be specified, ensure that the "cMapUrl" and "cMapPacked" API parameters are provided.')) } }]), e }(), c = function () { function e() { a(this, e) } return n(e, [{ key: "create", value: function (e, t) { (0, i.assert)(e > 0 && t > 0, "Invalid SVG dimensions"); var r = document.createElementNS(s, "svg:svg"); return r.setAttribute("version", "1.1"), r.setAttribute("width", e + "px"), r.setAttribute("height", t + "px"), r.setAttribute("preserveAspectRatio", "none"), r.setAttribute("viewBox", "0 0 " + e + " " + t), r } }, { key: "createElement", value: function (e) { return (0, i.assert)("string" == typeof e, "Invalid SVG element type"), document.createElementNS(s, e) } }]), e }(), h = function () { function e(t) { var r = t.viewBox, n = t.scale, i = t.rotation, o = t.offsetX, s = void 0 === o ? 0 : o, u = t.offsetY, l = void 0 === u ? 0 : u, c = t.dontFlip, h = void 0 !== c && c; a(this, e), this.viewBox = r, this.scale = n, this.rotation = i, this.offsetX = s, this.offsetY = l; var d = (r[2] + r[0]) / 2, f = (r[3] + r[1]) / 2, p = void 0, v = void 0, m = void 0, g = void 0; switch (i = (i %= 360) < 0 ? i + 360 : i) { case 180: p = -1, v = 0, m = 0, g = 1; break; case 90: p = 0, v = 1, m = 1, g = 0; break; case 270: p = 0, v = -1, m = -1, g = 0; break; default: p = 1, v = 0, m = 0, g = -1 }h && (m = -m, g = -g); var y = void 0, b = void 0, _ = void 0, A = void 0; 0 === p ? (y = Math.abs(f - r[1]) * n + s, b = Math!
 .abs(d - r[0]) * n + l, _ = Math.abs(r[3] - r[1]) * n, A = Math.abs(r[2] - r[0]) * n) : (y = Math.abs(d - r[0]) * n + s, b = Math.abs(f - r[1]) * n + l, _ = Math.abs(r[2] - r[0]) * n, A = Math.abs(r[3] - r[1]) * n), this.transform = [p * n, v * n, m * n, g * n, y - p * n * d - m * n * f, b - v * n * d - g * n * f], this.width = _, this.height = A } return n(e, [{ key: "clone", value: function () { var t = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {}, r = t.scale, n = void 0 === r ? this.scale : r, i = t.rotation, a = void 0 === i ? this.rotation : i, o = t.dontFlip, s = void 0 !== o && o; return new e({ viewBox: this.viewBox.slice(), scale: n, rotation: a, offsetX: this.offsetX, offsetY: this.offsetY, dontFlip: s }) } }, { key: "convertToViewportPoint", value: function (e, t) { return i.Util.applyTransform([e, t], this.transform) } }, { key: "convertToViewportRectangle", value: function (e) { var t = i.Util.applyTransform([e[0], e[1]], this.transform), r = i.Util.applyTransform([e[2], e[3]], this.transform); return [t[0], t[1], r[0], r[1]] } }, { key: "convertToPdfPoint", value: function (e, t) { return i.Util.applyInverseTransform([e, t], this.transform) } }]), e }(), d = function () { function e(e, t) { this.message = e, this.type = t } return e.prototype = new Error, e.prototype.name = "RenderingCancelledException", e.constructor = e, e }(), f = { NONE: 0, SELF: 1, BLANK: 2, PARENT: 3, TOP: 4 }, p = ["", "_self", "_blank", "_parent", "_top"]; var v = function () { function e() { var t = !(arguments.length > 0 && void 0 !== arguments[0]) || arguments[0]; a(this, e), this.enabled = !!t, this.started = Object.create(null), this.times = [] } return n(e, [{ key: "time", value: function (e) { this.enabled && (e in this.started && (0, i.warn)("Timer is already running for " + e), this.started[e] = Date.now()) } }, { key: "timeEnd", value: function (e) { this.enabled && (e in this.started || (0, i.warn)("Timer has not been started for " + e), this.times.push({ name: e, start: this.started[e], e!
 nd: Date..now() }), delete this.started[e]) } }, { key: "toString", value: function () { for (var e = this.times, t = "", r = 0, n = 0, i = e.length; n < i; ++n) { var a = e[n].name; a.length > r && (r = a.length) } for (var o = 0, s = e.length; o < s; ++o) { var u = e[o], l = u.end - u.start; t += u.name.padEnd(r) + " " + l + "ms\n" } return t } }]), e }(), m = function () { function e() { a(this, e), (0, i.unreachable)("Cannot initialize DummyStatTimer.") } return n(e, null, [{ key: "time", value: function (e) { } }, { key: "timeEnd", value: function (e) { } }, { key: "toString", value: function () { return "" } }]), e }(); t.PageViewport = h, t.RenderingCancelledException = d, t.addLinkAttributes = function (e) { var t = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : {}, r = t.url, n = t.target, a = t.rel; if (e.href = e.title = r ? (0, i.removeNullCharacters)(r) : "", r) { var s = Object.values(f).includes(n) ? n : f.NONE; e.target = p[s], e.rel = "string" == typeof a ? a : o } }, t.getFilenameFromUrl = function (e) { var t = e.indexOf("#"), r = e.indexOf("?"), n = Math.min(t > 0 ? t : e.length, r > 0 ? r : e.length); return e.substring(e.lastIndexOf("/", n) + 1, n) }, t.LinkTarget = f, t.DEFAULT_LINK_REL = o, t.DOMCanvasFactory = u, t.DOMCMapReaderFactory = l, t.DOMSVGFactory = c, t.StatTimer = v, t.DummyStatTimer = m, t.loadScript = function (e) { return new Promise(function (t, r) { var n = document.createElement("script"); n.src = e, n.onload = t, n.onerror = function () { r(new Error("Cannot load script at: " + n.src)) }, (document.head || document.documentElement).appendChild(n) }) } }, function (e, t, r) { "use strict"; Object.defineProperty(t, "__esModule", { value: !0 }), t.FontLoader = t.FontFaceObject = void 0; var n = function () { function e(e, t) { for (var r = 0; r < t.length; r++) { var n = t[r]; n.enumerable = n.enumerable || !1, n.configurable = !0, "value" in n && (n.writable = !0), Object.defineProperty(e, n.key, n) } } return function (t, r, n) { return r && e(t.prototyp!
 e, r), n && e(t, n), t } }(), i = r(1); function a(e, t) { if (!(e instanceof t)) throw new TypeError("Cannot call a class as a function") } var o, s = function () { function e(t) { a(this, e), this.constructor === e && (0, i.unreachable)("Cannot initialize BaseFontLoader."), this.docId = t, this.nativeFontFaces = [], this.styleElement = null, this.loadingContext = { requests: [], nextRequestId: 0 } } return n(e, [{ key: "addNativeFontFace", value: function (e) { this.nativeFontFaces.push(e), document.fonts.add(e) } }, { key: "insertRule", value: function (e) { var t = this.styleElement; t || ((t = this.styleElement = document.createElement("style")).id = "PDFJS_FONT_STYLE_TAG_" + this.docId, document.documentElement.getElementsByTagName("head")[0].appendChild(t)); var r = t.sheet; r.insertRule(e, r.cssRules.length) } }, { key: "clear", value: function () { this.nativeFontFaces.forEach(function (e) { document.fonts.delete(e) }), this.nativeFontFaces.length = 0, this.styleElement && (this.styleElement.remove(), this.styleElement = null) } }, { key: "bind", value: function (e, t) { var r = [], n = [], a = [], o = function (e) { return e.loaded.catch(function (t) { (0, i.warn)('Failed to load font "' + e.family + '": ' + t) }) }, s = !0, u = !1, l = void 0; try { for (var c, h = e[Symbol.iterator](); !(s = (c = h.next()).done); s = !0) { var d = c.value; if (!d.attached && !d.missingFile) if (d.attached = !0, this.isFontLoadingAPISupported) { var f = d.createNativeFontFace(); f && (this.addNativeFontFace(f), a.push(o(f))) } else { var p = d.createFontFaceRule(); p && (this.insertRule(p), r.push(p), n.push(d)) } } } catch (e) { u = !0, l = e } finally { try { !s && h.return && h.return() } finally { if (u) throw l } } var v = this._queueLoadingCallback(t); this.isFontLoadingAPISupported ? Promise.all(a).then(v.complete) : r.length > 0 && !this.isSyncFontLoadingSupported ? this._prepareFontLoadEvent(r, n, v) : v.complete() } }, { key: "_queueLoadingCallback", value: function (e) { var t = this.loadingContext, r = { i!
 d: "pdfjs-font-loading-" + t.nextRequestId++, done: !1, complete: function () { for ((0, i.assert)(!r.done, "completeRequest() cannot be called twice."), r.done = !0; t.requests.length > 0 && t.requests[0].done;) { var e = t.requests.shift(); setTimeout(e.callback, 0) } }, callback: e }; return t.requests.push(r), r } }, { key: "_prepareFontLoadEvent", value: function (e, t, r) { (0, i.unreachable)("Abstract method `_prepareFontLoadEvent`.") } }, { key: "isFontLoadingAPISupported", get: function () { (0, i.unreachable)("Abstract method `isFontLoadingAPISupported`.") } }, { key: "isSyncFontLoadingSupported", get: function () { (0, i.unreachable)("Abstract method `isSyncFontLoadingSupported`.") } }, { key: "_loadTestFont", get: function () { (0, i.unreachable)("Abstract method `_loadTestFont`.") } }]), e }(); t.FontLoader = o = function (e) { function t(e) { a(this, t); var r = function (e, t) { if (!e) throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); return !t || "object" != typeof t && "function" != typeof t ? e : t }(this, (t.__proto__ || Object.getPrototypeOf(t)).call(this, e)); return r.loadTestFontId = 0, r } return function (e, t) { if ("function" != typeof t && null !== t) throw new TypeError("Super expression must either be null or a function, not " + typeof t); e.prototype = Object.create(t && t.prototype, { constructor: { value: e, enumerable: !1, writable: !0, configurable: !0 } }), t && (Object.setPrototypeOf ? Object.setPrototypeOf(e, t) : e.__proto__ = t) }(t, s), n(t, [{ key: "_prepareFontLoadEvent", value: function (e, t, r) { function n(e, t) { return e.charCodeAt(t) << 24 | e.charCodeAt(t + 1) << 16 | e.charCodeAt(t + 2) << 8 | 255 & e.charCodeAt(t + 3) } function a(e, t, r, n) { return e.substring(0, t) + n + e.substring(t + r) } var o = void 0, s = void 0, u = document.createElement("canvas"); u.width = 1, u.height = 1; var l = u.getContext("2d"), c = 0; var h = "lt" + Date.now() + this.loadTestFontId++, d = this._loadTestFont, f = n(d = a(d, 976, h.length!
 , h), 16); for (o = 0, s = h.length - 3; o < s; o += 4)f = f - 1482184792 + n(h, o) | 0; o < h.length && (f = f - 1482184792 + n(h + "XXX", o) | 0), d = a(d, 16, 4, (0, i.string32)(f)); var p = '@font-face {font-family:"' + h + '";src:' + ("url(data:font/opentype;base64," + btoa(d) + ");") + "}"; this.insertRule(p); var v = []; for (o = 0, s = t.length; o < s; o++)v.push(t[o].loadedName); v.push(h); var m = document.createElement("div"); for (m.setAttribute("style", "visibility: hidden;width: 10px; height: 10px;position: absolute; top: 0px; left: 0px;"), o = 0, s = v.length; o < s; ++o) { var g = document.createElement("span"); g.textContent = "Hi", g.style.fontFamily = v[o], m.appendChild(g) } document.body.appendChild(m), function e(t, r) { if (++c > 30) return (0, i.warn)("Load test font never loaded."), void r(); l.font = "30px " + t, l.fillText(".", 0, 20), l.getImageData(0, 0, 1, 1).data[3] > 0 ? r() : setTimeout(e.bind(null, t, r)) }(h, function () { document.body.removeChild(m), r.complete() }) } }, { key: "isFontLoadingAPISupported", get: function () { var e = "undefined" != typeof document && !!document.fonts; if (e && "undefined" != typeof navigator) { var t = /Mozilla\/5.0.*?rv:(\d+).*? Gecko/.exec(navigator.userAgent); t && t[1] < 63 && (e = !1) } return (0, i.shadow)(this, "isFontLoadingAPISupported", e) } }, { key: "isSyncFontLoadingSupported", get: function () { var e = !1; if ("undefined" == typeof navigator) e = !0; else { var t = /Mozilla\/5.0.*?rv:(\d+).*? Gecko/.exec(navigator.userAgent); t && t[1] >= 14 && (e = !0) } return (0, i.shadow)(this, "isSyncFontLoadingSupported", e) } }, { key: "_loadTestFont", get: function () { return (0, i.shadow)(this, "_loadTestFont", atob("T1RUTwALAIAAAwAwQ0ZGIDHtZg4AAAOYAAAAgUZGVE1lkzZwAAAEHAAAABxHREVGABQAFQAABDgAAAAeT1MvMlYNYwkAAAEgAAAAYGNtYXABDQLUAAACNAAAAUJoZWFk/xVFDQAAALwAAAA2aGhlYQdkA+oAAAD0AAAAJGhtdHgD6AAAAAAEWAAAAAZtYXhwAAJQAAAAARgAAAAGbmFtZVjmdH4AAAGAAAAAsXBvc3T/hgAzAAADeAAAACAAAQAAAAEAALZRFsRfDzz1AAsD6AAAAADOBOTLAAAAAM4KHDwAAAAAA+gDIQAAAAgAAgAAAAAA!
 AAABAAADIQAAAFoD6AAAAAAD6AABAAAAAAAAAAAAAAAAAAAAAQAAUAAAAgAAAAQD6AH0AAUAAAKKArwAAACMAooCvAAAAeAAMQECAAACAAYJAAAAAAAAAAAAAQAAAAAAAAAAAAAAAFBmRWQAwAAuAC4DIP84AFoDIQAAAAAAAQAAAAAAAAAAACAAIAABAAAADgCuAAEAAAAAAAAAAQAAAAEAAAAAAAEAAQAAAAEAAAAAAAIAAQAAAAEAAAAAAAMAAQAAAAEAAAAAAAQAAQAAAAEAAAAAAAUAAQAAAAEAAAAAAAYAAQAAAAMAAQQJAAAAAgABAAMAAQQJAAEAAgABAAMAAQQJAAIAAgABAAMAAQQJAAMAAgABAAMAAQQJAAQAAgABAAMAAQQJAAUAAgABAAMAAQQJAAYAAgABWABYAAAAAAAAAwAAAAMAAAAcAAEAAAAAADwAAwABAAAAHAAEACAAAAAEAAQAAQAAAC7//wAAAC7////TAAEAAAAAAAABBgAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMAAAAAAAD/gwAyAAAAAQAAAAAAAAAAAAAAAAAAAAABAAQEAAEBAQJYAAEBASH4DwD4GwHEAvgcA/gXBIwMAYuL+nz5tQXkD5j3CBLnEQACAQEBIVhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYAAABAQAADwACAQEEE/t3Dov6fAH6fAT+fPp8+nwHDosMCvm1Cvm1DAz6fBQAAAAAAAABAAAAAMmJbzEAAAAAzgTjFQAAAADOBOQpAAEAAAAAAAAADAAUAAQAAAABAAAAAgABAAAAAAAAAAAD6AAAAAAAAA==")) } }]), t }(); var u = { get value() { return (0, i.shadow)(this, "value", (0, i.isEvalSupported)()) } }, l = function () { function e(t, r) { var n = r.isEvalSupported, i = void 0 === n || n, o = r.disableFontFace, s = void 0 !== o && o, u = r.ignoreErrors, l = void 0 !== u && u, c = r.onUnsupportedFeature, h = void 0 === c ? null : c, d = r.fontRegistry, f = void 0 === d ? null : d; for (var p in a(this, e), this.compiledGlyphs = Object.create(null), t) this[p] = t[p]; this.isEvalSupported = !1 !== i, this.disableFontFace = !0 === s, this.ignoreErrors = !0 === l, this._onUnsupportedFeature = h, this.fontRegistry = f } return n(e, [{ key: "createNativeFontFace", value: function () { if (!this.data || this.disableFontFace) return null; var e = new FontFace(this.loadedName, this.data, {}); return this.fontRegistry && this.fontRegistry.registerFont(this), e } },!
  { key: "createFontFaceRule", value: function () { if (!this.data || this.disableFontFace) return null; var e = (0, i.bytesToString)(new Uint8Array(this.data)), t = "url(data:" + this.mimetype + ";base64," + btoa(e) + ");", r = '@font-face {font-family:"' + this.loadedName + '";src:' + t + "}"; return this.fontRegistry && this.fontRegistry.registerFont(this, t), r } }, { key: "getPathGenerator", value: function (e, t) { if (void 0 !== this.compiledGlyphs[t]) return this.compiledGlyphs[t]; var r = void 0, n = void 0; try { r = e.get(this.loadedName + "_path_" + t) } catch (e) { if (!this.ignoreErrors) throw e; return this._onUnsupportedFeature && this._onUnsupportedFeature({ featureId: i.UNSUPPORTED_FEATURES.font }), (0, i.warn)('getPathGenerator - ignoring character: "' + e + '".'), this.compiledGlyphs[t] = function (e, t) { } } if (this.isEvalSupported && u.value) { for (var a = void 0, o = "", s = 0, l = r.length; s < l; s++)a = void 0 !== (n = r[s]).args ? n.args.join(",") : "", o += "c." + n.cmd + "(" + a + ");\n"; return this.compiledGlyphs[t] = new Function("c", "size", o) } return this.compiledGlyphs[t] = function (e, t) { for (var i = 0, a = r.length; i < a; i++)"scale" === (n = r[i]).cmd && (n.args = [t, -t]), e[n.cmd].apply(e, n.args) } } }]), e }(); t.FontFaceObject = l, t.FontLoader = o }, function (e, t, r) { "use strict"; var n = Object.create(null), i = r(4), a = "undefined" != typeof navigator && navigator.userAgent || "", o = /Trident/.test(a), s = /CriOS/.test(a); (o || s) && (n.disableCreateObjectURL = !0), i() && (n.disableFontFace = !0, n.nativeImageDecoderSupport = "none"), t.apiCompatibilityParams = Object.freeze(n) }, function (e, t, r) { "use strict"; Object.defineProperty(t, "__esModule", { value: !0 }), t.CanvasGraphics = void 0; var n = r(1), i = r(134), a = 16, o = { get value() { return (0, n.shadow)(o, "value", (0, n.isLittleEndian)()) } }; function s(e) { e.mozCurrentTransform || (e._originalSave = e.save, e._originalRestore = e.restore, e._originalRotate = e.rotate, e._originalSc!
 ale = e.scale, e._originalTranslate = e.translate, e._originalTransform = e.transform, e._originalSetTransform = e.setTransform, e._transformMatrix = e._transformMatrix || [1, 0, 0, 1, 0, 0], e._transformStack = [], Object.defineProperty(e, "mozCurrentTransform", { get: function () { return this._transformMatrix } }), Object.defineProperty(e, "mozCurrentTransformInverse", { get: function () { var e = this._transformMatrix, t = e[0], r = e[1], n = e[2], i = e[3], a = e[4], o = e[5], s = t * i - r * n, u = r * n - t * i; return [i / s, r / u, n / u, t / s, (i * a - n * o) / u, (r * a - t * o) / s] } }), e.save = function () { var e = this._transformMatrix; this._transformStack.push(e), this._transformMatrix = e.slice(0, 6), this._originalSave() }, e.restore = function () { var e = this._transformStack.pop(); e && (this._transformMatrix = e, this._originalRestore()) }, e.translate = function (e, t) { var r = this._transformMatrix; r[4] = r[0] * e + r[2] * t + r[4], r[5] = r[1] * e + r[3] * t + r[5], this._originalTranslate(e, t) }, e.scale = function (e, t) { var r = this._transformMatrix; r[0] = r[0] * e, r[1] = r[1] * e, r[2] = r[2] * t, r[3] = r[3] * t, this._originalScale(e, t) }, e.transform = function (t, r, n, i, a, o) { var s = this._transformMatrix; this._transformMatrix = [s[0] * t + s[2] * r, s[1] * t + s[3] * r, s[0] * n + s[2] * i, s[1] * n + s[3] * i, s[0] * a + s[2] * o + s[4], s[1] * a + s[3] * o + s[5]], e._originalTransform(t, r, n, i, a, o) }, e.setTransform = function (t, r, n, i, a, o) { this._transformMatrix = [t, r, n, i, a, o], e._originalSetTransform(t, r, n, i, a, o) }, e.rotate = function (e) { var t = Math.cos(e), r = Math.sin(e), n = this._transformMatrix; this._transformMatrix = [n[0] * t + n[2] * r, n[1] * t + n[3] * r, n[0] * -r + n[2] * t, n[1] * -r + n[3] * t, n[4], n[5]], this._originalRotate(e) }) } var u = function () { function e(e) { this.canvasFactory = e, this.cache = Object.create(null) } return e.prototype = { getCanvas: function (e, t, r, n) { var i; return void 0 !== thi!
 s.cache[e] ? (i = this.cache[e], this.canvasFactory.reset(i, t, r), i.context.setTransform(1, 0, 0, 1, 0, 0)) : (i = this.canvasFactory.create(t, r), this.cache[e] = i), n && s(i.context), i }, clear: function () { for (var e in this.cache) { var t = this.cache[e]; this.canvasFactory.destroy(t), delete this.cache[e] } } }, e }(); var l = function () { function e() { this.alphaIsShape = !1, this.fontSize = 0, this.fontSizeScale = 1, this.textMatrix = n.IDENTITY_MATRIX, this.textMatrixScale = 1, this.fontMatrix = n.FONT_IDENTITY_MATRIX, this.leading = 0, this.x = 0, this.y = 0, this.lineX = 0, this.lineY = 0, this.charSpacing = 0, this.wordSpacing = 0, this.textHScale = 1, this.textRenderingMode = n.TextRenderingMode.FILL, this.textRise = 0, this.fillColor = "#000000", this.strokeColor = "#000000", this.patternFill = !1, this.fillAlpha = 1, this.strokeAlpha = 1, this.lineWidth = 1, this.activeSMask = null, this.resumeSMaskCtx = null } return e.prototype = { clone: function () { return Object.create(this) }, setCurrentPoint: function (e, t) { this.x = e, this.y = t } }, e }(), c = function () { function e(e, t, r, n, i, a) { this.ctx = e, this.current = new l, this.stateStack = [], this.pendingClip = null, this.pendingEOFill = !1, this.res = null, this.xobjs = null, this.commonObjs = t, this.objs = r, this.canvasFactory = n, this.webGLContext = i, this.imageLayer = a, this.groupStack = [], this.processingType3 = null, this.baseTransform = null, this.baseTransformStack = [], this.groupLevel = 0, this.smaskStack = [], this.smaskCounter = 0, this.tempSMask = null, this.cachedCanvases = new u(this.canvasFactory), e && s(e), this._cachedGetSinglePixelWidth = null } function t(e, t) { if ("undefined" != typeof ImageData && t instanceof ImageData) e.putImageData(t, 0, 0); else { var r, i, s, u, l, c = t.height, h = t.width, d = c % a, f = (c - d) / a, p = 0 === d ? f : f + 1, v = e.createImageData(h, a), m = 0, g = t.data, y = v.data; if (t.kind === n.ImageKind.GRAYSCALE_1BPP) { var b = g.byteLength, _ = new Uint32Array(y!
 .buffer, 0, y.byteLength >> 2), A = _.length, S = h + 7 >> 3, w = 4294967295, k = o.value ? 4278190080 : 255; for (i = 0; i < p; i++) { for (u = i < f ? a : d, r = 0, s = 0; s < u; s++) { for (var P = b - m, x = 0, C = P > S ? h : 8 * P - 7, R = -8 & C, E = 0, T = 0; x < R; x += 8)T = g[m++], _[r++] = 128 & T ? w : k, _[r++] = 64 & T ? w : k, _[r++] = 32 & T ? w : k, _[r++] = 16 & T ? w : k, _[r++] = 8 & T ? w : k, _[r++] = 4 & T ? w : k, _[r++] = 2 & T ? w : k, _[r++] = 1 & T ? w : k; for (; x < C; x++)0 === E && (T = g[m++], E = 128), _[r++] = T & E ? w : k, E >>= 1 } for (; r < A;)_[r++] = 0; e.putImageData(v, 0, i * a) } } else if (t.kind === n.ImageKind.RGBA_32BPP) { for (s = 0, l = h * a * 4, i = 0; i < f; i++)y.set(g.subarray(m, m + l)), m += l, e.putImageData(v, 0, s), s += a; i < p && (l = h * d * 4, y.set(g.subarray(m, m + l)), e.putImageData(v, 0, s)) } else { if (t.kind !== n.ImageKind.RGB_24BPP) throw new Error("bad image kind: " + t.kind); for (l = h * (u = a), i = 0; i < p; i++) { for (i >= f && (l = h * (u = d)), r = 0, s = l; s--;)y[r++] = g[m++], y[r++] = g[m++], y[r++] = g[m++], y[r++] = 255; e.putImageData(v, 0, i * a) } } } } function r(e, t) { for (var r = t.height, n = t.width, i = r % a, o = (r - i) / a, s = 0 === i ? o : o + 1, u = e.createImageData(n, a), l = 0, c = t.data, h = u.data, d = 0; d < s; d++) { for (var f = d < o ? a : i, p = 3, v = 0; v < f; v++)for (var m = 0, g = 0; g < n; g++) { if (!m) { var y = c[l++]; m = 128 } h[p] = y & m ? 0 : 255, p += 4, m >>= 1 } e.putImageData(u, 0, d * a) } } function c(e, t) { for (var r = ["strokeStyle", "fillStyle", "fillRule", "globalAlpha", "lineWidth", "lineCap", "lineJoin", "miterLimit", "globalCompositeOperation", "font"], n = 0, i = r.length; n < i; n++) { var a = r[n]; void 0 !== e[a] && (t[a] = e[a]) } void 0 !== e.setLineDash && (t.setLineDash(e.getLineDash()), t.lineDashOffset = e.lineDashOffset) } function h(e) { e.strokeStyle = "#000000", e.fillStyle = "#000000", e.fillRule = "nonzero", e.globalAlpha = 1, e.lineWidth = 1, e.line!
 Cap = "butt", e.lineJoin = "miter", e.miterLimit = 10, e.globalCompositeOperation = "source-over", e.font = "10px sans-serif", void 0 !== e.setLineDash && (e.setLineDash([]), e.lineDashOffset = 0) } function d(e, t, r, n) { for (var i = e.length, a = 3; a < i; a += 4) { var o = e[a]; if (0 === o) e[a - 3] = t, e[a - 2] = r, e[a - 1] = n; else if (o < 255) { var s = 255 - o; e[a - 3] = e[a - 3] * o + t * s >> 8, e[a - 2] = e[a - 2] * o + r * s >> 8, e[a - 1] = e[a - 1] * o + n * s >> 8 } } } function f(e, t, r) { for (var n = e.length, i = 3; i < n; i += 4) { var a = r ? r[e[i]] : e[i]; t[i] = t[i] * a * (1 / 255) | 0 } } function p(e, t, r) { for (var n = e.length, i = 3; i < n; i += 4) { var a = 77 * e[i - 3] + 152 * e[i - 2] + 28 * e[i - 1]; t[i] = r ? t[i] * r[a >> 8] >> 8 : t[i] * a >> 16 } } function v(e, t, r, n) { var i = t.canvas, a = t.context; e.setTransform(t.scaleX, 0, 0, t.scaleY, t.offsetX, t.offsetY); var o = t.backdrop || null; if (!t.transferMap && n.isEnabled) { var s = n.composeSMask({ layer: r.canvas, mask: i, properties: { subtype: t.subtype, backdrop: o } }); return e.setTransform(1, 0, 0, 1, 0, 0), void e.drawImage(s, t.offsetX, t.offsetY) } !function (e, t, r, n, i, a, o) { var s, u = !!a, l = u ? a[0] : 0, c = u ? a[1] : 0, h = u ? a[2] : 0; s = "Luminosity" === i ? p : f; for (var v = Math.min(n, Math.ceil(1048576 / r)), m = 0; m < n; m += v) { var g = Math.min(v, n - m), y = e.getImageData(0, m, r, g), b = t.getImageData(0, m, r, g); u && d(y.data, l, c, h), s(y.data, b.data, o), e.putImageData(b, 0, m) } }(a, r, i.width, i.height, t.subtype, o, t.transferMap), e.drawImage(i, 0, 0) } var m = ["butt", "round", "square"], g = ["miter", "round", "bevel"], y = {}, b = {}; for (var _ in e.prototype = { beginDrawing: function (e) { var t = e.transform, r = e.viewport, n = e.transparency, i = e.background, a = void 0 === i ? null : i, o = this.ctx.canvas.width, s = this.ctx.canvas.height; if (this.ctx.save(), this.ctx.fillStyle = a || "rgb(255, 255, 255)", this.ctx.fillRect(0, 0, o, s), this.!
 ctx.restore(), n) { var u = this.cachedCanvases.getCanvas("transparent", o, s, !0); this.compositeCtx = this.ctx, this.transparentCanvas = u.canvas, this.ctx = u.context, this.ctx.save(), this.ctx.transform.apply(this.ctx, this.compositeCtx.mozCurrentTransform) } this.ctx.save(), h(this.ctx), t && this.ctx.transform.apply(this.ctx, t), this.ctx.transform.apply(this.ctx, r.transform), this.baseTransform = this.ctx.mozCurrentTransform.slice(), this.imageLayer && this.imageLayer.beginLayout() }, executeOperatorList: function (e, t, r, i) { var a = e.argsArray, o = e.fnArray, s = t || 0, u = a.length; if (u === s) return s; for (var l, c = u - s > 10 && "function" == typeof r, h = c ? Date.now() + 15 : 0, d = 0, f = this.commonObjs, p = this.objs; ;) { if (void 0 !== i && s === i.nextBreakPoint) return i.breakIt(s, r), s; if ((l = o[s]) !== n.OPS.dependency) this[l].apply(this, a[s]); else for (var v = a[s], m = 0, g = v.length; m < g; m++) { var y = v[m], b = "g" === y[0] && "_" === y[1] ? f : p; if (!b.isResolved(y)) return b.get(y, r), s } if (++s === u) return s; if (c && ++d > 10) { if (Date.now() > h) return r(), s; d = 0 } } }, endDrawing: function () { null !== this.current.activeSMask && this.endSMaskGroup(), this.ctx.restore(), this.transparentCanvas && (this.ctx = this.compositeCtx, this.ctx.save(), this.ctx.setTransform(1, 0, 0, 1, 0, 0), this.ctx.drawImage(this.transparentCanvas, 0, 0), this.ctx.restore(), this.transparentCanvas = null), this.cachedCanvases.clear(), this.webGLContext.clear(), this.imageLayer && this.imageLayer.endLayout() }, setLineWidth: function (e) { this.current.lineWidth = e, this.ctx.lineWidth = e }, setLineCap: function (e) { this.ctx.lineCap = m[e] }, setLineJoin: function (e) { this.ctx.lineJoin = g[e] }, setMiterLimit: function (e) { this.ctx.miterLimit = e }, setDash: function (e, t) { var r = this.ctx; void 0 !== r.setLineDash && (r.setLineDash(e), r.lineDashOffset = t) }, setRenderingIntent: function (e) { }, setFlatness: function (e) { }, setGState: function (e) { for (var!
  t = 0, r = e.length; t < r; t++) { var n = e[t], i = n[0], a = n[1]; switch (i) { case "LW": this.setLineWidth(a); break; case "LC": this.setLineCap(a); break; case "LJ": this.setLineJoin(a); break; case "ML": this.setMiterLimit(a); break; case "D": this.setDash(a[0], a[1]); break; case "RI": this.setRenderingIntent(a); break; case "FL": this.setFlatness(a); break; case "Font": this.setFont(a[0], a[1]); break; case "CA": this.current.strokeAlpha = n[1]; break; case "ca": this.current.fillAlpha = n[1], this.ctx.globalAlpha = n[1]; break; case "BM": this.ctx.globalCompositeOperation = a; break; case "SMask": this.current.activeSMask && (this.stateStack.length > 0 && this.stateStack[this.stateStack.length - 1].activeSMask === this.current.activeSMask ? this.suspendSMaskGroup() : this.endSMaskGroup()), this.current.activeSMask = a ? this.tempSMask : null, this.current.activeSMask && this.beginSMaskGroup(), this.tempSMask = null } } }, beginSMaskGroup: function () { var e = this.current.activeSMask, t = e.canvas.width, r = e.canvas.height, n = "smaskGroupAt" + this.groupLevel, i = this.cachedCanvases.getCanvas(n, t, r, !0), a = this.ctx, o = a.mozCurrentTransform; this.ctx.save(); var s = i.context; s.scale(1 / e.scaleX, 1 / e.scaleY), s.translate(-e.offsetX, -e.offsetY), s.transform.apply(s, o), e.startTransformInverse = s.mozCurrentTransformInverse, c(a, s), this.ctx = s, this.setGState([["BM", "source-over"], ["ca", 1], ["CA", 1]]), this.groupStack.push(a), this.groupLevel++ }, suspendSMaskGroup: function () { var e = this.ctx; this.groupLevel--, this.ctx = this.groupStack.pop(), v(this.ctx, this.current.activeSMask, e, this.webGLContext), this.ctx.restore(), this.ctx.save(), c(e, this.ctx), this.current.resumeSMaskCtx = e; var t = n.Util.transform(this.current.activeSMask.startTransformInverse, e.mozCurrentTransform); this.ctx.transform.apply(this.ctx, t), e.save(), e.setTransform(1, 0, 0, 1, 0, 0), e.clearRect(0, 0, e.canvas.width, e.canvas.height), e.restore() }, resumeSMaskGroup: function () { var e = this.cu!
 rrent.resumeSMaskCtx, t = this.ctx; this.ctx = e, this.groupStack.push(t), this.groupLevel++ }, endSMaskGroup: function () { var e = this.ctx; this.groupLevel--, this.ctx = this.groupStack.pop(), v(this.ctx, this.current.activeSMask, e, this.webGLContext), this.ctx.restore(), c(e, this.ctx); var t = n.Util.transform(this.current.activeSMask.startTransformInverse, e.mozCurrentTransform); this.ctx.transform.apply(this.ctx, t) }, save: function () { this.ctx.save(); var e = this.current; this.stateStack.push(e), this.current = e.clone(), this.current.resumeSMaskCtx = null }, restore: function () { this.current.resumeSMaskCtx && this.resumeSMaskGroup(), null === this.current.activeSMask || 0 !== this.stateStack.length && this.stateStack[this.stateStack.length - 1].activeSMask === this.current.activeSMask || this.endSMaskGroup(), 0 !== this.stateStack.length && (this.current = this.stateStack.pop(), this.ctx.restore(), this.pendingClip = null, this._cachedGetSinglePixelWidth = null) }, transform: function (e, t, r, n, i, a) { this.ctx.transform(e, t, r, n, i, a), this._cachedGetSinglePixelWidth = null }, constructPath: function (e, t) { for (var r = this.ctx, i = this.current, a = i.x, o = i.y, s = 0, u = 0, l = e.length; s < l; s++)switch (0 | e[s]) { case n.OPS.rectangle: a = t[u++], o = t[u++]; var c = t[u++], h = t[u++]; 0 === c && (c = this.getSinglePixelWidth()), 0 === h && (h = this.getSinglePixelWidth()); var d = a + c, f = o + h; this.ctx.moveTo(a, o), this.ctx.lineTo(d, o), this.ctx.lineTo(d, f), this.ctx.lineTo(a, f), this.ctx.lineTo(a, o), this.ctx.closePath(); break; case n.OPS.moveTo: a = t[u++], o = t[u++], r.moveTo(a, o); break; case n.OPS.lineTo: a = t[u++], o = t[u++], r.lineTo(a, o); break; case n.OPS.curveTo: a = t[u + 4], o = t[u + 5], r.bezierCurveTo(t[u], t[u + 1], t[u + 2], t[u + 3], a, o), u += 6; break; case n.OPS.curveTo2: r.bezierCurveTo(a, o, t[u], t[u + 1], t[u + 2], t[u + 3]), a = t[u + 2], o = t[u + 3], u += 4; break; case n.OPS.curveTo3: a = t[u + 2], o = t[u + 3], r.bezierCurveTo(t[u!
 ], t[u + 1], a, o, a, o), u += 4; break; case n.OPS.closePath: r.closePath() }i.setCurrentPoint(a, o) }, closePath: function () { this.ctx.closePath() }, stroke: function (e) { e = void 0 === e || e; var t = this.ctx, r = this.current.strokeColor; t.lineWidth = Math.max(.65 * this.getSinglePixelWidth(), this.current.lineWidth), t.globalAlpha = this.current.strokeAlpha, r && r.hasOwnProperty("type") && "Pattern" === r.type ? (t.save(), t.strokeStyle = r.getPattern(t, this), t.stroke(), t.restore()) : t.stroke(), e && this.consumePath(), t.globalAlpha = this.current.fillAlpha }, closeStroke: function () { this.closePath(), this.stroke() }, fill: function (e) { e = void 0 === e || e; var t = this.ctx, r = this.current.fillColor, n = !1; this.current.patternFill && (t.save(), this.baseTransform && t.setTransform.apply(t, this.baseTransform), t.fillStyle = r.getPattern(t, this), n = !0), this.pendingEOFill ? (t.fill("evenodd"), this.pendingEOFill = !1) : t.fill(), n && t.restore(), e && this.consumePath() }, eoFill: function () { this.pendingEOFill = !0, this.fill() }, fillStroke: function () { this.fill(!1), this.stroke(!1), this.consumePath() }, eoFillStroke: function () { this.pendingEOFill = !0, this.fillStroke() }, closeFillStroke: function () { this.closePath(), this.fillStroke() }, closeEOFillStroke: function () { this.pendingEOFill = !0, this.closePath(), this.fillStroke() }, endPath: function () { this.consumePath() }, clip: function () { this.pendingClip = y }, eoClip: function () { this.pendingClip = b }, beginText: function () { this.current.textMatrix = n.IDENTITY_MATRIX, this.current.textMatrixScale = 1, this.current.x = this.current.lineX = 0, this.current.y = this.current.lineY = 0 }, endText: function () { var e = this.pendingTextPaths, t = this.ctx; if (void 0 !== e) { t.save(), t.beginPath(); for (var r = 0; r < e.length; r++) { var n = e[r]; t.setTransform.apply(t, n.transform), t.translate(n.x, n.y), n.addToPath(t, n.fontSize) } t.restore(), t.clip(), t.beginPath(), delete this.pendingTextPaths }!
  else t.beginPath() }, setCharSpacing: function (e) { this.current.charSpacing = e }, setWordSpacing: function (e) { this.current.wordSpacing = e }, setHScale: function (e) { this.current.textHScale = e / 100 }, setLeading: function (e) { this.current.leading = -e }, setFont: function (e, t) { var r = this.commonObjs.get(e), i = this.current; if (!r) throw new Error("Can't find font for " + e); if (i.fontMatrix = r.fontMatrix ? r.fontMatrix : n.FONT_IDENTITY_MATRIX, 0 !== i.fontMatrix[0] && 0 !== i.fontMatrix[3] || (0, n.warn)("Invalid font matrix for font " + e), t < 0 ? (t = -t, i.fontDirection = -1) : i.fontDirection = 1, this.current.font = r, this.current.fontSize = t, !r.isType3Font) { var a = r.loadedName || "sans-serif", o = r.black ? "900" : r.bold ? "bold" : "normal", s = r.italic ? "italic" : "normal", u = '"' + a + '", ' + r.fallbackName, l = t < 16 ? 16 : t > 100 ? 100 : t; this.current.fontSizeScale = t / l; var c = s + " " + o + " " + l + "px " + u; this.ctx.font = c } }, setTextRenderingMode: function (e) { this.current.textRenderingMode = e }, setTextRise: function (e) { this.current.textRise = e }, moveText: function (e, t) { this.current.x = this.current.lineX += e, this.current.y = this.current.lineY += t }, setLeadingMoveText: function (e, t) { this.setLeading(-t), this.moveText(e, t) }, setTextMatrix: function (e, t, r, n, i, a) { this.current.textMatrix = [e, t, r, n, i, a], this.current.textMatrixScale = Math.sqrt(e * e + t * t), this.current.x = this.current.lineX = 0, this.current.y = this.current.lineY = 0 }, nextLine: function () { this.moveText(0, this.current.leading) }, paintChar: function (e, t, r, i) { var a, o = this.ctx, s = this.current, u = s.font, l = s.textRenderingMode, c = s.fontSize / s.fontSizeScale, h = l & n.TextRenderingMode.FILL_STROKE_MASK, d = !!(l & n.TextRenderingMode.ADD_TO_PATH_FLAG), f = s.patternFill && u.data; ((u.disableFontFace || d || f) && (a = u.getPathGenerator(this.commonObjs, e)), u.disableFontFace || f ? (o.save(), o.translate(t, r), o.beginPath(),!
  a(o, c), i && o.setTransform.apply(o, i), h !== n.TextRenderingMode.FILL && h !== n.TextRenderingMode.FILL_STROKE || o.fill(), h !== n.TextRenderingMode.STROKE && h !== n.TextRenderingMode.FILL_STROKE || o.stroke(), o.restore()) : (h !== n.TextRenderingMode.FILL && h !== n.TextRenderingMode.FILL_STROKE || o.fillText(e, t, r), h !== n.TextRenderingMode.STROKE && h !== n.TextRenderingMode.FILL_STROKE || o.strokeText(e, t, r)), d) && (this.pendingTextPaths || (this.pendingTextPaths = [])).push({ transform: o.mozCurrentTransform, x: t, y: r, fontSize: c, addToPath: a }) }, get isFontSubpixelAAEnabled() { var e = this.canvasFactory.create(10, 10).context; e.scale(1.5, 1), e.fillText("I", 0, 10); for (var t = e.getImageData(0, 0, 10, 10).data, r = !1, i = 3; i < t.length; i += 4)if (t[i] > 0 && t[i] < 255) { r = !0; break } return (0, n.shadow)(this, "isFontSubpixelAAEnabled", r) }, showText: function (e) { var t = this.current, r = t.font; if (r.isType3Font) return this.showType3Text(e); var i = t.fontSize; if (0 !== i) { var a = this.ctx, o = t.fontSizeScale, s = t.charSpacing, u = t.wordSpacing, l = t.fontDirection, c = t.textHScale * l, h = e.length, d = r.vertical, f = d ? 1 : -1, p = r.defaultVMetrics, v = i * t.fontMatrix[0], m = t.textRenderingMode === n.TextRenderingMode.FILL && !r.disableFontFace && !t.patternFill; a.save(); var g = void 0; if (t.patternFill) { a.save(); var y = t.fillColor.getPattern(a, this); g = a.mozCurrentTransform, a.restore(), a.fillStyle = y } a.transform.apply(a, t.textMatrix), a.translate(t.x, t.y + t.textRise), l > 0 ? a.scale(c, -1) : a.scale(c, 1); var b = t.lineWidth, _ = t.textMatrixScale; if (0 === _ || 0 === b) { var A = t.textRenderingMode & n.TextRenderingMode.FILL_STROKE_MASK; A !== n.TextRenderingMode.STROKE && A !== n.TextRenderingMode.FILL_STROKE || (this._cachedGetSinglePixelWidth = null, b = .65 * this.getSinglePixelWidth()) } else b /= _; 1 !== o && (a.scale(o, o), b /= o), a.lineWidth = b; var S, w = 0; for (S = 0; S < h; ++S) { var k = e[S]; if ((0, n.isNum)(k)) !
 w += f * k * i / 1e3; else { var P, x, C, R, E, T, O, I = !1, F = (k.isSpace ? u : 0) + s, L = k.fontChar, j = k.accent, M = k.width; if (d) E = k.vmetric || p, T = -(T = k.vmetric ? E[1] : .5 * M) * v, O = E[2] * v, M = E ? -E[0] : M, P = T / o, x = (w + O) / o; else P = w / o, x = 0; if (r.remeasure && M > 0) { var D = 1e3 * a.measureText(L).width / i * o; if (M < D && this.isFontSubpixelAAEnabled) { var N = M / D; I = !0, a.save(), a.scale(N, 1), P /= N } else M !== D && (P += (M - D) / 2e3 * i / o) } (k.isInFont || r.missingFile) && (m && !j ? a.fillText(L, P, x) : (this.paintChar(L, P, x, g), j && (C = P + j.offset.x / o, R = x - j.offset.y / o, this.paintChar(j.fontChar, C, R, g)))), w += M * v + F * l, I && a.restore() } } d ? t.y -= w * c : t.x += w * c, a.restore() } }, showType3Text: function (e) { var t, r, i, a, o = this.ctx, s = this.current, u = s.font, l = s.fontSize, c = s.fontDirection, h = u.vertical ? 1 : -1, d = s.charSpacing, f = s.wordSpacing, p = s.textHScale * c, v = s.fontMatrix || n.FONT_IDENTITY_MATRIX, m = e.length; if (!(s.textRenderingMode === n.TextRenderingMode.INVISIBLE) && 0 !== l) { for (this._cachedGetSinglePixelWidth = null, o.save(), o.transform.apply(o, s.textMatrix), o.translate(s.x, s.y), o.scale(p, c), t = 0; t < m; ++t)if (r = e[t], (0, n.isNum)(r)) a = h * r * l / 1e3, this.ctx.translate(a, 0), s.x += a * p; else { var g = (r.isSpace ? f : 0) + d, y = u.charProcOperatorList[r.operatorListId]; if (y) this.processingType3 = r, this.save(), o.scale(l, l), o.transform.apply(o, v), this.executeOperatorList(y), this.restore(), i = n.Util.applyTransform([r.width, 0], v)[0] * l + g, o.translate(i, 0), s.x += i * p; else (0, n.warn)('Type3 character "' + r.operatorListId + '" is not available.') } o.restore(), this.processingType3 = null } }, setCharWidth: function (e, t) { }, setCharWidthAndBounds: function (e, t, r, n, i, a) { this.ctx.rect(r, n, i - r, a - n), this.clip(), this.endPath() }, getColorN_Pattern: function (t) { var r, n = this; if ("TilingPattern" === t[0]) { va!
 r a = t[1], o = this.baseTransform || this.ctx.mozCurrentTransform.slice(), s = { createCanvasGraphics: function (t) { return new e(t, n.commonObjs, n.objs, n.canvasFactory, n.webGLContext) } }; r = new i.TilingPattern(t, a, this.ctx, s, o) } else r = (0, i.getShadingPatternFromIR)(t); return r }, setStrokeColorN: function () { this.current.strokeColor = this.getColorN_Pattern(arguments) }, setFillColorN: function () { this.current.fillColor = this.getColorN_Pattern(arguments), this.current.patternFill = !0 }, setStrokeRGBColor: function (e, t, r) { var i = n.Util.makeCssRgb(e, t, r); this.ctx.strokeStyle = i, this.current.strokeColor = i }, setFillRGBColor: function (e, t, r) { var i = n.Util.makeCssRgb(e, t, r); this.ctx.fillStyle = i, this.current.fillColor = i, this.current.patternFill = !1 }, shadingFill: function (e) { var t = this.ctx; this.save(); var r = (0, i.getShadingPatternFromIR)(e); t.fillStyle = r.getPattern(t, this, !0); var a = t.mozCurrentTransformInverse; if (a) { var o = t.canvas, s = o.width, u = o.height, l = n.Util.applyTransform([0, 0], a), c = n.Util.applyTransform([0, u], a), h = n.Util.applyTransform([s, 0], a), d = n.Util.applyTransform([s, u], a), f = Math.min(l[0], c[0], h[0], d[0]), p = Math.min(l[1], c[1], h[1], d[1]), v = Math.max(l[0], c[0], h[0], d[0]), m = Math.max(l[1], c[1], h[1], d[1]); this.ctx.fillRect(f, p, v - f, m - p) } else this.ctx.fillRect(-1e10, -1e10, 2e10, 2e10); this.restore() }, beginInlineImage: function () { (0, n.unreachable)("Should not call beginInlineImage") }, beginImageData: function () { (0, n.unreachable)("Should not call beginImageData") }, paintFormXObjectBegin: function (e, t) { if (this.save(), this.baseTransformStack.push(this.baseTransform), Array.isArray(e) && 6 === e.length && this.transform.apply(this, e), this.baseTransform = this.ctx.mozCurrentTransform, Array.isArray(t) && 4 === t.length) { var r = t[2] - t[0], n = t[3] - t[1]; this.ctx.rect(t[0], t[1], r, n), this.clip(), this.endPath() } }, paintFormXObjectEnd: function () { this.resto!
 re(), this.baseTransform = this.baseTransformStack.pop() }, beginGroup: function (e) { this.save(); var t = this.ctx; e.isolated || (0, n.info)("TODO: Support non-isolated groups."), e.knockout && (0, n.warn)("Knockout groups not supported."); var r = t.mozCurrentTransform; if (e.matrix && t.transform.apply(t, e.matrix), !e.bbox) throw new Error("Bounding box is required."); var i = n.Util.getAxialAlignedBoundingBox(e.bbox, t.mozCurrentTransform), a = [0, 0, t.canvas.width, t.canvas.height]; i = n.Util.intersect(i, a) || [0, 0, 0, 0]; var o = Math.floor(i[0]), s = Math.floor(i[1]), u = Math.max(Math.ceil(i[2]) - o, 1), l = Math.max(Math.ceil(i[3]) - s, 1), h = 1, d = 1; u > 4096 && (h = u / 4096, u = 4096), l > 4096 && (d = l / 4096, l = 4096); var f = "groupAt" + this.groupLevel; e.smask && (f += "_smask_" + this.smaskCounter++ % 2); var p = this.cachedCanvases.getCanvas(f, u, l, !0), v = p.context; v.scale(1 / h, 1 / d), v.translate(-o, -s), v.transform.apply(v, r), e.smask ? this.smaskStack.push({ canvas: p.canvas, context: v, offsetX: o, offsetY: s, scaleX: h, scaleY: d, subtype: e.smask.subtype, backdrop: e.smask.backdrop, transferMap: e.smask.transferMap || null, startTransformInverse: null }) : (t.setTransform(1, 0, 0, 1, 0, 0), t.translate(o, s), t.scale(h, d)), c(t, v), this.ctx = v, this.setGState([["BM", "source-over"], ["ca", 1], ["CA", 1]]), this.groupStack.push(t), this.groupLevel++, this.current.activeSMask = null }, endGroup: function (e) { this.groupLevel--; var t = this.ctx; this.ctx = this.groupStack.pop(), void 0 !== this.ctx.imageSmoothingEnabled ? this.ctx.imageSmoothingEnabled = !1 : this.ctx.mozImageSmoothingEnabled = !1, e.smask ? this.tempSMask = this.smaskStack.pop() : this.ctx.drawImage(t.canvas, 0, 0), this.restore() }, beginAnnotations: function () { this.save(), this.baseTransform && this.ctx.setTransform.apply(this.ctx, this.baseTransform) }, endAnnotations: function () { this.restore() }, beginAnnotation: function (e, t, r) { if (this.save(), h(this.ctx), this.current = new l, Ar!
 ray.isArray(e) && 4 === e.length) { var n = e[2] - e[0], i = e[3] - e[1]; this.ctx.rect(e[0], e[1], n, i), this.clip(), this.endPath() } this.transform.apply(this, t), this.transform.apply(this, r) }, endAnnotation: function () { this.restore() }, paintJpegXObject: function (e, t, r) { var i = this.objs.get(e); if (i) { this.save(); var a = this.ctx; if (a.scale(1 / t, -1 / r), a.drawImage(i, 0, 0, i.width, i.height, 0, -r, t, r), this.imageLayer) { var o = a.mozCurrentTransformInverse, s = this.getCanvasPosition(0, 0); this.imageLayer.appendImage({ objId: e, left: s[0], top: s[1], width: t / o[0], height: r / o[3] }) } this.restore() } else (0, n.warn)("Dependent image isn't ready yet") }, paintImageMaskXObject: function (e) { var t = this.ctx, n = e.width, i = e.height, a = this.current.fillColor, o = this.current.patternFill, s = this.processingType3; if (s && void 0 === s.compiled && (s.compiled = n <= 1e3 && i <= 1e3 ? function (e) { var t, r, n, i, a = e.width, o = e.height, s = a + 1, u = new Uint8Array(s * (o + 1)), l = new Uint8Array([0, 2, 4, 0, 1, 0, 5, 4, 8, 10, 0, 8, 0, 2, 1, 0]), c = a + 7 & -8, h = e.data, d = new Uint8Array(c * o), f = 0; for (t = 0, i = h.length; t < i; t++)for (var p = 128, v = h[t]; p > 0;)d[f++] = v & p ? 0 : 255, p >>= 1; var m = 0; for (0 !== d[f = 0] && (u[0] = 1, ++m), r = 1; r < a; r++)d[f] !== d[f + 1] && (u[r] = d[f] ? 2 : 1, ++m), f++; for (0 !== d[f] && (u[r] = 2, ++m), t = 1; t < o; t++) { n = t * s, d[(f = t * c) - c] !== d[f] && (u[n] = d[f] ? 1 : 8, ++m); var g = (d[f] ? 4 : 0) + (d[f - c] ? 8 : 0); for (r = 1; r < a; r++)l[g = (g >> 2) + (d[f + 1] ? 4 : 0) + (d[f - c + 1] ? 8 : 0)] && (u[n + r] = l[g], ++m), f++; if (d[f - c] !== d[f] && (u[n + r] = d[f] ? 2 : 4, ++m), m > 1e3) return null } for (n = t * s, 0 !== d[f = c * (o - 1)] && (u[n] = 8, ++m), r = 1; r < a; r++)d[f] !== d[f + 1] && (u[n + r] = d[f] ? 4 : 8, ++m), f++; if (0 !== d[f] && (u[n + r] = 4, ++m), m > 1e3) return null; var y = new Int32Array([0, s, -1, 0, -s, 0, 0, 0, 1]), b = []; for (t = 0; m !
 && t <= o; t++) { for (var _ = t * s, A = _ + a; _ < A && !u[_];)_++; if (_ !== A) { var S, w = [_ % s, t], k = u[_], P = _; do { var x = y[k]; do { _ += x } while (!u[_]); 5 !== (S = u[_]) && 10 !== S ? (k = S, u[_] = 0) : (k = S & 51 * k >> 4, u[_] &= k >> 2 | k << 2), w.push(_ % s), w.push(_ / s | 0), --m } while (P !== _); b.push(w), --t } } return function (e) { e.save(), e.scale(1 / a, -1 / o), e.translate(0, -o), e.beginPath(); for (var t = 0, r = b.length; t < r; t++) { var n = b[t]; e.moveTo(n[0], n[1]); for (var i = 2, s = n.length; i < s; i += 2)e.lineTo(n[i], n[i + 1]) } e.fill(), e.beginPath(), e.restore() } }({ data: e.data, width: n, height: i }) : null), s && s.compiled) s.compiled(t); else { var u = this.cachedCanvases.getCanvas("maskCanvas", n, i), l = u.context; l.save(), r(l, e), l.globalCompositeOperation = "source-in", l.fillStyle = o ? a.getPattern(l, this) : a, l.fillRect(0, 0, n, i), l.restore(), this.paintInlineImageXObject(u.canvas) } }, paintImageMaskXObjectRepeat: function (e, t, n, i) { var a = e.width, o = e.height, s = this.current.fillColor, u = this.current.patternFill, l = this.cachedCanvases.getCanvas("maskCanvas", a, o), c = l.context; c.save(), r(c, e), c.globalCompositeOperation = "source-in", c.fillStyle = u ? s.getPattern(c, this) : s, c.fillRect(0, 0, a, o), c.restore(); for (var h = this.ctx, d = 0, f = i.length; d < f; d += 2)h.save(), h.transform(t, 0, 0, n, i[d], i[d + 1]), h.scale(1, -1), h.drawImage(l.canvas, 0, 0, a, o, 0, -1, 1, 1), h.restore() }, paintImageMaskXObjectGroup: function (e) { for (var t = this.ctx, n = this.current.fillColor, i = this.current.patternFill, a = 0, o = e.length; a < o; a++) { var s = e[a], u = s.width, l = s.height, c = this.cachedCanvases.getCanvas("maskCanvas", u, l), h = c.context; h.save(), r(h, s), h.globalCompositeOperation = "source-in", h.fillStyle = i ? n.getPattern(h, this) : n, h.fillRect(0, 0, u, l), h.restore(), t.save(), t.transform.apply(t, s.transform), t.scale(1, -1), t.drawImage(c.canvas, 0, 0, u, l, 0, -1, 1, 1), t.r!
 estore() } }, paintImageXObject: function (e) { var t = this.objs.get(e); t ? this.paintInlineImageXObject(t) : (0, n.warn)("Dependent image isn't ready yet") }, paintImageXObjectRepeat: function (e, t, r, i) { var a = this.objs.get(e); if (a) { for (var o = a.width, s = a.height, u = [], l = 0, c = i.length; l < c; l += 2)u.push({ transform: [t, 0, 0, r, i[l], i[l + 1]], x: 0, y: 0, w: o, h: s }); this.paintInlineImageXObjectGroup(a, u) } else (0, n.warn)("Dependent image isn't ready yet") }, paintInlineImageXObject: function (e) { var r = e.width, n = e.height, i = this.ctx; this.save(), i.scale(1 / r, -1 / n); var a, o, s = i.mozCurrentTransformInverse, u = s[0], l = s[1], c = Math.max(Math.sqrt(u * u + l * l), 1), h = s[2], d = s[3], f = Math.max(Math.sqrt(h * h + d * d), 1); if ("function" == typeof HTMLElement && e instanceof HTMLElement || !e.data) a = e; else { var p = (o = this.cachedCanvases.getCanvas("inlineImage", r, n)).context; t(p, e), a = o.canvas } for (var v = r, m = n, g = "prescale1"; c > 2 && v > 1 || f > 2 && m > 1;) { var y = v, b = m; c > 2 && v > 1 && (c /= v / (y = Math.ceil(v / 2))), f > 2 && m > 1 && (f /= m / (b = Math.ceil(m / 2))), (p = (o = this.cachedCanvases.getCanvas(g, y, b)).context).clearRect(0, 0, y, b), p.drawImage(a, 0, 0, v, m, 0, 0, y, b), a = o.canvas, v = y, m = b, g = "prescale1" === g ? "prescale2" : "prescale1" } if (i.drawImage(a, 0, 0, v, m, 0, -n, r, n), this.imageLayer) { var _ = this.getCanvasPosition(0, -n); this.imageLayer.appendImage({ imgData: e, left: _[0], top: _[1], width: r / s[0], height: n / s[3] }) } this.restore() }, paintInlineImageXObjectGroup: function (e, r) { var n = this.ctx, i = e.width, a = e.height, o = this.cachedCanvases.getCanvas("inlineImage", i, a); t(o.context, e); for (var s = 0, u = r.length; s < u; s++) { var l = r[s]; if (n.save(), n.transform.apply(n, l.transform), n.scale(1, -1), n.drawImage(o.canvas, l.x, l.y, l.w, l.h, 0, -1, 1, 1), this.imageLayer) { var c = this.getCanvasPosition(l.x, l.y); this.imageLayer.appendImage({ img!
 Data: e, left: c[0], top: c[1], width: i, height: a }) } n.restore() } }, paintSolidColorImageMask: function () { this.ctx.fillRect(0, 0, 1, 1) }, paintXObject: function () { (0, n.warn)("Unsupported 'paintXObject' command.") }, markPoint: function (e) { }, markPointProps: function (e, t) { }, beginMarkedContent: function (e) { }, beginMarkedContentProps: function (e, t) { }, endMarkedContent: function () { }, beginCompat: function () { }, endCompat: function () { }, consumePath: function () { var e = this.ctx; this.pendingClip && (this.pendingClip === b ? e.clip("evenodd") : e.clip(), this.pendingClip = null), e.beginPath() }, getSinglePixelWidth: function (e) { if (null === this._cachedGetSinglePixelWidth) { var t = this.ctx.mozCurrentTransformInverse; this._cachedGetSinglePixelWidth = Math.sqrt(Math.max(t[0] * t[0] + t[1] * t[1], t[2] * t[2] + t[3] * t[3])) } return this._cachedGetSinglePixelWidth }, getCanvasPosition: function (e, t) { var r = this.ctx.mozCurrentTransform; return [r[0] * e + r[2] * t + r[4], r[1] * e + r[3] * t + r[5]] } }, n.OPS) e.prototype[n.OPS[_]] = e.prototype[_]; return e }(); t.CanvasGraphics = c }, function (e, t, r) { "use strict"; Object.defineProperty(t, "__esModule", { value: !0 }), t.TilingPattern = t.getShadingPatternFromIR = void 0; var n = r(1), i = { RadialAxial: { fromIR: function (e) { var t = e[1], r = e[2], n = e[3], i = e[4], a = e[5], o = e[6]; return { type: "Pattern", getPattern: function (e) { var s; "axial" === t ? s = e.createLinearGradient(n[0], n[1], i[0], i[1]) : "radial" === t && (s = e.createRadialGradient(n[0], n[1], a, i[0], i[1], o)); for (var u = 0, l = r.length; u < l; ++u) { var c = r[u]; s.addColorStop(c[0], c[1]) } return s } } } } }, a = function () { function e(e, t, r, n, i, a, o, s) { var u, l = t.coords, c = t.colors, h = e.data, d = 4 * e.width; l[r + 1] > l[n + 1] && (u = r, r = n, n = u, u = a, a = o, o = u), l[n + 1] > l[i + 1] && (u = n, n = i, i = u, u = o, o = s, s = u), l[r + 1] > l[n + 1] && (u = r, r = n, n = u, u = a, a = o, o = u); v!
 ar f = (l[r] + t.offsetX) * t.scaleX, p = (l[r + 1] + t.offsetY) * t.scaleY, v = (l[n] + t.offsetX) * t.scaleX, m = (l[n + 1] + t.offsetY) * t.scaleY, g = (l[i] + t.offsetX) * t.scaleX, y = (l[i + 1] + t.offsetY) * t.scaleY; if (!(p >= y)) for (var b, _, A, S, w, k, P, x, C, R = c[a], E = c[a + 1], T = c[a + 2], O = c[o], I = c[o + 1], F = c[o + 2], L = c[s], j = c[s + 1], M = c[s + 2], D = Math.round(p), N = Math.round(y), q = D; q <= N; q++) { q < m ? (b = f - (f - v) * (C = q < p ? 0 : p === m ? 1 : (p - q) / (p - m)), _ = R - (R - O) * C, A = E - (E - I) * C, S = T - (T - F) * C) : (b = v - (v - g) * (C = q > y ? 1 : m === y ? 0 : (m - q) / (m - y)), _ = O - (O - L) * C, A = I - (I - j) * C, S = F - (F - M) * C), w = f - (f - g) * (C = q < p ? 0 : q > y ? 1 : (p - q) / (p - y)), k = R - (R - L) * C, P = E - (E - j) * C, x = T - (T - M) * C; for (var W = Math.round(Math.min(b, w)), U = Math.round(Math.max(b, w)), B = d * q + 4 * W, z = W; z <= U; z++)C = (C = (b - z) / (b - w)) < 0 ? 0 : C > 1 ? 1 : C, h[B++] = _ - (_ - k) * C | 0, h[B++] = A - (A - P) * C | 0, h[B++] = S - (S - x) * C | 0, h[B++] = 255 } } function t(t, r, n) { var i, a, o = r.coords, s = r.colors; switch (r.type) { case "lattice": var u = r.verticesPerRow, l = Math.floor(o.length / u) - 1, c = u - 1; for (i = 0; i < l; i++)for (var h = i * u, d = 0; d < c; d++, h++)e(t, n, o[h], o[h + 1], o[h + u], s[h], s[h + 1], s[h + u]), e(t, n, o[h + u + 1], o[h + 1], o[h + u], s[h + u + 1], s[h + 1], s[h + u]); break; case "triangles": for (i = 0, a = o.length; i < a; i += 3)e(t, n, o[i], o[i + 1], o[i + 2], s[i], s[i + 1], s[i + 2]); break; default: throw new Error("illegal figure") } } return function (e, r, n, i, a, o, s, u) { var l, c, h, d, f = Math.floor(e[0]), p = Math.floor(e[1]), v = Math.ceil(e[2]) - f, m = Math.ceil(e[3]) - p, g = Math.min(Math.ceil(Math.abs(v * r[0] * 1.1)), 3e3), y = Math.min(Math.ceil(Math.abs(m * r[1] * 1.1)), 3e3), b = v / g, _ = m / y, A = { coords: n, colors: i, offsetX: -f, offsetY: -p, scaleX: 1 / b, scaleY: 1 / _ !
 }, S = g + 4, w = y + 4; if (u.isEnabled) l = u.drawFigures({ width: g, height: y, backgroundColor: o, figures: a, context: A }), (c = s.getCanvas("mesh", S, w, !1)).context.drawImage(l, 2, 2), l = c.canvas; else { var k = (c = s.getCanvas("mesh", S, w, !1)).context, P = k.createImageData(g, y); if (o) { var x = P.data; for (h = 0, d = x.length; h < d; h += 4)x[h] = o[0], x[h + 1] = o[1], x[h + 2] = o[2], x[h + 3] = 255 } for (h = 0; h < a.length; h++)t(P, a[h], A); k.putImageData(P, 2, 2), l = c.canvas } return { canvas: l, offsetX: f - 2 * b, offsetY: p - 2 * _, scaleX: b, scaleY: _ } } }(); i.Mesh = { fromIR: function (e) { var t = e[2], r = e[3], i = e[4], o = e[5], s = e[6], u = e[8]; return { type: "Pattern", getPattern: function (e, l, c) { var h; if (c) h = n.Util.singularValueDecompose2dScale(e.mozCurrentTransform); else if (h = n.Util.singularValueDecompose2dScale(l.baseTransform), s) { var d = n.Util.singularValueDecompose2dScale(s); h = [h[0] * d[0], h[1] * d[1]] } var f = a(o, h, t, r, i, c ? null : u, l.cachedCanvases, l.webGLContext); return c || (e.setTransform.apply(e, l.baseTransform), s && e.transform.apply(e, s)), e.translate(f.offsetX, f.offsetY), e.scale(f.scaleX, f.scaleY), e.createPattern(f.canvas, "no-repeat") } } } }, i.Dummy = { fromIR: function () { return { type: "Pattern", getPattern: function () { return "hotpink" } } } }; var o = function () { var e = 1, t = 2; function r(e, t, r, n, i) { this.operatorList = e[2], this.matrix = e[3] || [1, 0, 0, 1, 0, 0], this.bbox = e[4], this.xstep = e[5], this.ystep = e[6], this.paintType = e[7], this.tilingType = e[8], this.color = t, this.canvasGraphicsFactory = n, this.baseTransform = i, this.type = "Pattern", this.ctx = r } return r.prototype = { createPatternCanvas: function (e) { var t = this.operatorList, r = this.bbox, i = this.xstep, a = this.ystep, o = this.paintType, s = this.tilingType, u = this.color, l = this.canvasGraphicsFactory; (0, n.info)("TilingType: " + s); var c = r[0], h = r[1], d = r[2], f = r[3], p = [c, h], v = [c + i,!
  h + a], m = v[0] - p[0], g = v[1] - p[1], y = n.Util.singularValueDecompose2dScale(this.matrix), b = n.Util.singularValueDecompose2dScale(this.baseTransform), _ = [y[0] * b[0], y[1] * b[1]]; m = Math.min(Math.ceil(Math.abs(m * _[0])), 3e3), g = Math.min(Math.ceil(Math.abs(g * _[1])), 3e3); var A = e.cachedCanvases.getCanvas("pattern", m, g, !0), S = A.context, w = l.createCanvasGraphics(S); w.groupLevel = e.groupLevel, this.setFillAndStrokeStyleToContext(w, o, u), this.setScale(m, g, i, a), this.transformToScale(w); var k = [1, 0, 0, 1, -p[0], -p[1]]; return w.transform.apply(w, k), this.clipBbox(w, r, c, h, d, f), w.executeOperatorList(t), A.canvas }, setScale: function (e, t, r, n) { this.scale = [e / r, t / n] }, transformToScale: function (e) { var t = this.scale, r = [t[0], 0, 0, t[1], 0, 0]; e.transform.apply(e, r) }, scaleToContext: function () { var e = this.scale; this.ctx.scale(1 / e[0], 1 / e[1]) }, clipBbox: function (e, t, r, n, i, a) { if (Array.isArray(t) && 4 === t.length) { var o = i - r, s = a - n; e.ctx.rect(r, n, o, s), e.clip(), e.endPath() } }, setFillAndStrokeStyleToContext: function (r, i, a) { var o = r.ctx, s = r.current; switch (i) { case e: var u = this.ctx; o.fillStyle = u.fillStyle, o.strokeStyle = u.strokeStyle, s.fillColor = u.fillStyle, s.strokeColor = u.strokeStyle; break; case t: var l = n.Util.makeCssRgb(a[0], a[1], a[2]); o.fillStyle = l, o.strokeStyle = l, s.fillColor = l, s.strokeColor = l; break; default: throw new n.FormatError("Unsupported paint type: " + i) } }, getPattern: function (e, t) { var r = this.createPatternCanvas(t); return (e = this.ctx).setTransform.apply(e, this.baseTransform), e.transform.apply(e, this.matrix), this.scaleToContext(), e.createPattern(r, "repeat") } }, r }(); t.getShadingPatternFromIR = function (e) { var t = i[e[0]]; if (!t) throw new Error("Unknown IR type: " + e[0]); return t.fromIR(e) }, t.TilingPattern = o }, function (e, t, r) { "use strict"; Object.defineProperty(t, "__esModule", { value: !0 }); var n = Object.create(null); n.worker!
 Port = void 0 === n.workerPort ? null : n.workerPort, n.workerSrc = void 0 === n.workerSrc ? "" : n.workerSrc, t.GlobalWorkerOptions = n }, function (e, t, r) { "use strict"; Object.defineProperty(t, "__esModule", { value: !0 }), t.MessageHandler = void 0; var n, i, a, o = r(137), s = (n = o) && n.__esModule ? n : { default: n }, u = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (e) { return typeof e } : function (e) { return e && "function" == typeof Symbol && e.constructor === Symbol && e !== Symbol.prototype ? "symbol" : typeof e }, l = (i = s.default.mark(function e(t, r) { var n = arguments.length > 2 && void 0 !== arguments[2] ? arguments[2] : null; return s.default.wrap(function (e) { for (; ;)switch (e.prev = e.next) { case 0: if (t) { e.next = 2; break } return e.abrupt("return"); case 2: return e.abrupt("return", t.apply(n, r)); case 3: case "end": return e.stop() } }, e, this) }), a = function () { var e = i.apply(this, arguments); return new Promise(function (t, r) { return function n(i, a) { try { var o = e[i](a), s = o.value } catch (e) { return void r(e) } if (!o.done) return Promise.resolve(s).then(function (e) { n("next", e) }, function (e) { n("throw", e) }); t(s) }("next") }) }, function (e, t) { return a.apply(this, arguments) }), c = r(1); function h(e) { if ("object" !== (void 0 === e ? "undefined" : u(e))) return e; switch (e.name) { case "AbortException": return new c.AbortException(e.message); case "MissingPDFException": return new c.MissingPDFException(e.message); case "UnexpectedResponseException": return new c.UnexpectedResponseException(e.message, e.status); default: return new c.UnknownErrorException(e.message, e.details) } } function d(e, t, r) { t ? e.resolve() : e.reject(r) } function f(e, t, r) { var n = this; this.sourceName = e, this.targetName = t, this.comObj = r, this.callbackId = 1, this.streamId = 1, this.postMessageTransfers = !0, this.streamSinks = Object.create(null), this.streamControllers = Object.create(null); var i = this.callbacksCap!
 abilities = Object.create(null), a = this.actionHandler = Object.create(null); this._onComObjOnMessage = function (e) { var t = e.data; if (t.targetName === n.sourceName) if (t.stream) n._processStreamMessage(t); else if (t.isReply) { var o = t.callbackId; if (!(t.callbackId in i)) throw new Error("Cannot resolve callback " + o); var s = i[o]; delete i[o], "error" in t ? s.reject(h(t.error)) : s.resolve(t.data) } else { if (!(t.action in a)) throw new Error("Unknown action from worker: " + t.action); var u = a[t.action]; if (t.callbackId) { var l = n.sourceName, d = t.sourceName; Promise.resolve().then(function () { return u[0].call(u[1], t.data) }).then(function (e) { r.postMessage({ sourceName: l, targetName: d, isReply: !0, callbackId: t.callbackId, data: e }) }, function (e) { r.postMessage({ sourceName: l, targetName: d, isReply: !0, callbackId: t.callbackId, error: function (e) { return !(e instanceof Error) || e instanceof c.AbortException || e instanceof c.MissingPDFException || e instanceof c.UnexpectedResponseException || e instanceof c.UnknownErrorException ? e : new c.UnknownErrorException(e.message, e.toString()) }(e) }) }) } else t.streamId ? n._createStreamSink(t) : u[0].call(u[1], t.data) } }, r.addEventListener("message", this._onComObjOnMessage) } f.prototype = { on: function (e, t, r) { var n = this.actionHandler; if (n[e]) throw new Error('There is already an actionName called "' + e + '"'); n[e] = [t, r] }, send: function (e, t, r) { var n = { sourceName: this.sourceName, targetName: this.targetName, action: e, data: t }; this.postMessage(n, r) }, sendWithPromise: function (e, t, r) { var n = this.callbackId++, i = { sourceName: this.sourceName, targetName: this.targetName, action: e, data: t, callbackId: n }, a = (0, c.createPromiseCapability)(); this.callbacksCapabilities[n] = a; try { this.postMessage(i, r) } catch (e) { a.reject(e) } return a.promise }, sendWithStream: function (e, t, r, n) { var i = this, a = this.streamId++, o = this.sourceName, s = this.targetName; return new c.Readab!
 leStream({ start: function (r) { var n = (0, c.createPromiseCapability)(); return i.streamControllers[a] = { controller: r, startCall: n, isClosed: !1 }, i.postMessage({ sourceName: o, targetName: s, action: e, streamId: a, data: t, desiredSize: r.desiredSize }), n.promise }, pull: function (e) { var t = (0, c.createPromiseCapability)(); return i.streamControllers[a].pullCall = t, i.postMessage({ sourceName: o, targetName: s, stream: "pull", streamId: a, desiredSize: e.desiredSize }), t.promise }, cancel: function (e) { var t = (0, c.createPromiseCapability)(); return i.streamControllers[a].cancelCall = t, i.streamControllers[a].isClosed = !0, i.postMessage({ sourceName: o, targetName: s, stream: "cancel", reason: e, streamId: a }), t.promise } }, r) }, _createStreamSink: function (e) { var t = this, r = this, n = this.actionHandler[e.action], i = e.streamId, a = e.desiredSize, o = this.sourceName, s = e.sourceName, u = function (e) { var r = e.stream, n = e.chunk, a = e.transfers, u = e.success, l = e.reason; t.postMessage({ sourceName: o, targetName: s, stream: r, streamId: i, chunk: n, success: u, reason: l }, a) }, h = { enqueue: function (e) { var t = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : 1, r = arguments[2]; if (!this.isCancelled) { var n = this.desiredSize; this.desiredSize -= t, n > 0 && this.desiredSize <= 0 && (this.sinkCapability = (0, c.createPromiseCapability)(), this.ready = this.sinkCapability.promise), u({ stream: "enqueue", chunk: e, transfers: r }) } }, close: function () { this.isCancelled || (this.isCancelled = !0, u({ stream: "close" }), delete r.streamSinks[i]) }, error: function (e) { this.isCancelled || (this.isCancelled = !0, u({ stream: "error", reason: e })) }, sinkCapability: (0, c.createPromiseCapability)(), onPull: null, onCancel: null, isCancelled: !1, desiredSize: a, ready: null }; h.sinkCapability.resolve(), h.ready = h.sinkCapability.promise, this.streamSinks[i] = h, l(n[0], [e.data, h], n[1]).then(function () { u({ stream: "start_complete", success: !!
 0 }) }, function (e) { u({ stream: "start_complete", success: !1, reason: e }) }) }, _processStreamMessage: function (e) { var t = this, r = this.sourceName, n = e.sourceName, i = e.streamId, a = function (e) { var a = e.stream, o = e.success, s = e.reason; t.comObj.postMessage({ sourceName: r, targetName: n, stream: a, success: o, streamId: i, reason: s }) }, o = function () { Promise.all([t.streamControllers[e.streamId].startCall, t.streamControllers[e.streamId].pullCall, t.streamControllers[e.streamId].cancelCall].map(function (e) { return e && (t = e.promise, Promise.resolve(t).catch(function () { })); var t })).then(function () { delete t.streamControllers[e.streamId] }) }; switch (e.stream) { case "start_complete": d(this.streamControllers[e.streamId].startCall, e.success, h(e.reason)); break; case "pull_complete": d(this.streamControllers[e.streamId].pullCall, e.success, h(e.reason)); break; case "pull": if (!this.streamSinks[e.streamId]) { a({ stream: "pull_complete", success: !0 }); break } this.streamSinks[e.streamId].desiredSize <= 0 && e.desiredSize > 0 && this.streamSinks[e.streamId].sinkCapability.resolve(), this.streamSinks[e.streamId].desiredSize = e.desiredSize, l(this.streamSinks[e.streamId].onPull).then(function () { a({ stream: "pull_complete", success: !0 }) }, function (e) { a({ stream: "pull_complete", success: !1, reason: e }) }); break; case "enqueue": (0, c.assert)(this.streamControllers[e.streamId], "enqueue should have stream controller"), this.streamControllers[e.streamId].isClosed || this.streamControllers[e.streamId].controller.enqueue(e.chunk); break; case "close": if ((0, c.assert)(this.streamControllers[e.streamId], "close should have stream controller"), this.streamControllers[e.streamId].isClosed) break; this.streamControllers[e.streamId].isClosed = !0, this.streamControllers[e.streamId].controller.close(), o(); break; case "error": (0, c.assert)(this.streamControllers[e.streamId], "error should have stream controller"), this.streamControllers[e.streamId].controller.error(h(e.!
 reason)), o(); break; case "cancel_complete": d(this.streamControllers[e.streamId].cancelCall, e.success, h(e.reason)), o(); break; case "cancel": if (!this.streamSinks[e.streamId]) break; l(this.streamSinks[e.streamId].onCancel, [h(e.reason)]).then(function () { a({ stream: "cancel_complete", success: !0 }) }, function (e) { a({ stream: "cancel_complete", success: !1, reason: e }) }), this.streamSinks[e.streamId].sinkCapability.reject(h(e.reason)), this.streamSinks[e.streamId].isCancelled = !0, delete this.streamSinks[e.streamId]; break; default: throw new Error("Unexpected stream case") } }, postMessage: function (e, t) { t && this.postMessageTransfers ? this.comObj.postMessage(e, t) : this.comObj.postMessage(e) }, destroy: function () { this.comObj.removeEventListener("message", this._onComObjOnMessage) } }, t.MessageHandler = f }, function (e, t, r) { "use strict"; e.exports = r(138) }, function (e, t, r) { "use strict"; var n = function () { return this }() || Function("return this")(), i = n.regeneratorRuntime && Object.getOwnPropertyNames(n).indexOf("regeneratorRuntime") >= 0, a = i && n.regeneratorRuntime; if (n.regeneratorRuntime = void 0, e.exports = r(139), i) n.regeneratorRuntime = a; else try { delete n.regeneratorRuntime } catch (e) { n.regeneratorRuntime = void 0 } }, function (e, t, r) { "use strict"; (function (e) { var t = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (e) { return typeof e } : function (e) { return e && "function" == typeof Symbol && e.constructor === Symbol && e !== Symbol.prototype ? "symbol" : typeof e }; !function (r) { var n, i = Object.prototype, a = i.hasOwnProperty, o = "function" == typeof Symbol ? Symbol : {}, s = o.iterator || "@@iterator", u = o.asyncIterator || "@@asyncIterator", l = o.toStringTag || "@@toStringTag", c = "object" === t(e), h = r.regeneratorRuntime; if (h) c && (e.exports = h); else { (h = r.regeneratorRuntime = c ? e.exports : {}).wrap = A; var d = "suspendedStart", f = "suspendedYield", p = "executing", v = "complete!
 d", m = {}, g = {}; g[s] = function () { return this }; var y = Object.getPrototypeOf, b = y && y(y(I([]))); b && b !== i && a.call(b, s) && (g = b); var _ = P.prototype = w.prototype = Object.create(g); k.prototype = _.constructor = P, P.constructor = k, P[l] = k.displayName = "GeneratorFunction", h.isGeneratorFunction = function (e) { var t = "function" == typeof e && e.constructor; return !!t && (t === k || "GeneratorFunction" === (t.displayName || t.name)) }, h.mark = function (e) { return Object.setPrototypeOf ? Object.setPrototypeOf(e, P) : (e.__proto__ = P, l in e || (e[l] = "GeneratorFunction")), e.prototype = Object.create(_), e }, h.awrap = function (e) { return { __await: e } }, x(C.prototype), C.prototype[u] = function () { return this }, h.AsyncIterator = C, h.async = function (e, t, r, n) { var i = new C(A(e, t, r, n)); return h.isGeneratorFunction(t) ? i : i.next().then(function (e) { return e.done ? e.value : i.next() }) }, x(_), _[l] = "Generator", _[s] = function () { return this }, _.toString = function () { return "[object Generator]" }, h.keys = function (e) { var t = []; for (var r in e) t.push(r); return t.reverse(), function r() { for (; t.length;) { var n = t.pop(); if (n in e) return r.value = n, r.done = !1, r } return r.done = !0, r } }, h.values = I, O.prototype = { constructor: O, reset: function (e) { if (this.prev = 0, this.next = 0, this.sent = this._sent = n, this.done = !1, this.delegate = null, this.method = "next", this.arg = n, this.tryEntries.forEach(T), !e) for (var t in this) "t" === t.charAt(0) && a.call(this, t) && !isNaN(+t.slice(1)) && (this[t] = n) }, stop: function () { this.done = !0; var e = this.tryEntries[0].completion; if ("throw" === e.type) throw e.arg; return this.rval }, dispatchException: function (e) { if (this.done) throw e; var t = this; function r(r, i) { return s.type = "throw", s.arg = e, t.next = r, i && (t.method = "next", t.arg = n), !!i } for (var i = this.tryEntries.length - 1; i >= 0; --i) { var o = this.tryEntries[i], s = o.completion; if ("ro!
 ot" === o.tryLoc) return r("end"); if (o.tryLoc <= this.prev) { var u = a.call(o, "catchLoc"), l = a.call(o, "finallyLoc"); if (u && l) { if (this.prev < o.catchLoc) return r(o.catchLoc, !0); if (this.prev < o.finallyLoc) return r(o.finallyLoc) } else if (u) { if (this.prev < o.catchLoc) return r(o.catchLoc, !0) } else { if (!l) throw new Error("try statement without catch or finally"); if (this.prev < o.finallyLoc) return r(o.finallyLoc) } } } }, abrupt: function (e, t) { for (var r = this.tryEntries.length - 1; r >= 0; --r) { var n = this.tryEntries[r]; if (n.tryLoc <= this.prev && a.call(n, "finallyLoc") && this.prev < n.finallyLoc) { var i = n; break } } i && ("break" === e || "continue" === e) && i.tryLoc <= t && t <= i.finallyLoc && (i = null); var o = i ? i.completion : {}; return o.type = e, o.arg = t, i ? (this.method = "next", this.next = i.finallyLoc, m) : this.complete(o) }, complete: function (e, t) { if ("throw" === e.type) throw e.arg; return "break" === e.type || "continue" === e.type ? this.next = e.arg : "return" === e.type ? (this.rval = this.arg = e.arg, this.method = "return", this.next = "end") : "normal" === e.type && t && (this.next = t), m }, finish: function (e) { for (var t = this.tryEntries.length - 1; t >= 0; --t) { var r = this.tryEntries[t]; if (r.finallyLoc === e) return this.complete(r.completion, r.afterLoc), T(r), m } }, catch: function (e) { for (var t = this.tryEntries.length - 1; t >= 0; --t) { var r = this.tryEntries[t]; if (r.tryLoc === e) { var n = r.completion; if ("throw" === n.type) { var i = n.arg; T(r) } return i } } throw new Error("illegal catch attempt") }, delegateYield: function (e, t, r) { return this.delegate = { iterator: I(e), resultName: t, nextLoc: r }, "next" === this.method && (this.arg = n), m } } } function A(e, t, r, n) { var i = t && t.prototype instanceof w ? t : w, a = Object.create(i.prototype), o = new O(n || []); return a._invoke = function (e, t, r) { var n = d; return function (i, a) { if (n === p) throw new Error("Generator is already running!
 "); if (n === v) { if ("throw" === i) throw a; return F() } for (r.method = i, r.arg = a; ;) { var o = r.delegate; if (o) { var s = R(o, r); if (s) { if (s === m) continue; return s } } if ("next" === r.method) r.sent = r._sent = r.arg; else if ("throw" === r.method) { if (n === d) throw n = v, r.arg; r.dispatchException(r.arg) } else "return" === r.method && r.abrupt("return", r.arg); n = p; var u = S(e, t, r); if ("normal" === u.type) { if (n = r.done ? v : f, u.arg === m) continue; return { value: u.arg, done: r.done } } "throw" === u.type && (n = v, r.method = "throw", r.arg = u.arg) } } }(e, r, o), a } function S(e, t, r) { try { return { type: "normal", arg: e.call(t, r) } } catch (e) { return { type: "throw", arg: e } } } function w() { } function k() { } function P() { } function x(e) { ["next", "throw", "return"].forEach(function (t) { e[t] = function (e) { return this._invoke(t, e) } }) } function C(e) { var r; this._invoke = function (n, i) { function o() { return new Promise(function (r, o) { !function r(n, i, o, s) { var u = S(e[n], e, i); if ("throw" !== u.type) { var l = u.arg, c = l.value; return c && "object" === (void 0 === c ? "undefined" : t(c)) && a.call(c, "__await") ? Promise.resolve(c.__await).then(function (e) { r("next", e, o, s) }, function (e) { r("throw", e, o, s) }) : Promise.resolve(c).then(function (e) { l.value = e, o(l) }, s) } s(u.arg) }(n, i, r, o) }) } return r = r ? r.then(o, o) : o() } } function R(e, t) { var r = e.iterator[t.method]; if (r === n) { if (t.delegate = null, "throw" === t.method) { if (e.iterator.return && (t.method = "return", t.arg = n, R(e, t), "throw" === t.method)) return m; t.method = "throw", t.arg = new TypeError("The iterator does not provide a 'throw' method") } return m } var i = S(r, e.iterator, t.arg); if ("throw" === i.type) return t.method = "throw", t.arg = i.arg, t.delegate = null, m; var a = i.arg; return a ? a.done ? (t[e.resultName] = a.value, t.next = e.nextLoc, "return" !== t.method && (t.method = "next", t.arg = n), t.delegate = null, m!
 ) : a : (t.method = "throw", t.arg = new TypeError("iterator result is not an object"), t.delegate = null, m) } function E(e) { var t = { tryLoc: e[0] }; 1 in e && (t.catchLoc = e[1]), 2 in e && (t.finallyLoc = e[2], t.afterLoc = e[3]), this.tryEntries.push(t) } function T(e) { var t = e.completion || {}; t.type = "normal", delete t.arg, e.completion = t } function O(e) { this.tryEntries = [{ tryLoc: "root" }], e.forEach(E, this), this.reset(!0) } function I(e) { if (e) { var t = e[s]; if (t) return t.call(e); if ("function" == typeof e.next) return e; if (!isNaN(e.length)) { var r = -1, i = function t() { for (; ++r < e.length;)if (a.call(e, r)) return t.value = e[r], t.done = !1, t; return t.value = n, t.done = !0, t }; return i.next = i } } return { next: F } } function F() { return { value: n, done: !0 } } }(function () { return this }() || Function("return this")()) }).call(this, r(140)(e)) }, function (e, t, r) { "use strict"; e.exports = function (e) { return e.webpackPolyfill || (e.deprecate = function () { }, e.paths = [], e.children || (e.children = []), Object.defineProperty(e, "loaded", { enumerable: !0, get: function () { return e.l } }), Object.defineProperty(e, "id", { enumerable: !0, get: function () { return e.i } }), e.webpackPolyfill = 1), e } }, function (e, t, r) { "use strict"; Object.defineProperty(t, "__esModule", { value: !0 }), t.Metadata = void 0; var n = function () { function e(e, t) { for (var r = 0; r < t.length; r++) { var n = t[r]; n.enumerable = n.enumerable || !1, n.configurable = !0, "value" in n && (n.writable = !0), Object.defineProperty(e, n.key, n) } } return function (t, r, n) { return r && e(t.prototype, r), n && e(t, n), t } }(), i = r(1), a = r(142); var o = function () { function e(t) { !function (e, t) { if (!(e instanceof t)) throw new TypeError("Cannot call a class as a function") }(this, e), (0, i.assert)("string" == typeof t, "Metadata: input is not a string"), t = this._repair(t); var r = (new a.SimpleXMLParser).parseFromString(t); this._metadata = Object.create!
 (null), r && this._parse(r) } return n(e, [{ key: "_repair", value: function (e) { return e.replace(/>\\376\\377([^<]+)/g, function (e, t) { for (var r = t.replace(/\\([0-3])([0-7])([0-7])/g, function (e, t, r, n) { return String.fromCharCode(64 * t + 8 * r + 1 * n) }).replace(/&(amp|apos|gt|lt|quot);/g, function (e, t) { switch (t) { case "amp": return "&"; case "apos": return "'"; case "gt": return ">"; case "lt": return "<"; case "quot": return '"' }throw new Error("_repair: " + t + " isn't defined.") }), n = "", i = 0, a = r.length; i < a; i += 2) { var o = 256 * r.charCodeAt(i) + r.charCodeAt(i + 1); n += o >= 32 && o < 127 && 60 !== o && 62 !== o && 38 !== o ? String.fromCharCode(o) : "&#x" + (65536 + o).toString(16).substring(1) + ";" } return ">" + n }) } }, { key: "_parse", value: function (e) { var t = e.documentElement; if ("rdf:rdf" !== t.nodeName.toLowerCase()) for (t = t.firstChild; t && "rdf:rdf" !== t.nodeName.toLowerCase();)t = t.nextSibling; var r = t ? t.nodeName.toLowerCase() : null; if (t && "rdf:rdf" === r && t.hasChildNodes()) for (var n = t.childNodes, i = 0, a = n.length; i < a; i++) { var o = n[i]; if ("rdf:description" === o.nodeName.toLowerCase()) for (var s = 0, u = o.childNodes.length; s < u; s++)if ("#text" !== o.childNodes[s].nodeName.toLowerCase()) { var l = o.childNodes[s], c = l.nodeName.toLowerCase(); this._metadata[c] = l.textContent.trim() } } } }, { key: "get", value: function (e) { return this._metadata[e] || null } }, { key: "getAll", value: function () { return this._metadata } }, { key: "has", value: function (e) { return void 0 !== this._metadata[e] } }]), e }(); t.Metadata = o }, function (e, t, r) { "use strict"; Object.defineProperty(t, "__esModule", { value: !0 }); var n = function () { return function (e, t) { if (Array.isArray(e)) return e; if (Symbol.iterator in Object(e)) return function (e, t) { var r = [], n = !0, i = !1, a = void 0; try { for (var o, s = e[Symbol.iterator](); !(n = (o = s.next()).done) && (r.push(o.value), !t || r.length !== t); n = !0); } c!
 atch (e) { i = !0, a = e } finally { try { !n && s.return && s.return() } finally { if (i) throw a } } return r }(e, t); throw new TypeError("Invalid attempt to destructure non-iterable instance") } }(), i = function () { function e(e, t) { for (var r = 0; r < t.length; r++) { var n = t[r]; n.enumerable = n.enumerable || !1, n.configurable = !0, "value" in n && (n.writable = !0), Object.defineProperty(e, n.key, n) } } return function (t, r, n) { return r && e(t.prototype, r), n && e(t, n), t } }(); function a(e, t) { if (!(e instanceof t)) throw new TypeError("Cannot call a class as a function") } var o = { NoError: 0, EndOfDocument: -1, UnterminatedCdat: -2, UnterminatedXmlDeclaration: -3, UnterminatedDoctypeDeclaration: -4, UnterminatedComment: -5, MalformedElement: -6, OutOfMemory: -7, UnterminatedAttributeValue: -8, UnterminatedElement: -9, ElementNeverBegun: -10 }; function s(e, t) { var r = e[t]; return " " === r || "\n" === r || "\r" === r || "\t" === r } var u = function () { function e() { a(this, e) } return i(e, [{ key: "_resolveEntities", value: function (e) { return e.replace(/&([^;]+);/g, function (e, t) { if ("#x" === t.substring(0, 2)) return String.fromCharCode(parseInt(t.substring(2), 16)); if ("#" === t.substring(0, 1)) return String.fromCharCode(parseInt(t.substring(1), 10)); switch (t) { case "lt": return "<"; case "gt": return ">"; case "amp": return "&"; case "quot": return '"' }return this.onResolveEntity(t) }) } }, { key: "_parseContent", value: function (e, t) { var r, n = t, i = []; function a() { for (; n < e.length && s(e, n);)++n } for (; n < e.length && !s(e, n) && ">" !== e[n] && "/" !== e[n];)++n; for (r = e.substring(t, n), a(); n < e.length && ">" !== e[n] && "/" !== e[n] && "?" !== e[n];) { a(); for (var o, u = ""; n < e.length && !s(e, n) && "=" !== e[n];)u += e[n], ++n; if (a(), "=" !== e[n]) return null; ++n, a(); var l = e[n]; if ('"' !== l && "'" !== l) return null; var c = e.indexOf(l, ++n); if (c < 0) return null; o = e.substring(n, c), i.push({ name: u, value: this._re!
 solveEntities(o) }), n = c + 1, a() } return { name: r, attributes: i, parsed: n - t } } }, { key: "_parseProcessingInstruction", value: function (e, t) { var r, n = t; for (; n < e.length && !s(e, n) && ">" !== e[n] && "/" !== e[n];)++n; r = e.substring(t, n), function () { for (; n < e.length && s(e, n);)++n }(); for (var i = n; n < e.length && ("?" !== e[n] || ">" !== e[n + 1]);)++n; return { name: r, value: e.substring(i, n), parsed: n - t } } }, { key: "parseXml", value: function (e) { for (var t = 0; t < e.length;) { var r = t; if ("<" === e[t]) { var n = void 0; switch (e[++r]) { case "/": if (++r, (n = e.indexOf(">", r)) < 0) return void this.onError(o.UnterminatedElement); this.onEndElement(e.substring(r, n)), r = n + 1; break; case "?": ++r; var i = this._parseProcessingInstruction(e, r); if ("?>" !== e.substring(r + i.parsed, r + i.parsed + 2)) return void this.onError(o.UnterminatedXmlDeclaration); this.onPi(i.name, i.value), r += i.parsed + 2; break; case "!": if ("--" === e.substring(r + 1, r + 3)) { if ((n = e.indexOf("--\x3e", r + 3)) < 0) return void this.onError(o.UnterminatedComment); this.onComment(e.substring(r + 3, n)), r = n + 3 } else if ("[CDATA[" === e.substring(r + 1, r + 8)) { if ((n = e.indexOf("]]>", r + 8)) < 0) return void this.onError(o.UnterminatedCdat); this.onCdata(e.substring(r + 8, n)), r = n + 3 } else { if ("DOCTYPE" !== e.substring(r + 1, r + 8)) return void this.onError(o.MalformedElement); var a = e.indexOf("[", r + 8), s = !1; if ((n = e.indexOf(">", r + 8)) < 0) return void this.onError(o.UnterminatedDoctypeDeclaration); if (a > 0 && n > a) { if ((n = e.indexOf("]>", r + 8)) < 0) return void this.onError(o.UnterminatedDoctypeDeclaration); s = !0 } var u = e.substring(r + 8, n + (s ? 1 : 0)); this.onDoctype(u), r = n + (s ? 2 : 1) } break; default: var l = this._parseContent(e, r); if (null === l) return void this.onError(o.MalformedElement); var c = !1; if ("/>" === e.substring(r + l.parsed, r + l.parsed + 2)) c = !0; else if (">" !== e.substring(r + l.parsed, r + l.p!
 arsed + 1)) return void this.onError(o.UnterminatedElement); this.onBeginElement(l.name, l.attributes, c), r += l.parsed + (c ? 2 : 1) } } else { for (; r < e.length && "<" !== e[r];)r++; var h = e.substring(t, r); this.onText(this._resolveEntities(h)) } t = r } } }, { key: "onResolveEntity", value: function (e) { return "&" + e + ";" } }, { key: "onPi", value: function (e, t) { } }, { key: "onComment", value: function (e) { } }, { key: "onCdata", value: function (e) { } }, { key: "onDoctype", value: function (e) { } }, { key: "onText", value: function (e) { } }, { key: "onBeginElement", value: function (e, t, r) { } }, { key: "onEndElement", value: function (e) { } }, { key: "onError", value: function (e) { } }]), e }(), l = function () { function e(t, r) { a(this, e), this.nodeName = t, this.nodeValue = r, Object.defineProperty(this, "parentNode", { value: null, writable: !0 }) } return i(e, [{ key: "hasChildNodes", value: function () { return this.childNodes && this.childNodes.length > 0 } }, { key: "firstChild", get: function () { return this.childNodes[0] } }, { key: "nextSibling", get: function () { var e = this.parentNode.childNodes.indexOf(this); return this.parentNode.childNodes[e + 1] } }, { key: "textContent", get: function () { return this.childNodes ? this.childNodes.map(function (e) { return e.textContent }).join("") : this.nodeValue || "" } }]), e }(), c = function (e) { function t() { a(this, t); var e = function (e, t) { if (!e) throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); return !t || "object" != typeof t && "function" != typeof t ? e : t }(this, (t.__proto__ || Object.getPrototypeOf(t)).call(this)); return e._currentFragment = null, e._stack = null, e._errorCode = o.NoError, e } return function (e, t) { if ("function" != typeof t && null !== t) throw new TypeError("Super expression must either be null or a function, not " + typeof t); e.prototype = Object.create(t && t.prototype, { constructor: { value: e, enumerable: !1, writable: !0, configurable: !0!
  } }), t && (Object.setPrototypeOf ? Object.setPrototypeOf(e, t) : e.__proto__ = t) }(t, u), i(t, [{ key: "parseFromString", value: function (e) { if (this._currentFragment = [], this._stack = [], this._errorCode = o.NoError, this.parseXml(e), this._errorCode === o.NoError) { var t = n(this._currentFragment, 1)[0]; if (t) return { documentElement: t } } } }, { key: "onResolveEntity", value: function (e) { switch (e) { case "apos": return "'" }return function e(t, r, n) { null === t && (t = Function.prototype); var i = Object.getOwnPropertyDescriptor(t, r); if (void 0 === i) { var a = Object.getPrototypeOf(t); return null === a ? void 0 : e(a, r, n) } if ("value" in i) return i.value; var o = i.get; return void 0 !== o ? o.call(n) : void 0 }(t.prototype.__proto__ || Object.getPrototypeOf(t.prototype), "onResolveEntity", this).call(this, e) } }, { key: "onText", value: function (e) { if (!function (e) { for (var t = 0, r = e.length; t < r; t++)if (!s(e, t)) return !1; return !0 }(e)) { var t = new l("#text", e); this._currentFragment.push(t) } } }, { key: "onCdata", value: function (e) { var t = new l("#text", e); this._currentFragment.push(t) } }, { key: "onBeginElement", value: function (e, t, r) { var n = new l(e); n.childNodes = [], this._currentFragment.push(n), r || (this._stack.push(this._currentFragment), this._currentFragment = n.childNodes) } }, { key: "onEndElement", value: function (e) { this._currentFragment = this._stack.pop(); for (var t = this._currentFragment[this._currentFragment.length - 1], r = 0, n = t.childNodes.length; r < n; r++)t.childNodes[r].parentNode = t } }, { key: "onError", value: function (e) { this._errorCode = e } }]), t }(); t.SimpleXMLParser = c }, function (e, t, r) { "use strict"; Object.defineProperty(t, "__esModule", { value: !0 }), t.PDFDataTransportStream = void 0; var n, i = r(137), a = (n = i) && n.__esModule ? n : { default: n }, o = r(1); function s(e) { return function () { var t = e.apply(this, arguments); return new Promise(function (e, r) { return function n(i, a)!
  { try { var o = t[i](a), s = o.value } catch (e) { return void r(e) } if (!o.done) return Promise.resolve(s).then(function (e) { n("next", e) }, function (e) { n("throw", e) }); e(s) }("next") }) } } var u = function () { function e(e, t) { var r = this; (0, o.assert)(t), this._queuedChunks = []; var n = e.initialData; if (n && n.length > 0) { var i = new Uint8Array(n).buffer; this._queuedChunks.push(i) } this._pdfDataRangeTransport = t, this._isStreamingSupported = !e.disableStream, this._isRangeSupported = !e.disableRange, this._contentLength = e.length, this._fullRequestReader = null, this._rangeReaders = [], this._pdfDataRangeTransport.addRangeListener(function (e, t) { r._onReceiveData({ begin: e, chunk: t }) }), this._pdfDataRangeTransport.addProgressListener(function (e) { r._onProgress({ loaded: e }) }), this._pdfDataRangeTransport.addProgressiveReadListener(function (e) { r._onReceiveData({ chunk: e }) }), this._pdfDataRangeTransport.transportReady() } function t(e, t) { this._stream = e, this._done = !1, this._filename = null, this._queuedChunks = t || [], this._requests = [], this._headersReady = Promise.resolve(), e._fullRequestReader = this, this.onProgress = null } function r(e, t, r) { this._stream = e, this._begin = t, this._end = r, this._queuedChunk = null, this._requests = [], this._done = !1, this.onProgress = null } return e.prototype = { _onReceiveData: function (e) { var t = new Uint8Array(e.chunk).buffer; if (void 0 === e.begin) this._fullRequestReader ? this._fullRequestReader._enqueue(t) : this._queuedChunks.push(t); else { var r = this._rangeReaders.some(function (r) { return r._begin === e.begin && (r._enqueue(t), !0) }); (0, o.assert)(r) } }, _onProgress: function (e) { if (this._rangeReaders.length > 0) { var t = this._rangeReaders[0]; t.onProgress && t.onProgress({ loaded: e.loaded }) } }, _removeRangeReader: function (e) { var t = this._rangeReaders.indexOf(e); t >= 0 && this._rangeReaders.splice(t, 1) }, getFullReader: function () { (0, o.assert)(!this._fullRequestReader); var e!
  = this._queuedChunks; return this._queuedChunks = null, new t(this, e) }, getRangeReader: function (e, t) { var n = new r(this, e, t); return this._pdfDataRangeTransport.requestDataRange(e, t), this._rangeReaders.push(n), n }, cancelAllRequests: function (e) { this._fullRequestReader && this._fullRequestReader.cancel(e), this._rangeReaders.slice(0).forEach(function (t) { t.cancel(e) }), this._pdfDataRangeTransport.abort() } }, t.prototype = { _enqueue: function (e) { this._done || (this._requests.length > 0 ? this._requests.shift().resolve({ value: e, done: !1 }) : this._queuedChunks.push(e)) }, get headersReady() { return this._headersReady }, get filename() { return this._filename }, get isRangeSupported() { return this._stream._isRangeSupported }, get isStreamingSupported() { return this._stream._isStreamingSupported }, get contentLength() { return this._stream._contentLength }, read: function () { var e = s(a.default.mark(function e() { var t, r; return a.default.wrap(function (e) { for (; ;)switch (e.prev = e.next) { case 0: if (!(this._queuedChunks.length > 0)) { e.next = 3; break } return t = this._queuedChunks.shift(), e.abrupt("return", { value: t, done: !1 }); case 3: if (!this._done) { e.next = 5; break } return e.abrupt("return", { value: void 0, done: !0 }); case 5: return r = (0, o.createPromiseCapability)(), this._requests.push(r), e.abrupt("return", r.promise); case 8: case "end": return e.stop() } }, e, this) })); return function () { return e.apply(this, arguments) } }(), cancel: function (e) { this._done = !0, this._requests.forEach(function (e) { e.resolve({ value: void 0, done: !0 }) }), this._requests = [] } }, r.prototype = { _enqueue: function (e) { if (!this._done) { if (0 === this._requests.length) this._queuedChunk = e; else this._requests.shift().resolve({ value: e, done: !1 }), this._requests.forEach(function (e) { e.resolve({ value: void 0, done: !0 }) }), this._requests = []; this._done = !0, this._stream._removeRangeReader(this) } }, get isStreamingSupported() { return !1 }, read!
 : function () { var e = s(a.default.mark(function e() { var t, r; return a.default.wrap(function (e) { for (; ;)switch (e.prev = e.next) { case 0: if (!this._queuedChunk) { e.next = 4; break } return t = this._queuedChunk, this._queuedChunk = null, e.abrupt("return", { value: t, done: !1 }); case 4: if (!this._done) { e.next = 6; break } return e.abrupt("return", { value: void 0, done: !0 }); case 6: return r = (0, o.createPromiseCapability)(), this._requests.push(r), e.abrupt("return", r.promise); case 9: case "end": return e.stop() } }, e, this) })); return function () { return e.apply(this, arguments) } }(), cancel: function (e) { this._done = !0, this._requests.forEach(function (e) { e.resolve({ value: void 0, done: !0 }) }), this._requests = [], this._stream._removeRangeReader(this) } }, e }(); t.PDFDataTransportStream = u }, function (e, t, r) { "use strict"; Object.defineProperty(t, "__esModule", { value: !0 }), t.WebGLContext = void 0; var n = function () { function e(e, t) { for (var r = 0; r < t.length; r++) { var n = t[r]; n.enumerable = n.enumerable || !1, n.configurable = !0, "value" in n && (n.writable = !0), Object.defineProperty(e, n.key, n) } } return function (t, r, n) { return r && e(t.prototype, r), n && e(t, n), t } }(), i = r(1); var a = function () { function e(t) { var r = t.enable, n = void 0 !== r && r; !function (e, t) { if (!(e instanceof t)) throw new TypeError("Cannot call a class as a function") }(this, e), this._enabled = !0 === n } return n(e, [{ key: "composeSMask", value: function (e) { var t = e.layer, r = e.mask, n = e.properties; return o.composeSMask(t, r, n) } }, { key: "drawFigures", value: function (e) { var t = e.width, r = e.height, n = e.backgroundColor, i = e.figures, a = e.context; return o.drawFigures(t, r, n, i, a) } }, { key: "clear", value: function () { o.cleanup() } }, { key: "isEnabled", get: function () { var e = this._enabled; return e && (e = o.tryInitGL()), (0, i.shadow)(this, "isEnabled", e) } }]), e }(), o = function () { function e(e, t, r) { var n = e!
 .createShader(r); if (e.shaderSource(n, t), e.compileShader(n), !e.getShaderParameter(n, e.COMPILE_STATUS)) { var i = e.getShaderInfoLog(n); throw new Error("Error during shader compilation: " + i) } return n } function t(t, r) { return e(t, r, t.VERTEX_SHADER) } function r(t, r) { return e(t, r, t.FRAGMENT_SHADER) } function n(e, t) { for (var r = e.createProgram(), n = 0, i = t.length; n < i; ++n)e.attachShader(r, t[n]); if (e.linkProgram(r), !e.getProgramParameter(r, e.LINK_STATUS)) { var a = e.getProgramInfoLog(r); throw new Error("Error during program linking: " + a) } return r } function i(e, t, r) { e.activeTexture(r); var n = e.createTexture(); return e.bindTexture(e.TEXTURE_2D, n), e.texParameteri(e.TEXTURE_2D, e.TEXTURE_WRAP_S, e.CLAMP_TO_EDGE), e.texParameteri(e.TEXTURE_2D, e.TEXTURE_WRAP_T, e.CLAMP_TO_EDGE), e.texParameteri(e.TEXTURE_2D, e.TEXTURE_MIN_FILTER, e.NEAREST), e.texParameteri(e.TEXTURE_2D, e.TEXTURE_MAG_FILTER, e.NEAREST), e.texImage2D(e.TEXTURE_2D, 0, e.RGBA, e.RGBA, e.UNSIGNED_BYTE, t), n } var a, o; function s() { a || (o = document.createElement("canvas"), a = o.getContext("webgl", { premultipliedalpha: !1 })) } var u = "  attribute vec2 a_position;                                      attribute vec2 a_texCoord;                                                                                                      uniform vec2 u_resolution;                                                                                                      varying vec2 v_texCoord;                                                                                                        void main() {                                                     vec2 clipSpace = (a_position / u_resolution) * 2.0 - 1.0;       gl_Position = vec4(clipSpace * vec2(1, -1), 0, 1);                                                                              v_texCoord = a_texCoord;                                      }                                                             ", l = "  precision mediump float;               !
                                                                                          uniform vec4 u_backdrop;                                        uniform int u_subtype;                                          uniform sampler2D u_image;                                      uniform sampler2D u_mask;                                                                                                       varying vec2 v_texCoord;                                                                                                        void main() {                                                     vec4 imageColor = texture2D(u_image, v_texCoord);               vec4 maskColor = texture2D(u_mask, v_texCoord);                 if (u_backdrop.a > 0.0) {                                         maskColor.rgb = maskColor.rgb * maskColor.a +                                   u_backdrop.rgb * (1.0 - maskColor.a);         }                                                               float lum;                                                      if (u_subtype == 0) {                                             lum = maskColor.a;                                            } else {                                                          lum = maskColor.r * 0.3 + maskColor.g * 0.59 +                        maskColor.b * 0.11;                                     }                                                               imageColor.a *= lum;                                            imageColor.rgb *= imageColor.a;                                 gl_FragColor = imageColor;                                    }                                                             ", c = null; var h = "  attribute vec2 a_position;                                      attribute vec3 a_color;                                                                                                         uniform vec2 u_resolution;                                      uniform vec2 u_scale;                                           uniform vec2 u_o!
 ffset;                                                                                                          varying vec4 v_color;                                                                                                           void main() {                                                     vec2 position = (a_position + u_offset) * u_scale;              vec2 clipSpace = (position / u_resolution) * 2.0 - 1.0;         gl_Position = vec4(clipSpace * vec2(1, -1), 0, 1);                                                                              v_color = vec4(a_color / 255.0, 1.0);                         }                                                             ", d = "  precision mediump float;                                                                                                        varying vec4 v_color;                                                                                                           void main() {                                                     gl_FragColor = v_color;                                       }                                                             ", f = null; return { tryInitGL: function () { try { return s(), !!a } catch (e) { } return !1 }, composeSMask: function (e, h, d) { var f = e.width, p = e.height; c || function () { var e, i; s(), e = o, o = null, i = a, a = null; var h = n(i, [t(i, u), r(i, l)]); i.useProgram(h); var d = {}; d.gl = i, d.canvas = e, d.resolutionLocation = i.getUniformLocation(h, "u_resolution"), d.positionLocation = i.getAttribLocation(h, "a_position"), d.backdropLocation = i.getUniformLocation(h, "u_backdrop"), d.subtypeLocation = i.getUniformLocation(h, "u_subtype"); var f = i.getAttribLocation(h, "a_texCoord"), p = i.getUniformLocation(h, "u_image"), v = i.getUniformLocation(h, "u_mask"), m = i.createBuffer(); i.bindBuffer(i.ARRAY_BUFFER, m), i.bufferData(i.ARRAY_BUFFER, new Float32Array([0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1]), i.STATIC_DRAW), i.enableVertexAttribArray(f), i.vertexAttribPointer(f, 2, i.FLOA!
 T, !1, 0, 0), i.uniform1i(p, 0), i.uniform1i(v, 1), c = d }(); var v = c, m = v.canvas, g = v.gl; m.width = f, m.height = p, g.viewport(0, 0, g.drawingBufferWidth, g.drawingBufferHeight), g.uniform2f(v.resolutionLocation, f, p), d.backdrop ? g.uniform4f(v.resolutionLocation, d.backdrop[0], d.backdrop[1], d.backdrop[2], 1) : g.uniform4f(v.resolutionLocation, 0, 0, 0, 0), g.uniform1i(v.subtypeLocation, "Luminosity" === d.subtype ? 1 : 0); var y = i(g, e, g.TEXTURE0), b = i(g, h, g.TEXTURE1), _ = g.createBuffer(); return g.bindBuffer(g.ARRAY_BUFFER, _), g.bufferData(g.ARRAY_BUFFER, new Float32Array([0, 0, f, 0, 0, p, 0, p, f, 0, f, p]), g.STATIC_DRAW), g.enableVertexAttribArray(v.positionLocation), g.vertexAttribPointer(v.positionLocation, 2, g.FLOAT, !1, 0, 0), g.clearColor(0, 0, 0, 0), g.enable(g.BLEND), g.blendFunc(g.ONE, g.ONE_MINUS_SRC_ALPHA), g.clear(g.COLOR_BUFFER_BIT), g.drawArrays(g.TRIANGLES, 0, 6), g.flush(), g.deleteTexture(y), g.deleteTexture(b), g.deleteBuffer(_), m }, drawFigures: function (e, i, u, l, c) { f || function () { var e, i; s(), e = o, o = null, i = a, a = null; var u = n(i, [t(i, h), r(i, d)]); i.useProgram(u); var l = {}; l.gl = i, l.canvas = e, l.resolutionLocation = i.getUniformLocation(u, "u_resolution"), l.scaleLocation = i.getUniformLocation(u, "u_scale"), l.offsetLocation = i.getUniformLocation(u, "u_offset"), l.positionLocation = i.getAttribLocation(u, "a_position"), l.colorLocation = i.getAttribLocation(u, "a_color"), f = l }(); var p = f, v = p.canvas, m = p.gl; v.width = e, v.height = i, m.viewport(0, 0, m.drawingBufferWidth, m.drawingBufferHeight), m.uniform2f(p.resolutionLocation, e, i); var g, y, b, _ = 0; for (g = 0, y = l.length; g < y; g++)switch (l[g].type) { case "lattice": _ += ((b = l[g].coords.length / l[g].verticesPerRow | 0) - 1) * (l[g].verticesPerRow - 1) * 6; break; case "triangles": _ += l[g].coords.length }var A = new Float32Array(2 * _), S = new Uint8Array(3 * _), w = c.coords, k = c.colors, P = 0, x = 0; for (g = 0, y = l.length; g < y; g++) { var C = l[g],!
  R = C.coords, E = C.colors; switch (C.type) { case "lattice": var T = C.verticesPerRow; b = R.length / T | 0; for (var O = 1; O < b; O++)for (var I = O * T + 1, F = 1; F < T; F++, I++)A[P] = w[R[I - T - 1]], A[P + 1] = w[R[I - T - 1] + 1], A[P + 2] = w[R[I - T]], A[P + 3] = w[R[I - T] + 1], A[P + 4] = w[R[I - 1]], A[P + 5] = w[R[I - 1] + 1], S[x] = k[E[I - T - 1]], S[x + 1] = k[E[I - T - 1] + 1], S[x + 2] = k[E[I - T - 1] + 2], S[x + 3] = k[E[I - T]], S[x + 4] = k[E[I - T] + 1], S[x + 5] = k[E[I - T] + 2], S[x + 6] = k[E[I - 1]], S[x + 7] = k[E[I - 1] + 1], S[x + 8] = k[E[I - 1] + 2], A[P + 6] = A[P + 2], A[P + 7] = A[P + 3], A[P + 8] = A[P + 4], A[P + 9] = A[P + 5], A[P + 10] = w[R[I]], A[P + 11] = w[R[I] + 1], S[x + 9] = S[x + 3], S[x + 10] = S[x + 4], S[x + 11] = S[x + 5], S[x + 12] = S[x + 6], S[x + 13] = S[x + 7], S[x + 14] = S[x + 8], S[x + 15] = k[E[I]], S[x + 16] = k[E[I] + 1], S[x + 17] = k[E[I] + 2], P += 12, x += 18; break; case "triangles": for (var L = 0, j = R.length; L < j; L++)A[P] = w[R[L]], A[P + 1] = w[R[L] + 1], S[x] = k[E[L]], S[x + 1] = k[E[L] + 1], S[x + 2] = k[E[L] + 2], P += 2, x += 3 } } u ? m.clearColor(u[0] / 255, u[1] / 255, u[2] / 255, 1) : m.clearColor(0, 0, 0, 0), m.clear(m.COLOR_BUFFER_BIT); var M = m.createBuffer(); m.bindBuffer(m.ARRAY_BUFFER, M), m.bufferData(m.ARRAY_BUFFER, A, m.STATIC_DRAW), m.enableVertexAttribArray(p.positionLocation), m.vertexAttribPointer(p.positionLocation, 2, m.FLOAT, !1, 0, 0); var D = m.createBuffer(); return m.bindBuffer(m.ARRAY_BUFFER, D), m.bufferData(m.ARRAY_BUFFER, S, m.STATIC_DRAW), m.enableVertexAttribArray(p.colorLocation), m.vertexAttribPointer(p.colorLocation, 3, m.UNSIGNED_BYTE, !1, 0, 0), m.uniform2f(p.scaleLocation, c.scaleX, c.scaleY), m.uniform2f(p.offsetLocation, c.offsetX, c.offsetY), m.drawArrays(m.TRIANGLES, 0, _), m.flush(), m.deleteBuffer(M), m.deleteBuffer(D), v }, cleanup: function () { c && c.canvas && (c.canvas.width = 0, c.canvas.height = 0), f && f.canvas && (f.canvas.width = 0, f.canvas.height = 0), c = null, f = null } }!
  }(); t.WebGLContext = a }, function (e, t, r) { "use strict"; Object.defineProperty(t, "__esModule", { value: !0 }), t.renderTextLayer = void 0; var n, i = r(1), a = r(3), o = (n = a) && n.__esModule ? n : { default: n }; var s = function () { var e = 1e5, t = /\S/; var r = ["left: ", 0, "px; top: ", 0, "px; font-size: ", 0, "px; font-family: ", "", ";"]; function n(e, n, a) { var o, s = document.createElement("div"), u = { style: null, angle: 0, canvasWidth: 0, isWhitespace: !1, originalTransform: null, paddingBottom: 0, paddingLeft: 0, paddingRight: 0, paddingTop: 0, scale: 1 }; if (e._textDivs.push(s), o = n.str, !t.test(o)) return u.isWhitespace = !0, void e._textDivProperties.set(s, u); var l = i.Util.transform(e._viewport.transform, n.transform), c = Math.atan2(l[1], l[0]), h = a[n.fontName]; h.vertical && (c += Math.PI / 2); var d, f, p = Math.sqrt(l[2] * l[2] + l[3] * l[3]), v = p; if (h.ascent ? v = h.ascent * v : h.descent && (v = (1 + h.descent) * v), 0 === c ? (d = l[4], f = l[5] - v) : (d = l[4] + v * Math.sin(c), f = l[5] - v * Math.cos(c)), r[1] = d, r[3] = f, r[5] = p, r[7] = h.fontFamily, u.style = r.join(""), s.setAttribute("style", u.style), s.textContent = n.str, e._fontInspectorEnabled && (s.dataset.fontName = n.fontName), 0 !== c && (u.angle = c * (180 / Math.PI)), n.str.length > 1 && (h.vertical ? u.canvasWidth = n.height * e._viewport.scale : u.canvasWidth = n.width * e._viewport.scale), e._textDivProperties.set(s, u), e._textContentStream && e._layoutText(s), e._enhanceTextSelection) { var m = 1, g = 0; 0 !== c && (m = Math.cos(c), g = Math.sin(c)); var y, b, _ = (h.vertical ? n.height : n.width) * e._viewport.scale, A = p; 0 !== c ? (y = [m, g, -g, m, d, f], b = i.Util.getAxialAlignedBoundingBox([0, 0, _, A], y)) : b = [d, f, d + _, f + A], e._bounds.push({ left: b[0], top: b[1], right: b[2], bottom: b[3], div: s, size: [_, A], m: y }) } } function a(t) { if (!t._canceled) { var r = t._textDivs, n = t._capability, i = r.length; if (i > e) return t._renderingDone = !0, void n.resolve();!
  if (!t._textContentStream) for (var a = 0; a < i; a++)t._layoutText(r[a]); t._renderingDone = !0, n.resolve() } } function s(e) { for (var t = e._bounds, r = e._viewport, n = function (e, t, r) { var n = r.map(function (e, t) { return { x1: e.left, y1: e.top, x2: e.right, y2: e.bottom, index: t, x1New: void 0, x2New: void 0 } }); u(e, n); var i = new Array(r.length); return n.forEach(function (e) { var t = e.index; i[t] = { left: e.x1New, top: 0, right: e.x2New, bottom: 0 } }), r.map(function (t, r) { var a = i[r], o = n[r]; o.x1 = t.top, o.y1 = e - a.right, o.x2 = t.bottom, o.y2 = e - a.left, o.index = r, o.x1New = void 0, o.x2New = void 0 }), u(t, n), n.forEach(function (e) { var t = e.index; i[t].top = e.x1New, i[t].bottom = e.x2New }), i }(r.width, r.height, t), a = 0; a < n.length; a++) { var o = t[a].div, s = e._textDivProperties.get(o); if (0 !== s.angle) { var l = n[a], c = t[a], h = c.m, d = h[0], f = h[1], p = [[0, 0], [0, c.size[1]], [c.size[0], 0], c.size], v = new Float64Array(64); p.forEach(function (e, t) { var r = i.Util.applyTransform(e, h); v[t + 0] = d && (l.left - r[0]) / d, v[t + 4] = f && (l.top - r[1]) / f, v[t + 8] = d && (l.right - r[0]) / d, v[t + 12] = f && (l.bottom - r[1]) / f, v[t + 16] = f && (l.left - r[0]) / -f, v[t + 20] = d && (l.top - r[1]) / d, v[t + 24] = f && (l.right - r[0]) / -f, v[t + 28] = d && (l.bottom - r[1]) / d, v[t + 32] = d && (l.left - r[0]) / -d, v[t + 36] = f && (l.top - r[1]) / -f, v[t + 40] = d && (l.right - r[0]) / -d, v[t + 44] = f && (l.bottom - r[1]) / -f, v[t + 48] = f && (l.left - r[0]) / f, v[t + 52] = d && (l.top - r[1]) / -d, v[t + 56] = f && (l.right - r[0]) / f, v[t + 60] = d && (l.bottom - r[1]) / -d }); var m = function (e, t, r) { for (var n = 0, i = 0; i < r; i++) { var a = e[t++]; a > 0 && (n = n ? Math.min(a, n) : a) } return n }, g = 1 + Math.min(Math.abs(d), Math.abs(f)); s.paddingLeft = m(v, 32, 16) / g, s.paddingTop = m(v, 48, 16) / g, s.paddingRight = m(v, 0, 16) / g, s.paddingBottom = m(v, 16, 16) / g, e._textDivProperties.set(o, s) }!
  else s.paddingLeft = t[a].left - n[a].left, s.paddingTop = t[a].top - n[a].top, s.paddingRight = n[a].right - t[a].right, s.paddingBottom = n[a].bottom - t[a].bottom, e._textDivProperties.set(o, s) } } function u(e, t) { t.sort(function (e, t) { return e.x1 - t.x1 || e.index - t.index }); var r = [{ start: -1 / 0, end: 1 / 0, boundary: { x1: -1 / 0, y1: -1 / 0, x2: 0, y2: 1 / 0, index: -1, x1New: 0, x2New: 0 } }]; t.forEach(function (e) { for (var t = 0; t < r.length && r[t].end <= e.y1;)t++; for (var n, i, a = r.length - 1; a >= 0 && r[a].start >= e.y2;)a--; var o, s, u = -1 / 0; for (o = t; o <= a; o++) { var l; (l = (i = (n = r[o]).boundary).x2 > e.x1 ? i.index > e.index ? i.x1New : e.x1 : void 0 === i.x2New ? (i.x2 + e.x1) / 2 : i.x2New) > u && (u = l) } for (e.x1New = u, o = t; o <= a; o++)void 0 === (i = (n = r[o]).boundary).x2New ? i.x2 > e.x1 ? i.index > e.index && (i.x2New = i.x2) : i.x2New = u : i.x2New > u && (i.x2New = Math.max(u, i.x2)); var c = [], h = null; for (o = t; o <= a; o++) { var d = (i = (n = r[o]).boundary).x2 > e.x2 ? i : e; h === d ? c[c.length - 1].end = n.end : (c.push({ start: n.start, end: n.end, boundary: d }), h = d) } for (r[t].start < e.y1 && (c[0].start = e.y1, c.unshift({ start: r[t].start, end: e.y1, boundary: r[t].boundary })), e.y2 < r[a].end && (c[c.length - 1].end = e.y2, c.push({ start: e.y2, end: r[a].end, boundary: r[a].boundary })), o = t; o <= a; o++)if (void 0 === (i = (n = r[o]).boundary).x2New) { var f = !1; for (s = t - 1; !f && s >= 0 && r[s].start >= i.y1; s--)f = r[s].boundary === i; for (s = a + 1; !f && s < r.length && r[s].end <= i.y2; s++)f = r[s].boundary === i; for (s = 0; !f && s < c.length; s++)f = c[s].boundary === i; f || (i.x2New = u) } Array.prototype.splice.apply(r, [t, a - t + 1].concat(c)) }), r.forEach(function (t) { var r = t.boundary; void 0 === r.x2New && (r.x2New = Math.max(e, r.x2)) }) } function l(e) { var t = e.textContent, r = e.textContentStream, n = e.container, a = e.viewport, s = e.textDivs, u = e.textContentItemsStr, l = e.enhanc!
 eTextSelection; this._textContent = t, this._textContentStream = r, this._container = n, this._viewport = a, this._textDivs = s || [], this._textContentItemsStr = u || [], this._enhanceTextSelection = !!l, this._fontInspectorEnabled = !(!o.default.FontInspector || !o.default.FontInspector.enabled), this._reader = null, this._layoutTextLastFontSize = null, this._layoutTextLastFontFamily = null, this._layoutTextCtx = null, this._textDivProperties = new WeakMap, this._renderingDone = !1, this._canceled = !1, this._capability = (0, i.createPromiseCapability)(), this._renderTimer = null, this._bounds = [] } return l.prototype = { get promise() { return this._capability.promise }, cancel: function () { this._reader && (this._reader.cancel(new i.AbortException("text layer task cancelled")), this._reader = null), this._canceled = !0, null !== this._renderTimer && (clearTimeout(this._renderTimer), this._renderTimer = null), this._capability.reject("canceled") }, _processItems: function (e, t) { for (var r = 0, i = e.length; r < i; r++)this._textContentItemsStr.push(e[r].str), n(this, e[r], t) }, _layoutText: function (e) { var t = this._container, r = this._textDivProperties.get(e); if (!r.isWhitespace) { var n = e.style.fontSize, i = e.style.fontFamily; n === this._layoutTextLastFontSize && i === this._layoutTextLastFontFamily || (this._layoutTextCtx.font = n + " " + i, this._layoutTextLastFontSize = n, this._layoutTextLastFontFamily = i); var a = this._layoutTextCtx.measureText(e.textContent).width, o = ""; 0 !== r.canvasWidth && a > 0 && (r.scale = r.canvasWidth / a, o = "scaleX(" + r.scale + ")"), 0 !== r.angle && (o = "rotate(" + r.angle + "deg) " + o), "" !== o && (r.originalTransform = o, e.style.transform = o), this._textDivProperties.set(e, r), t.appendChild(e) } }, _render: function (e) { var t = this, r = (0, i.createPromiseCapability)(), n = Object.create(null), o = document.createElement("canvas"); if (o.mozOpaque = !0, this._layoutTextCtx = o.getContext("2d", { alpha: !1 }), this._textContent) { var s = thi!
 s._textContent.items, u = this._textContent.styles; this._processItems(s, u), r.resolve() } else { if (!this._textContentStream) throw new Error('Neither "textContent" nor "textContentStream" parameters specified.'); this._reader = this._textContentStream.getReader(), function e() { t._reader.read().then(function (i) { var a = i.value; i.done ? r.resolve() : (Object.assign(n, a.styles), t._processItems(a.items, n), e()) }, r.reject) }() } r.promise.then(function () { n = null, e ? t._renderTimer = setTimeout(function () { a(t), t._renderTimer = null }, e) : a(t) }, this._capability.reject) }, expandTextDivs: function (e) { if (this._enhanceTextSelection && this._renderingDone) { null !== this._bounds && (s(this), this._bounds = null); for (var t = 0, r = this._textDivs.length; t < r; t++) { var n = this._textDivs[t], i = this._textDivProperties.get(n); if (!i.isWhitespace) if (e) { var a = "", o = ""; 1 !== i.scale && (a = "scaleX(" + i.scale + ")"), 0 !== i.angle && (a = "rotate(" + i.angle + "deg) " + a), 0 !== i.paddingLeft && (o += " padding-left: " + i.paddingLeft / i.scale + "px;", a += " translateX(" + -i.paddingLeft / i.scale + "px)"), 0 !== i.paddingTop && (o += " padding-top: " + i.paddingTop + "px;", a += " translateY(" + -i.paddingTop + "px)"), 0 !== i.paddingRight && (o += " padding-right: " + i.paddingRight / i.scale + "px;"), 0 !== i.paddingBottom && (o += " padding-bottom: " + i.paddingBottom + "px;"), "" !== o && n.setAttribute("style", i.style + o), "" !== a && (n.style.transform = a) } else n.style.padding = 0, n.style.transform = i.originalTransform || "" } } } }, function (e) { var t = new l({ textContent: e.textContent, textContentStream: e.textContentStream, container: e.container, viewport: e.viewport, textDivs: e.textDivs, textContentItemsStr: e.textContentItemsStr, enhanceTextSelection: e.enhanceTextSelection }); return t._render(e.timeout), t } }(); t.renderTextLayer = s }, function (e, t, r) { "use strict"; Object.defineProperty(t, "__esModule", { value: !0 }), t.AnnotationLayer = voi!
 d 0; var n = function () { function e(e, t) { for (var r = 0; r < t.length; r++) { var n = t[r]; n.enumerable = n.enumerable || !1, n.configurable = !0, "value" in n && (n.writable = !0), Object.defineProperty(e, n.key, n) } } return function (t, r, n) { return r && e(t.prototype, r), n && e(t, n), t } }(), i = r(130), a = r(1); function o(e, t) { if (!e) throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); return !t || "object" != typeof t && "function" != typeof t ? e : t } function s(e, t) { if ("function" != typeof t && null !== t) throw new TypeError("Super expression must either be null or a function, not " + typeof t); e.prototype = Object.create(t && t.prototype, { constructor: { value: e, enumerable: !1, writable: !0, configurable: !0 } }), t && (Object.setPrototypeOf ? Object.setPrototypeOf(e, t) : e.__proto__ = t) } function u(e, t) { if (!(e instanceof t)) throw new TypeError("Cannot call a class as a function") } var l = function () { function e() { u(this, e) } return n(e, null, [{ key: "create", value: function (e) { switch (e.data.annotationType) { case a.AnnotationType.LINK: return new h(e); case a.AnnotationType.TEXT: return new d(e); case a.AnnotationType.WIDGET: switch (e.data.fieldType) { case "Tx": return new p(e); case "Btn": return e.data.radioButton ? new m(e) : e.data.checkBox ? new v(e) : new g(e); case "Ch": return new y(e) }return new f(e); case a.AnnotationType.POPUP: return new b(e); case a.AnnotationType.LINE: return new A(e); case a.AnnotationType.SQUARE: return new S(e); case a.AnnotationType.CIRCLE: return new w(e); case a.AnnotationType.POLYLINE: return new k(e); case a.AnnotationType.INK: return new x(e); case a.AnnotationType.POLYGON: return new P(e); case a.AnnotationType.HIGHLIGHT: return new C(e); case a.AnnotationType.UNDERLINE: return new R(e); case a.AnnotationType.SQUIGGLY: return new E(e); case a.AnnotationType.STRIKEOUT: return new T(e); case a.AnnotationType.STAMP: return new O(e); case a.AnnotationType.FILEATTACHMENT: return new I!
 (e); default: return new c(e) } } }]), e }(), c = function () { function e(t) { var r = arguments.length > 1 && void 0 !== arguments[1] && arguments[1], n = arguments.length > 2 && void 0 !== arguments[2] && arguments[2]; u(this, e), this.isRenderable = r, this.data = t.data, this.layer = t.layer, this.page = t.page, this.viewport = t.viewport, this.linkService = t.linkService, this.downloadManager = t.downloadManager, this.imageResourcesPath = t.imageResourcesPath, this.renderInteractiveForms = t.renderInteractiveForms, this.svgFactory = t.svgFactory, r && (this.container = this._createContainer(n)) } return n(e, [{ key: "_createContainer", value: function () { var e = arguments.length > 0 && void 0 !== arguments[0] && arguments[0], t = this.data, r = this.page, n = this.viewport, i = document.createElement("section"), o = t.rect[2] - t.rect[0], s = t.rect[3] - t.rect[1]; i.setAttribute("data-annotation-id", t.id); var u = a.Util.normalizeRect([t.rect[0], r.view[3] - t.rect[1] + r.view[1], t.rect[2], r.view[3] - t.rect[3] + r.view[1]]); if (i.style.transform = "matrix(" + n.transform.join(",") + ")", i.style.transformOrigin = -u[0] + "px " + -u[1] + "px", !e && t.borderStyle.width > 0) { i.style.borderWidth = t.borderStyle.width + "px", t.borderStyle.style !== a.AnnotationBorderStyleType.UNDERLINE && (o -= 2 * t.borderStyle.width, s -= 2 * t.borderStyle.width); var l = t.borderStyle.horizontalCornerRadius, c = t.borderStyle.verticalCornerRadius; if (l > 0 || c > 0) { var h = l + "px / " + c + "px"; i.style.borderRadius = h } switch (t.borderStyle.style) { case a.AnnotationBorderStyleType.SOLID: i.style.borderStyle = "solid"; break; case a.AnnotationBorderStyleType.DASHED: i.style.borderStyle = "dashed"; break; case a.AnnotationBorderStyleType.BEVELED: (0, a.warn)("Unimplemented border style: beveled"); break; case a.AnnotationBorderStyleType.INSET: (0, a.warn)("Unimplemented border style: inset"); break; case a.AnnotationBorderStyleType.UNDERLINE: i.style.borderBottomStyle = "solid" }t.color ? i.style.borderCol!
 or = a.Util.makeCssRgb(0 | t.color[0], 0 | t.color[1], 0 | t.color[2]) : i.style.borderWidth = 0 } return i.style.left = u[0] + "px", i.style.top = u[1] + "px", i.style.width = o + "px", i.style.height = s + "px", i } }, { key: "_createPopup", value: function (e, t, r) { t || ((t = document.createElement("div")).style.height = e.style.height, t.style.width = e.style.width, e.appendChild(t)); var n = new _({ container: e, trigger: t, color: r.color, title: r.title, contents: r.contents, hideWrapper: !0 }).render(); n.style.left = e.style.width, e.appendChild(n) } }, { key: "render", value: function () { (0, a.unreachable)("Abstract method `AnnotationElement.render` called") } }]), e }(), h = function (e) { function t(e) { u(this, t); var r = !!(e.data.url || e.data.dest || e.data.action); return o(this, (t.__proto__ || Object.getPrototypeOf(t)).call(this, e, r)) } return s(t, c), n(t, [{ key: "render", value: function () { this.container.className = "linkAnnotation"; var e = this.data, t = this.linkService, r = document.createElement("a"); return (0, i.addLinkAttributes)(r, { url: e.url, target: e.newWindow ? i.LinkTarget.BLANK : t.externalLinkTarget, rel: t.externalLinkRel }), e.url || (e.action ? this._bindNamedAction(r, e.action) : this._bindLink(r, e.dest)), this.container.appendChild(r), this.container } }, { key: "_bindLink", value: function (e, t) { var r = this; e.href = this.linkService.getDestinationHash(t), e.onclick = function () { return t && r.linkService.navigateTo(t), !1 }, t && (e.className = "internalLink") } }, { key: "_bindNamedAction", value: function (e, t) { var r = this; e.href = this.linkService.getAnchorUrl(""), e.onclick = function () { return r.linkService.executeNamedAction(t), !1 }, e.className = "internalLink" } }]), t }(), d = function (e) { function t(e) { u(this, t); var r = !!(e.data.hasPopup || e.data.title || e.data.contents); return o(this, (t.__proto__ || Object.getPrototypeOf(t)).call(this, e, r)) } return s(t, c), n(t, [{ key: "render", value: function () { this.container.!
 className = "textAnnotation"; var e = document.createElement("img"); return e.style.height = this.container.style.height, e.style.width = this.container.style.width, e.src = this.imageResourcesPath + "annotation-" + this.data.name.toLowerCase() + ".svg", e.alt = "[{{type}} Annotation]", e.dataset.l10nId = "text_annotation_type", e.dataset.l10nArgs = JSON.stringify({ type: this.data.name }), this.data.hasPopup || this._createPopup(this.container, e, this.data), this.container.appendChild(e), this.container } }]), t }(), f = function (e) { function t() { return u(this, t), o(this, (t.__proto__ || Object.getPrototypeOf(t)).apply(this, arguments)) } return s(t, c), n(t, [{ key: "render", value: function () { return this.container } }]), t }(), p = function (e) { function t(e) { u(this, t); var r = e.renderInteractiveForms || !e.data.hasAppearance && !!e.data.fieldValue; return o(this, (t.__proto__ || Object.getPrototypeOf(t)).call(this, e, r)) } return s(t, f), n(t, [{ key: "render", value: function () { this.container.className = "textWidgetAnnotation"; var e = null; if (this.renderInteractiveForms) { if (this.data.multiLine ? (e = document.createElement("textarea")).textContent = this.data.fieldValue : ((e = document.createElement("input")).type = "text", e.setAttribute("value", this.data.fieldValue)), e.disabled = this.data.readOnly, null !== this.data.maxLen && (e.maxLength = this.data.maxLen), this.data.comb) { var t = (this.data.rect[2] - this.data.rect[0]) / this.data.maxLen; e.classList.add("comb"), e.style.letterSpacing = "calc(" + t + "px - 1ch)" } } else { (e = document.createElement("div")).textContent = this.data.fieldValue, e.style.verticalAlign = "middle", e.style.display = "table-cell"; var r = null; this.data.fontRefName && (r = this.page.commonObjs.getData(this.data.fontRefName)), this._setTextStyle(e, r) } return null !== this.data.textAlignment && (e.style.textAlign = ["left", "center", "right"][this.data.textAlignment]), this.container.appendChild(e), this.container } }, { key: "_setTextStyle", !
 value: function (e, t) { var r = e.style; if (r.fontSize = this.data.fontSize + "px", r.direction = this.data.fontDirection < 0 ? "rtl" : "ltr", t) { r.fontWeight = t.black ? t.bold ? "900" : "bold" : t.bold ? "bold" : "normal", r.fontStyle = t.italic ? "italic" : "normal"; var n = t.loadedName ? '"' + t.loadedName + '", ' : "", i = t.fallbackName || "Helvetica, sans-serif"; r.fontFamily = n + i } } }]), t }(), v = function (e) { function t(e) { return u(this, t), o(this, (t.__proto__ || Object.getPrototypeOf(t)).call(this, e, e.renderInteractiveForms)) } return s(t, f), n(t, [{ key: "render", value: function () { this.container.className = "buttonWidgetAnnotation checkBox"; var e = document.createElement("input"); return e.disabled = this.data.readOnly, e.type = "checkbox", this.data.fieldValue && "Off" !== this.data.fieldValue && e.setAttribute("checked", !0), this.container.appendChild(e), this.container } }]), t }(), m = function (e) { function t(e) { return u(this, t), o(this, (t.__proto__ || Object.getPrototypeOf(t)).call(this, e, e.renderInteractiveForms)) } return s(t, f), n(t, [{ key: "render", value: function () { this.container.className = "buttonWidgetAnnotation radioButton"; var e = document.createElement("input"); return e.disabled = this.data.readOnly, e.type = "radio", e.name = this.data.fieldName, this.data.fieldValue === this.data.buttonValue && e.setAttribute("checked", !0), this.container.appendChild(e), this.container } }]), t }(), g = function (e) { function t() { return u(this, t), o(this, (t.__proto__ || Object.getPrototypeOf(t)).apply(this, arguments)) } return s(t, h), n(t, [{ key: "render", value: function () { var e = function e(t, r, n) { null === t && (t = Function.prototype); var i = Object.getOwnPropertyDescriptor(t, r); if (void 0 === i) { var a = Object.getPrototypeOf(t); return null === a ? void 0 : e(a, r, n) } if ("value" in i) return i.value; var o = i.get; return void 0 !== o ? o.call(n) : void 0 }(t.prototype.__proto__ || Object.getPrototypeOf(t.prototype), "render", this)!
 .call(this); return e.className = "buttonWidgetAnnotation pushButton", e } }]), t }(), y = function (e) { function t(e) { return u(this, t), o(this, (t.__proto__ || Object.getPrototypeOf(t)).call(this, e, e.renderInteractiveForms)) } return s(t, f), n(t, [{ key: "render", value: function () { this.container.className = "choiceWidgetAnnotation"; var e = document.createElement("select"); e.disabled = this.data.readOnly, this.data.combo || (e.size = this.data.options.length, this.data.multiSelect && (e.multiple = !0)); for (var t = 0, r = this.data.options.length; t < r; t++) { var n = this.data.options[t], i = document.createElement("option"); i.textContent = n.displayValue, i.value = n.exportValue, this.data.fieldValue.includes(n.displayValue) && i.setAttribute("selected", !0), e.appendChild(i) } return this.container.appendChild(e), this.container } }]), t }(), b = function (e) { function t(e) { u(this, t); var r = !(!e.data.title && !e.data.contents); return o(this, (t.__proto__ || Object.getPrototypeOf(t)).call(this, e, r)) } return s(t, c), n(t, [{ key: "render", value: function () { if (this.container.className = "popupAnnotation", ["Line", "Square", "Circle", "PolyLine", "Polygon", "Ink"].includes(this.data.parentType)) return this.container; var e = '[data-annotation-id="' + this.data.parentId + '"]', t = this.layer.querySelector(e); if (!t) return this.container; var r = new _({ container: this.container, trigger: t, color: this.data.color, title: this.data.title, contents: this.data.contents }), n = parseFloat(t.style.left), i = parseFloat(t.style.width); return this.container.style.transformOrigin = -(n + i) + "px -" + t.style.top, this.container.style.left = n + i + "px", this.container.appendChild(r.render()), this.container } }]), t }(), _ = function () { function e(t) { u(this, e), this.container = t.container, this.trigger = t.trigger, this.color = t.color, this.title = t.title, this.contents = t.contents, this.hideWrapper = t.hideWrapper || !1, this.pinned = !1 } return n(e, [{ key: "render", valu!
 e: function () { var e = document.createElement("div"); e.className = "popupWrapper", this.hideElement = this.hideWrapper ? e : this.container, this.hideElement.setAttribute("hidden", !0); var t = document.createElement("div"); t.className = "popup"; var r = this.color; if (r) { var n = .7 * (255 - r[0]) + r[0], i = .7 * (255 - r[1]) + r[1], o = .7 * (255 - r[2]) + r[2]; t.style.backgroundColor = a.Util.makeCssRgb(0 | n, 0 | i, 0 | o) } var s = this._formatContents(this.contents), u = document.createElement("h1"); return u.textContent = this.title, this.trigger.addEventListener("click", this._toggle.bind(this)), this.trigger.addEventListener("mouseover", this._show.bind(this, !1)), this.trigger.addEventListener("mouseout", this._hide.bind(this, !1)), t.addEventListener("click", this._hide.bind(this, !0)), t.appendChild(u), t.appendChild(s), e.appendChild(t), e } }, { key: "_formatContents", value: function (e) { for (var t = document.createElement("p"), r = e.split(/(?:\r\n?|\n)/), n = 0, i = r.length; n < i; ++n) { var a = r[n]; t.appendChild(document.createTextNode(a)), n < i - 1 && t.appendChild(document.createElement("br")) } return t } }, { key: "_toggle", value: function () { this.pinned ? this._hide(!0) : this._show(!0) } }, { key: "_show", value: function () { arguments.length > 0 && void 0 !== arguments[0] && arguments[0] && (this.pinned = !0), this.hideElement.hasAttribute("hidden") && (this.hideElement.removeAttribute("hidden"), this.container.style.zIndex += 1) } }, { key: "_hide", value: function () { (!(arguments.length > 0 && void 0 !== arguments[0]) || arguments[0]) && (this.pinned = !1), this.hideElement.hasAttribute("hidden") || this.pinned || (this.hideElement.setAttribute("hidden", !0), this.container.style.zIndex -= 1) } }]), e }(), A = function (e) { function t(e) { u(this, t); var r = !!(e.data.hasPopup || e.data.title || e.data.contents); return o(this, (t.__proto__ || Object.getPrototypeOf(t)).call(this, e, r, !0)) } return s(t, c), n(t, [{ key: "render", value: function () { this.contai!
 ner.className = "lineAnnotation"; var e = this.data, t = e.rect[2] - e.rect[0], r = e.rect[3] - e.rect[1], n = this.svgFactory.create(t, r), i = this.svgFactory.createElement("svg:line"); return i.setAttribute("x1", e.rect[2] - e.lineCoordinates[0]), i.setAttribute("y1", e.rect[3] - e.lineCoordinates[1]), i.setAttribute("x2", e.rect[2] - e.lineCoordinates[2]), i.setAttribute("y2", e.rect[3] - e.lineCoordinates[3]), i.setAttribute("stroke-width", e.borderStyle.width), i.setAttribute("stroke", "transparent"), n.appendChild(i), this.container.append(n), this._createPopup(this.container, i, e), this.container } }]), t }(), S = function (e) { function t(e) { u(this, t); var r = !!(e.data.hasPopup || e.data.title || e.data.contents); return o(this, (t.__proto__ || Object.getPrototypeOf(t)).call(this, e, r, !0)) } return s(t, c), n(t, [{ key: "render", value: function () { this.container.className = "squareAnnotation"; var e = this.data, t = e.rect[2] - e.rect[0], r = e.rect[3] - e.rect[1], n = this.svgFactory.create(t, r), i = e.borderStyle.width, a = this.svgFactory.createElement("svg:rect"); return a.setAttribute("x", i / 2), a.setAttribute("y", i / 2), a.setAttribute("width", t - i), a.setAttribute("height", r - i), a.setAttribute("stroke-width", i), a.setAttribute("stroke", "transparent"), a.setAttribute("fill", "none"), n.appendChild(a), this.container.append(n), this._createPopup(this.container, a, e), this.container } }]), t }(), w = function (e) { function t(e) { u(this, t); var r = !!(e.data.hasPopup || e.data.title || e.data.contents); return o(this, (t.__proto__ || Object.getPrototypeOf(t)).call(this, e, r, !0)) } return s(t, c), n(t, [{ key: "render", value: function () { this.container.className = "circleAnnotation"; var e = this.data, t = e.rect[2] - e.rect[0], r = e.rect[3] - e.rect[1], n = this.svgFactory.create(t, r), i = e.borderStyle.width, a = this.svgFactory.createElement("svg:ellipse"); return a.setAttribute("cx", t / 2), a.setAttribute("cy", r / 2), a.setAttribute("rx", t / 2 - i / 2), a.setAttr!
 ibute("ry", r / 2 - i / 2), a.setAttribute("stroke-width", i), a.setAttribute("stroke", "transparent"), a.setAttribute("fill", "none"), n.appendChild(a), this.container.append(n), this._createPopup(this.container, a, e), this.container } }]), t }(), k = function (e) { function t(e) { u(this, t); var r = !!(e.data.hasPopup || e.data.title || e.data.contents), n = o(this, (t.__proto__ || Object.getPrototypeOf(t)).call(this, e, r, !0)); return n.containerClassName = "polylineAnnotation", n.svgElementName = "svg:polyline", n } return s(t, c), n(t, [{ key: "render", value: function () { this.container.className = this.containerClassName; for (var e = this.data, t = e.rect[2] - e.rect[0], r = e.rect[3] - e.rect[1], n = this.svgFactory.create(t, r), i = e.vertices, a = [], o = 0, s = i.length; o < s; o++) { var u = i[o].x - e.rect[0], l = e.rect[3] - i[o].y; a.push(u + "," + l) } a = a.join(" "); var c = e.borderStyle.width, h = this.svgFactory.createElement(this.svgElementName); return h.setAttribute("points", a), h.setAttribute("stroke-width", c), h.setAttribute("stroke", "transparent"), h.setAttribute("fill", "none"), n.appendChild(h), this.container.append(n), this._createPopup(this.container, h, e), this.container } }]), t }(), P = function (e) { function t(e) { u(this, t); var r = o(this, (t.__proto__ || Object.getPrototypeOf(t)).call(this, e)); return r.containerClassName = "polygonAnnotation", r.svgElementName = "svg:polygon", r } return s(t, k), t }(), x = function (e) { function t(e) { u(this, t); var r = !!(e.data.hasPopup || e.data.title || e.data.contents), n = o(this, (t.__proto__ || Object.getPrototypeOf(t)).call(this, e, r, !0)); return n.containerClassName = "inkAnnotation", n.svgElementName = "svg:polyline", n } return s(t, c), n(t, [{ key: "render", value: function () { this.container.className = this.containerClassName; for (var e = this.data, t = e.rect[2] - e.rect[0], r = e.rect[3] - e.rect[1], n = this.svgFactory.create(t, r), i = e.inkLists, a = 0, o = i.length; a < o; a++) { for (var s = i[a], !
 u = [], l = 0, c = s.length; l < c; l++) { var h = s[l].x - e.rect[0], d = e.rect[3] - s[l].y; u.push(h + "," + d) } u = u.join(" "); var f = e.borderStyle.width, p = this.svgFactory.createElement(this.svgElementName); p.setAttribute("points", u), p.setAttribute("stroke-width", f), p.setAttribute("stroke", "transparent"), p.setAttribute("fill", "none"), this._createPopup(this.container, p, e), n.appendChild(p) } return this.container.append(n), this.container } }]), t }(), C = function (e) { function t(e) { u(this, t); var r = !!(e.data.hasPopup || e.data.title || e.data.contents); return o(this, (t.__proto__ || Object.getPrototypeOf(t)).call(this, e, r, !0)) } return s(t, c), n(t, [{ key: "render", value: function () { return this.container.className = "highlightAnnotation", this.data.hasPopup || this._createPopup(this.container, null, this.data), this.container } }]), t }(), R = function (e) { function t(e) { u(this, t); var r = !!(e.data.hasPopup || e.data.title || e.data.contents); return o(this, (t.__proto__ || Object.getPrototypeOf(t)).call(this, e, r, !0)) } return s(t, c), n(t, [{ key: "render", value: function () { return this.container.className = "underlineAnnotation", this.data.hasPopup || this._createPopup(this.container, null, this.data), this.container } }]), t }(), E = function (e) { function t(e) { u(this, t); var r = !!(e.data.hasPopup || e.data.title || e.data.contents); return o(this, (t.__proto__ || Object.getPrototypeOf(t)).call(this, e, r, !0)) } return s(t, c), n(t, [{ key: "render", value: function () { return this.container.className = "squigglyAnnotation", this.data.hasPopup || this._createPopup(this.container, null, this.data), this.container } }]), t }(), T = function (e) { function t(e) { u(this, t); var r = !!(e.data.hasPopup || e.data.title || e.data.contents); return o(this, (t.__proto__ || Object.getPrototypeOf(t)).call(this, e, r, !0)) } return s(t, c), n(t, [{ key: "render", value: function () { return this.container.className = "strikeoutAnnotation", this.data.hasPopup || thi!
 s._createPopup(this.container, null, this.data), this.container } }]), t }(), O = function (e) { function t(e) { u(this, t); var r = !!(e.data.hasPopup || e.data.title || e.data.contents); return o(this, (t.__proto__ || Object.getPrototypeOf(t)).call(this, e, r, !0)) } return s(t, c), n(t, [{ key: "render", value: function () { return this.container.className = "stampAnnotation", this.data.hasPopup || this._createPopup(this.container, null, this.data), this.container } }]), t }(), I = function (e) { function t(e) { u(this, t); var r = o(this, (t.__proto__ || Object.getPrototypeOf(t)).call(this, e, !0)), n = r.data.file, s = n.filename, l = n.content; return r.filename = (0, i.getFilenameFromUrl)(s), r.content = l, r.linkService.eventBus && r.linkService.eventBus.dispatch("fileattachmentannotation", { source: r, id: (0, a.stringToPDFString)(s), filename: s, content: l }), r } return s(t, c), n(t, [{ key: "render", value: function () { this.container.className = "fileAttachmentAnnotation"; var e = document.createElement("div"); return e.style.height = this.container.style.height, e.style.width = this.container.style.width, e.addEventListener("dblclick", this._download.bind(this)), this.data.hasPopup || !this.data.title && !this.data.contents || this._createPopup(this.container, e, this.data), this.container.appendChild(e), this.container } }, { key: "_download", value: function () { this.downloadManager ? this.downloadManager.downloadData(this.content, this.filename, "") : (0, a.warn)("Download cannot be started due to unavailable download manager") } }]), t }(), F = function () { function e() { u(this, e) } return n(e, null, [{ key: "render", value: function (e) { for (var t = 0, r = e.annotations.length; t < r; t++) { var n = e.annotations[t]; if (n) { var a = l.create({ data: n, layer: e.div, page: e.page, viewport: e.viewport, linkService: e.linkService, downloadManager: e.downloadManager, imageResourcesPath: e.imageResourcesPath || "", renderInteractiveForms: e.renderInteractiveForms || !1, svgFactory: new i.!
 DOMSVGFactory }); a.isRenderable && e.div.appendChild(a.render()) } } } }, { key: "update", value: function (e) { for (var t = 0, r = e.annotations.length; t < r; t++) { var n = e.annotations[t], i = e.div.querySelector('[data-annotation-id="' + n.id + '"]'); i && (i.style.transform = "matrix(" + e.viewport.transform.join(",") + ")") } e.div.removeAttribute("hidden") } }]), e }(); t.AnnotationLayer = F }, function (e, t, r) { "use strict"; Object.defineProperty(t, "__esModule", { value: !0 }), t.SVGGraphics = void 0; var n, i = r(1), a = r(130), o = r(4), s = (n = o) && n.__esModule ? n : { default: n }; var u, l = { fontStyle: "normal", fontWeight: "normal", fillColor: "#000000" }, c = function () { for (var e = new Uint8Array([137, 80, 78, 71, 13, 10, 26, 10]), t = 12, r = new Int32Array(256), n = 0; n < 256; n++) { for (var a = n, o = 0; o < 8; o++)a = 1 & a ? 3988292384 ^ a >> 1 & 2147483647 : a >> 1 & 2147483647; r[n] = a } function u(e, t, n, i) { var a = i, o = t.length; n[a] = o >> 24 & 255, n[a + 1] = o >> 16 & 255, n[a + 2] = o >> 8 & 255, n[a + 3] = 255 & o, n[a += 4] = 255 & e.charCodeAt(0), n[a + 1] = 255 & e.charCodeAt(1), n[a + 2] = 255 & e.charCodeAt(2), n[a + 3] = 255 & e.charCodeAt(3), a += 4, n.set(t, a); var s = function (e, t, n) { for (var i = -1, a = t; a < n; a++) { var o = 255 & (i ^ e[a]); i = i >>> 8 ^ r[o] } return -1 ^ i }(n, i + 4, a += t.length); n[a] = s >> 24 & 255, n[a + 1] = s >> 16 & 255, n[a + 2] = s >> 8 & 255, n[a + 3] = 255 & s } function l(e) { var t = e.length, r = Math.ceil(t / 65535), n = new Uint8Array(2 + t + 5 * r + 4), i = 0; n[i++] = 120, n[i++] = 156; for (var a = 0; t > 65535;)n[i++] = 0, n[i++] = 255, n[i++] = 255, n[i++] = 0, n[i++] = 0, n.set(e.subarray(a, a + 65535), i), i += 65535, a += 65535, t -= 65535; n[i++] = 1, n[i++] = 255 & t, n[i++] = t >> 8 & 255, n[i++] = 255 & ~t, n[i++] = (65535 & ~t) >> 8 & 255, n.set(e.subarray(a), i), i += e.length - a; var o = function (e, t, r) { for (var n = 1, i = 0, a = t; a < r; ++a)i = (i + (n = (n + (255 & e[a])) % 6!
 5521)) % 65521; return i << 16 | n }(e, 0, e.length); return n[i++] = o >> 24 & 255, n[i++] = o >> 16 & 255, n[i++] = o >> 8 & 255, n[i++] = 255 & o, n } function c(r, n, a, o) { var c, h, d, f = r.width, p = r.height, v = r.data; switch (n) { case i.ImageKind.GRAYSCALE_1BPP: h = 0, c = 1, d = f + 7 >> 3; break; case i.ImageKind.RGB_24BPP: h = 2, c = 8, d = 3 * f; break; case i.ImageKind.RGBA_32BPP: h = 6, c = 8, d = 4 * f; break; default: throw new Error("invalid format") }var m, g, y = new Uint8Array((1 + d) * p), b = 0, _ = 0; for (m = 0; m < p; ++m)y[b++] = 0, y.set(v.subarray(_, _ + d), b), _ += d, b += d; if (n === i.ImageKind.GRAYSCALE_1BPP && o) for (b = 0, m = 0; m < p; m++)for (b++, g = 0; g < d; g++)y[b++] ^= 255; var A = new Uint8Array([f >> 24 & 255, f >> 16 & 255, f >> 8 & 255, 255 & f, p >> 24 & 255, p >> 16 & 255, p >> 8 & 255, 255 & p, c, h, 0, 0, 0]), S = function (e) { if (!(0, s.default)()) return l(e); try { var t; t = parseInt(process.versions.node) >= 8 ? e : new Buffer(e); var r = require("zlib").deflateSync(t, { level: 9 }); return r instanceof Uint8Array ? r : new Uint8Array(r) } catch (e) { (0, i.warn)("Not compressing PNG because zlib.deflateSync is unavailable: " + e) } return l(e) }(y), w = e.length + 3 * t + A.length + S.length, k = new Uint8Array(w), P = 0; return k.set(e, P), u("IHDR", A, k, P += e.length), u("IDATA", S, k, P += t + A.length), P += t + S.length, u("IEND", new Uint8Array(0), k, P), (0, i.createObjectURL)(k, "image/png", a) } return function (e, t, r) { return c(e, void 0 === e.kind ? i.ImageKind.GRAYSCALE_1BPP : e.kind, t, r) } }(), h = function () { function e() { this.fontSizeScale = 1, this.fontWeight = l.fontWeight, this.fontSize = 0, this.textMatrix = i.IDENTITY_MATRIX, this.fontMatrix = i.FONT_IDENTITY_MATRIX, this.leading = 0, this.textRenderingMode = i.TextRenderingMode.FILL, this.x = 0, this.y = 0, this.lineX = 0, this.lineY = 0, this.charSpacing = 0, this.wordSpacing = 0, this.textHScale = 1, this.textRise = 0, this.fillColor = l.fillColor, this.strokeCo!
 lor = "#000000", this.fillAlpha = 1, this.strokeAlpha = 1, this.lineWidth = 1, this.lineJoin = "", this.lineCap = "", this.miterLimit = 0, this.dashArray = [], this.dashPhase = 0, this.dependencies = [], this.activeClipUrl = null, this.clipGroup = null, this.maskId = "" } return e.prototype = { clone: function () { return Object.create(this) }, setCurrentPoint: function (e, t) { this.x = e, this.y = t } }, e }(); t.SVGGraphics = u = function () { function e(e) { if (Number.isInteger(e)) return e.toString(); var t = e.toFixed(10), r = t.length - 1; if ("0" !== t[r]) return t; do { r-- } while ("0" === t[r]); return t.substring(0, "." === t[r] ? r : r + 1) } function t(t) { if (0 === t[4] && 0 === t[5]) { if (0 === t[1] && 0 === t[2]) return 1 === t[0] && 1 === t[3] ? "" : "scale(" + e(t[0]) + " " + e(t[3]) + ")"; if (t[0] === t[3] && t[1] === -t[2]) return "rotate(" + e(180 * Math.acos(t[0]) / Math.PI) + ")" } else if (1 === t[0] && 0 === t[1] && 0 === t[2] && 1 === t[3]) return "translate(" + e(t[4]) + " " + e(t[5]) + ")"; return "matrix(" + e(t[0]) + " " + e(t[1]) + " " + e(t[2]) + " " + e(t[3]) + " " + e(t[4]) + " " + e(t[5]) + ")" } function r(e, t, r) { this.svgFactory = new a.DOMSVGFactory, this.current = new h, this.transformMatrix = i.IDENTITY_MATRIX, this.transformStack = [], this.extraStack = [], this.commonObjs = e, this.objs = t, this.pendingClip = null, this.pendingEOFill = !1, this.embedFonts = !1, this.embeddedFonts = Object.create(null), this.cssStyle = null, this.forceDataSchema = !!r } var n = "http://www.w3.org/1999/xlink", o = ["butt", "round", "square"], s = ["miter", "round", "bevel"], u = 0, d = 0; return r.prototype = { save: function () { this.transformStack.push(this.transformMatrix); var e = this.current; this.extraStack.push(e), this.current = e.clone() }, restore: function () { this.transformMatrix = this.transformStack.pop(), this.current = this.extraStack.pop(), this.pendingClip = null, this.tgrp = null }, group: function (e) { this.save(), this.executeOpTree(e), this.restore() }, l!
 oadDependencies: function (e) { for (var t = this, r = e.fnArray, n = r.length, a = e.argsArray, o = 0; o < n; o++)if (i.OPS.dependency === r[o]) for (var s = a[o], u = 0, l = s.length; u < l; u++) { var c, h = s[u]; c = "g_" === h.substring(0, 2) ? new Promise(function (e) { t.commonObjs.get(h, e) }) : new Promise(function (e) { t.objs.get(h, e) }), this.current.dependencies.push(c) } return Promise.all(this.current.dependencies) }, transform: function (e, t, r, n, a, o) { var s = [e, t, r, n, a, o]; this.transformMatrix = i.Util.transform(this.transformMatrix, s), this.tgrp = null }, getSVG: function (e, t) { var r = this; this.viewport = t; var n = this._initialize(t); return this.loadDependencies(e).then(function () { r.transformMatrix = i.IDENTITY_MATRIX; var t = r.convertOpList(e); return r.executeOpTree(t), n }) }, convertOpList: function (e) { var t = e.argsArray, r = e.fnArray, n = r.length, a = [], o = []; for (var s in i.OPS) a[i.OPS[s]] = s; for (var u = 0; u < n; u++) { var l = r[u]; o.push({ fnId: l, fn: a[l], args: t[u] }) } return function (e) { for (var t = [], r = [], n = e.length, i = 0; i < n; i++)"save" !== e[i].fn ? "restore" === e[i].fn ? t = r.pop() : t.push(e[i]) : (t.push({ fnId: 92, fn: "group", items: [] }), r.push(t), t = t[t.length - 1].items); return t }(o) }, executeOpTree: function (e) { for (var t = e.length, r = 0; r < t; r++) { var n = e[r].fn, a = e[r].fnId, o = e[r].args; switch (0 | a) { case i.OPS.beginText: this.beginText(); break; case i.OPS.dependency: break; case i.OPS.setLeading: this.setLeading(o); break; case i.OPS.setLeadingMoveText: this.setLeadingMoveText(o[0], o[1]); break; case i.OPS.setFont: this.setFont(o); break; case i.OPS.showText: case i.OPS.showSpacedText: this.showText(o[0]); break; case i.OPS.endText: this.endText(); break; case i.OPS.moveText: this.moveText(o[0], o[1]); break; case i.OPS.setCharSpacing: this.setCharSpacing(o[0]); break; case i.OPS.setWordSpacing: this.setWordSpacing(o[0]); break; case i.OPS.setHScale: this.setHScale(o[0]); break; case!
  i.OPS.setTextMatrix: this.setTextMatrix(o[0], o[1], o[2], o[3], o[4], o[5]); break; case i.OPS.setTextRise: this.setTextRise(o[0]); break; case i.OPS.setTextRenderingMode: this.setTextRenderingMode(o[0]); break; case i.OPS.setLineWidth: this.setLineWidth(o[0]); break; case i.OPS.setLineJoin: this.setLineJoin(o[0]); break; case i.OPS.setLineCap: this.setLineCap(o[0]); break; case i.OPS.setMiterLimit: this.setMiterLimit(o[0]); break; case i.OPS.setFillRGBColor: this.setFillRGBColor(o[0], o[1], o[2]); break; case i.OPS.setStrokeRGBColor: this.setStrokeRGBColor(o[0], o[1], o[2]); break; case i.OPS.setDash: this.setDash(o[0], o[1]); break; case i.OPS.setGState: this.setGState(o[0]); break; case i.OPS.fill: this.fill(); break; case i.OPS.eoFill: this.eoFill(); break; case i.OPS.stroke: this.stroke(); break; case i.OPS.fillStroke: this.fillStroke(); break; case i.OPS.eoFillStroke: this.eoFillStroke(); break; case i.OPS.clip: this.clip("nonzero"); break; case i.OPS.eoClip: this.clip("evenodd"); break; case i.OPS.paintSolidColorImageMask: this.paintSolidColorImageMask(); break; case i.OPS.paintJpegXObject: this.paintJpegXObject(o[0], o[1], o[2]); break; case i.OPS.paintImageXObject: this.paintImageXObject(o[0]); break; case i.OPS.paintInlineImageXObject: this.paintInlineImageXObject(o[0]); break; case i.OPS.paintImageMaskXObject: this.paintImageMaskXObject(o[0]); break; case i.OPS.paintFormXObjectBegin: this.paintFormXObjectBegin(o[0], o[1]); break; case i.OPS.paintFormXObjectEnd: this.paintFormXObjectEnd(); break; case i.OPS.closePath: this.closePath(); break; case i.OPS.closeStroke: this.closeStroke(); break; case i.OPS.closeFillStroke: this.closeFillStroke(); break; case i.OPS.closeEOFillStroke: this.closeEOFillStroke(); break; case i.OPS.nextLine: this.nextLine(); break; case i.OPS.transform: this.transform(o[0], o[1], o[2], o[3], o[4], o[5]); break; case i.OPS.constructPath: this.constructPath(o[0], o[1]); break; case i.OPS.endPath: this.endPath(); break; case 92: this.group(e[r].items); break; default: (0, i.warn)!
 ("Unimplemented operator " + n) } } }, setWordSpacing: function (e) { this.current.wordSpacing = e }, setCharSpacing: function (e) { this.current.charSpacing = e }, nextLine: function () { this.moveText(0, this.current.leading) }, setTextMatrix: function (t, r, n, i, a, o) { var s = this.current; this.current.textMatrix = this.current.lineMatrix = [t, r, n, i, a, o], this.current.x = this.current.lineX = 0, this.current.y = this.current.lineY = 0, s.xcoords = [], s.tspan = this.svgFactory.createElement("svg:tspan"), s.tspan.setAttributeNS(null, "font-family", s.fontFamily), s.tspan.setAttributeNS(null, "font-size", e(s.fontSize) + "px"), s.tspan.setAttributeNS(null, "y", e(-s.y)), s.txtElement = this.svgFactory.createElement("svg:text"), s.txtElement.appendChild(s.tspan) }, beginText: function () { this.current.x = this.current.lineX = 0, this.current.y = this.current.lineY = 0, this.current.textMatrix = i.IDENTITY_MATRIX, this.current.lineMatrix = i.IDENTITY_MATRIX, this.current.tspan = this.svgFactory.createElement("svg:tspan"), this.current.txtElement = this.svgFactory.createElement("svg:text"), this.current.txtgrp = this.svgFactory.createElement("svg:g"), this.current.xcoords = [] }, moveText: function (t, r) { var n = this.current; this.current.x = this.current.lineX += t, this.current.y = this.current.lineY += r, n.xcoords = [], n.tspan = this.svgFactory.createElement("svg:tspan"), n.tspan.setAttributeNS(null, "font-family", n.fontFamily), n.tspan.setAttributeNS(null, "font-size", e(n.fontSize) + "px"), n.tspan.setAttributeNS(null, "y", e(-n.y)) }, showText: function (r) { var n = this.current, a = n.font, o = n.fontSize; if (0 !== o) { var s, u = n.charSpacing, c = n.wordSpacing, h = n.fontDirection, d = n.textHScale * h, f = r.length, p = a.vertical, v = o * n.fontMatrix[0], m = 0; for (s = 0; s < f; ++s) { var g = r[s]; if (null !== g) if ((0, i.isNum)(g)) m += -g * o * .001; else { var y = g.width, b = g.fontChar, _ = y * v + ((g.isSpace ? c : 0) + u) * h; g.isInFont || a.missingFile ? (n.xcoords.push(!
 n.x + m * d), n.tspan.textContent += b, m += _) : m += _ } else m += h * c } p ? n.y -= m * d : n.x += m * d, n.tspan.setAttributeNS(null, "x", n.xcoords.map(e).join(" ")), n.tspan.setAttributeNS(null, "y", e(-n.y)), n.tspan.setAttributeNS(null, "font-family", n.fontFamily), n.tspan.setAttributeNS(null, "font-size", e(n.fontSize) + "px"), n.fontStyle !== l.fontStyle && n.tspan.setAttributeNS(null, "font-style", n.fontStyle), n.fontWeight !== l.fontWeight && n.tspan.setAttributeNS(null, "font-weight", n.fontWeight); var A = n.textRenderingMode & i.TextRenderingMode.FILL_STROKE_MASK; A === i.TextRenderingMode.FILL || A === i.TextRenderingMode.FILL_STROKE ? (n.fillColor !== l.fillColor && n.tspan.setAttributeNS(null, "fill", n.fillColor), n.fillAlpha < 1 && n.tspan.setAttributeNS(null, "fill-opacity", n.fillAlpha)) : n.textRenderingMode === i.TextRenderingMode.ADD_TO_PATH ? n.tspan.setAttributeNS(null, "fill", "transparent") : n.tspan.setAttributeNS(null, "fill", "none"), A !== i.TextRenderingMode.STROKE && A !== i.TextRenderingMode.FILL_STROKE || this._setStrokeAttributes(n.tspan); var S = n.textMatrix; 0 !== n.textRise && ((S = S.slice())[5] += n.textRise), n.txtElement.setAttributeNS(null, "transform", t(S) + " scale(1, -1)"), n.txtElement.setAttributeNS("http://www.w3.org/XML/1998/namespace", "xml:space", "preserve"), n.txtElement.appendChild(n.tspan), n.txtgrp.appendChild(n.txtElement), this._ensureTransformGroup().appendChild(n.txtElement) } }, setLeadingMoveText: function (e, t) { this.setLeading(-t), this.moveText(e, t) }, addFontStyle: function (e) { this.cssStyle || (this.cssStyle = this.svgFactory.createElement("svg:style"), this.cssStyle.setAttributeNS(null, "type", "text/css"), this.defs.appendChild(this.cssStyle)); var t = (0, i.createObjectURL)(e.data, e.mimetype, this.forceDataSchema); this.cssStyle.textContent += '@font-face { font-family: "' + e.loadedName + '"; src: url(' + t + "); }\n" }, setFont: function (t) { var r = this.current, n = this.commonObjs.get(t[0]), a = t[1]; this.current.font = n!
 , this.embedFonts && n.data && !this.embeddedFonts[n.loadedName] && (this.addFontStyle(n), this.embeddedFonts[n.loadedName] = n), r.fontMatrix = n.fontMatrix ? n.fontMatrix : i.FONT_IDENTITY_MATRIX; var o = n.black ? n.bold ? "bolder" : "bold" : n.bold ? "bold" : "normal", s = n.italic ? "italic" : "normal"; a < 0 ? (a = -a, r.fontDirection = -1) : r.fontDirection = 1, r.fontSize = a, r.fontFamily = n.loadedName, r.fontWeight = o, r.fontStyle = s, r.tspan = this.svgFactory.createElement("svg:tspan"), r.tspan.setAttributeNS(null, "y", e(-r.y)), r.xcoords = [] }, endText: function () { var e = this.current; e.textRenderingMode & i.TextRenderingMode.ADD_TO_PATH_FLAG && e.txtElement && e.txtElement.hasChildNodes() && (e.element = e.txtElement, this.clip("nonzero"), this.endPath()) }, setLineWidth: function (e) { this.current.lineWidth = e }, setLineCap: function (e) { this.current.lineCap = o[e] }, setLineJoin: function (e) { this.current.lineJoin = s[e] }, setMiterLimit: function (e) { this.current.miterLimit = e }, setStrokeAlpha: function (e) { this.current.strokeAlpha = e }, setStrokeRGBColor: function (e, t, r) { var n = i.Util.makeCssRgb(e, t, r); this.current.strokeColor = n }, setFillAlpha: function (e) { this.current.fillAlpha = e }, setFillRGBColor: function (e, t, r) { var n = i.Util.makeCssRgb(e, t, r); this.current.fillColor = n, this.current.tspan = this.svgFactory.createElement("svg:tspan"), this.current.xcoords = [] }, setDash: function (e, t) { this.current.dashArray = e, this.current.dashPhase = t }, constructPath: function (t, r) { var n = this.current, a = n.x, o = n.y; n.path = this.svgFactory.createElement("svg:path"); for (var s = [], u = t.length, l = 0, c = 0; l < u; l++)switch (0 | t[l]) { case i.OPS.rectangle: a = r[c++], o = r[c++]; var h = a + r[c++], d = o + r[c++]; s.push("M", e(a), e(o), "L", e(h), e(o), "L", e(h), e(d), "L", e(a), e(d), "Z"); break; case i.OPS.moveTo: a = r[c++], o = r[c++], s.push("M", e(a), e(o)); break; case i.OPS.lineTo: a = r[c++], o = r[c++], s.push("L", e(a), !
 e(o)); break; case i.OPS.curveTo: a = r[c + 4], o = r[c + 5], s.push("C", e(r[c]), e(r[c + 1]), e(r[c + 2]), e(r[c + 3]), e(a), e(o)), c += 6; break; case i.OPS.curveTo2: a = r[c + 2], o = r[c + 3], s.push("C", e(a), e(o), e(r[c]), e(r[c + 1]), e(r[c + 2]), e(r[c + 3])), c += 4; break; case i.OPS.curveTo3: a = r[c + 2], o = r[c + 3], s.push("C", e(r[c]), e(r[c + 1]), e(a), e(o), e(a), e(o)), c += 4; break; case i.OPS.closePath: s.push("Z") }n.path.setAttributeNS(null, "d", s.join(" ")), n.path.setAttributeNS(null, "fill", "none"), this._ensureTransformGroup().appendChild(n.path), n.element = n.path, n.setCurrentPoint(a, o) }, endPath: function () { if (this.pendingClip) { var e = this.current, r = "clippath" + u; u++; var n = this.svgFactory.createElement("svg:clipPath"); n.setAttributeNS(null, "id", r), n.setAttributeNS(null, "transform", t(this.transformMatrix)); var i = e.element.cloneNode(!0); "evenodd" === this.pendingClip ? i.setAttributeNS(null, "clip-rule", "evenodd") : i.setAttributeNS(null, "clip-rule", "nonzero"), this.pendingClip = null, n.appendChild(i), this.defs.appendChild(n), e.activeClipUrl && (e.clipGroup = null, this.extraStack.forEach(function (e) { e.clipGroup = null }), n.setAttributeNS(null, "clip-path", e.activeClipUrl)), e.activeClipUrl = "url(#" + r + ")", this.tgrp = null } }, clip: function (e) { this.pendingClip = e }, closePath: function () { var e = this.current; if (e.path) { var t = e.path.getAttributeNS(null, "d"); t += "Z", e.path.setAttributeNS(null, "d", t) } }, setLeading: function (e) { this.current.leading = -e }, setTextRise: function (e) { this.current.textRise = e }, setTextRenderingMode: function (e) { this.current.textRenderingMode = e }, setHScale: function (e) { this.current.textHScale = e / 100 }, setGState: function (e) { for (var t = 0, r = e.length; t < r; t++) { var n = e[t], a = n[0], o = n[1]; switch (a) { case "LW": this.setLineWidth(o); break; case "LC": this.setLineCap(o); break; case "LJ": this.setLineJoin(o); break; case "ML": this.setMiterLimit(o); bre!
 ak; case "D": this.setDash(o[0], o[1]); break; case "Font": this.setFont(o); break; case "CA": this.setStrokeAlpha(o); break; case "ca": this.setFillAlpha(o); break; default: (0, i.warn)("Unimplemented graphic state " + a) } } }, fill: function () { var e = this.current; e.element && (e.element.setAttributeNS(null, "fill", e.fillColor), e.element.setAttributeNS(null, "fill-opacity", e.fillAlpha), this.endPath()) }, stroke: function () { var e = this.current; e.element && (this._setStrokeAttributes(e.element), e.element.setAttributeNS(null, "fill", "none"), this.endPath()) }, _setStrokeAttributes: function (t) { var r = this.current; t.setAttributeNS(null, "stroke", r.strokeColor), t.setAttributeNS(null, "stroke-opacity", r.strokeAlpha), t.setAttributeNS(null, "stroke-miterlimit", e(r.miterLimit)), t.setAttributeNS(null, "stroke-linecap", r.lineCap), t.setAttributeNS(null, "stroke-linejoin", r.lineJoin), t.setAttributeNS(null, "stroke-width", e(r.lineWidth) + "px"), t.setAttributeNS(null, "stroke-dasharray", r.dashArray.map(e).join(" ")), t.setAttributeNS(null, "stroke-dashoffset", e(r.dashPhase) + "px") }, eoFill: function () { this.current.element && this.current.element.setAttributeNS(null, "fill-rule", "evenodd"), this.fill() }, fillStroke: function () { this.stroke(), this.fill() }, eoFillStroke: function () { this.current.element && this.current.element.setAttributeNS(null, "fill-rule", "evenodd"), this.fillStroke() }, closeStroke: function () { this.closePath(), this.stroke() }, closeFillStroke: function () { this.closePath(), this.fillStroke() }, closeEOFillStroke: function () { this.closePath(), this.eoFillStroke() }, paintSolidColorImageMask: function () { var e = this.current, t = this.svgFactory.createElement("svg:rect"); t.setAttributeNS(null, "x", "0"), t.setAttributeNS(null, "y", "0"), t.setAttributeNS(null, "width", "1px"), t.setAttributeNS(null, "height", "1px"), t.setAttributeNS(null, "fill", e.fillColor), this._ensureTransformGroup().appendChild(t) }, paintJpegXObject: function (t, r, i) { var !
 a = this..objs.get(t), o = this.svgFactory.createElement("svg:image"); o.setAttributeNS(n, "xlink:href", a.src), o.setAttributeNS(null, "width", e(r)), o.setAttributeNS(null, "height", e(i)), o.setAttributeNS(null, "x", "0"), o.setAttributeNS(null, "y", e(-i)), o.setAttributeNS(null, "transform", "scale(" + e(1 / r) + " " + e(-1 / i) + ")"), this._ensureTransformGroup().appendChild(o) }, paintImageXObject: function (e) { var t = this.objs.get(e); t ? this.paintInlineImageXObject(t) : (0, i.warn)("Dependent image isn't ready yet") }, paintInlineImageXObject: function (t, r) { var i = t.width, a = t.height, o = c(t, this.forceDataSchema, !!r), s = this.svgFactory.createElement("svg:rect"); s.setAttributeNS(null, "x", "0"), s.setAttributeNS(null, "y", "0"), s.setAttributeNS(null, "width", e(i)), s.setAttributeNS(null, "height", e(a)), this.current.element = s, this.clip("nonzero"); var u = this.svgFactory.createElement("svg:image"); u.setAttributeNS(n, "xlink:href", o), u.setAttributeNS(null, "x", "0"), u.setAttributeNS(null, "y", e(-a)), u.setAttributeNS(null, "width", e(i) + "px"), u.setAttributeNS(null, "height", e(a) + "px"), u.setAttributeNS(null, "transform", "scale(" + e(1 / i) + " " + e(-1 / a) + ")"), r ? r.appendChild(u) : this._ensureTransformGroup().appendChild(u) }, paintImageMaskXObject: function (t) { var r = this.current, n = t.width, i = t.height, a = r.fillColor; r.maskId = "mask" + d++; var o = this.svgFactory.createElement("svg:mask"); o.setAttributeNS(null, "id", r.maskId); var s = this.svgFactory.createElement("svg:rect"); s.setAttributeNS(null, "x", "0"), s.setAttributeNS(null, "y", "0"), s.setAttributeNS(null, "width", e(n)), s.setAttributeNS(null, "height", e(i)), s.setAttributeNS(null, "fill", a), s.setAttributeNS(null, "mask", "url(#" + r.maskId + ")"), this.defs.appendChild(o), this._ensureTransformGroup().appendChild(s), this.paintInlineImageXObject(t, o) }, paintFormXObjectBegin: function (t, r) { if (Array.isArray(t) && 6 === t.length && this.transform(t[0], t[1], t[2], t[3], t[4], t[5!
 ]), Array.isArray(r) && 4 === r.length) { var n = r[2] - r[0], i = r[3] - r[1], a = this.svgFactory.createElement("svg:rect"); a.setAttributeNS(null, "x", r[0]), a.setAttributeNS(null, "y", r[1]), a.setAttributeNS(null, "width", e(n)), a.setAttributeNS(null, "height", e(i)), this.current.element = a, this.clip("nonzero"), this.endPath() } }, paintFormXObjectEnd: function () { }, _initialize: function (e) { var r = this.svgFactory.create(e.width, e.height), n = this.svgFactory.createElement("svg:defs"); r.appendChild(n), this.defs = n; var i = this.svgFactory.createElement("svg:g"); return i.setAttributeNS(null, "transform", t(e.transform)), r.appendChild(i), this.svg = i, r }, _ensureClipGroup: function () { if (!this.current.clipGroup) { var e = this.svgFactory.createElement("svg:g"); e.setAttributeNS(null, "clip-path", this.current.activeClipUrl), this.svg.appendChild(e), this.current.clipGroup = e } return this.current.clipGroup }, _ensureTransformGroup: function () { return this.tgrp || (this.tgrp = this.svgFactory.createElement("svg:g"), this.tgrp.setAttributeNS(null, "transform", t(this.transformMatrix)), this.current.activeClipUrl ? this._ensureClipGroup().appendChild(this.tgrp) : this.svg.appendChild(this.tgrp)), this.tgrp } }, r }(), t.SVGGraphics = u }, function (e, t, r) { "use strict"; Object.defineProperty(t, "__esModule", { value: !0 }), t.PDFNodeStream = void 0; var n, i = r(137), a = (n = i) && n.__esModule ? n : { default: n }, o = function () { function e(e, t) { for (var r = 0; r < t.length; r++) { var n = t[r]; n.enumerable = n.enumerable || !1, n.configurable = !0, "value" in n && (n.writable = !0), Object.defineProperty(e, n.key, n) } } return function (t, r, n) { return r && e(t.prototype, r), n && e(t, n), t } }(), s = r(1), u = r(149); function l(e, t) { if (!e) throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); return !t || "object" != typeof t && "function" != typeof t ? e : t } function c(e, t) { if ("function" != typeof t && null !== t) throw new T!
 ypeError("Super expression must either be null or a function, not " + typeof t); e.prototype = Object.create(t && t.prototype, { constructor: { value: e, enumerable: !1, writable: !0, configurable: !0 } }), t && (Object.setPrototypeOf ? Object.setPrototypeOf(e, t) : e.__proto__ = t) } function h(e) { return function () { var t = e.apply(this, arguments); return new Promise(function (e, r) { return function n(i, a) { try { var o = t[i](a), s = o.value } catch (e) { return void r(e) } if (!o.done) return Promise.resolve(s).then(function (e) { n("next", e) }, function (e) { n("throw", e) }); e(s) }("next") }) } } function d(e, t) { if (!(e instanceof t)) throw new TypeError("Cannot call a class as a function") } var f = require("fs"), p = require("http"), v = require("https"), m = require("url"), g = /^file:\/\/\/[a-zA-Z]:\//; var y = function () { function e(t) { var r, n; d(this, e), this.source = t, this.url = (r = t.url, "file:" === (n = m.parse(r)).protocol || n.host ? n : /^[a-z]:[/\\]/i.test(r) ? m.parse("file:///" + r) : (n.host || (n.protocol = "file:"), n)), this.isHttp = "http:" === this.url.protocol || "https:" === this.url.protocol, this.isFsUrl = "file:" === this.url.protocol, this.httpHeaders = this.isHttp && t.httpHeaders || {}, this._fullRequest = null, this._rangeRequestReaders = [] } return o(e, [{ key: "getFullReader", value: function () { return (0, s.assert)(!this._fullRequest), this._fullRequest = this.isFsUrl ? new k(this) : new S(this), this._fullRequest } }, { key: "getRangeReader", value: function (e, t) { var r = this.isFsUrl ? new P(this, e, t) : new w(this, e, t); return this._rangeRequestReaders.push(r), r } }, { key: "cancelAllRequests", value: function (e) { this._fullRequest && this._fullRequest.cancel(e), this._rangeRequestReaders.slice(0).forEach(function (t) { t.cancel(e) }) } }]), e }(), b = function () { function e(t) { d(this, e), this._url = t.url, this._done = !1, this._storedError = null, this.onProgress = null; var r = t.source; this._contentLength = r.length, this._loade!
 d = 0, this._filename = null, this._disableRange = r.disableRange || !1, this._rangeChunkSize = r.rangeChunkSize, this._rangeChunkSize || this._disableRange || (this._disableRange = !0), this._isStreamingSupported = !r.disableStream, this._isRangeSupported = !r.disableRange, this._readableStream = null, this._readCapability = (0, s.createPromiseCapability)(), this._headersCapability = (0, s.createPromiseCapability)() } return o(e, [{ key: "read", value: function () { var e = h(a.default.mark(function e() { var t, r; return a.default.wrap(function (e) { for (; ;)switch (e.prev = e.next) { case 0: return e.next = 2, this._readCapability.promise; case 2: if (!this._done) { e.next = 4; break } return e.abrupt("return", { value: void 0, done: !0 }); case 4: if (!this._storedError) { e.next = 6; break } throw this._storedError; case 6: if (null !== (t = this._readableStream.read())) { e.next = 10; break } return this._readCapability = (0, s.createPromiseCapability)(), e.abrupt("return", this.read()); case 10: return this._loaded += t.length, this.onProgress && this.onProgress({ loaded: this._loaded, total: this._contentLength }), r = new Uint8Array(t).buffer, e.abrupt("return", { value: r, done: !1 }); case 14: case "end": return e.stop() } }, e, this) })); return function () { return e.apply(this, arguments) } }() }, { key: "cancel", value: function (e) { this._readableStream ? this._readableStream.destroy(e) : this._error(e) } }, { key: "_error", value: function (e) { this._storedError = e, this._readCapability.resolve() } }, { key: "_setReadableStream", value: function (e) { var t = this; this._readableStream = e, e.on("readable", function () { t._readCapability.resolve() }), e.on("end", function () { e.destroy(), t._done = !0, t._readCapability.resolve() }), e.on("error", function (e) { t._error(e) }), !this._isStreamingSupported && this._isRangeSupported && this._error(new s.AbortException("streaming is disabled")), this._storedError && this._readableStream.destroy(this._storedError) } }, { key: "headersReady", g!
 et: function () { return this._headersCapability.promise } }, { key: "filename", get: function () { return this._filename } }, { key: "contentLength", get: function () { return this._contentLength } }, { key: "isRangeSupported", get: function () { return this._isRangeSupported } }, { key: "isStreamingSupported", get: function () { return this._isStreamingSupported } }]), e }(), _ = function () { function e(t) { d(this, e), this._url = t.url, this._done = !1, this._storedError = null, this.onProgress = null, this._loaded = 0, this._readableStream = null, this._readCapability = (0, s.createPromiseCapability)(); var r = t.source; this._isStreamingSupported = !r.disableStream } return o(e, [{ key: "read", value: function () { var e = h(a.default.mark(function e() { var t, r; return a.default.wrap(function (e) { for (; ;)switch (e.prev = e.next) { case 0: return e.next = 2, this._readCapability.promise; case 2: if (!this._done) { e.next = 4; break } return e.abrupt("return", { value: void 0, done: !0 }); case 4: if (!this._storedError) { e.next = 6; break } throw this._storedError; case 6: if (null !== (t = this._readableStream.read())) { e.next = 10; break } return this._readCapability = (0, s.createPromiseCapability)(), e.abrupt("return", this.read()); case 10: return this._loaded += t.length, this.onProgress && this.onProgress({ loaded: this._loaded }), r = new Uint8Array(t).buffer, e.abrupt("return", { value: r, done: !1 }); case 14: case "end": return e.stop() } }, e, this) })); return function () { return e.apply(this, arguments) } }() }, { key: "cancel", value: function (e) { this._readableStream ? this._readableStream.destroy(e) : this._error(e) } }, { key: "_error", value: function (e) { this._storedError = e, this._readCapability.resolve() } }, { key: "_setReadableStream", value: function (e) { var t = this; this._readableStream = e, e.on("readable", function () { t._readCapability.resolve() }), e.on("end", function () { e.destroy(), t._done = !0, t._readCapability.resolve() }), e.on("error", function (e) {!
  t._error(e) }), this._storedError && this._readableStream.destroy(this._storedError) } }, { key: "isStreamingSupported", get: function () { return this._isStreamingSupported } }]), e }(); function A(e, t) { return { protocol: e.protocol, auth: e.auth, host: e.hostname, port: e.port, path: e.path, method: "GET", headers: t } } var S = function (e) { function t(e) { d(this, t); var r = l(this, (t.__proto__ || Object.getPrototypeOf(t)).call(this, e)), n = function (t) { if (404 === t.statusCode) { var n = new s.MissingPDFException('Missing PDF "' + r._url + '".'); return r._storedError = n, void r._headersCapability.reject(n) } r._headersCapability.resolve(), r._setReadableStream(t); var i = function (e) { return r._readableStream.headers[e.toLowerCase()] }, a = (0, u.validateRangeRequestCapabilities)({ getResponseHeader: i, isHttp: e.isHttp, rangeChunkSize: r._rangeChunkSize, disableRange: r._disableRange }), o = a.allowRangeRequests, l = a.suggestedLength; r._isRangeSupported = o, r._contentLength = l || r._contentLength, r._filename = (0, u.extractFilenameFromHeader)(i) }; return r._request = null, "http:" === r._url.protocol ? r._request = p.request(A(r._url, e.httpHeaders), n) : r._request = v.request(A(r._url, e.httpHeaders), n), r._request.on("error", function (e) { r._storedError = e, r._headersCapability.reject(e) }), r._request.end(), r } return c(t, b), t }(), w = function (e) { function t(e, r, n) { d(this, t); var i = l(this, (t.__proto__ || Object.getPrototypeOf(t)).call(this, e)); for (var a in i._httpHeaders = {}, e.httpHeaders) { var o = e.httpHeaders[a]; void 0 !== o && (i._httpHeaders[a] = o) } i._httpHeaders.Range = "bytes=" + r + "-" + (n - 1); var u = function (e) { if (404 !== e.statusCode) i._setReadableStream(e); else { var t = new s.MissingPDFException('Missing PDF "' + i._url + '".'); i._storedError = t } }; return i._request = null, "http:" === i._url.protocol ? i._request = p.request(A(i._url, i._httpHeaders), u) : i._request = v.request(A(i._url, i._httpHeaders), u), i._request.on("er!
 ror", function (e) { i._storedError = e }), i._request.end(), i } return c(t, _), t }(), k = function (e) { function t(e) { d(this, t); var r = l(this, (t.__proto__ || Object.getPrototypeOf(t)).call(this, e)), n = decodeURIComponent(r._url.path); return g.test(r._url.href) && (n = n.replace(/^\//, "")), f.lstat(n, function (e, t) { if (e) return "ENOENT" === e.code && (e = new s.MissingPDFException('Missing PDF "' + n + '".')), r._storedError = e, void r._headersCapability.reject(e); r._contentLength = t.size, r._setReadableStream(f.createReadStream(n)), r._headersCapability.resolve() }), r } return c(t, b), t }(), P = function (e) { function t(e, r, n) { d(this, t); var i = l(this, (t.__proto__ || Object.getPrototypeOf(t)).call(this, e)), a = decodeURIComponent(i._url.path); return g.test(i._url.href) && (a = a.replace(/^\//, "")), i._setReadableStream(f.createReadStream(a, { start: r, end: n - 1 })), i } return c(t, _), t }(); t.PDFNodeStream = y }, function (e, t, r) { "use strict"; Object.defineProperty(t, "__esModule", { value: !0 }), t.validateResponseStatus = t.validateRangeRequestCapabilities = t.extractFilenameFromHeader = t.createResponseStatusError = void 0; var n = r(1), i = r(150); t.createResponseStatusError = function (e, t) { return 404 === e || 0 === e && /^file:/.test(t) ? new n.MissingPDFException('Missing PDF "' + t + '".') : new n.UnexpectedResponseException("Unexpected server response (" + e + ') while retrieving PDF "' + t + '".', e) }, t.extractFilenameFromHeader = function (e) { var t = e("Content-Disposition"); if (t) { var r = (0, i.getFilenameFromContentDispositionHeader)(t); if (/\.pdf$/i.test(r)) return r } return null }, t.validateRangeRequestCapabilities = function (e) { var t = e.getResponseHeader, r = e.isHttp, i = e.rangeChunkSize, a = e.disableRange; (0, n.assert)(i > 0, "Range chunk size must be larger than zero"); var o = { allowRangeRequests: !1, suggestedLength: void 0 }, s = parseInt(t("Content-Length"), 10); return Number.isInteger(s) ? (o.suggestedLength = s, s <= 2 * i!
  ? o : a || !r ? o : "bytes" !== t("Accept-Ranges") ? o : "identity" !== (t("Content-Encoding") || "identity") ? o : (o.allowRangeRequests = !0, o)) : o }, t.validateResponseStatus = function (e) { return 200 === e || 206 === e } }, function (e, t, r) { "use strict"; Object.defineProperty(t, "__esModule", { value: !0 }); var n = function () { return function (e, t) { if (Array.isArray(e)) return e; if (Symbol.iterator in Object(e)) return function (e, t) { var r = [], n = !0, i = !1, a = void 0; try { for (var o, s = e[Symbol.iterator](); !(n = (o = s.next()).done) && (r.push(o.value), !t || r.length !== t); n = !0); } catch (e) { i = !0, a = e } finally { try { !n && s.return && s.return() } finally { if (i) throw a } } return r }(e, t); throw new TypeError("Invalid attempt to destructure non-iterable instance") } }(); t.getFilenameFromContentDispositionHeader = function (e) { var t = !0, r = o("filename\\*", "i").exec(e); if (r) { var i = l(r = r[1]); return u(i = h(i = c(i = unescape(i)))) } if (r = function (e) { for (var t = [], r = void 0, i = o("filename\\*((?!0\\d)\\d+)(\\*?)", "ig"); null !== (r = i.exec(e));) { var a = r, s = n(a, 4), u = s[1], h = s[2], d = s[3]; if ((u = parseInt(u, 10)) in t) { if (0 === u) break } else t[u] = [h, d] } for (var f = [], p = 0; p < t.length && p in t; ++p) { var v = n(t[p], 2), m = v[0], g = v[1]; g = l(g), m && (g = unescape(g), 0 === p && (g = c(g))), f.push(g) } return f.join("") }(e)) return u(h(r)); if (r = o("filename", "i").exec(e)) { var a = l(r = r[1]); return u(a = h(a)) } function o(e, t) { return new RegExp("(?:^|;)\\s*" + e + '\\s*=\\s*([^";\\s][^;\\s]*|"(?:[^"\\\\]|\\\\"?)+"?)', t) } function s(e, r) { if (e) { if (!/^[\x00-\xFF]+$/.test(r)) return r; try { for (var n = new TextDecoder(e, { fatal: !0 }), i = new Array(r.length), a = 0; a < r.length; ++a)i[a] = r.charCodeAt(a); r = n.decode(new Uint8Array(i)), t = !1 } catch (n) { if (/^utf-?8$/i.test(e)) try { r = decodeURIComponent(escape(r)), t = !1 } catch (e) { } } } return r } function u(e) { return!
  t && /[\x80-\xff]/.test(e) && (e = s("utf-8", e), t && (e = s("iso-8859-1", e))), e } function l(e) { if ('"' === e.charAt(0)) { for (var t = e.slice(1).split('\\"'), r = 0; r < t.length; ++r) { var n = t[r].indexOf('"'); -1 !== n && (t[r] = t[r].slice(0, n), t.length = r + 1), t[r] = t[r].replace(/\\(.)/g, "$1") } e = t.join('"') } return e } function c(e) { var t = e.indexOf("'"); return -1 === t ? e : s(e.slice(0, t), e.slice(t + 1).replace(/^[^']*'/, "")) } function h(e) { return "=?" !== e.slice(0, 2) || /[\x00-\x19\x80-\xff]/.test(e) ? e : e.replace(/=\?([\w-]*)\?([QqBb])\?((?:[^?]|\?(?!=))*)\?=/g, function (e, t, r, n) { if ("q" === r || "Q" === r) return s(t, n = (n = n.replace(/_/g, " ")).replace(/=([0-9a-fA-F]{2})/g, function (e, t) { return String.fromCharCode(parseInt(t, 16)) })); try { n = atob(n) } catch (e) { } return s(t, n) }) } return "" } }, function (e, t, r) { "use strict"; Object.defineProperty(t, "__esModule", { value: !0 }), t.PDFFetchStream = void 0; var n, i = r(137), a = (n = i) && n.__esModule ? n : { default: n }, o = function () { function e(e, t) { for (var r = 0; r < t.length; r++) { var n = t[r]; n.enumerable = n.enumerable || !1, n.configurable = !0, "value" in n && (n.writable = !0), Object.defineProperty(e, n.key, n) } } return function (t, r, n) { return r && e(t.prototype, r), n && e(t, n), t } }(), s = r(1), u = r(149); function l(e) { return function () { var t = e.apply(this, arguments); return new Promise(function (e, r) { return function n(i, a) { try { var o = t[i](a), s = o.value } catch (e) { return void r(e) } if (!o.done) return Promise.resolve(s).then(function (e) { n("next", e) }, function (e) { n("throw", e) }); e(s) }("next") }) } } function c(e, t) { if (!(e instanceof t)) throw new TypeError("Cannot call a class as a function") } function h(e, t, r) { return { method: "GET", headers: e, signal: r && r.signal, mode: "cors", credentials: t ? "include" : "same-origin", redirect: "follow" } } var d = function () { function e(t) { c(this, e), this.source = t, thi!
 s.isHttp = /^https?:/i.test(t.url), this.httpHeaders = this.isHttp && t.httpHeaders || {}, this._fullRequestReader = null, this._rangeRequestReaders = [] } return o(e, [{ key: "getFullReader", value: function () { return (0, s.assert)(!this._fullRequestReader), this._fullRequestReader = new f(this), this._fullRequestReader } }, { key: "getRangeReader", value: function (e, t) { var r = new p(this, e, t); return this._rangeRequestReaders.push(r), r } }, { key: "cancelAllRequests", value: function (e) { this._fullRequestReader && this._fullRequestReader.cancel(e), this._rangeRequestReaders.slice(0).forEach(function (t) { t.cancel(e) }) } }]), e }(), f = function () { function e(t) { var r = this; c(this, e), this._stream = t, this._reader = null, this._loaded = 0, this._filename = null; var n = t.source; for (var i in this._withCredentials = n.withCredentials, this._contentLength = n.length, this._headersCapability = (0, s.createPromiseCapability)(), this._disableRange = n.disableRange || !1, this._rangeChunkSize = n.rangeChunkSize, this._rangeChunkSize || this._disableRange || (this._disableRange = !0), "undefined" != typeof AbortController && (this._abortController = new AbortController), this._isStreamingSupported = !n.disableStream, this._isRangeSupported = !n.disableRange, this._headers = new Headers, this._stream.httpHeaders) { var a = this._stream.httpHeaders[i]; void 0 !== a && this._headers.append(i, a) } var o = n.url; fetch(o, h(this._headers, this._withCredentials, this._abortController)).then(function (e) { if (!(0, u.validateResponseStatus)(e.status)) throw (0, u.createResponseStatusError)(e.status, o); r._reader = e.body.getReader(), r._headersCapability.resolve(); var t = function (t) { return e.headers.get(t) }, n = (0, u.validateRangeRequestCapabilities)({ getResponseHeader: t, isHttp: r._stream.isHttp, rangeChunkSize: r._rangeChunkSize, disableRange: r._disableRange }), i = n.allowRangeRequests, a = n.suggestedLength; r._isRangeSupported = i, r._contentLength = a || r._contentLength, r._filename !
 = (0, u.extractFilenameFromHeader)(t), !r._isStreamingSupported && r._isRangeSupported && r.cancel(new s.AbortException("streaming is disabled")) }).catch(this._headersCapability.reject), this.onProgress = null } return o(e, [{ key: "read", value: function () { var e = l(a.default.mark(function e() { var t, r, n, i; return a.default.wrap(function (e) { for (; ;)switch (e.prev = e.next) { case 0: return e.next = 2, this._headersCapability.promise; case 2: return e.next = 4, this._reader.read(); case 4: if (t = e.sent, r = t.value, !(n = t.done)) { e.next = 9; break } return e.abrupt("return", { value: r, done: n }); case 9: return this._loaded += r.byteLength, this.onProgress && this.onProgress({ loaded: this._loaded, total: this._contentLength }), i = new Uint8Array(r).buffer, e.abrupt("return", { value: i, done: !1 }); case 13: case "end": return e.stop() } }, e, this) })); return function () { return e.apply(this, arguments) } }() }, { key: "cancel", value: function (e) { this._reader && this._reader.cancel(e), this._abortController && this._abortController.abort() } }, { key: "headersReady", get: function () { return this._headersCapability.promise } }, { key: "filename", get: function () { return this._filename } }, { key: "contentLength", get: function () { return this._contentLength } }, { key: "isRangeSupported", get: function () { return this._isRangeSupported } }, { key: "isStreamingSupported", get: function () { return this._isStreamingSupported } }]), e }(), p = function () { function e(t, r, n) { var i = this; c(this, e), this._stream = t, this._reader = null, this._loaded = 0; var a = t.source; for (var o in this._withCredentials = a.withCredentials, this._readCapability = (0, s.createPromiseCapability)(), this._isStreamingSupported = !a.disableStream, "undefined" != typeof AbortController && (this._abortController = new AbortController), this._headers = new Headers, this._stream.httpHeaders) { var l = this._stream.httpHeaders[o]; void 0 !== l && this._headers.append(o, l) } var d = r + "-" + (n - 1!
 ); this._headers.append("Range", "bytes=" + d); var f = a.url; fetch(f, h(this._headers, this._withCredentials, this._abortController)).then(function (e) { if (!(0, u.validateResponseStatus)(e.status)) throw (0, u.createResponseStatusError)(e.status, f); i._readCapability.resolve(), i._reader = e.body.getReader() }), this.onProgress = null } return o(e, [{ key: "read", value: function () { var e = l(a.default.mark(function e() { var t, r, n, i; return a.default.wrap(function (e) { for (; ;)switch (e.prev = e.next) { case 0: return e.next = 2, this._readCapability.promise; case 2: return e.next = 4, this._reader.read(); case 4: if (t = e.sent, r = t.value, !(n = t.done)) { e.next = 9; break } return e.abrupt("return", { value: r, done: n }); case 9: return this._loaded += r.byteLength, this.onProgress && this.onProgress({ loaded: this._loaded }), i = new Uint8Array(r).buffer, e.abrupt("return", { value: i, done: !1 }); case 13: case "end": return e.stop() } }, e, this) })); return function () { return e.apply(this, arguments) } }() }, { key: "cancel", value: function (e) { this._reader && this._reader.cancel(e), this._abortController && this._abortController.abort() } }, { key: "isStreamingSupported", get: function () { return this._isStreamingSupported } }]), e }(); t.PDFFetchStream = d }, function (e, t, r) { "use strict"; Object.defineProperty(t, "__esModule", { value: !0 }), t.NetworkManager = t.PDFNetworkStream = void 0; var n = s(r(137)), i = r(1), a = r(149), o = s(r(3)); function s(e) { return e && e.__esModule ? e : { default: e } } function u(e) { return function () { var t = e.apply(this, arguments); return new Promise(function (e, r) { return function n(i, a) { try { var o = t[i](a), s = o.value } catch (e) { return void r(e) } if (!o.done) return Promise.resolve(s).then(function (e) { n("next", e) }, function (e) { n("throw", e) }); e(s) }("next") }) } } function l(e, t) { this.url = e, t = t || {}, this.isHttp = /^https?:/i.test(e), this.httpHeaders = this.isHttp && t.httpHeaders || {}, this.withCre!
 dentials = t.withCredentials || !1, this.getXhr = t.getXhr || function () { return new XMLHttpRequest }, this.currXhrId = 0, this.pendingRequests = Object.create(null), this.loadedRequests = Object.create(null) } function c(e) { var t = e.response; return "string" != typeof t ? t : (0, i.stringToBytes)(t).buffer } var h = function () { try { var e = new XMLHttpRequest; return e.open("GET", o.default.location.href), e.responseType = "moz-chunked-arraybuffer", "moz-chunked-arraybuffer" === e.responseType } catch (e) { return !1 } }(); function d(e) { this._source = e, this._manager = new l(e.url, { httpHeaders: e.httpHeaders, withCredentials: e.withCredentials }), this._rangeChunkSize = e.rangeChunkSize, this._fullRequestReader = null, this._rangeRequestReaders = [] } function f(e, t) { this._manager = e; var r = { onHeadersReceived: this._onHeadersReceived.bind(this), onProgressiveData: t.disableStream ? null : this._onProgressiveData.bind(this), onDone: this._onDone.bind(this), onError: this._onError.bind(this), onProgress: this._onProgress.bind(this) }; this._url = t.url, this._fullRequestId = e.requestFull(r), this._headersReceivedCapability = (0, i.createPromiseCapability)(), this._disableRange = t.disableRange || !1, this._contentLength = t.length, this._rangeChunkSize = t.rangeChunkSize, this._rangeChunkSize || this._disableRange || (this._disableRange = !0), this._isStreamingSupported = !1, this._isRangeSupported = !1, this._cachedChunks = [], this._requests = [], this._done = !1, this._storedError = void 0, this._filename = null, this.onProgress = null } function p(e, t, r) { this._manager = e; var n = { onDone: this._onDone.bind(this), onProgress: this._onProgress.bind(this) }; this._requestId = e.requestRange(t, r, n), this._requests = [], this._queuedChunk = null, this._done = !1, this.onProgress = null, this.onClosed = null } l.prototype = { requestRange: function (e, t, r) { var n = { begin: e, end: t }; for (var i in r) n[i] = r[i]; return this.request(n) }, requestFull: function (e) { return this.r!
 equest(e) }, request: function (e) { var t = this.getXhr(), r = this.currXhrId++, n = this.pendingRequests[r] = { xhr: t }; for (var i in t.open("GET", this.url), t.withCredentials = this.withCredentials, this.httpHeaders) { var a = this.httpHeaders[i]; void 0 !== a && t.setRequestHeader(i, a) } if (this.isHttp && "begin" in e && "end" in e) { var o = e.begin + "-" + (e.end - 1); t.setRequestHeader("Range", "bytes=" + o), n.expectedStatus = 206 } else n.expectedStatus = 200; return h && !!e.onProgressiveData ? (t.responseType = "moz-chunked-arraybuffer", n.onProgressiveData = e.onProgressiveData, n.mozChunked = !0) : t.responseType = "arraybuffer", e.onError && (t.onerror = function (r) { e.onError(t.status) }), t.onreadystatechange = this.onStateChange.bind(this, r), t.onprogress = this.onProgress.bind(this, r), n.onHeadersReceived = e.onHeadersReceived, n.onDone = e.onDone, n.onError = e.onError, n.onProgress = e.onProgress, t.send(null), r }, onProgress: function (e, t) { var r = this.pendingRequests[e]; if (r) { if (r.mozChunked) { var n = c(r.xhr); r.onProgressiveData(n) } var i = r.onProgress; i && i(t) } }, onStateChange: function (e, t) { var r = this.pendingRequests[e]; if (r) { var n = r.xhr; if (n.readyState >= 2 && r.onHeadersReceived && (r.onHeadersReceived(), delete r.onHeadersReceived), 4 === n.readyState && e in this.pendingRequests) if (delete this.pendingRequests[e], 0 === n.status && this.isHttp) r.onError && r.onError(n.status); else { var i = n.status || 200; if (200 === i && 206 === r.expectedStatus || i === r.expectedStatus) { this.loadedRequests[e] = !0; var a = c(n); if (206 === i) { var o = n.getResponseHeader("Content-Range"), s = /bytes (\d+)-(\d+)\/(\d+)/.exec(o), u = parseInt(s[1], 10); r.onDone({ begin: u, chunk: a }) } else r.onProgressiveData ? r.onDone(null) : a ? r.onDone({ begin: 0, chunk: a }) : r.onError && r.onError(n.status) } else r.onError && r.onError(n.status) } } }, hasPendingRequests: function () { for (var e in this.pendingRequests) return !0; return !1 }, getReques!
 tXhr: function (e) { return this.pendingRequests[e].xhr }, isStreamingRequest: function (e) { return !!this.pendingRequests[e].onProgressiveData }, isPendingRequest: function (e) { return e in this.pendingRequests }, isLoadedRequest: function (e) { return e in this.loadedRequests }, abortAllRequests: function () { for (var e in this.pendingRequests) this.abortRequest(0 | e) }, abortRequest: function (e) { var t = this.pendingRequests[e].xhr; delete this.pendingRequests[e], t.abort() } }, d.prototype = { _onRangeRequestReaderClosed: function (e) { var t = this._rangeRequestReaders.indexOf(e); t >= 0 && this._rangeRequestReaders.splice(t, 1) }, getFullReader: function () { return (0, i.assert)(!this._fullRequestReader), this._fullRequestReader = new f(this._manager, this._source), this._fullRequestReader }, getRangeReader: function (e, t) { var r = new p(this._manager, e, t); return r.onClosed = this._onRangeRequestReaderClosed.bind(this), this._rangeRequestReaders.push(r), r }, cancelAllRequests: function (e) { this._fullRequestReader && this._fullRequestReader.cancel(e), this._rangeRequestReaders.slice(0).forEach(function (t) { t.cancel(e) }) } }, f.prototype = { _onHeadersReceived: function () { var e = this._fullRequestId, t = this._manager.getRequestXhr(e), r = function (e) { return t.getResponseHeader(e) }, n = (0, a.validateRangeRequestCapabilities)({ getResponseHeader: r, isHttp: this._manager.isHttp, rangeChunkSize: this._rangeChunkSize, disableRange: this._disableRange }), i = n.allowRangeRequests, o = n.suggestedLength; i && (this._isRangeSupported = !0), this._contentLength = o || this._contentLength, this._filename = (0, a.extractFilenameFromHeader)(r); var s = this._manager; s.isStreamingRequest(e) ? this._isStreamingSupported = !0 : this._isRangeSupported && s.abortRequest(e), this._headersReceivedCapability.resolve() }, _onProgressiveData: function (e) { this._requests.length > 0 ? this._requests.shift().resolve({ value: e, done: !1 }) : this._cachedChunks.push(e) }, _onDone: function (e) { e && th!
 is._onProgressiveData(e.chunk), this._done = !0, this._cachedChunks.length > 0 || (this._requests.forEach(function (e) { e.resolve({ value: void 0, done: !0 }) }), this._requests = []) }, _onError: function (e) { var t = this._url, r = (0, a.createResponseStatusError)(e, t); this._storedError = r, this._headersReceivedCapability.reject(r), this._requests.forEach(function (e) { e.reject(r) }), this._requests = [], this._cachedChunks = [] }, _onProgress: function (e) { this.onProgress && this.onProgress({ loaded: e.loaded, total: e.lengthComputable ? e.total : this._contentLength }) }, get filename() { return this._filename }, get isRangeSupported() { return this._isRangeSupported }, get isStreamingSupported() { return this._isStreamingSupported }, get contentLength() { return this._contentLength }, get headersReady() { return this._headersReceivedCapability.promise }, read: function () { var e = u(n.default.mark(function e() { var t, r; return n.default.wrap(function (e) { for (; ;)switch (e.prev = e.next) { case 0: if (!this._storedError) { e.next = 2; break } throw this._storedError; case 2: if (!(this._cachedChunks.length > 0)) { e.next = 5; break } return t = this._cachedChunks.shift(), e.abrupt("return", { value: t, done: !1 }); case 5: if (!this._done) { e.next = 7; break } return e.abrupt("return", { value: void 0, done: !0 }); case 7: return r = (0, i.createPromiseCapability)(), this._requests.push(r), e.abrupt("return", r.promise); case 10: case "end": return e.stop() } }, e, this) })); return function () { return e.apply(this, arguments) } }(), cancel: function (e) { this._done = !0, this._headersReceivedCapability.reject(e), this._requests.forEach(function (e) { e.resolve({ value: void 0, done: !0 }) }), this._requests = [], this._manager.isPendingRequest(this._fullRequestId) && this._manager.abortRequest(this._fullRequestId), this._fullRequestReader = null } }, p.prototype = { _close: function () { this.onClosed && this.onClosed(this) }, _onDone: function (e) { var t = e.chunk; this._requests.length >!
  0 ? this._requests.shift().resolve({ value: t, done: !1 }) : this._queuedChunk = t; this._done = !0, this._requests.forEach(function (e) { e.resolve({ value: void 0, done: !0 }) }), this._requests = [], this._close() }, _onProgress: function (e) { !this.isStreamingSupported && this.onProgress && this.onProgress({ loaded: e.loaded }) }, get isStreamingSupported() { return !1 }, read: function () { var e = u(n.default.mark(function e() { var t, r; return n.default.wrap(function (e) { for (; ;)switch (e.prev = e.next) { case 0: if (null === this._queuedChunk) { e.next = 4; break } return t = this._queuedChunk, this._queuedChunk = null, e.abrupt("return", { value: t, done: !1 }); case 4: if (!this._done) { e.next = 6; break } return e.abrupt("return", { value: void 0, done: !0 }); case 6: return r = (0, i.createPromiseCapability)(), this._requests.push(r), e.abrupt("return", r.promise); case 9: case "end": return e.stop() } }, e, this) })); return function () { return e.apply(this, arguments) } }(), cancel: function (e) { this._done = !0, this._requests.forEach(function (e) { e.resolve({ value: void 0, done: !0 }) }), this._requests = [], this._manager.isPendingRequest(this._requestId) && this._manager.abortRequest(this._requestId), this._close() } }, t.PDFNetworkStream = d, t.NetworkManager = l }]) });
\ No newline at end of file

Added: trunk/Master/texmf-dist/doc/latex/figput/javascript/pdf.worker.min.js
===================================================================
--- trunk/Master/texmf-dist/doc/latex/figput/javascript/pdf.worker.min.js	                        (rev 0)
+++ trunk/Master/texmf-dist/doc/latex/figput/javascript/pdf.worker.min.js	2022-07-22 21:48:41 UTC (rev 63957)
@@ -0,0 +1 @@

@@ Diff output truncated at 1234567 characters. @@


More information about the tex-live-commits mailing list.