texlive[62265] Master: asymptote 2.78 support files

commits+karl at tug.org commits+karl at tug.org
Mon Feb 28 00:41:12 CET 2022


Revision: 62265
          http://tug.org/svn/texlive?view=revision&revision=62265
Author:   karl
Date:     2022-02-28 00:41:11 +0100 (Mon, 28 Feb 2022)
Log Message:
-----------
asymptote 2.78 support files

Modified Paths:
--------------
    trunk/Master/texmf-dist/asymptote/GUI/CustMatTransform.py
    trunk/Master/texmf-dist/asymptote/GUI/DebugFlags.py
    trunk/Master/texmf-dist/asymptote/GUI/GuidesManager.py
    trunk/Master/texmf-dist/asymptote/GUI/InplaceAddObj.py
    trunk/Master/texmf-dist/asymptote/GUI/PrimitiveShape.py
    trunk/Master/texmf-dist/asymptote/GUI/SetCustomAnchor.py
    trunk/Master/texmf-dist/asymptote/GUI/Widg_addLabel.py
    trunk/Master/texmf-dist/asymptote/GUI/Widg_addPolyOpt.py
    trunk/Master/texmf-dist/asymptote/GUI/Widg_editBezier.py
    trunk/Master/texmf-dist/asymptote/GUI/Window1.py
    trunk/Master/texmf-dist/asymptote/GUI/configs/xasyconfig.cson
    trunk/Master/texmf-dist/asymptote/GUI/configs/xasykeymap.cson
    trunk/Master/texmf-dist/asymptote/GUI/labelEditor.py
    trunk/Master/texmf-dist/asymptote/GUI/pyUIClass/custMatTransform.py
    trunk/Master/texmf-dist/asymptote/GUI/pyUIClass/labelTextEditor.py
    trunk/Master/texmf-dist/asymptote/GUI/pyUIClass/setCustomAnchor.py
    trunk/Master/texmf-dist/asymptote/GUI/pyUIClass/widg_addLabel.py
    trunk/Master/texmf-dist/asymptote/GUI/pyUIClass/widg_addPolyOpt.py
    trunk/Master/texmf-dist/asymptote/GUI/pyUIClass/widg_editBezier.py
    trunk/Master/texmf-dist/asymptote/GUI/pyUIClass/widgetPointEditor.py
    trunk/Master/texmf-dist/asymptote/GUI/pyUIClass/window1.py
    trunk/Master/texmf-dist/asymptote/GUI/res/icons/bucket.svg
    trunk/Master/texmf-dist/asymptote/GUI/res/icons/center.svg
    trunk/Master/texmf-dist/asymptote/GUI/res/icons/centerorigin.svg
    trunk/Master/texmf-dist/asymptote/GUI/res/icons/closedcurve.svg
    trunk/Master/texmf-dist/asymptote/GUI/res/icons/closedpolygon.svg
    trunk/Master/texmf-dist/asymptote/GUI/res/icons/filledbucket.svg
    trunk/Master/texmf-dist/asymptote/GUI/res/icons/opencurve.svg
    trunk/Master/texmf-dist/asymptote/GUI/res/icons/openpolygon.svg
    trunk/Master/texmf-dist/asymptote/GUI/res/icons.qrc
    trunk/Master/texmf-dist/asymptote/GUI/setup.py
    trunk/Master/texmf-dist/asymptote/GUI/xasy.py
    trunk/Master/texmf-dist/asymptote/GUI/xasy2asy.py
    trunk/Master/texmf-dist/asymptote/GUI/xasyArgs.py
    trunk/Master/texmf-dist/asymptote/GUI/xasyBezierInterface.py
    trunk/Master/texmf-dist/asymptote/GUI/xasyFile.py
    trunk/Master/texmf-dist/asymptote/GUI/xasyOptions.py
    trunk/Master/texmf-dist/asymptote/GUI/xasyStrings.py
    trunk/Master/texmf-dist/asymptote/GUI/xasySvg.py
    trunk/Master/texmf-dist/asymptote/GUI/xasyTransform.py
    trunk/Master/texmf-dist/asymptote/GUI/xasyUtils.py
    trunk/Master/texmf-dist/asymptote/GUI/xasyVersion.py
    trunk/Master/texmf-dist/asymptote/asy-keywords.el
    trunk/Master/texmf-dist/asymptote/asy-mode.el
    trunk/Master/texmf-dist/asymptote/asy.vim
    trunk/Master/texmf-dist/asymptote/geometry.asy
    trunk/Master/texmf-dist/asymptote/graph.asy
    trunk/Master/texmf-dist/asymptote/math.asy
    trunk/Master/texmf-dist/asymptote/palette.asy
    trunk/Master/texmf-dist/asymptote/patterns.asy
    trunk/Master/texmf-dist/asymptote/plain.asy
    trunk/Master/texmf-dist/asymptote/plain_boxes.asy
    trunk/Master/texmf-dist/asymptote/plain_constants.asy
    trunk/Master/texmf-dist/asymptote/plain_filldraw.asy
    trunk/Master/texmf-dist/asymptote/plain_margins.asy
    trunk/Master/texmf-dist/asymptote/plain_markers.asy
    trunk/Master/texmf-dist/asymptote/plain_paths.asy
    trunk/Master/texmf-dist/asymptote/plain_pens.asy
    trunk/Master/texmf-dist/asymptote/plain_picture.asy
    trunk/Master/texmf-dist/asymptote/plain_prethree.asy
    trunk/Master/texmf-dist/asymptote/plain_scaling.asy
    trunk/Master/texmf-dist/asymptote/plain_shipout.asy
    trunk/Master/texmf-dist/asymptote/plain_strings.asy
    trunk/Master/texmf-dist/asymptote/pstoedit.asy
    trunk/Master/texmf-dist/asymptote/rational.asy
    trunk/Master/texmf-dist/asymptote/roundedpath.asy
    trunk/Master/texmf-dist/asymptote/shaders/fragment.glsl
    trunk/Master/texmf-dist/asymptote/shaders/vertex.glsl
    trunk/Master/texmf-dist/asymptote/simplex.asy
    trunk/Master/texmf-dist/asymptote/slide.asy
    trunk/Master/texmf-dist/asymptote/slopefield.asy
    trunk/Master/texmf-dist/asymptote/smoothcontour3.asy
    trunk/Master/texmf-dist/asymptote/solids.asy
    trunk/Master/texmf-dist/asymptote/stats.asy
    trunk/Master/texmf-dist/asymptote/syzygy.asy
    trunk/Master/texmf-dist/asymptote/three.asy
    trunk/Master/texmf-dist/asymptote/three_arrows.asy
    trunk/Master/texmf-dist/asymptote/three_light.asy
    trunk/Master/texmf-dist/asymptote/three_margins.asy
    trunk/Master/texmf-dist/asymptote/three_surface.asy
    trunk/Master/texmf-dist/asymptote/three_tube.asy
    trunk/Master/texmf-dist/asymptote/trembling.asy
    trunk/Master/texmf-dist/asymptote/version.asy
    trunk/Master/texmf-dist/asymptote/webgl/asygl.js
    trunk/Master/texmf-dist/asymptote/x11colors.asy
    trunk/Master/texmf-dist/doc/asymptote/CAD.pdf
    trunk/Master/texmf-dist/doc/asymptote/TeXShopAndAsymptote.pdf
    trunk/Master/texmf-dist/doc/asymptote/asy-latex.pdf
    trunk/Master/texmf-dist/doc/asymptote/asyRefCard.pdf
    trunk/Master/texmf-dist/doc/asymptote/asymptote.pdf
    trunk/Master/texmf-dist/doc/asymptote/examples/1overx.asy
    trunk/Master/texmf-dist/doc/asymptote/examples/NURBScurve.asy
    trunk/Master/texmf-dist/doc/asymptote/examples/NURBSsphere.asy
    trunk/Master/texmf-dist/doc/asymptote/examples/NURBSsurface.asy
    trunk/Master/texmf-dist/doc/asymptote/examples/alignedaxis.asy
    trunk/Master/texmf-dist/doc/asymptote/examples/fillcontour.asy
    trunk/Master/texmf-dist/doc/asymptote/examples/imagecontour.asy
    trunk/Master/texmf-dist/doc/asymptote/examples/interpolate1.asy
    trunk/Master/texmf-dist/doc/asymptote/examples/latexusage.tex
    trunk/Master/texmf-dist/doc/asymptote/examples/layers.asy
    trunk/Master/texmf-dist/doc/asymptote/examples/legend.asy
    trunk/Master/texmf-dist/doc/asymptote/examples/markregular.asy
    trunk/Master/texmf-dist/doc/asymptote/examples/orthocenter.asy
    trunk/Master/texmf-dist/doc/asymptote/examples/secondaryaxis.asy
    trunk/Master/texmf-dist/doc/asymptote/examples/spectrum.asy
    trunk/Master/texmf-dist/doc/asymptote/examples/strokepath.asy
    trunk/Master/texmf-dist/doc/asymptote/examples/teapot.asy
    trunk/Master/texmf-dist/doc/asymptote/examples/transparency.asy
    trunk/Master/texmf-dist/doc/asymptote/examples/workcone.asy
    trunk/Master/texmf-dist/doc/info/asy-faq.info
    trunk/Master/texmf-dist/doc/info/asymptote.info
    trunk/Master/texmf-dist/doc/man/man1/asy.1
    trunk/Master/texmf-dist/doc/man/man1/asy.man1.pdf
    trunk/Master/texmf-dist/doc/man/man1/xasy.man1.pdf
    trunk/Master/texmf-dist/tex/latex/asymptote/asymptote.sty
    trunk/Master/tlpkg/asymptote/asy.exe
    trunk/Master/tlpkg/asymptote64/asy.exe

Added Paths:
-----------
    trunk/Master/texmf-dist/asymptote/GUI/res/icons/brush.svg
    trunk/Master/texmf-dist/asymptote/GUI/res/icons/redo.svg
    trunk/Master/texmf-dist/asymptote/GUI/res/icons/undo.svg
    trunk/Master/texmf-dist/asymptote/shaders/blend.glsl
    trunk/Master/texmf-dist/asymptote/shaders/count.glsl
    trunk/Master/texmf-dist/asymptote/shaders/count0.glsl
    trunk/Master/texmf-dist/asymptote/shaders/offset.glsl
    trunk/Master/texmf-dist/asymptote/shaders/partialsum.glsl
    trunk/Master/texmf-dist/asymptote/shaders/presum.glsl
    trunk/Master/texmf-dist/asymptote/shaders/screen.glsl
    trunk/Master/texmf-dist/asymptote/v3d.asy
    trunk/Master/texmf-dist/asymptote/v3dheadertypes.asy
    trunk/Master/texmf-dist/asymptote/v3dtypes.asy
    trunk/Master/texmf-dist/doc/asymptote/examples/graphwithderiv.asy
    trunk/Master/texmf-dist/doc/asymptote/examples/teapotIBL.asy
    trunk/Master/texmf-dist/doc/asymptote/examples/twoSpheres.asy
    trunk/Master/texmf-dist/doc/man/man1/twill.man1.pdf

Removed Paths:
-------------
    trunk/Master/texmf-dist/asymptote/GUI/icons_rc.py

Modified: trunk/Master/texmf-dist/asymptote/GUI/CustMatTransform.py
===================================================================
--- trunk/Master/texmf-dist/asymptote/GUI/CustMatTransform.py	2022-02-27 23:39:53 UTC (rev 62264)
+++ trunk/Master/texmf-dist/asymptote/GUI/CustMatTransform.py	2022-02-27 23:41:11 UTC (rev 62265)
@@ -1,14 +1,14 @@
 #!/usr/bin/env python3
 
-import PyQt5.QtWidgets as Qw
-import PyQt5.QtGui as Qg
-import PyQt5.QtCore as Qc
-import numpy as np
-import xasy2asy as x2a
+import PyQt5.QtWidgets as QtWidgets
+import PyQt5.QtGui as QtGui
+import PyQt5.QtCore as QtCore
+import numpy as numpy
+import xasy2asy as xasy2asy
 from pyUIClass.custMatTransform import Ui_Dialog
 
 
-class CustMatTransform(Qw.QDialog):
+class CustMatTransform(QtWidgets.QDialog):
     def __init__(self):
         super().__init__()
         self.ui = Ui_Dialog()
@@ -18,7 +18,7 @@
         self.ui.btnCancel.clicked.connect(self.reject)
         self.ui.btnReset.clicked.connect(self.resetDialog)
 
-        self.mainTransformation = Qg.QTransform()
+        self.mainTransformation = QtGui.QTransform()
         self.mainTransformation.scale(1, -1)
 
         self.matrixLineInputs = [
@@ -25,7 +25,7 @@
             self.ui.lineMat00, self.ui.lineMat01, self.ui.lineMatTx,
             self.ui.lineMat10, self.ui.lineMat11, self.ui.lineMatTy]
 
-        validator = Qg.QDoubleValidator()
+        validator = QtGui.QDoubleValidator()
         for lineInput in self.matrixLineInputs:
             lineInput.setValidator(validator)
             lineInput.textChanged.connect(self.handleUpdateText)
@@ -37,7 +37,7 @@
 
     def createCanvas(self):
         self.canvSize = self.ui.imgPreview.size()
-        self.previewPixmap = Qg.QPixmap(self.canvSize)
+        self.previewPixmap = QtGui.QPixmap(self.canvSize)
         tx, ty = self.canvSize.width() / 2, self.canvSize.height() / 2
         self.mainTransformation.translate(tx, -ty)
 
@@ -52,27 +52,27 @@
 
     def updatePreview(self):
         self.previewPixmap.fill()
-        canvas = Qg.QPainter(self.previewPixmap)
+        canvas = QtGui.QPainter(self.previewPixmap)
         if not canvas.isActive():
             return
         canvas.setTransform(self.mainTransformation)
 
         canvas.save()
-        canvas.setPen(Qc.Qt.lightGray)
+        canvas.setPen(QtCore.Qt.lightGray)
         self.drawBasicGrid(canvas)
-        transform = x2a.asyTransform.fromNumpyMatrix(self.getTransformationMatrix())
+        transform = xasy2asy.asyTransform.fromNumpyMatrix(self.getTransformationMatrix())
         canvTransform = transform.toQTransform()
         canvas.setTransform(canvTransform, True)
 
-        canvas.setPen(Qc.Qt.black)
+        canvas.setPen(QtCore.Qt.black)
 
         if canvTransform.isInvertible():
             self.drawBasicGrid(canvas, False)
 
             if canvTransform.determinant() <= 0:
-                canvas.setPen(Qc.Qt.red)
+                canvas.setPen(QtCore.Qt.red)
 
-            canvas.drawRect(Qc.QRect(Qc.QPoint(0, 0), Qc.QSize(20, 20)))
+            canvas.drawRect(QtCore.QRect(QtCore.QPoint(0, 0), QtCore.QSize(20, 20)))
 
         self.ui.imgPreview.setPixmap(self.previewPixmap)
 
@@ -86,17 +86,17 @@
         self.ui.lineMat11.setText('1')
 
     def drawBasicGrid(self, canvas, grid=True):
-        canvas.drawLine(Qc.QLine(-9999, 0, 9999, 0))
-        canvas.drawLine(Qc.QLine(0, -9999, 0, 9999))
+        canvas.drawLine(QtCore.QLine(-9999, 0, 9999, 0))
+        canvas.drawLine(QtCore.QLine(0, -9999, 0, 9999))
 
         fromIter, toIter = -7, 7
         gridSize = 20
         if grid:
             for iterIndex in range(fromIter, toIter + 1):
-                canvas.drawLine(Qc.QLine(-9999, iterIndex * gridSize, 9999, iterIndex * gridSize))
-                canvas.drawLine(Qc.QLine(iterIndex * gridSize, -9999, iterIndex * gridSize, 9999))
+                canvas.drawLine(QtCore.QLine(-9999, iterIndex * gridSize, 9999, iterIndex * gridSize))
+                canvas.drawLine(QtCore.QLine(iterIndex * gridSize, -9999, iterIndex * gridSize, 9999))
 
     def getTransformationMatrix(self):
         rawMatrixNum = [float(lineInput.text()) for lineInput in self.matrixLineInputs]
         rawMatrixNum.extend([0, 0, 1])
-        return np.matrix(rawMatrixNum).reshape((3, 3))
+        return numpy.matrix(rawMatrixNum).reshape((3, 3))

Modified: trunk/Master/texmf-dist/asymptote/GUI/DebugFlags.py
===================================================================
--- trunk/Master/texmf-dist/asymptote/GUI/DebugFlags.py	2022-02-27 23:39:53 UTC (rev 62264)
+++ trunk/Master/texmf-dist/asymptote/GUI/DebugFlags.py	2022-02-27 23:41:11 UTC (rev 62265)
@@ -1,6 +1,5 @@
 #!/usr/bin/env python3
 
 keepFiles = False
-printFoutTranscript = False
+printAsyTranscript = False
 printDeconstTranscript = False
-forceRasterizationSVG = False

Modified: trunk/Master/texmf-dist/asymptote/GUI/GuidesManager.py
===================================================================
--- trunk/Master/texmf-dist/asymptote/GUI/GuidesManager.py	2022-02-27 23:39:53 UTC (rev 62264)
+++ trunk/Master/texmf-dist/asymptote/GUI/GuidesManager.py	2022-02-27 23:41:11 UTC (rev 62265)
@@ -1,18 +1,17 @@
 #!/usr/bin/env python3
-import PyQt5.QtWidgets as Qw
-import PyQt5.QtGui as Qg
-import PyQt5.QtCore as Qc
-import numpy as np
+import PyQt5.QtGui as QtGui
+import PyQt5.QtCore as QtCore
+import numpy as numpy
 
 class Guide:
     def __init__(self, pen=None):
         if pen is None:
-            pen = Qg.QPen()
-        assert isinstance(pen, Qg.QPen)
+            pen = QtGui.QPen()
+        assert isinstance(pen, QtGui.QPen)
         self.pen = pen
 
     def drawShape(self, pen):
-        assert isinstance(pen, Qg.QPainter)
+        assert isinstance(pen, QtGui.QPainter)
         pen.save()
         pen.setPen(self.pen)
 
@@ -24,19 +23,19 @@
 
     def drawShape(self, pen):
         super().drawShape(pen)
-        p1 = self.origin + (9999 * Qc.QPointF(np.cos(self.direction), np.sin(self.direction)))
-        p2 = self.origin - (9999 * Qc.QPointF(np.cos(self.direction), np.sin(self.direction)))
-        pen.drawLine(Qc.QLineF(p1, p2))
+        p1 = self.origin + (9999 * QtCore.QPointF(numpy.cos(self.direction), numpy.sin(self.direction)))
+        p2 = self.origin - (9999 * QtCore.QPointF(numpy.cos(self.direction), numpy.sin(self.direction)))
+        pen.drawLine(QtCore.QLineF(p1, p2))
         pen.restore()
 
 class ArcGuide(Guide):
     @classmethod
     def radTo16Deg(cls, radians):
-        return int(round(np.rad2deg(radians) * 16))
+        return int(round(numpy.rad2deg(radians) * 16))
 
-    def __init__(self, center=None, radius=1, startAng=0, endAng=(2*np.pi), pen=None):
+    def __init__(self, center=None, radius=1, startAng=0, endAng=(2*numpy.pi), pen=None):
         if center is None:
-            center = Qc.QPointF(0, 0)
+            center = QtCore.QPointF(0, 0)
         super().__init__(pen)
         self.center = center
         self.radius = int(radius)
@@ -45,7 +44,7 @@
 
     def drawShape(self, pen):
         super().drawShape(pen)
-        assert isinstance(pen, Qg.QPainter)
+        assert isinstance(pen, QtGui.QPainter)
         x, y = int(round(self.center.x())), int(round(self.center.y()))
         pen.drawArc(x - self.radius, y - self.radius, 2 * self.radius, 2 * self.radius, ArcGuide.radTo16Deg(self.startAng),
                     -ArcGuide.radTo16Deg(self.endAng - self.startAng))

Modified: trunk/Master/texmf-dist/asymptote/GUI/InplaceAddObj.py
===================================================================
--- trunk/Master/texmf-dist/asymptote/GUI/InplaceAddObj.py	2022-02-27 23:39:53 UTC (rev 62264)
+++ trunk/Master/texmf-dist/asymptote/GUI/InplaceAddObj.py	2022-02-27 23:41:11 UTC (rev 62265)
@@ -1,8 +1,8 @@
 #!/usr/bin/env python3
 
-import PyQt5.QtCore as Qc
-import PyQt5.QtGui as Qg
-import xasy2asy as x2a
+import PyQt5.QtCore as QtCore
+import PyQt5.QtGui as QtGui
+import xasy2asy as xasy2asy
 
 import PrimitiveShape
 import math
@@ -11,9 +11,9 @@
 import Widg_addLabel
 
 
-class InplaceObjProcess(Qc.QObject):
-    objectCreated = Qc.pyqtSignal(Qc.QObject)
-    objectUpdated = Qc.pyqtSignal()
+class InplaceObjProcess(QtCore.QObject):
+    objectCreated = QtCore.pyqtSignal(QtCore.QObject)
+    objectUpdated = QtCore.pyqtSignal()
 
     def __init__(self, parent=None):
         super().__init__(parent)
@@ -24,10 +24,10 @@
     def active(self):
         return self._active
 
-    def mouseDown(self, pos, info, mouseEvent: Qg.QMouseEvent=None):
+    def mouseDown(self, pos, info, mouseEvent: QtGui.QMouseEvent=None):
         raise NotImplementedError
 
-    def mouseMove(self, pos, event: Qg.QMouseEvent):
+    def mouseMove(self, pos, event: QtGui.QMouseEvent):
         raise NotImplementedError
 
     def mouseRelease(self):
@@ -45,7 +45,7 @@
     def getXasyObject(self):
         raise NotImplementedError
 
-    def postDrawPreview(self, canvas: Qg.QPainter):
+    def postDrawPreview(self, canvas: QtGui.QPainter):
         pass
 
     def createOptWidget(self, info):
@@ -55,10 +55,10 @@
 class AddCircle(InplaceObjProcess):
     def __init__(self, parent=None):
         super().__init__(parent)
-        self.center = Qc.QPointF(0, 0)
+        self.center = QtCore.QPointF(0, 0)
         self.radius = 0
 
-    def mouseDown(self, pos, info, mouseEvent: Qg.QMouseEvent=None):
+    def mouseDown(self, pos, info, mouseEvent: QtGui.QMouseEvent=None):
         x, y = PrimitiveShape.PrimitiveShape.pos_to_tuple(pos)
         self.radius = 0
         self.center.setX(x)
@@ -75,9 +75,9 @@
 
     def getPreview(self):
         x, y = PrimitiveShape.PrimitiveShape.pos_to_tuple(self.center)
-        boundRect = Qc.QRectF(x - self.radius, y - self.radius, 2 * self.radius, 2 * self.radius)
+        boundRect = QtCore.QRectF(x - self.radius, y - self.radius, 2 * self.radius, 2 * self.radius)
         # because the internal image is flipped...
-        newPath = Qg.QPainterPath()
+        newPath = QtGui.QPainterPath()
         newPath.addEllipse(boundRect)
         # newPath.addRect(boundRect)
         return newPath
@@ -87,9 +87,9 @@
 
     def getXasyObject(self):
         if self.fill:
-            newObj = x2a.xasyFilledShape(self.getObject(), None)
+            newObj = xasy2asy.xasyFilledShape(self.getObject(), None)
         else:
-            newObj = x2a.xasyShape(self.getObject(), None)
+            newObj = xasy2asy.xasyShape(self.getObject(), None)
         return newObj
 
     def forceFinalize(self):
@@ -102,8 +102,9 @@
         self.alignMode = None
         self.opt = None
         self.text = None
-        self.anchor = Qc.QPointF(0, 0)
+        self.anchor = QtCore.QPointF(0, 0)
         self._active = False
+        self.fontSize = 12
 
     def createOptWidget(self, info):
         self.opt = Widg_addLabel.Widg_addLabel(info)
@@ -121,7 +122,7 @@
         self.anchor.setX(x)
         self.anchor.setY(y)
 
-    def mouseDown(self, pos, info, mouseEvent: Qg.QMouseEvent=None):
+    def mouseDown(self, pos, info, mouseEvent: QtGui.QMouseEvent=None):
         if self.opt is not None:
             self.text = self.opt.labelText
         x, y = PrimitiveShape.PrimitiveShape.pos_to_tuple(pos)
@@ -140,7 +141,7 @@
         text = self.text
         align = str(self.alignMode)
         anchor = PrimitiveShape.PrimitiveShape.pos_to_tuple(self.anchor)
-        newLabel = x2a.xasyText(text=text, location=anchor, pen=None,
+        newLabel = xasy2asy.xasyText(text=text, location=anchor, pen=None,
                                 align=align, asyengine=None, fontsize=self.fontSize)
         newLabel.asyfied = False
         return newLabel
@@ -164,11 +165,11 @@
         # Linkmode should be to the last point.
         # (x, y, linkmode), (u, v, lm2) <==> (x, y) <=lm2=> (u, v)
         self.pointsList = []
-        self.currentPoint = Qc.QPointF(0, 0)
+        self.currentPoint = QtCore.QPointF(0, 0)
         self.pendingPoint = None
         self.useLegacy = False
 
-    def mouseDown(self, pos, info, mouseEvent: Qg.QMouseEvent=None):
+    def mouseDown(self, pos, info, mouseEvent: QtGui.QMouseEvent=None):
         x, y = PrimitiveShape.PrimitiveShape.pos_to_tuple(pos)
         self.currentPoint.setX(x)
         self.currentPoint.setY(y)
@@ -222,7 +223,7 @@
         # self.updateBasePath()
 
     def updateBasePath(self):
-        self.basePath = x2a.asyPath(asyengine=self.asyengine, forceCurve=self.useBezierBase)
+        self.basePath = xasy2asy.asyPath(asyengine=self.asyengine, forceCurve=self.useBezierBase)
         newNode = [(x, y) for x, y, _ in self.pointsList]
         newLink = [lnk for *args, lnk in self.pointsList[1:]]
         if self.useLegacy:
@@ -237,7 +238,7 @@
             self.basePath.computeControls()
 
     def updateBasePathPreview(self):
-        self.basePathPreview = x2a.asyPath(
+        self.basePathPreview = xasy2asy.asyPath(
             asyengine=self.asyengine, forceCurve=self.useBezierBase)
         newNode = [(x, y) for x, y, _ in self.pointsList] + [(self.currentPoint.x(), self.currentPoint.y())]
         newLink = [lnk for *args, lnk in self.pointsList[1:]] + [self._getLinkType()]
@@ -271,16 +272,16 @@
 
     def getXasyObject(self):
         if self.fill:
-            return x2a.xasyFilledShape(self.getObject(), None)
+            return xasy2asy.xasyFilledShape(self.getObject(), None)
         else:
-            return x2a.xasyShape(self.getObject(), None)
+            return xasy2asy.xasyShape(self.getObject(), None)
 
 
 class AddPoly(InplaceObjProcess):
     def __init__(self, parent=None):
         super().__init__(parent)
-        self.center = Qc.QPointF(0, 0)
-        self.currPos = Qc.QPointF(0, 0)
+        self.center = QtCore.QPointF(0, 0)
+        self.currPos = QtCore.QPointF(0, 0)
         self.sides = None
         self.inscribed = None
         self.centermode = None
@@ -288,7 +289,7 @@
         self.fill = None
         self.opt = None
 
-    def mouseDown(self, pos, info, mouseEvent: Qg.QMouseEvent=None):
+    def mouseDown(self, pos, info, mouseEvent: QtGui.QMouseEvent=None):
         self._active = True
         self.sides = info['sides']
         self.inscribed = info['inscribed']
@@ -295,11 +296,11 @@
         self.centermode = info['centermode']
         self.fill = info['fill']
 
-        
+
         x, y = PrimitiveShape.PrimitiveShape.pos_to_tuple(pos)
         self.center.setX(x)
         self.center.setY(y)
-        self.currPos = Qc.QPointF(self.center)
+        self.currPos = QtCore.QPointF(self.center)
 
     def mouseMove(self, pos, event):
         x, y = PrimitiveShape.PrimitiveShape.pos_to_tuple(pos)
@@ -329,7 +330,7 @@
         else:
             poly = PrimitiveShape.PrimitiveShape.exscribedRegPolygon(self.sides, self.center, self._rad(),
                                                                      self._angle(), qpoly=True)
-        newPath = Qg.QPainterPath()
+        newPath = QtGui.QPainterPath()
         newPath.addPolygon(poly)
         return newPath
 
@@ -350,7 +351,121 @@
 
     def getXasyObject(self):
         if self.fill:
-            newObj = x2a.xasyFilledShape(self.getObject(), None)
+            newObj = xasy2asy.xasyFilledShape(self.getObject(), None)
         else:
-            newObj = x2a.xasyShape(self.getObject(), None)
+            newObj = xasy2asy.xasyShape(self.getObject(), None)
         return newObj
+
+class AddFreehand(InplaceObjProcess):
+    # TODO: At the moment this is just a copy-paste of the AddBezierObj.
+    # Must find a better algorithm for constructing the obj rather than
+    # a node for every pixel the mouse moves.
+    def __init__(self, parent=None):
+        super().__init__(parent)
+        self.asyengine = None
+        self.basePath = None
+        self.basePathPreview = None
+        self.closedPath = None
+        self.info = None
+        self.fill = False
+        self.opt = None
+
+        # list of "committed" points with Linkage information.
+        # Linkmode should be to the last point.
+        # (x, y, linkmode), (u, v, lm2) <==> (x, y) <=lm2=> (u, v)
+        self.pointsList = []
+        self.currentPoint = QtCore.QPointF(0, 0)
+        self.pendingPoint = None
+        self.useLegacy = False
+
+    def mouseDown(self, pos, info, mouseEvent: QtGui.QMouseEvent=None):
+        x, y = PrimitiveShape.PrimitiveShape.pos_to_tuple(pos)
+        self.currentPoint.setX(x)
+        self.currentPoint.setY(y)
+        self.info = info
+
+        if not self._active:
+            self._active = True
+            self.fill = info['fill']
+            self.asyengine = info['asyengine']
+            self.closedPath = info['closedPath']
+            self.useBezierBase = info['useBezier']
+            self.useLegacy = self.info['options']['useLegacyDrawMode']
+            self.pointsList.clear()
+            self.pointsList.append((x, y, None))
+        else:
+            # see http://doc.qt.io/archives/qt-4.8/qt.html#MouseButton-enum
+            if (int(mouseEvent.buttons()) if mouseEvent is not None else 0) & 0x2 and self.useLegacy:
+                self.forceFinalize()
+
+    def _getLinkType(self):
+        if self.info['useBezier']:
+            return '..'
+        else:
+            return '--'
+
+    def mouseMove(self, pos, event):
+        # in postscript coords.
+        if self._active:
+            x, y = PrimitiveShape.PrimitiveShape.pos_to_tuple(pos)
+
+            if self.useLegacy or int(event.buttons()) != 0:
+                self.currentPoint.setX(x)
+                self.currentPoint.setY(y)
+                self.pointsList.append((x, y, self._getLinkType()))
+
+
+    def createOptWidget(self, info):
+        return None
+
+    def mouseRelease(self):
+        self.updateBasePath()
+        self._active = False
+        self.pointsList.clear()
+        self.objectCreated.emit(self.getXasyObject())
+        self.basePath = None
+
+    def updateBasePath(self):
+        self.basePath = xasy2asy.asyPath(asyengine=self.asyengine, forceCurve=self.useBezierBase)
+        newNode = [(x, y) for x, y, _ in self.pointsList]
+        newLink = [lnk for *args, lnk in self.pointsList[1:]]
+        if self.useLegacy:
+            newNode += [(self.currentPoint.x(), self.currentPoint.y())]
+            newLink += [self._getLinkType()]
+        if self.closedPath:
+            newNode.append('cycle')
+            newLink.append(self._getLinkType())
+        self.basePath.initFromNodeList(newNode, newLink)
+
+        if self.useBezierBase:
+            self.basePath.computeControls()
+
+    def updateBasePathPreview(self):
+        self.basePathPreview = xasy2asy.asyPath(
+            asyengine=self.asyengine, forceCurve=self.useBezierBase)
+        newNode = [(x, y) for x, y, _ in self.pointsList] + [(self.currentPoint.x(), self.currentPoint.y())]
+        newLink = [lnk for *args, lnk in self.pointsList[1:]] + [self._getLinkType()]
+        if self.closedPath:
+            newNode.append('cycle')
+            newLink.append(self._getLinkType())
+        self.basePathPreview.initFromNodeList(newNode, newLink)
+
+        if self.useBezierBase:
+            self.basePathPreview.computeControls()
+
+    def getObject(self):
+        if self.basePath is None:
+            raise RuntimeError('BasePath is None')
+        self.basePath.asyengine = self.asyengine
+        return self.basePath
+
+    def getPreview(self):
+        if self._active:
+            if self.pointsList:
+                self.updateBasePathPreview()
+                newPath = self.basePathPreview.toQPainterPath()
+                return newPath
+
+    def getXasyObject(self):
+        self.fill = False
+        return xasy2asy.xasyShape(self.getObject(), None)

Modified: trunk/Master/texmf-dist/asymptote/GUI/PrimitiveShape.py
===================================================================
--- trunk/Master/texmf-dist/asymptote/GUI/PrimitiveShape.py	2022-02-27 23:39:53 UTC (rev 62264)
+++ trunk/Master/texmf-dist/asymptote/GUI/PrimitiveShape.py	2022-02-27 23:41:11 UTC (rev 62265)
@@ -1,10 +1,10 @@
 #!/usr/bin/env python3
 
-import xasy2asy as x2a
-import numpy as np
+import xasy2asy as xasy2asy
+import numpy as numpy
 import math
-import PyQt5.QtCore as Qc
-import PyQt5.QtGui as Qg
+import PyQt5.QtCore as QtCore
+import PyQt5.QtGui as QtGui
 
 
 class PrimitiveShape:
@@ -14,9 +14,9 @@
 
     @staticmethod
     def pos_to_tuple(pos):
-        if isinstance(pos, tuple) or isinstance(pos, np.ndarray):
+        if isinstance(pos, tuple) or isinstance(pos, numpy.ndarray):
             return pos
-        elif isinstance(pos, Qc.QPoint) or isinstance(pos, Qc.QPointF):
+        elif isinstance(pos, QtCore.QPoint) or isinstance(pos, QtCore.QPointF):
             return pos.x(), pos.y()
         else:
             raise TypeError("Position must be a valid type!")
@@ -32,7 +32,7 @@
     @classmethod
     def circle(cls, position, radius):
         pos_x, pos_y = PrimitiveShape.pos_to_tuple(position)
-        newCircle = x2a.asyPath()
+        newCircle = xasy2asy.asyPath()
         ptsList = [(pos_x + radius, pos_y), (pos_x, pos_y + radius), (pos_x - radius, pos_y), (pos_x, pos_y - radius),
                    'cycle']
         # cycle doesn't work for now.
@@ -45,16 +45,16 @@
         pos_x, pos_y = PrimitiveShape.pos_to_tuple(position)
         lkList = ['--'] * sides
         ptsList = []
-        for ang in np.linspace(starting_rad, starting_rad + math.tau, sides, endpoint=False):
+        for ang in numpy.linspace(starting_rad, starting_rad + math.tau, sides, endpoint=False):
             ptsList.append((pos_x + radius * math.cos(ang), pos_y + radius * math.sin(ang)))
 
         if qpoly:
             ptsList.append((pos_x + radius * math.cos(starting_rad), pos_y + radius * math.sin(starting_rad)))
-            qpoints = [Qc.QPointF(x, y) for (x, y) in ptsList]
-            return Qg.QPolygonF(qpoints)
+            qpoints = [QtCore.QPointF(x, y) for (x, y) in ptsList]
+            return QtGui.QPolygonF(qpoints)
         else:
             ptsList.append('cycle')
-            newPoly = x2a.asyPath()
+            newPoly = xasy2asy.asyPath()
             newPoly.initFromNodeList(ptsList, lkList)
             return newPoly
 

Modified: trunk/Master/texmf-dist/asymptote/GUI/SetCustomAnchor.py
===================================================================
--- trunk/Master/texmf-dist/asymptote/GUI/SetCustomAnchor.py	2022-02-27 23:39:53 UTC (rev 62264)
+++ trunk/Master/texmf-dist/asymptote/GUI/SetCustomAnchor.py	2022-02-27 23:41:11 UTC (rev 62265)
@@ -1,20 +1,20 @@
 #!/usr/bin/env python3
 
-import PyQt5.QtWidgets as Qw
-import PyQt5.QtGui as Qg
-import PyQt5.QtCore as Qc
+import PyQt5.QtWidgets as QtWidgets
+import PyQt5.QtGui as QtGui
+import PyQt5.QtCore as QtCore
 from pyUIClass.setCustomAnchor import Ui_Dialog
 
 
-class CustomAnchorDialog(Qw.QDialog):
+class CustomAnchorDialog(QtWidgets.QDialog):
 
     def __init__(self):
         super().__init__()
         self.ui = Ui_Dialog()
         self.ui.setupUi(self)
-        self.ui.buttonBox.button(Qw.QDialogButtonBox.Reset).clicked.connect(self.resetDialog)
+        self.ui.buttonBox.button(QtWidgets.QDialogButtonBox.Reset).clicked.connect(self.resetDialog)
 
-        validator = Qg.QDoubleValidator()
+        validator = QtGui.QDoubleValidator()
 
         self.ui.lineEditX.setValidator(validator)
         self.ui.lineEditY.setValidator(validator)
@@ -24,18 +24,18 @@
 
     def checkTextChanged(self, text):
         if str(text) not in {'.', '-', '.-', '-.'} and str(text):
-            self.ui.buttonBox.button(Qw.QDialogButtonBox.Ok).setEnabled(True)
+            self.ui.buttonBox.button(QtWidgets.QDialogButtonBox.Ok).setEnabled(True)
         else:
-            self.ui.buttonBox.button(Qw.QDialogButtonBox.Ok).setEnabled(False)
+            self.ui.buttonBox.button(QtWidgets.QDialogButtonBox.Ok).setEnabled(False)
 
     def getPoint(self):
         xPoint = float(self.ui.lineEditX.text())
         yPoint = float(self.ui.lineEditY.text())
 
-        return Qc.QPointF(xPoint, yPoint)
+        return QtCore.QPointF(xPoint, yPoint)
 
     def handleBtnBoxClick(self, button):
-        assert isinstance(button, Qw.QAbstractButton)
+        assert isinstance(button, QtWidgets.QAbstractButton)
         if button.text() == 'Reset':
             self.resetDialog()
 

Modified: trunk/Master/texmf-dist/asymptote/GUI/Widg_addLabel.py
===================================================================
--- trunk/Master/texmf-dist/asymptote/GUI/Widg_addLabel.py	2022-02-27 23:39:53 UTC (rev 62264)
+++ trunk/Master/texmf-dist/asymptote/GUI/Widg_addLabel.py	2022-02-27 23:41:11 UTC (rev 62265)
@@ -1,14 +1,14 @@
 #!/usr/bin/env python3
 
 from pyUIClass.widg_addLabel import Ui_Form
-import PyQt5.QtWidgets as Qw
-import PyQt5.QtGui as Qg
+import PyQt5.QtWidgets as QtWidgets
+import PyQt5.QtGui as QtGui
 
 import labelEditor
 import xasyUtils as xu
 
 
-class Widg_addLabel(Qw.QWidget):
+class Widg_addLabel(QtWidgets.QWidget):
     def __init__(self, info):
         super().__init__()
         self.ui = Ui_Form()
@@ -34,11 +34,11 @@
         if self.info['shift_y'] is not None:
             self.ui.txtShiftY.setText(str(self.info['shift_y']))
 
-        
+
         self.ui.cmbFontSize.setCurrentText(str(self.info['fontSize']) if self.info['fontSize'] is not None else '-')
         self.ui.cmbAlign.setCurrentIndex(self.info['alignIndex'])
 
-        validator = Qg.QDoubleValidator()
+        validator = QtGui.QDoubleValidator()
 
         self.ui.txtShiftX.setValidator(validator)
         self.ui.txtShiftY.setValidator(validator)
@@ -53,7 +53,7 @@
 
         self.updateCheck(self.ui.cmbAlign.currentText())
 
-    def cmbFontSizeTextChanged(self, text: str): 
+    def cmbFontSizeTextChanged(self, text: str):
         tryParseVal = xu.tryParse(text, float)
         self.info['fontSize'] = tryParseVal
 
@@ -61,7 +61,7 @@
         advancedEditDialog = labelEditor.labelEditor(self.ui.txtLabelText.text())
         advancedEditDialog.show()
         result = advancedEditDialog.exec_()
-        if result == Qw.QDialog.Accepted:
+        if result == QtWidgets.QDialog.Accepted:
             self.ui.txtLabelText.setText(advancedEditDialog.getText())
 
     @property

Modified: trunk/Master/texmf-dist/asymptote/GUI/Widg_addPolyOpt.py
===================================================================
--- trunk/Master/texmf-dist/asymptote/GUI/Widg_addPolyOpt.py	2022-02-27 23:39:53 UTC (rev 62264)
+++ trunk/Master/texmf-dist/asymptote/GUI/Widg_addPolyOpt.py	2022-02-27 23:41:11 UTC (rev 62265)
@@ -1,14 +1,13 @@
 #!/usr/bin/env python3
 
 from pyUIClass.widg_addPolyOpt import Ui_Form
-import PyQt5.QtWidgets as Qw
-import PyQt5.QtGui as Qg
-import PyQt5.QtCore as Qc
+import PyQt5.QtWidgets as QtWidgets
+import PyQt5.QtGui as QtGui
 
 import sys
 
 
-class Widg_addPolyOpt(Qw.QWidget):
+class Widg_addPolyOpt(QtWidgets.QWidget):
     def __init__(self, info):
         super().__init__()
         self.ui = Ui_Form()
@@ -18,7 +17,7 @@
 
         self.ui.chkInscribed.setChecked(self.info['inscribed'])
         self.ui.txtSides.setText(str(self.info['sides']))
-        self.ui.txtSides.setValidator(Qg.QIntValidator())
+        self.ui.txtSides.setValidator(QtGui.QIntValidator())
 
         self.ui.chkInscribed.stateChanged.connect(self.chkInscribedUpdate)
         self.ui.txtSides.textChanged.connect(self.txtSidesUpdate)

Modified: trunk/Master/texmf-dist/asymptote/GUI/Widg_editBezier.py
===================================================================
--- trunk/Master/texmf-dist/asymptote/GUI/Widg_editBezier.py	2022-02-27 23:39:53 UTC (rev 62264)
+++ trunk/Master/texmf-dist/asymptote/GUI/Widg_editBezier.py	2022-02-27 23:41:11 UTC (rev 62265)
@@ -2,9 +2,8 @@
 
 from pyUIClass.widg_editBezier import Ui_Form
 
-import PyQt5.QtCore as Qc
-import PyQt5.QtWidgets as Qw
-import PyQt5.QtGui as Qg
+import PyQt5.QtWidgets as QtWidgets
+import PyQt5.QtCore as QtCore
 
 class LockMode:
     noLock = 0
@@ -11,7 +10,7 @@
     angleLock = 1
     angleAndScaleLock = 2
 
-class Widg_editBezier(Qw.QWidget):
+class Widg_editBezier(QtWidgets.QWidget):
     def __init__(self, info: dict, enableCurveFeatures: bool=True):
         super().__init__()
         self.ui = Ui_Form()
@@ -38,16 +37,16 @@
     def lockMode(self) -> int:
         return self.ui.cmbLockMode.currentIndex()
 
-    @Qc.pyqtSlot(int)
+    @QtCore.pyqtSlot(int)
     def cmbLockIndexChange(self, index: int):
         self.info['editBezierlockMode'] = index
 
-    @Qc.pyqtSlot(int)
+    @QtCore.pyqtSlot(int)
     def chkRecomputeChanged(self, checked: int):
         isChecked = (checked == 2)
         for obj in self.disableOnAutoRecompute:
             obj.setEnabled(not checked)
         self.info['autoRecompute'] = checked
-        
+
         if isChecked:
             self.ui.btnForceRecompute.clicked.emit()

Modified: trunk/Master/texmf-dist/asymptote/GUI/Window1.py
===================================================================
--- trunk/Master/texmf-dist/asymptote/GUI/Window1.py	2022-02-27 23:39:53 UTC (rev 62264)
+++ trunk/Master/texmf-dist/asymptote/GUI/Window1.py	2022-02-27 23:41:11 UTC (rev 62265)
@@ -18,6 +18,7 @@
 import datetime
 import string
 import atexit
+import pickle
 
 import xasyUtils as xu
 import xasy2asy as x2a
@@ -50,7 +51,6 @@
         self.transformation = transformation
         self.isLocal = isLocal
 
-
 class ObjCreationChanges(ActionChanges):
     def __init__(self, obj):
         self.object = obj
@@ -60,6 +60,18 @@
         self.item = obj
         self.objIndex = pos
 
+class SoftDeletionChanges(ActionChanges):
+    def __init__(self, obj, keyPos):
+        self.item = obj
+        self.keyMap = keyPos
+
+class EditBezierChanges(ActionChanges):
+    def __init__(self, obj, pos, oldPath, newPath):
+        self.item = obj
+        self.objIndex = pos
+        self.oldPath = oldPath
+        self.newPath = newPath
+
 class AnchorMode:
     center = 0
     origin = 1
@@ -68,8 +80,8 @@
     bottomRight = 4
     bottomLeft = 5
     customAnchor = 6
-    
 
+
 class GridMode:
     cartesian = 0
     polar = 1
@@ -84,6 +96,14 @@
     delete = 5
     setAnchor = 6
     selectEdit = 7
+    openPoly = 8
+    closedPoly = 9
+    openCurve = 10
+    closedCurve = 11
+    addPoly = 12
+    addCircle = 13
+    addLabel = 14
+    addFreehand = 15
 
 class AddObjectMode:
     Circle = 0
@@ -92,14 +112,15 @@
 
 class MainWindow1(Qw.QMainWindow):
     defaultFrameStyle = """
-    QFrame{{ 
+    QFrame{{
         padding: 4.0;
-        border-radius: 3.0; 
+        border-radius: 3.0;
         background: rgb({0}, {1}, {2})
     }}
     """
 
     def __init__(self):
+        self.testingActions = []
         super().__init__()
         self.ui = Ui_MainWindow()
         global devicePixelRatio
@@ -109,12 +130,13 @@
 
         self.settings = xo.BasicConfigs.defaultOpt
         self.keyMaps = xo.BasicConfigs.keymaps
+        self.openRecent = xo.BasicConfigs.openRecent
 
         self.raw_args = Qc.QCoreApplication.arguments()
         self.args = xa.parseArgs(self.raw_args)
 
         self.strings = xs.xasyString(self.args.language)
-        self.asy2psmap = x2a.identity()
+        self.asy2psmap = x2a.yflip()
 
         if self.settings['asyBaseLocation'] is not None:
             os.environ['ASYMPTOTE_DIR'] = self.settings['asyBaseLocation']
@@ -134,7 +156,8 @@
 
         # For initialization purposes
         self.canvSize = Qc.QSize()
-        self.filename = None
+        self.fileName = None
+        self.asyFileName = None
         self.currDir = None
         self.mainCanvas = None
         self.dpi = 300
@@ -165,9 +188,9 @@
         self.inMidTransformation = False
         self.addMode = None
         self.currentlySelectedObj = {'key': None, 'allSameKey': set(), 'selectedIndex': None, 'keyIndex': None}
-        self.pendingSelectedObjList = [] 
+        self.pendingSelectedObjList = []
         self.pendingSelectedObjIndex = -1
-        
+
         self.savedMousePosition = None
         self.currentBoundingBox = None
         self.selectionDelta = None
@@ -177,9 +200,12 @@
         self.scaleFactor = 1
         self.panOffset = [0, 0]
 
+        # Keyboard can focus outside of textboxes
+        self.setFocusPolicy(Qc.Qt.StrongFocus)
+
         super().setMouseTracking(True)
         # setMouseTracking(True)
-        
+
         self.undoRedoStack = Urs.actionStack()
 
         self.lockX = False
@@ -211,8 +237,10 @@
 
         self.modeButtons = {
             self.ui.btnTranslate, self.ui.btnRotate, self.ui.btnScale, # self.ui.btnSelect,
-            self.ui.btnPan, self.ui.btnDeleteMode, self.ui.btnAnchor, 
-            self.ui.btnSelectEdit
+            self.ui.btnPan, self.ui.btnDeleteMode, self.ui.btnAnchor,
+            self.ui.btnSelectEdit, self.ui.btnOpenPoly, self.ui.btnClosedPoly,
+            self.ui.btnOpenCurve, self.ui.btnClosedCurve, self.ui.btnAddPoly,
+            self.ui.btnAddCircle, self.ui.btnAddLabel, self.ui.btnAddFreehand
                             }
 
         self.objButtons = {self.ui.btnCustTransform, self.ui.actionTransform, self.ui.btnSendForwards,
@@ -225,17 +253,17 @@
 
         self.currAddOptionsWgt = None
         self.currAddOptions = {
-            'options': self.settings, 
+            'options': self.settings,
             'inscribed': True,
             'sides': 3,
             'centermode': True,
-            'fontSize': None, 
+            'fontSize': None,
             'asyengine': self.asyEngine,
             'fill': self.ui.btnFill.isChecked(),
             'closedPath': False,
-            'useBezier': True, 
+            'useBezier': True,
             'magnification': self.magnification,
-            'editBezierlockMode': xbi.Web.LockMode.angleLock, 
+            'editBezierlockMode': xbi.Web.LockMode.angleLock,
             'autoRecompute': False
         }
 
@@ -249,7 +277,7 @@
 
         # commands switchboard
         self.commandsFunc = {
-            'quit': Qc.QCoreApplication.quit,
+            'quit': self.btnCloseFileonClick,
             'undo': self.btnUndoOnClick,
             'redo': self.btnRedoOnClick,
             'manual': self.actionManual,
@@ -261,10 +289,10 @@
             'commandPalette': self.enterCustomCommand,
             'clearGuide': self.clearGuides,
             'finalizeAddObj': self.finalizeAddObj,
-            'finalizeCurve': self.finalizeCurve, 
-            'finalizeCurveClosed': self.finalizeCurveClosed, 
+            'finalizeCurve': self.finalizeCurve,
+            'finalizeCurveClosed': self.finalizeCurveClosed,
             'setMag': self.setMagPrompt,
-            'deleteObject': self.btnSelectiveDeleteOnClick, 
+            'deleteObject': self.btnSelectiveDeleteOnClick,
             'anchorMode': self.switchToAnchorMode,
             'moveUp': lambda: self.translate(0, -1),
             'moveDown': lambda: self.translate(0, 1),
@@ -274,10 +302,17 @@
             'scrollLeft': lambda: self.arrowButtons(-1, 0, True),
             'scrollRight': lambda: self.arrowButtons(1, 0, True),
             'scrollUp': lambda: self.arrowButtons(0, 1, True),
-            'scrollDown': lambda: self.arrowButtons(0, -1, True), 
+            'scrollDown': lambda: self.arrowButtons(0, -1, True),
 
-            'zoomIn': lambda: self.arrowButtons(0, 1, False, True), 
-            'zoomOut': lambda: self.arrowButtons(0, -1, False, True)
+            'zoomIn': lambda: self.arrowButtons(0, 1, False, True),
+            'zoomOut': lambda: self.arrowButtons(0, -1, False, True),
+
+            'open': self.btnLoadFileonClick,
+            'save': self.actionSave,
+            'export': self.btnExportAsymptoteOnClick,
+
+            'copy': self.copyItem,
+            'paste': self.pasteItem
         }
 
         self.hiddenKeys = set()
@@ -291,6 +326,7 @@
         # from xasyoptions config file
         self.loadKeyMaps()
         self.setupXasyOptions()
+        self.populateOpenRecent()
 
         self.colorDialog = Qw.QColorDialog(x2a.asyPen.convertToQColor(self._currentPen.color), self)
         self.initPenInterface()
@@ -320,7 +356,7 @@
     def getScrsTransform(self):
         # pipeline:
         # assuming origin <==> top left
-        # (Pan) * (Translate) * (Flip the images) * (Zoom) * (Obj transform) * (Base Information) 
+        # (Pan) * (Translate) * (Flip the images) * (Zoom) * (Obj transform) * (Base Information)
 
         # pipeline --> let x, y be the postscript point
         # p = (mx + cx + panoffset, -ny + cy + panoffset)
@@ -366,6 +402,12 @@
         self.settings.load()
         self.quickUpdate()
 
+    def openAndReloadKeymaps(self):
+        keymapsFile = self.keyMaps.settingsFileLocation()
+        subprocess.run(args=self.getExternalEditor(asypath=keymapsFile))
+        self.settings.load()
+        self.quickUpdate()
+
     def setMagPrompt(self):
         commandText, result = Qw.QInputDialog.getText(self, '', 'Enter magnification:')
         if result:
@@ -373,6 +415,11 @@
             self.currAddOptions['magnification'] = self.magnification
             self.quickUpdate()
 
+    def setTextPrompt(self):
+        commandText, result = Qw.QInputDialog.getText(self, '', 'Enter new text:')
+        if result:
+            return commandText
+
     def btnTogglePythonOnClick(self, checked):
         self.terminalPythonMode = checked
 
@@ -381,7 +428,10 @@
 
     def handleArguments(self):
         if self.args.filename is not None:
-            self.loadFile(self.args.filename)
+            if os.path.exists(self.args.filename):
+                self.actionOpen(os.path.abspath(self.args.filename))
+            else:
+                self.loadFile(self.args.filename)
         else:
             self.initializeEmptyFile()
 
@@ -417,14 +467,18 @@
         self.ui.actionRedo.triggered.connect(lambda: self.execCustomCommand('redo'))
         self.ui.actionTransform.triggered.connect(lambda: self.execCustomCommand('transform'))
 
+        self.ui.actionNewFile.triggered.connect(self.actionNewFile)
         self.ui.actionOpen.triggered.connect(self.actionOpen)
+        self.ui.actionClearRecent.triggered.connect(self.actionClearRecent)
         self.ui.actionSave.triggered.connect(self.actionSave)
         self.ui.actionSaveAs.triggered.connect(self.actionSaveAs)
         self.ui.actionManual.triggered.connect(self.actionManual)
         self.ui.actionAbout.triggered.connect(self.actionAbout)
         self.ui.actionSettings.triggered.connect(self.openAndReloadSettings)
+        self.ui.actionKeymaps.triggered.connect(self.openAndReloadKeymaps)
         self.ui.actionEnterCommand.triggered.connect(self.enterCustomCommand)
-        self.ui.actionExportAsymptote.triggered.connect(self.btnExportAsyOnClick)
+        self.ui.actionExportAsymptote.triggered.connect(self.btnExportAsymptoteOnClick)
+        self.ui.actionExportToAsy.triggered.connect(self.btnExportToAsyOnClick)
 
     def setupXasyOptions(self):
         if self.settings['debugMode']:
@@ -443,7 +497,7 @@
         self.ui.btnSave.clicked.connect(self.btnSaveonClick)
         self.ui.btnQuickScreenshot.clicked.connect(self.btnQuickScreenshotOnClick)
 
-        # self.ui.btnExportAsy.clicked.connect(self.btnExportAsyOnClick)
+        # self.ui.btnExportAsy.clicked.connect(self.btnExportAsymptoteOnClick)
 
         self.ui.btnDrawAxes.clicked.connect(self.btnDrawAxesOnClick)
 #        self.ui.btnAsyfy.clicked.connect(lambda: self.asyfyCanvas(True))
@@ -467,7 +521,7 @@
         self.ui.btnAnchor.clicked.connect(self.btnAnchorModeOnClick)
 
         self.ui.btnSelectColor.clicked.connect(self.btnColorSelectOnClick)
-        self.ui.txtLineWidth.textEdited.connect(self.txtLineWithEdited)
+        self.ui.txtLineWidth.textEdited.connect(self.txtLineWidthEdited)
 
         # self.ui.btnCreateCurve.clicked.connect(self.btnCreateCurveOnClick)
         self.ui.btnDrawGrid.clicked.connect(self.btnDrawGridOnClick)
@@ -475,6 +529,7 @@
         self.ui.btnAddCircle.clicked.connect(self.btnAddCircleOnClick)
         self.ui.btnAddPoly.clicked.connect(self.btnAddPolyOnClick)
         self.ui.btnAddLabel.clicked.connect(self.btnAddLabelOnClick)
+        self.ui.btnAddFreehand.clicked.connect(self.btnAddFreehandOnClick)
         # self.ui.btnAddBezierInplace.clicked.connect(self.btnAddBezierInplaceOnClick)
         self.ui.btnClosedCurve.clicked.connect(self.btnAddClosedCurveOnClick)
         self.ui.btnOpenCurve.clicked.connect(self.btnAddOpenCurveOnClick)
@@ -489,16 +544,19 @@
         self.ui.btnDeleteMode.clicked.connect(self.btnDeleteModeOnClick)
         # self.ui.btnSoftDelete.clicked.connect(self.btnSoftDeleteOnClick)
         self.ui.btnToggleVisible.clicked.connect(self.btnSetVisibilityOnClick)
-        
+
         self.ui.btnEnterCommand.clicked.connect(self.btnTerminalCommandOnClick)
         self.ui.btnTogglePython.clicked.connect(self.btnTogglePythonOnClick)
         self.ui.btnSelectEdit.clicked.connect(self.btnSelectEditOnClick)
 
     def btnDeleteModeOnClick(self):
-        self.currentModeStack = [SelectionMode.delete]
-        self.ui.statusbar.showMessage('Delete Mode')
-        self.clearSelection()
-        self.updateChecks()
+        if self.currentModeStack[-1] != SelectionMode.delete:
+            self.currentModeStack = [SelectionMode.delete]
+            self.ui.statusbar.showMessage('Delete mode')
+            self.clearSelection()
+            self.updateChecks()
+        else:
+            self.btnTranslateonClick()
 
     def btnTerminalCommandOnClick(self):
         if self.terminalPythonMode:
@@ -507,18 +565,25 @@
         else:
             pass
             # TODO: How to handle this case?
-            # Like AutoCAD? 
+            # Like AutoCAD?
         self.ui.txtTerminalPrompt.clear()
 
-    def btnFillOnClick(self, checked): 
+    def btnFillOnClick(self, checked):
+        if self.currentModeStack == [SelectionMode.selectEdit]:
+            if isinstance(self.addMode,xbi.InteractiveBezierEditor):
+                self.addMode.swapObjFill() #Check for crashes
         self.currAddOptions['fill'] = checked
         self.ui.btnOpenCurve.setEnabled(not checked)
         self.ui.btnOpenPoly.setEnabled(not checked)
 
     def btnSelectEditOnClick(self):
-        self.ui.statusbar.showMessage('Edit mode')
-        self.currentModeStack = [SelectionMode.selectEdit]
-        self.updateChecks()
+        if self.currentModeStack[-1] != SelectionMode.selectEdit:
+            self.currentModeStack = [SelectionMode.selectEdit]
+            self.ui.statusbar.showMessage('Edit mode')
+            self.clearSelection()
+            self.updateChecks()
+        else:
+            self.btnTranslateonClick()
 
     @property
     def currentPen(self):
@@ -544,7 +609,7 @@
         except Exception:
             pass
 
-        self.currentModeStack[-1] = None
+        #self.currentModeStack[-1] = None
         self.addMode.objectCreated.connect(self.addInPlace)
         self.updateModeBtnsOnly()
 
@@ -557,7 +622,10 @@
 
     def addInPlace(self, obj):
         obj.asyengine = self.asyEngine
-        obj.pen = self.currentPen
+        if isinstance(obj, x2a.xasyText):
+            obj.label.pen = self.currentPen
+        else:
+            obj.pen = self.currentPen
         obj.onCanvas = self.xasyDrawObj
         obj.setKey(str(self.globalObjectCounter))
         self.globalObjectCounter = self.globalObjectCounter + 1
@@ -576,11 +644,6 @@
         self.currentGuides.clear()
         self.quickUpdate()
 
-    def btnAddCircleOnClick(self):
-        self.addMode = InplaceAddObj.AddCircle(self)
-        self.ui.statusbar.showMessage('')
-        self.updateOptionWidget()
-
     LegacyHint='Click and drag to draw; right click or space bar to finalize'
     Hint='Click and drag to draw; release and click in place to add node; continue dragging'
     HintClose=' or c to close.'
@@ -598,49 +661,90 @@
             self.ui.statusbar.showMessage(self.Hint+self.HintClose)
 
     def btnAddBezierInplaceOnClick(self):
+        self.fileChanged = True
         self.addMode = InplaceAddObj.AddBezierShape(self)
         self.updateOptionWidget()
 
     def btnAddOpenLineOnClick(self):
-        self.currAddOptions['useBezier'] = False
-        self.currAddOptions['closedPath'] = False
-        self.drawHintOpen()
-        self.btnAddBezierInplaceOnClick()
+        if self.currentModeStack[-1] != SelectionMode.openPoly:
+            self.currentModeStack = [SelectionMode.openPoly]
+            self.currAddOptions['useBezier'] = False
+            self.currAddOptions['closedPath'] = False
+            self.drawHintOpen()
+            self.btnAddBezierInplaceOnClick()
+        else:
+            self.btnTranslateonClick()
 
     def btnAddClosedLineOnClick(self):
-        self.currAddOptions['useBezier'] = False
-        self.currAddOptions['closedPath'] = True
-        self.drawHint()
-        self.btnAddBezierInplaceOnClick()
+        if self.currentModeStack[-1] != SelectionMode.closedPoly:
+            self.currentModeStack = [SelectionMode.closedPoly]
+            self.currAddOptions['useBezier'] = False
+            self.currAddOptions['closedPath'] = True
+            self.drawHint()
+            self.btnAddBezierInplaceOnClick()
+        else:
+            self.btnTranslateonClick()
 
     def btnAddOpenCurveOnClick(self):
-        self.currAddOptions['useBezier'] = True
-        self.currAddOptions['closedPath'] = False
-        self.drawHintOpen()
-        self.btnAddBezierInplaceOnClick()
+        if self.currentModeStack[-1] != SelectionMode.openCurve:
+            self.currentModeStack = [SelectionMode.openCurve]
+            self.currAddOptions['useBezier'] = True
+            self.currAddOptions['closedPath'] = False
+            self.drawHintOpen()
+            self.btnAddBezierInplaceOnClick()
+        else:
+            self.btnTranslateonClick()
 
     def btnAddClosedCurveOnClick(self):
-        self.currAddOptions['useBezier'] = True
-        self.currAddOptions['closedPath'] = True
-        self.drawHint()
-        self.btnAddBezierInplaceOnClick()
+        if self.currentModeStack[-1] != SelectionMode.closedCurve:
+            self.currentModeStack = [SelectionMode.closedCurve]
+            self.currAddOptions['useBezier'] = True
+            self.currAddOptions['closedPath'] = True
+            self.drawHint()
+            self.btnAddBezierInplaceOnClick()
+        else:
+            self.btnTranslateonClick()
 
     def btnAddPolyOnClick(self):
-        self.addMode = InplaceAddObj.AddPoly(self)
-        self.ui.statusbar.showMessage('')
-        self.updateOptionWidget()
+        if self.currentModeStack[-1] != SelectionMode.addPoly:
+            self.currentModeStack = [SelectionMode.addPoly]
+            self.addMode = InplaceAddObj.AddPoly(self)
+            self.ui.statusbar.showMessage('Add polygon on click')
+            self.updateOptionWidget()
+        else:
+            self.btnTranslateonClick()
 
+    def btnAddCircleOnClick(self):
+        if self.currentModeStack[-1] != SelectionMode.addCircle:
+            self.currentModeStack = [SelectionMode.addCircle]
+            self.addMode = InplaceAddObj.AddCircle(self)
+            self.ui.statusbar.showMessage('Add circle on click')
+            self.updateOptionWidget()
+        else:
+            self.btnTranslateonClick()
+
     def btnAddLabelOnClick(self):
-        self.addMode = InplaceAddObj.AddLabel(self)
-        self.ui.statusbar.showMessage('')
-        self.updateOptionWidget()
+        if self.currentModeStack[-1] != SelectionMode.addLabel:
+            self.currentModeStack = [SelectionMode.addLabel]
+            self.addMode = InplaceAddObj.AddLabel(self)
+            self.ui.statusbar.showMessage('Add label on click')
+            self.updateOptionWidget()
+        else:
+            self.btnTranslateonClick()
 
-    def updateCurve(self, valid, newCurve):
-        self.previewCurve = newCurve
-        self.quickUpdate()
+    def btnAddFreehandOnClick(self):
+        if self.currentModeStack[-1] != SelectionMode.addFreehand:
+            self.currentModeStack = [SelectionMode.addFreehand]
+            self.currAddOptions['useBezier'] = False
+            self.currAddOptions['closedPath'] = False
+            self.ui.statusbar.showMessage("Draw freehand")
+            self.addMode = InplaceAddObj.AddFreehand(self)
+            self.updateOptionWidget()
+        else:
+            self.btnTranslateonClick()
 
     def addTransformationChanges(self, objIndex, transform, isLocal=False):
-        self.undoRedoStack.add(self.createAction(TransformationChanges(objIndex, 
+        self.undoRedoStack.add(self.createAction(TransformationChanges(objIndex,
                             transform, isLocal)))
         self.checkUndoRedoButtons()
 
@@ -665,7 +769,11 @@
             parent = selectedObj.parent()
 
             if isinstance(parent, x2a.xasyScript):
-                self.hiddenKeys.add((selectedObj.key, selectedObj.keyIndex))
+                objKey=(selectedObj.key, selectedObj.keyIndex)
+                self.hiddenKeys.add(objKey)
+                self.undoRedoStack.add(self.createAction(
+                    SoftDeletionChanges(selectedObj.parent(), objKey)
+                    ))
                 self.softDeleteObj((maj, minor))
             else:
                 index = self.fileItems.index(selectedObj.parent())
@@ -673,10 +781,10 @@
                 self.undoRedoStack.add(self.createAction(
                     HardDeletionChanges(selectedObj.parent(), index)
                 ))
-                self.checkUndoRedoButtons()
-                
+
                 self.fileItems.remove(selectedObj.parent())
 
+            self.checkUndoRedoButtons()
             self.fileChanged = True
             self.clearSelection()
             self.asyfyCanvas()
@@ -709,8 +817,16 @@
 
 
     def btnUndoOnClick(self):
-        self.undoRedoStack.undo()
-        self.checkUndoRedoButtons()
+        if self.currentlySelectedObj['selectedIndex'] is not None:
+            # avoid deleting currently selected object
+            maj, minor = self.currentlySelectedObj['selectedIndex']
+            selectedObj = self.drawObjects[maj][minor]
+            if selectedObj != self.drawObjects[-1][0]:
+                self.undoRedoStack.undo()
+                self.checkUndoRedoButtons()
+        else:
+            self.undoRedoStack.undo()
+            self.checkUndoRedoButtons()
 
     def btnRedoOnClick(self):
         self.undoRedoStack.redo()
@@ -731,6 +847,12 @@
             self.fileItems.pop()
         elif isinstance(change, HardDeletionChanges):
             self.fileItems.insert(change.objIndex, change.item)
+        elif isinstance(change, SoftDeletionChanges):
+            key, keyIndex = change.keyMap
+            self.hiddenKeys.remove((key, keyIndex))
+            change.item.transfKeymap[key][keyIndex].deleted = False
+        elif isinstance(change, EditBezierChanges):
+            self.fileItems[change.objIndex].path = change.oldPath
         self.asyfyCanvas()
 
     def handleRedoChanges(self, change):
@@ -742,6 +864,12 @@
             self.fileItems.append(change.object)
         elif isinstance(change, HardDeletionChanges):
             self.fileItems.remove(change.item)
+        elif isinstance(change, SoftDeletionChanges):
+            key, keyIndex = change.keyMap
+            self.hiddenKeys.add((key, keyIndex))
+            change.item.transfKeymap[key][keyIndex].deleted = True
+        elif isinstance(change, EditBezierChanges):
+            self.fileItems[change.objIndex].path = change.newPath
         self.asyfyCanvas()
 
     #  is this a "pythonic" way?
@@ -765,12 +893,27 @@
         if result:
             self.execCustomCommand(commandText)
 
-    def addItemFromPath(self, path):
-        newItem = x2a.xasyShape(path, self.asyEngine, pen=self.currentPen)
+    def addXasyShapeFromPath(self, path, pen = None, transform = x2a.identity(), key = None):
+        if not pen:
+            pen = self.currentPen
+        else:
+            pen = x2a.asyPen(self.asyEngine, color = pen['color'], width = pen['width'], pen_options = pen['options'])
+
+        newItem = x2a.xasyShape(path, self.asyEngine, pen = pen, transform = transform)
+        newItem.setKey(key)
         self.fileItems.append(newItem)
-        self.fileChanged = True
-        self.asyfyCanvas()
 
+    def addXasyTextFromData(self, text, location, pen, transform, key, align, fontSize):
+        if not pen:
+            pen = self.currentPen
+        else:
+            pen = x2a.asyPen(self.asyEngine, color = pen['color'], width = pen['width'], pen_options = pen['options'])
+        newItem = x2a.xasyText(text, location, self.asyEngine, pen, transform, key, align, fontSize)
+        newItem.setKey(key)
+        newItem.onCanvas = self.xasyDrawObj
+        self.fileItems.append(newItem)
+
+
     def actionManual(self):
         asyManualURL = 'https://asymptote.sourceforge.io/asymptote.pdf'
         webbrowser.open_new(asyManualURL)
@@ -778,11 +921,35 @@
     def actionAbout(self):
         Qw.QMessageBox.about(self,"xasy","This is xasy "+xasyVersion.xasyVersion+"; a graphical front end to the Asymptote vector graphics language: https://asymptote.sourceforge.io/")
 
-    def btnExportAsyOnClick(self):
+    def actionExport(self, pathToFile):
+        asyFile = io.open(os.path.realpath(pathToFile), 'w')
+        xf.saveFile(asyFile, self.fileItems, self.asy2psmap)
+        asyFile.close()
+        self.ui.statusbar.showMessage(f"Exported to '{pathToFile}' as Asymptote File.")
+
+    def btnExportToAsyOnClick(self):
+        if self.fileName:
+            pathToFile = os.path.splitext(self.fileName)[0]+'.asy'
+        else:
+            self.btnExportAsymptoteOnClick()
+            return
+        if os.path.isfile(pathToFile):
+            reply = Qw.QMessageBox.question(self, 'Message',
+                f'"{os.path.split(pathToFile)[1]}" already exists.  Do you want to overwrite it?',
+                Qw.QMessageBox.Yes, Qw.QMessageBox.No)
+            if reply == Qw.QMessageBox.No:
+                return
+            self.actionExport(pathToFile)
+
+    def btnExportAsymptoteOnClick(self):
         diag = Qw.QFileDialog(self)
         diag.setAcceptMode(Qw.QFileDialog.AcceptSave)
 
         formatId = {
+            'asy': {
+                'name': 'Asymptote Files',
+                'ext': ['*.asy']
+            },
             'pdf': {
                 'name': 'PDF Files',
                 'ext': ['*.pdf']
@@ -805,7 +972,7 @@
             }
         }
 
-        formats = ['pdf', 'svg', 'eps', 'png', '*']
+        formats = ['asy', 'pdf', 'svg', 'eps', 'png', '*']
 
         formatText = ';;'.join('{0:s} ({1:s})'.format(formatId[form]['name'], ' '.join(formatId[form]['ext']))
                                for form in formats)
@@ -812,7 +979,7 @@
 
         if self.currDir is not None:
             diag.setDirectory(self.currDir)
-            rawFile = os.path.splitext(os.path.basename(self.filename))[0] + '.pdf'
+            rawFile = os.path.splitext(os.path.basename(self.fileName))[0] + '.asy'
             diag.selectFile(rawFile)
 
         diag.setNameFilter(formatText)
@@ -823,26 +990,108 @@
             return
 
         finalFiles = diag.selectedFiles()
+        finalString = xf.xasy2asyCode(self.fileItems, self.asy2psmap)
 
-        with io.StringIO() as finalCode:
-            xf.saveFile(finalCode, self.fileItems, self.asy2psmap)
-            finalString = finalCode.getvalue()
-
         for file in finalFiles:
             ext = os.path.splitext(file)
             if len(ext) < 2:
-                ext = 'pdf'
+                ext = 'asy'
             else:
                 ext = ext[1][1:]
+            if ext == 'asy':
+                pathToFile = os.path.splitext(file)[0]+'.'+ext
+                asyFile = io.open(os.path.realpath(pathToFile), 'w')
+                xf.saveFile(asyFile, self.fileItems, self.asy2psmap)
+                asyFile.close()
+            else:
+                with subprocess.Popen(args=[self.asyPath, '-f{0}'.format(ext), '-o{0}'.format(file), '-'], encoding='utf-8',
+                                    stdin=subprocess.PIPE) as asy:
 
-            with subprocess.Popen(args=[self.asyPath, '-f{0}'.format(ext), '-o{0}'.format(file), '-'], encoding='utf-8',
-                                  stdin=subprocess.PIPE) as asy:
-                print('test:', finalString)
-                asy.stdin.write(finalString)
-                asy.stdin.close()
-                asy.wait(timeout=35)
+                    asy.stdin.write(finalString)
+                    asy.stdin.close()
+                    asy.wait(timeout=35)
 
+    def actionExportXasy(self, file):
+        xasyObjects, asyItems = xf.xasyToDict(self.fileName, self.fileItems, self.asy2psmap)
 
+        if asyItems:
+
+            # Save imported items into the twin asy file
+            asyScriptItems = [item['item'] for item in asyItems if item['type'] == 'xasyScript']
+
+            prefix = os.path.splitext(self.fileName)[0]
+            asyFilePath = prefix + '.asy'
+
+            saveAsyFile = io.open(asyFilePath, 'w')
+            xf.saveFile(saveAsyFile, asyScriptItems, self.asy2psmap)
+            saveAsyFile.close()
+            self.updateScript()
+
+        openFile = open(file, 'wb')
+        pickle.dump(xasyObjects, openFile)
+        openFile.close()
+
+    def actionLoadXasy(self, file):
+        self.erase()
+        self.ui.statusbar.showMessage('Load {0}'.format(file)) # TODO: This doesn't show on the UI
+        self.fileName = file
+        self.currDir = os.path.dirname(self.fileName)
+
+        input_file = open(file, 'rb')
+        xasyObjects = pickle.load(input_file)
+        input_file.close()
+
+        prefix = os.path.splitext(self.fileName)[0]
+        asyFilePath = prefix + '.asy'
+        rawText = None
+        existsAsy = False
+
+        if os.path.isfile(asyFilePath):
+            asyFile = io.open(asyFilePath, 'r')
+            rawText = asyFile.read()
+            asyFile.close()
+            rawText, transfDict = xf.extractTransformsFromFile(rawText)
+            obj = x2a.xasyScript(canvas=self.xasyDrawObj, engine=self.asyEngine, transfKeyMap=transfDict)
+            obj.setScript(rawText)
+            self.fileItems.append(obj)
+            existsAsy = True
+
+        self.asyfyCanvas(force=True)
+
+        for item in xasyObjects['objects']:
+            key=item['transfKey']
+            if(key) in obj.transfKeymap.keys():
+                continue
+            obj.maxKey=max(obj.maxKey,int(key))
+            if item['type'] == 'xasyScript':
+                print("Uh oh, there should not be any asy objects loaded")
+
+            elif item['type'] == 'xasyText':
+                self.addXasyTextFromData( text = item['text'],
+                        location = item['location'], pen = None,
+                        transform = x2a.asyTransform(item['transform']), key = item['transfKey'],
+                        align = item['align'], fontSize = item['fontSize']
+                        )
+
+            elif item['type'] == 'xasyShape':
+                nodeSet = item['nodes']
+                linkSet = item['links']
+                path = x2a.asyPath(self.asyEngine)
+                path.initFromNodeList(nodeSet, linkSet)
+                self.addXasyShapeFromPath(path, pen = item['pen'], transform = x2a.asyTransform(item['transform']), key = item['transfKey'])
+            else:
+                print("ERROR")
+
+        self.asy2psmap = x2a.asyTransform(xasyObjects['asy2psmap'])
+        self.globalObjectCounter = obj.maxKey+1
+
+        self.asyfyCanvas()
+
+        if existsAsy:
+            self.ui.statusbar.showMessage(f"Corresponding Asymptote File '{os.path.basename(asyFilePath)}' found.  Loaded both files.")
+        else:
+            self.ui.statusbar.showMessage("No Asymptote file found.  Loaded exclusively GUI objects.")
+
     def loadKeyMaps(self):
         """Inverts the mapping of the key
            Input map is in format 'Action' : 'Key Sequence' """
@@ -865,28 +1114,147 @@
 
     def erase(self):
         self.fileItems.clear()
+        self.hiddenKeys.clear()
+        self.undoRedoStack.clear()
+        self.checkUndoRedoButtons()
         self.fileChanged = False
 
-    def actionOpen(self):
+    #We include this function to keep the general program flow consistent
+    def closeEvent(self, event):
+        if self.actionClose() == Qw.QMessageBox.Cancel:
+            event.ignore()
+
+    def actionNewFile(self):
         if self.fileChanged:
-            save="Save current file?"
-            reply=Qw.QMessageBox.question(self,'Message',save,Qw.QMessageBox.Yes,
-                                        Qw.QMessageBox.No)
+            reply = self.saveDialog()
             if reply == Qw.QMessageBox.Yes:
                 self.actionSave()
+            elif reply == Qw.QMessageBox.Cancel:
+                return
+        self.erase()
+        self.asyfyCanvas(force=True)
+        self.fileName = None
+        self.updateTitle()
 
-        filename = Qw.QFileDialog.getOpenFileName(self, 'Open Asymptote File','', '*.asy')
-        if filename[0]:
-            self.loadFile(filename[0])
 
+    def actionOpen(self, fileName = None):
+        if self.fileChanged:
+            reply = self.saveDialog()
+            if reply == Qw.QMessageBox.Yes:
+                self.actionSave()
+            elif reply == Qw.QMessageBox.Cancel:
+                return
+
+        if fileName:
+            # Opening via open recent or cmd args
+            _, file_extension = os.path.splitext(fileName)
+            if file_extension == '.xasy':
+                self.actionLoadXasy(fileName)
+            else:
+                self.loadFile(fileName)
+            self.populateOpenRecent(fileName)
+        else:
+            filename = Qw.QFileDialog.getOpenFileName(self, 'Open Xasy/Asymptote File','', '(*.xasy *.asy)')
+            if filename[0]:
+                _, file_extension = os.path.splitext(filename[0])
+                if file_extension == '.xasy':
+                    self.actionLoadXasy(filename[0])
+                else:
+                    self.loadFile(filename[0])
+
+            self.populateOpenRecent(filename[0].strip())
+
+    def actionClearRecent(self):
+        self.ui.menuOpenRecent.clear()
+        self.openRecent.clear()
+        self.ui.menuOpenRecent.addAction("Clear", self.actionClearRecent)
+
+    def populateOpenRecent(self, recentOpenedFile = None):
+        self.ui.menuOpenRecent.clear()
+        if recentOpenedFile:
+            self.openRecent.insert(recentOpenedFile)
+        for count, path in enumerate(self.openRecent.pathList):
+            if count > 8:
+                break
+            action = Qw.QAction(path, self, triggered = lambda state, path = path: self.actionOpen(fileName = path))
+            self.ui.menuOpenRecent.addAction(action)
+        self.ui.menuOpenRecent.addSeparator()
+        self.ui.menuOpenRecent.addAction("Clear", self.actionClearRecent)
+
+    def saveDialog(self) -> bool:
+        save = "Save current file?"
+        replyBox = Qw.QMessageBox()
+        replyBox.setText("Save current file?")
+        replyBox.setWindowTitle("Message")
+        replyBox.setStandardButtons(Qw.QMessageBox.Yes | Qw.QMessageBox.No | Qw.QMessageBox.Cancel)
+        reply = replyBox.exec()
+
+        return reply
+
+    def actionClose(self):
+        if self.fileChanged:
+            reply = self.saveDialog()
+            if reply == Qw.QMessageBox.Yes:
+                self.actionSave()
+                Qc.QCoreApplication.quit()
+            elif reply == Qw.QMessageBox.No:
+                Qc.QCoreApplication.quit()
+            else:
+                return reply
+        else:
+            Qc.QCoreApplication.quit()
+
     def actionSave(self):
-        if self.filename is None:
+        if self.fileName is None:
             self.actionSaveAs()
+
         else:
-            saveFile = io.open(self.filename, 'w')
-            xf.saveFile(saveFile, self.fileItems, self.asy2psmap)
-            saveFile.close()
+            _, file_extension = os.path.splitext(self.fileName)
+            if file_extension == ".asy":
+                if self.existsXasy():
+                    warning = "Choose save format. Note that objects saved in asy format cannot be edited graphically."
+                    replyBox = Qw.QMessageBox()
+                    replyBox.setWindowTitle('Warning')
+                    replyBox.setText(warning)
+                    replyBox.addButton("Save as .xasy", replyBox.NoRole)
+                    replyBox.addButton("Save as .asy", replyBox.YesRole)
+                    replyBox.addButton(Qw.QMessageBox.Cancel)
+                    reply = replyBox.exec()
+                    if reply == 1:
+                        saveFile = io.open(self.fileName, 'w')
+                        xf.saveFile(saveFile, self.fileItems, self.asy2psmap)
+                        saveFile.close()
+                        self.ui.statusbar.showMessage('File saved as {}'.format(self.fileName))
+                        self.fileChanged = False
+                    elif reply == 0:
+                        prefix = os.path.splitext(self.fileName)[0]
+                        xasyFilePath = prefix + '.xasy'
+                        if os.path.isfile(xasyFilePath):
+                            warning = f'"{os.path.basename(xasyFilePath)}" already exists.  Do you want to overwrite it?'
+                            reply = Qw.QMessageBox.question(self, "Same File", warning, Qw.QMessageBox.No, Qw.QMessageBox.Yes)
+                            if reply == Qw.QMessageBox.No:
+                                return
+
+                        self.actionExportXasy(xasyFilePath)
+                        self.fileName = xasyFilePath
+                        self.ui.statusbar.showMessage('File saved as {}'.format(self.fileName))
+                        self.fileChanged = False
+                    else:
+                        return
+
+                else:
+                    saveFile = io.open(self.fileName, 'w')
+                    xf.saveFile(saveFile, self.fileItems, self.asy2psmap)
+                    saveFile.close()
+                    self.fileChanged = False
+            elif file_extension == ".xasy":
+                self.actionExportXasy(self.fileName)
+                self.ui.statusbar.showMessage('File saved as {}'.format(self.fileName))
+                self.fileChanged = False
+            else:
+                print("ERROR: file extension not supported")
             self.updateScript()
+            self.updateTitle()
 
     def updateScript(self):
         for item in self.fileItems:
@@ -895,16 +1263,31 @@
                     item.setScript(item.updatedCode)
                     item.updatedCode = None
 
+    def existsXasy(self):
+        for item in self.fileItems:
+            if not isinstance(item, x2a.xasyScript):
+                return True
+        return False
+
     def actionSaveAs(self):
-        saveLocation = Qw.QFileDialog.getSaveFileName(self, 'Save File')[0]
+        initSave = os.path.splitext(str(self.fileName))[0]+'.xasy'
+        saveLocation = Qw.QFileDialog.getSaveFileName(self, 'Save File', initSave, "Xasy File (*.xasy)")[0]
         if saveLocation:
-            saveFile = io.open(saveLocation, 'w')
-            xf.saveFile(saveFile, self.fileItems, self.asy2psmap)
-            saveFile.close()
-            self.filename = saveLocation
+            _, file_extension = os.path.splitext(saveLocation)
+            if not file_extension:
+                saveLocation += '.xasy'
+                self.actionExportXasy(saveLocation)
+            elif file_extension == ".xasy":
+                self.actionExportXasy(saveLocation)
+            else:
+                print("ERROR: file extension not supported")
+            self.fileName = saveLocation
             self.updateScript()
-            
+            self.fileChanged = False
+            self.updateTitle()
+            self.populateOpenRecent(saveLocation)
 
+
     def btnQuickScreenshotOnClick(self):
         saveLocation = Qw.QFileDialog.getSaveFileName(self, 'Save Screenshot','')
         if saveLocation[0]:
@@ -913,6 +1296,9 @@
     def btnLoadFileonClick(self):
         self.actionOpen()
 
+    def btnCloseFileonClick(self):
+        self.actionClose()
+
     def btnSaveonClick(self):
         self.actionSave()
 
@@ -933,7 +1319,7 @@
             self._currentPen.setColorFromQColor(self.colorDialog.selectedColor())
             self.updateFrameDispColor()
 
-    def txtLineWithEdited(self, text):
+    def txtLineWidthEdited(self, text):
         new_val = xu.tryParse(text, float)
         if new_val is not None:
             if new_val > 0:
@@ -985,12 +1371,12 @@
 
     def mouseMoveEvent(self, mouseEvent: Qg.QMouseEvent):  # TODO: Actually refine grid snapping...
         if not self.ui.imgLabel.underMouse() and not self.mouseDown:
-            return 
+            return
 
         self.updateMouseCoordLabel()
         asyPos, canvasPos = self.getAsyCoordinates()
 
-        # add mode 
+        # add mode
         if self.addMode is not None:
             if self.addMode.active:
                 self.addMode.mouseMove(asyPos, mouseEvent)
@@ -1016,7 +1402,7 @@
             self.quickUpdate()
             return
 
-        # otherwise, in transformation 
+        # otherwise, in transformation
         if self.inMidTransformation:
             if self.currentModeStack[-1] == SelectionMode.translate:
                 newPos = canvasPos - self.savedMousePosition
@@ -1080,11 +1466,11 @@
                 self.pendingSelectedObjList.clear()
                 self.pendingSelectedObjIndex = -1
             self.quickUpdate()
-            return 
+            return
 
 
     def mouseReleaseEvent(self, mouseEvent):
-        assert isinstance(mouseEvent, Qg.QMouseEvent) 
+        assert isinstance(mouseEvent, Qg.QMouseEvent)
         if not self.mouseDown:
             return
 
@@ -1124,8 +1510,7 @@
         keyModifiers = keyModifiers | defaultModifiers
         if keyModifiers & int(Qc.Qt.ControlModifier):
             oldMag = self.magnification
-
-            factor=0.5/devicePixelRatio;
+            factor = 0.5/devicePixelRatio
             cx, cy = self.canvSize.width()*factor, self.canvSize.height()*factor
             centerPoint = Qc.QPointF(cx, cy) * self.getScrsTransform().inverted()[0]
 
@@ -1203,7 +1588,7 @@
         if self.addMode is not None:
             if self.addMode.active and isinstance(self.addMode, InplaceAddObj.AddBezierShape):
                 bezierException = True
-                
+
         if not self.ui.imgLabel.underMouse() and not bezierException:
             return
 
@@ -1252,7 +1637,15 @@
         self.addMode = None
         self.deleteAddOptions()
 
-    def editFinalized(self):
+    def editAccepted(self, obj, objIndex):
+        self.undoRedoStack.add(self.createAction(
+            EditBezierChanges(obj, objIndex,
+                    self.addMode.asyPathBackup,
+                    self.addMode.asyPath
+            )
+        ))
+        self.checkUndoRedoButtons()
+
         self.addMode.forceFinalize()
         self.removeAddMode()
         self.fileChanged = True
@@ -1260,7 +1653,10 @@
 
     def editRejected(self):
         self.addMode.resetObj()
-        self.editFinalized()
+        self.addMode.forceFinalize()
+        self.removeAddMode()
+        self.fileChanged = True
+        self.quickUpdate()
 
     def setupSelectEdit(self):
         """For Select-Edit mode. For now, if the object selected is a bezier curve, opens up a bezier editor"""
@@ -1270,12 +1666,20 @@
             # bezier path
             self.addMode = xbi.InteractiveBezierEditor(self, obj, self.currAddOptions)
             self.addMode.objectUpdated.connect(self.objectUpdated)
-            self.addMode.editAccepted.connect(self.editFinalized)
+            self.addMode.editAccepted.connect(lambda: self.editAccepted(obj, maj))
             self.addMode.editRejected.connect(self.editRejected)
             self.updateOptionWidget()
             self.currentModeStack[-1] = SelectionMode.selectEdit
             self.fileChanged = True
+        elif isinstance(obj, x2a.xasyText):
+            newText = self.setTextPrompt()
+            if newText:
+                self.drawObjects.remove(obj.generateDrawObjects(False))
+                obj.label.setText(newText)
+                self.drawObjects.append(obj.generateDrawObjects(True))
+                self.fileChanged = True
         else:
+            self.ui.statusbar.showMessage('Warning: Selected object cannot be edited')
             self.clearSelection()
         self.quickUpdate()
 
@@ -1359,7 +1763,7 @@
         # but it's much more work...
         newCenter = self.magnification * newCenter
         self.panOffset = [-newCenter.x(), newCenter.y()]
-        
+
         self.quickUpdate()
 
     def selectObject(self):
@@ -1410,7 +1814,7 @@
     def getWindowCoordinates(self):
         # assert self.ui.imgLabel.underMouse()
         return self.mapFromGlobal(Qg.QCursor.pos())
-        
+
     def refreshCanvas(self):
         if self.mainCanvas.isActive():
             self.mainCanvas.end()
@@ -1430,10 +1834,12 @@
         self.coordLabel.setText('{0:.2f}, {1:.2f}    '.format(nx, ny))
 
     def quickUpdate(self):
+        # TODO: Some documentation here would be nice since this is one of the
+        # main functions that gets called everywhere.
         self.updateMouseCoordLabel()
         self.refreshCanvas()
 
-        self.preDraw(self.mainCanvas)
+        self.preDraw(self.mainCanvas) # coordinates/background
         self.quickDraw()
 
         self.mainCanvas.end()
@@ -1440,6 +1846,8 @@
         self.postDraw()
         self.updateScreen()
 
+        self.updateTitle()
+
     def quickDraw(self):
         assert self.isReady()
         dpi = self.magnification * self.dpi
@@ -1466,7 +1874,7 @@
             if self.pendingSelectedObjList:
                 maj, minor = self.pendingSelectedObjList[self.pendingSelectedObjIndex]
                 self.drawObjects[maj][minor].draw(canvas=self.mainCanvas, dpi=dpi)
-            # and apply the preview too... 
+            # and apply the preview too...
             elif activeItem is not None:
                 if self.useGlobalCoords:
                     activeItem.draw(self.newTransform, canvas=self.mainCanvas, dpi=dpi)
@@ -1474,6 +1882,17 @@
                     activeItem.draw(self.newTransform, applyReverse=True, canvas=self.mainCanvas, dpi=dpi)
                 activeItem = None
 
+    def updateTitle(self):
+        # TODO: Undo redo doesn't update appropriately. Have to find a fix for this.
+        title = ''
+        if self.fileName:
+            title += os.path.basename(self.fileName)
+        else:
+            title += "[Not Saved]"
+        if self.fileChanged:
+            title += ' *'
+        self.setWindowTitle(title)
+
     def updateScreen(self):
         self.finalPixmap = Qg.QPixmap(self.canvSize)
         self.finalPixmap.setDevicePixelRatio(devicePixelRatio)
@@ -1502,6 +1921,7 @@
         for x in np.arange(0, 2 * x_range + 1, majorGrid):  # have to do
             # this in two stages...
             preCanvas.setPen(minorGridCol)
+            self.makePenCosmetic(preCanvas)
             for xMinor in range(1, minorGridCount + 1):
                 xCoord = x + ((xMinor / (minorGridCount + 1)) * majorGrid)
                 preCanvas.drawLine(Qc.QLine(xCoord, -9999, xCoord, 9999))
@@ -1509,6 +1929,7 @@
 
         for y in np.arange(0, 2 * y_range + 1, majorGrid):
             preCanvas.setPen(minorGridCol)
+            self.makePenCosmetic(preCanvas)
             for yMinor in range(1, minorGridCount + 1):
                 yCoord = y + ((yMinor / (minorGridCount + 1)) * majorGrid)
                 preCanvas.drawLine(Qc.QLine(-9999, yCoord, 9999, yCoord))
@@ -1515,11 +1936,13 @@
                 preCanvas.drawLine(Qc.QLine(-9999, -yCoord, 9999, -yCoord))
 
             preCanvas.setPen(majorGridCol)
+            self.makePenCosmetic(preCanvas)
             preCanvas.drawLine(Qc.QLine(-9999, y, 9999, y))
             preCanvas.drawLine(Qc.QLine(-9999, -y, 9999, -y))
 
         for x in np.arange(0, 2 * x_range + 1, majorGrid):
             preCanvas.setPen(majorGridCol)
+            self.makePenCosmetic(preCanvas)
             preCanvas.drawLine(Qc.QLine(x, -9999, x, 9999))
             preCanvas.drawLine(Qc.QLine(-x, -9999, -x, 9999))
 
@@ -1568,6 +1991,7 @@
 
         if self.drawAxes:
             preCanvas.setPen(Qc.Qt.gray)
+            self.makePenCosmetic(preCanvas)
             preCanvas.drawLine(Qc.QLine(-9999, 0, 9999, 0))
             preCanvas.drawLine(Qc.QLine(0, -9999, 0, 9999))
 
@@ -1590,13 +2014,14 @@
                     painter.setPen(self.currentPen.toQPen())
                     painter.drawPath(self.addMode.getPreview())
                 self.addMode.postDrawPreview(painter)
-                
 
+
     def drawTransformPreview(self, painter):
         if self.currentBoundingBox is not None and self.currentlySelectedObj['selectedIndex'] is not None:
             painter.save()
             maj, minor = self.currentlySelectedObj['selectedIndex']
             selObj = self.drawObjects[maj][minor]
+            self.makePenCosmetic(painter)
             if not self.useGlobalCoords:
                 painter.save()
                 painter.setTransform(
@@ -1621,6 +2046,7 @@
         with Qg.QPainter(self.postCanvasPixmap) as postCanvas:
             postCanvas.setRenderHints(self.mainCanvas.renderHints())
             postCanvas.setTransform(self.getScrsTransform())
+            # self.makePenCosmetic(postCanvas)
 
             self.drawTransformPreview(postCanvas)
 
@@ -1627,7 +2053,7 @@
             if self.pendingSelectedObjList:
                 maj, minor = self.pendingSelectedObjList[self.pendingSelectedObjIndex]
                 postCanvas.drawRect(self.drawObjects[maj][minor].boundingBox)
-                
+
             self.drawAddModePreview(postCanvas)
 
             if self.customAnchor is not None and self.anchorMode == AnchorMode.customAnchor:
@@ -1657,11 +2083,29 @@
             activeBtn = self.ui.btnDeleteMode
         elif self.currentModeStack[-1] == SelectionMode.selectEdit:
             activeBtn = self.ui.btnSelectEdit
+        elif self.currentModeStack[-1] == SelectionMode.openPoly:
+            activeBtn = self.ui.btnOpenPoly
+        elif self.currentModeStack[-1] == SelectionMode.closedPoly:
+            activeBtn = self.ui.btnClosedPoly
+        elif self.currentModeStack[-1] == SelectionMode.openCurve:
+            activeBtn = self.ui.btnOpenCurve
+        elif self.currentModeStack[-1] == SelectionMode.closedCurve:
+            activeBtn = self.ui.btnClosedCurve
+        elif self.currentModeStack[-1] == SelectionMode.addPoly:
+            activeBtn = self.ui.btnAddPoly
+        elif self.currentModeStack[-1] == SelectionMode.addCircle:
+            activeBtn = self.ui.btnAddCircle
+        elif self.currentModeStack[-1] == SelectionMode.addLabel:
+            activeBtn = self.ui.btnAddLabel
+        elif self.currentModeStack[-1] == SelectionMode.addFreehand:
+            activeBtn = self.ui.btnAddFreehand
         else:
             activeBtn = None
 
-        
+
         disableFill = isinstance(self.addMode, InplaceAddObj.AddBezierShape) and not self.currAddOptions['closedPath']
+        if isinstance(self.addMode, xbi.InteractiveBezierEditor):
+            disableFill = disableFill or not (self.addMode.obj.path.nodeSet[-1] == "cycle")
         self.ui.btnFill.setEnabled(not disableFill)
         if disableFill and self.ui.btnFill.isEnabled():
             self.ui.btnFill.setChecked(not disableFill)
@@ -1670,6 +2114,14 @@
         for button in self.modeButtons:
             button.setChecked(button is activeBtn)
 
+        if activeBtn in [self.ui.btnDeleteMode,self.ui.btnSelectEdit]:
+            self.ui.btnAlignX.setEnabled(False)
+            self.ui.btnAlignY.setEnabled(False)
+        else:
+            self.ui.btnAlignX.setEnabled(True)
+            self.ui.btnAlignY.setEnabled(True)
+
+
     def updateChecks(self):
         self.removeAddMode()
         self.updateModeBtnsOnly()
@@ -1676,16 +2128,22 @@
         self.quickUpdate()
 
     def btnAlignXOnClick(self, checked):
-        self.lockY = checked
-        if self.lockX:
-            self.lockX = False
-            self.ui.btnAlignY.setChecked(False)
+        if self.currentModeStack[0] in [SelectionMode.selectEdit,SelectionMode.delete]:
+            self.ui.btnAlignX.setChecked(False)
+        else:
+            self.lockY = checked
+            if self.lockX:
+                self.lockX = False
+                self.ui.btnAlignY.setChecked(False)
 
     def btnAlignYOnClick(self, checked):
-        self.lockX = checked
-        if self.lockY:
-            self.lockY = False
-            self.ui.btnAlignX.setChecked(False)
+        if self.currentModeStack[0] in [SelectionMode.selectEdit,SelectionMode.delete]:
+            self.ui.btnAlignY.setChecked(False)
+        else:
+            self.lockX = checked
+            if self.lockY:
+                self.lockY = False
+                self.ui.btnAlignX.setChecked(False)
 
     def btnAnchorModeOnClick(self):
         if self.currentModeStack[-1] != SelectionMode.setAnchor:
@@ -1704,22 +2162,31 @@
         self.updateChecks()
 
     def btnRotateOnClick(self):
-        self.currentModeStack = [SelectionMode.rotate]
-        self.ui.statusbar.showMessage('Rotate mode')
-        self.clearSelection()
-        self.updateChecks()
+        if self.currentModeStack[-1] != SelectionMode.rotate:
+            self.currentModeStack = [SelectionMode.rotate]
+            self.ui.statusbar.showMessage('Rotate mode')
+            self.clearSelection()
+            self.updateChecks()
+        else:
+            self.btnTranslateonClick()
 
     def btnScaleOnClick(self):
-        self.currentModeStack = [SelectionMode.scale]
-        self.ui.statusbar.showMessage('Scale mode')
-        self.clearSelection()
-        self.updateChecks()
+        if self.currentModeStack[-1] != SelectionMode.scale:
+            self.currentModeStack = [SelectionMode.scale]
+            self.ui.statusbar.showMessage('Scale mode')
+            self.clearSelection()
+            self.updateChecks()
+        else:
+            self.btnTranslateonClick()
 
     def btnPanOnClick(self):
-        self.currentModeStack = [SelectionMode.pan]
-        self.ui.statusbar.showMessage('Pan mode')
-        self.clearSelection()
-        self.updateChecks()
+        if self.currentModeStack[-1] != SelectionMode.pan:
+            self.currentModeStack = [SelectionMode.pan]
+            self.ui.statusbar.showMessage('Pan mode')
+            self.clearSelection()
+            self.updateChecks()
+        else:
+            self.btnTranslateonClick()
 
     def btnWorldCoordsOnClick(self, checked):
         self.useGlobalCoords = checked
@@ -1754,24 +2221,26 @@
         self.quickUpdate()
 
     def btnLoadEditorOnClick(self):
+        pathToFile = os.path.splitext(self.fileName)[0]+'.asy'
         if self.fileChanged:
             save = "Save current file?"
             reply = Qw.QMessageBox.question(self, 'Message', save, Qw.QMessageBox.Yes,
                                             Qw.QMessageBox.No)
             if reply == Qw.QMessageBox.Yes:
-                self.actionSave()
-                
-        subprocess.Popen(args=self.getExternalEditor(asypath=self.filename));
+                self.actionExport(pathToFile)
 
+        subprocess.run(args=self.getExternalEditor(asypath=pathToFile));
+        self.loadFile(pathToFile)
+
     def btnAddCodeOnClick(self):
         header = """
-// xasy object created at $time 
+// xasy object created at $time
 // Object Number: $uid
-// This header is automatically generated by xasy. 
+// This header is automatically generated by xasy.
 // Your code here
 """
         header = string.Template(header).substitute(time=str(datetime.datetime.now()), uid=str(self.globalObjectCounter))
-                
+
         with tempfile.TemporaryDirectory() as tmpdir:
             newPath = os.path.join(tmpdir, 'tmpcode.asy')
             f = io.open(newPath, 'w')
@@ -1791,6 +2260,7 @@
         self.asyfyCanvas()
 
         self.globalObjectCounter = self.globalObjectCounter + 1
+
     def softDeleteObj(self, objKey):
         maj, minor = objKey
         drawObj = self.drawObjects[maj][minor]
@@ -1869,7 +2339,7 @@
             s = editor.split()
             rawExternalEditor = s[0]
             rawExtEditorArgs = s[1:]+["$asypath"]
-            
+
         execEditor = [rawExternalEditor]
 
         for arg in rawExtEditorArgs:
@@ -1881,7 +2351,9 @@
     def loadFile(self, name):
         filename = os.path.abspath(name)
         if not os.path.isfile(filename):
-            filename = filename + '.asy'
+            parts = os.path.splitext(filename)
+            if parts[1] == '':
+                filename = parts[0] + '.asy'
 
         if not os.path.isfile(filename):
             self.ui.statusbar.showMessage('File {0} not found'.format(filename))
@@ -1888,27 +2360,28 @@
             return
 
         self.ui.statusbar.showMessage('Load {0}'.format(filename))
-        self.filename = filename
-        self.currDir = os.path.dirname(self.filename)
+        self.fileName = filename
+        self.asyFileName = filename
+        self.currDir = os.path.dirname(self.fileName)
 
         self.erase()
 
-        f = open(self.filename, 'rt')
+        f = open(self.fileName, 'rt')
         try:
             rawFileStr = f.read()
         except IOError:
             Qw.QMessageBox.critical(self, self.strings.fileOpenFailed, self.strings.fileOpenFailedText)
         else:
-            rawText, transfDict, maxKey = xf.extractTransformsFromFile(rawFileStr)
+            rawText, transfDict = xf.extractTransformsFromFile(rawFileStr)
             item = x2a.xasyScript(canvas=self.xasyDrawObj, engine=self.asyEngine, transfKeyMap=transfDict)
 
             item.setScript(rawText)
             self.fileItems.append(item)
-            self.asyfyCanvas(True)
+            self.asyfyCanvas(force=True)
 
-            maxKey2 = item.getMaxKeyCounter()
+            self.globalObjectCounter = item.maxKey+1
             self.asy2psmap = item.asy2psmap
-            self.globalObjectCounter = max(maxKey + 1, maxKey2)
+
         finally:
             f.close()
 
@@ -1916,3 +2389,37 @@
         self.itemCount = 0
         for item in self.fileItems:
             self.drawObjects.append(item.generateDrawObjects(forceUpdate))
+
+    def makePenCosmetic(self, painter):
+        localPen = painter.pen()
+        localPen.setCosmetic(True)
+        painter.setPen(localPen)
+
+    def copyItem(self):
+        self.selectOnHover()
+        if self.currentlySelectedObj['selectedIndex'] is not None:
+            maj, minor = self.currentlySelectedObj['selectedIndex']
+            if isinstance(self.fileItems[maj],x2a.xasyShape) or isinstance(self.fileItems[maj],x2a.xasyText):
+                self.copiedObject = self.fileItems[maj].copy()
+            else:
+                self.ui.statusbar.showMessage('Copying not supported with current item type')
+        else:
+            self.ui.statusbar.showMessage('No object selected to copy')
+            self.copiedObject = None
+        self.clearSelection()
+
+    def pasteItem(self):
+        if hasattr(self, 'copiedObject') and not self.copiedObject is None:
+            self.copiedObject = self.copiedObject.copy()
+            self.addInPlace(self.copiedObject)
+            mousePos = self.getWindowCoordinates() - self.copiedObject.path.toQPainterPath().boundingRect().center() - (Qc.QPointF(self.canvSize.width(), self.canvSize.height()) + Qc.QPointF(62, 201))/2 #I don't really know what that last constant is? Is it the size of the framing?
+            newTransform = Qg.QTransform.fromTranslate(mousePos.x(), mousePos.y())
+            self.currentlySelectedObj['selectedIndex'] = (self.globalObjectCounter - 1,0)
+            self.currentlySelectedObj['key'],  self.currentlySelectedObj['allSameKey'] = self.selectObjectSet()
+            newTransform = x2a.asyTransform.fromQTransform(newTransform)
+            objKey = self.currentlySelectedObj['selectedIndex']
+            self.addTransformationChanges(objKey, newTransform, not self.useGlobalCoords)
+            self.transformObject(objKey, newTransform, not self.useGlobalCoords)
+            self.quickUpdate()
+        else:
+            self.ui.statusbar.showMessage('No object to paste')

Modified: trunk/Master/texmf-dist/asymptote/GUI/configs/xasyconfig.cson
===================================================================
--- trunk/Master/texmf-dist/asymptote/GUI/configs/xasyconfig.cson	2022-02-27 23:39:53 UTC (rev 62264)
+++ trunk/Master/texmf-dist/asymptote/GUI/configs/xasyconfig.cson	2022-02-27 23:41:11 UTC (rev 62265)
@@ -45,6 +45,9 @@
 gridMajorAxesSpacing: 5
 gridMinorAxesCount: 9
 
+# Number of pixels per bp in 3D rendered bitmaps
+renderDensity: 2
+
 # Magnification Settings
 minimumMagnification: 0.01
 maximumMagnification: 100

Modified: trunk/Master/texmf-dist/asymptote/GUI/configs/xasykeymap.cson
===================================================================
--- trunk/Master/texmf-dist/asymptote/GUI/configs/xasykeymap.cson	2022-02-27 23:39:53 UTC (rev 62264)
+++ trunk/Master/texmf-dist/asymptote/GUI/configs/xasykeymap.cson	2022-02-27 23:41:11 UTC (rev 62265)
@@ -23,4 +23,11 @@
 scrollRight: 'Shift+Right'
 
 zoomIn: 'Ctrl+Up'
-zoomOut: 'Ctrl+Down'
\ No newline at end of file
+zoomOut: 'Ctrl+Down'
+
+open: 'Ctrl+O'
+save: 'Ctrl+S'
+export: 'Ctrl+E'
+
+copy: 'Ctrl+C'
+paste: 'Ctrl+V'

Deleted: trunk/Master/texmf-dist/asymptote/GUI/icons_rc.py
===================================================================
--- trunk/Master/texmf-dist/asymptote/GUI/icons_rc.py	2022-02-27 23:39:53 UTC (rev 62264)
+++ trunk/Master/texmf-dist/asymptote/GUI/icons_rc.py	2022-02-27 23:41:11 UTC (rev 62265)
@@ -1,2721 +0,0 @@
-# -*- coding: utf-8 -*-
-
-# Resource object code
-#
-# Created by: The Resource Compiler for PyQt5 (Qt v5.12.5)
-#
-# WARNING! All changes made in this file will be lost!
-
-from PyQt5 import QtCore
-
-qt_resource_data = b"\
-\x00\x00\x04\xa2\
-\x3c\
-\x3f\x78\x6d\x6c\x20\x76\x65\x72\x73\x69\x6f\x6e\x3d\x27\x31\x2e\
-\x30\x27\x20\x65\x6e\x63\x6f\x64\x69\x6e\x67\x3d\x27\x55\x54\x46\
-\x2d\x38\x27\x3f\x3e\x0a\x3c\x21\x2d\x2d\x20\x54\x68\x69\x73\x20\
-\x66\x69\x6c\x65\x20\x77\x61\x73\x20\x67\x65\x6e\x65\x72\x61\x74\
-\x65\x64\x20\x62\x79\x20\x64\x76\x69\x73\x76\x67\x6d\x20\x32\x2e\
-\x38\x20\x2d\x2d\x3e\x0a\x3c\x73\x76\x67\x20\x76\x65\x72\x73\x69\
-\x6f\x6e\x3d\x27\x31\x2e\x31\x27\x20\x78\x6d\x6c\x6e\x73\x3d\x27\
-\x68\x74\x74\x70\x3a\x2f\x2f\x77\x77\x77\x2e\x77\x33\x2e\x6f\x72\
-\x67\x2f\x32\x30\x30\x30\x2f\x73\x76\x67\x27\x20\x78\x6d\x6c\x6e\
-\x73\x3a\x78\x6c\x69\x6e\x6b\x3d\x27\x68\x74\x74\x70\x3a\x2f\x2f\
-\x77\x77\x77\x2e\x77\x33\x2e\x6f\x72\x67\x2f\x31\x39\x39\x39\x2f\
-\x78\x6c\x69\x6e\x6b\x27\x20\x77\x69\x64\x74\x68\x3d\x27\x36\x33\
-\x2e\x39\x39\x39\x36\x70\x74\x27\x20\x68\x65\x69\x67\x68\x74\x3d\
-\x27\x36\x33\x2e\x39\x39\x39\x37\x70\x74\x27\x20\x76\x69\x65\x77\
-\x42\x6f\x78\x3d\x27\x35\x36\x2e\x34\x30\x39\x34\x20\x35\x33\x2e\
-\x38\x35\x38\x33\x20\x36\x33\x2e\x39\x39\x39\x36\x20\x36\x33\x2e\
-\x39\x39\x39\x37\x27\x3e\x0a\x3c\x67\x20\x69\x64\x3d\x27\x70\x61\
-\x67\x65\x31\x27\x3e\x0a\x3c\x67\x20\x74\x72\x61\x6e\x73\x66\x6f\
-\x72\x6d\x3d\x27\x6d\x61\x74\x72\x69\x78\x28\x30\x2e\x39\x39\x36\
-\x32\x36\x34\x20\x30\x20\x30\x20\x30\x2e\x39\x39\x36\x32\x36\x34\
-\x20\x35\x38\x2e\x34\x36\x36\x39\x20\x31\x31\x37\x2e\x38\x35\x38\
-\x29\x27\x3e\x0a\x3c\x70\x61\x74\x68\x20\x64\x3d\x27\x4d\x20\x33\
-\x2e\x39\x35\x37\x33\x35\x20\x2d\x33\x32\x2e\x31\x32\x43\x20\x34\
-\x2e\x31\x35\x35\x35\x36\x20\x2d\x33\x39\x2e\x32\x37\x34\x35\x20\
-\x36\x2e\x39\x38\x34\x37\x33\x20\x2d\x34\x36\x2e\x31\x30\x34\x37\
-\x20\x31\x31\x2e\x39\x30\x33\x36\x20\x2d\x35\x31\x2e\x33\x30\x33\
-\x39\x43\x20\x32\x37\x2e\x34\x34\x31\x31\x20\x2d\x36\x37\x2e\x37\
-\x32\x36\x39\x20\x35\x33\x2e\x33\x30\x32\x31\x20\x2d\x36\x31\x2e\
-\x35\x34\x30\x35\x20\x35\x36\x2e\x31\x35\x32\x33\x20\x2d\x34\x32\
-\x2e\x35\x30\x32\x32\x43\x20\x35\x37\x2e\x36\x32\x37\x20\x2d\x33\
-\x32\x2e\x36\x35\x31\x39\x20\x35\x30\x2e\x35\x38\x35\x36\x20\x2d\
-\x32\x33\x2e\x35\x36\x32\x31\x20\x34\x30\x2e\x36\x37\x39\x34\x20\
-\x2d\x32\x32\x2e\x35\x32\x38\x31\x27\x20\x66\x69\x6c\x6c\x3d\x27\
-\x6e\x6f\x6e\x65\x27\x20\x73\x74\x72\x6f\x6b\x65\x3d\x27\x23\x30\
-\x30\x30\x30\x30\x30\x27\x20\x73\x74\x72\x6f\x6b\x65\x2d\x6c\x69\
-\x6e\x65\x63\x61\x70\x3d\x27\x72\x6f\x75\x6e\x64\x27\x20\x73\x74\
-\x72\x6f\x6b\x65\x2d\x6c\x69\x6e\x65\x6a\x6f\x69\x6e\x3d\x27\x72\
-\x6f\x75\x6e\x64\x27\x20\x73\x74\x72\x6f\x6b\x65\x2d\x6d\x69\x74\
-\x65\x72\x6c\x69\x6d\x69\x74\x3d\x27\x31\x30\x2e\x30\x33\x37\x35\
-\x27\x20\x73\x74\x72\x6f\x6b\x65\x2d\x77\x69\x64\x74\x68\x3d\x27\
-\x32\x2e\x35\x30\x39\x33\x37\x27\x2f\x3e\x0a\x3c\x2f\x67\x3e\x0a\
-\x3c\x67\x20\x74\x72\x61\x6e\x73\x66\x6f\x72\x6d\x3d\x27\x6d\x61\
-\x74\x72\x69\x78\x28\x30\x2e\x39\x39\x36\x32\x36\x34\x20\x30\x20\
-\x30\x20\x30\x2e\x39\x39\x36\x32\x36\x34\x20\x35\x38\x2e\x34\x36\
-\x36\x39\x20\x31\x31\x37\x2e\x38\x35\x38\x29\x27\x3e\x0a\x3c\x63\
-\x69\x72\x63\x6c\x65\x20\x63\x78\x3d\x27\x33\x2e\x39\x35\x37\x33\
-\x35\x27\x20\x63\x79\x3d\x27\x2d\x33\x32\x2e\x31\x32\x27\x20\x66\
-\x69\x6c\x6c\x3d\x27\x23\x30\x30\x30\x30\x30\x30\x27\x20\x72\x3d\
-\x27\x36\x2e\x30\x32\x32\x35\x27\x2f\x3e\x0a\x3c\x2f\x67\x3e\x0a\
-\x3c\x67\x20\x74\x72\x61\x6e\x73\x66\x6f\x72\x6d\x3d\x27\x6d\x61\
-\x74\x72\x69\x78\x28\x30\x2e\x39\x39\x36\x32\x36\x34\x20\x30\x20\
-\x30\x20\x30\x2e\x39\x39\x36\x32\x36\x34\x20\x35\x38\x2e\x34\x36\
-\x36\x39\x20\x31\x31\x37\x2e\x38\x35\x38\x29\x27\x3e\x0a\x3c\x63\
-\x69\x72\x63\x6c\x65\x20\x63\x78\x3d\x27\x31\x31\x2e\x39\x30\x33\
-\x36\x27\x20\x63\x79\x3d\x27\x2d\x35\x31\x2e\x33\x30\x33\x39\x27\
-\x20\x66\x69\x6c\x6c\x3d\x27\x23\x30\x30\x30\x30\x30\x30\x27\x20\
-\x72\x3d\x27\x36\x2e\x30\x32\x32\x35\x27\x2f\x3e\x0a\x3c\x2f\x67\
-\x3e\x0a\x3c\x67\x20\x74\x72\x61\x6e\x73\x66\x6f\x72\x6d\x3d\x27\
-\x6d\x61\x74\x72\x69\x78\x28\x30\x2e\x39\x39\x36\x32\x36\x34\x20\
-\x30\x20\x30\x20\x30\x2e\x39\x39\x36\x32\x36\x34\x20\x35\x38\x2e\
-\x34\x36\x36\x39\x20\x31\x31\x37\x2e\x38\x35\x38\x29\x27\x3e\x0a\
-\x3c\x63\x69\x72\x63\x6c\x65\x20\x63\x78\x3d\x27\x35\x36\x2e\x31\
-\x35\x32\x33\x27\x20\x63\x79\x3d\x27\x2d\x34\x32\x2e\x35\x30\x32\
-\x32\x27\x20\x66\x69\x6c\x6c\x3d\x27\x23\x30\x30\x30\x30\x30\x30\
-\x27\x20\x72\x3d\x27\x36\x2e\x30\x32\x32\x35\x27\x2f\x3e\x0a\x3c\
-\x2f\x67\x3e\x0a\x3c\x67\x20\x74\x72\x61\x6e\x73\x66\x6f\x72\x6d\
-\x3d\x27\x6d\x61\x74\x72\x69\x78\x28\x30\x2e\x39\x39\x36\x32\x36\
-\x34\x20\x30\x20\x30\x20\x30\x2e\x39\x39\x36\x32\x36\x34\x20\x35\
-\x38\x2e\x34\x36\x36\x39\x20\x31\x31\x37\x2e\x38\x35\x38\x29\x27\
-\x3e\x0a\x3c\x63\x69\x72\x63\x6c\x65\x20\x63\x78\x3d\x27\x34\x30\
-\x2e\x36\x37\x39\x34\x27\x20\x63\x79\x3d\x27\x2d\x32\x32\x2e\x35\
-\x32\x38\x31\x27\x20\x66\x69\x6c\x6c\x3d\x27\x23\x30\x30\x30\x30\
-\x30\x30\x27\x20\x72\x3d\x27\x36\x2e\x30\x32\x32\x35\x27\x2f\x3e\
-\x0a\x3c\x2f\x67\x3e\x0a\x3c\x2f\x67\x3e\x0a\x3c\x2f\x73\x76\x67\
-\x3e\
-\x00\x00\x03\x0c\
-\x3c\
-\x3f\x78\x6d\x6c\x20\x76\x65\x72\x73\x69\x6f\x6e\x3d\x22\x31\x2e\
-\x30\x22\x20\x65\x6e\x63\x6f\x64\x69\x6e\x67\x3d\x22\x75\x74\x66\
-\x2d\x38\x22\x3f\x3e\x0d\x0a\x3c\x21\x2d\x2d\x20\x47\x65\x6e\x65\
-\x72\x61\x74\x6f\x72\x3a\x20\x41\x64\x6f\x62\x65\x20\x49\x6c\x6c\
-\x75\x73\x74\x72\x61\x74\x6f\x72\x20\x31\x38\x2e\x31\x2e\x30\x2c\
-\x20\x53\x56\x47\x20\x45\x78\x70\x6f\x72\x74\x20\x50\x6c\x75\x67\
-\x2d\x49\x6e\x20\x2e\x20\x53\x56\x47\x20\x56\x65\x72\x73\x69\x6f\
-\x6e\x3a\x20\x36\x2e\x30\x30\x20\x42\x75\x69\x6c\x64\x20\x30\x29\
-\x20\x20\x2d\x2d\x3e\x0d\x0a\x3c\x21\x44\x4f\x43\x54\x59\x50\x45\
-\x20\x73\x76\x67\x20\x50\x55\x42\x4c\x49\x43\x20\x22\x2d\x2f\x2f\
-\x57\x33\x43\x2f\x2f\x44\x54\x44\x20\x53\x56\x47\x20\x31\x2e\x31\
-\x2f\x2f\x45\x4e\x22\x20\x22\x68\x74\x74\x70\x3a\x2f\x2f\x77\x77\
-\x77\x2e\x77\x33\x2e\x6f\x72\x67\x2f\x47\x72\x61\x70\x68\x69\x63\
-\x73\x2f\x53\x56\x47\x2f\x31\x2e\x31\x2f\x44\x54\x44\x2f\x73\x76\
-\x67\x31\x31\x2e\x64\x74\x64\x22\x3e\x0d\x0a\x3c\x73\x76\x67\x20\
-\x76\x65\x72\x73\x69\x6f\x6e\x3d\x22\x31\x2e\x31\x22\x20\x69\x64\
-\x3d\x22\x43\x68\x65\x63\x6b\x22\x20\x78\x6d\x6c\x6e\x73\x3d\x22\
-\x68\x74\x74\x70\x3a\x2f\x2f\x77\x77\x77\x2e\x77\x33\x2e\x6f\x72\
-\x67\x2f\x32\x30\x30\x30\x2f\x73\x76\x67\x22\x20\x78\x6d\x6c\x6e\
-\x73\x3a\x78\x6c\x69\x6e\x6b\x3d\x22\x68\x74\x74\x70\x3a\x2f\x2f\
-\x77\x77\x77\x2e\x77\x33\x2e\x6f\x72\x67\x2f\x31\x39\x39\x39\x2f\
-\x78\x6c\x69\x6e\x6b\x22\x20\x78\x3d\x22\x30\x70\x78\x22\x20\x79\
-\x3d\x22\x30\x70\x78\x22\x0d\x0a\x09\x20\x76\x69\x65\x77\x42\x6f\
-\x78\x3d\x22\x30\x20\x30\x20\x32\x30\x20\x32\x30\x22\x20\x65\x6e\
-\x61\x62\x6c\x65\x2d\x62\x61\x63\x6b\x67\x72\x6f\x75\x6e\x64\x3d\
-\x22\x6e\x65\x77\x20\x30\x20\x30\x20\x32\x30\x20\x32\x30\x22\x20\
-\x78\x6d\x6c\x3a\x73\x70\x61\x63\x65\x3d\x22\x70\x72\x65\x73\x65\
-\x72\x76\x65\x22\x3e\x0d\x0a\x3c\x70\x61\x74\x68\x20\x64\x3d\x22\
-\x4d\x38\x2e\x32\x39\x34\x2c\x31\x36\x2e\x39\x39\x38\x63\x2d\x30\
-\x2e\x34\x33\x35\x2c\x30\x2d\x30\x2e\x38\x34\x37\x2d\x30\x2e\x32\
-\x30\x33\x2d\x31\x2e\x31\x31\x31\x2d\x30\x2e\x35\x35\x33\x4c\x33\
-\x2e\x36\x31\x2c\x31\x31\x2e\x37\x32\x34\x63\x2d\x30\x2e\x34\x36\
-\x35\x2d\x30\x2e\x36\x31\x33\x2d\x30\x2e\x33\x34\x34\x2d\x31\x2e\
-\x34\x38\x36\x2c\x30\x2e\x32\x37\x2d\x31\x2e\x39\x35\x31\x0d\x0a\
-\x09\x63\x30\x2e\x36\x31\x35\x2d\x30\x2e\x34\x36\x37\x2c\x31\x2e\
-\x34\x38\x38\x2d\x30\x2e\x33\x34\x34\x2c\x31\x2e\x39\x35\x33\x2c\
-\x30\x2e\x32\x37\x6c\x32\x2e\x33\x35\x31\x2c\x33\x2e\x31\x30\x34\
-\x6c\x35\x2e\x39\x31\x31\x2d\x39\x2e\x34\x39\x32\x63\x30\x2e\x34\
-\x30\x37\x2d\x30\x2e\x36\x35\x32\x2c\x31\x2e\x32\x36\x37\x2d\x30\
-\x2e\x38\x35\x32\x2c\x31\x2e\x39\x32\x31\x2d\x30\x2e\x34\x34\x35\
-\x0d\x0a\x09\x63\x30\x2e\x36\x35\x33\x2c\x30\x2e\x34\x30\x36\x2c\
-\x30\x2e\x38\x35\x34\x2c\x31\x2e\x32\x36\x36\x2c\x30\x2e\x34\x34\
-\x36\x2c\x31\x2e\x39\x32\x4c\x39\x2e\x34\x37\x38\x2c\x31\x36\x2e\
-\x33\x34\x63\x2d\x30\x2e\x32\x34\x32\x2c\x30\x2e\x33\x39\x31\x2d\
-\x30\x2e\x36\x36\x31\x2c\x30\x2e\x36\x33\x35\x2d\x31\x2e\x31\x32\
-\x2c\x30\x2e\x36\x35\x36\x43\x38\x2e\x33\x33\x36\x2c\x31\x36\x2e\
-\x39\x39\x38\x2c\x38\x2e\x33\x31\x36\x2c\x31\x36\x2e\x39\x39\x38\
-\x2c\x38\x2e\x32\x39\x34\x2c\x31\x36\x2e\x39\x39\x38\x7a\x22\x2f\
-\x3e\x0d\x0a\x3c\x2f\x73\x76\x67\x3e\x0d\x0a\
-\x00\x00\x03\xc4\
-\x3c\
-\x3f\x78\x6d\x6c\x20\x76\x65\x72\x73\x69\x6f\x6e\x3d\x22\x31\x2e\
-\x30\x22\x20\x65\x6e\x63\x6f\x64\x69\x6e\x67\x3d\x22\x75\x74\x66\
-\x2d\x38\x22\x3f\x3e\x0d\x0a\x3c\x21\x2d\x2d\x20\x47\x65\x6e\x65\
-\x72\x61\x74\x6f\x72\x3a\x20\x41\x64\x6f\x62\x65\x20\x49\x6c\x6c\
-\x75\x73\x74\x72\x61\x74\x6f\x72\x20\x31\x38\x2e\x31\x2e\x30\x2c\
-\x20\x53\x56\x47\x20\x45\x78\x70\x6f\x72\x74\x20\x50\x6c\x75\x67\
-\x2d\x49\x6e\x20\x2e\x20\x53\x56\x47\x20\x56\x65\x72\x73\x69\x6f\
-\x6e\x3a\x20\x36\x2e\x30\x30\x20\x42\x75\x69\x6c\x64\x20\x30\x29\
-\x20\x20\x2d\x2d\x3e\x0d\x0a\x3c\x21\x44\x4f\x43\x54\x59\x50\x45\
-\x20\x73\x76\x67\x20\x50\x55\x42\x4c\x49\x43\x20\x22\x2d\x2f\x2f\
-\x57\x33\x43\x2f\x2f\x44\x54\x44\x20\x53\x56\x47\x20\x31\x2e\x31\
-\x2f\x2f\x45\x4e\x22\x20\x22\x68\x74\x74\x70\x3a\x2f\x2f\x77\x77\
-\x77\x2e\x77\x33\x2e\x6f\x72\x67\x2f\x47\x72\x61\x70\x68\x69\x63\
-\x73\x2f\x53\x56\x47\x2f\x31\x2e\x31\x2f\x44\x54\x44\x2f\x73\x76\
-\x67\x31\x31\x2e\x64\x74\x64\x22\x3e\x0d\x0a\x3c\x73\x76\x67\x20\
-\x76\x65\x72\x73\x69\x6f\x6e\x3d\x22\x31\x2e\x31\x22\x20\x69\x64\
-\x3d\x22\x4d\x61\x67\x6e\x69\x66\x79\x69\x6e\x67\x5f\x67\x6c\x61\
-\x73\x73\x22\x20\x78\x6d\x6c\x6e\x73\x3d\x22\x68\x74\x74\x70\x3a\
-\x2f\x2f\x77\x77\x77\x2e\x77\x33\x2e\x6f\x72\x67\x2f\x32\x30\x30\
-\x30\x2f\x73\x76\x67\x22\x20\x78\x6d\x6c\x6e\x73\x3a\x78\x6c\x69\
-\x6e\x6b\x3d\x22\x68\x74\x74\x70\x3a\x2f\x2f\x77\x77\x77\x2e\x77\
-\x33\x2e\x6f\x72\x67\x2f\x31\x39\x39\x39\x2f\x78\x6c\x69\x6e\x6b\
-\x22\x20\x78\x3d\x22\x30\x70\x78\x22\x0d\x0a\x09\x20\x79\x3d\x22\
-\x30\x70\x78\x22\x20\x76\x69\x65\x77\x42\x6f\x78\x3d\x22\x30\x20\
-\x30\x20\x35\x31\x32\x20\x35\x31\x32\x22\x20\x65\x6e\x61\x62\x6c\
-\x65\x2d\x62\x61\x63\x6b\x67\x72\x6f\x75\x6e\x64\x3d\x22\x6e\x65\
-\x77\x20\x30\x20\x30\x20\x35\x31\x32\x20\x35\x31\x32\x22\x20\x78\
-\x6d\x6c\x3a\x73\x70\x61\x63\x65\x3d\x22\x70\x72\x65\x73\x65\x72\
-\x76\x65\x22\x3e\x0d\x0a\x3c\x67\x20\x74\x72\x61\x6e\x73\x66\x6f\
-\x72\x6d\x3d\x27\x6d\x61\x74\x72\x69\x78\x28\x32\x34\x20\x30\x20\
-\x30\x20\x32\x34\x20\x30\x20\x30\x29\x27\x3e\x0d\x0a\x3c\x70\x61\
-\x74\x68\x20\x64\x3d\x22\x4d\x31\x37\x2e\x35\x34\x35\x2c\x31\x35\
-\x2e\x34\x36\x37\x6c\x2d\x33\x2e\x37\x37\x39\x2d\x33\x2e\x37\x37\
-\x39\x63\x30\x2e\x35\x37\x2d\x30\x2e\x39\x33\x35\x2c\x30\x2e\x38\
-\x39\x38\x2d\x32\x2e\x30\x33\x35\x2c\x30\x2e\x38\x39\x38\x2d\x33\
-\x2e\x32\x31\x63\x30\x2d\x33\x2e\x34\x31\x37\x2d\x32\x2e\x39\x36\
-\x31\x2d\x36\x2e\x33\x37\x37\x2d\x36\x2e\x33\x37\x38\x2d\x36\x2e\
-\x33\x37\x37\x0d\x0a\x09\x43\x34\x2e\x38\x36\x39\x2c\x32\x2e\x31\
-\x2c\x32\x2e\x31\x2c\x34\x2e\x38\x37\x2c\x32\x2e\x31\x2c\x38\x2e\
-\x32\x38\x37\x63\x30\x2c\x33\x2e\x34\x31\x36\x2c\x32\x2e\x39\x36\
-\x31\x2c\x36\x2e\x33\x37\x37\x2c\x36\x2e\x33\x37\x37\x2c\x36\x2e\
-\x33\x37\x37\x63\x31\x2e\x31\x33\x37\x2c\x30\x2c\x32\x2e\x32\x2d\
-\x30\x2e\x33\x30\x39\x2c\x33\x2e\x31\x31\x35\x2d\x30\x2e\x38\x34\
-\x34\x6c\x33\x2e\x37\x39\x39\x2c\x33\x2e\x38\x30\x31\x0d\x0a\x09\
-\x63\x30\x2e\x33\x37\x32\x2c\x30\x2e\x33\x37\x31\x2c\x30\x2e\x39\
-\x37\x35\x2c\x30\x2e\x33\x37\x31\x2c\x31\x2e\x33\x34\x36\x2c\x30\
-\x6c\x30\x2e\x39\x34\x33\x2d\x30\x2e\x39\x34\x33\x43\x31\x38\x2e\
-\x30\x35\x31\x2c\x31\x36\x2e\x33\x30\x37\x2c\x31\x37\x2e\x39\x31\
-\x36\x2c\x31\x35\x2e\x38\x33\x38\x2c\x31\x37\x2e\x35\x34\x35\x2c\
-\x31\x35\x2e\x34\x36\x37\x7a\x20\x4d\x34\x2e\x30\x30\x34\x2c\x38\
-\x2e\x32\x38\x37\x0d\x0a\x09\x63\x30\x2d\x32\x2e\x33\x36\x36\x2c\
-\x31\x2e\x39\x31\x37\x2d\x34\x2e\x32\x38\x33\x2c\x34\x2e\x32\x38\
-\x32\x2d\x34\x2e\x32\x38\x33\x63\x32\x2e\x33\x36\x36\x2c\x30\x2c\
-\x34\x2e\x34\x37\x34\x2c\x32\x2e\x31\x30\x37\x2c\x34\x2e\x34\x37\
-\x34\x2c\x34\x2e\x34\x37\x34\x63\x30\x2c\x32\x2e\x33\x36\x35\x2d\
-\x31\x2e\x39\x31\x38\x2c\x34\x2e\x32\x38\x33\x2d\x34\x2e\x32\x38\
-\x33\x2c\x34\x2e\x32\x38\x33\x0d\x0a\x09\x43\x36\x2e\x31\x31\x31\
-\x2c\x31\x32\x2e\x37\x36\x2c\x34\x2e\x30\x30\x34\x2c\x31\x30\x2e\
-\x36\x35\x32\x2c\x34\x2e\x30\x30\x34\x2c\x38\x2e\x32\x38\x37\x7a\
-\x22\x2f\x3e\x0d\x0a\x3c\x2f\x67\x3e\x0d\x0a\x3c\x2f\x73\x76\x67\
-\x3e\x0d\x0a\
-\x00\x00\x01\x69\
-\x3c\
-\x73\x76\x67\x20\x78\x6d\x6c\x6e\x73\x3d\x22\x68\x74\x74\x70\x3a\
-\x2f\x2f\x77\x77\x77\x2e\x77\x33\x2e\x6f\x72\x67\x2f\x32\x30\x30\
-\x30\x2f\x73\x76\x67\x22\x20\x77\x69\x64\x74\x68\x3d\x22\x35\x31\
-\x32\x70\x78\x22\x20\x68\x65\x69\x67\x68\x74\x3d\x22\x35\x31\x32\
-\x70\x78\x22\x20\x76\x69\x65\x77\x42\x6f\x78\x3d\x22\x30\x20\x30\
-\x20\x35\x31\x32\x20\x35\x31\x32\x22\x3e\x3c\x67\x20\x74\x72\x61\
-\x6e\x73\x66\x6f\x72\x6d\x3d\x27\x6d\x61\x74\x72\x69\x78\x28\x32\
-\x34\x20\x30\x20\x30\x20\x32\x34\x20\x30\x20\x30\x29\x27\x3e\x3c\
-\x70\x61\x74\x68\x20\x64\x3d\x22\x4d\x34\x2e\x33\x34\x20\x31\x35\
-\x2e\x36\x36\x41\x37\x2e\x39\x37\x20\x37\x2e\x39\x37\x20\x30\x20\
-\x30\x20\x30\x20\x39\x20\x31\x37\x2e\x39\x34\x56\x31\x30\x48\x35\
-\x56\x38\x68\x34\x56\x35\x2e\x38\x33\x61\x33\x20\x33\x20\x30\x20\
-\x31\x20\x31\x20\x32\x20\x30\x56\x38\x68\x34\x76\x32\x68\x2d\x34\
-\x76\x37\x2e\x39\x34\x61\x37\x2e\x39\x37\x20\x37\x2e\x39\x37\x20\
-\x30\x20\x30\x20\x30\x20\x34\x2e\x36\x36\x2d\x32\x2e\x32\x38\x6c\
-\x2d\x31\x2e\x34\x32\x2d\x31\x2e\x34\x32\x68\x35\x2e\x36\x36\x6c\
-\x2d\x32\x2e\x38\x33\x20\x32\x2e\x38\x33\x61\x31\x30\x20\x31\x30\
-\x20\x30\x20\x30\x20\x31\x2d\x31\x34\x2e\x31\x34\x20\x30\x4c\x2e\
-\x31\x20\x31\x34\x2e\x32\x34\x68\x35\x2e\x36\x36\x6c\x2d\x31\x2e\
-\x34\x32\x20\x31\x2e\x34\x32\x7a\x4d\x31\x30\x20\x34\x61\x31\x20\
-\x31\x20\x30\x20\x31\x20\x30\x20\x30\x2d\x32\x20\x31\x20\x31\x20\
-\x30\x20\x30\x20\x30\x20\x30\x20\x32\x7a\x22\x2f\x3e\x3c\x2f\x67\
-\x3e\x3c\x2f\x73\x76\x67\x3e\x0a\
-\x00\x00\x03\x7c\
-\x3c\
-\x3f\x78\x6d\x6c\x20\x76\x65\x72\x73\x69\x6f\x6e\x3d\x27\x31\x2e\
-\x30\x27\x20\x65\x6e\x63\x6f\x64\x69\x6e\x67\x3d\x27\x55\x54\x46\
-\x2d\x38\x27\x3f\x3e\x0a\x3c\x21\x2d\x2d\x20\x54\x68\x69\x73\x20\
-\x66\x69\x6c\x65\x20\x77\x61\x73\x20\x67\x65\x6e\x65\x72\x61\x74\
-\x65\x64\x20\x62\x79\x20\x64\x76\x69\x73\x76\x67\x6d\x20\x32\x2e\
-\x38\x20\x2d\x2d\x3e\x0a\x3c\x73\x76\x67\x20\x76\x65\x72\x73\x69\
-\x6f\x6e\x3d\x27\x31\x2e\x31\x27\x20\x78\x6d\x6c\x6e\x73\x3d\x27\
-\x68\x74\x74\x70\x3a\x2f\x2f\x77\x77\x77\x2e\x77\x33\x2e\x6f\x72\
-\x67\x2f\x32\x30\x30\x30\x2f\x73\x76\x67\x27\x20\x78\x6d\x6c\x6e\
-\x73\x3a\x78\x6c\x69\x6e\x6b\x3d\x27\x68\x74\x74\x70\x3a\x2f\x2f\
-\x77\x77\x77\x2e\x77\x33\x2e\x6f\x72\x67\x2f\x31\x39\x39\x39\x2f\
-\x78\x6c\x69\x6e\x6b\x27\x20\x77\x69\x64\x74\x68\x3d\x27\x36\x33\
-\x2e\x39\x39\x39\x36\x70\x74\x27\x20\x68\x65\x69\x67\x68\x74\x3d\
-\x27\x36\x33\x2e\x39\x39\x39\x37\x70\x74\x27\x20\x76\x69\x65\x77\
-\x42\x6f\x78\x3d\x27\x35\x36\x2e\x34\x30\x39\x34\x20\x35\x33\x2e\
-\x38\x35\x38\x33\x20\x36\x33\x2e\x39\x39\x39\x36\x20\x36\x33\x2e\
-\x39\x39\x39\x37\x27\x3e\x0a\x3c\x67\x20\x69\x64\x3d\x27\x70\x61\
-\x67\x65\x31\x27\x3e\x0a\x3c\x67\x20\x74\x72\x61\x6e\x73\x66\x6f\
-\x72\x6d\x3d\x27\x6d\x61\x74\x72\x69\x78\x28\x30\x2e\x39\x39\x36\
-\x32\x36\x34\x20\x30\x20\x30\x20\x30\x2e\x39\x39\x36\x32\x36\x34\
-\x20\x35\x36\x2e\x34\x30\x39\x34\x20\x31\x31\x37\x2e\x38\x35\x38\
-\x29\x27\x3e\x0a\x3c\x70\x61\x74\x68\x20\x64\x3d\x27\x4d\x20\x32\
-\x2e\x30\x30\x37\x35\x20\x2d\x32\x2e\x30\x30\x37\x35\x4c\x20\x36\
-\x32\x2e\x32\x33\x32\x35\x20\x2d\x32\x2e\x30\x30\x37\x35\x4c\x20\
-\x36\x32\x2e\x32\x33\x32\x35\x20\x2d\x36\x32\x2e\x32\x33\x32\x35\
-\x4c\x20\x32\x2e\x30\x30\x37\x35\x20\x2d\x36\x32\x2e\x32\x33\x32\
-\x35\x4c\x20\x32\x2e\x30\x30\x37\x35\x20\x2d\x32\x2e\x30\x30\x37\
-\x35\x5a\x27\x20\x66\x69\x6c\x6c\x3d\x27\x6e\x6f\x6e\x65\x27\x20\
-\x73\x74\x72\x6f\x6b\x65\x3d\x27\x23\x30\x30\x30\x30\x30\x30\x27\
-\x20\x73\x74\x72\x6f\x6b\x65\x2d\x6c\x69\x6e\x65\x63\x61\x70\x3d\
-\x27\x72\x6f\x75\x6e\x64\x27\x20\x73\x74\x72\x6f\x6b\x65\x2d\x6c\
-\x69\x6e\x65\x6a\x6f\x69\x6e\x3d\x27\x72\x6f\x75\x6e\x64\x27\x20\
-\x73\x74\x72\x6f\x6b\x65\x2d\x6d\x69\x74\x65\x72\x6c\x69\x6d\x69\
-\x74\x3d\x27\x31\x30\x2e\x30\x33\x37\x35\x27\x20\x73\x74\x72\x6f\
-\x6b\x65\x2d\x77\x69\x64\x74\x68\x3d\x27\x34\x2e\x30\x31\x35\x27\
-\x2f\x3e\x0a\x3c\x2f\x67\x3e\x0a\x3c\x67\x20\x74\x72\x61\x6e\x73\
-\x66\x6f\x72\x6d\x3d\x27\x6d\x61\x74\x72\x69\x78\x28\x30\x2e\x39\
-\x39\x36\x32\x36\x34\x20\x30\x20\x30\x20\x30\x2e\x39\x39\x36\x32\
-\x36\x34\x20\x35\x36\x2e\x34\x30\x39\x34\x20\x31\x31\x37\x2e\x38\
-\x35\x38\x29\x27\x3e\x0a\x3c\x70\x61\x74\x68\x20\x64\x3d\x27\x4d\
-\x20\x34\x37\x2e\x31\x37\x36\x32\x20\x2d\x33\x32\x2e\x31\x32\x43\
-\x20\x34\x37\x2e\x31\x37\x36\x32\x20\x2d\x34\x30\x2e\x34\x33\x35\
-\x33\x20\x34\x30\x2e\x34\x33\x35\x33\x20\x2d\x34\x37\x2e\x31\x37\
-\x36\x32\x20\x33\x32\x2e\x31\x32\x20\x2d\x34\x37\x2e\x31\x37\x36\
-\x32\x43\x20\x32\x33\x2e\x38\x30\x34\x37\x20\x2d\x34\x37\x2e\x31\
-\x37\x36\x32\x20\x31\x37\x2e\x30\x36\x33\x37\x20\x2d\x34\x30\x2e\
-\x34\x33\x35\x33\x20\x31\x37\x2e\x30\x36\x33\x37\x20\x2d\x33\x32\
-\x2e\x31\x32\x43\x20\x31\x37\x2e\x30\x36\x33\x37\x20\x2d\x32\x33\
-\x2e\x38\x30\x34\x37\x20\x32\x33\x2e\x38\x30\x34\x37\x20\x2d\x31\
-\x37\x2e\x30\x36\x33\x37\x20\x33\x32\x2e\x31\x32\x20\x2d\x31\x37\
-\x2e\x30\x36\x33\x37\x43\x20\x34\x30\x2e\x34\x33\x35\x33\x20\x2d\
-\x31\x37\x2e\x30\x36\x33\x37\x20\x34\x37\x2e\x31\x37\x36\x32\x20\
-\x2d\x32\x33\x2e\x38\x30\x34\x37\x20\x34\x37\x2e\x31\x37\x36\x32\
-\x20\x2d\x33\x32\x2e\x31\x32\x5a\x27\x20\x66\x69\x6c\x6c\x3d\x27\
-\x23\x30\x30\x30\x30\x30\x30\x27\x2f\x3e\x0a\x3c\x2f\x67\x3e\x0a\
-\x3c\x2f\x67\x3e\x0a\x3c\x2f\x73\x76\x67\x3e\
-\x00\x00\x02\x21\
-\x00\
-\x00\x07\xaf\x78\x9c\xdd\x55\x4d\x6f\x9c\x30\x10\xbd\xf7\x57\x4c\
-\xd5\x83\xdb\x03\xc6\xdf\x86\x28\x24\x52\x57\xea\x29\xbd\x25\x97\
-\xde\x68\xf0\x82\x9b\x5d\x58\x01\x5d\xb6\xff\xbe\x66\xd7\x60\x4a\
-\xaa\xf4\x92\x43\x15\x90\x30\xf3\x18\xbf\x99\xe7\xf1\x98\xeb\xdb\
-\xd3\x7e\x07\x47\xd3\x76\xb6\xa9\x33\x44\x31\x41\x60\xea\xc7\xa6\
-\xb0\x75\x99\xa1\x87\xfb\x2f\x51\x82\x6e\x6f\xde\x5d\xbf\x8f\x22\
-\xb8\xaf\x6c\x07\x5b\xbb\x33\x30\xe4\x1d\x94\xa6\x36\x6d\xde\x9b\
-\x02\xbe\xff\x82\xe2\x68\xbb\x63\xb9\x07\x86\x13\x88\x22\xe7\xef\
-\xac\x25\x2b\x45\xe0\xe2\xd4\x5d\x86\xaa\xbe\x3f\x5c\xc5\xf1\x30\
-\x0c\x78\xe0\xb8\x69\xcb\x98\x11\x42\x62\xe7\xef\x5d\xae\x4e\x3b\
-\x5b\x3f\xfd\xcd\x91\xa6\x69\x1a\x9f\xbf\x22\x18\x6c\xd1\x57\x19\
-\x52\x1c\x3b\x50\x1d\x7a\x04\x95\xb1\x65\xd5\x4f\x90\x1e\xa1\xa3\
-\x35\xc3\xe7\xe6\x94\x21\xa9\xb0\x20\xa9\x00\xc9\x71\x22\x13\x0e\
-\x7e\x9a\x1f\x35\x72\x09\x97\x60\x8b\x0c\x1d\xf2\xd2\xd0\x8b\xd9\
-\xb7\x79\xdd\x6d\x9b\x76\x9f\xa1\x7d\xde\xb7\xf6\xf4\x91\x38\x67\
-\xc5\x94\x00\x32\xde\x93\x31\x71\x53\xaa\x47\xf2\x4f\xe3\xec\x43\
-\xde\x57\xe0\xe8\xbe\x42\x8a\xb9\xd0\x82\x41\xc4\x38\x26\x94\xde\
-\x05\xc0\xbf\x3c\x47\x36\xcf\x90\x7f\x03\x8b\x39\x12\x53\x29\x29\
-\x05\x9a\x62\x29\x38\x85\x88\x62\x2d\x95\x54\xc0\x19\xa6\x6c\x36\
-\x37\x20\x04\x56\xa9\x4a\x83\x83\x14\x38\x49\x99\x0a\x14\x33\x30\
-\xe7\xfa\x02\x32\x09\x9c\x01\xae\xb0\xd2\x42\x6e\x02\x22\x08\x4e\
-\x94\x4a\x42\x64\xf7\xc2\x94\x14\x53\x6a\xde\xdc\x84\xdc\x27\x87\
-\x59\xdd\x44\x31\x03\x3e\xca\xdd\x7a\xa5\xbf\xa1\x71\xab\xee\x32\
-\xf4\x41\x6f\xc7\x1b\xc5\xae\x2e\x71\xf9\x8a\xa5\x0d\x42\x53\xac\
-\x29\x49\x97\x42\xdd\xbe\x22\x9c\x2d\x84\x6a\xcc\x09\xd5\xb3\xd0\
-\x8b\xb9\x14\xea\x1d\x82\x50\x4f\x11\x84\x4e\x51\x02\x22\xb1\xa4\
-\x89\x0c\x24\x17\x76\x1f\xe3\x3c\x2c\xaa\x7c\x81\x43\xd2\x7e\xf2\
-\x5a\xc5\xbc\x6e\x75\x53\x1b\x04\x5d\xdf\x36\x4f\xc6\xad\x22\x39\
-\x5f\x13\x10\xb9\x2e\x34\x8f\xf9\x21\x43\x6d\xf3\xb3\x2e\xfe\x80\
-\x7f\x34\xb6\x5e\xe3\x7b\xdb\x9b\x76\x67\xdd\xe0\x4e\x03\x82\x09\
-\xd7\x72\xfe\xe6\x5b\x99\xbb\x7c\x38\x65\xaf\x5f\xa7\xf5\x0a\xbe\
-\xe1\x1e\xf4\x0a\xdf\x5c\x09\x5f\x68\x35\xc9\x30\x4b\xf4\xe2\x4c\
-\x51\x0c\x8b\x84\xcf\x67\x8a\x37\x17\xad\x36\x39\x84\x6a\x79\x8a\
-\xf5\x46\xf9\x6f\x96\xf1\xf2\x70\xbf\xc8\x9b\xdf\xf9\x80\xe2\xe1\
-\
-\x00\x00\x04\x1c\
-\x3c\
-\x3f\x78\x6d\x6c\x20\x76\x65\x72\x73\x69\x6f\x6e\x3d\x27\x31\x2e\
-\x30\x27\x20\x65\x6e\x63\x6f\x64\x69\x6e\x67\x3d\x27\x55\x54\x46\
-\x2d\x38\x27\x3f\x3e\x0a\x3c\x21\x2d\x2d\x20\x54\x68\x69\x73\x20\
-\x66\x69\x6c\x65\x20\x77\x61\x73\x20\x67\x65\x6e\x65\x72\x61\x74\
-\x65\x64\x20\x62\x79\x20\x64\x76\x69\x73\x76\x67\x6d\x20\x32\x2e\
-\x38\x20\x2d\x2d\x3e\x0a\x3c\x73\x76\x67\x20\x76\x65\x72\x73\x69\
-\x6f\x6e\x3d\x27\x31\x2e\x31\x27\x20\x78\x6d\x6c\x6e\x73\x3d\x27\
-\x68\x74\x74\x70\x3a\x2f\x2f\x77\x77\x77\x2e\x77\x33\x2e\x6f\x72\
-\x67\x2f\x32\x30\x30\x30\x2f\x73\x76\x67\x27\x20\x78\x6d\x6c\x6e\
-\x73\x3a\x78\x6c\x69\x6e\x6b\x3d\x27\x68\x74\x74\x70\x3a\x2f\x2f\
-\x77\x77\x77\x2e\x77\x33\x2e\x6f\x72\x67\x2f\x31\x39\x39\x39\x2f\
-\x78\x6c\x69\x6e\x6b\x27\x20\x77\x69\x64\x74\x68\x3d\x27\x36\x33\
-\x2e\x39\x39\x39\x36\x70\x74\x27\x20\x68\x65\x69\x67\x68\x74\x3d\
-\x27\x36\x33\x2e\x39\x39\x39\x37\x70\x74\x27\x20\x76\x69\x65\x77\
-\x42\x6f\x78\x3d\x27\x35\x36\x2e\x34\x30\x39\x34\x20\x35\x33\x2e\
-\x38\x35\x38\x33\x20\x36\x33\x2e\x39\x39\x39\x36\x20\x36\x33\x2e\
-\x39\x39\x39\x37\x27\x3e\x0a\x3c\x67\x20\x69\x64\x3d\x27\x70\x61\
-\x67\x65\x31\x27\x3e\x0a\x3c\x67\x20\x74\x72\x61\x6e\x73\x66\x6f\
-\x72\x6d\x3d\x27\x6d\x61\x74\x72\x69\x78\x28\x30\x2e\x39\x39\x36\
-\x32\x36\x34\x20\x30\x20\x30\x20\x30\x2e\x39\x39\x36\x32\x36\x34\
-\x20\x35\x36\x2e\x34\x30\x39\x34\x20\x31\x31\x37\x2e\x38\x35\x38\
-\x29\x27\x3e\x0a\x3c\x70\x61\x74\x68\x20\x64\x3d\x27\x4d\x20\x32\
-\x2e\x30\x30\x37\x35\x20\x2d\x32\x2e\x30\x30\x37\x35\x4c\x20\x36\
-\x32\x2e\x32\x33\x32\x35\x20\x2d\x32\x2e\x30\x30\x37\x35\x4c\x20\
-\x36\x32\x2e\x32\x33\x32\x35\x20\x2d\x36\x32\x2e\x32\x33\x32\x35\
-\x4c\x20\x32\x2e\x30\x30\x37\x35\x20\x2d\x36\x32\x2e\x32\x33\x32\
-\x35\x4c\x20\x32\x2e\x30\x30\x37\x35\x20\x2d\x32\x2e\x30\x30\x37\
-\x35\x5a\x27\x20\x66\x69\x6c\x6c\x3d\x27\x6e\x6f\x6e\x65\x27\x20\
-\x73\x74\x72\x6f\x6b\x65\x3d\x27\x23\x30\x30\x30\x30\x30\x30\x27\
-\x20\x73\x74\x72\x6f\x6b\x65\x2d\x6c\x69\x6e\x65\x63\x61\x70\x3d\
-\x27\x72\x6f\x75\x6e\x64\x27\x20\x73\x74\x72\x6f\x6b\x65\x2d\x6c\
-\x69\x6e\x65\x6a\x6f\x69\x6e\x3d\x27\x72\x6f\x75\x6e\x64\x27\x20\
-\x73\x74\x72\x6f\x6b\x65\x2d\x6d\x69\x74\x65\x72\x6c\x69\x6d\x69\
-\x74\x3d\x27\x31\x30\x2e\x30\x33\x37\x35\x27\x20\x73\x74\x72\x6f\
-\x6b\x65\x2d\x77\x69\x64\x74\x68\x3d\x27\x34\x2e\x30\x31\x35\x27\
-\x2f\x3e\x0a\x3c\x2f\x67\x3e\x0a\x3c\x67\x20\x74\x72\x61\x6e\x73\
-\x66\x6f\x72\x6d\x3d\x27\x6d\x61\x74\x72\x69\x78\x28\x30\x2e\x39\
-\x39\x36\x32\x36\x34\x20\x30\x20\x30\x20\x30\x2e\x39\x39\x36\x32\
-\x36\x34\x20\x35\x36\x2e\x34\x30\x39\x34\x20\x31\x31\x37\x2e\x38\
-\x35\x38\x29\x27\x3e\x0a\x3c\x70\x61\x74\x68\x20\x64\x3d\x27\x4d\
-\x20\x32\x2e\x30\x30\x37\x35\x20\x2d\x33\x32\x2e\x31\x32\x4c\x20\
-\x36\x32\x2e\x32\x33\x32\x35\x20\x2d\x33\x32\x2e\x31\x32\x27\x20\
-\x66\x69\x6c\x6c\x3d\x27\x6e\x6f\x6e\x65\x27\x20\x73\x74\x72\x6f\
-\x6b\x65\x3d\x27\x23\x30\x30\x30\x30\x30\x30\x27\x20\x73\x74\x72\
-\x6f\x6b\x65\x2d\x6c\x69\x6e\x65\x63\x61\x70\x3d\x27\x72\x6f\x75\
-\x6e\x64\x27\x20\x73\x74\x72\x6f\x6b\x65\x2d\x6c\x69\x6e\x65\x6a\
-\x6f\x69\x6e\x3d\x27\x72\x6f\x75\x6e\x64\x27\x20\x73\x74\x72\x6f\
-\x6b\x65\x2d\x6d\x69\x74\x65\x72\x6c\x69\x6d\x69\x74\x3d\x27\x31\
-\x30\x2e\x30\x33\x37\x35\x27\x20\x73\x74\x72\x6f\x6b\x65\x2d\x77\
-\x69\x64\x74\x68\x3d\x27\x34\x2e\x30\x31\x35\x27\x2f\x3e\x0a\x3c\
-\x2f\x67\x3e\x0a\x3c\x67\x20\x74\x72\x61\x6e\x73\x66\x6f\x72\x6d\
-\x3d\x27\x6d\x61\x74\x72\x69\x78\x28\x30\x2e\x39\x39\x36\x32\x36\
-\x34\x20\x30\x20\x30\x20\x30\x2e\x39\x39\x36\x32\x36\x34\x20\x35\
-\x36\x2e\x34\x30\x39\x34\x20\x31\x31\x37\x2e\x38\x35\x38\x29\x27\
-\x3e\x0a\x3c\x70\x61\x74\x68\x20\x64\x3d\x27\x4d\x20\x33\x32\x2e\
-\x31\x32\x20\x2d\x32\x2e\x30\x30\x37\x35\x4c\x20\x33\x32\x2e\x31\
-\x32\x20\x2d\x36\x32\x2e\x32\x33\x32\x35\x27\x20\x66\x69\x6c\x6c\
-\x3d\x27\x6e\x6f\x6e\x65\x27\x20\x73\x74\x72\x6f\x6b\x65\x3d\x27\
-\x23\x30\x30\x30\x30\x30\x30\x27\x20\x73\x74\x72\x6f\x6b\x65\x2d\
-\x6c\x69\x6e\x65\x63\x61\x70\x3d\x27\x72\x6f\x75\x6e\x64\x27\x20\
-\x73\x74\x72\x6f\x6b\x65\x2d\x6c\x69\x6e\x65\x6a\x6f\x69\x6e\x3d\
-\x27\x72\x6f\x75\x6e\x64\x27\x20\x73\x74\x72\x6f\x6b\x65\x2d\x6d\
-\x69\x74\x65\x72\x6c\x69\x6d\x69\x74\x3d\x27\x31\x30\x2e\x30\x33\
-\x37\x35\x27\x20\x73\x74\x72\x6f\x6b\x65\x2d\x77\x69\x64\x74\x68\
-\x3d\x27\x34\x2e\x30\x31\x35\x27\x2f\x3e\x0a\x3c\x2f\x67\x3e\x0a\
-\x3c\x2f\x67\x3e\x0a\x3c\x2f\x73\x76\x67\x3e\
-\x00\x00\x02\xa1\
-\x3c\
-\x3f\x78\x6d\x6c\x20\x76\x65\x72\x73\x69\x6f\x6e\x3d\x22\x31\x2e\
-\x30\x22\x20\x65\x6e\x63\x6f\x64\x69\x6e\x67\x3d\x22\x75\x74\x66\
-\x2d\x38\x22\x3f\x3e\x0d\x0a\x3c\x21\x2d\x2d\x20\x47\x65\x6e\x65\
-\x72\x61\x74\x6f\x72\x3a\x20\x41\x64\x6f\x62\x65\x20\x49\x6c\x6c\
-\x75\x73\x74\x72\x61\x74\x6f\x72\x20\x31\x38\x2e\x31\x2e\x31\x2c\
-\x20\x53\x56\x47\x20\x45\x78\x70\x6f\x72\x74\x20\x50\x6c\x75\x67\
-\x2d\x49\x6e\x20\x2e\x20\x53\x56\x47\x20\x56\x65\x72\x73\x69\x6f\
-\x6e\x3a\x20\x36\x2e\x30\x30\x20\x42\x75\x69\x6c\x64\x20\x30\x29\
-\x20\x20\x2d\x2d\x3e\x0d\x0a\x3c\x21\x44\x4f\x43\x54\x59\x50\x45\
-\x20\x73\x76\x67\x20\x50\x55\x42\x4c\x49\x43\x20\x22\x2d\x2f\x2f\
-\x57\x33\x43\x2f\x2f\x44\x54\x44\x20\x53\x56\x47\x20\x31\x2e\x31\
-\x2f\x2f\x45\x4e\x22\x20\x22\x68\x74\x74\x70\x3a\x2f\x2f\x77\x77\
-\x77\x2e\x77\x33\x2e\x6f\x72\x67\x2f\x47\x72\x61\x70\x68\x69\x63\
-\x73\x2f\x53\x56\x47\x2f\x31\x2e\x31\x2f\x44\x54\x44\x2f\x73\x76\
-\x67\x31\x31\x2e\x64\x74\x64\x22\x3e\x0d\x0a\x3c\x73\x76\x67\x20\
-\x76\x65\x72\x73\x69\x6f\x6e\x3d\x22\x31\x2e\x31\x22\x20\x69\x64\
-\x3d\x22\x53\x61\x76\x65\x22\x20\x78\x6d\x6c\x6e\x73\x3d\x22\x68\
-\x74\x74\x70\x3a\x2f\x2f\x77\x77\x77\x2e\x77\x33\x2e\x6f\x72\x67\
-\x2f\x32\x30\x30\x30\x2f\x73\x76\x67\x22\x20\x78\x6d\x6c\x6e\x73\
-\x3a\x78\x6c\x69\x6e\x6b\x3d\x22\x68\x74\x74\x70\x3a\x2f\x2f\x77\
-\x77\x77\x2e\x77\x33\x2e\x6f\x72\x67\x2f\x31\x39\x39\x39\x2f\x78\
-\x6c\x69\x6e\x6b\x22\x20\x78\x3d\x22\x35\x31\x32\x70\x78\x22\x20\
-\x79\x3d\x22\x35\x31\x32\x70\x78\x22\x0d\x0a\x09\x20\x76\x69\x65\
-\x77\x42\x6f\x78\x3d\x22\x30\x20\x30\x20\x35\x31\x32\x20\x35\x31\
-\x32\x22\x20\x65\x6e\x61\x62\x6c\x65\x2d\x62\x61\x63\x6b\x67\x72\
-\x6f\x75\x6e\x64\x3d\x22\x6e\x65\x77\x20\x30\x20\x30\x20\x35\x31\
-\x32\x20\x35\x31\x32\x22\x20\x78\x6d\x6c\x3a\x73\x70\x61\x63\x65\
-\x3d\x22\x70\x72\x65\x73\x65\x72\x76\x65\x22\x3e\x0d\x0a\x3c\x67\
-\x20\x74\x72\x61\x6e\x73\x66\x6f\x72\x6d\x3d\x27\x6d\x61\x74\x72\
-\x69\x78\x28\x32\x34\x20\x30\x20\x30\x20\x32\x34\x20\x30\x20\x30\
-\x29\x27\x3e\x0d\x0a\x3c\x70\x61\x74\x68\x20\x64\x3d\x22\x4d\x31\
-\x35\x2e\x31\x37\x33\x2c\x32\x48\x34\x43\x32\x2e\x38\x39\x39\x2c\
-\x32\x2c\x32\x2c\x32\x2e\x39\x2c\x32\x2c\x34\x76\x31\x32\x63\x30\
-\x2c\x31\x2e\x31\x2c\x30\x2e\x38\x39\x39\x2c\x32\x2c\x32\x2c\x32\
-\x68\x31\x32\x63\x31\x2e\x31\x30\x31\x2c\x30\x2c\x32\x2d\x30\x2e\
-\x39\x2c\x32\x2d\x32\x56\x35\x2e\x31\x32\x37\x4c\x31\x35\x2e\x31\
-\x37\x33\x2c\x32\x7a\x20\x4d\x31\x34\x2c\x38\x63\x30\x2c\x30\x2e\
-\x35\x34\x39\x2d\x30\x2e\x34\x35\x2c\x31\x2d\x31\x2c\x31\x48\x37\
-\x0d\x0a\x09\x43\x36\x2e\x34\x35\x2c\x39\x2c\x36\x2c\x38\x2e\x35\
-\x34\x39\x2c\x36\x2c\x38\x56\x33\x68\x38\x56\x38\x7a\x20\x4d\x31\
-\x33\x2c\x34\x68\x2d\x32\x76\x34\x68\x32\x56\x34\x7a\x22\x2f\x3e\
-\x0d\x0a\x3c\x2f\x67\x3e\x0d\x0a\x3c\x2f\x73\x76\x67\x3e\x0d\x0a\
-\
-\x00\x00\x02\xf7\
-\x3c\
-\x3f\x78\x6d\x6c\x20\x76\x65\x72\x73\x69\x6f\x6e\x3d\x22\x31\x2e\
-\x30\x22\x20\x65\x6e\x63\x6f\x64\x69\x6e\x67\x3d\x22\x75\x74\x66\
-\x2d\x38\x22\x3f\x3e\x0d\x0a\x3c\x21\x2d\x2d\x20\x47\x65\x6e\x65\
-\x72\x61\x74\x6f\x72\x3a\x20\x41\x64\x6f\x62\x65\x20\x49\x6c\x6c\
-\x75\x73\x74\x72\x61\x74\x6f\x72\x20\x31\x36\x2e\x32\x2e\x31\x2c\
-\x20\x53\x56\x47\x20\x45\x78\x70\x6f\x72\x74\x20\x50\x6c\x75\x67\
-\x2d\x49\x6e\x20\x2e\x20\x53\x56\x47\x20\x56\x65\x72\x73\x69\x6f\
-\x6e\x3a\x20\x36\x2e\x30\x30\x20\x42\x75\x69\x6c\x64\x20\x30\x29\
-\x20\x20\x2d\x2d\x3e\x0d\x0a\x3c\x21\x44\x4f\x43\x54\x59\x50\x45\
-\x20\x73\x76\x67\x20\x50\x55\x42\x4c\x49\x43\x20\x22\x2d\x2f\x2f\
-\x57\x33\x43\x2f\x2f\x44\x54\x44\x20\x53\x56\x47\x20\x31\x2e\x31\
-\x2f\x2f\x45\x4e\x22\x20\x22\x68\x74\x74\x70\x3a\x2f\x2f\x77\x77\
-\x77\x2e\x77\x33\x2e\x6f\x72\x67\x2f\x47\x72\x61\x70\x68\x69\x63\
-\x73\x2f\x53\x56\x47\x2f\x31\x2e\x31\x2f\x44\x54\x44\x2f\x73\x76\
-\x67\x31\x31\x2e\x64\x74\x64\x22\x3e\x0d\x0a\x3c\x73\x76\x67\x20\
-\x76\x65\x72\x73\x69\x6f\x6e\x3d\x22\x31\x2e\x31\x22\x20\x69\x64\
-\x3d\x22\x4c\x61\x79\x65\x72\x5f\x31\x22\x20\x78\x6d\x6c\x6e\x73\
-\x3d\x22\x68\x74\x74\x70\x3a\x2f\x2f\x77\x77\x77\x2e\x77\x33\x2e\
-\x6f\x72\x67\x2f\x32\x30\x30\x30\x2f\x73\x76\x67\x22\x20\x78\x6d\
-\x6c\x6e\x73\x3a\x78\x6c\x69\x6e\x6b\x3d\x22\x68\x74\x74\x70\x3a\
-\x2f\x2f\x77\x77\x77\x2e\x77\x33\x2e\x6f\x72\x67\x2f\x31\x39\x39\
-\x39\x2f\x78\x6c\x69\x6e\x6b\x22\x20\x78\x3d\x22\x30\x70\x78\x22\
-\x20\x79\x3d\x22\x30\x70\x78\x22\x0d\x0a\x09\x20\x77\x69\x64\x74\
-\x68\x3d\x22\x35\x31\x32\x70\x78\x22\x20\x68\x65\x69\x67\x68\x74\
-\x3d\x22\x35\x31\x32\x70\x78\x22\x20\x76\x69\x65\x77\x42\x6f\x78\
-\x3d\x22\x30\x20\x30\x20\x35\x31\x32\x20\x35\x31\x32\x22\x20\x73\
-\x74\x79\x6c\x65\x3d\x22\x65\x6e\x61\x62\x6c\x65\x2d\x62\x61\x63\
-\x6b\x67\x72\x6f\x75\x6e\x64\x3a\x6e\x65\x77\x20\x30\x20\x30\x20\
-\x35\x31\x32\x20\x35\x31\x32\x3b\x22\x20\x78\x6d\x6c\x3a\x73\x70\
-\x61\x63\x65\x3d\x22\x70\x72\x65\x73\x65\x72\x76\x65\x22\x3e\x0d\
-\x0a\x3c\x70\x61\x74\x68\x20\x64\x3d\x22\x4d\x34\x31\x37\x2e\x34\
-\x2c\x32\x32\x34\x48\x32\x38\x38\x56\x39\x34\x2e\x36\x63\x30\x2d\
-\x31\x36\x2e\x39\x2d\x31\x34\x2e\x33\x2d\x33\x30\x2e\x36\x2d\x33\
-\x32\x2d\x33\x30\x2e\x36\x63\x2d\x31\x37\x2e\x37\x2c\x30\x2d\x33\
-\x32\x2c\x31\x33\x2e\x37\x2d\x33\x32\x2c\x33\x30\x2e\x36\x56\x32\
-\x32\x34\x48\x39\x34\x2e\x36\x43\x37\x37\x2e\x37\x2c\x32\x32\x34\
-\x2c\x36\x34\x2c\x32\x33\x38\x2e\x33\x2c\x36\x34\x2c\x32\x35\x36\
-\x0d\x0a\x09\x63\x30\x2c\x31\x37\x2e\x37\x2c\x31\x33\x2e\x37\x2c\
-\x33\x32\x2c\x33\x30\x2e\x36\x2c\x33\x32\x48\x32\x32\x34\x76\x31\
-\x32\x39\x2e\x34\x63\x30\x2c\x31\x36\x2e\x39\x2c\x31\x34\x2e\x33\
-\x2c\x33\x30\x2e\x36\x2c\x33\x32\x2c\x33\x30\x2e\x36\x63\x31\x37\
-\x2e\x37\x2c\x30\x2c\x33\x32\x2d\x31\x33\x2e\x37\x2c\x33\x32\x2d\
-\x33\x30\x2e\x36\x56\x32\x38\x38\x68\x31\x32\x39\x2e\x34\x63\x31\
-\x36\x2e\x39\x2c\x30\x2c\x33\x30\x2e\x36\x2d\x31\x34\x2e\x33\x2c\
-\x33\x30\x2e\x36\x2d\x33\x32\x0d\x0a\x09\x43\x34\x34\x38\x2c\x32\
-\x33\x38\x2e\x33\x2c\x34\x33\x34\x2e\x33\x2c\x32\x32\x34\x2c\x34\
-\x31\x37\x2e\x34\x2c\x32\x32\x34\x7a\x22\x2f\x3e\x0d\x0a\x3c\x2f\
-\x73\x76\x67\x3e\x0d\x0a\
-\x00\x00\x03\x22\
-\x3c\
-\x3f\x78\x6d\x6c\x20\x76\x65\x72\x73\x69\x6f\x6e\x3d\x22\x31\x2e\
-\x30\x22\x20\x65\x6e\x63\x6f\x64\x69\x6e\x67\x3d\x22\x75\x74\x66\
-\x2d\x38\x22\x3f\x3e\x0d\x0a\x3c\x21\x2d\x2d\x20\x47\x65\x6e\x65\
-\x72\x61\x74\x6f\x72\x3a\x20\x41\x64\x6f\x62\x65\x20\x49\x6c\x6c\
-\x75\x73\x74\x72\x61\x74\x6f\x72\x20\x31\x36\x2e\x32\x2e\x31\x2c\
-\x20\x53\x56\x47\x20\x45\x78\x70\x6f\x72\x74\x20\x50\x6c\x75\x67\
-\x2d\x49\x6e\x20\x2e\x20\x53\x56\x47\x20\x56\x65\x72\x73\x69\x6f\
-\x6e\x3a\x20\x36\x2e\x30\x30\x20\x42\x75\x69\x6c\x64\x20\x30\x29\
-\x20\x20\x2d\x2d\x3e\x0d\x0a\x3c\x21\x44\x4f\x43\x54\x59\x50\x45\
-\x20\x73\x76\x67\x20\x50\x55\x42\x4c\x49\x43\x20\x22\x2d\x2f\x2f\
-\x57\x33\x43\x2f\x2f\x44\x54\x44\x20\x53\x56\x47\x20\x31\x2e\x31\
-\x2f\x2f\x45\x4e\x22\x20\x22\x68\x74\x74\x70\x3a\x2f\x2f\x77\x77\
-\x77\x2e\x77\x33\x2e\x6f\x72\x67\x2f\x47\x72\x61\x70\x68\x69\x63\
-\x73\x2f\x53\x56\x47\x2f\x31\x2e\x31\x2f\x44\x54\x44\x2f\x73\x76\
-\x67\x31\x31\x2e\x64\x74\x64\x22\x3e\x0d\x0a\x3c\x73\x76\x67\x20\
-\x76\x65\x72\x73\x69\x6f\x6e\x3d\x22\x31\x2e\x31\x22\x20\x69\x64\
-\x3d\x22\x4c\x61\x79\x65\x72\x5f\x31\x22\x20\x78\x6d\x6c\x6e\x73\
-\x3d\x22\x68\x74\x74\x70\x3a\x2f\x2f\x77\x77\x77\x2e\x77\x33\x2e\
-\x6f\x72\x67\x2f\x32\x30\x30\x30\x2f\x73\x76\x67\x22\x20\x78\x6d\
-\x6c\x6e\x73\x3a\x78\x6c\x69\x6e\x6b\x3d\x22\x68\x74\x74\x70\x3a\
-\x2f\x2f\x77\x77\x77\x2e\x77\x33\x2e\x6f\x72\x67\x2f\x31\x39\x39\
-\x39\x2f\x78\x6c\x69\x6e\x6b\x22\x20\x78\x3d\x22\x30\x70\x78\x22\
-\x20\x79\x3d\x22\x30\x70\x78\x22\x0d\x0a\x09\x20\x77\x69\x64\x74\
-\x68\x3d\x22\x35\x31\x32\x70\x78\x22\x20\x68\x65\x69\x67\x68\x74\
-\x3d\x22\x35\x31\x32\x70\x78\x22\x20\x76\x69\x65\x77\x42\x6f\x78\
-\x3d\x22\x30\x20\x30\x20\x35\x31\x32\x20\x35\x31\x32\x22\x20\x65\
-\x6e\x61\x62\x6c\x65\x2d\x62\x61\x63\x6b\x67\x72\x6f\x75\x6e\x64\
-\x3d\x22\x6e\x65\x77\x20\x30\x20\x30\x20\x35\x31\x32\x20\x35\x31\
-\x32\x22\x20\x78\x6d\x6c\x3a\x73\x70\x61\x63\x65\x3d\x22\x70\x72\
-\x65\x73\x65\x72\x76\x65\x22\x3e\x0d\x0a\x3c\x67\x3e\x0d\x0a\x09\
-\x3c\x63\x69\x72\x63\x6c\x65\x20\x63\x78\x3d\x22\x32\x35\x36\x22\
-\x20\x63\x79\x3d\x22\x32\x38\x30\x22\x20\x72\x3d\x22\x36\x33\x22\
-\x2f\x3e\x0d\x0a\x09\x3c\x70\x61\x74\x68\x20\x64\x3d\x22\x4d\x34\
-\x34\x30\x2c\x39\x36\x68\x2d\x38\x38\x6c\x2d\x33\x32\x2d\x33\x32\
-\x48\x31\x39\x32\x6c\x2d\x33\x32\x2c\x33\x32\x48\x37\x32\x63\x2d\
-\x32\x32\x2e\x30\x39\x32\x2c\x30\x2d\x34\x30\x2c\x31\x37\x2e\x39\
-\x30\x38\x2d\x34\x30\x2c\x34\x30\x76\x32\x37\x32\x63\x30\x2c\x32\
-\x32\x2e\x30\x39\x32\x2c\x31\x37\x2e\x39\x30\x38\x2c\x34\x30\x2c\
-\x34\x30\x2c\x34\x30\x68\x33\x36\x38\x63\x32\x32\x2e\x30\x39\x32\
-\x2c\x30\x2c\x34\x30\x2d\x31\x37\x2e\x39\x30\x38\x2c\x34\x30\x2d\
-\x34\x30\x0d\x0a\x09\x09\x56\x31\x33\x36\x43\x34\x38\x30\x2c\x31\
-\x31\x33\x2e\x39\x30\x38\x2c\x34\x36\x32\x2e\x30\x39\x32\x2c\x39\
-\x36\x2c\x34\x34\x30\x2c\x39\x36\x7a\x20\x4d\x32\x35\x36\x2c\x33\
-\x39\x32\x63\x2d\x36\x31\x2e\x38\x35\x35\x2c\x30\x2d\x31\x31\x32\
-\x2d\x35\x30\x2e\x31\x34\x35\x2d\x31\x31\x32\x2d\x31\x31\x32\x73\
-\x35\x30\x2e\x31\x34\x35\x2d\x31\x31\x32\x2c\x31\x31\x32\x2d\x31\
-\x31\x32\x73\x31\x31\x32\x2c\x35\x30\x2e\x31\x34\x35\x2c\x31\x31\
-\x32\x2c\x31\x31\x32\x0d\x0a\x09\x09\x53\x33\x31\x37\x2e\x38\x35\
-\x35\x2c\x33\x39\x32\x2c\x32\x35\x36\x2c\x33\x39\x32\x7a\x22\x2f\
-\x3e\x0d\x0a\x3c\x2f\x67\x3e\x0d\x0a\x3c\x2f\x73\x76\x67\x3e\x0d\
-\x0a\
-\x00\x00\x02\xfc\
-\x3c\
-\x3f\x78\x6d\x6c\x20\x76\x65\x72\x73\x69\x6f\x6e\x3d\x22\x31\x2e\
-\x30\x22\x20\x65\x6e\x63\x6f\x64\x69\x6e\x67\x3d\x22\x75\x74\x66\
-\x2d\x38\x22\x3f\x3e\x0d\x0a\x3c\x21\x2d\x2d\x20\x47\x65\x6e\x65\
-\x72\x61\x74\x6f\x72\x3a\x20\x41\x64\x6f\x62\x65\x20\x49\x6c\x6c\
-\x75\x73\x74\x72\x61\x74\x6f\x72\x20\x31\x36\x2e\x32\x2e\x31\x2c\
-\x20\x53\x56\x47\x20\x45\x78\x70\x6f\x72\x74\x20\x50\x6c\x75\x67\
-\x2d\x49\x6e\x20\x2e\x20\x53\x56\x47\x20\x56\x65\x72\x73\x69\x6f\
-\x6e\x3a\x20\x36\x2e\x30\x30\x20\x42\x75\x69\x6c\x64\x20\x30\x29\
-\x20\x20\x2d\x2d\x3e\x0d\x0a\x3c\x21\x44\x4f\x43\x54\x59\x50\x45\
-\x20\x73\x76\x67\x20\x50\x55\x42\x4c\x49\x43\x20\x22\x2d\x2f\x2f\
-\x57\x33\x43\x2f\x2f\x44\x54\x44\x20\x53\x56\x47\x20\x31\x2e\x31\
-\x2f\x2f\x45\x4e\x22\x20\x22\x68\x74\x74\x70\x3a\x2f\x2f\x77\x77\
-\x77\x2e\x77\x33\x2e\x6f\x72\x67\x2f\x47\x72\x61\x70\x68\x69\x63\
-\x73\x2f\x53\x56\x47\x2f\x31\x2e\x31\x2f\x44\x54\x44\x2f\x73\x76\
-\x67\x31\x31\x2e\x64\x74\x64\x22\x3e\x0d\x0a\x3c\x73\x76\x67\x20\
-\x76\x65\x72\x73\x69\x6f\x6e\x3d\x22\x31\x2e\x31\x22\x20\x69\x64\
-\x3d\x22\x4c\x61\x79\x65\x72\x5f\x31\x22\x20\x78\x6d\x6c\x6e\x73\
-\x3d\x22\x68\x74\x74\x70\x3a\x2f\x2f\x77\x77\x77\x2e\x77\x33\x2e\
-\x6f\x72\x67\x2f\x32\x30\x30\x30\x2f\x73\x76\x67\x22\x20\x78\x6d\
-\x6c\x6e\x73\x3a\x78\x6c\x69\x6e\x6b\x3d\x22\x68\x74\x74\x70\x3a\
-\x2f\x2f\x77\x77\x77\x2e\x77\x33\x2e\x6f\x72\x67\x2f\x31\x39\x39\
-\x39\x2f\x78\x6c\x69\x6e\x6b\x22\x20\x78\x3d\x22\x30\x70\x78\x22\
-\x20\x79\x3d\x22\x30\x70\x78\x22\x0d\x0a\x09\x20\x77\x69\x64\x74\
-\x68\x3d\x22\x35\x31\x32\x70\x78\x22\x20\x68\x65\x69\x67\x68\x74\
-\x3d\x22\x35\x31\x32\x70\x78\x22\x20\x76\x69\x65\x77\x42\x6f\x78\
-\x3d\x22\x30\x20\x30\x20\x35\x31\x32\x20\x35\x31\x32\x22\x20\x65\
-\x6e\x61\x62\x6c\x65\x2d\x62\x61\x63\x6b\x67\x72\x6f\x75\x6e\x64\
-\x3d\x22\x6e\x65\x77\x20\x30\x20\x30\x20\x35\x31\x32\x20\x35\x31\
-\x32\x22\x20\x78\x6d\x6c\x3a\x73\x70\x61\x63\x65\x3d\x22\x70\x72\
-\x65\x73\x65\x72\x76\x65\x22\x3e\x0d\x0a\x3c\x67\x20\x69\x64\x3d\
-\x22\x49\x63\x6f\x6e\x5f\x32\x30\x5f\x22\x3e\x0d\x0a\x09\x3c\x67\
-\x3e\x0d\x0a\x09\x09\x3c\x70\x61\x74\x68\x20\x64\x3d\x22\x4d\x32\
-\x35\x36\x2c\x34\x38\x43\x31\x34\x31\x2e\x36\x30\x31\x2c\x34\x38\
-\x2c\x34\x38\x2c\x31\x34\x31\x2e\x36\x30\x31\x2c\x34\x38\x2c\x32\
-\x35\x36\x73\x39\x33\x2e\x36\x30\x31\x2c\x32\x30\x38\x2c\x32\x30\
-\x38\x2c\x32\x30\x38\x73\x32\x30\x38\x2d\x39\x33\x2e\x36\x30\x31\
-\x2c\x32\x30\x38\x2d\x32\x30\x38\x53\x33\x37\x30\x2e\x33\x39\x39\
-\x2c\x34\x38\x2c\x32\x35\x36\x2c\x34\x38\x7a\x20\x4d\x32\x35\x36\
-\x2c\x34\x32\x32\x2e\x33\x39\x39\x0d\x0a\x09\x09\x09\x63\x2d\x39\
-\x31\x2e\x35\x31\x38\x2c\x30\x2d\x31\x36\x36\x2e\x33\x39\x39\x2d\
-\x37\x34\x2e\x38\x38\x32\x2d\x31\x36\x36\x2e\x33\x39\x39\x2d\x31\
-\x36\x36\x2e\x33\x39\x39\x53\x31\x36\x34\x2e\x34\x38\x32\x2c\x38\
-\x39\x2e\x36\x2c\x32\x35\x36\x2c\x38\x39\x2e\x36\x53\x34\x32\x32\
-\x2e\x34\x2c\x31\x36\x34\x2e\x34\x38\x32\x2c\x34\x32\x32\x2e\x34\
-\x2c\x32\x35\x36\x53\x33\x34\x37\x2e\x35\x31\x38\x2c\x34\x32\x32\
-\x2e\x33\x39\x39\x2c\x32\x35\x36\x2c\x34\x32\x32\x2e\x33\x39\x39\
-\x7a\x22\x2f\x3e\x0d\x0a\x09\x3c\x2f\x67\x3e\x0d\x0a\x3c\x2f\x67\
-\x3e\x0d\x0a\x3c\x2f\x73\x76\x67\x3e\x0d\x0a\
-\x00\x00\x03\xf5\
-\x3c\
-\x3f\x78\x6d\x6c\x20\x76\x65\x72\x73\x69\x6f\x6e\x3d\x22\x31\x2e\
-\x30\x22\x20\x65\x6e\x63\x6f\x64\x69\x6e\x67\x3d\x22\x75\x74\x66\
-\x2d\x38\x22\x3f\x3e\x0d\x0a\x3c\x21\x2d\x2d\x20\x47\x65\x6e\x65\
-\x72\x61\x74\x6f\x72\x3a\x20\x41\x64\x6f\x62\x65\x20\x49\x6c\x6c\
-\x75\x73\x74\x72\x61\x74\x6f\x72\x20\x31\x38\x2e\x31\x2e\x31\x2c\
-\x20\x53\x56\x47\x20\x45\x78\x70\x6f\x72\x74\x20\x50\x6c\x75\x67\
-\x2d\x49\x6e\x20\x2e\x20\x53\x56\x47\x20\x56\x65\x72\x73\x69\x6f\
-\x6e\x3a\x20\x36\x2e\x30\x30\x20\x42\x75\x69\x6c\x64\x20\x30\x29\
-\x20\x20\x2d\x2d\x3e\x0d\x0a\x3c\x21\x44\x4f\x43\x54\x59\x50\x45\
-\x20\x73\x76\x67\x20\x50\x55\x42\x4c\x49\x43\x20\x22\x2d\x2f\x2f\
-\x57\x33\x43\x2f\x2f\x44\x54\x44\x20\x53\x56\x47\x20\x31\x2e\x31\
-\x2f\x2f\x45\x4e\x22\x20\x22\x68\x74\x74\x70\x3a\x2f\x2f\x77\x77\
-\x77\x2e\x77\x33\x2e\x6f\x72\x67\x2f\x47\x72\x61\x70\x68\x69\x63\
-\x73\x2f\x53\x56\x47\x2f\x31\x2e\x31\x2f\x44\x54\x44\x2f\x73\x76\
-\x67\x31\x31\x2e\x64\x74\x64\x22\x3e\x0d\x0a\x3c\x73\x76\x67\x20\
-\x76\x65\x72\x73\x69\x6f\x6e\x3d\x22\x31\x2e\x31\x22\x20\x69\x64\
-\x3d\x22\x43\x68\x65\x76\x72\x6f\x6e\x5f\x63\x69\x72\x63\x6c\x65\
-\x64\x5f\x6c\x65\x66\x74\x22\x20\x78\x6d\x6c\x6e\x73\x3d\x22\x68\
-\x74\x74\x70\x3a\x2f\x2f\x77\x77\x77\x2e\x77\x33\x2e\x6f\x72\x67\
-\x2f\x32\x30\x30\x30\x2f\x73\x76\x67\x22\x20\x78\x6d\x6c\x6e\x73\
-\x3a\x78\x6c\x69\x6e\x6b\x3d\x22\x68\x74\x74\x70\x3a\x2f\x2f\x77\
-\x77\x77\x2e\x77\x33\x2e\x6f\x72\x67\x2f\x31\x39\x39\x39\x2f\x78\
-\x6c\x69\x6e\x6b\x22\x0d\x0a\x09\x20\x78\x3d\x22\x30\x70\x78\x22\
-\x20\x79\x3d\x22\x30\x70\x78\x22\x20\x76\x69\x65\x77\x42\x6f\x78\
-\x3d\x22\x30\x20\x30\x20\x35\x31\x32\x20\x35\x31\x32\x22\x20\x65\
-\x6e\x61\x62\x6c\x65\x2d\x62\x61\x63\x6b\x67\x72\x6f\x75\x6e\x64\
-\x3d\x22\x6e\x65\x77\x20\x30\x20\x30\x20\x35\x31\x32\x20\x35\x31\
-\x32\x22\x20\x78\x6d\x6c\x3a\x73\x70\x61\x63\x65\x3d\x22\x70\x72\
-\x65\x73\x65\x72\x76\x65\x22\x3e\x0d\x0a\x3c\x67\x20\x74\x72\x61\
-\x6e\x73\x66\x6f\x72\x6d\x3d\x27\x6d\x61\x74\x72\x69\x78\x28\x32\
-\x34\x20\x30\x20\x30\x20\x32\x34\x20\x30\x20\x30\x29\x27\x3e\x0d\
-\x0a\x3c\x70\x61\x74\x68\x20\x64\x3d\x22\x4d\x31\x31\x2e\x33\x30\
-\x32\x2c\x36\x2e\x37\x37\x36\x63\x2d\x30\x2e\x31\x39\x36\x2d\x30\
-\x2e\x31\x39\x37\x2d\x30\x2e\x35\x31\x35\x2d\x30\x2e\x31\x39\x37\
-\x2d\x30\x2e\x37\x31\x2c\x30\x4c\x37\x2e\x37\x38\x35\x2c\x39\x2e\
-\x36\x34\x31\x63\x2d\x30\x2e\x31\x39\x36\x2c\x30\x2e\x31\x39\x39\
-\x2d\x30\x2e\x31\x39\x36\x2c\x30\x2e\x35\x32\x2c\x30\x2c\x30\x2e\
-\x37\x31\x37\x6c\x32\x2e\x38\x30\x37\x2c\x32\x2e\x38\x36\x34\x0d\
-\x0a\x09\x63\x30\x2e\x31\x39\x35\x2c\x30\x2e\x31\x39\x39\x2c\x30\
-\x2e\x35\x31\x34\x2c\x30\x2e\x31\x39\x38\x2c\x30\x2e\x37\x31\x2c\
-\x30\x63\x30\x2e\x31\x39\x36\x2d\x30\x2e\x31\x39\x37\x2c\x30\x2e\
-\x31\x39\x36\x2d\x30\x2e\x35\x31\x38\x2c\x30\x2d\x30\x2e\x37\x31\
-\x37\x4c\x39\x2c\x31\x30\x6c\x32\x2e\x33\x30\x32\x2d\x32\x2e\x35\
-\x30\x36\x43\x31\x31\x2e\x34\x39\x38\x2c\x37\x2e\x32\x39\x36\x2c\
-\x31\x31\x2e\x34\x39\x38\x2c\x36\x2e\x39\x37\x36\x2c\x31\x31\x2e\
-\x33\x30\x32\x2c\x36\x2e\x37\x37\x36\x7a\x0d\x0a\x09\x20\x4d\x31\
-\x30\x2c\x30\x2e\x34\x63\x2d\x35\x2e\x33\x30\x32\x2c\x30\x2d\x39\
-\x2e\x36\x2c\x34\x2e\x32\x39\x38\x2d\x39\x2e\x36\x2c\x39\x2e\x36\
-\x63\x30\x2c\x35\x2e\x33\x30\x33\x2c\x34\x2e\x32\x39\x38\x2c\x39\
-\x2e\x36\x2c\x39\x2e\x36\x2c\x39\x2e\x36\x73\x39\x2e\x36\x2d\x34\
-\x2e\x32\x39\x37\x2c\x39\x2e\x36\x2d\x39\x2e\x36\x43\x31\x39\x2e\
-\x36\x2c\x34\x2e\x36\x39\x38\x2c\x31\x35\x2e\x33\x30\x32\x2c\x30\
-\x2e\x34\x2c\x31\x30\x2c\x30\x2e\x34\x7a\x20\x4d\x31\x30\x2c\x31\
-\x38\x2e\x33\x35\x34\x0d\x0a\x09\x63\x2d\x34\x2e\x36\x31\x35\x2c\
-\x30\x2d\x38\x2e\x33\x35\x34\x2d\x33\x2e\x37\x34\x2d\x38\x2e\x33\
-\x35\x34\x2d\x38\x2e\x33\x35\x34\x63\x30\x2d\x34\x2e\x36\x31\x34\
-\x2c\x33\x2e\x37\x33\x39\x2d\x38\x2e\x33\x35\x34\x2c\x38\x2e\x33\
-\x35\x34\x2d\x38\x2e\x33\x35\x34\x63\x34\x2e\x36\x31\x33\x2c\x30\
-\x2c\x38\x2e\x33\x35\x34\x2c\x33\x2e\x37\x34\x2c\x38\x2e\x33\x35\
-\x34\x2c\x38\x2e\x33\x35\x34\x0d\x0a\x09\x43\x31\x38\x2e\x33\x35\
-\x34\x2c\x31\x34\x2e\x36\x31\x34\x2c\x31\x34\x2e\x36\x31\x33\x2c\
-\x31\x38\x2e\x33\x35\x34\x2c\x31\x30\x2c\x31\x38\x2e\x33\x35\x34\
-\x7a\x22\x2f\x3e\x0d\x0a\x3c\x2f\x67\x3e\x0d\x0a\x3c\x2f\x73\x76\
-\x67\x3e\x0d\x0a\
-\x00\x00\x02\xb7\
-\x3c\
-\x3f\x78\x6d\x6c\x20\x76\x65\x72\x73\x69\x6f\x6e\x3d\x22\x31\x2e\
-\x30\x22\x20\x65\x6e\x63\x6f\x64\x69\x6e\x67\x3d\x22\x75\x74\x66\
-\x2d\x38\x22\x3f\x3e\x0d\x0a\x3c\x21\x2d\x2d\x20\x47\x65\x6e\x65\
-\x72\x61\x74\x6f\x72\x3a\x20\x41\x64\x6f\x62\x65\x20\x49\x6c\x6c\
-\x75\x73\x74\x72\x61\x74\x6f\x72\x20\x31\x36\x2e\x32\x2e\x31\x2c\
-\x20\x53\x56\x47\x20\x45\x78\x70\x6f\x72\x74\x20\x50\x6c\x75\x67\
-\x2d\x49\x6e\x20\x2e\x20\x53\x56\x47\x20\x56\x65\x72\x73\x69\x6f\
-\x6e\x3a\x20\x36\x2e\x30\x30\x20\x42\x75\x69\x6c\x64\x20\x30\x29\
-\x20\x20\x2d\x2d\x3e\x0d\x0a\x3c\x21\x44\x4f\x43\x54\x59\x50\x45\
-\x20\x73\x76\x67\x20\x50\x55\x42\x4c\x49\x43\x20\x22\x2d\x2f\x2f\
-\x57\x33\x43\x2f\x2f\x44\x54\x44\x20\x53\x56\x47\x20\x31\x2e\x31\
-\x2f\x2f\x45\x4e\x22\x20\x22\x68\x74\x74\x70\x3a\x2f\x2f\x77\x77\
-\x77\x2e\x77\x33\x2e\x6f\x72\x67\x2f\x47\x72\x61\x70\x68\x69\x63\
-\x73\x2f\x53\x56\x47\x2f\x31\x2e\x31\x2f\x44\x54\x44\x2f\x73\x76\
-\x67\x31\x31\x2e\x64\x74\x64\x22\x3e\x0d\x0a\x3c\x73\x76\x67\x20\
-\x76\x65\x72\x73\x69\x6f\x6e\x3d\x22\x31\x2e\x31\x22\x20\x69\x64\
-\x3d\x22\x4c\x61\x79\x65\x72\x5f\x31\x22\x20\x78\x6d\x6c\x6e\x73\
-\x3d\x22\x68\x74\x74\x70\x3a\x2f\x2f\x77\x77\x77\x2e\x77\x33\x2e\
-\x6f\x72\x67\x2f\x32\x30\x30\x30\x2f\x73\x76\x67\x22\x20\x78\x6d\
-\x6c\x6e\x73\x3a\x78\x6c\x69\x6e\x6b\x3d\x22\x68\x74\x74\x70\x3a\
-\x2f\x2f\x77\x77\x77\x2e\x77\x33\x2e\x6f\x72\x67\x2f\x31\x39\x39\
-\x39\x2f\x78\x6c\x69\x6e\x6b\x22\x20\x78\x3d\x22\x30\x70\x78\x22\
-\x20\x79\x3d\x22\x30\x70\x78\x22\x0d\x0a\x09\x20\x77\x69\x64\x74\
-\x68\x3d\x22\x35\x31\x32\x70\x78\x22\x20\x68\x65\x69\x67\x68\x74\
-\x3d\x22\x35\x31\x32\x70\x78\x22\x20\x76\x69\x65\x77\x42\x6f\x78\
-\x3d\x22\x30\x20\x30\x20\x35\x31\x32\x20\x35\x31\x32\x22\x20\x65\
-\x6e\x61\x62\x6c\x65\x2d\x62\x61\x63\x6b\x67\x72\x6f\x75\x6e\x64\
-\x3d\x22\x6e\x65\x77\x20\x30\x20\x30\x20\x35\x31\x32\x20\x35\x31\
-\x32\x22\x20\x78\x6d\x6c\x3a\x73\x70\x61\x63\x65\x3d\x22\x70\x72\
-\x65\x73\x65\x72\x76\x65\x22\x3e\x0d\x0a\x3c\x67\x20\x69\x64\x3d\
-\x22\x49\x63\x6f\x6e\x5f\x35\x5f\x22\x3e\x0d\x0a\x09\x3c\x67\x3e\
-\x0d\x0a\x09\x09\x3c\x70\x6f\x6c\x79\x67\x6f\x6e\x20\x70\x6f\x69\
-\x6e\x74\x73\x3d\x22\x34\x30\x35\x2c\x31\x33\x36\x2e\x37\x39\x38\
-\x20\x33\x37\x35\x2e\x32\x30\x32\x2c\x31\x30\x37\x20\x32\x35\x36\
-\x2c\x32\x32\x36\x2e\x32\x30\x32\x20\x31\x33\x36\x2e\x37\x39\x38\
-\x2c\x31\x30\x37\x20\x31\x30\x37\x2c\x31\x33\x36\x2e\x37\x39\x38\
-\x20\x32\x32\x36\x2e\x32\x30\x32\x2c\x32\x35\x36\x20\x31\x30\x37\
-\x2c\x33\x37\x35\x2e\x32\x30\x32\x20\x31\x33\x36\x2e\x37\x39\x38\
-\x2c\x34\x30\x35\x20\x32\x35\x36\x2c\x32\x38\x35\x2e\x37\x39\x38\
-\x20\x0d\x0a\x09\x09\x09\x33\x37\x35\x2e\x32\x30\x32\x2c\x34\x30\
-\x35\x20\x34\x30\x35\x2c\x33\x37\x35\x2e\x32\x30\x32\x20\x32\x38\
-\x35\x2e\x37\x39\x38\x2c\x32\x35\x36\x20\x09\x09\x22\x2f\x3e\x0d\
-\x0a\x09\x3c\x2f\x67\x3e\x0d\x0a\x3c\x2f\x67\x3e\x0d\x0a\x3c\x2f\
-\x73\x76\x67\x3e\x0d\x0a\
-\x00\x00\x04\xca\
-\x3c\
-\x3f\x78\x6d\x6c\x20\x76\x65\x72\x73\x69\x6f\x6e\x3d\x22\x31\x2e\
-\x30\x22\x20\x65\x6e\x63\x6f\x64\x69\x6e\x67\x3d\x22\x75\x74\x66\
-\x2d\x38\x22\x3f\x3e\x0a\x3c\x21\x2d\x2d\x20\x47\x65\x6e\x65\x72\
-\x61\x74\x6f\x72\x3a\x20\x41\x64\x6f\x62\x65\x20\x49\x6c\x6c\x75\
-\x73\x74\x72\x61\x74\x6f\x72\x20\x31\x39\x2e\x32\x2e\x31\x2c\x20\
-\x53\x56\x47\x20\x45\x78\x70\x6f\x72\x74\x20\x50\x6c\x75\x67\x2d\
-\x49\x6e\x20\x2e\x20\x53\x56\x47\x20\x56\x65\x72\x73\x69\x6f\x6e\
-\x3a\x20\x36\x2e\x30\x30\x20\x42\x75\x69\x6c\x64\x20\x30\x29\x20\
-\x20\x2d\x2d\x3e\x0a\x3c\x21\x44\x4f\x43\x54\x59\x50\x45\x20\x73\
-\x76\x67\x20\x50\x55\x42\x4c\x49\x43\x20\x22\x2d\x2f\x2f\x57\x33\
-\x43\x2f\x2f\x44\x54\x44\x20\x53\x56\x47\x20\x31\x2e\x31\x2f\x2f\
-\x45\x4e\x22\x20\x22\x68\x74\x74\x70\x3a\x2f\x2f\x77\x77\x77\x2e\
-\x77\x33\x2e\x6f\x72\x67\x2f\x47\x72\x61\x70\x68\x69\x63\x73\x2f\
-\x53\x56\x47\x2f\x31\x2e\x31\x2f\x44\x54\x44\x2f\x73\x76\x67\x31\
-\x31\x2e\x64\x74\x64\x22\x3e\x0a\x3c\x73\x76\x67\x20\x76\x65\x72\
-\x73\x69\x6f\x6e\x3d\x22\x31\x2e\x31\x22\x0a\x09\x20\x69\x64\x3d\
-\x22\x73\x76\x67\x34\x36\x31\x39\x22\x20\x69\x6e\x6b\x73\x63\x61\
-\x70\x65\x3a\x76\x65\x72\x73\x69\x6f\x6e\x3d\x22\x30\x2e\x39\x31\
-\x2b\x64\x65\x76\x65\x6c\x2b\x6f\x73\x78\x6d\x65\x6e\x75\x20\x72\
-\x31\x32\x39\x31\x31\x22\x20\x73\x6f\x64\x69\x70\x6f\x64\x69\x3a\
-\x64\x6f\x63\x6e\x61\x6d\x65\x3d\x22\x74\x72\x69\x61\x6e\x67\x6c\
-\x65\x2d\x73\x74\x72\x6f\x6b\x65\x64\x2d\x31\x35\x2e\x73\x76\x67\
-\x22\x20\x78\x6d\x6c\x6e\x73\x3a\x63\x63\x3d\x22\x68\x74\x74\x70\
-\x3a\x2f\x2f\x63\x72\x65\x61\x74\x69\x76\x65\x63\x6f\x6d\x6d\x6f\
-\x6e\x73\x2e\x6f\x72\x67\x2f\x6e\x73\x23\x22\x20\x78\x6d\x6c\x6e\
-\x73\x3a\x64\x63\x3d\x22\x68\x74\x74\x70\x3a\x2f\x2f\x70\x75\x72\
-\x6c\x2e\x6f\x72\x67\x2f\x64\x63\x2f\x65\x6c\x65\x6d\x65\x6e\x74\
-\x73\x2f\x31\x2e\x31\x2f\x22\x20\x78\x6d\x6c\x6e\x73\x3a\x69\x6e\
-\x6b\x73\x63\x61\x70\x65\x3d\x22\x68\x74\x74\x70\x3a\x2f\x2f\x77\
-\x77\x77\x2e\x69\x6e\x6b\x73\x63\x61\x70\x65\x2e\x6f\x72\x67\x2f\
-\x6e\x61\x6d\x65\x73\x70\x61\x63\x65\x73\x2f\x69\x6e\x6b\x73\x63\
-\x61\x70\x65\x22\x20\x78\x6d\x6c\x6e\x73\x3a\x72\x64\x66\x3d\x22\
-\x68\x74\x74\x70\x3a\x2f\x2f\x77\x77\x77\x2e\x77\x33\x2e\x6f\x72\
-\x67\x2f\x31\x39\x39\x39\x2f\x30\x32\x2f\x32\x32\x2d\x72\x64\x66\
-\x2d\x73\x79\x6e\x74\x61\x78\x2d\x6e\x73\x23\x22\x20\x78\x6d\x6c\
-\x6e\x73\x3a\x73\x6f\x64\x69\x70\x6f\x64\x69\x3d\x22\x68\x74\x74\
-\x70\x3a\x2f\x2f\x73\x6f\x64\x69\x70\x6f\x64\x69\x2e\x73\x6f\x75\
-\x72\x63\x65\x66\x6f\x72\x67\x65\x2e\x6e\x65\x74\x2f\x44\x54\x44\
-\x2f\x73\x6f\x64\x69\x70\x6f\x64\x69\x2d\x30\x2e\x64\x74\x64\x22\
-\x20\x78\x6d\x6c\x6e\x73\x3a\x73\x76\x67\x3d\x22\x68\x74\x74\x70\
-\x3a\x2f\x2f\x77\x77\x77\x2e\x77\x33\x2e\x6f\x72\x67\x2f\x32\x30\
-\x30\x30\x2f\x73\x76\x67\x22\x0a\x09\x20\x78\x6d\x6c\x6e\x73\x3d\
-\x22\x68\x74\x74\x70\x3a\x2f\x2f\x77\x77\x77\x2e\x77\x33\x2e\x6f\
-\x72\x67\x2f\x32\x30\x30\x30\x2f\x73\x76\x67\x22\x20\x78\x6d\x6c\
-\x6e\x73\x3a\x78\x6c\x69\x6e\x6b\x3d\x22\x68\x74\x74\x70\x3a\x2f\
-\x2f\x77\x77\x77\x2e\x77\x33\x2e\x6f\x72\x67\x2f\x31\x39\x39\x39\
-\x2f\x78\x6c\x69\x6e\x6b\x22\x20\x78\x3d\x22\x30\x70\x78\x22\x20\
-\x79\x3d\x22\x30\x70\x78\x22\x20\x77\x69\x64\x74\x68\x3d\x22\x36\
-\x34\x70\x78\x22\x20\x68\x65\x69\x67\x68\x74\x3d\x22\x36\x34\x70\
-\x78\x22\x0a\x09\x20\x76\x69\x65\x77\x42\x6f\x78\x3d\x22\x30\x20\
-\x30\x20\x31\x35\x20\x31\x35\x22\x20\x73\x74\x79\x6c\x65\x3d\x22\
-\x65\x6e\x61\x62\x6c\x65\x2d\x62\x61\x63\x6b\x67\x72\x6f\x75\x6e\
-\x64\x3a\x6e\x65\x77\x20\x30\x20\x30\x20\x31\x35\x20\x31\x35\x3b\
-\x22\x20\x78\x6d\x6c\x3a\x73\x70\x61\x63\x65\x3d\x22\x70\x72\x65\
-\x73\x65\x72\x76\x65\x22\x3e\x0a\x3c\x70\x61\x74\x68\x20\x69\x64\
-\x3d\x22\x72\x65\x63\x74\x33\x33\x33\x38\x22\x20\x69\x6e\x6b\x73\
-\x63\x61\x70\x65\x3a\x63\x6f\x6e\x6e\x65\x63\x74\x6f\x72\x2d\x63\
-\x75\x72\x76\x61\x74\x75\x72\x65\x3d\x22\x30\x22\x20\x73\x6f\x64\
-\x69\x70\x6f\x64\x69\x3a\x6e\x6f\x64\x65\x74\x79\x70\x65\x73\x3d\
-\x22\x63\x63\x63\x63\x63\x63\x63\x63\x63\x63\x63\x63\x22\x20\x64\
-\x3d\x22\x4d\x37\x2e\x35\x32\x34\x33\x2c\x31\x2e\x35\x30\x30\x34\
-\x0a\x09\x43\x37\x2e\x32\x34\x32\x39\x2c\x31\x2e\x34\x39\x31\x33\
-\x2c\x36\x2e\x39\x37\x38\x37\x2c\x31\x2e\x36\x34\x32\x33\x2c\x36\
-\x2e\x38\x33\x33\x36\x2c\x31\x2e\x38\x39\x35\x32\x6c\x2d\x35\x2e\
-\x35\x2c\x39\x2e\x38\x36\x39\x32\x43\x31\x2e\x30\x32\x31\x38\x2c\
-\x31\x32\x2e\x33\x30\x37\x38\x2c\x31\x2e\x33\x39\x35\x2c\x31\x32\
-\x2e\x39\x39\x39\x39\x2c\x32\x2c\x31\x33\x68\x31\x31\x0a\x09\x63\
-\x30\x2e\x36\x30\x35\x2d\x30\x2e\x30\x30\x30\x31\x2c\x30\x2e\x39\
-\x37\x38\x32\x2d\x30\x2e\x36\x39\x32\x32\x2c\x30\x2e\x36\x36\x36\
-\x34\x2d\x31\x2e\x32\x33\x35\x35\x6c\x2d\x35\x2e\x35\x2d\x39\x2e\
-\x38\x36\x39\x32\x43\x38\x2e\x30\x33\x30\x32\x2c\x31\x2e\x36\x35\
-\x37\x39\x2c\x37\x2e\x37\x38\x38\x34\x2c\x31\x2e\x35\x30\x39\x32\
-\x2c\x37\x2e\x35\x32\x34\x33\x2c\x31\x2e\x35\x30\x30\x34\x7a\x20\
-\x4d\x37\x2e\x35\x2c\x33\x2e\x38\x39\x39\x33\x6c\x34\x2e\x31\x32\
-\x36\x37\x2c\x37\x2e\x34\x37\x30\x34\x0a\x09\x48\x33\x2e\x33\x37\
-\x33\x33\x4c\x37\x2e\x35\x2c\x33\x2e\x38\x39\x39\x33\x7a\x22\x2f\
-\x3e\x0a\x3c\x2f\x73\x76\x67\x3e\x0a\
-\x00\x00\x01\xdd\
-\x00\
-\x00\x06\xe4\x78\x9c\xcd\x54\x4d\x6f\x9b\x40\x10\x3d\x13\x29\xff\
-\x61\xba\xb7\x4a\xec\x17\xc4\xd4\xa6\xa6\x51\xfd\x21\xcb\x52\x9a\
-\x58\x6a\xea\xaa\xa7\x0a\xc3\x16\x50\x28\x20\x58\xc0\xce\xaf\xef\
-\xee\x92\x54\x51\x95\xfa\x18\xfb\xb0\x33\xda\x79\x6f\xde\xbc\x65\
-\x24\xa6\xd7\xfb\xdf\x39\x74\xa2\x6e\xb2\xb2\x08\x10\x27\x0c\x81\
-\x28\xa2\x32\xce\x8a\x24\x40\xad\xfc\x85\xc7\xe8\xfa\xd3\xe5\xc5\
-\xf4\x1d\xc6\xb0\x12\x85\xa8\x43\x59\xd6\x3e\x7c\x8e\xcb\x9d\x80\
-\x75\x9e\xb7\x8d\x34\x25\xe0\x1e\x71\x08\xb7\xe1\xeb\x76\x05\xcb\
-\x7d\x55\xd6\x12\x36\x79\x9b\xe0\x75\x01\xc4\x14\xb7\xc3\x10\x1f\
-\x3c\xc2\x18\xcc\xda\x2c\x8f\x81\xbd\x07\xc0\xd8\xe8\x2f\xee\xe6\
-\xf7\x3f\x36\x4b\x68\xba\x04\x36\xdf\x66\x37\xeb\x39\x20\x4c\xe9\
-\x77\x77\x4e\xe9\xe2\x7e\x61\x24\x38\xe1\x94\x2e\x6f\x11\xa0\x54\
-\xca\xca\xa7\xb4\xef\x7b\xd2\xbb\xa4\xac\x13\xba\xaa\xc3\x2a\xcd\
-\xa2\x86\x2a\x22\xd5\x44\xd5\x44\x95\x18\xe7\x24\x96\x31\xd2\x33\
-\xb4\xf4\x8b\xa7\x72\x04\x59\x1c\xa0\x9b\xf0\x20\xea\x9f\xea\xa2\
-\xbe\x44\xd1\x04\xaf\x48\x3b\x8c\x31\x2d\xf5\x44\xf1\xf7\x79\x56\
-\x3c\xbc\x46\xe4\x93\xc9\x84\x1a\x54\x51\x03\xc4\xaa\x3d\x82\xc3\
-\x90\x2f\x2f\x2c\xe8\xb3\x58\xa6\x01\x1a\x71\x47\x03\xa9\xc8\x92\
-\x54\xfe\xbd\x76\x99\xe8\x67\xa5\xee\x02\x06\xaa\xa6\x0f\x82\x46\
-\x1e\x72\x11\x20\x51\x84\xbb\x5c\xe0\x5d\x18\x3d\x24\x75\xd9\x16\
-\xb1\x5f\x88\x1e\x5e\x30\x3f\x1a\x6f\x7e\x53\x85\x91\xa2\x57\xb5\
-\x68\x44\xdd\x09\xf3\xea\x44\x05\x6b\x88\xd6\xb4\x0a\x65\x0a\xea\
-\xd1\x5f\xb8\xc7\x6c\x3e\x72\x89\x1b\x31\xdb\x25\x1f\xb0\x6b\x7b\
-\x2a\xaa\xa3\x73\x8a\x47\x8c\x8c\x22\xac\x00\x9b\xe9\x22\x76\xf1\
-\x13\xdc\x0d\x10\x33\x98\xfb\xdc\xa0\x73\x6a\x00\xd3\xa2\x4b\xb6\
-\x51\xd4\x67\x6b\xe6\x3c\xea\x4f\x60\x59\xf4\x1f\x1f\xce\x78\x7c\
-\x16\x3e\xae\xb8\x77\x3a\x1f\x53\xfa\xff\x25\x39\x63\xfe\x26\xa6\
-\xcc\x9c\x23\x4b\x3a\x07\x1f\x7a\x49\x27\xf3\x71\x6c\x49\x57\x6c\
-\xf2\x26\xa6\xcc\x9c\x23\x4b\x3a\x07\x1f\x7a\x49\x27\xf3\x31\x2c\
-\xe9\x39\xaa\x7f\xb6\xca\x7f\x00\x99\x18\x96\x19\
-\x00\x00\x03\x46\
-\x3c\
-\x3f\x78\x6d\x6c\x20\x76\x65\x72\x73\x69\x6f\x6e\x3d\x22\x31\x2e\
-\x30\x22\x20\x65\x6e\x63\x6f\x64\x69\x6e\x67\x3d\x22\x75\x74\x66\
-\x2d\x38\x22\x3f\x3e\x0d\x0a\x3c\x21\x2d\x2d\x20\x47\x65\x6e\x65\
-\x72\x61\x74\x6f\x72\x3a\x20\x41\x64\x6f\x62\x65\x20\x49\x6c\x6c\
-\x75\x73\x74\x72\x61\x74\x6f\x72\x20\x31\x36\x2e\x32\x2e\x31\x2c\
-\x20\x53\x56\x47\x20\x45\x78\x70\x6f\x72\x74\x20\x50\x6c\x75\x67\
-\x2d\x49\x6e\x20\x2e\x20\x53\x56\x47\x20\x56\x65\x72\x73\x69\x6f\
-\x6e\x3a\x20\x36\x2e\x30\x30\x20\x42\x75\x69\x6c\x64\x20\x30\x29\
-\x20\x20\x2d\x2d\x3e\x0d\x0a\x3c\x21\x44\x4f\x43\x54\x59\x50\x45\
-\x20\x73\x76\x67\x20\x50\x55\x42\x4c\x49\x43\x20\x22\x2d\x2f\x2f\
-\x57\x33\x43\x2f\x2f\x44\x54\x44\x20\x53\x56\x47\x20\x31\x2e\x31\
-\x2f\x2f\x45\x4e\x22\x20\x22\x68\x74\x74\x70\x3a\x2f\x2f\x77\x77\
-\x77\x2e\x77\x33\x2e\x6f\x72\x67\x2f\x47\x72\x61\x70\x68\x69\x63\
-\x73\x2f\x53\x56\x47\x2f\x31\x2e\x31\x2f\x44\x54\x44\x2f\x73\x76\
-\x67\x31\x31\x2e\x64\x74\x64\x22\x3e\x0d\x0a\x3c\x73\x76\x67\x20\
-\x76\x65\x72\x73\x69\x6f\x6e\x3d\x22\x31\x2e\x31\x22\x20\x69\x64\
-\x3d\x22\x4c\x61\x79\x65\x72\x5f\x31\x22\x20\x78\x6d\x6c\x6e\x73\
-\x3d\x22\x68\x74\x74\x70\x3a\x2f\x2f\x77\x77\x77\x2e\x77\x33\x2e\
-\x6f\x72\x67\x2f\x32\x30\x30\x30\x2f\x73\x76\x67\x22\x20\x78\x6d\
-\x6c\x6e\x73\x3a\x78\x6c\x69\x6e\x6b\x3d\x22\x68\x74\x74\x70\x3a\
-\x2f\x2f\x77\x77\x77\x2e\x77\x33\x2e\x6f\x72\x67\x2f\x31\x39\x39\
-\x39\x2f\x78\x6c\x69\x6e\x6b\x22\x20\x78\x3d\x22\x30\x70\x78\x22\
-\x20\x79\x3d\x22\x30\x70\x78\x22\x0d\x0a\x09\x20\x77\x69\x64\x74\
-\x68\x3d\x22\x35\x31\x32\x70\x78\x22\x20\x68\x65\x69\x67\x68\x74\
-\x3d\x22\x35\x31\x32\x70\x78\x22\x20\x76\x69\x65\x77\x42\x6f\x78\
-\x3d\x22\x30\x20\x30\x20\x35\x31\x32\x20\x35\x31\x32\x22\x20\x73\
-\x74\x79\x6c\x65\x3d\x22\x65\x6e\x61\x62\x6c\x65\x2d\x62\x61\x63\
-\x6b\x67\x72\x6f\x75\x6e\x64\x3a\x6e\x65\x77\x20\x30\x20\x30\x20\
-\x35\x31\x32\x20\x35\x31\x32\x3b\x22\x20\x78\x6d\x6c\x3a\x73\x70\
-\x61\x63\x65\x3d\x22\x70\x72\x65\x73\x65\x72\x76\x65\x22\x3e\x0d\
-\x0a\x3c\x70\x61\x74\x68\x20\x64\x3d\x22\x4d\x34\x33\x37\x2e\x35\
-\x2c\x33\x38\x36\x2e\x36\x4c\x33\x30\x36\x2e\x39\x2c\x32\x35\x36\
-\x6c\x31\x33\x30\x2e\x36\x2d\x31\x33\x30\x2e\x36\x63\x31\x34\x2e\
-\x31\x2d\x31\x34\x2e\x31\x2c\x31\x34\x2e\x31\x2d\x33\x36\x2e\x38\
-\x2c\x30\x2d\x35\x30\x2e\x39\x63\x2d\x31\x34\x2e\x31\x2d\x31\x34\
-\x2e\x31\x2d\x33\x36\x2e\x38\x2d\x31\x34\x2e\x31\x2d\x35\x30\x2e\
-\x39\x2c\x30\x4c\x32\x35\x36\x2c\x32\x30\x35\x2e\x31\x4c\x31\x32\
-\x35\x2e\x34\x2c\x37\x34\x2e\x35\x0d\x0a\x09\x63\x2d\x31\x34\x2e\
-\x31\x2d\x31\x34\x2e\x31\x2d\x33\x36\x2e\x38\x2d\x31\x34\x2e\x31\
-\x2d\x35\x30\x2e\x39\x2c\x30\x63\x2d\x31\x34\x2e\x31\x2c\x31\x34\
-\x2e\x31\x2d\x31\x34\x2e\x31\x2c\x33\x36\x2e\x38\x2c\x30\x2c\x35\
-\x30\x2e\x39\x4c\x32\x30\x35\x2e\x31\x2c\x32\x35\x36\x4c\x37\x34\
-\x2e\x35\x2c\x33\x38\x36\x2e\x36\x63\x2d\x31\x34\x2e\x31\x2c\x31\
-\x34\x2e\x31\x2d\x31\x34\x2e\x31\x2c\x33\x36\x2e\x38\x2c\x30\x2c\
-\x35\x30\x2e\x39\x0d\x0a\x09\x63\x31\x34\x2e\x31\x2c\x31\x34\x2e\
-\x31\x2c\x33\x36\x2e\x38\x2c\x31\x34\x2e\x31\x2c\x35\x30\x2e\x39\
-\x2c\x30\x4c\x32\x35\x36\x2c\x33\x30\x36\x2e\x39\x6c\x31\x33\x30\
-\x2e\x36\x2c\x31\x33\x30\x2e\x36\x63\x31\x34\x2e\x31\x2c\x31\x34\
-\x2e\x31\x2c\x33\x36\x2e\x38\x2c\x31\x34\x2e\x31\x2c\x35\x30\x2e\
-\x39\x2c\x30\x43\x34\x35\x31\x2e\x35\x2c\x34\x32\x33\x2e\x34\x2c\
-\x34\x35\x31\x2e\x35\x2c\x34\x30\x30\x2e\x36\x2c\x34\x33\x37\x2e\
-\x35\x2c\x33\x38\x36\x2e\x36\x7a\x22\x2f\x3e\x0d\x0a\x3c\x2f\x73\
-\x76\x67\x3e\x0d\x0a\
-\x00\x00\x03\x26\
-\x3c\
-\x3f\x78\x6d\x6c\x20\x76\x65\x72\x73\x69\x6f\x6e\x3d\x22\x31\x2e\
-\x30\x22\x20\x65\x6e\x63\x6f\x64\x69\x6e\x67\x3d\x22\x75\x74\x66\
-\x2d\x38\x22\x3f\x3e\x0d\x0a\x3c\x21\x2d\x2d\x20\x47\x65\x6e\x65\
-\x72\x61\x74\x6f\x72\x3a\x20\x41\x64\x6f\x62\x65\x20\x49\x6c\x6c\
-\x75\x73\x74\x72\x61\x74\x6f\x72\x20\x31\x36\x2e\x32\x2e\x31\x2c\
-\x20\x53\x56\x47\x20\x45\x78\x70\x6f\x72\x74\x20\x50\x6c\x75\x67\
-\x2d\x49\x6e\x20\x2e\x20\x53\x56\x47\x20\x56\x65\x72\x73\x69\x6f\
-\x6e\x3a\x20\x36\x2e\x30\x30\x20\x42\x75\x69\x6c\x64\x20\x30\x29\
-\x20\x20\x2d\x2d\x3e\x0d\x0a\x3c\x21\x44\x4f\x43\x54\x59\x50\x45\
-\x20\x73\x76\x67\x20\x50\x55\x42\x4c\x49\x43\x20\x22\x2d\x2f\x2f\
-\x57\x33\x43\x2f\x2f\x44\x54\x44\x20\x53\x56\x47\x20\x31\x2e\x31\
-\x2f\x2f\x45\x4e\x22\x20\x22\x68\x74\x74\x70\x3a\x2f\x2f\x77\x77\
-\x77\x2e\x77\x33\x2e\x6f\x72\x67\x2f\x47\x72\x61\x70\x68\x69\x63\
-\x73\x2f\x53\x56\x47\x2f\x31\x2e\x31\x2f\x44\x54\x44\x2f\x73\x76\
-\x67\x31\x31\x2e\x64\x74\x64\x22\x3e\x0d\x0a\x3c\x73\x76\x67\x20\
-\x76\x65\x72\x73\x69\x6f\x6e\x3d\x22\x31\x2e\x31\x22\x20\x69\x64\
-\x3d\x22\x4c\x61\x79\x65\x72\x5f\x31\x22\x20\x78\x6d\x6c\x6e\x73\
-\x3d\x22\x68\x74\x74\x70\x3a\x2f\x2f\x77\x77\x77\x2e\x77\x33\x2e\
-\x6f\x72\x67\x2f\x32\x30\x30\x30\x2f\x73\x76\x67\x22\x20\x78\x6d\
-\x6c\x6e\x73\x3a\x78\x6c\x69\x6e\x6b\x3d\x22\x68\x74\x74\x70\x3a\
-\x2f\x2f\x77\x77\x77\x2e\x77\x33\x2e\x6f\x72\x67\x2f\x31\x39\x39\
-\x39\x2f\x78\x6c\x69\x6e\x6b\x22\x20\x78\x3d\x22\x30\x70\x78\x22\
-\x20\x79\x3d\x22\x30\x70\x78\x22\x0d\x0a\x09\x20\x77\x69\x64\x74\
-\x68\x3d\x22\x35\x31\x32\x70\x78\x22\x20\x68\x65\x69\x67\x68\x74\
-\x3d\x22\x35\x31\x32\x70\x78\x22\x20\x76\x69\x65\x77\x42\x6f\x78\
-\x3d\x22\x30\x20\x30\x20\x35\x31\x32\x20\x35\x31\x32\x22\x20\x65\
-\x6e\x61\x62\x6c\x65\x2d\x62\x61\x63\x6b\x67\x72\x6f\x75\x6e\x64\
-\x3d\x22\x6e\x65\x77\x20\x30\x20\x30\x20\x35\x31\x32\x20\x35\x31\
-\x32\x22\x20\x78\x6d\x6c\x3a\x73\x70\x61\x63\x65\x3d\x22\x70\x72\
-\x65\x73\x65\x72\x76\x65\x22\x3e\x0d\x0a\x3c\x67\x3e\x0d\x0a\x09\
-\x3c\x70\x61\x74\x68\x20\x64\x3d\x22\x4d\x32\x35\x36\x2c\x33\x38\
-\x38\x63\x2d\x37\x32\x2e\x35\x39\x37\x2c\x30\x2d\x31\x33\x32\x2d\
-\x35\x39\x2e\x34\x30\x35\x2d\x31\x33\x32\x2d\x31\x33\x32\x63\x30\
-\x2d\x37\x32\x2e\x36\x30\x31\x2c\x35\x39\x2e\x34\x30\x33\x2d\x31\
-\x33\x32\x2c\x31\x33\x32\x2d\x31\x33\x32\x63\x33\x36\x2e\x33\x2c\
-\x30\x2c\x36\x39\x2e\x32\x39\x39\x2c\x31\x35\x2e\x34\x2c\x39\x32\
-\x2e\x34\x30\x36\x2c\x33\x39\x2e\x36\x30\x31\x4c\x32\x37\x38\x2c\
-\x32\x33\x34\x68\x31\x35\x34\x56\x38\x30\x0d\x0a\x09\x09\x6c\x2d\
-\x35\x31\x2e\x36\x39\x38\x2c\x35\x31\x2e\x37\x30\x32\x43\x33\x34\
-\x38\x2e\x34\x30\x36\x2c\x39\x39\x2e\x37\x39\x38\x2c\x33\x30\x34\
-\x2e\x34\x30\x36\x2c\x38\x30\x2c\x32\x35\x36\x2c\x38\x30\x63\x2d\
-\x39\x36\x2e\x37\x39\x37\x2c\x30\x2d\x31\x37\x36\x2c\x37\x39\x2e\
-\x32\x30\x33\x2d\x31\x37\x36\x2c\x31\x37\x36\x73\x37\x38\x2e\x30\
-\x39\x34\x2c\x31\x37\x36\x2c\x31\x37\x36\x2c\x31\x37\x36\x0d\x0a\
-\x09\x09\x63\x38\x31\x2e\x30\x34\x35\x2c\x30\x2c\x31\x34\x38\x2e\
-\x32\x38\x37\x2d\x35\x34\x2e\x31\x33\x34\x2c\x31\x36\x39\x2e\x34\
-\x30\x31\x2d\x31\x32\x38\x48\x33\x37\x38\x2e\x38\x35\x43\x33\x36\
-\x30\x2e\x31\x30\x35\x2c\x33\x35\x33\x2e\x35\x36\x31\x2c\x33\x31\
-\x31\x2e\x37\x31\x32\x2c\x33\x38\x38\x2c\x32\x35\x36\x2c\x33\x38\
-\x38\x7a\x22\x2f\x3e\x0d\x0a\x3c\x2f\x67\x3e\x0d\x0a\x3c\x2f\x73\
-\x76\x67\x3e\x0d\x0a\
-\x00\x00\x05\xd4\
-\x3c\
-\x3f\x78\x6d\x6c\x20\x76\x65\x72\x73\x69\x6f\x6e\x3d\x27\x31\x2e\
-\x30\x27\x20\x65\x6e\x63\x6f\x64\x69\x6e\x67\x3d\x27\x55\x54\x46\
-\x2d\x38\x27\x3f\x3e\x0a\x3c\x21\x2d\x2d\x20\x54\x68\x69\x73\x20\
-\x66\x69\x6c\x65\x20\x77\x61\x73\x20\x67\x65\x6e\x65\x72\x61\x74\
-\x65\x64\x20\x62\x79\x20\x64\x76\x69\x73\x76\x67\x6d\x20\x32\x2e\
-\x38\x20\x2d\x2d\x3e\x0a\x3c\x73\x76\x67\x20\x76\x65\x72\x73\x69\
-\x6f\x6e\x3d\x27\x31\x2e\x31\x27\x20\x78\x6d\x6c\x6e\x73\x3d\x27\
-\x68\x74\x74\x70\x3a\x2f\x2f\x77\x77\x77\x2e\x77\x33\x2e\x6f\x72\
-\x67\x2f\x32\x30\x30\x30\x2f\x73\x76\x67\x27\x20\x78\x6d\x6c\x6e\
-\x73\x3a\x78\x6c\x69\x6e\x6b\x3d\x27\x68\x74\x74\x70\x3a\x2f\x2f\
-\x77\x77\x77\x2e\x77\x33\x2e\x6f\x72\x67\x2f\x31\x39\x39\x39\x2f\
-\x78\x6c\x69\x6e\x6b\x27\x20\x77\x69\x64\x74\x68\x3d\x27\x36\x33\
-\x2e\x39\x39\x39\x36\x70\x74\x27\x20\x68\x65\x69\x67\x68\x74\x3d\
-\x27\x36\x33\x2e\x39\x39\x39\x37\x70\x74\x27\x20\x76\x69\x65\x77\
-\x42\x6f\x78\x3d\x27\x35\x36\x2e\x34\x30\x39\x34\x20\x35\x33\x2e\
-\x38\x35\x38\x33\x20\x36\x33\x2e\x39\x39\x39\x36\x20\x36\x33\x2e\
-\x39\x39\x39\x37\x27\x3e\x0a\x3c\x67\x20\x69\x64\x3d\x27\x70\x61\
-\x67\x65\x31\x27\x3e\x0a\x3c\x67\x20\x74\x72\x61\x6e\x73\x66\x6f\
-\x72\x6d\x3d\x27\x6d\x61\x74\x72\x69\x78\x28\x30\x2e\x39\x39\x36\
-\x32\x36\x34\x20\x30\x20\x30\x20\x30\x2e\x39\x39\x36\x32\x36\x34\
-\x20\x35\x36\x2e\x34\x30\x39\x34\x20\x31\x31\x37\x2e\x38\x35\x38\
-\x29\x27\x3e\x0a\x3c\x70\x61\x74\x68\x20\x64\x3d\x27\x4d\x20\x35\
-\x34\x2e\x38\x39\x32\x36\x20\x2d\x33\x39\x2e\x37\x31\x30\x39\x43\
-\x20\x35\x34\x2e\x38\x39\x32\x36\x20\x2d\x34\x33\x2e\x39\x30\x33\
-\x32\x20\x34\x34\x2e\x36\x39\x36\x39\x20\x2d\x34\x37\x2e\x33\x30\
-\x31\x37\x20\x33\x32\x2e\x31\x32\x20\x2d\x34\x37\x2e\x33\x30\x31\
-\x37\x43\x20\x31\x39\x2e\x35\x34\x33\x31\x20\x2d\x34\x37\x2e\x33\
-\x30\x31\x37\x20\x39\x2e\x33\x34\x37\x34\x32\x20\x2d\x34\x33\x2e\
-\x39\x30\x33\x32\x20\x39\x2e\x33\x34\x37\x34\x32\x20\x2d\x33\x39\
-\x2e\x37\x31\x30\x39\x43\x20\x39\x2e\x33\x34\x37\x34\x32\x20\x2d\
-\x33\x35\x2e\x35\x31\x38\x35\x20\x31\x39\x2e\x35\x34\x33\x31\x20\
-\x2d\x33\x32\x2e\x31\x32\x20\x33\x32\x2e\x31\x32\x20\x2d\x33\x32\
-\x2e\x31\x32\x43\x20\x34\x34\x2e\x36\x39\x36\x39\x20\x2d\x33\x32\
-\x2e\x31\x32\x20\x35\x34\x2e\x38\x39\x32\x36\x20\x2d\x33\x35\x2e\
-\x35\x31\x38\x35\x20\x35\x34\x2e\x38\x39\x32\x36\x20\x2d\x33\x39\
-\x2e\x37\x31\x30\x39\x5a\x27\x20\x66\x69\x6c\x6c\x3d\x27\x6e\x6f\
-\x6e\x65\x27\x20\x73\x74\x72\x6f\x6b\x65\x3d\x27\x23\x30\x30\x30\
-\x30\x30\x30\x27\x20\x73\x74\x72\x6f\x6b\x65\x2d\x6c\x69\x6e\x65\
-\x63\x61\x70\x3d\x27\x72\x6f\x75\x6e\x64\x27\x20\x73\x74\x72\x6f\
-\x6b\x65\x2d\x6c\x69\x6e\x65\x6a\x6f\x69\x6e\x3d\x27\x72\x6f\x75\
-\x6e\x64\x27\x20\x73\x74\x72\x6f\x6b\x65\x2d\x6d\x69\x74\x65\x72\
-\x6c\x69\x6d\x69\x74\x3d\x27\x31\x30\x2e\x30\x33\x37\x35\x27\x20\
-\x73\x74\x72\x6f\x6b\x65\x2d\x77\x69\x64\x74\x68\x3d\x27\x33\x2e\
-\x35\x31\x33\x31\x32\x27\x2f\x3e\x0a\x3c\x2f\x67\x3e\x0a\x3c\x67\
-\x20\x74\x72\x61\x6e\x73\x66\x6f\x72\x6d\x3d\x27\x6d\x61\x74\x72\
-\x69\x78\x28\x30\x2e\x39\x39\x36\x32\x36\x34\x20\x30\x20\x30\x20\
-\x30\x2e\x39\x39\x36\x32\x36\x34\x20\x35\x36\x2e\x34\x30\x39\x34\
-\x20\x31\x31\x37\x2e\x38\x35\x38\x29\x27\x3e\x0a\x3c\x70\x61\x74\
-\x68\x20\x64\x3d\x27\x4d\x20\x39\x2e\x33\x34\x37\x34\x32\x20\x2d\
-\x33\x39\x2e\x37\x31\x30\x39\x4c\x20\x39\x2e\x33\x34\x37\x34\x32\
-\x20\x2d\x39\x2e\x33\x34\x37\x34\x32\x4c\x20\x39\x2e\x33\x34\x37\
-\x34\x32\x20\x2d\x39\x2e\x33\x34\x37\x34\x32\x43\x20\x39\x2e\x33\
-\x34\x37\x34\x32\x20\x2d\x39\x2e\x33\x34\x37\x34\x32\x20\x39\x2e\
-\x33\x34\x37\x34\x32\x20\x2d\x39\x2e\x33\x34\x37\x34\x32\x20\x39\
-\x2e\x33\x34\x37\x34\x32\x20\x2d\x39\x2e\x33\x34\x37\x34\x32\x43\
-\x20\x39\x2e\x33\x34\x37\x34\x32\x20\x2d\x35\x2e\x31\x35\x35\x31\
-\x31\x20\x31\x39\x2e\x35\x34\x33\x31\x20\x2d\x31\x2e\x37\x35\x36\
-\x35\x36\x20\x33\x32\x2e\x31\x32\x20\x2d\x31\x2e\x37\x35\x36\x35\
-\x36\x43\x20\x34\x34\x2e\x36\x39\x36\x39\x20\x2d\x31\x2e\x37\x35\
-\x36\x35\x36\x20\x35\x34\x2e\x38\x39\x32\x36\x20\x2d\x35\x2e\x31\
-\x35\x35\x31\x31\x20\x35\x34\x2e\x38\x39\x32\x36\x20\x2d\x39\x2e\
-\x33\x34\x37\x34\x32\x4c\x20\x35\x34\x2e\x38\x39\x32\x36\x20\x2d\
-\x39\x2e\x33\x34\x37\x34\x32\x4c\x20\x35\x34\x2e\x38\x39\x32\x36\
-\x20\x2d\x33\x39\x2e\x37\x31\x30\x39\x27\x20\x66\x69\x6c\x6c\x3d\
-\x27\x6e\x6f\x6e\x65\x27\x20\x73\x74\x72\x6f\x6b\x65\x3d\x27\x23\
-\x30\x30\x30\x30\x30\x30\x27\x20\x73\x74\x72\x6f\x6b\x65\x2d\x6c\
-\x69\x6e\x65\x63\x61\x70\x3d\x27\x72\x6f\x75\x6e\x64\x27\x20\x73\
-\x74\x72\x6f\x6b\x65\x2d\x6c\x69\x6e\x65\x6a\x6f\x69\x6e\x3d\x27\
-\x72\x6f\x75\x6e\x64\x27\x20\x73\x74\x72\x6f\x6b\x65\x2d\x6d\x69\
-\x74\x65\x72\x6c\x69\x6d\x69\x74\x3d\x27\x31\x30\x2e\x30\x33\x37\
-\x35\x27\x20\x73\x74\x72\x6f\x6b\x65\x2d\x77\x69\x64\x74\x68\x3d\
-\x27\x33\x2e\x35\x31\x33\x31\x32\x27\x2f\x3e\x0a\x3c\x2f\x67\x3e\
-\x0a\x3c\x67\x20\x74\x72\x61\x6e\x73\x66\x6f\x72\x6d\x3d\x27\x6d\
-\x61\x74\x72\x69\x78\x28\x30\x2e\x39\x39\x36\x32\x36\x34\x20\x30\
-\x20\x30\x20\x30\x2e\x39\x39\x36\x32\x36\x34\x20\x35\x36\x2e\x34\
-\x30\x39\x34\x20\x31\x31\x37\x2e\x38\x35\x38\x29\x27\x3e\x0a\x3c\
-\x70\x61\x74\x68\x20\x64\x3d\x27\x4d\x20\x35\x34\x2e\x38\x39\x32\
-\x36\x20\x2d\x33\x39\x2e\x37\x31\x30\x39\x43\x20\x35\x34\x2e\x38\
-\x39\x32\x36\x20\x2d\x35\x32\x2e\x32\x38\x37\x38\x20\x34\x34\x2e\
-\x36\x39\x36\x39\x20\x2d\x36\x32\x2e\x34\x38\x33\x34\x20\x33\x32\
-\x2e\x31\x32\x20\x2d\x36\x32\x2e\x34\x38\x33\x34\x43\x20\x31\x39\
-\x2e\x35\x34\x33\x31\x20\x2d\x36\x32\x2e\x34\x38\x33\x34\x20\x39\
-\x2e\x33\x34\x37\x34\x32\x20\x2d\x35\x32\x2e\x32\x38\x37\x38\x20\
-\x39\x2e\x33\x34\x37\x34\x32\x20\x2d\x33\x39\x2e\x37\x31\x30\x39\
-\x27\x20\x66\x69\x6c\x6c\x3d\x27\x6e\x6f\x6e\x65\x27\x20\x73\x74\
-\x72\x6f\x6b\x65\x3d\x27\x23\x30\x30\x30\x30\x30\x30\x27\x20\x73\
-\x74\x72\x6f\x6b\x65\x2d\x6c\x69\x6e\x65\x63\x61\x70\x3d\x27\x72\
-\x6f\x75\x6e\x64\x27\x20\x73\x74\x72\x6f\x6b\x65\x2d\x6c\x69\x6e\
-\x65\x6a\x6f\x69\x6e\x3d\x27\x72\x6f\x75\x6e\x64\x27\x20\x73\x74\
-\x72\x6f\x6b\x65\x2d\x6d\x69\x74\x65\x72\x6c\x69\x6d\x69\x74\x3d\
-\x27\x31\x30\x2e\x30\x33\x37\x35\x27\x20\x73\x74\x72\x6f\x6b\x65\
-\x2d\x77\x69\x64\x74\x68\x3d\x27\x33\x2e\x35\x31\x33\x31\x32\x27\
-\x2f\x3e\x0a\x3c\x2f\x67\x3e\x0a\x3c\x2f\x67\x3e\x0a\x3c\x2f\x73\
-\x76\x67\x3e\
-\x00\x00\x03\xe6\
-\x3c\
-\x3f\x78\x6d\x6c\x20\x76\x65\x72\x73\x69\x6f\x6e\x3d\x22\x31\x2e\
-\x30\x22\x20\x65\x6e\x63\x6f\x64\x69\x6e\x67\x3d\x22\x75\x74\x66\
-\x2d\x38\x22\x3f\x3e\x0d\x0a\x3c\x21\x2d\x2d\x20\x47\x65\x6e\x65\
-\x72\x61\x74\x6f\x72\x3a\x20\x41\x64\x6f\x62\x65\x20\x49\x6c\x6c\
-\x75\x73\x74\x72\x61\x74\x6f\x72\x20\x31\x38\x2e\x31\x2e\x31\x2c\
-\x20\x53\x56\x47\x20\x45\x78\x70\x6f\x72\x74\x20\x50\x6c\x75\x67\
-\x2d\x49\x6e\x20\x2e\x20\x53\x56\x47\x20\x56\x65\x72\x73\x69\x6f\
-\x6e\x3a\x20\x36\x2e\x30\x30\x20\x42\x75\x69\x6c\x64\x20\x30\x29\
-\x20\x20\x2d\x2d\x3e\x0d\x0a\x3c\x21\x44\x4f\x43\x54\x59\x50\x45\
-\x20\x73\x76\x67\x20\x50\x55\x42\x4c\x49\x43\x20\x22\x2d\x2f\x2f\
-\x57\x33\x43\x2f\x2f\x44\x54\x44\x20\x53\x56\x47\x20\x31\x2e\x31\
-\x2f\x2f\x45\x4e\x22\x20\x22\x68\x74\x74\x70\x3a\x2f\x2f\x77\x77\
-\x77\x2e\x77\x33\x2e\x6f\x72\x67\x2f\x47\x72\x61\x70\x68\x69\x63\
-\x73\x2f\x53\x56\x47\x2f\x31\x2e\x31\x2f\x44\x54\x44\x2f\x73\x76\
-\x67\x31\x31\x2e\x64\x74\x64\x22\x3e\x0d\x0a\x3c\x73\x76\x67\x20\
-\x76\x65\x72\x73\x69\x6f\x6e\x3d\x22\x31\x2e\x31\x22\x20\x69\x64\
-\x3d\x22\x43\x68\x65\x76\x72\x6f\x6e\x5f\x63\x69\x72\x63\x6c\x65\
-\x64\x5f\x72\x69\x67\x68\x74\x22\x20\x78\x6d\x6c\x6e\x73\x3d\x22\
-\x68\x74\x74\x70\x3a\x2f\x2f\x77\x77\x77\x2e\x77\x33\x2e\x6f\x72\
-\x67\x2f\x32\x30\x30\x30\x2f\x73\x76\x67\x22\x20\x78\x6d\x6c\x6e\
-\x73\x3a\x78\x6c\x69\x6e\x6b\x3d\x22\x68\x74\x74\x70\x3a\x2f\x2f\
-\x77\x77\x77\x2e\x77\x33\x2e\x6f\x72\x67\x2f\x31\x39\x39\x39\x2f\
-\x78\x6c\x69\x6e\x6b\x22\x0d\x0a\x09\x20\x78\x3d\x22\x30\x70\x78\
-\x22\x20\x79\x3d\x22\x30\x70\x78\x22\x20\x76\x69\x65\x77\x42\x6f\
-\x78\x3d\x22\x30\x20\x30\x20\x35\x31\x32\x20\x35\x31\x32\x22\x20\
-\x65\x6e\x61\x62\x6c\x65\x2d\x62\x61\x63\x6b\x67\x72\x6f\x75\x6e\
-\x64\x3d\x22\x6e\x65\x77\x20\x30\x20\x30\x20\x35\x31\x32\x20\x35\
-\x31\x32\x22\x20\x78\x6d\x6c\x3a\x73\x70\x61\x63\x65\x3d\x22\x70\
-\x72\x65\x73\x65\x72\x76\x65\x22\x3e\x0d\x0a\x3c\x67\x20\x74\x72\
-\x61\x6e\x73\x66\x6f\x72\x6d\x3d\x27\x6d\x61\x74\x72\x69\x78\x28\
-\x32\x34\x20\x30\x20\x30\x20\x32\x34\x20\x30\x20\x30\x29\x27\x3e\
-\x0d\x0a\x3c\x70\x61\x74\x68\x20\x64\x3d\x22\x4d\x31\x31\x2c\x31\
-\x30\x4c\x38\x2e\x36\x39\x38\x2c\x37\x2e\x34\x39\x34\x63\x2d\x30\
-\x2e\x31\x39\x36\x2d\x30\x2e\x31\x39\x38\x2d\x30\x2e\x31\x39\x36\
-\x2d\x30\x2e\x35\x31\x39\x2c\x30\x2d\x30\x2e\x37\x31\x38\x63\x30\
-\x2e\x31\x39\x36\x2d\x30\x2e\x31\x39\x37\x2c\x30\x2e\x35\x31\x35\
-\x2d\x30\x2e\x31\x39\x37\x2c\x30\x2e\x37\x31\x2c\x30\x6c\x32\x2e\
-\x38\x30\x37\x2c\x32\x2e\x38\x36\x34\x0d\x0a\x09\x63\x30\x2e\x31\
-\x39\x36\x2c\x30\x2e\x31\x39\x39\x2c\x30\x2e\x31\x39\x36\x2c\x30\
-\x2e\x35\x32\x2c\x30\x2c\x30\x2e\x37\x31\x37\x6c\x2d\x32\x2e\x38\
-\x30\x37\x2c\x32\x2e\x38\x36\x34\x63\x2d\x30\x2e\x31\x39\x35\x2c\
-\x30\x2e\x31\x39\x39\x2d\x30\x2e\x35\x31\x34\x2c\x30\x2e\x31\x39\
-\x38\x2d\x30\x2e\x37\x31\x2c\x30\x63\x2d\x30\x2e\x31\x39\x36\x2d\
-\x30\x2e\x31\x39\x37\x2d\x30\x2e\x31\x39\x36\x2d\x30\x2e\x35\x31\
-\x38\x2c\x30\x2d\x30\x2e\x37\x31\x37\x4c\x31\x31\x2c\x31\x30\x7a\
-\x20\x4d\x31\x30\x2c\x30\x2e\x34\x0d\x0a\x09\x63\x35\x2e\x33\x30\
-\x32\x2c\x30\x2c\x39\x2e\x36\x2c\x34\x2e\x32\x39\x38\x2c\x39\x2e\
-\x36\x2c\x39\x2e\x36\x63\x30\x2c\x35\x2e\x33\x30\x33\x2d\x34\x2e\
-\x32\x39\x38\x2c\x39\x2e\x36\x2d\x39\x2e\x36\x2c\x39\x2e\x36\x53\
-\x30\x2e\x34\x2c\x31\x35\x2e\x33\x30\x33\x2c\x30\x2e\x34\x2c\x31\
-\x30\x43\x30\x2e\x34\x2c\x34\x2e\x36\x39\x38\x2c\x34\x2e\x36\x39\
-\x38\x2c\x30\x2e\x34\x2c\x31\x30\x2c\x30\x2e\x34\x7a\x20\x4d\x31\
-\x30\x2c\x31\x38\x2e\x33\x35\x34\x0d\x0a\x09\x63\x34\x2e\x36\x31\
-\x33\x2c\x30\x2c\x38\x2e\x33\x35\x34\x2d\x33\x2e\x37\x34\x2c\x38\
-\x2e\x33\x35\x34\x2d\x38\x2e\x33\x35\x34\x63\x30\x2d\x34\x2e\x36\
-\x31\x34\x2d\x33\x2e\x37\x34\x31\x2d\x38\x2e\x33\x35\x34\x2d\x38\
-\x2e\x33\x35\x34\x2d\x38\x2e\x33\x35\x34\x63\x2d\x34\x2e\x36\x31\
-\x35\x2c\x30\x2d\x38\x2e\x33\x35\x34\x2c\x33\x2e\x37\x34\x2d\x38\
-\x2e\x33\x35\x34\x2c\x38\x2e\x33\x35\x34\x0d\x0a\x09\x43\x31\x2e\
-\x36\x34\x35\x2c\x31\x34\x2e\x36\x31\x34\x2c\x35\x2e\x33\x38\x35\
-\x2c\x31\x38\x2e\x33\x35\x34\x2c\x31\x30\x2c\x31\x38\x2e\x33\x35\
-\x34\x7a\x22\x2f\x3e\x0d\x0a\x3c\x2f\x67\x3e\x0d\x0a\x3c\x2f\x73\
-\x76\x67\x3e\x0d\x0a\
-\x00\x00\x01\x1c\
-\x3c\
-\x73\x76\x67\x20\x78\x6d\x6c\x6e\x73\x3d\x22\x68\x74\x74\x70\x3a\
-\x2f\x2f\x77\x77\x77\x2e\x77\x33\x2e\x6f\x72\x67\x2f\x32\x30\x30\
-\x30\x2f\x73\x76\x67\x22\x20\x77\x69\x64\x74\x68\x3d\x22\x35\x31\
-\x32\x70\x78\x22\x20\x68\x65\x69\x67\x68\x74\x3d\x22\x35\x31\x32\
-\x70\x78\x22\x0a\x20\x20\x20\x20\x20\x76\x69\x65\x77\x42\x6f\x78\
-\x3d\x22\x30\x20\x30\x20\x35\x31\x32\x20\x35\x31\x32\x22\x3e\x0a\
-\x3c\x67\x20\x74\x72\x61\x6e\x73\x66\x6f\x72\x6d\x3d\x27\x6d\x61\
-\x74\x72\x69\x78\x28\x34\x38\x20\x30\x20\x30\x20\x34\x38\x20\x34\
-\x38\x20\x34\x38\x29\x27\x3e\x0a\x20\x20\x3c\x70\x61\x74\x68\x20\
-\x64\x3d\x22\x4d\x30\x20\x30\x76\x32\x68\x2e\x35\x63\x30\x2d\x2e\
-\x35\x35\x2e\x34\x35\x2d\x31\x20\x31\x2d\x31\x68\x31\x2e\x35\x76\
-\x35\x2e\x35\x63\x30\x20\x2e\x32\x38\x2d\x2e\x32\x32\x2e\x35\x2d\
-\x2e\x35\x2e\x35\x68\x2d\x2e\x35\x76\x31\x68\x34\x76\x2d\x31\x68\
-\x2d\x2e\x35\x63\x2d\x2e\x32\x38\x20\x30\x2d\x2e\x35\x2d\x2e\x32\
-\x32\x2d\x2e\x35\x2d\x2e\x35\x76\x2d\x35\x2e\x35\x68\x31\x2e\x35\
-\x63\x2e\x35\x35\x20\x30\x20\x31\x20\x2e\x34\x35\x20\x31\x20\x31\
-\x68\x2e\x35\x76\x2d\x32\x68\x2d\x38\x7a\x22\x20\x2f\x3e\x0a\x3c\
-\x2f\x67\x3e\x0a\x3c\x2f\x73\x76\x67\x3e\x0a\
-\x00\x00\x04\x64\
-\x3c\
-\x3f\x78\x6d\x6c\x20\x76\x65\x72\x73\x69\x6f\x6e\x3d\x22\x31\x2e\
-\x30\x22\x20\x65\x6e\x63\x6f\x64\x69\x6e\x67\x3d\x22\x75\x74\x66\
-\x2d\x38\x22\x3f\x3e\x0d\x0a\x3c\x21\x2d\x2d\x20\x47\x65\x6e\x65\
-\x72\x61\x74\x6f\x72\x3a\x20\x41\x64\x6f\x62\x65\x20\x49\x6c\x6c\
-\x75\x73\x74\x72\x61\x74\x6f\x72\x20\x31\x36\x2e\x32\x2e\x31\x2c\
-\x20\x53\x56\x47\x20\x45\x78\x70\x6f\x72\x74\x20\x50\x6c\x75\x67\
-\x2d\x49\x6e\x20\x2e\x20\x53\x56\x47\x20\x56\x65\x72\x73\x69\x6f\
-\x6e\x3a\x20\x36\x2e\x30\x30\x20\x42\x75\x69\x6c\x64\x20\x30\x29\
-\x20\x20\x2d\x2d\x3e\x0d\x0a\x3c\x21\x44\x4f\x43\x54\x59\x50\x45\
-\x20\x73\x76\x67\x20\x50\x55\x42\x4c\x49\x43\x20\x22\x2d\x2f\x2f\
-\x57\x33\x43\x2f\x2f\x44\x54\x44\x20\x53\x56\x47\x20\x31\x2e\x31\
-\x2f\x2f\x45\x4e\x22\x20\x22\x68\x74\x74\x70\x3a\x2f\x2f\x77\x77\
-\x77\x2e\x77\x33\x2e\x6f\x72\x67\x2f\x47\x72\x61\x70\x68\x69\x63\
-\x73\x2f\x53\x56\x47\x2f\x31\x2e\x31\x2f\x44\x54\x44\x2f\x73\x76\
-\x67\x31\x31\x2e\x64\x74\x64\x22\x3e\x0d\x0a\x3c\x73\x76\x67\x20\
-\x76\x65\x72\x73\x69\x6f\x6e\x3d\x22\x31\x2e\x31\x22\x20\x69\x64\
-\x3d\x22\x4c\x61\x79\x65\x72\x5f\x31\x22\x20\x78\x6d\x6c\x6e\x73\
-\x3d\x22\x68\x74\x74\x70\x3a\x2f\x2f\x77\x77\x77\x2e\x77\x33\x2e\
-\x6f\x72\x67\x2f\x32\x30\x30\x30\x2f\x73\x76\x67\x22\x20\x78\x6d\
-\x6c\x6e\x73\x3a\x78\x6c\x69\x6e\x6b\x3d\x22\x68\x74\x74\x70\x3a\
-\x2f\x2f\x77\x77\x77\x2e\x77\x33\x2e\x6f\x72\x67\x2f\x31\x39\x39\
-\x39\x2f\x78\x6c\x69\x6e\x6b\x22\x20\x78\x3d\x22\x30\x70\x78\x22\
-\x20\x79\x3d\x22\x30\x70\x78\x22\x0d\x0a\x09\x20\x77\x69\x64\x74\
-\x68\x3d\x22\x35\x31\x32\x70\x78\x22\x20\x68\x65\x69\x67\x68\x74\
-\x3d\x22\x35\x31\x32\x70\x78\x22\x20\x76\x69\x65\x77\x42\x6f\x78\
-\x3d\x22\x30\x20\x30\x20\x35\x31\x32\x20\x35\x31\x32\x22\x20\x65\
-\x6e\x61\x62\x6c\x65\x2d\x62\x61\x63\x6b\x67\x72\x6f\x75\x6e\x64\
-\x3d\x22\x6e\x65\x77\x20\x30\x20\x30\x20\x35\x31\x32\x20\x35\x31\
-\x32\x22\x20\x78\x6d\x6c\x3a\x73\x70\x61\x63\x65\x3d\x22\x70\x72\
-\x65\x73\x65\x72\x76\x65\x22\x3e\x0d\x0a\x3c\x67\x20\x69\x64\x3d\
-\x22\x49\x63\x6f\x6e\x22\x3e\x0d\x0a\x09\x3c\x67\x3e\x0d\x0a\x09\
-\x09\x3c\x70\x61\x74\x68\x20\x64\x3d\x22\x4d\x32\x35\x36\x2c\x31\
-\x37\x36\x63\x2d\x34\x34\x2e\x30\x30\x34\x2c\x30\x2d\x38\x30\x2e\
-\x30\x30\x31\x2c\x33\x36\x2d\x38\x30\x2e\x30\x30\x31\x2c\x38\x30\
-\x63\x30\x2c\x34\x34\x2e\x30\x30\x34\x2c\x33\x35\x2e\x39\x39\x37\
-\x2c\x38\x30\x2c\x38\x30\x2e\x30\x30\x31\x2c\x38\x30\x63\x34\x34\
-\x2e\x30\x30\x35\x2c\x30\x2c\x37\x39\x2e\x39\x39\x39\x2d\x33\x35\
-\x2e\x39\x39\x36\x2c\x37\x39\x2e\x39\x39\x39\x2d\x38\x30\x0d\x0a\
-\x09\x09\x09\x43\x33\x33\x35\x2e\x39\x39\x39\x2c\x32\x31\x32\x2c\
-\x33\x30\x30\x2e\x30\x30\x35\x2c\x31\x37\x36\x2c\x32\x35\x36\x2c\
-\x31\x37\x36\x7a\x20\x4d\x34\x34\x36\x2e\x39\x33\x38\x2c\x32\x33\
-\x34\x2e\x36\x36\x37\x63\x2d\x39\x2e\x36\x30\x35\x2d\x38\x38\x2e\
-\x35\x33\x31\x2d\x38\x31\x2e\x30\x37\x34\x2d\x31\x36\x30\x2d\x31\
-\x36\x39\x2e\x36\x30\x35\x2d\x31\x36\x39\x2e\x35\x39\x39\x56\x33\
-\x32\x68\x2d\x34\x32\x2e\x36\x36\x36\x76\x33\x33\x2e\x30\x36\x37\
-\x0d\x0a\x09\x09\x09\x63\x2d\x38\x38\x2e\x35\x33\x31\x2c\x39\x2e\
-\x35\x39\x39\x2d\x31\x36\x30\x2c\x38\x31\x2e\x30\x36\x38\x2d\x31\
-\x36\x39\x2e\x36\x30\x34\x2c\x31\x36\x39\x2e\x35\x39\x39\x48\x33\
-\x32\x76\x34\x32\x2e\x36\x36\x37\x68\x33\x33\x2e\x30\x36\x32\x63\
-\x39\x2e\x36\x30\x34\x2c\x38\x38\x2e\x35\x33\x31\x2c\x38\x31\x2e\
-\x30\x37\x32\x2c\x31\x36\x30\x2c\x31\x36\x39\x2e\x36\x30\x34\x2c\
-\x31\x36\x39\x2e\x36\x30\x34\x56\x34\x38\x30\x68\x34\x32\x2e\x36\
-\x36\x36\x76\x2d\x33\x33\x2e\x30\x36\x32\x0d\x0a\x09\x09\x09\x63\
-\x38\x38\x2e\x35\x33\x31\x2d\x39\x2e\x36\x30\x34\x2c\x31\x36\x30\
-\x2d\x38\x31\x2e\x30\x37\x33\x2c\x31\x36\x39\x2e\x36\x30\x35\x2d\
-\x31\x36\x39\x2e\x36\x30\x34\x48\x34\x38\x30\x76\x2d\x34\x32\x2e\
-\x36\x36\x37\x48\x34\x34\x36\x2e\x39\x33\x38\x7a\x20\x4d\x32\x35\
-\x36\x2c\x34\x30\x35\x2e\x33\x33\x33\x63\x2d\x38\x32\x2e\x31\x33\
-\x37\x2c\x30\x2d\x31\x34\x39\x2e\x33\x33\x34\x2d\x36\x37\x2e\x31\
-\x39\x38\x2d\x31\x34\x39\x2e\x33\x33\x34\x2d\x31\x34\x39\x2e\x33\
-\x33\x33\x0d\x0a\x09\x09\x09\x63\x30\x2d\x38\x32\x2e\x31\x33\x36\
-\x2c\x36\x37\x2e\x31\x39\x37\x2d\x31\x34\x39\x2e\x33\x33\x33\x2c\
-\x31\x34\x39\x2e\x33\x33\x34\x2d\x31\x34\x39\x2e\x33\x33\x33\x63\
-\x38\x32\x2e\x31\x33\x35\x2c\x30\x2c\x31\x34\x39\x2e\x33\x33\x32\
-\x2c\x36\x37\x2e\x31\x39\x38\x2c\x31\x34\x39\x2e\x33\x33\x32\x2c\
-\x31\x34\x39\x2e\x33\x33\x33\x43\x34\x30\x35\x2e\x33\x33\x32\x2c\
-\x33\x33\x38\x2e\x31\x33\x35\x2c\x33\x33\x38\x2e\x31\x33\x35\x2c\
-\x34\x30\x35\x2e\x33\x33\x33\x2c\x32\x35\x36\x2c\x34\x30\x35\x2e\
-\x33\x33\x33\x7a\x0d\x0a\x09\x09\x09\x22\x2f\x3e\x0d\x0a\x09\x3c\
-\x2f\x67\x3e\x0d\x0a\x3c\x2f\x67\x3e\x0d\x0a\x3c\x2f\x73\x76\x67\
-\x3e\x0d\x0a\
-\x00\x00\x03\x36\
-\x3c\
-\x3f\x78\x6d\x6c\x20\x76\x65\x72\x73\x69\x6f\x6e\x3d\x22\x31\x2e\
-\x30\x22\x20\x65\x6e\x63\x6f\x64\x69\x6e\x67\x3d\x22\x75\x74\x66\
-\x2d\x38\x22\x3f\x3e\x0d\x0a\x3c\x21\x2d\x2d\x20\x47\x65\x6e\x65\
-\x72\x61\x74\x6f\x72\x3a\x20\x41\x64\x6f\x62\x65\x20\x49\x6c\x6c\
-\x75\x73\x74\x72\x61\x74\x6f\x72\x20\x31\x36\x2e\x32\x2e\x31\x2c\
-\x20\x53\x56\x47\x20\x45\x78\x70\x6f\x72\x74\x20\x50\x6c\x75\x67\
-\x2d\x49\x6e\x20\x2e\x20\x53\x56\x47\x20\x56\x65\x72\x73\x69\x6f\
-\x6e\x3a\x20\x36\x2e\x30\x30\x20\x42\x75\x69\x6c\x64\x20\x30\x29\
-\x20\x20\x2d\x2d\x3e\x0d\x0a\x3c\x21\x44\x4f\x43\x54\x59\x50\x45\
-\x20\x73\x76\x67\x20\x50\x55\x42\x4c\x49\x43\x20\x22\x2d\x2f\x2f\
-\x57\x33\x43\x2f\x2f\x44\x54\x44\x20\x53\x56\x47\x20\x31\x2e\x31\
-\x2f\x2f\x45\x4e\x22\x20\x22\x68\x74\x74\x70\x3a\x2f\x2f\x77\x77\
-\x77\x2e\x77\x33\x2e\x6f\x72\x67\x2f\x47\x72\x61\x70\x68\x69\x63\
-\x73\x2f\x53\x56\x47\x2f\x31\x2e\x31\x2f\x44\x54\x44\x2f\x73\x76\
-\x67\x31\x31\x2e\x64\x74\x64\x22\x3e\x0d\x0a\x3c\x73\x76\x67\x20\
-\x76\x65\x72\x73\x69\x6f\x6e\x3d\x22\x31\x2e\x31\x22\x20\x69\x64\
-\x3d\x22\x4c\x61\x79\x65\x72\x5f\x31\x22\x20\x78\x6d\x6c\x6e\x73\
-\x3d\x22\x68\x74\x74\x70\x3a\x2f\x2f\x77\x77\x77\x2e\x77\x33\x2e\
-\x6f\x72\x67\x2f\x32\x30\x30\x30\x2f\x73\x76\x67\x22\x20\x78\x6d\
-\x6c\x6e\x73\x3a\x78\x6c\x69\x6e\x6b\x3d\x22\x68\x74\x74\x70\x3a\
-\x2f\x2f\x77\x77\x77\x2e\x77\x33\x2e\x6f\x72\x67\x2f\x31\x39\x39\
-\x39\x2f\x78\x6c\x69\x6e\x6b\x22\x20\x78\x3d\x22\x30\x70\x78\x22\
-\x20\x79\x3d\x22\x30\x70\x78\x22\x0d\x0a\x09\x20\x77\x69\x64\x74\
-\x68\x3d\x22\x35\x31\x32\x70\x78\x22\x20\x68\x65\x69\x67\x68\x74\
-\x3d\x22\x35\x31\x32\x70\x78\x22\x20\x76\x69\x65\x77\x42\x6f\x78\
-\x3d\x22\x30\x20\x30\x20\x35\x31\x32\x20\x35\x31\x32\x22\x20\x65\
-\x6e\x61\x62\x6c\x65\x2d\x62\x61\x63\x6b\x67\x72\x6f\x75\x6e\x64\
-\x3d\x22\x6e\x65\x77\x20\x30\x20\x30\x20\x35\x31\x32\x20\x35\x31\
-\x32\x22\x20\x78\x6d\x6c\x3a\x73\x70\x61\x63\x65\x3d\x22\x70\x72\
-\x65\x73\x65\x72\x76\x65\x22\x3e\x0d\x0a\x3c\x67\x3e\x0d\x0a\x09\
-\x3c\x70\x6f\x6c\x79\x67\x6f\x6e\x20\x70\x6f\x69\x6e\x74\x73\x3d\
-\x22\x33\x39\x36\x2e\x37\x39\x35\x2c\x33\x39\x36\x2e\x38\x20\x33\
-\x32\x30\x2c\x33\x39\x36\x2e\x38\x20\x33\x32\x30\x2c\x34\x34\x38\
-\x20\x34\x34\x38\x2c\x34\x34\x38\x20\x34\x34\x38\x2c\x33\x32\x30\
-\x20\x33\x39\x36\x2e\x37\x39\x35\x2c\x33\x32\x30\x20\x09\x22\x2f\
-\x3e\x0d\x0a\x09\x3c\x70\x6f\x6c\x79\x67\x6f\x6e\x20\x70\x6f\x69\
-\x6e\x74\x73\x3d\x22\x33\x39\x36\x2e\x38\x2c\x31\x31\x35\x2e\x32\
-\x30\x35\x20\x33\x39\x36\x2e\x38\x2c\x31\x39\x32\x20\x34\x34\x38\
-\x2c\x31\x39\x32\x20\x34\x34\x38\x2c\x36\x34\x20\x33\x32\x30\x2c\
-\x36\x34\x20\x33\x32\x30\x2c\x31\x31\x35\x2e\x32\x30\x35\x20\x09\
-\x22\x2f\x3e\x0d\x0a\x09\x3c\x70\x6f\x6c\x79\x67\x6f\x6e\x20\x70\
-\x6f\x69\x6e\x74\x73\x3d\x22\x31\x31\x35\x2e\x32\x30\x35\x2c\x31\
-\x31\x35\x2e\x32\x20\x31\x39\x32\x2c\x31\x31\x35\x2e\x32\x20\x31\
-\x39\x32\x2c\x36\x34\x20\x36\x34\x2c\x36\x34\x20\x36\x34\x2c\x31\
-\x39\x32\x20\x31\x31\x35\x2e\x32\x30\x35\x2c\x31\x39\x32\x20\x09\
-\x22\x2f\x3e\x0d\x0a\x09\x3c\x70\x6f\x6c\x79\x67\x6f\x6e\x20\x70\
-\x6f\x69\x6e\x74\x73\x3d\x22\x31\x31\x35\x2e\x32\x2c\x33\x39\x36\
-\x2e\x37\x39\x35\x20\x31\x31\x35\x2e\x32\x2c\x33\x32\x30\x20\x36\
-\x34\x2c\x33\x32\x30\x20\x36\x34\x2c\x34\x34\x38\x20\x31\x39\x32\
-\x2c\x34\x34\x38\x20\x31\x39\x32\x2c\x33\x39\x36\x2e\x37\x39\x35\
-\x20\x09\x22\x2f\x3e\x0d\x0a\x3c\x2f\x67\x3e\x0d\x0a\x3c\x2f\x73\
-\x76\x67\x3e\x0d\x0a\
-\x00\x00\x04\xaa\
-\x3c\
-\x3f\x78\x6d\x6c\x20\x76\x65\x72\x73\x69\x6f\x6e\x3d\x22\x31\x2e\
-\x30\x22\x20\x65\x6e\x63\x6f\x64\x69\x6e\x67\x3d\x22\x75\x74\x66\
-\x2d\x38\x22\x3f\x3e\x0d\x0a\x3c\x21\x2d\x2d\x20\x47\x65\x6e\x65\
-\x72\x61\x74\x6f\x72\x3a\x20\x41\x64\x6f\x62\x65\x20\x49\x6c\x6c\
-\x75\x73\x74\x72\x61\x74\x6f\x72\x20\x31\x38\x2e\x31\x2e\x30\x2c\
-\x20\x53\x56\x47\x20\x45\x78\x70\x6f\x72\x74\x20\x50\x6c\x75\x67\
-\x2d\x49\x6e\x20\x2e\x20\x53\x56\x47\x20\x56\x65\x72\x73\x69\x6f\
-\x6e\x3a\x20\x36\x2e\x30\x30\x20\x42\x75\x69\x6c\x64\x20\x30\x29\
-\x20\x20\x2d\x2d\x3e\x0d\x0a\x3c\x21\x44\x4f\x43\x54\x59\x50\x45\
-\x20\x73\x76\x67\x20\x50\x55\x42\x4c\x49\x43\x20\x22\x2d\x2f\x2f\
-\x57\x33\x43\x2f\x2f\x44\x54\x44\x20\x53\x56\x47\x20\x31\x2e\x31\
-\x2f\x2f\x45\x4e\x22\x20\x22\x68\x74\x74\x70\x3a\x2f\x2f\x77\x77\
-\x77\x2e\x77\x33\x2e\x6f\x72\x67\x2f\x47\x72\x61\x70\x68\x69\x63\
-\x73\x2f\x53\x56\x47\x2f\x31\x2e\x31\x2f\x44\x54\x44\x2f\x73\x76\
-\x67\x31\x31\x2e\x64\x74\x64\x22\x3e\x0d\x0a\x3c\x73\x76\x67\x20\
-\x76\x65\x72\x73\x69\x6f\x6e\x3d\x22\x31\x2e\x31\x22\x20\x69\x64\
-\x3d\x22\x43\x6f\x64\x65\x22\x20\x78\x6d\x6c\x6e\x73\x3d\x22\x68\
-\x74\x74\x70\x3a\x2f\x2f\x77\x77\x77\x2e\x77\x33\x2e\x6f\x72\x67\
-\x2f\x32\x30\x30\x30\x2f\x73\x76\x67\x22\x20\x78\x6d\x6c\x6e\x73\
-\x3a\x78\x6c\x69\x6e\x6b\x3d\x22\x68\x74\x74\x70\x3a\x2f\x2f\x77\
-\x77\x77\x2e\x77\x33\x2e\x6f\x72\x67\x2f\x31\x39\x39\x39\x2f\x78\
-\x6c\x69\x6e\x6b\x22\x20\x78\x3d\x22\x32\x34\x70\x78\x22\x20\x79\
-\x3d\x22\x32\x34\x70\x78\x22\x0d\x0a\x09\x20\x76\x69\x65\x77\x42\
-\x6f\x78\x3d\x22\x30\x20\x30\x20\x35\x31\x32\x20\x35\x31\x32\x22\
-\x20\x65\x6e\x61\x62\x6c\x65\x2d\x62\x61\x63\x6b\x67\x72\x6f\x75\
-\x6e\x64\x3d\x22\x6e\x65\x77\x20\x30\x20\x30\x20\x35\x31\x32\x20\
-\x35\x31\x32\x22\x20\x78\x6d\x6c\x3a\x73\x70\x61\x63\x65\x3d\x22\
-\x70\x72\x65\x73\x65\x72\x76\x65\x22\x3e\x0d\x0a\x3c\x67\x20\x74\
-\x72\x61\x6e\x73\x66\x6f\x72\x6d\x3d\x27\x6d\x61\x74\x72\x69\x78\
-\x28\x32\x34\x20\x30\x20\x30\x20\x32\x34\x20\x30\x20\x30\x29\x27\
-\x3e\x3c\x70\x61\x74\x68\x20\x64\x3d\x22\x4d\x35\x2e\x37\x31\x39\
-\x2c\x31\x34\x2e\x37\x35\x63\x2d\x30\x2e\x32\x33\x36\x2c\x30\x2d\
-\x30\x2e\x34\x37\x34\x2d\x30\x2e\x30\x38\x33\x2d\x30\x2e\x36\x36\
-\x34\x2d\x30\x2e\x32\x35\x32\x4c\x2d\x30\x2e\x30\x30\x35\x2c\x31\
-\x30\x6c\x35\x2e\x33\x34\x31\x2d\x34\x2e\x37\x34\x38\x43\x35\x2e\
-\x37\x34\x38\x2c\x34\x2e\x38\x38\x37\x2c\x36\x2e\x33\x38\x2c\x34\
-\x2e\x39\x32\x32\x2c\x36\x2e\x37\x34\x37\x2c\x35\x2e\x33\x33\x35\
-\x0d\x0a\x09\x63\x30\x2e\x33\x36\x37\x2c\x30\x2e\x34\x31\x33\x2c\
-\x30\x2e\x33\x33\x2c\x31\x2e\x30\x34\x35\x2d\x30\x2e\x30\x38\x33\
-\x2c\x31\x2e\x34\x31\x32\x4c\x33\x2e\x30\x30\x35\x2c\x31\x30\x6c\
-\x33\x2e\x33\x37\x38\x2c\x33\x2e\x30\x30\x32\x63\x30\x2e\x34\x31\
-\x33\x2c\x30\x2e\x33\x36\x37\x2c\x30\x2e\x34\x35\x2c\x30\x2e\x39\
-\x39\x39\x2c\x30\x2e\x30\x38\x33\x2c\x31\x2e\x34\x31\x32\x0d\x0a\
-\x09\x43\x36\x2e\x32\x36\x39\x2c\x31\x34\x2e\x36\x33\x37\x2c\x35\
-\x2e\x39\x39\x34\x2c\x31\x34\x2e\x37\x35\x2c\x35\x2e\x37\x31\x39\
-\x2c\x31\x34\x2e\x37\x35\x7a\x20\x4d\x31\x34\x2e\x36\x36\x34\x2c\
-\x31\x34\x2e\x37\x34\x38\x4c\x32\x30\x2e\x30\x30\x35\x2c\x31\x30\
-\x6c\x2d\x35\x2e\x30\x36\x2d\x34\x2e\x34\x39\x38\x63\x2d\x30\x2e\
-\x34\x31\x33\x2d\x30\x2e\x33\x36\x37\x2d\x31\x2e\x30\x34\x35\x2d\
-\x30\x2e\x33\x33\x2d\x31\x2e\x34\x31\x31\x2c\x30\x2e\x30\x38\x33\
-\x0d\x0a\x09\x63\x2d\x30\x2e\x33\x36\x37\x2c\x30\x2e\x34\x31\x33\
-\x2d\x30\x2e\x33\x33\x2c\x31\x2e\x30\x34\x35\x2c\x30\x2e\x30\x38\
-\x33\x2c\x31\x2e\x34\x31\x32\x4c\x31\x36\x2e\x39\x39\x35\x2c\x31\
-\x30\x6c\x2d\x33\x2e\x36\x35\x39\x2c\x33\x2e\x32\x35\x32\x63\x2d\
-\x30\x2e\x34\x31\x33\x2c\x30\x2e\x33\x36\x37\x2d\x30\x2e\x34\x35\
-\x2c\x30\x2e\x39\x39\x39\x2d\x30\x2e\x30\x38\x33\x2c\x31\x2e\x34\
-\x31\x32\x43\x31\x33\x2e\x34\x35\x2c\x31\x34\x2e\x38\x38\x37\x2c\
-\x31\x33\x2e\x37\x32\x35\x2c\x31\x35\x2c\x31\x34\x2c\x31\x35\x0d\
-\x0a\x09\x43\x31\x34\x2e\x32\x33\x36\x2c\x31\x35\x2c\x31\x34\x2e\
-\x34\x37\x34\x2c\x31\x34\x2e\x39\x31\x37\x2c\x31\x34\x2e\x36\x36\
-\x34\x2c\x31\x34\x2e\x37\x34\x38\x7a\x20\x4d\x39\x2e\x39\x38\x36\
-\x2c\x31\x36\x2e\x31\x36\x35\x6c\x32\x2d\x31\x32\x63\x30\x2e\x30\
-\x39\x31\x2d\x30\x2e\x35\x34\x35\x2d\x30\x2e\x32\x37\x37\x2d\x31\
-\x2e\x30\x36\x2d\x30\x2e\x38\x32\x32\x2d\x31\x2e\x31\x35\x31\x0d\
-\x0a\x09\x63\x2d\x30\x2e\x35\x34\x37\x2d\x30\x2e\x30\x39\x32\x2d\
-\x31\x2e\x30\x36\x31\x2c\x30\x2e\x32\x37\x37\x2d\x31\x2e\x31\x35\
-\x2c\x30\x2e\x38\x32\x32\x6c\x2d\x32\x2c\x31\x32\x63\x2d\x30\x2e\
-\x30\x39\x31\x2c\x30\x2e\x35\x34\x35\x2c\x30\x2e\x32\x37\x37\x2c\
-\x31\x2e\x30\x36\x2c\x30\x2e\x38\x32\x32\x2c\x31\x2e\x31\x35\x31\
-\x43\x38\x2e\x38\x39\x32\x2c\x31\x36\x2e\x39\x39\x36\x2c\x38\x2e\
-\x39\x34\x36\x2c\x31\x37\x2c\x39\x2e\x30\x30\x31\x2c\x31\x37\x0d\
-\x0a\x09\x43\x39\x2e\x34\x38\x31\x2c\x31\x37\x2c\x39\x2e\x39\x30\
-\x35\x2c\x31\x36\x2e\x36\x35\x33\x2c\x39\x2e\x39\x38\x36\x2c\x31\
-\x36\x2e\x31\x36\x35\x7a\x22\x2f\x3e\x0d\x0a\x3c\x2f\x67\x3e\x0d\
-\x0a\x3c\x2f\x73\x76\x67\x3e\x0d\x0a\
-\x00\x00\x02\x7d\
-\x3c\
-\x3f\x78\x6d\x6c\x20\x76\x65\x72\x73\x69\x6f\x6e\x3d\x22\x31\x2e\
-\x30\x22\x20\x65\x6e\x63\x6f\x64\x69\x6e\x67\x3d\x22\x75\x74\x66\
-\x2d\x38\x22\x3f\x3e\x0d\x0a\x3c\x21\x2d\x2d\x20\x47\x65\x6e\x65\
-\x72\x61\x74\x6f\x72\x3a\x20\x41\x64\x6f\x62\x65\x20\x49\x6c\x6c\
-\x75\x73\x74\x72\x61\x74\x6f\x72\x20\x31\x36\x2e\x32\x2e\x31\x2c\
-\x20\x53\x56\x47\x20\x45\x78\x70\x6f\x72\x74\x20\x50\x6c\x75\x67\
-\x2d\x49\x6e\x20\x2e\x20\x53\x56\x47\x20\x56\x65\x72\x73\x69\x6f\
-\x6e\x3a\x20\x36\x2e\x30\x30\x20\x42\x75\x69\x6c\x64\x20\x30\x29\
-\x20\x20\x2d\x2d\x3e\x0d\x0a\x3c\x21\x44\x4f\x43\x54\x59\x50\x45\
-\x20\x73\x76\x67\x20\x50\x55\x42\x4c\x49\x43\x20\x22\x2d\x2f\x2f\
-\x57\x33\x43\x2f\x2f\x44\x54\x44\x20\x53\x56\x47\x20\x31\x2e\x31\
-\x2f\x2f\x45\x4e\x22\x20\x22\x68\x74\x74\x70\x3a\x2f\x2f\x77\x77\
-\x77\x2e\x77\x33\x2e\x6f\x72\x67\x2f\x47\x72\x61\x70\x68\x69\x63\
-\x73\x2f\x53\x56\x47\x2f\x31\x2e\x31\x2f\x44\x54\x44\x2f\x73\x76\
-\x67\x31\x31\x2e\x64\x74\x64\x22\x3e\x0d\x0a\x3c\x73\x76\x67\x20\
-\x76\x65\x72\x73\x69\x6f\x6e\x3d\x22\x31\x2e\x31\x22\x20\x69\x64\
-\x3d\x22\x4c\x61\x79\x65\x72\x5f\x31\x22\x20\x78\x6d\x6c\x6e\x73\
-\x3d\x22\x68\x74\x74\x70\x3a\x2f\x2f\x77\x77\x77\x2e\x77\x33\x2e\
-\x6f\x72\x67\x2f\x32\x30\x30\x30\x2f\x73\x76\x67\x22\x20\x78\x6d\
-\x6c\x6e\x73\x3a\x78\x6c\x69\x6e\x6b\x3d\x22\x68\x74\x74\x70\x3a\
-\x2f\x2f\x77\x77\x77\x2e\x77\x33\x2e\x6f\x72\x67\x2f\x31\x39\x39\
-\x39\x2f\x78\x6c\x69\x6e\x6b\x22\x20\x78\x3d\x22\x30\x70\x78\x22\
-\x20\x79\x3d\x22\x30\x70\x78\x22\x0d\x0a\x09\x20\x77\x69\x64\x74\
-\x68\x3d\x22\x35\x31\x32\x70\x78\x22\x20\x68\x65\x69\x67\x68\x74\
-\x3d\x22\x35\x31\x32\x70\x78\x22\x20\x76\x69\x65\x77\x42\x6f\x78\
-\x3d\x22\x30\x20\x30\x20\x35\x31\x32\x20\x35\x31\x32\x22\x20\x65\
-\x6e\x61\x62\x6c\x65\x2d\x62\x61\x63\x6b\x67\x72\x6f\x75\x6e\x64\
-\x3d\x22\x6e\x65\x77\x20\x30\x20\x30\x20\x35\x31\x32\x20\x35\x31\
-\x32\x22\x20\x78\x6d\x6c\x3a\x73\x70\x61\x63\x65\x3d\x22\x70\x72\
-\x65\x73\x65\x72\x76\x65\x22\x3e\x0d\x0a\x3c\x67\x20\x69\x64\x3d\
-\x22\x49\x63\x6f\x6e\x5f\x38\x5f\x22\x3e\x0d\x0a\x09\x3c\x67\x3e\
-\x0d\x0a\x09\x09\x3c\x70\x61\x74\x68\x20\x64\x3d\x22\x4d\x38\x35\
-\x2c\x32\x37\x37\x2e\x33\x37\x35\x68\x32\x35\x39\x2e\x37\x30\x34\
-\x4c\x32\x32\x35\x2e\x30\x30\x32\x2c\x33\x39\x37\x2e\x30\x37\x37\
-\x4c\x32\x35\x36\x2c\x34\x32\x37\x6c\x31\x37\x31\x2d\x31\x37\x31\
-\x4c\x32\x35\x36\x2c\x38\x35\x6c\x2d\x32\x39\x2e\x39\x32\x32\x2c\
-\x32\x39\x2e\x39\x32\x34\x6c\x31\x31\x38\x2e\x36\x32\x36\x2c\x31\
-\x31\x39\x2e\x37\x30\x31\x48\x38\x35\x56\x32\x37\x37\x2e\x33\x37\
-\x35\x7a\x22\x2f\x3e\x0d\x0a\x09\x3c\x2f\x67\x3e\x0d\x0a\x3c\x2f\
-\x67\x3e\x0d\x0a\x3c\x2f\x73\x76\x67\x3e\x0d\x0a\
-\x00\x00\x04\x4e\
-\x3c\
-\x3f\x78\x6d\x6c\x20\x76\x65\x72\x73\x69\x6f\x6e\x3d\x27\x31\x2e\
-\x30\x27\x20\x65\x6e\x63\x6f\x64\x69\x6e\x67\x3d\x27\x55\x54\x46\
-\x2d\x38\x27\x3f\x3e\x0a\x3c\x21\x2d\x2d\x20\x54\x68\x69\x73\x20\
-\x66\x69\x6c\x65\x20\x77\x61\x73\x20\x67\x65\x6e\x65\x72\x61\x74\
-\x65\x64\x20\x62\x79\x20\x64\x76\x69\x73\x76\x67\x6d\x20\x32\x2e\
-\x38\x20\x2d\x2d\x3e\x0a\x3c\x73\x76\x67\x20\x76\x65\x72\x73\x69\
-\x6f\x6e\x3d\x27\x31\x2e\x31\x27\x20\x78\x6d\x6c\x6e\x73\x3d\x27\
-\x68\x74\x74\x70\x3a\x2f\x2f\x77\x77\x77\x2e\x77\x33\x2e\x6f\x72\
-\x67\x2f\x32\x30\x30\x30\x2f\x73\x76\x67\x27\x20\x78\x6d\x6c\x6e\
-\x73\x3a\x78\x6c\x69\x6e\x6b\x3d\x27\x68\x74\x74\x70\x3a\x2f\x2f\
-\x77\x77\x77\x2e\x77\x33\x2e\x6f\x72\x67\x2f\x31\x39\x39\x39\x2f\
-\x78\x6c\x69\x6e\x6b\x27\x20\x77\x69\x64\x74\x68\x3d\x27\x36\x33\
-\x2e\x39\x39\x39\x36\x70\x74\x27\x20\x68\x65\x69\x67\x68\x74\x3d\
-\x27\x36\x33\x2e\x39\x39\x39\x37\x70\x74\x27\x20\x76\x69\x65\x77\
-\x42\x6f\x78\x3d\x27\x35\x36\x2e\x34\x30\x39\x34\x20\x35\x33\x2e\
-\x38\x35\x38\x33\x20\x36\x33\x2e\x39\x39\x39\x36\x20\x36\x33\x2e\
-\x39\x39\x39\x37\x27\x3e\x0a\x3c\x67\x20\x69\x64\x3d\x27\x70\x61\
-\x67\x65\x31\x27\x3e\x0a\x3c\x67\x20\x74\x72\x61\x6e\x73\x66\x6f\
-\x72\x6d\x3d\x27\x6d\x61\x74\x72\x69\x78\x28\x30\x2e\x39\x39\x36\
-\x32\x36\x34\x20\x30\x20\x30\x20\x30\x2e\x39\x39\x36\x32\x36\x34\
-\x20\x35\x38\x2e\x34\x36\x36\x39\x20\x31\x31\x37\x2e\x38\x35\x38\
-\x29\x27\x3e\x0a\x3c\x70\x61\x74\x68\x20\x64\x3d\x27\x4d\x20\x33\
-\x2e\x39\x35\x37\x33\x35\x20\x2d\x33\x32\x2e\x31\x32\x4c\x20\x31\
-\x31\x2e\x39\x30\x33\x36\x20\x2d\x35\x31\x2e\x33\x30\x33\x39\x4c\
-\x20\x35\x36\x2e\x31\x35\x32\x33\x20\x2d\x34\x32\x2e\x35\x30\x32\
-\x32\x4c\x20\x34\x30\x2e\x36\x37\x39\x34\x20\x2d\x32\x32\x2e\x35\
-\x32\x38\x31\x4c\x20\x33\x2e\x39\x35\x37\x33\x35\x20\x2d\x33\x32\
-\x2e\x31\x32\x5a\x27\x20\x66\x69\x6c\x6c\x3d\x27\x6e\x6f\x6e\x65\
-\x27\x20\x73\x74\x72\x6f\x6b\x65\x3d\x27\x23\x30\x30\x30\x30\x30\
-\x30\x27\x20\x73\x74\x72\x6f\x6b\x65\x2d\x6c\x69\x6e\x65\x63\x61\
-\x70\x3d\x27\x72\x6f\x75\x6e\x64\x27\x20\x73\x74\x72\x6f\x6b\x65\
-\x2d\x6c\x69\x6e\x65\x6a\x6f\x69\x6e\x3d\x27\x72\x6f\x75\x6e\x64\
-\x27\x20\x73\x74\x72\x6f\x6b\x65\x2d\x6d\x69\x74\x65\x72\x6c\x69\
-\x6d\x69\x74\x3d\x27\x31\x30\x2e\x30\x33\x37\x35\x27\x20\x73\x74\
-\x72\x6f\x6b\x65\x2d\x77\x69\x64\x74\x68\x3d\x27\x32\x2e\x35\x30\
-\x39\x33\x37\x27\x2f\x3e\x0a\x3c\x2f\x67\x3e\x0a\x3c\x67\x20\x74\
-\x72\x61\x6e\x73\x66\x6f\x72\x6d\x3d\x27\x6d\x61\x74\x72\x69\x78\
-\x28\x30\x2e\x39\x39\x36\x32\x36\x34\x20\x30\x20\x30\x20\x30\x2e\
-\x39\x39\x36\x32\x36\x34\x20\x35\x38\x2e\x34\x36\x36\x39\x20\x31\
-\x31\x37\x2e\x38\x35\x38\x29\x27\x3e\x0a\x3c\x63\x69\x72\x63\x6c\
-\x65\x20\x63\x78\x3d\x27\x33\x2e\x39\x35\x37\x33\x35\x27\x20\x63\
-\x79\x3d\x27\x2d\x33\x32\x2e\x31\x32\x27\x20\x66\x69\x6c\x6c\x3d\
-\x27\x23\x30\x30\x30\x30\x30\x30\x27\x20\x72\x3d\x27\x36\x2e\x30\
-\x32\x32\x35\x27\x2f\x3e\x0a\x3c\x2f\x67\x3e\x0a\x3c\x67\x20\x74\
-\x72\x61\x6e\x73\x66\x6f\x72\x6d\x3d\x27\x6d\x61\x74\x72\x69\x78\
-\x28\x30\x2e\x39\x39\x36\x32\x36\x34\x20\x30\x20\x30\x20\x30\x2e\
-\x39\x39\x36\x32\x36\x34\x20\x35\x38\x2e\x34\x36\x36\x39\x20\x31\
-\x31\x37\x2e\x38\x35\x38\x29\x27\x3e\x0a\x3c\x63\x69\x72\x63\x6c\
-\x65\x20\x63\x78\x3d\x27\x31\x31\x2e\x39\x30\x33\x36\x27\x20\x63\
-\x79\x3d\x27\x2d\x35\x31\x2e\x33\x30\x33\x39\x27\x20\x66\x69\x6c\
-\x6c\x3d\x27\x23\x30\x30\x30\x30\x30\x30\x27\x20\x72\x3d\x27\x36\
-\x2e\x30\x32\x32\x35\x27\x2f\x3e\x0a\x3c\x2f\x67\x3e\x0a\x3c\x67\
-\x20\x74\x72\x61\x6e\x73\x66\x6f\x72\x6d\x3d\x27\x6d\x61\x74\x72\
-\x69\x78\x28\x30\x2e\x39\x39\x36\x32\x36\x34\x20\x30\x20\x30\x20\
-\x30\x2e\x39\x39\x36\x32\x36\x34\x20\x35\x38\x2e\x34\x36\x36\x39\
-\x20\x31\x31\x37\x2e\x38\x35\x38\x29\x27\x3e\x0a\x3c\x63\x69\x72\
-\x63\x6c\x65\x20\x63\x78\x3d\x27\x35\x36\x2e\x31\x35\x32\x33\x27\
-\x20\x63\x79\x3d\x27\x2d\x34\x32\x2e\x35\x30\x32\x32\x27\x20\x66\
-\x69\x6c\x6c\x3d\x27\x23\x30\x30\x30\x30\x30\x30\x27\x20\x72\x3d\
-\x27\x36\x2e\x30\x32\x32\x35\x27\x2f\x3e\x0a\x3c\x2f\x67\x3e\x0a\
-\x3c\x67\x20\x74\x72\x61\x6e\x73\x66\x6f\x72\x6d\x3d\x27\x6d\x61\
-\x74\x72\x69\x78\x28\x30\x2e\x39\x39\x36\x32\x36\x34\x20\x30\x20\
-\x30\x20\x30\x2e\x39\x39\x36\x32\x36\x34\x20\x35\x38\x2e\x34\x36\
-\x36\x39\x20\x31\x31\x37\x2e\x38\x35\x38\x29\x27\x3e\x0a\x3c\x63\
-\x69\x72\x63\x6c\x65\x20\x63\x78\x3d\x27\x34\x30\x2e\x36\x37\x39\
-\x34\x27\x20\x63\x79\x3d\x27\x2d\x32\x32\x2e\x35\x32\x38\x31\x27\
-\x20\x66\x69\x6c\x6c\x3d\x27\x23\x30\x30\x30\x30\x30\x30\x27\x20\
-\x72\x3d\x27\x36\x2e\x30\x32\x32\x35\x27\x2f\x3e\x0a\x3c\x2f\x67\
-\x3e\x0a\x3c\x2f\x67\x3e\x0a\x3c\x2f\x73\x76\x67\x3e\
-\x00\x00\x04\xd5\
-\x3c\
-\x3f\x78\x6d\x6c\x20\x76\x65\x72\x73\x69\x6f\x6e\x3d\x27\x31\x2e\
-\x30\x27\x20\x65\x6e\x63\x6f\x64\x69\x6e\x67\x3d\x27\x55\x54\x46\
-\x2d\x38\x27\x3f\x3e\x0a\x3c\x21\x2d\x2d\x20\x54\x68\x69\x73\x20\
-\x66\x69\x6c\x65\x20\x77\x61\x73\x20\x67\x65\x6e\x65\x72\x61\x74\
-\x65\x64\x20\x62\x79\x20\x64\x76\x69\x73\x76\x67\x6d\x20\x32\x2e\
-\x38\x20\x2d\x2d\x3e\x0a\x3c\x73\x76\x67\x20\x76\x65\x72\x73\x69\
-\x6f\x6e\x3d\x27\x31\x2e\x31\x27\x20\x78\x6d\x6c\x6e\x73\x3d\x27\
-\x68\x74\x74\x70\x3a\x2f\x2f\x77\x77\x77\x2e\x77\x33\x2e\x6f\x72\
-\x67\x2f\x32\x30\x30\x30\x2f\x73\x76\x67\x27\x20\x78\x6d\x6c\x6e\
-\x73\x3a\x78\x6c\x69\x6e\x6b\x3d\x27\x68\x74\x74\x70\x3a\x2f\x2f\
-\x77\x77\x77\x2e\x77\x33\x2e\x6f\x72\x67\x2f\x31\x39\x39\x39\x2f\
-\x78\x6c\x69\x6e\x6b\x27\x20\x77\x69\x64\x74\x68\x3d\x27\x36\x33\
-\x2e\x39\x39\x39\x36\x70\x74\x27\x20\x68\x65\x69\x67\x68\x74\x3d\
-\x27\x36\x33\x2e\x39\x39\x39\x37\x70\x74\x27\x20\x76\x69\x65\x77\
-\x42\x6f\x78\x3d\x27\x35\x36\x2e\x34\x30\x39\x34\x20\x35\x33\x2e\
-\x38\x35\x38\x33\x20\x36\x33\x2e\x39\x39\x39\x36\x20\x36\x33\x2e\
-\x39\x39\x39\x37\x27\x3e\x0a\x3c\x67\x20\x69\x64\x3d\x27\x70\x61\
-\x67\x65\x31\x27\x3e\x0a\x3c\x67\x20\x74\x72\x61\x6e\x73\x66\x6f\
-\x72\x6d\x3d\x27\x6d\x61\x74\x72\x69\x78\x28\x30\x2e\x39\x39\x36\
-\x32\x36\x34\x20\x30\x20\x30\x20\x30\x2e\x39\x39\x36\x32\x36\x34\
-\x20\x35\x38\x2e\x34\x36\x36\x39\x20\x31\x31\x37\x2e\x38\x35\x38\
-\x29\x27\x3e\x0a\x3c\x70\x61\x74\x68\x20\x64\x3d\x27\x4d\x20\x33\
-\x2e\x39\x35\x37\x33\x35\x20\x2d\x33\x32\x2e\x31\x32\x43\x20\x32\
-\x2e\x32\x38\x39\x32\x32\x20\x2d\x33\x39\x2e\x33\x31\x31\x33\x20\
-\x36\x2e\x33\x36\x37\x30\x32\x20\x2d\x34\x36\x2e\x32\x33\x38\x36\
-\x20\x31\x31\x2e\x39\x30\x33\x36\x20\x2d\x35\x31\x2e\x33\x30\x33\
-\x39\x43\x20\x32\x39\x2e\x36\x36\x38\x37\x20\x2d\x36\x37\x2e\x35\
-\x35\x36\x38\x20\x35\x35\x2e\x32\x32\x39\x32\x20\x2d\x36\x30\x2e\
-\x36\x34\x32\x20\x35\x36\x2e\x31\x35\x32\x33\x20\x2d\x34\x32\x2e\
-\x35\x30\x32\x32\x43\x20\x35\x36\x2e\x36\x31\x33\x36\x20\x2d\x33\
-\x33\x2e\x34\x33\x38\x31\x20\x34\x39\x2e\x31\x31\x33\x32\x20\x2d\
-\x32\x36\x2e\x35\x39\x35\x39\x20\x34\x30\x2e\x36\x37\x39\x34\x20\
-\x2d\x32\x32\x2e\x35\x32\x38\x31\x43\x20\x32\x35\x2e\x33\x39\x39\
-\x35\x20\x2d\x31\x35\x2e\x31\x35\x38\x32\x20\x37\x2e\x31\x39\x39\
-\x33\x35\x20\x2d\x31\x38\x2e\x31\x34\x33\x36\x20\x33\x2e\x39\x35\
-\x37\x33\x35\x20\x2d\x33\x32\x2e\x31\x32\x5a\x27\x20\x66\x69\x6c\
-\x6c\x3d\x27\x6e\x6f\x6e\x65\x27\x20\x73\x74\x72\x6f\x6b\x65\x3d\
-\x27\x23\x30\x30\x30\x30\x30\x30\x27\x20\x73\x74\x72\x6f\x6b\x65\
-\x2d\x6c\x69\x6e\x65\x63\x61\x70\x3d\x27\x72\x6f\x75\x6e\x64\x27\
-\x20\x73\x74\x72\x6f\x6b\x65\x2d\x6c\x69\x6e\x65\x6a\x6f\x69\x6e\
-\x3d\x27\x72\x6f\x75\x6e\x64\x27\x20\x73\x74\x72\x6f\x6b\x65\x2d\
-\x6d\x69\x74\x65\x72\x6c\x69\x6d\x69\x74\x3d\x27\x31\x30\x2e\x30\
-\x33\x37\x35\x27\x20\x73\x74\x72\x6f\x6b\x65\x2d\x77\x69\x64\x74\
-\x68\x3d\x27\x32\x2e\x35\x30\x39\x33\x37\x27\x2f\x3e\x0a\x3c\x2f\
-\x67\x3e\x0a\x3c\x67\x20\x74\x72\x61\x6e\x73\x66\x6f\x72\x6d\x3d\
-\x27\x6d\x61\x74\x72\x69\x78\x28\x30\x2e\x39\x39\x36\x32\x36\x34\
-\x20\x30\x20\x30\x20\x30\x2e\x39\x39\x36\x32\x36\x34\x20\x35\x38\
-\x2e\x34\x36\x36\x39\x20\x31\x31\x37\x2e\x38\x35\x38\x29\x27\x3e\
-\x0a\x3c\x63\x69\x72\x63\x6c\x65\x20\x63\x78\x3d\x27\x33\x2e\x39\
-\x35\x37\x33\x35\x27\x20\x63\x79\x3d\x27\x2d\x33\x32\x2e\x31\x32\
-\x27\x20\x66\x69\x6c\x6c\x3d\x27\x23\x30\x30\x30\x30\x30\x30\x27\
-\x20\x72\x3d\x27\x36\x2e\x30\x32\x32\x35\x27\x2f\x3e\x0a\x3c\x2f\
-\x67\x3e\x0a\x3c\x67\x20\x74\x72\x61\x6e\x73\x66\x6f\x72\x6d\x3d\
-\x27\x6d\x61\x74\x72\x69\x78\x28\x30\x2e\x39\x39\x36\x32\x36\x34\
-\x20\x30\x20\x30\x20\x30\x2e\x39\x39\x36\x32\x36\x34\x20\x35\x38\
-\x2e\x34\x36\x36\x39\x20\x31\x31\x37\x2e\x38\x35\x38\x29\x27\x3e\
-\x0a\x3c\x63\x69\x72\x63\x6c\x65\x20\x63\x78\x3d\x27\x31\x31\x2e\
-\x39\x30\x33\x36\x27\x20\x63\x79\x3d\x27\x2d\x35\x31\x2e\x33\x30\
-\x33\x39\x27\x20\x66\x69\x6c\x6c\x3d\x27\x23\x30\x30\x30\x30\x30\
-\x30\x27\x20\x72\x3d\x27\x36\x2e\x30\x32\x32\x35\x27\x2f\x3e\x0a\
-\x3c\x2f\x67\x3e\x0a\x3c\x67\x20\x74\x72\x61\x6e\x73\x66\x6f\x72\
-\x6d\x3d\x27\x6d\x61\x74\x72\x69\x78\x28\x30\x2e\x39\x39\x36\x32\
-\x36\x34\x20\x30\x20\x30\x20\x30\x2e\x39\x39\x36\x32\x36\x34\x20\
-\x35\x38\x2e\x34\x36\x36\x39\x20\x31\x31\x37\x2e\x38\x35\x38\x29\
-\x27\x3e\x0a\x3c\x63\x69\x72\x63\x6c\x65\x20\x63\x78\x3d\x27\x35\
-\x36\x2e\x31\x35\x32\x33\x27\x20\x63\x79\x3d\x27\x2d\x34\x32\x2e\
-\x35\x30\x32\x32\x27\x20\x66\x69\x6c\x6c\x3d\x27\x23\x30\x30\x30\
-\x30\x30\x30\x27\x20\x72\x3d\x27\x36\x2e\x30\x32\x32\x35\x27\x2f\
-\x3e\x0a\x3c\x2f\x67\x3e\x0a\x3c\x67\x20\x74\x72\x61\x6e\x73\x66\
-\x6f\x72\x6d\x3d\x27\x6d\x61\x74\x72\x69\x78\x28\x30\x2e\x39\x39\
-\x36\x32\x36\x34\x20\x30\x20\x30\x20\x30\x2e\x39\x39\x36\x32\x36\
-\x34\x20\x35\x38\x2e\x34\x36\x36\x39\x20\x31\x31\x37\x2e\x38\x35\
-\x38\x29\x27\x3e\x0a\x3c\x63\x69\x72\x63\x6c\x65\x20\x63\x78\x3d\
-\x27\x34\x30\x2e\x36\x37\x39\x34\x27\x20\x63\x79\x3d\x27\x2d\x32\
-\x32\x2e\x35\x32\x38\x31\x27\x20\x66\x69\x6c\x6c\x3d\x27\x23\x30\
-\x30\x30\x30\x30\x30\x27\x20\x72\x3d\x27\x36\x2e\x30\x32\x32\x35\
-\x27\x2f\x3e\x0a\x3c\x2f\x67\x3e\x0a\x3c\x2f\x67\x3e\x0a\x3c\x2f\
-\x73\x76\x67\x3e\
-\x00\x00\x02\xf2\
-\x3c\
-\x3f\x78\x6d\x6c\x20\x76\x65\x72\x73\x69\x6f\x6e\x3d\x22\x31\x2e\
-\x30\x22\x20\x65\x6e\x63\x6f\x64\x69\x6e\x67\x3d\x22\x75\x74\x66\
-\x2d\x38\x22\x3f\x3e\x0d\x0a\x3c\x21\x2d\x2d\x20\x47\x65\x6e\x65\
-\x72\x61\x74\x6f\x72\x3a\x20\x41\x64\x6f\x62\x65\x20\x49\x6c\x6c\
-\x75\x73\x74\x72\x61\x74\x6f\x72\x20\x31\x38\x2e\x31\x2e\x30\x2c\
-\x20\x53\x56\x47\x20\x45\x78\x70\x6f\x72\x74\x20\x50\x6c\x75\x67\
-\x2d\x49\x6e\x20\x2e\x20\x53\x56\x47\x20\x56\x65\x72\x73\x69\x6f\
-\x6e\x3a\x20\x36\x2e\x30\x30\x20\x42\x75\x69\x6c\x64\x20\x30\x29\
-\x20\x20\x2d\x2d\x3e\x0d\x0a\x3c\x21\x44\x4f\x43\x54\x59\x50\x45\
-\x20\x73\x76\x67\x20\x50\x55\x42\x4c\x49\x43\x20\x22\x2d\x2f\x2f\
-\x57\x33\x43\x2f\x2f\x44\x54\x44\x20\x53\x56\x47\x20\x31\x2e\x31\
-\x2f\x2f\x45\x4e\x22\x20\x22\x68\x74\x74\x70\x3a\x2f\x2f\x77\x77\
-\x77\x2e\x77\x33\x2e\x6f\x72\x67\x2f\x47\x72\x61\x70\x68\x69\x63\
-\x73\x2f\x53\x56\x47\x2f\x31\x2e\x31\x2f\x44\x54\x44\x2f\x73\x76\
-\x67\x31\x31\x2e\x64\x74\x64\x22\x3e\x0d\x0a\x3c\x73\x76\x67\x20\
-\x76\x65\x72\x73\x69\x6f\x6e\x3d\x22\x31\x2e\x31\x22\x20\x69\x64\
-\x3d\x22\x43\x69\x72\x63\x6c\x65\x22\x20\x78\x6d\x6c\x6e\x73\x3d\
-\x22\x68\x74\x74\x70\x3a\x2f\x2f\x77\x77\x77\x2e\x77\x33\x2e\x6f\
-\x72\x67\x2f\x32\x30\x30\x30\x2f\x73\x76\x67\x22\x20\x78\x6d\x6c\
-\x6e\x73\x3a\x78\x6c\x69\x6e\x6b\x3d\x22\x68\x74\x74\x70\x3a\x2f\
-\x2f\x77\x77\x77\x2e\x77\x33\x2e\x6f\x72\x67\x2f\x31\x39\x39\x39\
-\x2f\x78\x6c\x69\x6e\x6b\x22\x20\x78\x3d\x22\x35\x31\x32\x70\x78\
-\x22\x20\x79\x3d\x22\x35\x31\x32\x70\x78\x22\x0d\x0a\x09\x20\x76\
-\x69\x65\x77\x42\x6f\x78\x3d\x22\x30\x20\x30\x20\x35\x31\x32\x20\
-\x35\x31\x32\x22\x20\x65\x6e\x61\x62\x6c\x65\x2d\x62\x61\x63\x6b\
-\x67\x72\x6f\x75\x6e\x64\x3d\x22\x6e\x65\x77\x20\x30\x20\x30\x20\
-\x35\x31\x32\x20\x35\x31\x32\x22\x20\x78\x6d\x6c\x3a\x73\x70\x61\
-\x63\x65\x3d\x22\x70\x72\x65\x73\x65\x72\x76\x65\x22\x3e\x0d\x0a\
-\x3c\x67\x20\x74\x72\x61\x6e\x73\x66\x6f\x72\x6d\x3d\x27\x6d\x61\
-\x74\x72\x69\x78\x28\x32\x34\x20\x30\x20\x30\x20\x32\x34\x20\x30\
-\x20\x30\x29\x27\x3e\x0d\x0a\x3c\x70\x61\x74\x68\x20\x64\x3d\x22\
-\x4d\x31\x30\x2c\x30\x2e\x34\x43\x34\x2e\x36\x39\x38\x2c\x30\x2e\
-\x34\x2c\x30\x2e\x34\x2c\x34\x2e\x36\x39\x38\x2c\x30\x2e\x34\x2c\
-\x31\x30\x43\x30\x2e\x34\x2c\x31\x35\x2e\x33\x30\x32\x2c\x34\x2e\
-\x36\x39\x38\x2c\x31\x39\x2e\x36\x2c\x31\x30\x2c\x31\x39\x2e\x36\
-\x63\x35\x2e\x33\x30\x31\x2c\x30\x2c\x39\x2e\x36\x2d\x34\x2e\x32\
-\x39\x38\x2c\x39\x2e\x36\x2d\x39\x2e\x36\x30\x31\x0d\x0a\x09\x43\
-\x31\x39\x2e\x36\x2c\x34\x2e\x36\x39\x38\x2c\x31\x35\x2e\x33\x30\
-\x31\x2c\x30\x2e\x34\x2c\x31\x30\x2c\x30\x2e\x34\x7a\x20\x4d\x31\
-\x30\x2c\x31\x37\x2e\x35\x39\x39\x63\x2d\x34\x2e\x31\x39\x37\x2c\
-\x30\x2d\x37\x2e\x36\x2d\x33\x2e\x34\x30\x32\x2d\x37\x2e\x36\x2d\
-\x37\x2e\x36\x53\x35\x2e\x38\x30\x32\x2c\x32\x2e\x34\x2c\x31\x30\
-\x2c\x32\x2e\x34\x63\x34\x2e\x31\x39\x37\x2c\x30\x2c\x37\x2e\x36\
-\x30\x31\x2c\x33\x2e\x34\x30\x32\x2c\x37\x2e\x36\x30\x31\x2c\x37\
-\x2e\x36\x0d\x0a\x09\x53\x31\x34\x2e\x31\x39\x37\x2c\x31\x37\x2e\
-\x35\x39\x39\x2c\x31\x30\x2c\x31\x37\x2e\x35\x39\x39\x7a\x22\x2f\
-\x3e\x0d\x0a\x3c\x2f\x67\x3e\x0d\x0a\x3c\x2f\x73\x76\x67\x3e\x0d\
-\x0a\
-\x00\x00\x03\x4c\
-\x3c\
-\x3f\x78\x6d\x6c\x20\x76\x65\x72\x73\x69\x6f\x6e\x3d\x22\x31\x2e\
-\x30\x22\x20\x65\x6e\x63\x6f\x64\x69\x6e\x67\x3d\x22\x75\x74\x66\
-\x2d\x38\x22\x3f\x3e\x0d\x0a\x3c\x21\x2d\x2d\x20\x47\x65\x6e\x65\
-\x72\x61\x74\x6f\x72\x3a\x20\x41\x64\x6f\x62\x65\x20\x49\x6c\x6c\
-\x75\x73\x74\x72\x61\x74\x6f\x72\x20\x31\x36\x2e\x32\x2e\x31\x2c\
-\x20\x53\x56\x47\x20\x45\x78\x70\x6f\x72\x74\x20\x50\x6c\x75\x67\
-\x2d\x49\x6e\x20\x2e\x20\x53\x56\x47\x20\x56\x65\x72\x73\x69\x6f\
-\x6e\x3a\x20\x36\x2e\x30\x30\x20\x42\x75\x69\x6c\x64\x20\x30\x29\
-\x20\x20\x2d\x2d\x3e\x0d\x0a\x3c\x21\x44\x4f\x43\x54\x59\x50\x45\
-\x20\x73\x76\x67\x20\x50\x55\x42\x4c\x49\x43\x20\x22\x2d\x2f\x2f\
-\x57\x33\x43\x2f\x2f\x44\x54\x44\x20\x53\x56\x47\x20\x31\x2e\x31\
-\x2f\x2f\x45\x4e\x22\x20\x22\x68\x74\x74\x70\x3a\x2f\x2f\x77\x77\
-\x77\x2e\x77\x33\x2e\x6f\x72\x67\x2f\x47\x72\x61\x70\x68\x69\x63\
-\x73\x2f\x53\x56\x47\x2f\x31\x2e\x31\x2f\x44\x54\x44\x2f\x73\x76\
-\x67\x31\x31\x2e\x64\x74\x64\x22\x3e\x0d\x0a\x3c\x73\x76\x67\x20\
-\x76\x65\x72\x73\x69\x6f\x6e\x3d\x22\x31\x2e\x31\x22\x20\x69\x64\
-\x3d\x22\x4c\x61\x79\x65\x72\x5f\x31\x22\x20\x78\x6d\x6c\x6e\x73\
-\x3d\x22\x68\x74\x74\x70\x3a\x2f\x2f\x77\x77\x77\x2e\x77\x33\x2e\
-\x6f\x72\x67\x2f\x32\x30\x30\x30\x2f\x73\x76\x67\x22\x20\x78\x6d\
-\x6c\x6e\x73\x3a\x78\x6c\x69\x6e\x6b\x3d\x22\x68\x74\x74\x70\x3a\
-\x2f\x2f\x77\x77\x77\x2e\x77\x33\x2e\x6f\x72\x67\x2f\x31\x39\x39\
-\x39\x2f\x78\x6c\x69\x6e\x6b\x22\x20\x78\x3d\x22\x30\x70\x78\x22\
-\x20\x79\x3d\x22\x30\x70\x78\x22\x0d\x0a\x09\x20\x77\x69\x64\x74\
-\x68\x3d\x22\x35\x31\x32\x70\x78\x22\x20\x68\x65\x69\x67\x68\x74\
-\x3d\x22\x35\x31\x32\x70\x78\x22\x20\x76\x69\x65\x77\x42\x6f\x78\
-\x3d\x22\x30\x20\x30\x20\x35\x31\x32\x20\x35\x31\x32\x22\x20\x65\
-\x6e\x61\x62\x6c\x65\x2d\x62\x61\x63\x6b\x67\x72\x6f\x75\x6e\x64\
-\x3d\x22\x6e\x65\x77\x20\x30\x20\x30\x20\x35\x31\x32\x20\x35\x31\
-\x32\x22\x20\x78\x6d\x6c\x3a\x73\x70\x61\x63\x65\x3d\x22\x70\x72\
-\x65\x73\x65\x72\x76\x65\x22\x3e\x0d\x0a\x3c\x67\x20\x69\x64\x3d\
-\x22\x49\x63\x6f\x6e\x5f\x32\x31\x5f\x22\x3e\x0d\x0a\x09\x3c\x67\
-\x3e\x0d\x0a\x09\x09\x3c\x70\x61\x74\x68\x20\x64\x3d\x22\x4d\x32\
-\x35\x36\x2c\x31\x35\x32\x63\x2d\x35\x37\x2e\x32\x2c\x30\x2d\x31\
-\x30\x34\x2c\x34\x36\x2e\x38\x2d\x31\x30\x34\x2c\x31\x30\x34\x73\
-\x34\x36\x2e\x38\x2c\x31\x30\x34\x2c\x31\x30\x34\x2c\x31\x30\x34\
-\x73\x31\x30\x34\x2d\x34\x36\x2e\x38\x2c\x31\x30\x34\x2d\x31\x30\
-\x34\x53\x33\x31\x33\x2e\x32\x2c\x31\x35\x32\x2c\x32\x35\x36\x2c\
-\x31\x35\x32\x7a\x20\x4d\x32\x35\x36\x2c\x34\x38\x0d\x0a\x09\x09\
-\x09\x43\x31\x34\x31\x2e\x36\x30\x31\x2c\x34\x38\x2c\x34\x38\x2c\
-\x31\x34\x31\x2e\x36\x30\x31\x2c\x34\x38\x2c\x32\x35\x36\x73\x39\
-\x33\x2e\x36\x30\x31\x2c\x32\x30\x38\x2c\x32\x30\x38\x2c\x32\x30\
-\x38\x73\x32\x30\x38\x2d\x39\x33\x2e\x36\x30\x31\x2c\x32\x30\x38\
-\x2d\x32\x30\x38\x53\x33\x37\x30\x2e\x33\x39\x39\x2c\x34\x38\x2c\
-\x32\x35\x36\x2c\x34\x38\x7a\x20\x4d\x32\x35\x36\x2c\x34\x32\x32\
-\x2e\x34\x0d\x0a\x09\x09\x09\x63\x2d\x39\x31\x2e\x35\x31\x38\x2c\
-\x30\x2d\x31\x36\x36\x2e\x34\x2d\x37\x34\x2e\x38\x38\x33\x2d\x31\
-\x36\x36\x2e\x34\x2d\x31\x36\x36\x2e\x34\x53\x31\x36\x34\x2e\x34\
-\x38\x32\x2c\x38\x39\x2e\x36\x2c\x32\x35\x36\x2c\x38\x39\x2e\x36\
-\x53\x34\x32\x32\x2e\x34\x2c\x31\x36\x34\x2e\x34\x38\x32\x2c\x34\
-\x32\x32\x2e\x34\x2c\x32\x35\x36\x53\x33\x34\x37\x2e\x35\x31\x38\
-\x2c\x34\x32\x32\x2e\x34\x2c\x32\x35\x36\x2c\x34\x32\x32\x2e\x34\
-\x7a\x22\x2f\x3e\x0d\x0a\x09\x3c\x2f\x67\x3e\x0d\x0a\x3c\x2f\x67\
-\x3e\x0d\x0a\x3c\x2f\x73\x76\x67\x3e\x0d\x0a\
-\x00\x00\x02\x7f\
-\x3c\
-\x3f\x78\x6d\x6c\x20\x76\x65\x72\x73\x69\x6f\x6e\x3d\x22\x31\x2e\
-\x30\x22\x20\x65\x6e\x63\x6f\x64\x69\x6e\x67\x3d\x22\x75\x74\x66\
-\x2d\x38\x22\x3f\x3e\x0d\x0a\x3c\x21\x2d\x2d\x20\x47\x65\x6e\x65\
-\x72\x61\x74\x6f\x72\x3a\x20\x41\x64\x6f\x62\x65\x20\x49\x6c\x6c\
-\x75\x73\x74\x72\x61\x74\x6f\x72\x20\x31\x36\x2e\x32\x2e\x31\x2c\
-\x20\x53\x56\x47\x20\x45\x78\x70\x6f\x72\x74\x20\x50\x6c\x75\x67\
-\x2d\x49\x6e\x20\x2e\x20\x53\x56\x47\x20\x56\x65\x72\x73\x69\x6f\
-\x6e\x3a\x20\x36\x2e\x30\x30\x20\x42\x75\x69\x6c\x64\x20\x30\x29\
-\x20\x20\x2d\x2d\x3e\x0d\x0a\x3c\x21\x44\x4f\x43\x54\x59\x50\x45\
-\x20\x73\x76\x67\x20\x50\x55\x42\x4c\x49\x43\x20\x22\x2d\x2f\x2f\
-\x57\x33\x43\x2f\x2f\x44\x54\x44\x20\x53\x56\x47\x20\x31\x2e\x31\
-\x2f\x2f\x45\x4e\x22\x20\x22\x68\x74\x74\x70\x3a\x2f\x2f\x77\x77\
-\x77\x2e\x77\x33\x2e\x6f\x72\x67\x2f\x47\x72\x61\x70\x68\x69\x63\
-\x73\x2f\x53\x56\x47\x2f\x31\x2e\x31\x2f\x44\x54\x44\x2f\x73\x76\
-\x67\x31\x31\x2e\x64\x74\x64\x22\x3e\x0d\x0a\x3c\x73\x76\x67\x20\
-\x76\x65\x72\x73\x69\x6f\x6e\x3d\x22\x31\x2e\x31\x22\x20\x69\x64\
-\x3d\x22\x4c\x61\x79\x65\x72\x5f\x31\x22\x20\x78\x6d\x6c\x6e\x73\
-\x3d\x22\x68\x74\x74\x70\x3a\x2f\x2f\x77\x77\x77\x2e\x77\x33\x2e\
-\x6f\x72\x67\x2f\x32\x30\x30\x30\x2f\x73\x76\x67\x22\x20\x78\x6d\
-\x6c\x6e\x73\x3a\x78\x6c\x69\x6e\x6b\x3d\x22\x68\x74\x74\x70\x3a\
-\x2f\x2f\x77\x77\x77\x2e\x77\x33\x2e\x6f\x72\x67\x2f\x31\x39\x39\
-\x39\x2f\x78\x6c\x69\x6e\x6b\x22\x20\x78\x3d\x22\x30\x70\x78\x22\
-\x20\x79\x3d\x22\x30\x70\x78\x22\x0d\x0a\x09\x20\x77\x69\x64\x74\
-\x68\x3d\x22\x35\x31\x32\x70\x78\x22\x20\x68\x65\x69\x67\x68\x74\
-\x3d\x22\x35\x31\x32\x70\x78\x22\x20\x76\x69\x65\x77\x42\x6f\x78\
-\x3d\x22\x30\x20\x30\x20\x35\x31\x32\x20\x35\x31\x32\x22\x20\x73\
-\x74\x79\x6c\x65\x3d\x22\x65\x6e\x61\x62\x6c\x65\x2d\x62\x61\x63\
-\x6b\x67\x72\x6f\x75\x6e\x64\x3a\x6e\x65\x77\x20\x30\x20\x30\x20\
-\x35\x31\x32\x20\x35\x31\x32\x3b\x22\x20\x78\x6d\x6c\x3a\x73\x70\
-\x61\x63\x65\x3d\x22\x70\x72\x65\x73\x65\x72\x76\x65\x22\x3e\x0d\
-\x0a\x3c\x70\x6f\x6c\x79\x67\x6f\x6e\x20\x70\x6f\x69\x6e\x74\x73\
-\x3d\x22\x32\x38\x38\x2c\x39\x36\x20\x33\x33\x37\x2e\x39\x2c\x31\
-\x34\x35\x2e\x39\x20\x32\x37\x34\x2c\x32\x30\x39\x2e\x37\x20\x32\
-\x37\x34\x2c\x32\x30\x39\x2e\x37\x20\x31\x34\x35\x2e\x39\x2c\x33\
-\x33\x37\x2e\x39\x20\x39\x36\x2c\x32\x38\x38\x20\x39\x36\x2c\x34\
-\x31\x36\x20\x32\x32\x34\x2c\x34\x31\x36\x20\x31\x37\x34\x2e\x31\
-\x2c\x33\x36\x36\x2e\x31\x20\x33\x35\x37\x2e\x34\x2c\x31\x38\x32\
-\x2e\x39\x20\x33\x36\x36\x2e\x31\x2c\x31\x37\x34\x2e\x31\x20\x0d\
-\x0a\x09\x34\x31\x36\x2c\x32\x32\x34\x20\x34\x31\x36\x2c\x39\x36\
-\x20\x22\x2f\x3e\x0d\x0a\x3c\x2f\x73\x76\x67\x3e\x0d\x0a\
-\x00\x00\x02\xa2\
-\x3c\
-\x3f\x78\x6d\x6c\x20\x76\x65\x72\x73\x69\x6f\x6e\x3d\x22\x31\x2e\
-\x30\x22\x20\x65\x6e\x63\x6f\x64\x69\x6e\x67\x3d\x22\x75\x74\x66\
-\x2d\x38\x22\x3f\x3e\x0d\x0a\x3c\x21\x2d\x2d\x20\x47\x65\x6e\x65\
-\x72\x61\x74\x6f\x72\x3a\x20\x41\x64\x6f\x62\x65\x20\x49\x6c\x6c\
-\x75\x73\x74\x72\x61\x74\x6f\x72\x20\x31\x36\x2e\x32\x2e\x31\x2c\
-\x20\x53\x56\x47\x20\x45\x78\x70\x6f\x72\x74\x20\x50\x6c\x75\x67\
-\x2d\x49\x6e\x20\x2e\x20\x53\x56\x47\x20\x56\x65\x72\x73\x69\x6f\
-\x6e\x3a\x20\x36\x2e\x30\x30\x20\x42\x75\x69\x6c\x64\x20\x30\x29\
-\x20\x20\x2d\x2d\x3e\x0d\x0a\x3c\x21\x44\x4f\x43\x54\x59\x50\x45\
-\x20\x73\x76\x67\x20\x50\x55\x42\x4c\x49\x43\x20\x22\x2d\x2f\x2f\
-\x57\x33\x43\x2f\x2f\x44\x54\x44\x20\x53\x56\x47\x20\x31\x2e\x31\
-\x2f\x2f\x45\x4e\x22\x20\x22\x68\x74\x74\x70\x3a\x2f\x2f\x77\x77\
-\x77\x2e\x77\x33\x2e\x6f\x72\x67\x2f\x47\x72\x61\x70\x68\x69\x63\
-\x73\x2f\x53\x56\x47\x2f\x31\x2e\x31\x2f\x44\x54\x44\x2f\x73\x76\
-\x67\x31\x31\x2e\x64\x74\x64\x22\x3e\x0d\x0a\x3c\x73\x76\x67\x20\
-\x76\x65\x72\x73\x69\x6f\x6e\x3d\x22\x31\x2e\x31\x22\x20\x69\x64\
-\x3d\x22\x4c\x61\x79\x65\x72\x5f\x31\x22\x20\x78\x6d\x6c\x6e\x73\
-\x3d\x22\x68\x74\x74\x70\x3a\x2f\x2f\x77\x77\x77\x2e\x77\x33\x2e\
-\x6f\x72\x67\x2f\x32\x30\x30\x30\x2f\x73\x76\x67\x22\x20\x78\x6d\
-\x6c\x6e\x73\x3a\x78\x6c\x69\x6e\x6b\x3d\x22\x68\x74\x74\x70\x3a\
-\x2f\x2f\x77\x77\x77\x2e\x77\x33\x2e\x6f\x72\x67\x2f\x31\x39\x39\
-\x39\x2f\x78\x6c\x69\x6e\x6b\x22\x20\x78\x3d\x22\x30\x70\x78\x22\
-\x20\x79\x3d\x22\x30\x70\x78\x22\x0d\x0a\x09\x20\x77\x69\x64\x74\
-\x68\x3d\x22\x35\x31\x32\x70\x78\x22\x20\x68\x65\x69\x67\x68\x74\
-\x3d\x22\x35\x31\x32\x70\x78\x22\x20\x76\x69\x65\x77\x42\x6f\x78\
-\x3d\x22\x30\x20\x30\x20\x35\x31\x32\x20\x35\x31\x32\x22\x20\x65\
-\x6e\x61\x62\x6c\x65\x2d\x62\x61\x63\x6b\x67\x72\x6f\x75\x6e\x64\
-\x3d\x22\x6e\x65\x77\x20\x30\x20\x30\x20\x35\x31\x32\x20\x35\x31\
-\x32\x22\x20\x78\x6d\x6c\x3a\x73\x70\x61\x63\x65\x3d\x22\x70\x72\
-\x65\x73\x65\x72\x76\x65\x22\x3e\x0d\x0a\x3c\x67\x3e\x0d\x0a\x09\
-\x3c\x70\x61\x74\x68\x20\x64\x3d\x22\x4d\x31\x32\x38\x2c\x34\x30\
-\x35\x2e\x34\x32\x39\x43\x31\x32\x38\x2c\x34\x32\x38\x2e\x38\x34\
-\x36\x2c\x31\x34\x37\x2e\x31\x39\x38\x2c\x34\x34\x38\x2c\x31\x37\
-\x30\x2e\x36\x36\x37\x2c\x34\x34\x38\x68\x31\x37\x30\x2e\x36\x36\
-\x37\x43\x33\x36\x34\x2e\x38\x30\x32\x2c\x34\x34\x38\x2c\x33\x38\
-\x34\x2c\x34\x32\x38\x2e\x38\x34\x36\x2c\x33\x38\x34\x2c\x34\x30\
-\x35\x2e\x34\x32\x39\x56\x31\x36\x30\x48\x31\x32\x38\x56\x34\x30\
-\x35\x2e\x34\x32\x39\x7a\x20\x4d\x34\x31\x36\x2c\x39\x36\x0d\x0a\
-\x09\x09\x68\x2d\x38\x30\x6c\x2d\x32\x36\x2e\x37\x38\x35\x2d\x33\
-\x32\x48\x32\x30\x32\x2e\x37\x38\x36\x4c\x31\x37\x36\x2c\x39\x36\
-\x48\x39\x36\x76\x33\x32\x68\x33\x32\x30\x56\x39\x36\x7a\x22\x2f\
-\x3e\x0d\x0a\x3c\x2f\x67\x3e\x0d\x0a\x3c\x2f\x73\x76\x67\x3e\x0d\
-\x0a\
-\x00\x00\x04\x3d\
-\x3c\
-\x3f\x78\x6d\x6c\x20\x76\x65\x72\x73\x69\x6f\x6e\x3d\x27\x31\x2e\
-\x30\x27\x20\x65\x6e\x63\x6f\x64\x69\x6e\x67\x3d\x27\x55\x54\x46\
-\x2d\x38\x27\x3f\x3e\x0a\x3c\x21\x2d\x2d\x20\x54\x68\x69\x73\x20\
-\x66\x69\x6c\x65\x20\x77\x61\x73\x20\x67\x65\x6e\x65\x72\x61\x74\
-\x65\x64\x20\x62\x79\x20\x64\x76\x69\x73\x76\x67\x6d\x20\x32\x2e\
-\x38\x20\x2d\x2d\x3e\x0a\x3c\x73\x76\x67\x20\x76\x65\x72\x73\x69\
-\x6f\x6e\x3d\x27\x31\x2e\x31\x27\x20\x78\x6d\x6c\x6e\x73\x3d\x27\
-\x68\x74\x74\x70\x3a\x2f\x2f\x77\x77\x77\x2e\x77\x33\x2e\x6f\x72\
-\x67\x2f\x32\x30\x30\x30\x2f\x73\x76\x67\x27\x20\x78\x6d\x6c\x6e\
-\x73\x3a\x78\x6c\x69\x6e\x6b\x3d\x27\x68\x74\x74\x70\x3a\x2f\x2f\
-\x77\x77\x77\x2e\x77\x33\x2e\x6f\x72\x67\x2f\x31\x39\x39\x39\x2f\
-\x78\x6c\x69\x6e\x6b\x27\x20\x77\x69\x64\x74\x68\x3d\x27\x36\x33\
-\x2e\x39\x39\x39\x36\x70\x74\x27\x20\x68\x65\x69\x67\x68\x74\x3d\
-\x27\x36\x33\x2e\x39\x39\x39\x37\x70\x74\x27\x20\x76\x69\x65\x77\
-\x42\x6f\x78\x3d\x27\x35\x36\x2e\x34\x30\x39\x34\x20\x35\x33\x2e\
-\x38\x35\x38\x33\x20\x36\x33\x2e\x39\x39\x39\x36\x20\x36\x33\x2e\
-\x39\x39\x39\x37\x27\x3e\x0a\x3c\x67\x20\x69\x64\x3d\x27\x70\x61\
-\x67\x65\x31\x27\x3e\x0a\x3c\x67\x20\x74\x72\x61\x6e\x73\x66\x6f\
-\x72\x6d\x3d\x27\x6d\x61\x74\x72\x69\x78\x28\x30\x2e\x39\x39\x36\
-\x32\x36\x34\x20\x30\x20\x30\x20\x30\x2e\x39\x39\x36\x32\x36\x34\
-\x20\x35\x38\x2e\x34\x36\x36\x39\x20\x31\x31\x37\x2e\x38\x35\x38\
-\x29\x27\x3e\x0a\x3c\x70\x61\x74\x68\x20\x64\x3d\x27\x4d\x20\x33\
-\x2e\x39\x35\x37\x33\x35\x20\x2d\x33\x32\x2e\x31\x32\x4c\x20\x31\
-\x31\x2e\x39\x30\x33\x36\x20\x2d\x35\x31\x2e\x33\x30\x33\x39\x4c\
-\x20\x35\x36\x2e\x31\x35\x32\x33\x20\x2d\x34\x32\x2e\x35\x30\x32\
-\x32\x4c\x20\x34\x30\x2e\x36\x37\x39\x34\x20\x2d\x32\x32\x2e\x35\
-\x32\x38\x31\x27\x20\x66\x69\x6c\x6c\x3d\x27\x6e\x6f\x6e\x65\x27\
-\x20\x73\x74\x72\x6f\x6b\x65\x3d\x27\x23\x30\x30\x30\x30\x30\x30\
-\x27\x20\x73\x74\x72\x6f\x6b\x65\x2d\x6c\x69\x6e\x65\x63\x61\x70\
-\x3d\x27\x72\x6f\x75\x6e\x64\x27\x20\x73\x74\x72\x6f\x6b\x65\x2d\
-\x6c\x69\x6e\x65\x6a\x6f\x69\x6e\x3d\x27\x72\x6f\x75\x6e\x64\x27\
-\x20\x73\x74\x72\x6f\x6b\x65\x2d\x6d\x69\x74\x65\x72\x6c\x69\x6d\
-\x69\x74\x3d\x27\x31\x30\x2e\x30\x33\x37\x35\x27\x20\x73\x74\x72\
-\x6f\x6b\x65\x2d\x77\x69\x64\x74\x68\x3d\x27\x32\x2e\x35\x30\x39\
-\x33\x37\x27\x2f\x3e\x0a\x3c\x2f\x67\x3e\x0a\x3c\x67\x20\x74\x72\
-\x61\x6e\x73\x66\x6f\x72\x6d\x3d\x27\x6d\x61\x74\x72\x69\x78\x28\
-\x30\x2e\x39\x39\x36\x32\x36\x34\x20\x30\x20\x30\x20\x30\x2e\x39\
-\x39\x36\x32\x36\x34\x20\x35\x38\x2e\x34\x36\x36\x39\x20\x31\x31\
-\x37\x2e\x38\x35\x38\x29\x27\x3e\x0a\x3c\x63\x69\x72\x63\x6c\x65\
-\x20\x63\x78\x3d\x27\x33\x2e\x39\x35\x37\x33\x35\x27\x20\x63\x79\
-\x3d\x27\x2d\x33\x32\x2e\x31\x32\x27\x20\x66\x69\x6c\x6c\x3d\x27\
-\x23\x30\x30\x30\x30\x30\x30\x27\x20\x72\x3d\x27\x36\x2e\x30\x32\
-\x32\x35\x27\x2f\x3e\x0a\x3c\x2f\x67\x3e\x0a\x3c\x67\x20\x74\x72\
-\x61\x6e\x73\x66\x6f\x72\x6d\x3d\x27\x6d\x61\x74\x72\x69\x78\x28\
-\x30\x2e\x39\x39\x36\x32\x36\x34\x20\x30\x20\x30\x20\x30\x2e\x39\
-\x39\x36\x32\x36\x34\x20\x35\x38\x2e\x34\x36\x36\x39\x20\x31\x31\
-\x37\x2e\x38\x35\x38\x29\x27\x3e\x0a\x3c\x63\x69\x72\x63\x6c\x65\
-\x20\x63\x78\x3d\x27\x31\x31\x2e\x39\x30\x33\x36\x27\x20\x63\x79\
-\x3d\x27\x2d\x35\x31\x2e\x33\x30\x33\x39\x27\x20\x66\x69\x6c\x6c\
-\x3d\x27\x23\x30\x30\x30\x30\x30\x30\x27\x20\x72\x3d\x27\x36\x2e\
-\x30\x32\x32\x35\x27\x2f\x3e\x0a\x3c\x2f\x67\x3e\x0a\x3c\x67\x20\
-\x74\x72\x61\x6e\x73\x66\x6f\x72\x6d\x3d\x27\x6d\x61\x74\x72\x69\
-\x78\x28\x30\x2e\x39\x39\x36\x32\x36\x34\x20\x30\x20\x30\x20\x30\
-\x2e\x39\x39\x36\x32\x36\x34\x20\x35\x38\x2e\x34\x36\x36\x39\x20\
-\x31\x31\x37\x2e\x38\x35\x38\x29\x27\x3e\x0a\x3c\x63\x69\x72\x63\
-\x6c\x65\x20\x63\x78\x3d\x27\x35\x36\x2e\x31\x35\x32\x33\x27\x20\
-\x63\x79\x3d\x27\x2d\x34\x32\x2e\x35\x30\x32\x32\x27\x20\x66\x69\
-\x6c\x6c\x3d\x27\x23\x30\x30\x30\x30\x30\x30\x27\x20\x72\x3d\x27\
-\x36\x2e\x30\x32\x32\x35\x27\x2f\x3e\x0a\x3c\x2f\x67\x3e\x0a\x3c\
-\x67\x20\x74\x72\x61\x6e\x73\x66\x6f\x72\x6d\x3d\x27\x6d\x61\x74\
-\x72\x69\x78\x28\x30\x2e\x39\x39\x36\x32\x36\x34\x20\x30\x20\x30\
-\x20\x30\x2e\x39\x39\x36\x32\x36\x34\x20\x35\x38\x2e\x34\x36\x36\
-\x39\x20\x31\x31\x37\x2e\x38\x35\x38\x29\x27\x3e\x0a\x3c\x63\x69\
-\x72\x63\x6c\x65\x20\x63\x78\x3d\x27\x34\x30\x2e\x36\x37\x39\x34\
-\x27\x20\x63\x79\x3d\x27\x2d\x32\x32\x2e\x35\x32\x38\x31\x27\x20\
-\x66\x69\x6c\x6c\x3d\x27\x23\x30\x30\x30\x30\x30\x30\x27\x20\x72\
-\x3d\x27\x36\x2e\x30\x32\x32\x35\x27\x2f\x3e\x0a\x3c\x2f\x67\x3e\
-\x0a\x3c\x2f\x67\x3e\x0a\x3c\x2f\x73\x76\x67\x3e\
-\x00\x00\x02\x7d\
-\x3c\
-\x3f\x78\x6d\x6c\x20\x76\x65\x72\x73\x69\x6f\x6e\x3d\x22\x31\x2e\
-\x30\x22\x20\x65\x6e\x63\x6f\x64\x69\x6e\x67\x3d\x22\x75\x74\x66\
-\x2d\x38\x22\x3f\x3e\x0d\x0a\x3c\x21\x2d\x2d\x20\x47\x65\x6e\x65\
-\x72\x61\x74\x6f\x72\x3a\x20\x41\x64\x6f\x62\x65\x20\x49\x6c\x6c\
-\x75\x73\x74\x72\x61\x74\x6f\x72\x20\x31\x36\x2e\x32\x2e\x31\x2c\
-\x20\x53\x56\x47\x20\x45\x78\x70\x6f\x72\x74\x20\x50\x6c\x75\x67\
-\x2d\x49\x6e\x20\x2e\x20\x53\x56\x47\x20\x56\x65\x72\x73\x69\x6f\
-\x6e\x3a\x20\x36\x2e\x30\x30\x20\x42\x75\x69\x6c\x64\x20\x30\x29\
-\x20\x20\x2d\x2d\x3e\x0d\x0a\x3c\x21\x44\x4f\x43\x54\x59\x50\x45\
-\x20\x73\x76\x67\x20\x50\x55\x42\x4c\x49\x43\x20\x22\x2d\x2f\x2f\
-\x57\x33\x43\x2f\x2f\x44\x54\x44\x20\x53\x56\x47\x20\x31\x2e\x31\
-\x2f\x2f\x45\x4e\x22\x20\x22\x68\x74\x74\x70\x3a\x2f\x2f\x77\x77\
-\x77\x2e\x77\x33\x2e\x6f\x72\x67\x2f\x47\x72\x61\x70\x68\x69\x63\
-\x73\x2f\x53\x56\x47\x2f\x31\x2e\x31\x2f\x44\x54\x44\x2f\x73\x76\
-\x67\x31\x31\x2e\x64\x74\x64\x22\x3e\x0d\x0a\x3c\x73\x76\x67\x20\
-\x76\x65\x72\x73\x69\x6f\x6e\x3d\x22\x31\x2e\x31\x22\x20\x69\x64\
-\x3d\x22\x4c\x61\x79\x65\x72\x5f\x31\x22\x20\x78\x6d\x6c\x6e\x73\
-\x3d\x22\x68\x74\x74\x70\x3a\x2f\x2f\x77\x77\x77\x2e\x77\x33\x2e\
-\x6f\x72\x67\x2f\x32\x30\x30\x30\x2f\x73\x76\x67\x22\x20\x78\x6d\
-\x6c\x6e\x73\x3a\x78\x6c\x69\x6e\x6b\x3d\x22\x68\x74\x74\x70\x3a\
-\x2f\x2f\x77\x77\x77\x2e\x77\x33\x2e\x6f\x72\x67\x2f\x31\x39\x39\
-\x39\x2f\x78\x6c\x69\x6e\x6b\x22\x20\x78\x3d\x22\x30\x70\x78\x22\
-\x20\x79\x3d\x22\x30\x70\x78\x22\x0d\x0a\x09\x20\x77\x69\x64\x74\
-\x68\x3d\x22\x35\x31\x32\x70\x78\x22\x20\x68\x65\x69\x67\x68\x74\
-\x3d\x22\x35\x31\x32\x70\x78\x22\x20\x76\x69\x65\x77\x42\x6f\x78\
-\x3d\x22\x30\x20\x30\x20\x35\x31\x32\x20\x35\x31\x32\x22\x20\x65\
-\x6e\x61\x62\x6c\x65\x2d\x62\x61\x63\x6b\x67\x72\x6f\x75\x6e\x64\
-\x3d\x22\x6e\x65\x77\x20\x30\x20\x30\x20\x35\x31\x32\x20\x35\x31\
-\x32\x22\x20\x78\x6d\x6c\x3a\x73\x70\x61\x63\x65\x3d\x22\x70\x72\
-\x65\x73\x65\x72\x76\x65\x22\x3e\x0d\x0a\x3c\x67\x20\x69\x64\x3d\
-\x22\x49\x63\x6f\x6e\x5f\x38\x5f\x22\x3e\x0d\x0a\x09\x3c\x67\x3e\
-\x0d\x0a\x09\x09\x3c\x70\x61\x74\x68\x20\x64\x3d\x22\x4d\x34\x32\
-\x37\x2c\x32\x33\x34\x2e\x36\x32\x35\x48\x31\x36\x37\x2e\x32\x39\
-\x36\x6c\x31\x31\x39\x2e\x37\x30\x32\x2d\x31\x31\x39\x2e\x37\x30\
-\x32\x4c\x32\x35\x36\x2c\x38\x35\x4c\x38\x35\x2c\x32\x35\x36\x6c\
-\x31\x37\x31\x2c\x31\x37\x31\x6c\x32\x39\x2e\x39\x32\x32\x2d\x32\
-\x39\x2e\x39\x32\x34\x4c\x31\x36\x37\x2e\x32\x39\x36\x2c\x32\x37\
-\x37\x2e\x33\x37\x35\x48\x34\x32\x37\x56\x32\x33\x34\x2e\x36\x32\
-\x35\x7a\x22\x2f\x3e\x0d\x0a\x09\x3c\x2f\x67\x3e\x0d\x0a\x3c\x2f\
-\x67\x3e\x0d\x0a\x3c\x2f\x73\x76\x67\x3e\x0d\x0a\
-\x00\x00\x02\xc9\
-\x3c\
-\x3f\x78\x6d\x6c\x20\x76\x65\x72\x73\x69\x6f\x6e\x3d\x22\x31\x2e\
-\x30\x22\x20\x65\x6e\x63\x6f\x64\x69\x6e\x67\x3d\x22\x75\x74\x66\
-\x2d\x38\x22\x3f\x3e\x0d\x0a\x3c\x21\x2d\x2d\x20\x47\x65\x6e\x65\
-\x72\x61\x74\x6f\x72\x3a\x20\x41\x64\x6f\x62\x65\x20\x49\x6c\x6c\
-\x75\x73\x74\x72\x61\x74\x6f\x72\x20\x31\x36\x2e\x32\x2e\x31\x2c\
-\x20\x53\x56\x47\x20\x45\x78\x70\x6f\x72\x74\x20\x50\x6c\x75\x67\
-\x2d\x49\x6e\x20\x2e\x20\x53\x56\x47\x20\x56\x65\x72\x73\x69\x6f\
-\x6e\x3a\x20\x36\x2e\x30\x30\x20\x42\x75\x69\x6c\x64\x20\x30\x29\
-\x20\x20\x2d\x2d\x3e\x0d\x0a\x3c\x21\x44\x4f\x43\x54\x59\x50\x45\
-\x20\x73\x76\x67\x20\x50\x55\x42\x4c\x49\x43\x20\x22\x2d\x2f\x2f\
-\x57\x33\x43\x2f\x2f\x44\x54\x44\x20\x53\x56\x47\x20\x31\x2e\x31\
-\x2f\x2f\x45\x4e\x22\x20\x22\x68\x74\x74\x70\x3a\x2f\x2f\x77\x77\
-\x77\x2e\x77\x33\x2e\x6f\x72\x67\x2f\x47\x72\x61\x70\x68\x69\x63\
-\x73\x2f\x53\x56\x47\x2f\x31\x2e\x31\x2f\x44\x54\x44\x2f\x73\x76\
-\x67\x31\x31\x2e\x64\x74\x64\x22\x3e\x0d\x0a\x3c\x73\x76\x67\x20\
-\x76\x65\x72\x73\x69\x6f\x6e\x3d\x22\x31\x2e\x31\x22\x20\x69\x64\
-\x3d\x22\x4c\x61\x79\x65\x72\x5f\x31\x22\x20\x78\x6d\x6c\x6e\x73\
-\x3d\x22\x68\x74\x74\x70\x3a\x2f\x2f\x77\x77\x77\x2e\x77\x33\x2e\
-\x6f\x72\x67\x2f\x32\x30\x30\x30\x2f\x73\x76\x67\x22\x20\x78\x6d\
-\x6c\x6e\x73\x3a\x78\x6c\x69\x6e\x6b\x3d\x22\x68\x74\x74\x70\x3a\
-\x2f\x2f\x77\x77\x77\x2e\x77\x33\x2e\x6f\x72\x67\x2f\x31\x39\x39\
-\x39\x2f\x78\x6c\x69\x6e\x6b\x22\x20\x78\x3d\x22\x30\x70\x78\x22\
-\x20\x79\x3d\x22\x30\x70\x78\x22\x0d\x0a\x09\x20\x77\x69\x64\x74\
-\x68\x3d\x22\x35\x31\x32\x70\x78\x22\x20\x68\x65\x69\x67\x68\x74\
-\x3d\x22\x35\x31\x32\x70\x78\x22\x20\x76\x69\x65\x77\x42\x6f\x78\
-\x3d\x22\x30\x20\x30\x20\x35\x31\x32\x20\x35\x31\x32\x22\x20\x73\
-\x74\x79\x6c\x65\x3d\x22\x65\x6e\x61\x62\x6c\x65\x2d\x62\x61\x63\
-\x6b\x67\x72\x6f\x75\x6e\x64\x3a\x6e\x65\x77\x20\x30\x20\x30\x20\
-\x35\x31\x32\x20\x35\x31\x32\x3b\x22\x20\x78\x6d\x6c\x3a\x73\x70\
-\x61\x63\x65\x3d\x22\x70\x72\x65\x73\x65\x72\x76\x65\x22\x3e\x0d\
-\x0a\x3c\x70\x6f\x6c\x79\x67\x6f\x6e\x20\x70\x6f\x69\x6e\x74\x73\
-\x3d\x22\x34\x38\x30\x2c\x32\x35\x36\x20\x33\x38\x34\x2c\x31\x36\
-\x30\x20\x33\x38\x34\x2c\x32\x33\x36\x20\x32\x37\x36\x2c\x32\x33\
-\x36\x20\x32\x37\x36\x2c\x31\x32\x38\x20\x33\x35\x32\x2c\x31\x32\
-\x38\x20\x32\x35\x36\x2c\x33\x32\x20\x31\x36\x30\x2c\x31\x32\x38\
-\x20\x32\x33\x36\x2c\x31\x32\x38\x20\x32\x33\x36\x2c\x32\x33\x36\
-\x20\x31\x32\x38\x2c\x32\x33\x36\x20\x31\x32\x38\x2c\x31\x36\x30\
-\x20\x33\x32\x2c\x32\x35\x36\x20\x31\x32\x38\x2c\x33\x35\x32\x20\
-\x0d\x0a\x09\x31\x32\x38\x2c\x32\x37\x36\x20\x32\x33\x36\x2c\x32\
-\x37\x36\x20\x32\x33\x36\x2c\x33\x38\x34\x20\x31\x36\x30\x2c\x33\
-\x38\x34\x20\x32\x35\x36\x2c\x34\x38\x30\x20\x33\x35\x32\x2c\x33\
-\x38\x34\x20\x32\x37\x35\x2e\x38\x2c\x33\x38\x34\x20\x32\x37\x35\
-\x2e\x34\x2c\x32\x37\x35\x2e\x35\x20\x33\x38\x34\x2c\x32\x37\x35\
-\x2e\x38\x20\x33\x38\x34\x2c\x33\x35\x32\x20\x22\x2f\x3e\x0d\x0a\
-\x3c\x2f\x73\x76\x67\x3e\x0d\x0a\
-\x00\x00\x05\xca\
-\x3c\
-\x3f\x78\x6d\x6c\x20\x76\x65\x72\x73\x69\x6f\x6e\x3d\x22\x31\x2e\
-\x30\x22\x20\x65\x6e\x63\x6f\x64\x69\x6e\x67\x3d\x22\x75\x74\x66\
-\x2d\x38\x22\x3f\x3e\x0d\x0a\x3c\x21\x2d\x2d\x20\x47\x65\x6e\x65\
-\x72\x61\x74\x6f\x72\x3a\x20\x41\x64\x6f\x62\x65\x20\x49\x6c\x6c\
-\x75\x73\x74\x72\x61\x74\x6f\x72\x20\x31\x36\x2e\x32\x2e\x31\x2c\
-\x20\x53\x56\x47\x20\x45\x78\x70\x6f\x72\x74\x20\x50\x6c\x75\x67\
-\x2d\x49\x6e\x20\x2e\x20\x53\x56\x47\x20\x56\x65\x72\x73\x69\x6f\
-\x6e\x3a\x20\x36\x2e\x30\x30\x20\x42\x75\x69\x6c\x64\x20\x30\x29\
-\x20\x20\x2d\x2d\x3e\x0d\x0a\x3c\x21\x44\x4f\x43\x54\x59\x50\x45\
-\x20\x73\x76\x67\x20\x50\x55\x42\x4c\x49\x43\x20\x22\x2d\x2f\x2f\
-\x57\x33\x43\x2f\x2f\x44\x54\x44\x20\x53\x56\x47\x20\x31\x2e\x31\
-\x2f\x2f\x45\x4e\x22\x20\x22\x68\x74\x74\x70\x3a\x2f\x2f\x77\x77\
-\x77\x2e\x77\x33\x2e\x6f\x72\x67\x2f\x47\x72\x61\x70\x68\x69\x63\
-\x73\x2f\x53\x56\x47\x2f\x31\x2e\x31\x2f\x44\x54\x44\x2f\x73\x76\
-\x67\x31\x31\x2e\x64\x74\x64\x22\x3e\x0d\x0a\x3c\x73\x76\x67\x20\
-\x76\x65\x72\x73\x69\x6f\x6e\x3d\x22\x31\x2e\x31\x22\x20\x69\x64\
-\x3d\x22\x4c\x61\x79\x65\x72\x5f\x31\x22\x20\x78\x6d\x6c\x6e\x73\
-\x3d\x22\x68\x74\x74\x70\x3a\x2f\x2f\x77\x77\x77\x2e\x77\x33\x2e\
-\x6f\x72\x67\x2f\x32\x30\x30\x30\x2f\x73\x76\x67\x22\x20\x78\x6d\
-\x6c\x6e\x73\x3a\x78\x6c\x69\x6e\x6b\x3d\x22\x68\x74\x74\x70\x3a\
-\x2f\x2f\x77\x77\x77\x2e\x77\x33\x2e\x6f\x72\x67\x2f\x31\x39\x39\
-\x39\x2f\x78\x6c\x69\x6e\x6b\x22\x20\x78\x3d\x22\x30\x70\x78\x22\
-\x20\x79\x3d\x22\x30\x70\x78\x22\x0d\x0a\x09\x20\x77\x69\x64\x74\
-\x68\x3d\x22\x35\x31\x32\x70\x78\x22\x20\x68\x65\x69\x67\x68\x74\
-\x3d\x22\x35\x31\x32\x70\x78\x22\x20\x76\x69\x65\x77\x42\x6f\x78\
-\x3d\x22\x30\x20\x30\x20\x35\x31\x32\x20\x35\x31\x32\x22\x20\x65\
-\x6e\x61\x62\x6c\x65\x2d\x62\x61\x63\x6b\x67\x72\x6f\x75\x6e\x64\
-\x3d\x22\x6e\x65\x77\x20\x30\x20\x30\x20\x35\x31\x32\x20\x35\x31\
-\x32\x22\x20\x78\x6d\x6c\x3a\x73\x70\x61\x63\x65\x3d\x22\x70\x72\
-\x65\x73\x65\x72\x76\x65\x22\x3e\x0d\x0a\x3c\x70\x61\x74\x68\x20\
-\x64\x3d\x22\x4d\x34\x35\x30\x2e\x36\x37\x39\x2c\x32\x37\x33\x2e\
-\x35\x63\x2d\x31\x34\x2e\x35\x38\x35\x2d\x31\x34\x2e\x35\x37\x37\
-\x2d\x33\x36\x2e\x30\x35\x34\x2d\x31\x35\x2e\x38\x39\x2d\x35\x30\
-\x2e\x36\x33\x39\x2d\x31\x2e\x33\x31\x32\x6c\x2d\x34\x31\x2e\x36\
-\x38\x37\x2c\x34\x31\x2e\x36\x36\x34\x63\x2d\x31\x30\x2e\x38\x35\
-\x32\x2c\x31\x30\x2e\x38\x33\x36\x2d\x32\x33\x2e\x39\x33\x2c\x31\
-\x30\x2e\x38\x35\x39\x2d\x33\x31\x2e\x35\x36\x34\x2c\x31\x2e\x38\
-\x35\x32\x0d\x0a\x09\x63\x2d\x35\x2e\x30\x35\x37\x2d\x35\x2e\x39\
-\x36\x38\x2d\x33\x2e\x30\x36\x31\x2d\x32\x34\x2e\x33\x37\x34\x2d\
-\x31\x2e\x36\x34\x34\x2d\x33\x36\x2e\x30\x34\x39\x6c\x32\x30\x2e\
-\x39\x30\x37\x2d\x31\x37\x31\x2e\x38\x34\x39\x63\x31\x2e\x38\x36\
-\x37\x2d\x31\x35\x2e\x33\x35\x33\x2d\x39\x2e\x30\x37\x2d\x33\x30\
-\x2e\x31\x38\x35\x2d\x32\x34\x2e\x34\x33\x2d\x33\x32\x2e\x30\x35\
-\x31\x0d\x0a\x09\x63\x2d\x31\x35\x2e\x33\x35\x38\x2d\x31\x2e\x38\
-\x36\x37\x2d\x32\x39\x2e\x33\x32\x32\x2c\x39\x2e\x39\x33\x39\x2d\
-\x33\x31\x2e\x31\x39\x31\x2c\x32\x35\x2e\x32\x38\x39\x4c\x32\x36\
-\x37\x2e\x33\x37\x2c\x32\x33\x36\x2e\x30\x32\x31\x63\x2d\x31\x2e\
-\x32\x30\x35\x2c\x33\x2e\x33\x35\x38\x2d\x33\x2e\x37\x39\x2c\x33\
-\x2e\x39\x33\x38\x2d\x34\x2e\x30\x38\x31\x2d\x30\x2e\x35\x38\x32\
-\x4c\x32\x35\x35\x2e\x34\x34\x2c\x36\x30\x0d\x0a\x09\x63\x30\x2d\
-\x31\x35\x2e\x34\x36\x35\x2d\x31\x32\x2e\x35\x34\x32\x2d\x32\x38\
-\x2d\x32\x38\x2e\x30\x31\x34\x2d\x32\x38\x63\x2d\x31\x35\x2e\x34\
-\x37\x33\x2c\x30\x2d\x32\x38\x2e\x30\x31\x35\x2c\x31\x32\x2e\x35\
-\x33\x35\x2d\x32\x38\x2e\x30\x31\x35\x2c\x32\x38\x6c\x2d\x30\x2e\
-\x35\x35\x32\x2c\x31\x37\x36\x2e\x37\x35\x32\x63\x30\x2e\x31\x34\
-\x36\x2c\x32\x2e\x30\x34\x2d\x31\x2e\x36\x30\x34\x2c\x32\x2e\x36\
-\x32\x34\x2d\x31\x2e\x39\x32\x2c\x30\x2e\x32\x39\x34\x4c\x31\x37\
-\x32\x2e\x30\x31\x36\x2c\x39\x39\x2e\x30\x37\x37\x0d\x0a\x09\x63\
-\x2d\x32\x2e\x37\x35\x2d\x31\x35\x2e\x32\x31\x39\x2d\x31\x37\x2e\
-\x33\x32\x33\x2d\x32\x36\x2e\x32\x30\x33\x2d\x33\x32\x2e\x35\x34\
-\x38\x2d\x32\x33\x2e\x34\x35\x33\x63\x2d\x31\x35\x2e\x32\x32\x37\
-\x2c\x32\x2e\x37\x34\x38\x2d\x32\x35\x2e\x33\x33\x39\x2c\x31\x38\
-\x2e\x31\x38\x37\x2d\x32\x32\x2e\x35\x39\x31\x2c\x33\x33\x2e\x34\
-\x30\x33\x6c\x32\x32\x2e\x31\x39\x33\x2c\x31\x36\x31\x2e\x34\x35\
-\x35\x0d\x0a\x09\x63\x30\x2e\x30\x32\x33\x2c\x32\x2e\x38\x37\x32\
-\x2d\x30\x2e\x39\x34\x31\x2c\x34\x2e\x35\x31\x33\x2d\x32\x2e\x33\
-\x30\x38\x2c\x30\x2e\x38\x33\x31\x6c\x2d\x33\x33\x2e\x31\x30\x39\
-\x2d\x38\x38\x2e\x35\x31\x37\x63\x2d\x35\x2e\x31\x38\x2d\x31\x34\
-\x2e\x35\x37\x32\x2d\x32\x31\x2e\x31\x39\x36\x2d\x32\x33\x2e\x30\
-\x36\x35\x2d\x33\x35\x2e\x37\x37\x36\x2d\x31\x37\x2e\x38\x38\x39\
-\x0d\x0a\x09\x63\x2d\x31\x34\x2e\x35\x37\x39\x2c\x35\x2e\x31\x37\
-\x37\x2d\x32\x32\x2e\x32\x30\x31\x2c\x32\x32\x2e\x30\x36\x31\x2d\
-\x31\x37\x2e\x30\x32\x33\x2c\x33\x36\x2e\x36\x33\x31\x6c\x35\x38\
-\x2e\x30\x34\x32\x2c\x31\x38\x39\x2e\x36\x32\x35\x63\x30\x2e\x33\
-\x30\x33\x2c\x31\x2e\x30\x34\x36\x2c\x30\x2e\x36\x32\x34\x2c\x32\
-\x2e\x30\x38\x35\x2c\x30\x2e\x39\x35\x33\x2c\x33\x2e\x31\x31\x38\
-\x6c\x30\x2e\x31\x32\x31\x2c\x30\x2e\x33\x39\x0d\x0a\x09\x63\x30\
-\x2e\x30\x31\x31\x2c\x30\x2e\x30\x33\x31\x2c\x30\x2e\x30\x32\x35\
-\x2c\x30\x2e\x30\x35\x38\x2c\x30\x2e\x30\x33\x35\x2c\x30\x2e\x30\
-\x38\x38\x43\x31\x32\x36\x2e\x30\x37\x39\x2c\x34\x34\x34\x2e\x32\
-\x33\x33\x2c\x31\x37\x32\x2e\x35\x37\x2c\x34\x38\x30\x2c\x32\x32\
-\x37\x2e\x34\x32\x37\x2c\x34\x38\x30\x63\x33\x35\x2e\x31\x31\x36\
-\x2c\x30\x2c\x37\x31\x2e\x35\x39\x31\x2d\x31\x32\x2e\x33\x37\x38\
-\x2c\x39\x39\x2e\x33\x35\x37\x2d\x33\x33\x2e\x36\x37\x32\x0d\x0a\
-\x09\x63\x30\x2e\x30\x30\x31\x2c\x30\x2c\x30\x2e\x30\x30\x33\x2d\
-\x30\x2e\x30\x30\x32\x2c\x30\x2e\x30\x30\x33\x2d\x30\x2e\x30\x30\
-\x32\x63\x32\x39\x2e\x39\x39\x2d\x31\x38\x2e\x30\x35\x31\x2c\x31\
-\x32\x36\x2e\x30\x37\x31\x2d\x31\x32\x31\x2e\x33\x34\x37\x2c\x31\
-\x32\x36\x2e\x30\x37\x31\x2d\x31\x32\x31\x2e\x33\x34\x37\x43\x34\
-\x36\x37\x2e\x34\x34\x35\x2c\x33\x31\x30\x2e\x34\x30\x32\x2c\x34\
-\x36\x35\x2e\x32\x36\x36\x2c\x32\x38\x38\x2e\x30\x38\x2c\x34\x35\
-\x30\x2e\x36\x37\x39\x2c\x32\x37\x33\x2e\x35\x7a\x22\x2f\x3e\x0d\
-\x0a\x3c\x2f\x73\x76\x67\x3e\x0d\x0a\
-\x00\x00\x03\x52\
-\x3c\
-\x3f\x78\x6d\x6c\x20\x76\x65\x72\x73\x69\x6f\x6e\x3d\x22\x31\x2e\
-\x30\x22\x20\x65\x6e\x63\x6f\x64\x69\x6e\x67\x3d\x22\x75\x74\x66\
-\x2d\x38\x22\x3f\x3e\x0d\x0a\x3c\x21\x2d\x2d\x20\x47\x65\x6e\x65\
-\x72\x61\x74\x6f\x72\x3a\x20\x41\x64\x6f\x62\x65\x20\x49\x6c\x6c\
-\x75\x73\x74\x72\x61\x74\x6f\x72\x20\x31\x36\x2e\x32\x2e\x31\x2c\
-\x20\x53\x56\x47\x20\x45\x78\x70\x6f\x72\x74\x20\x50\x6c\x75\x67\
-\x2d\x49\x6e\x20\x2e\x20\x53\x56\x47\x20\x56\x65\x72\x73\x69\x6f\
-\x6e\x3a\x20\x36\x2e\x30\x30\x20\x42\x75\x69\x6c\x64\x20\x30\x29\
-\x20\x20\x2d\x2d\x3e\x0d\x0a\x3c\x21\x44\x4f\x43\x54\x59\x50\x45\
-\x20\x73\x76\x67\x20\x50\x55\x42\x4c\x49\x43\x20\x22\x2d\x2f\x2f\
-\x57\x33\x43\x2f\x2f\x44\x54\x44\x20\x53\x56\x47\x20\x31\x2e\x31\
-\x2f\x2f\x45\x4e\x22\x20\x22\x68\x74\x74\x70\x3a\x2f\x2f\x77\x77\
-\x77\x2e\x77\x33\x2e\x6f\x72\x67\x2f\x47\x72\x61\x70\x68\x69\x63\
-\x73\x2f\x53\x56\x47\x2f\x31\x2e\x31\x2f\x44\x54\x44\x2f\x73\x76\
-\x67\x31\x31\x2e\x64\x74\x64\x22\x3e\x0d\x0a\x3c\x73\x76\x67\x20\
-\x76\x65\x72\x73\x69\x6f\x6e\x3d\x22\x31\x2e\x31\x22\x20\x69\x64\
-\x3d\x22\x4c\x61\x79\x65\x72\x5f\x31\x22\x20\x78\x6d\x6c\x6e\x73\
-\x3d\x22\x68\x74\x74\x70\x3a\x2f\x2f\x77\x77\x77\x2e\x77\x33\x2e\
-\x6f\x72\x67\x2f\x32\x30\x30\x30\x2f\x73\x76\x67\x22\x20\x78\x6d\
-\x6c\x6e\x73\x3a\x78\x6c\x69\x6e\x6b\x3d\x22\x68\x74\x74\x70\x3a\
-\x2f\x2f\x77\x77\x77\x2e\x77\x33\x2e\x6f\x72\x67\x2f\x31\x39\x39\
-\x39\x2f\x78\x6c\x69\x6e\x6b\x22\x20\x78\x3d\x22\x30\x70\x78\x22\
-\x20\x79\x3d\x22\x30\x70\x78\x22\x0d\x0a\x09\x20\x77\x69\x64\x74\
-\x68\x3d\x22\x35\x31\x32\x70\x78\x22\x20\x68\x65\x69\x67\x68\x74\
-\x3d\x22\x35\x31\x32\x70\x78\x22\x20\x76\x69\x65\x77\x42\x6f\x78\
-\x3d\x22\x30\x20\x30\x20\x35\x31\x32\x20\x35\x31\x32\x22\x20\x65\
-\x6e\x61\x62\x6c\x65\x2d\x62\x61\x63\x6b\x67\x72\x6f\x75\x6e\x64\
-\x3d\x22\x6e\x65\x77\x20\x30\x20\x30\x20\x35\x31\x32\x20\x35\x31\
-\x32\x22\x20\x78\x6d\x6c\x3a\x73\x70\x61\x63\x65\x3d\x22\x70\x72\
-\x65\x73\x65\x72\x76\x65\x22\x3e\x0d\x0a\x3c\x70\x61\x74\x68\x20\
-\x64\x3d\x22\x4d\x34\x33\x37\x2e\x33\x33\x34\x2c\x31\x34\x34\x48\
-\x32\x35\x36\x2e\x30\x30\x36\x6c\x2d\x34\x32\x2e\x36\x36\x38\x2d\
-\x34\x38\x48\x37\x34\x2e\x36\x36\x36\x43\x35\x31\x2e\x31\x39\x37\
-\x2c\x39\x36\x2c\x33\x32\x2c\x31\x31\x35\x2e\x31\x39\x38\x2c\x33\
-\x32\x2c\x31\x33\x38\x2e\x36\x36\x37\x76\x32\x33\x34\x2e\x36\x36\
-\x36\x43\x33\x32\x2c\x33\x39\x36\x2e\x38\x30\x32\x2c\x35\x31\x2e\
-\x31\x39\x37\x2c\x34\x31\x36\x2c\x37\x34\x2e\x36\x36\x36\x2c\x34\
-\x31\x36\x68\x33\x36\x32\x2e\x36\x36\x38\x0d\x0a\x09\x43\x34\x36\
-\x30\x2e\x38\x30\x33\x2c\x34\x31\x36\x2c\x34\x38\x30\x2c\x33\x39\
-\x36\x2e\x38\x30\x32\x2c\x34\x38\x30\x2c\x33\x37\x33\x2e\x33\x33\
-\x33\x56\x31\x38\x36\x2e\x36\x36\x37\x43\x34\x38\x30\x2c\x31\x36\
-\x33\x2e\x31\x39\x38\x2c\x34\x36\x30\x2e\x38\x30\x33\x2c\x31\x34\
-\x34\x2c\x34\x33\x37\x2e\x33\x33\x34\x2c\x31\x34\x34\x7a\x20\x4d\
-\x34\x34\x38\x2c\x33\x37\x33\x2e\x33\x33\x33\x0d\x0a\x09\x63\x30\
-\x2c\x35\x2e\x37\x38\x32\x2d\x34\x2e\x38\x38\x35\x2c\x31\x30\x2e\
-\x36\x36\x37\x2d\x31\x30\x2e\x36\x36\x36\x2c\x31\x30\x2e\x36\x36\
-\x37\x48\x37\x34\x2e\x36\x36\x36\x43\x36\x38\x2e\x38\x38\x34\x2c\
-\x33\x38\x34\x2c\x36\x34\x2c\x33\x37\x39\x2e\x31\x31\x35\x2c\x36\
-\x34\x2c\x33\x37\x33\x2e\x33\x33\x33\x56\x31\x37\x36\x68\x33\x37\
-\x33\x2e\x33\x33\x34\x63\x35\x2e\x37\x38\x31\x2c\x30\x2c\x31\x30\
-\x2e\x36\x36\x36\x2c\x34\x2e\x38\x38\x35\x2c\x31\x30\x2e\x36\x36\
-\x36\x2c\x31\x30\x2e\x36\x36\x37\x0d\x0a\x09\x56\x33\x37\x33\x2e\
-\x33\x33\x33\x7a\x22\x2f\x3e\x0d\x0a\x3c\x2f\x73\x76\x67\x3e\x0d\
-\x0a\
-\x00\x00\x00\x6c\
-\x3c\
-\x73\x76\x67\x20\x78\x6d\x6c\x6e\x73\x3d\x22\x68\x74\x74\x70\x3a\
-\x2f\x2f\x77\x77\x77\x2e\x77\x33\x2e\x6f\x72\x67\x2f\x32\x30\x30\
-\x30\x2f\x73\x76\x67\x22\x20\x76\x69\x65\x77\x42\x6f\x78\x3d\x22\
-\x30\x20\x30\x20\x32\x30\x20\x32\x30\x22\x3e\x3c\x70\x61\x74\x68\
-\x20\x64\x3d\x22\x4d\x31\x38\x20\x31\x32\x76\x31\x48\x38\x76\x35\
-\x6c\x2d\x36\x2d\x36\x20\x36\x2d\x36\x76\x35\x68\x38\x56\x32\x68\
-\x32\x7a\x22\x2f\x3e\x3c\x2f\x73\x76\x67\x3e\
-\x00\x00\x02\x79\
-\x3c\
-\x3f\x78\x6d\x6c\x20\x76\x65\x72\x73\x69\x6f\x6e\x3d\x22\x31\x2e\
-\x30\x22\x20\x65\x6e\x63\x6f\x64\x69\x6e\x67\x3d\x22\x75\x74\x66\
-\x2d\x38\x22\x3f\x3e\x0d\x0a\x3c\x21\x2d\x2d\x20\x47\x65\x6e\x65\
-\x72\x61\x74\x6f\x72\x3a\x20\x41\x64\x6f\x62\x65\x20\x49\x6c\x6c\
-\x75\x73\x74\x72\x61\x74\x6f\x72\x20\x31\x36\x2e\x32\x2e\x31\x2c\
-\x20\x53\x56\x47\x20\x45\x78\x70\x6f\x72\x74\x20\x50\x6c\x75\x67\
-\x2d\x49\x6e\x20\x2e\x20\x53\x56\x47\x20\x56\x65\x72\x73\x69\x6f\
-\x6e\x3a\x20\x36\x2e\x30\x30\x20\x42\x75\x69\x6c\x64\x20\x30\x29\
-\x20\x20\x2d\x2d\x3e\x0d\x0a\x3c\x21\x44\x4f\x43\x54\x59\x50\x45\
-\x20\x73\x76\x67\x20\x50\x55\x42\x4c\x49\x43\x20\x22\x2d\x2f\x2f\
-\x57\x33\x43\x2f\x2f\x44\x54\x44\x20\x53\x56\x47\x20\x31\x2e\x31\
-\x2f\x2f\x45\x4e\x22\x20\x22\x68\x74\x74\x70\x3a\x2f\x2f\x77\x77\
-\x77\x2e\x77\x33\x2e\x6f\x72\x67\x2f\x47\x72\x61\x70\x68\x69\x63\
-\x73\x2f\x53\x56\x47\x2f\x31\x2e\x31\x2f\x44\x54\x44\x2f\x73\x76\
-\x67\x31\x31\x2e\x64\x74\x64\x22\x3e\x0d\x0a\x3c\x73\x76\x67\x20\
-\x76\x65\x72\x73\x69\x6f\x6e\x3d\x22\x31\x2e\x31\x22\x20\x69\x64\
-\x3d\x22\x4c\x61\x79\x65\x72\x5f\x31\x22\x20\x78\x6d\x6c\x6e\x73\
-\x3d\x22\x68\x74\x74\x70\x3a\x2f\x2f\x77\x77\x77\x2e\x77\x33\x2e\
-\x6f\x72\x67\x2f\x32\x30\x30\x30\x2f\x73\x76\x67\x22\x20\x78\x6d\
-\x6c\x6e\x73\x3a\x78\x6c\x69\x6e\x6b\x3d\x22\x68\x74\x74\x70\x3a\
-\x2f\x2f\x77\x77\x77\x2e\x77\x33\x2e\x6f\x72\x67\x2f\x31\x39\x39\
-\x39\x2f\x78\x6c\x69\x6e\x6b\x22\x20\x78\x3d\x22\x30\x70\x78\x22\
-\x20\x79\x3d\x22\x30\x70\x78\x22\x0d\x0a\x09\x20\x77\x69\x64\x74\
-\x68\x3d\x22\x35\x31\x32\x70\x78\x22\x20\x68\x65\x69\x67\x68\x74\
-\x3d\x22\x35\x31\x32\x70\x78\x22\x20\x76\x69\x65\x77\x42\x6f\x78\
-\x3d\x22\x30\x20\x30\x20\x35\x31\x32\x20\x35\x31\x32\x22\x20\x65\
-\x6e\x61\x62\x6c\x65\x2d\x62\x61\x63\x6b\x67\x72\x6f\x75\x6e\x64\
-\x3d\x22\x6e\x65\x77\x20\x30\x20\x30\x20\x35\x31\x32\x20\x35\x31\
-\x32\x22\x20\x78\x6d\x6c\x3a\x73\x70\x61\x63\x65\x3d\x22\x70\x72\
-\x65\x73\x65\x72\x76\x65\x22\x3e\x0d\x0a\x3c\x67\x20\x69\x64\x3d\
-\x22\x49\x63\x6f\x6e\x5f\x31\x5f\x22\x3e\x0d\x0a\x09\x3c\x67\x3e\
-\x0d\x0a\x09\x09\x3c\x67\x3e\x0d\x0a\x09\x09\x09\x3c\x70\x6f\x6c\
-\x79\x67\x6f\x6e\x20\x70\x6f\x69\x6e\x74\x73\x3d\x22\x31\x38\x36\
-\x2e\x33\x30\x31\x2c\x33\x33\x39\x2e\x38\x39\x33\x20\x39\x36\x2c\
-\x32\x34\x39\x2e\x34\x36\x31\x20\x36\x34\x2c\x32\x37\x39\x2e\x39\
-\x36\x38\x20\x31\x38\x36\x2e\x33\x30\x31\x2c\x34\x30\x32\x20\x34\
-\x34\x38\x2c\x31\x34\x30\x2e\x35\x30\x36\x20\x34\x31\x36\x2c\x31\
-\x31\x30\x20\x09\x09\x09\x22\x2f\x3e\x0d\x0a\x09\x09\x3c\x2f\x67\
-\x3e\x0d\x0a\x09\x3c\x2f\x67\x3e\x0d\x0a\x3c\x2f\x67\x3e\x0d\x0a\
-\x3c\x2f\x73\x76\x67\x3e\x0d\x0a\
-\x00\x00\x03\x6c\
-\x3c\
-\x3f\x78\x6d\x6c\x20\x76\x65\x72\x73\x69\x6f\x6e\x3d\x22\x31\x2e\
-\x30\x22\x20\x65\x6e\x63\x6f\x64\x69\x6e\x67\x3d\x22\x75\x74\x66\
-\x2d\x38\x22\x3f\x3e\x0d\x0a\x3c\x21\x2d\x2d\x20\x47\x65\x6e\x65\
-\x72\x61\x74\x6f\x72\x3a\x20\x41\x64\x6f\x62\x65\x20\x49\x6c\x6c\
-\x75\x73\x74\x72\x61\x74\x6f\x72\x20\x31\x36\x2e\x32\x2e\x31\x2c\
-\x20\x53\x56\x47\x20\x45\x78\x70\x6f\x72\x74\x20\x50\x6c\x75\x67\
-\x2d\x49\x6e\x20\x2e\x20\x53\x56\x47\x20\x56\x65\x72\x73\x69\x6f\
-\x6e\x3a\x20\x36\x2e\x30\x30\x20\x42\x75\x69\x6c\x64\x20\x30\x29\
-\x20\x20\x2d\x2d\x3e\x0d\x0a\x3c\x21\x44\x4f\x43\x54\x59\x50\x45\
-\x20\x73\x76\x67\x20\x50\x55\x42\x4c\x49\x43\x20\x22\x2d\x2f\x2f\
-\x57\x33\x43\x2f\x2f\x44\x54\x44\x20\x53\x56\x47\x20\x31\x2e\x31\
-\x2f\x2f\x45\x4e\x22\x20\x22\x68\x74\x74\x70\x3a\x2f\x2f\x77\x77\
-\x77\x2e\x77\x33\x2e\x6f\x72\x67\x2f\x47\x72\x61\x70\x68\x69\x63\
-\x73\x2f\x53\x56\x47\x2f\x31\x2e\x31\x2f\x44\x54\x44\x2f\x73\x76\
-\x67\x31\x31\x2e\x64\x74\x64\x22\x3e\x0d\x0a\x3c\x73\x76\x67\x20\
-\x76\x65\x72\x73\x69\x6f\x6e\x3d\x22\x31\x2e\x31\x22\x20\x69\x64\
-\x3d\x22\x4c\x61\x79\x65\x72\x5f\x31\x22\x20\x78\x6d\x6c\x6e\x73\
-\x3d\x22\x68\x74\x74\x70\x3a\x2f\x2f\x77\x77\x77\x2e\x77\x33\x2e\
-\x6f\x72\x67\x2f\x32\x30\x30\x30\x2f\x73\x76\x67\x22\x20\x78\x6d\
-\x6c\x6e\x73\x3a\x78\x6c\x69\x6e\x6b\x3d\x22\x68\x74\x74\x70\x3a\
-\x2f\x2f\x77\x77\x77\x2e\x77\x33\x2e\x6f\x72\x67\x2f\x31\x39\x39\
-\x39\x2f\x78\x6c\x69\x6e\x6b\x22\x20\x78\x3d\x22\x30\x70\x78\x22\
-\x20\x79\x3d\x22\x30\x70\x78\x22\x0d\x0a\x09\x20\x77\x69\x64\x74\
-\x68\x3d\x22\x35\x31\x32\x70\x78\x22\x20\x68\x65\x69\x67\x68\x74\
-\x3d\x22\x35\x31\x32\x70\x78\x22\x20\x76\x69\x65\x77\x42\x6f\x78\
-\x3d\x22\x30\x20\x30\x20\x35\x31\x32\x20\x35\x31\x32\x22\x20\x65\
-\x6e\x61\x62\x6c\x65\x2d\x62\x61\x63\x6b\x67\x72\x6f\x75\x6e\x64\
-\x3d\x22\x6e\x65\x77\x20\x30\x20\x30\x20\x35\x31\x32\x20\x35\x31\
-\x32\x22\x20\x78\x6d\x6c\x3a\x73\x70\x61\x63\x65\x3d\x22\x70\x72\
-\x65\x73\x65\x72\x76\x65\x22\x3e\x0d\x0a\x3c\x67\x3e\x0d\x0a\x09\
-\x0d\x0a\x09\x09\x3c\x72\x65\x63\x74\x20\x78\x3d\x22\x31\x37\x38\
-\x2e\x38\x34\x36\x22\x20\x79\x3d\x22\x39\x32\x2e\x30\x38\x37\x22\
-\x20\x74\x72\x61\x6e\x73\x66\x6f\x72\x6d\x3d\x22\x6d\x61\x74\x72\
-\x69\x78\x28\x2d\x30\x2e\x37\x30\x37\x31\x20\x2d\x30\x2e\x37\x30\
-\x37\x31\x20\x30\x2e\x37\x30\x37\x31\x20\x2d\x30\x2e\x37\x30\x37\
-\x31\x20\x32\x32\x34\x2e\x33\x34\x37\x36\x20\x36\x33\x31\x2e\x31\
-\x34\x39\x38\x29\x22\x20\x77\x69\x64\x74\x68\x3d\x22\x31\x32\x38\
-\x2e\x30\x38\x35\x22\x20\x68\x65\x69\x67\x68\x74\x3d\x22\x33\x35\
-\x34\x2e\x30\x34\x39\x22\x2f\x3e\x0d\x0a\x09\x3c\x70\x61\x74\x68\
-\x20\x64\x3d\x22\x4d\x34\x37\x31\x2e\x37\x32\x33\x2c\x38\x38\x2e\
-\x33\x39\x33\x6c\x2d\x34\x38\x2e\x31\x31\x35\x2d\x34\x38\x2e\x31\
-\x31\x34\x63\x2d\x31\x31\x2e\x37\x32\x33\x2d\x31\x31\x2e\x37\x32\
-\x34\x2d\x33\x31\x2e\x35\x35\x38\x2d\x31\x30\x2e\x38\x39\x36\x2d\
-\x34\x34\x2e\x33\x30\x34\x2c\x31\x2e\x38\x35\x6c\x2d\x34\x35\x2e\
-\x32\x30\x32\x2c\x34\x35\x2e\x32\x30\x33\x6c\x39\x30\x2e\x35\x36\
-\x39\x2c\x39\x30\x2e\x35\x36\x38\x6c\x34\x35\x2e\x32\x30\x32\x2d\
-\x34\x35\x2e\x32\x30\x32\x0d\x0a\x09\x09\x43\x34\x38\x32\x2e\x36\
-\x31\x36\x2c\x31\x31\x39\x2e\x39\x35\x32\x2c\x34\x38\x33\x2e\x34\
-\x34\x35\x2c\x31\x30\x30\x2e\x31\x31\x36\x2c\x34\x37\x31\x2e\x37\
-\x32\x33\x2c\x38\x38\x2e\x33\x39\x33\x7a\x22\x2f\x3e\x0d\x0a\x09\
-\x3c\x70\x6f\x6c\x79\x67\x6f\x6e\x20\x70\x6f\x69\x6e\x74\x73\x3d\
-\x22\x36\x34\x2e\x30\x32\x31\x2c\x33\x36\x33\x2e\x32\x35\x32\x20\
-\x33\x32\x2c\x34\x38\x30\x20\x31\x34\x38\x2e\x37\x33\x37\x2c\x34\
-\x34\x37\x2e\x39\x37\x39\x20\x09\x22\x2f\x3e\x0d\x0a\x3c\x2f\x67\
-\x3e\x0d\x0a\x3c\x2f\x73\x76\x67\x3e\x0d\x0a\
-\x00\x00\x05\x27\
-\x3c\
-\x3f\x78\x6d\x6c\x20\x76\x65\x72\x73\x69\x6f\x6e\x3d\x22\x31\x2e\
-\x30\x22\x20\x65\x6e\x63\x6f\x64\x69\x6e\x67\x3d\x22\x75\x74\x66\
-\x2d\x38\x22\x3f\x3e\x0d\x0a\x3c\x21\x2d\x2d\x20\x47\x65\x6e\x65\
-\x72\x61\x74\x6f\x72\x3a\x20\x41\x64\x6f\x62\x65\x20\x49\x6c\x6c\
-\x75\x73\x74\x72\x61\x74\x6f\x72\x20\x31\x36\x2e\x32\x2e\x31\x2c\
-\x20\x53\x56\x47\x20\x45\x78\x70\x6f\x72\x74\x20\x50\x6c\x75\x67\
-\x2d\x49\x6e\x20\x2e\x20\x53\x56\x47\x20\x56\x65\x72\x73\x69\x6f\
-\x6e\x3a\x20\x36\x2e\x30\x30\x20\x42\x75\x69\x6c\x64\x20\x30\x29\
-\x20\x20\x2d\x2d\x3e\x0d\x0a\x3c\x21\x44\x4f\x43\x54\x59\x50\x45\
-\x20\x73\x76\x67\x20\x50\x55\x42\x4c\x49\x43\x20\x22\x2d\x2f\x2f\
-\x57\x33\x43\x2f\x2f\x44\x54\x44\x20\x53\x56\x47\x20\x31\x2e\x31\
-\x2f\x2f\x45\x4e\x22\x20\x22\x68\x74\x74\x70\x3a\x2f\x2f\x77\x77\
-\x77\x2e\x77\x33\x2e\x6f\x72\x67\x2f\x47\x72\x61\x70\x68\x69\x63\
-\x73\x2f\x53\x56\x47\x2f\x31\x2e\x31\x2f\x44\x54\x44\x2f\x73\x76\
-\x67\x31\x31\x2e\x64\x74\x64\x22\x3e\x0d\x0a\x3c\x73\x76\x67\x20\
-\x76\x65\x72\x73\x69\x6f\x6e\x3d\x22\x31\x2e\x31\x22\x20\x69\x64\
-\x3d\x22\x4c\x61\x79\x65\x72\x5f\x31\x22\x20\x78\x6d\x6c\x6e\x73\
-\x3d\x22\x68\x74\x74\x70\x3a\x2f\x2f\x77\x77\x77\x2e\x77\x33\x2e\
-\x6f\x72\x67\x2f\x32\x30\x30\x30\x2f\x73\x76\x67\x22\x20\x78\x6d\
-\x6c\x6e\x73\x3a\x78\x6c\x69\x6e\x6b\x3d\x22\x68\x74\x74\x70\x3a\
-\x2f\x2f\x77\x77\x77\x2e\x77\x33\x2e\x6f\x72\x67\x2f\x31\x39\x39\
-\x39\x2f\x78\x6c\x69\x6e\x6b\x22\x20\x78\x3d\x22\x30\x70\x78\x22\
-\x20\x79\x3d\x22\x30\x70\x78\x22\x0d\x0a\x09\x20\x77\x69\x64\x74\
-\x68\x3d\x22\x35\x31\x32\x70\x78\x22\x20\x68\x65\x69\x67\x68\x74\
-\x3d\x22\x35\x31\x32\x70\x78\x22\x20\x76\x69\x65\x77\x42\x6f\x78\
-\x3d\x22\x30\x20\x30\x20\x35\x31\x32\x20\x35\x31\x32\x22\x20\x65\
-\x6e\x61\x62\x6c\x65\x2d\x62\x61\x63\x6b\x67\x72\x6f\x75\x6e\x64\
-\x3d\x22\x6e\x65\x77\x20\x30\x20\x30\x20\x35\x31\x32\x20\x35\x31\
-\x32\x22\x20\x78\x6d\x6c\x3a\x73\x70\x61\x63\x65\x3d\x22\x70\x72\
-\x65\x73\x65\x72\x76\x65\x22\x3e\x0d\x0a\x3c\x67\x20\x69\x64\x3d\
-\x22\x49\x63\x6f\x6e\x5f\x31\x32\x5f\x22\x3e\x0d\x0a\x09\x3c\x67\
-\x3e\x0d\x0a\x09\x09\x3c\x70\x61\x74\x68\x20\x64\x3d\x22\x4d\x32\
-\x35\x36\x2c\x36\x34\x43\x31\x35\x30\x2e\x34\x30\x31\x2c\x36\x34\
-\x2c\x36\x34\x2c\x31\x35\x30\x2e\x34\x30\x31\x2c\x36\x34\x2c\x32\
-\x35\x36\x63\x30\x2c\x31\x30\x35\x2e\x36\x30\x34\x2c\x38\x36\x2e\
-\x34\x30\x31\x2c\x31\x39\x32\x2c\x31\x39\x32\x2c\x31\x39\x32\x63\
-\x31\x38\x2e\x31\x33\x36\x2c\x30\x2c\x33\x32\x2d\x31\x33\x2e\x38\
-\x36\x34\x2c\x33\x32\x2d\x33\x32\x0d\x0a\x09\x09\x09\x63\x30\x2d\
-\x38\x2e\x35\x33\x31\x2d\x33\x2e\x31\x39\x38\x2d\x31\x36\x2d\x38\
-\x2e\x35\x33\x31\x2d\x32\x31\x2e\x33\x33\x33\x63\x2d\x35\x2e\x33\
-\x33\x33\x2d\x35\x2e\x33\x33\x34\x2d\x38\x2e\x35\x33\x31\x2d\x31\
-\x32\x2e\x38\x30\x33\x2d\x38\x2e\x35\x33\x31\x2d\x32\x31\x2e\x33\
-\x33\x34\x63\x30\x2d\x31\x38\x2e\x31\x33\x35\x2c\x31\x33\x2e\x38\
-\x36\x34\x2d\x33\x32\x2c\x33\x32\x2d\x33\x32\x68\x33\x38\x2e\x33\
-\x39\x36\x0d\x0a\x09\x09\x09\x63\x35\x38\x2e\x36\x36\x37\x2c\x30\
-\x2c\x31\x30\x36\x2e\x36\x36\x37\x2d\x34\x38\x2c\x31\x30\x36\x2e\
-\x36\x36\x37\x2d\x31\x30\x36\x2e\x36\x36\x36\x43\x34\x34\x38\x2c\
-\x31\x34\x30\x2e\x38\x30\x32\x2c\x33\x36\x31\x2e\x36\x30\x34\x2c\
-\x36\x34\x2c\x32\x35\x36\x2c\x36\x34\x7a\x20\x4d\x31\x33\x38\x2e\
-\x36\x36\x37\x2c\x32\x35\x36\x63\x2d\x31\x38\x2e\x31\x33\x36\x2c\
-\x30\x2d\x33\x32\x2d\x31\x33\x2e\x38\x36\x34\x2d\x33\x32\x2d\x33\
-\x32\x73\x31\x33\x2e\x38\x36\x34\x2d\x33\x32\x2c\x33\x32\x2d\x33\
-\x32\x0d\x0a\x09\x09\x09\x63\x31\x38\x2e\x31\x33\x35\x2c\x30\x2c\
-\x33\x32\x2c\x31\x33\x2e\x38\x36\x34\x2c\x33\x32\x2c\x33\x32\x53\
-\x31\x35\x36\x2e\x38\x30\x32\x2c\x32\x35\x36\x2c\x31\x33\x38\x2e\
-\x36\x36\x37\x2c\x32\x35\x36\x7a\x20\x4d\x32\x30\x32\x2e\x36\x36\
-\x37\x2c\x31\x37\x30\x2e\x36\x36\x37\x63\x2d\x31\x38\x2e\x31\x33\
-\x36\x2c\x30\x2d\x33\x32\x2d\x31\x33\x2e\x38\x36\x35\x2d\x33\x32\
-\x2d\x33\x32\x63\x30\x2d\x31\x38\x2e\x31\x33\x36\x2c\x31\x33\x2e\
-\x38\x36\x34\x2d\x33\x32\x2c\x33\x32\x2d\x33\x32\x0d\x0a\x09\x09\
-\x09\x63\x31\x38\x2e\x31\x33\x35\x2c\x30\x2c\x33\x32\x2c\x31\x33\
-\x2e\x38\x36\x34\x2c\x33\x32\x2c\x33\x32\x43\x32\x33\x34\x2e\x36\
-\x36\x37\x2c\x31\x35\x36\x2e\x38\x30\x32\x2c\x32\x32\x30\x2e\x38\
-\x30\x32\x2c\x31\x37\x30\x2e\x36\x36\x37\x2c\x32\x30\x32\x2e\x36\
-\x36\x37\x2c\x31\x37\x30\x2e\x36\x36\x37\x7a\x20\x4d\x33\x30\x39\
-\x2e\x33\x33\x33\x2c\x31\x37\x30\x2e\x36\x36\x37\x63\x2d\x31\x38\
-\x2e\x31\x33\x35\x2c\x30\x2d\x33\x32\x2d\x31\x33\x2e\x38\x36\x35\
-\x2d\x33\x32\x2d\x33\x32\x0d\x0a\x09\x09\x09\x63\x30\x2d\x31\x38\
-\x2e\x31\x33\x36\x2c\x31\x33\x2e\x38\x36\x35\x2d\x33\x32\x2c\x33\
-\x32\x2d\x33\x32\x63\x31\x38\x2e\x31\x33\x36\x2c\x30\x2c\x33\x32\
-\x2c\x31\x33\x2e\x38\x36\x34\x2c\x33\x32\x2c\x33\x32\x43\x33\x34\
-\x31\x2e\x33\x33\x33\x2c\x31\x35\x36\x2e\x38\x30\x32\x2c\x33\x32\
-\x37\x2e\x34\x36\x39\x2c\x31\x37\x30\x2e\x36\x36\x37\x2c\x33\x30\
-\x39\x2e\x33\x33\x33\x2c\x31\x37\x30\x2e\x36\x36\x37\x7a\x20\x4d\
-\x33\x37\x33\x2e\x33\x33\x33\x2c\x32\x35\x36\x0d\x0a\x09\x09\x09\
-\x63\x2d\x31\x38\x2e\x31\x33\x35\x2c\x30\x2d\x33\x32\x2d\x31\x33\
-\x2e\x38\x36\x34\x2d\x33\x32\x2d\x33\x32\x73\x31\x33\x2e\x38\x36\
-\x35\x2d\x33\x32\x2c\x33\x32\x2d\x33\x32\x63\x31\x38\x2e\x31\x33\
-\x36\x2c\x30\x2c\x33\x32\x2c\x31\x33\x2e\x38\x36\x34\x2c\x33\x32\
-\x2c\x33\x32\x53\x33\x39\x31\x2e\x34\x36\x39\x2c\x32\x35\x36\x2c\
-\x33\x37\x33\x2e\x33\x33\x33\x2c\x32\x35\x36\x7a\x22\x2f\x3e\x0d\
-\x0a\x09\x3c\x2f\x67\x3e\x0d\x0a\x3c\x2f\x67\x3e\x0d\x0a\x3c\x2f\
-\x73\x76\x67\x3e\x0d\x0a\
-\x00\x00\x07\x80\
-\x3c\
-\x3f\x78\x6d\x6c\x20\x76\x65\x72\x73\x69\x6f\x6e\x3d\x22\x31\x2e\
-\x30\x22\x20\x65\x6e\x63\x6f\x64\x69\x6e\x67\x3d\x22\x75\x74\x66\
-\x2d\x38\x22\x3f\x3e\x0d\x0a\x3c\x21\x2d\x2d\x20\x47\x65\x6e\x65\
-\x72\x61\x74\x6f\x72\x3a\x20\x41\x64\x6f\x62\x65\x20\x49\x6c\x6c\
-\x75\x73\x74\x72\x61\x74\x6f\x72\x20\x31\x36\x2e\x32\x2e\x31\x2c\
-\x20\x53\x56\x47\x20\x45\x78\x70\x6f\x72\x74\x20\x50\x6c\x75\x67\
-\x2d\x49\x6e\x20\x2e\x20\x53\x56\x47\x20\x56\x65\x72\x73\x69\x6f\
-\x6e\x3a\x20\x36\x2e\x30\x30\x20\x42\x75\x69\x6c\x64\x20\x30\x29\
-\x20\x20\x2d\x2d\x3e\x0d\x0a\x3c\x21\x44\x4f\x43\x54\x59\x50\x45\
-\x20\x73\x76\x67\x20\x50\x55\x42\x4c\x49\x43\x20\x22\x2d\x2f\x2f\
-\x57\x33\x43\x2f\x2f\x44\x54\x44\x20\x53\x56\x47\x20\x31\x2e\x31\
-\x2f\x2f\x45\x4e\x22\x20\x22\x68\x74\x74\x70\x3a\x2f\x2f\x77\x77\
-\x77\x2e\x77\x33\x2e\x6f\x72\x67\x2f\x47\x72\x61\x70\x68\x69\x63\
-\x73\x2f\x53\x56\x47\x2f\x31\x2e\x31\x2f\x44\x54\x44\x2f\x73\x76\
-\x67\x31\x31\x2e\x64\x74\x64\x22\x3e\x0d\x0a\x3c\x73\x76\x67\x20\
-\x76\x65\x72\x73\x69\x6f\x6e\x3d\x22\x31\x2e\x31\x22\x20\x69\x64\
-\x3d\x22\x4c\x61\x79\x65\x72\x5f\x31\x22\x20\x78\x6d\x6c\x6e\x73\
-\x3d\x22\x68\x74\x74\x70\x3a\x2f\x2f\x77\x77\x77\x2e\x77\x33\x2e\
-\x6f\x72\x67\x2f\x32\x30\x30\x30\x2f\x73\x76\x67\x22\x20\x78\x6d\
-\x6c\x6e\x73\x3a\x78\x6c\x69\x6e\x6b\x3d\x22\x68\x74\x74\x70\x3a\
-\x2f\x2f\x77\x77\x77\x2e\x77\x33\x2e\x6f\x72\x67\x2f\x31\x39\x39\
-\x39\x2f\x78\x6c\x69\x6e\x6b\x22\x20\x78\x3d\x22\x30\x70\x78\x22\
-\x20\x79\x3d\x22\x30\x70\x78\x22\x0d\x0a\x09\x20\x77\x69\x64\x74\
-\x68\x3d\x22\x35\x31\x32\x70\x78\x22\x20\x68\x65\x69\x67\x68\x74\
-\x3d\x22\x35\x31\x32\x70\x78\x22\x20\x76\x69\x65\x77\x42\x6f\x78\
-\x3d\x22\x30\x20\x30\x20\x35\x31\x32\x20\x35\x31\x32\x22\x20\x65\
-\x6e\x61\x62\x6c\x65\x2d\x62\x61\x63\x6b\x67\x72\x6f\x75\x6e\x64\
-\x3d\x22\x6e\x65\x77\x20\x30\x20\x30\x20\x35\x31\x32\x20\x35\x31\
-\x32\x22\x20\x78\x6d\x6c\x3a\x73\x70\x61\x63\x65\x3d\x22\x70\x72\
-\x65\x73\x65\x72\x76\x65\x22\x3e\x0d\x0a\x3c\x67\x3e\x0d\x0a\x09\
-\x3c\x70\x61\x74\x68\x20\x64\x3d\x22\x4d\x31\x39\x33\x2e\x34\x36\
-\x2c\x32\x34\x39\x2e\x30\x35\x36\x63\x33\x2e\x37\x32\x33\x2d\x30\
-\x2e\x36\x37\x2c\x37\x2e\x35\x38\x39\x2d\x31\x2e\x30\x34\x31\x2c\
-\x31\x31\x2e\x35\x38\x36\x2d\x31\x2e\x30\x34\x31\x4c\x32\x30\x31\
-\x2e\x39\x32\x34\x2c\x32\x34\x38\x68\x31\x30\x33\x2e\x38\x32\x33\
-\x63\x34\x2e\x35\x30\x33\x2c\x30\x2c\x38\x2e\x38\x30\x36\x2d\x30\
-\x2e\x36\x31\x37\x2c\x31\x32\x2e\x39\x30\x38\x2d\x31\x2e\x37\x35\
-\x34\x0d\x0a\x09\x09\x63\x31\x39\x2e\x33\x37\x2d\x35\x2e\x33\x36\
-\x33\x2c\x33\x33\x2e\x33\x34\x35\x2d\x32\x32\x2e\x35\x33\x37\x2c\
-\x33\x33\x2e\x33\x34\x35\x2d\x34\x33\x2e\x36\x36\x33\x76\x2d\x33\
-\x30\x2e\x38\x32\x32\x76\x2d\x35\x36\x2e\x34\x30\x32\x63\x30\x2d\
-\x32\x34\x2e\x38\x33\x32\x2d\x32\x31\x2e\x31\x35\x2d\x34\x33\x2e\
-\x34\x38\x34\x2d\x34\x36\x2e\x32\x38\x39\x2d\x34\x37\x2e\x36\x30\
-\x36\x0d\x0a\x09\x09\x63\x2d\x31\x35\x2e\x39\x33\x31\x2d\x32\x2e\
-\x36\x32\x34\x2d\x33\x39\x2e\x32\x35\x38\x2d\x33\x2e\x38\x32\x37\
-\x2d\x35\x35\x2e\x30\x38\x39\x2d\x33\x2e\x37\x34\x39\x63\x2d\x31\
-\x35\x2e\x38\x32\x39\x2c\x30\x2e\x30\x38\x36\x2d\x33\x30\x2e\x39\
-\x38\x31\x2c\x31\x2e\x34\x30\x34\x2d\x34\x34\x2e\x32\x37\x37\x2c\
-\x33\x2e\x37\x34\x39\x43\x31\x36\x37\x2e\x31\x34\x33\x2c\x37\x34\
-\x2e\x35\x37\x36\x2c\x31\x36\x30\x2c\x38\x38\x2e\x39\x32\x38\x2c\
-\x31\x36\x30\x2c\x31\x31\x35\x2e\x33\x35\x39\x56\x31\x34\x34\x68\
-\x39\x36\x0d\x0a\x09\x09\x76\x31\x36\x48\x31\x32\x38\x2e\x38\x32\
-\x63\x2d\x33\x35\x2e\x36\x32\x38\x2c\x30\x2d\x36\x34\x2e\x35\x33\
-\x38\x2c\x34\x32\x2e\x35\x37\x31\x2d\x36\x34\x2e\x38\x31\x33\x2c\
-\x39\x35\x2e\x32\x34\x32\x43\x36\x34\x2e\x30\x30\x35\x2c\x32\x35\
-\x35\x2e\x34\x39\x35\x2c\x36\x34\x2c\x32\x35\x35\x2e\x37\x34\x37\
-\x2c\x36\x34\x2c\x32\x35\x36\x63\x30\x2c\x39\x2e\x35\x32\x33\x2c\
-\x30\x2e\x39\x34\x2c\x31\x38\x2e\x37\x32\x2c\x32\x2e\x36\x38\x35\
-\x2c\x32\x37\x2e\x34\x30\x34\x0d\x0a\x09\x09\x43\x37\x34\x2e\x36\
-\x34\x38\x2c\x33\x32\x33\x2e\x30\x37\x2c\x39\x39\x2e\x34\x35\x31\
-\x2c\x33\x35\x32\x2c\x31\x32\x38\x2e\x38\x32\x2c\x33\x35\x32\x48\
-\x31\x34\x34\x76\x2d\x32\x2e\x36\x36\x32\x76\x2d\x34\x33\x2e\x32\
-\x37\x33\x43\x31\x34\x34\x2c\x32\x37\x39\x2e\x32\x33\x38\x2c\x31\
-\x36\x34\x2e\x31\x34\x36\x2c\x32\x35\x34\x2e\x33\x33\x32\x2c\x31\
-\x39\x33\x2e\x34\x36\x2c\x32\x34\x39\x2e\x30\x35\x36\x7a\x20\x4d\
-\x32\x30\x33\x2e\x36\x35\x36\x2c\x31\x32\x37\x2e\x30\x30\x32\x0d\
-\x0a\x09\x09\x63\x2d\x39\x2e\x35\x39\x32\x2c\x30\x2d\x31\x37\x2e\
-\x33\x38\x34\x2d\x37\x2e\x37\x38\x35\x2d\x31\x37\x2e\x33\x38\x34\
-\x2d\x31\x37\x2e\x34\x30\x33\x63\x30\x2d\x39\x2e\x36\x36\x34\x2c\
-\x37\x2e\x37\x37\x34\x2d\x31\x37\x2e\x35\x32\x2c\x31\x37\x2e\x33\
-\x38\x34\x2d\x31\x37\x2e\x35\x32\x63\x39\x2e\x35\x37\x34\x2c\x30\
-\x2c\x31\x37\x2e\x33\x39\x39\x2c\x37\x2e\x38\x35\x35\x2c\x31\x37\
-\x2e\x33\x39\x39\x2c\x31\x37\x2e\x35\x32\x0d\x0a\x09\x09\x43\x32\
-\x32\x31\x2e\x30\x35\x36\x2c\x31\x31\x39\x2e\x32\x31\x37\x2c\x32\
-\x31\x33\x2e\x32\x34\x36\x2c\x31\x32\x37\x2e\x30\x30\x32\x2c\x32\
-\x30\x33\x2e\x36\x35\x36\x2c\x31\x32\x37\x2e\x30\x30\x32\x7a\x22\
-\x2f\x3e\x0d\x0a\x09\x3c\x70\x61\x74\x68\x20\x64\x3d\x22\x4d\x34\
-\x34\x33\x2e\x39\x35\x31\x2c\x32\x32\x32\x2e\x35\x34\x33\x43\x34\
-\x33\x34\x2e\x37\x38\x2c\x31\x38\x36\x2e\x30\x32\x31\x2c\x34\x31\
-\x31\x2e\x30\x33\x33\x2c\x31\x36\x30\x2c\x33\x38\x33\x2e\x31\x38\
-\x2c\x31\x36\x30\x48\x33\x36\x38\x76\x32\x2e\x36\x32\x36\x76\x33\
-\x38\x2e\x30\x34\x36\x63\x30\x2c\x33\x33\x2e\x39\x31\x35\x2d\x32\
-\x32\x2e\x32\x38\x36\x2c\x35\x38\x2e\x34\x37\x34\x2d\x34\x39\x2e\
-\x34\x38\x39\x2c\x36\x32\x2e\x36\x38\x31\x0d\x0a\x09\x09\x63\x2d\
-\x32\x2e\x37\x33\x37\x2c\x30\x2e\x34\x32\x34\x2d\x35\x2e\x34\x38\
-\x33\x2c\x30\x2e\x36\x34\x36\x2d\x38\x2e\x33\x30\x31\x2c\x30\x2e\
-\x36\x34\x36\x48\x32\x30\x36\x2e\x33\x35\x31\x63\x2d\x34\x2e\x35\
-\x31\x38\x2c\x30\x2d\x38\x2e\x39\x30\x34\x2c\x30\x2e\x35\x38\x34\
-\x2d\x31\x33\x2e\x30\x34\x39\x2c\x31\x2e\x36\x37\x32\x43\x31\x37\
-\x34\x2e\x31\x38\x2c\x32\x37\x30\x2e\x36\x38\x39\x2c\x31\x36\x30\
-\x2c\x32\x38\x36\x2e\x36\x2c\x31\x36\x30\x2c\x33\x30\x37\x2e\x32\
-\x33\x36\x76\x33\x32\x2e\x39\x32\x32\x0d\x0a\x09\x09\x76\x35\x34\
-\x2e\x33\x30\x35\x63\x30\x2c\x32\x34\x2e\x38\x33\x32\x2c\x32\x34\
-\x2e\x39\x37\x37\x2c\x33\x39\x2e\x34\x32\x36\x2c\x34\x39\x2e\x34\
-\x38\x31\x2c\x34\x36\x2e\x35\x35\x31\x63\x32\x39\x2e\x33\x32\x37\
-\x2c\x38\x2e\x35\x33\x31\x2c\x36\x31\x2e\x32\x36\x37\x2c\x31\x30\
-\x2e\x30\x36\x38\x2c\x39\x36\x2e\x33\x36\x36\x2c\x30\x43\x33\x32\
-\x39\x2e\x31\x35\x2c\x34\x33\x34\x2e\x33\x35\x34\x2c\x33\x35\x32\
-\x2c\x34\x32\x30\x2e\x38\x39\x33\x2c\x33\x35\x32\x2c\x33\x39\x34\
-\x2e\x34\x36\x33\x56\x33\x36\x38\x0d\x0a\x09\x09\x68\x2d\x39\x36\
-\x76\x2d\x31\x36\x68\x31\x32\x37\x2e\x31\x38\x63\x32\x35\x2e\x32\
-\x34\x2c\x30\x2c\x34\x37\x2e\x31\x30\x37\x2d\x32\x31\x2e\x33\x36\
-\x35\x2c\x35\x37\x2e\x38\x31\x34\x2d\x35\x32\x2e\x35\x34\x39\x43\
-\x34\x34\x35\x2e\x34\x37\x34\x2c\x32\x38\x36\x2e\x34\x30\x34\x2c\
-\x34\x34\x38\x2c\x32\x37\x31\x2e\x36\x34\x31\x2c\x34\x34\x38\x2c\
-\x32\x35\x36\x0d\x0a\x09\x09\x43\x34\x34\x38\x2c\x32\x34\x34\x2e\
-\x32\x33\x32\x2c\x34\x34\x36\x2e\x35\x36\x37\x2c\x32\x33\x32\x2e\
-\x39\x36\x32\x2c\x34\x34\x33\x2e\x39\x35\x31\x2c\x32\x32\x32\x2e\
-\x35\x34\x33\x7a\x20\x4d\x33\x30\x37\x2e\x38\x36\x37\x2c\x33\x38\
-\x32\x2e\x38\x32\x63\x39\x2e\x35\x39\x2c\x30\x2c\x31\x37\x2e\x33\
-\x38\x31\x2c\x37\x2e\x37\x38\x35\x2c\x31\x37\x2e\x33\x38\x31\x2c\
-\x31\x37\x2e\x34\x0d\x0a\x09\x09\x63\x30\x2c\x39\x2e\x36\x35\x2d\
-\x37\x2e\x37\x39\x31\x2c\x31\x37\x2e\x35\x32\x31\x2d\x31\x37\x2e\
-\x33\x38\x31\x2c\x31\x37\x2e\x35\x32\x31\x63\x2d\x39\x2e\x35\x37\
-\x37\x2c\x30\x2d\x31\x37\x2e\x33\x39\x39\x2d\x37\x2e\x38\x37\x31\
-\x2d\x31\x37\x2e\x33\x39\x39\x2d\x31\x37\x2e\x35\x32\x31\x43\x32\
-\x39\x30\x2e\x34\x36\x38\x2c\x33\x39\x30\x2e\x35\x39\x2c\x32\x39\
-\x38\x2e\x32\x37\x34\x2c\x33\x38\x32\x2e\x38\x32\x2c\x33\x30\x37\
-\x2e\x38\x36\x37\x2c\x33\x38\x32\x2e\x38\x32\x7a\x22\x2f\x3e\x0d\
-\x0a\x3c\x2f\x67\x3e\x0d\x0a\x3c\x2f\x73\x76\x67\x3e\x0d\x0a\
-\x00\x00\x03\xeb\
-\x3c\
-\x3f\x78\x6d\x6c\x20\x76\x65\x72\x73\x69\x6f\x6e\x3d\x22\x31\x2e\
-\x30\x22\x20\x65\x6e\x63\x6f\x64\x69\x6e\x67\x3d\x22\x75\x74\x66\
-\x2d\x38\x22\x3f\x3e\x0d\x0a\x3c\x21\x2d\x2d\x20\x47\x65\x6e\x65\
-\x72\x61\x74\x6f\x72\x3a\x20\x41\x64\x6f\x62\x65\x20\x49\x6c\x6c\
-\x75\x73\x74\x72\x61\x74\x6f\x72\x20\x31\x36\x2e\x32\x2e\x31\x2c\
-\x20\x53\x56\x47\x20\x45\x78\x70\x6f\x72\x74\x20\x50\x6c\x75\x67\
-\x2d\x49\x6e\x20\x2e\x20\x53\x56\x47\x20\x56\x65\x72\x73\x69\x6f\
-\x6e\x3a\x20\x36\x2e\x30\x30\x20\x42\x75\x69\x6c\x64\x20\x30\x29\
-\x20\x20\x2d\x2d\x3e\x0d\x0a\x3c\x21\x44\x4f\x43\x54\x59\x50\x45\
-\x20\x73\x76\x67\x20\x50\x55\x42\x4c\x49\x43\x20\x22\x2d\x2f\x2f\
-\x57\x33\x43\x2f\x2f\x44\x54\x44\x20\x53\x56\x47\x20\x31\x2e\x31\
-\x2f\x2f\x45\x4e\x22\x20\x22\x68\x74\x74\x70\x3a\x2f\x2f\x77\x77\
-\x77\x2e\x77\x33\x2e\x6f\x72\x67\x2f\x47\x72\x61\x70\x68\x69\x63\
-\x73\x2f\x53\x56\x47\x2f\x31\x2e\x31\x2f\x44\x54\x44\x2f\x73\x76\
-\x67\x31\x31\x2e\x64\x74\x64\x22\x3e\x0d\x0a\x3c\x73\x76\x67\x20\
-\x76\x65\x72\x73\x69\x6f\x6e\x3d\x22\x31\x2e\x31\x22\x20\x69\x64\
-\x3d\x22\x4c\x61\x79\x65\x72\x5f\x31\x22\x20\x78\x6d\x6c\x6e\x73\
-\x3d\x22\x68\x74\x74\x70\x3a\x2f\x2f\x77\x77\x77\x2e\x77\x33\x2e\
-\x6f\x72\x67\x2f\x32\x30\x30\x30\x2f\x73\x76\x67\x22\x20\x78\x6d\
-\x6c\x6e\x73\x3a\x78\x6c\x69\x6e\x6b\x3d\x22\x68\x74\x74\x70\x3a\
-\x2f\x2f\x77\x77\x77\x2e\x77\x33\x2e\x6f\x72\x67\x2f\x31\x39\x39\
-\x39\x2f\x78\x6c\x69\x6e\x6b\x22\x20\x78\x3d\x22\x30\x70\x78\x22\
-\x20\x79\x3d\x22\x30\x70\x78\x22\x0d\x0a\x09\x20\x77\x69\x64\x74\
-\x68\x3d\x22\x35\x31\x32\x70\x78\x22\x20\x68\x65\x69\x67\x68\x74\
-\x3d\x22\x35\x31\x32\x70\x78\x22\x20\x76\x69\x65\x77\x42\x6f\x78\
-\x3d\x22\x30\x20\x30\x20\x35\x31\x32\x20\x35\x31\x32\x22\x20\x73\
-\x74\x79\x6c\x65\x3d\x22\x65\x6e\x61\x62\x6c\x65\x2d\x62\x61\x63\
-\x6b\x67\x72\x6f\x75\x6e\x64\x3a\x6e\x65\x77\x20\x30\x20\x30\x20\
-\x35\x31\x32\x20\x35\x31\x32\x3b\x22\x20\x78\x6d\x6c\x3a\x73\x70\
-\x61\x63\x65\x3d\x22\x70\x72\x65\x73\x65\x72\x76\x65\x22\x3e\x0d\
-\x0a\x3c\x67\x3e\x0d\x0a\x09\x3c\x70\x61\x74\x68\x20\x64\x3d\x22\
-\x4d\x32\x35\x36\x2c\x31\x32\x38\x63\x2d\x38\x31\x2e\x39\x2c\x30\
-\x2d\x31\x34\x35\x2e\x37\x2c\x34\x38\x2e\x38\x2d\x32\x32\x34\x2c\
-\x31\x32\x38\x63\x36\x37\x2e\x34\x2c\x36\x37\x2e\x37\x2c\x31\x32\
-\x34\x2c\x31\x32\x38\x2c\x32\x32\x34\x2c\x31\x32\x38\x63\x39\x39\
-\x2e\x39\x2c\x30\x2c\x31\x37\x33\x2e\x34\x2d\x37\x36\x2e\x34\x2c\
-\x32\x32\x34\x2d\x31\x32\x36\x2e\x36\x0d\x0a\x09\x09\x43\x34\x32\
-\x38\x2e\x32\x2c\x31\x39\x38\x2e\x36\x2c\x33\x35\x34\x2e\x38\x2c\
-\x31\x32\x38\x2c\x32\x35\x36\x2c\x31\x32\x38\x7a\x20\x4d\x32\x35\
-\x36\x2c\x33\x34\x37\x2e\x33\x63\x2d\x34\x39\x2e\x34\x2c\x30\x2d\
-\x38\x39\x2e\x36\x2d\x34\x31\x2d\x38\x39\x2e\x36\x2d\x39\x31\x2e\
-\x33\x63\x30\x2d\x35\x30\x2e\x34\x2c\x34\x30\x2e\x32\x2d\x39\x31\
-\x2e\x33\x2c\x38\x39\x2e\x36\x2d\x39\x31\x2e\x33\x73\x38\x39\x2e\
-\x36\x2c\x34\x31\x2c\x38\x39\x2e\x36\x2c\x39\x31\x2e\x33\x0d\x0a\
-\x09\x09\x43\x33\x34\x35\x2e\x36\x2c\x33\x30\x36\x2e\x34\x2c\x33\
-\x30\x35\x2e\x34\x2c\x33\x34\x37\x2e\x33\x2c\x32\x35\x36\x2c\x33\
-\x34\x37\x2e\x33\x7a\x22\x2f\x3e\x0d\x0a\x09\x3c\x67\x3e\x0d\x0a\
-\x09\x09\x3c\x70\x61\x74\x68\x20\x64\x3d\x22\x4d\x32\x35\x36\x2c\
-\x32\x32\x34\x63\x30\x2d\x37\x2e\x39\x2c\x32\x2e\x39\x2d\x31\x35\
-\x2e\x31\x2c\x37\x2e\x36\x2d\x32\x30\x2e\x37\x63\x2d\x32\x2e\x35\
-\x2d\x30\x2e\x34\x2d\x35\x2d\x30\x2e\x36\x2d\x37\x2e\x36\x2d\x30\
-\x2e\x36\x63\x2d\x32\x38\x2e\x38\x2c\x30\x2d\x35\x32\x2e\x33\x2c\
-\x32\x33\x2e\x39\x2d\x35\x32\x2e\x33\x2c\x35\x33\x2e\x33\x63\x30\
-\x2c\x32\x39\x2e\x34\x2c\x32\x33\x2e\x35\x2c\x35\x33\x2e\x33\x2c\
-\x35\x32\x2e\x33\x2c\x35\x33\x2e\x33\x0d\x0a\x09\x09\x09\x73\x35\
-\x32\x2e\x33\x2d\x32\x33\x2e\x39\x2c\x35\x32\x2e\x33\x2d\x35\x33\
-\x2e\x33\x63\x30\x2d\x32\x2e\x33\x2d\x30\x2e\x32\x2d\x34\x2e\x36\
-\x2d\x30\x2e\x34\x2d\x36\x2e\x39\x63\x2d\x35\x2e\x35\x2c\x34\x2e\
-\x33\x2d\x31\x32\x2e\x33\x2c\x36\x2e\x39\x2d\x31\x39\x2e\x38\x2c\
-\x36\x2e\x39\x43\x32\x37\x30\x2e\x33\x2c\x32\x35\x36\x2c\x32\x35\
-\x36\x2c\x32\x34\x31\x2e\x37\x2c\x32\x35\x36\x2c\x32\x32\x34\x7a\
-\x22\x2f\x3e\x0d\x0a\x09\x3c\x2f\x67\x3e\x0d\x0a\x3c\x2f\x67\x3e\
-\x0d\x0a\x3c\x2f\x73\x76\x67\x3e\x0d\x0a\
-"
-
-qt_resource_name = b"\
-\x00\x05\
-\x00\x6f\xa6\x53\
-\x00\x69\
-\x00\x63\x00\x6f\x00\x6e\x00\x73\
-\x00\x0d\
-\x05\x20\xce\x87\
-\x00\x6f\
-\x00\x70\x00\x65\x00\x6e\x00\x63\x00\x75\x00\x72\x00\x76\x00\x65\x00\x2e\x00\x73\x00\x76\x00\x67\
-\x00\x09\
-\x0b\x9e\x89\x07\
-\x00\x63\
-\x00\x68\x00\x65\x00\x63\x00\x6b\x00\x2e\x00\x73\x00\x76\x00\x67\
-\x00\x14\
-\x0f\xa5\xe0\xc7\
-\x00\x6d\
-\x00\x61\x00\x67\x00\x6e\x00\x69\x00\x66\x00\x79\x00\x69\x00\x6e\x00\x67\x00\x2d\x00\x67\x00\x6c\x00\x61\x00\x73\x00\x73\x00\x2e\
-\x00\x73\x00\x76\x00\x67\
-\x00\x0a\
-\x0f\x68\x53\xe7\
-\x00\x61\
-\x00\x6e\x00\x63\x00\x68\x00\x6f\x00\x72\x00\x2e\x00\x73\x00\x76\x00\x67\
-\x00\x0a\
-\x0a\xc8\x62\x67\
-\x00\x63\
-\x00\x65\x00\x6e\x00\x74\x00\x65\x00\x72\x00\x2e\x00\x73\x00\x76\x00\x67\
-\x00\x10\
-\x04\xa9\x22\xc7\
-\x00\x66\
-\x00\x69\x00\x6c\x00\x6c\x00\x65\x00\x64\x00\x62\x00\x75\x00\x63\x00\x6b\x00\x65\x00\x74\x00\x2e\x00\x73\x00\x76\x00\x67\
-\x00\x10\
-\x08\x89\xfa\x47\
-\x00\x63\
-\x00\x65\x00\x6e\x00\x74\x00\x65\x00\x72\x00\x6f\x00\x72\x00\x69\x00\x67\x00\x69\x00\x6e\x00\x2e\x00\x73\x00\x76\x00\x67\
-\x00\x08\
-\x08\xc8\x55\xe7\
-\x00\x73\
-\x00\x61\x00\x76\x00\x65\x00\x2e\x00\x73\x00\x76\x00\x67\
-\x00\x0e\
-\x0f\xcb\xd5\xc7\
-\x00\x70\
-\x00\x6c\x00\x75\x00\x73\x00\x2d\x00\x72\x00\x6f\x00\x75\x00\x6e\x00\x64\x00\x2e\x00\x73\x00\x76\x00\x67\
-\x00\x12\
-\x08\x79\x97\xe7\
-\x00\x61\
-\x00\x6e\x00\x64\x00\x72\x00\x6f\x00\x69\x00\x64\x00\x2d\x00\x63\x00\x61\x00\x6d\x00\x65\x00\x72\x00\x61\x00\x2e\x00\x73\x00\x76\
-\x00\x67\
-\x00\x1c\
-\x08\x8a\x79\x07\
-\x00\x61\
-\x00\x6e\x00\x64\x00\x72\x00\x6f\x00\x69\x00\x64\x00\x2d\x00\x72\x00\x61\x00\x64\x00\x69\x00\x6f\x00\x2d\x00\x62\x00\x75\x00\x74\
-\x00\x74\x00\x6f\x00\x6e\x00\x2d\x00\x6f\x00\x66\x00\x66\x00\x2e\x00\x73\x00\x76\x00\x67\
-\x00\x1c\
-\x04\x66\xe1\x67\
-\x00\x63\
-\x00\x68\x00\x65\x00\x76\x00\x72\x00\x6f\x00\x6e\x00\x2d\x00\x77\x00\x69\x00\x74\x00\x68\x00\x2d\x00\x63\x00\x69\x00\x72\x00\x63\
-\x00\x6c\x00\x65\x00\x2d\x00\x6c\x00\x65\x00\x66\x00\x74\x00\x2e\x00\x73\x00\x76\x00\x67\
-\x00\x11\
-\x0c\xdb\x38\xe7\
-\x00\x61\
-\x00\x6e\x00\x64\x00\x72\x00\x6f\x00\x69\x00\x64\x00\x2d\x00\x63\x00\x6c\x00\x6f\x00\x73\x00\x65\x00\x2e\x00\x73\x00\x76\x00\x67\
-\
-\x00\x17\
-\x06\xc6\x02\xa7\
-\x00\x74\
-\x00\x72\x00\x69\x00\x61\x00\x6e\x00\x67\x00\x6c\x00\x65\x00\x2d\x00\x73\x00\x74\x00\x72\x00\x6f\x00\x6b\x00\x65\x00\x64\x00\x2d\
-\x00\x31\x00\x35\x00\x2e\x00\x73\x00\x76\x00\x67\
-\x00\x08\
-\x08\xf7\x57\x07\
-\x00\x67\
-\x00\x72\x00\x69\x00\x64\x00\x2e\x00\x73\x00\x76\x00\x67\
-\x00\x0f\
-\x09\x76\x60\xc7\
-\x00\x63\
-\x00\x6c\x00\x6f\x00\x73\x00\x65\x00\x2d\x00\x72\x00\x6f\x00\x75\x00\x6e\x00\x64\x00\x2e\x00\x73\x00\x76\x00\x67\
-\x00\x13\
-\x03\x24\x75\x47\
-\x00\x61\
-\x00\x6e\x00\x64\x00\x72\x00\x6f\x00\x69\x00\x64\x00\x2d\x00\x72\x00\x65\x00\x66\x00\x72\x00\x65\x00\x73\x00\x68\x00\x2e\x00\x73\
-\x00\x76\x00\x67\
-\x00\x0a\
-\x01\xca\x6d\x87\
-\x00\x62\
-\x00\x75\x00\x63\x00\x6b\x00\x65\x00\x74\x00\x2e\x00\x73\x00\x76\x00\x67\
-\x00\x1d\
-\x06\xec\xf4\xc7\
-\x00\x63\
-\x00\x68\x00\x65\x00\x76\x00\x72\x00\x6f\x00\x6e\x00\x2d\x00\x77\x00\x69\x00\x74\x00\x68\x00\x2d\x00\x63\x00\x69\x00\x72\x00\x63\
-\x00\x6c\x00\x65\x00\x2d\x00\x72\x00\x69\x00\x67\x00\x68\x00\x74\x00\x2e\x00\x73\x00\x76\x00\x67\
-\x00\x08\
-\x0c\xf7\x55\x87\
-\x00\x74\
-\x00\x65\x00\x78\x00\x74\x00\x2e\x00\x73\x00\x76\x00\x67\
-\x00\x12\
-\x0c\x5e\xd4\xa7\
-\x00\x61\
-\x00\x6e\x00\x64\x00\x72\x00\x6f\x00\x69\x00\x64\x00\x2d\x00\x6c\x00\x6f\x00\x63\x00\x61\x00\x74\x00\x65\x00\x2e\x00\x73\x00\x76\
-\x00\x67\
-\x00\x12\
-\x04\xb2\x21\x47\
-\x00\x61\
-\x00\x6e\x00\x64\x00\x72\x00\x6f\x00\x69\x00\x64\x00\x2d\x00\x65\x00\x78\x00\x70\x00\x61\x00\x6e\x00\x64\x00\x2e\x00\x73\x00\x76\
-\x00\x67\
-\x00\x08\
-\x05\xa8\x57\x87\
-\x00\x63\
-\x00\x6f\x00\x64\x00\x65\x00\x2e\x00\x73\x00\x76\x00\x67\
-\x00\x19\
-\x0a\x43\x45\xc7\
-\x00\x61\
-\x00\x6e\x00\x64\x00\x72\x00\x6f\x00\x69\x00\x64\x00\x2d\x00\x61\x00\x72\x00\x72\x00\x6f\x00\x77\x00\x2d\x00\x66\x00\x6f\x00\x72\
-\x00\x77\x00\x61\x00\x72\x00\x64\x00\x2e\x00\x73\x00\x76\x00\x67\
-\x00\x11\
-\x0c\xa7\xc7\x47\
-\x00\x63\
-\x00\x6c\x00\x6f\x00\x73\x00\x65\x00\x64\x00\x70\x00\x6f\x00\x6c\x00\x79\x00\x67\x00\x6f\x00\x6e\x00\x2e\x00\x73\x00\x76\x00\x67\
-\
-\x00\x0f\
-\x04\xf2\xa7\x87\
-\x00\x63\
-\x00\x6c\x00\x6f\x00\x73\x00\x65\x00\x64\x00\x63\x00\x75\x00\x72\x00\x76\x00\x65\x00\x2e\x00\x73\x00\x76\x00\x67\
-\x00\x0a\
-\x0a\x2d\x1b\xc7\
-\x00\x63\
-\x00\x69\x00\x72\x00\x63\x00\x6c\x00\x65\x00\x2e\x00\x73\x00\x76\x00\x67\
-\x00\x1b\
-\x0e\xb5\x68\xe7\
-\x00\x61\
-\x00\x6e\x00\x64\x00\x72\x00\x6f\x00\x69\x00\x64\x00\x2d\x00\x72\x00\x61\x00\x64\x00\x69\x00\x6f\x00\x2d\x00\x62\x00\x75\x00\x74\
-\x00\x74\x00\x6f\x00\x6e\x00\x2d\x00\x6f\x00\x6e\x00\x2e\x00\x73\x00\x76\x00\x67\
-\x00\x10\
-\x0c\x57\x65\x47\
-\x00\x61\
-\x00\x72\x00\x72\x00\x6f\x00\x77\x00\x2d\x00\x72\x00\x65\x00\x73\x00\x69\x00\x7a\x00\x65\x00\x2e\x00\x73\x00\x76\x00\x67\
-\x00\x12\
-\x08\x55\xef\xc7\
-\x00\x61\
-\x00\x6e\x00\x64\x00\x72\x00\x6f\x00\x69\x00\x64\x00\x2d\x00\x64\x00\x65\x00\x6c\x00\x65\x00\x74\x00\x65\x00\x2e\x00\x73\x00\x76\
-\x00\x67\
-\x00\x0f\
-\x07\x0e\xc4\x87\
-\x00\x6f\
-\x00\x70\x00\x65\x00\x6e\x00\x70\x00\x6f\x00\x6c\x00\x79\x00\x67\x00\x6f\x00\x6e\x00\x2e\x00\x73\x00\x76\x00\x67\
-\x00\x16\
-\x01\xfb\x76\x27\
-\x00\x61\
-\x00\x6e\x00\x64\x00\x72\x00\x6f\x00\x69\x00\x64\x00\x2d\x00\x61\x00\x72\x00\x72\x00\x6f\x00\x77\x00\x2d\x00\x62\x00\x61\x00\x63\
-\x00\x6b\x00\x2e\x00\x73\x00\x76\x00\x67\
-\x00\x0e\
-\x05\xed\x38\x67\
-\x00\x61\
-\x00\x72\x00\x72\x00\x6f\x00\x77\x00\x2d\x00\x6d\x00\x6f\x00\x76\x00\x65\x00\x2e\x00\x73\x00\x76\x00\x67\
-\x00\x10\
-\x06\xe3\xaf\xe7\
-\x00\x61\
-\x00\x6e\x00\x64\x00\x72\x00\x6f\x00\x69\x00\x64\x00\x2d\x00\x68\x00\x61\x00\x6e\x00\x64\x00\x2e\x00\x73\x00\x76\x00\x67\
-\x00\x17\
-\x07\x87\x48\x27\
-\x00\x61\
-\x00\x6e\x00\x64\x00\x72\x00\x6f\x00\x69\x00\x64\x00\x2d\x00\x66\x00\x6f\x00\x6c\x00\x64\x00\x65\x00\x72\x00\x2d\x00\x6f\x00\x70\
-\x00\x65\x00\x6e\x00\x2e\x00\x73\x00\x76\x00\x67\
-\x00\x15\
-\x0f\xc4\x59\xe7\
-\x00\x73\
-\x00\x75\x00\x62\x00\x64\x00\x69\x00\x72\x00\x65\x00\x63\x00\x74\x00\x6f\x00\x72\x00\x79\x00\x2d\x00\x6c\x00\x65\x00\x66\x00\x74\
-\x00\x2e\x00\x73\x00\x76\x00\x67\
-\x00\x10\
-\x08\xe4\xaf\x47\
-\x00\x61\
-\x00\x6e\x00\x64\x00\x72\x00\x6f\x00\x69\x00\x64\x00\x2d\x00\x64\x00\x6f\x00\x6e\x00\x65\x00\x2e\x00\x73\x00\x76\x00\x67\
-\x00\x08\
-\x0b\x07\x57\xa7\
-\x00\x65\
-\x00\x64\x00\x69\x00\x74\x00\x2e\x00\x73\x00\x76\x00\x67\
-\x00\x19\
-\x0f\xef\x7b\xe7\
-\x00\x61\
-\x00\x6e\x00\x64\x00\x72\x00\x6f\x00\x69\x00\x64\x00\x2d\x00\x63\x00\x6f\x00\x6c\x00\x6f\x00\x72\x00\x2d\x00\x70\x00\x61\x00\x6c\
-\x00\x65\x00\x74\x00\x74\x00\x65\x00\x2e\x00\x73\x00\x76\x00\x67\
-\x00\x11\
-\x01\x60\xbc\x47\
-\x00\x73\
-\x00\x6f\x00\x63\x00\x69\x00\x61\x00\x6c\x00\x2d\x00\x70\x00\x79\x00\x74\x00\x68\x00\x6f\x00\x6e\x00\x2e\x00\x73\x00\x76\x00\x67\
-\
-\x00\x07\
-\x0c\xf8\x5a\x07\
-\x00\x65\
-\x00\x79\x00\x65\x00\x2e\x00\x73\x00\x76\x00\x67\
-"
-
-qt_resource_struct_v1 = b"\
-\x00\x00\x00\x00\x00\x02\x00\x00\x00\x01\x00\x00\x00\x01\
-\x00\x00\x00\x00\x00\x02\x00\x00\x00\x29\x00\x00\x00\x02\
-\x00\x00\x06\x10\x00\x00\x00\x00\x00\x01\x00\x00\x82\xd5\
-\x00\x00\x02\x96\x00\x00\x00\x00\x00\x01\x00\x00\x36\x4d\
-\x00\x00\x04\xbe\x00\x00\x00\x00\x00\x01\x00\x00\x68\xdb\
-\x00\x00\x02\x6a\x00\x00\x00\x00\x00\x01\x00\x00\x33\x23\
-\x00\x00\x01\x96\x00\x00\x00\x00\x00\x01\x00\x00\x22\x76\
-\x00\x00\x00\xaa\x00\x01\x00\x00\x00\x01\x00\x00\x10\x6b\
-\x00\x00\x03\x30\x00\x00\x00\x00\x00\x01\x00\x00\x45\x97\
-\x00\x00\x03\xd0\x00\x00\x00\x00\x00\x01\x00\x00\x54\x52\
-\x00\x00\x00\x10\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\
-\x00\x00\x03\x5a\x00\x00\x00\x00\x00\x01\x00\x00\x48\xd1\
-\x00\x00\x04\xf0\x00\x00\x00\x00\x00\x01\x00\x00\x6b\x5c\
-\x00\x00\x01\xfc\x00\x00\x00\x00\x00\x01\x00\x00\x29\x2a\
-\x00\x00\x05\x12\x00\x00\x00\x00\x00\x01\x00\x00\x6e\x29\
-\x00\x00\x02\xb0\x00\x00\x00\x00\x00\x01\x00\x00\x3c\x25\
-\x00\x00\x04\x9a\x00\x00\x00\x00\x00\x01\x00\x00\x64\x9a\
-\x00\x00\x05\x38\x00\x00\x00\x00\x00\x01\x00\x00\x73\xf7\
-\x00\x00\x04\x70\x00\x00\x00\x00\x00\x01\x00\x00\x61\xf4\
-\x00\x00\x01\x2e\x00\x00\x00\x00\x00\x01\x00\x00\x1c\x50\
-\x00\x00\x00\xd0\x00\x00\x00\x00\x00\x01\x00\x00\x12\x90\
-\x00\x00\x01\x58\x00\x00\x00\x00\x00\x01\x00\x00\x1f\x76\
-\x00\x00\x00\xf6\x00\x00\x00\x00\x00\x01\x00\x00\x16\xb0\
-\x00\x00\x05\x9c\x00\x00\x00\x00\x00\x01\x00\x00\x77\xbd\
-\x00\x00\x02\x30\x00\x01\x00\x00\x00\x01\x00\x00\x2d\xf8\
-\x00\x00\x02\x46\x00\x00\x00\x00\x00\x01\x00\x00\x2f\xd9\
-\x00\x00\x03\xf4\x00\x00\x00\x00\x00\x01\x00\x00\x59\x2b\
-\x00\x00\x03\x70\x00\x00\x00\x00\x00\x01\x00\x00\x4d\x7f\
-\x00\x00\x00\x90\x00\x00\x00\x00\x00\x01\x00\x00\x0c\xeb\
-\x00\x00\x05\xc2\x00\x00\x00\x00\x00\x01\x00\x00\x7a\x3a\
-\x00\x00\x00\x30\x00\x00\x00\x00\x00\x01\x00\x00\x04\xa6\
-\x00\x00\x04\x4a\x00\x00\x00\x00\x00\x01\x00\x00\x5f\x71\
-\x00\x00\x03\x06\x00\x00\x00\x00\x00\x01\x00\x00\x41\x2f\
-\x00\x00\x03\xa8\x00\x00\x00\x00\x00\x01\x00\x00\x50\x00\
-\x00\x00\x01\xd4\x00\x00\x00\x00\x00\x01\x00\x00\x26\x6f\
-\x00\x00\x02\xf0\x00\x00\x00\x00\x00\x01\x00\x00\x40\x0f\
-\x00\x00\x06\x38\x00\x00\x00\x00\x00\x01\x00\x00\x8a\x59\
-\x00\x00\x04\x0e\x00\x00\x00\x00\x00\x01\x00\x00\x5c\x21\
-\x00\x00\x00\x76\x00\x00\x00\x00\x00\x01\x00\x00\x0b\x7e\
-\x00\x00\x00\x48\x00\x00\x00\x00\x00\x01\x00\x00\x07\xb6\
-\x00\x00\x05\x6c\x00\x00\x00\x00\x00\x01\x00\x00\x77\x4d\
-\x00\x00\x01\x0c\x00\x00\x00\x00\x00\x01\x00\x00\x19\x55\
-\x00\x00\x05\xd8\x00\x00\x00\x00\x00\x01\x00\x00\x7d\xaa\
-"
-
-qt_resource_struct_v2 = b"\
-\x00\x00\x00\x00\x00\x02\x00\x00\x00\x01\x00\x00\x00\x01\
-\x00\x00\x00\x00\x00\x00\x00\x00\
-\x00\x00\x00\x00\x00\x02\x00\x00\x00\x29\x00\x00\x00\x02\
-\x00\x00\x00\x00\x00\x00\x00\x00\
-\x00\x00\x06\x10\x00\x00\x00\x00\x00\x01\x00\x00\x82\xd5\
-\x00\x00\x01\x78\x33\x4a\x26\xbc\
-\x00\x00\x02\x96\x00\x00\x00\x00\x00\x01\x00\x00\x36\x4d\
-\x00\x00\x01\x78\x33\x4a\x26\xbb\
-\x00\x00\x04\xbe\x00\x00\x00\x00\x00\x01\x00\x00\x68\xdb\
-\x00\x00\x01\x78\x33\x4a\x26\xbb\
-\x00\x00\x02\x6a\x00\x00\x00\x00\x00\x01\x00\x00\x33\x23\
-\x00\x00\x01\x78\x33\x4a\x26\xbb\
-\x00\x00\x01\x96\x00\x00\x00\x00\x00\x01\x00\x00\x22\x76\
-\x00\x00\x01\x78\x33\x4a\x26\xbc\
-\x00\x00\x00\xaa\x00\x01\x00\x00\x00\x01\x00\x00\x10\x6b\
-\x00\x00\x01\x78\x33\x4a\x26\xbc\
-\x00\x00\x03\x30\x00\x00\x00\x00\x00\x01\x00\x00\x45\x97\
-\x00\x00\x01\x78\x33\x4a\x26\xbb\
-\x00\x00\x03\xd0\x00\x00\x00\x00\x00\x01\x00\x00\x54\x52\
-\x00\x00\x01\x78\x33\x4a\x26\xbc\
-\x00\x00\x00\x10\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\
-\x00\x00\x01\x78\x33\x4a\x26\xbc\
-\x00\x00\x03\x5a\x00\x00\x00\x00\x00\x01\x00\x00\x48\xd1\
-\x00\x00\x01\x78\x33\x4a\x26\xbc\
-\x00\x00\x04\xf0\x00\x00\x00\x00\x00\x01\x00\x00\x6b\x5c\
-\x00\x00\x01\x78\x33\x4a\x26\xbb\
-\x00\x00\x01\xfc\x00\x00\x00\x00\x00\x01\x00\x00\x29\x2a\
-\x00\x00\x01\x78\x33\x4a\x26\xbc\
-\x00\x00\x05\x12\x00\x00\x00\x00\x00\x01\x00\x00\x6e\x29\
-\x00\x00\x01\x78\x33\x4a\x26\xbb\
-\x00\x00\x02\xb0\x00\x00\x00\x00\x00\x01\x00\x00\x3c\x25\
-\x00\x00\x01\x78\x33\x4a\x26\xbc\
-\x00\x00\x04\x9a\x00\x00\x00\x00\x00\x01\x00\x00\x64\x9a\
-\x00\x00\x01\x78\x33\x4a\x26\xbc\
-\x00\x00\x05\x38\x00\x00\x00\x00\x00\x01\x00\x00\x73\xf7\
-\x00\x00\x01\x78\x33\x4a\x26\xbb\
-\x00\x00\x04\x70\x00\x00\x00\x00\x00\x01\x00\x00\x61\xf4\
-\x00\x00\x01\x78\x33\x4a\x26\xbb\
-\x00\x00\x01\x2e\x00\x00\x00\x00\x00\x01\x00\x00\x1c\x50\
-\x00\x00\x01\x78\x33\x4a\x26\xbb\
-\x00\x00\x00\xd0\x00\x00\x00\x00\x00\x01\x00\x00\x12\x90\
-\x00\x00\x01\x78\x33\x4a\x26\xbb\
-\x00\x00\x01\x58\x00\x00\x00\x00\x00\x01\x00\x00\x1f\x76\
-\x00\x00\x01\x78\x33\x4a\x26\xbb\
-\x00\x00\x00\xf6\x00\x00\x00\x00\x00\x01\x00\x00\x16\xb0\
-\x00\x00\x01\x78\x33\x4a\x26\xbc\
-\x00\x00\x05\x9c\x00\x00\x00\x00\x00\x01\x00\x00\x77\xbd\
-\x00\x00\x01\x78\x33\x4a\x26\xbb\
-\x00\x00\x02\x30\x00\x01\x00\x00\x00\x01\x00\x00\x2d\xf8\
-\x00\x00\x01\x78\x33\x4a\x26\xbc\
-\x00\x00\x02\x46\x00\x00\x00\x00\x00\x01\x00\x00\x2f\xd9\
-\x00\x00\x01\x78\x33\x4a\x26\xbc\
-\x00\x00\x03\xf4\x00\x00\x00\x00\x00\x01\x00\x00\x59\x2b\
-\x00\x00\x01\x78\x33\x4a\x26\xbc\
-\x00\x00\x03\x70\x00\x00\x00\x00\x00\x01\x00\x00\x4d\x7f\
-\x00\x00\x01\x78\x33\x4a\x26\xbb\
-\x00\x00\x00\x90\x00\x00\x00\x00\x00\x01\x00\x00\x0c\xeb\
-\x00\x00\x01\x78\x33\x4a\x26\xbb\
-\x00\x00\x05\xc2\x00\x00\x00\x00\x00\x01\x00\x00\x7a\x3a\
-\x00\x00\x01\x78\x33\x4a\x26\xbc\
-\x00\x00\x00\x30\x00\x00\x00\x00\x00\x01\x00\x00\x04\xa6\
-\x00\x00\x01\x78\x33\x4a\x26\xbb\
-\x00\x00\x04\x4a\x00\x00\x00\x00\x00\x01\x00\x00\x5f\x71\
-\x00\x00\x01\x78\x33\x4a\x26\xbb\
-\x00\x00\x03\x06\x00\x00\x00\x00\x00\x01\x00\x00\x41\x2f\
-\x00\x00\x01\x78\x33\x4a\x26\xbb\
-\x00\x00\x03\xa8\x00\x00\x00\x00\x00\x01\x00\x00\x50\x00\
-\x00\x00\x01\x78\x33\x4a\x26\xbc\
-\x00\x00\x01\xd4\x00\x00\x00\x00\x00\x01\x00\x00\x26\x6f\
-\x00\x00\x01\x78\x33\x4a\x26\xbb\
-\x00\x00\x02\xf0\x00\x00\x00\x00\x00\x01\x00\x00\x40\x0f\
-\x00\x00\x01\x78\x33\x4a\x26\xbc\
-\x00\x00\x06\x38\x00\x00\x00\x00\x00\x01\x00\x00\x8a\x59\
-\x00\x00\x01\x78\x33\x4a\x26\xbc\
-\x00\x00\x04\x0e\x00\x00\x00\x00\x00\x01\x00\x00\x5c\x21\
-\x00\x00\x01\x78\x33\x4a\x26\xbb\
-\x00\x00\x00\x76\x00\x00\x00\x00\x00\x01\x00\x00\x0b\x7e\
-\x00\x00\x01\x78\x33\x4a\x26\xbb\
-\x00\x00\x00\x48\x00\x00\x00\x00\x00\x01\x00\x00\x07\xb6\
-\x00\x00\x01\x78\x33\x4a\x26\xbc\
-\x00\x00\x05\x6c\x00\x00\x00\x00\x00\x01\x00\x00\x77\x4d\
-\x00\x00\x01\x78\x33\x4a\x26\xbc\
-\x00\x00\x01\x0c\x00\x00\x00\x00\x00\x01\x00\x00\x19\x55\
-\x00\x00\x01\x78\x33\x4a\x26\xbc\
-\x00\x00\x05\xd8\x00\x00\x00\x00\x00\x01\x00\x00\x7d\xaa\
-\x00\x00\x01\x78\x33\x4a\x26\xbb\
-"
-
-qt_version = [int(v) for v in QtCore.qVersion().split('.')]
-if qt_version < [5, 8, 0]:
-    rcc_version = 1
-    qt_resource_struct = qt_resource_struct_v1
-else:
-    rcc_version = 2
-    qt_resource_struct = qt_resource_struct_v2
-
-def qInitResources():
-    QtCore.qRegisterResourceData(rcc_version, qt_resource_struct, qt_resource_name, qt_resource_data)
-
-def qCleanupResources():
-    QtCore.qUnregisterResourceData(rcc_version, qt_resource_struct, qt_resource_name, qt_resource_data)
-
-qInitResources()

Modified: trunk/Master/texmf-dist/asymptote/GUI/labelEditor.py
===================================================================
--- trunk/Master/texmf-dist/asymptote/GUI/labelEditor.py	2022-02-27 23:39:53 UTC (rev 62264)
+++ trunk/Master/texmf-dist/asymptote/GUI/labelEditor.py	2022-02-27 23:41:11 UTC (rev 62265)
@@ -1,15 +1,15 @@
 #!/usr/bin/env python3
 
 from pyUIClass.labelTextEditor import Ui_Dialog
-import PyQt5.QtWidgets as Qw
-import PyQt5.QtSvg as Qs
-import PyQt5.QtGui as Qg
-import PyQt5.QtCore as Qc
-import xasyArgs as xa
-import xasy2asy as x2a
+import PyQt5.QtWidgets as QtWidgets
+import PyQt5.QtSvg as QtSvg
+import PyQt5.QtGui as QtGui
+import PyQt5.QtCore as QtCore
+import xasyArgs as xasyArgs
+import xasy2asy as xasy2asy
+import xasyOptions as xasyOptions
+import xasyUtils as xasyUtils
 import subprocess
-import xasyOptions as xo
-import xasyUtils as xu
 import tempfile
 import uuid
 import os
@@ -16,7 +16,7 @@
 import io
 
 
-class labelEditor(Qw.QDialog):
+class labelEditor(QtWidgets.QDialog):
     def __init__(self, text=''):
         super().__init__()
         self.ui = Ui_Dialog()
@@ -67,9 +67,9 @@
             return rawText
 
     def btnPreviewOnClick(self):
-        path = xa.getArgs().asypath
+        path = xasyArgs.getArgs().asypath
         if path is None:
-            opt = xo.xasyOptions().load()
+            opt = xo.BasicConfigs.defaultOpt
             path = opt['asyPath']
 
         asyInput = """
@@ -80,7 +80,7 @@
         shipout(f);
         """
 
-        self.svgPreview = Qs.QSvgRenderer()
+        self.svgPreview = QtSvg.QSvgRenderer()
         with tempfile.TemporaryDirectory(prefix='xasylbl_') as tmpdir:
             id = str(uuid.uuid4())
             tmpFile = os.path.join(tmpdir, 'lbl-{0}.svg'.format(id))
@@ -95,8 +95,8 @@
 
             bounds_1, bounds_2 = [val.strip() for val in raw_array]
 
-            min_bounds = xu.listize(bounds_1, (float, float))
-            max_bounds = xu.listize(bounds_2, (float, float))
+            min_bounds = xasyUtils.listize(bounds_1, (float, float))
+            max_bounds = xasyUtils.listize(bounds_2, (float, float))
 
             new_rect = self.processBounds(min_bounds, max_bounds)
             self.svgPreview.load(tmpFile)
@@ -106,12 +106,12 @@
         self.drawPreview(new_rect)
 
     def drawPreview(self, naturalBounds):
-        img = Qg.QPixmap(self.ui.lblLabelPreview.size())
-        img.fill(Qg.QColor.fromRgbF(1, 1, 1, 1))
+        img = QtGui.QPixmap(self.ui.lblLabelPreview.size())
+        img.fill(QtGui.QColor.fromRgbF(1, 1, 1, 1))
         if self.svgPreview is None:
             pass
         else:
-            with Qg.QPainter(img) as pnt:
+            with QtGui.QPainter(img) as pnt:
                 scale_ratio = self.getIdealScaleRatio(naturalBounds, self.ui.lblLabelPreview.rect())
 
                 pnt.translate(self.ui.lblLabelPreview.rect().center())
@@ -121,8 +121,8 @@
 
 
     def getIdealScaleRatio(self, rect, boundsRect):
-        assert isinstance(rect, (Qc.QRect, Qc.QRectF))
-        assert isinstance(rect, (Qc.QRect, Qc.QRectF))
+        assert isinstance(rect, (QtCore.QRect, QtCore.QRectF))
+        assert isinstance(rect, (QtCore.QRect, QtCore.QRectF))
 
         magic_ratio = 0.50
         idealRatioHeight = (magic_ratio * boundsRect.height()) / rect.height()
@@ -139,15 +139,15 @@
         p1x, p1y = minPt
         p2x, p2y = maxPt
 
-        minPt = Qc.QPointF(p1x, p1y)
-        maxPt = Qc.QPointF(p2x, p2y)
+        minPt = QtCore.QPointF(p1x, p1y)
+        maxPt = QtCore.QPointF(p2x, p2y)
 
-        newRect = Qc.QRectF(minPt, maxPt)
+        newRect = QtCore.QRectF(minPt, maxPt)
         return newRect
 
 
     def btnGetTextOnClick(self):
-        msgbox = Qw.QMessageBox()
+        msgbox = QtWidgets.QMessageBox()
         msgbox.setText('Text Preview:\n' + self.getText())
         msgbox.setWindowTitle('Text preview')
         msgbox.show()

Modified: trunk/Master/texmf-dist/asymptote/GUI/pyUIClass/custMatTransform.py
===================================================================
--- trunk/Master/texmf-dist/asymptote/GUI/pyUIClass/custMatTransform.py	2022-02-27 23:39:53 UTC (rev 62264)
+++ trunk/Master/texmf-dist/asymptote/GUI/pyUIClass/custMatTransform.py	2022-02-27 23:41:11 UTC (rev 62265)
@@ -2,9 +2,10 @@
 
 # Form implementation generated from reading ui file 'GUI/windows/custMatTransform.ui'
 #
-# Created by: PyQt5 UI code generator 5.13.1
+# Created by: PyQt5 UI code generator 5.15.0
 #
-# WARNING! All changes made in this file will be lost!
+# WARNING: Any manual changes made to this file will be lost when pyuic5 is
+# run again.  Do not edit this file unless you know what you are doing.
 
 
 from PyQt5 import QtCore, QtGui, QtWidgets

Modified: trunk/Master/texmf-dist/asymptote/GUI/pyUIClass/labelTextEditor.py
===================================================================
--- trunk/Master/texmf-dist/asymptote/GUI/pyUIClass/labelTextEditor.py	2022-02-27 23:39:53 UTC (rev 62264)
+++ trunk/Master/texmf-dist/asymptote/GUI/pyUIClass/labelTextEditor.py	2022-02-27 23:41:11 UTC (rev 62265)
@@ -2,9 +2,10 @@
 
 # Form implementation generated from reading ui file 'GUI/windows/labelTextEditor.ui'
 #
-# Created by: PyQt5 UI code generator 5.13.1
+# Created by: PyQt5 UI code generator 5.15.0
 #
-# WARNING! All changes made in this file will be lost!
+# WARNING: Any manual changes made to this file will be lost when pyuic5 is
+# run again.  Do not edit this file unless you know what you are doing.
 
 
 from PyQt5 import QtCore, QtGui, QtWidgets

Modified: trunk/Master/texmf-dist/asymptote/GUI/pyUIClass/setCustomAnchor.py
===================================================================
--- trunk/Master/texmf-dist/asymptote/GUI/pyUIClass/setCustomAnchor.py	2022-02-27 23:39:53 UTC (rev 62264)
+++ trunk/Master/texmf-dist/asymptote/GUI/pyUIClass/setCustomAnchor.py	2022-02-27 23:41:11 UTC (rev 62265)
@@ -2,9 +2,10 @@
 
 # Form implementation generated from reading ui file 'GUI/windows/setCustomAnchor.ui'
 #
-# Created by: PyQt5 UI code generator 5.13.1
+# Created by: PyQt5 UI code generator 5.15.0
 #
-# WARNING! All changes made in this file will be lost!
+# WARNING: Any manual changes made to this file will be lost when pyuic5 is
+# run again.  Do not edit this file unless you know what you are doing.
 
 
 from PyQt5 import QtCore, QtGui, QtWidgets

Modified: trunk/Master/texmf-dist/asymptote/GUI/pyUIClass/widg_addLabel.py
===================================================================
--- trunk/Master/texmf-dist/asymptote/GUI/pyUIClass/widg_addLabel.py	2022-02-27 23:39:53 UTC (rev 62264)
+++ trunk/Master/texmf-dist/asymptote/GUI/pyUIClass/widg_addLabel.py	2022-02-27 23:41:11 UTC (rev 62265)
@@ -2,9 +2,10 @@
 
 # Form implementation generated from reading ui file 'GUI/windows/widg_addLabel.ui'
 #
-# Created by: PyQt5 UI code generator 5.13.1
+# Created by: PyQt5 UI code generator 5.15.0
 #
-# WARNING! All changes made in this file will be lost!
+# WARNING: Any manual changes made to this file will be lost when pyuic5 is
+# run again.  Do not edit this file unless you know what you are doing.
 
 
 from PyQt5 import QtCore, QtGui, QtWidgets

Modified: trunk/Master/texmf-dist/asymptote/GUI/pyUIClass/widg_addPolyOpt.py
===================================================================
--- trunk/Master/texmf-dist/asymptote/GUI/pyUIClass/widg_addPolyOpt.py	2022-02-27 23:39:53 UTC (rev 62264)
+++ trunk/Master/texmf-dist/asymptote/GUI/pyUIClass/widg_addPolyOpt.py	2022-02-27 23:41:11 UTC (rev 62265)
@@ -2,9 +2,10 @@
 
 # Form implementation generated from reading ui file 'GUI/windows/widg_addPolyOpt.ui'
 #
-# Created by: PyQt5 UI code generator 5.13.1
+# Created by: PyQt5 UI code generator 5.15.0
 #
-# WARNING! All changes made in this file will be lost!
+# WARNING: Any manual changes made to this file will be lost when pyuic5 is
+# run again.  Do not edit this file unless you know what you are doing.
 
 
 from PyQt5 import QtCore, QtGui, QtWidgets
@@ -31,11 +32,21 @@
         self.chkInscribed = QtWidgets.QCheckBox(Form)
         self.chkInscribed.setObjectName("chkInscribed")
         self.horizontalLayout.addWidget(self.chkInscribed)
+        spacerItem = QtWidgets.QSpacerItem(19, 20, QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Minimum)
+        self.horizontalLayout.addItem(spacerItem)
+        self.label = QtWidgets.QLabel(Form)
+        sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Fixed)
+        sizePolicy.setHorizontalStretch(0)
+        sizePolicy.setVerticalStretch(0)
+        sizePolicy.setHeightForWidth(self.label.sizePolicy().hasHeightForWidth())
+        self.label.setSizePolicy(sizePolicy)
+        self.label.setObjectName("label")
+        self.horizontalLayout.addWidget(self.label)
         self.txtSides = QtWidgets.QLineEdit(Form)
         self.txtSides.setObjectName("txtSides")
         self.horizontalLayout.addWidget(self.txtSides)
-        spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
-        self.horizontalLayout.addItem(spacerItem)
+        spacerItem1 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
+        self.horizontalLayout.addItem(spacerItem1)
         self.horizontalLayout_2.addLayout(self.horizontalLayout)
 
         self.retranslateUi(Form)
@@ -45,5 +56,6 @@
         _translate = QtCore.QCoreApplication.translate
         Form.setWindowTitle(_translate("Form", "Form"))
         self.chkInscribed.setText(_translate("Form", "Start at Vertex"))
+        self.label.setText(_translate("Form", "Sides:  "))
         self.txtSides.setToolTip(_translate("Form", "Number of Sides"))
         self.txtSides.setPlaceholderText(_translate("Form", "Sides"))

Modified: trunk/Master/texmf-dist/asymptote/GUI/pyUIClass/widg_editBezier.py
===================================================================
--- trunk/Master/texmf-dist/asymptote/GUI/pyUIClass/widg_editBezier.py	2022-02-27 23:39:53 UTC (rev 62264)
+++ trunk/Master/texmf-dist/asymptote/GUI/pyUIClass/widg_editBezier.py	2022-02-27 23:41:11 UTC (rev 62265)
@@ -2,9 +2,10 @@
 
 # Form implementation generated from reading ui file 'GUI/windows/widg_editBezier.ui'
 #
-# Created by: PyQt5 UI code generator 5.13.1
+# Created by: PyQt5 UI code generator 5.15.0
 #
-# WARNING! All changes made in this file will be lost!
+# WARNING: Any manual changes made to this file will be lost when pyuic5 is
+# run again.  Do not edit this file unless you know what you are doing.
 
 
 from PyQt5 import QtCore, QtGui, QtWidgets

Modified: trunk/Master/texmf-dist/asymptote/GUI/pyUIClass/widgetPointEditor.py
===================================================================
--- trunk/Master/texmf-dist/asymptote/GUI/pyUIClass/widgetPointEditor.py	2022-02-27 23:39:53 UTC (rev 62264)
+++ trunk/Master/texmf-dist/asymptote/GUI/pyUIClass/widgetPointEditor.py	2022-02-27 23:41:11 UTC (rev 62265)
@@ -2,9 +2,10 @@
 
 # Form implementation generated from reading ui file 'GUI/windows/widgetPointEditor.ui'
 #
-# Created by: PyQt5 UI code generator 5.13.1
+# Created by: PyQt5 UI code generator 5.15.0
 #
-# WARNING! All changes made in this file will be lost!
+# WARNING: Any manual changes made to this file will be lost when pyuic5 is
+# run again.  Do not edit this file unless you know what you are doing.
 
 
 from PyQt5 import QtCore, QtGui, QtWidgets

Modified: trunk/Master/texmf-dist/asymptote/GUI/pyUIClass/window1.py
===================================================================
--- trunk/Master/texmf-dist/asymptote/GUI/pyUIClass/window1.py	2022-02-27 23:39:53 UTC (rev 62264)
+++ trunk/Master/texmf-dist/asymptote/GUI/pyUIClass/window1.py	2022-02-27 23:41:11 UTC (rev 62265)
@@ -2,9 +2,10 @@
 
 # Form implementation generated from reading ui file 'GUI/windows/window1.ui'
 #
-# Created by: PyQt5 UI code generator 5.13.1
+# Created by: PyQt5 UI code generator 5.15.0
 #
-# WARNING! All changes made in this file will be lost!
+# WARNING: Any manual changes made to this file will be lost when pyuic5 is
+# run again.  Do not edit this file unless you know what you are doing.
 
 
 from PyQt5 import QtCore, QtGui, QtWidgets
@@ -62,7 +63,7 @@
         self.btnUndo.setBaseSize(QtCore.QSize(32, 32))
         self.btnUndo.setText("")
         icon = QtGui.QIcon()
-        icon.addPixmap(QtGui.QPixmap(":/icons/android-arrow-back.svg"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
+        icon.addPixmap(QtGui.QPixmap(":/icons/undo.svg"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
         self.btnUndo.setIcon(icon)
         self.btnUndo.setIconSize(QtCore.QSize(16, 16))
         self.btnUndo.setFlat(True)
@@ -79,7 +80,7 @@
         self.btnRedo.setBaseSize(QtCore.QSize(32, 32))
         self.btnRedo.setText("")
         icon1 = QtGui.QIcon()
-        icon1.addPixmap(QtGui.QPixmap(":/icons/android-arrow-forward.svg"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
+        icon1.addPixmap(QtGui.QPixmap(":/icons/redo.svg"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
         self.btnRedo.setIcon(icon1)
         self.btnRedo.setIconSize(QtCore.QSize(16, 16))
         self.btnRedo.setFlat(True)
@@ -251,7 +252,7 @@
         sizePolicy.setVerticalStretch(0)
         sizePolicy.setHeightForWidth(self.btnAlignX.sizePolicy().hasHeightForWidth())
         self.btnAlignX.setSizePolicy(sizePolicy)
-        self.btnAlignX.setMaximumSize(QtCore.QSize(25, 25))
+        self.btnAlignX.setMaximumSize(QtCore.QSize(32, 25))
         self.btnAlignX.setBaseSize(QtCore.QSize(32, 32))
         font = QtGui.QFont()
         font.setFamily("Roboto")
@@ -269,9 +270,10 @@
         sizePolicy.setVerticalStretch(0)
         sizePolicy.setHeightForWidth(self.btnAlignY.sizePolicy().hasHeightForWidth())
         self.btnAlignY.setSizePolicy(sizePolicy)
-        self.btnAlignY.setMaximumSize(QtCore.QSize(25, 25))
+        self.btnAlignY.setMaximumSize(QtCore.QSize(32, 25))
         self.btnAlignY.setBaseSize(QtCore.QSize(32, 32))
         font = QtGui.QFont()
+        font.setFamily("Roboto")
         font.setBold(True)
         font.setWeight(75)
         self.btnAlignY.setFont(font)
@@ -295,6 +297,7 @@
         icon11.addPixmap(QtGui.QPixmap(":/icons/edit.svg"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
         self.btnSelectEdit.setIcon(icon11)
         self.btnSelectEdit.setIconSize(QtCore.QSize(16, 16))
+        self.btnSelectEdit.setCheckable(True)
         self.btnSelectEdit.setFlat(True)
         self.btnSelectEdit.setObjectName("btnSelectEdit")
         self.horizontalLayout.addWidget(self.btnSelectEdit)
@@ -312,7 +315,7 @@
         icon12.addPixmap(QtGui.QPixmap(":/icons/android-delete.svg"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
         self.btnDeleteMode.setIcon(icon12)
         self.btnDeleteMode.setIconSize(QtCore.QSize(16, 16))
-        self.btnDeleteMode.setCheckable(False)
+        self.btnDeleteMode.setCheckable(True)
         self.btnDeleteMode.setFlat(True)
         self.btnDeleteMode.setObjectName("btnDeleteMode")
         self.horizontalLayout.addWidget(self.btnDeleteMode)
@@ -646,6 +649,7 @@
         icon24.addPixmap(QtGui.QPixmap(":/icons/openpolygon.svg"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
         self.btnOpenPoly.setIcon(icon24)
         self.btnOpenPoly.setIconSize(QtCore.QSize(16, 16))
+        self.btnOpenPoly.setCheckable(True)
         self.btnOpenPoly.setFlat(True)
         self.btnOpenPoly.setObjectName("btnOpenPoly")
         self.formLayout.setWidget(4, QtWidgets.QFormLayout.LabelRole, self.btnOpenPoly)
@@ -662,6 +666,7 @@
         icon25.addPixmap(QtGui.QPixmap(":/icons/closedpolygon.svg"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
         self.btnClosedPoly.setIcon(icon25)
         self.btnClosedPoly.setIconSize(QtCore.QSize(16, 16))
+        self.btnClosedPoly.setCheckable(True)
         self.btnClosedPoly.setFlat(True)
         self.btnClosedPoly.setObjectName("btnClosedPoly")
         self.formLayout.setWidget(5, QtWidgets.QFormLayout.LabelRole, self.btnClosedPoly)
@@ -678,6 +683,7 @@
         icon26.addPixmap(QtGui.QPixmap(":/icons/opencurve.svg"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
         self.btnOpenCurve.setIcon(icon26)
         self.btnOpenCurve.setIconSize(QtCore.QSize(16, 16))
+        self.btnOpenCurve.setCheckable(True)
         self.btnOpenCurve.setFlat(True)
         self.btnOpenCurve.setObjectName("btnOpenCurve")
         self.formLayout.setWidget(6, QtWidgets.QFormLayout.LabelRole, self.btnOpenCurve)
@@ -694,6 +700,7 @@
         icon27.addPixmap(QtGui.QPixmap(":/icons/closedcurve.svg"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
         self.btnClosedCurve.setIcon(icon27)
         self.btnClosedCurve.setIconSize(QtCore.QSize(16, 16))
+        self.btnClosedCurve.setCheckable(True)
         self.btnClosedCurve.setFlat(True)
         self.btnClosedCurve.setObjectName("btnClosedCurve")
         self.formLayout.setWidget(7, QtWidgets.QFormLayout.LabelRole, self.btnClosedCurve)
@@ -710,6 +717,7 @@
         icon28.addPixmap(QtGui.QPixmap(":/icons/triangle-stroked-15.svg"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
         self.btnAddPoly.setIcon(icon28)
         self.btnAddPoly.setIconSize(QtCore.QSize(16, 16))
+        self.btnAddPoly.setCheckable(True)
         self.btnAddPoly.setFlat(True)
         self.btnAddPoly.setObjectName("btnAddPoly")
         self.formLayout.setWidget(8, QtWidgets.QFormLayout.LabelRole, self.btnAddPoly)
@@ -726,6 +734,7 @@
         icon29.addPixmap(QtGui.QPixmap(":/icons/circle.svg"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
         self.btnAddCircle.setIcon(icon29)
         self.btnAddCircle.setIconSize(QtCore.QSize(16, 16))
+        self.btnAddCircle.setCheckable(True)
         self.btnAddCircle.setFlat(True)
         self.btnAddCircle.setObjectName("btnAddCircle")
         self.formLayout.setWidget(10, QtWidgets.QFormLayout.LabelRole, self.btnAddCircle)
@@ -742,9 +751,27 @@
         icon30.addPixmap(QtGui.QPixmap(":/icons/text.svg"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
         self.btnAddLabel.setIcon(icon30)
         self.btnAddLabel.setIconSize(QtCore.QSize(16, 16))
+        self.btnAddLabel.setCheckable(True)
         self.btnAddLabel.setFlat(True)
         self.btnAddLabel.setObjectName("btnAddLabel")
         self.formLayout.setWidget(11, QtWidgets.QFormLayout.LabelRole, self.btnAddLabel)
+        self.btnAddFreehand = QtWidgets.QPushButton(self.formFrame)
+        self.btnAddFreehand.setEnabled(True)
+        sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Maximum)
+        sizePolicy.setHorizontalStretch(0)
+        sizePolicy.setVerticalStretch(0)
+        sizePolicy.setHeightForWidth(self.btnAddFreehand.sizePolicy().hasHeightForWidth())
+        self.btnAddFreehand.setSizePolicy(sizePolicy)
+        self.btnAddFreehand.setMaximumSize(QtCore.QSize(32, 32))
+        self.btnAddFreehand.setText("")
+        icon31 = QtGui.QIcon()
+        icon31.addPixmap(QtGui.QPixmap(":/icons/brush.svg"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
+        self.btnAddFreehand.setIcon(icon31)
+        self.btnAddFreehand.setIconSize(QtCore.QSize(16, 16))
+        self.btnAddFreehand.setCheckable(True)
+        self.btnAddFreehand.setFlat(True)
+        self.btnAddFreehand.setObjectName("btnAddFreehand")
+        self.formLayout.setWidget(12, QtWidgets.QFormLayout.LabelRole, self.btnAddFreehand)
         self.horizontalLayout_7.addWidget(self.formFrame)
         self.imgFrame = QtWidgets.QFrame(self.mainWidget)
         self.imgFrame.setMinimumSize(QtCore.QSize(0, 6))
@@ -783,9 +810,9 @@
         sizePolicy.setHeightForWidth(self.btnTogglePython.sizePolicy().hasHeightForWidth())
         self.btnTogglePython.setSizePolicy(sizePolicy)
         self.btnTogglePython.setText("")
-        icon31 = QtGui.QIcon()
-        icon31.addPixmap(QtGui.QPixmap(":/icons/social-python.svg"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
-        self.btnTogglePython.setIcon(icon31)
+        icon32 = QtGui.QIcon()
+        icon32.addPixmap(QtGui.QPixmap(":/icons/social-python.svg"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
+        self.btnTogglePython.setIcon(icon32)
         self.btnTogglePython.setIconSize(QtCore.QSize(16, 16))
         self.btnTogglePython.setCheckable(True)
         self.btnTogglePython.setFlat(True)
@@ -807,9 +834,9 @@
         sizePolicy.setHeightForWidth(self.btnEnterCommand.sizePolicy().hasHeightForWidth())
         self.btnEnterCommand.setSizePolicy(sizePolicy)
         self.btnEnterCommand.setText("")
-        icon32 = QtGui.QIcon()
-        icon32.addPixmap(QtGui.QPixmap(":/icons/subdirectory-left.svg"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
-        self.btnEnterCommand.setIcon(icon32)
+        icon33 = QtGui.QIcon()
+        icon33.addPixmap(QtGui.QPixmap(":/icons/subdirectory-left.svg"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
+        self.btnEnterCommand.setIcon(icon33)
         self.btnEnterCommand.setIconSize(QtCore.QSize(16, 16))
         self.btnEnterCommand.setFlat(True)
         self.btnEnterCommand.setObjectName("btnEnterCommand")
@@ -820,10 +847,12 @@
         self.horizontalLayout_4.addWidget(self.mainWidget)
         MainWindow.setCentralWidget(self.centralwidget)
         self.menubar = QtWidgets.QMenuBar(MainWindow)
-        self.menubar.setGeometry(QtCore.QRect(0, 0, 1000, 29))
+        self.menubar.setGeometry(QtCore.QRect(0, 0, 1000, 26))
         self.menubar.setObjectName("menubar")
         self.menuFIle = QtWidgets.QMenu(self.menubar)
         self.menuFIle.setObjectName("menuFIle")
+        self.menuOpenRecent = QtWidgets.QMenu(self.menuFIle)
+        self.menuOpenRecent.setObjectName("menuOpenRecent")
         self.menuEdit = QtWidgets.QMenu(self.menubar)
         self.menuEdit.setObjectName("menuEdit")
         self.menuOptions = QtWidgets.QMenu(self.menubar)
@@ -869,9 +898,22 @@
         self.actionSave.setObjectName("actionSave")
         self.actionOpen = QtWidgets.QAction(MainWindow)
         self.actionOpen.setObjectName("actionOpen")
+        self.actionClearRecent = QtWidgets.QAction(MainWindow)
+        self.actionClearRecent.setObjectName("actionClearRecent")
+        self.actionNewFile = QtWidgets.QAction(MainWindow)
+        self.actionNewFile.setObjectName("actionNewFile")
+        self.actionExportToAsy = QtWidgets.QAction(MainWindow)
+        self.actionExportToAsy.setObjectName("actionExportToAsy")
+        self.actionKeymaps = QtWidgets.QAction(MainWindow)
+        self.actionKeymaps.setObjectName("actionKeymaps")
+        self.menuOpenRecent.addSeparator()
+        self.menuOpenRecent.addAction(self.actionClearRecent)
+        self.menuFIle.addAction(self.actionNewFile)
         self.menuFIle.addAction(self.actionOpen)
+        self.menuFIle.addAction(self.menuOpenRecent.menuAction())
         self.menuFIle.addAction(self.actionSave)
         self.menuFIle.addAction(self.actionSaveAs)
+        self.menuFIle.addAction(self.actionExportToAsy)
         self.menuFIle.addAction(self.actionExportAsymptote)
         self.menuFIle.addSeparator()
         self.menuFIle.addAction(self.actionQuit)
@@ -879,6 +921,7 @@
         self.menuEdit.addAction(self.actionRedo)
         self.menuEdit.addSeparator()
         self.menuOptions.addAction(self.actionSettings)
+        self.menuOptions.addAction(self.actionKeymaps)
         self.menuHelp.addAction(self.actionManual)
         self.menuHelp.addAction(self.actionAbout)
         self.menuTools.addAction(self.actionEnterCommand)
@@ -941,7 +984,9 @@
         self.btnAddPoly.setToolTip(_translate("MainWindow", "<html><head/><body><p>Regular polygon</p></body></html>"))
         self.btnAddCircle.setToolTip(_translate("MainWindow", "<html><head/><body><p>Circle</p></body></html>"))
         self.btnAddLabel.setToolTip(_translate("MainWindow", "<html><head/><body><p>Text</p></body></html>"))
+        self.btnAddFreehand.setToolTip(_translate("MainWindow", "<html><head/><body><p>Freehand</p></body></html>"))
         self.menuFIle.setTitle(_translate("MainWindow", "&File"))
+        self.menuOpenRecent.setTitle(_translate("MainWindow", "Open Recent"))
         self.menuEdit.setTitle(_translate("MainWindow", "&Edit"))
         self.menuOptions.setTitle(_translate("MainWindow", "Optio&ns"))
         self.menuHelp.setTitle(_translate("MainWindow", "&Help"))
@@ -950,7 +995,7 @@
         self.actionManual.setText(_translate("MainWindow", "&Manual"))
         self.actionSettings.setText(_translate("MainWindow", "&Settings"))
         self.actionPause.setText(_translate("MainWindow", "Pause "))
-        self.actionSaveAs.setText(_translate("MainWindow", "&Save As"))
+        self.actionSaveAs.setText(_translate("MainWindow", "&Save as"))
         self.actionEnterCommand.setText(_translate("MainWindow", "&Enter Command"))
         self.actionQuit.setText(_translate("MainWindow", "&Quit"))
         self.actionUndo.setText(_translate("MainWindow", "&Undo"))
@@ -958,7 +1003,11 @@
         self.actionShow_Grid.setText(_translate("MainWindow", "&Show Grid"))
         self.actionShow_Local_Grid.setText(_translate("MainWindow", "Show &Local Grid"))
         self.actionTransform.setText(_translate("MainWindow", "&Transform"))
-        self.actionExportAsymptote.setText(_translate("MainWindow", "Export"))
+        self.actionExportAsymptote.setText(_translate("MainWindow", "Export as..."))
         self.actionSave.setText(_translate("MainWindow", "Save"))
         self.actionOpen.setText(_translate("MainWindow", "Open"))
+        self.actionClearRecent.setText(_translate("MainWindow", "Clear Menu"))
+        self.actionNewFile.setText(_translate("MainWindow", "New File"))
+        self.actionExportToAsy.setText(_translate("MainWindow", "Export as Asy"))
+        self.actionKeymaps.setText(_translate("MainWindow", "&Keymaps"))
 import icons_rc

Added: trunk/Master/texmf-dist/asymptote/GUI/res/icons/brush.svg
===================================================================
--- trunk/Master/texmf-dist/asymptote/GUI/res/icons/brush.svg	                        (rev 0)
+++ trunk/Master/texmf-dist/asymptote/GUI/res/icons/brush.svg	2022-02-27 23:41:11 UTC (rev 62265)
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+	 width="512px" height="512px" viewBox="0 0 512 512" enable-background="new 0 0 512 512" xml:space="preserve">
+<g>
+	<path d="M48.451,464.828c40.023-0.315,45.01-9.955,58.052-50.132c24.057-63.408,132.419,16.591,65.269,44.374
+		C104.622,486.852,8.428,465.143,48.451,464.828z"/>
+	<path d="M458.857,46.902c-19.417-15.647-51.592-7.938-71.864,17.219L181.645,355.849c-20.272,25.154-20.171,20.347-0.754,35.992
+		c19.417,15.648,14.738,16.77,35.011-8.388l241.406-262.669C477.581,95.628,478.275,62.55,458.857,46.902z M406.065,81.825
+		c0,0-3-3.5-13-11.5c15-24.5,44.5-20,44.5-20C409.565,66.825,406.065,81.825,406.065,81.825z"/>
+</g>
+</svg>

Modified: trunk/Master/texmf-dist/asymptote/GUI/res/icons/bucket.svg
===================================================================
--- trunk/Master/texmf-dist/asymptote/GUI/res/icons/bucket.svg	2022-02-27 23:39:53 UTC (rev 62264)
+++ trunk/Master/texmf-dist/asymptote/GUI/res/icons/bucket.svg	2022-02-27 23:41:11 UTC (rev 62265)
@@ -1,15 +1,15 @@
 <?xml version='1.0' encoding='UTF-8'?>
-<!-- This file was generated by dvisvgm 2.8 -->
-<svg version='1.1' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' width='63.9996pt' height='63.9997pt' viewBox='56.4094 53.8583 63.9996 63.9997'>
+<!-- This file was generated by dvisvgm 2.11.1 -->
+<svg version='1.1' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' width='63.9996pt' height='64pt' viewBox='56.4094 117.858 63.9996 64'>
 <g id='page1'>
-<g transform='matrix(0.996264 0 0 0.996264 56.4094 117.858)'>
-<path d='M 54.8926 -39.7109C 54.8926 -43.9032 44.6969 -47.3017 32.12 -47.3017C 19.5431 -47.3017 9.34742 -43.9032 9.34742 -39.7109C 9.34742 -35.5185 19.5431 -32.12 32.12 -32.12C 44.6969 -32.12 54.8926 -35.5185 54.8926 -39.7109Z' fill='none' stroke='#000000' stroke-linecap='round' stroke-linejoin='round' stroke-miterlimit='10.0375' stroke-width='3.51312'/>
+<g transform='translate(56.4094 117.858)scale(.996264)'>
+<path d='M 54.8926 24.5291C 54.8926 20.3368 44.6969 16.9383 32.12 16.9383C 19.5431 16.9383 9.34742 20.3368 9.34742 24.5291C 9.34742 28.7215 19.5431 32.12 32.12 32.12C 44.6969 32.12 54.8926 28.7215 54.8926 24.5291Z' fill='none' stroke='#000000' stroke-linecap='round' stroke-linejoin='round' stroke-miterlimit='10.0375' stroke-width='3.51312'/>
 </g>
-<g transform='matrix(0.996264 0 0 0.996264 56.4094 117.858)'>
-<path d='M 9.34742 -39.7109L 9.34742 -9.34742L 9.34742 -9.34742C 9.34742 -9.34742 9.34742 -9.34742 9.34742 -9.34742C 9.34742 -5.15511 19.5431 -1.75656 32.12 -1.75656C 44.6969 -1.75656 54.8926 -5.15511 54.8926 -9.34742L 54.8926 -9.34742L 54.8926 -39.7109' fill='none' stroke='#000000' stroke-linecap='round' stroke-linejoin='round' stroke-miterlimit='10.0375' stroke-width='3.51312'/>
+<g transform='translate(56.4094 117.858)scale(.996264)'>
+<path d='M 9.34742 24.5291L 9.34742 54.8926L 9.34742 54.8926C 9.34742 54.8926 9.34742 54.8926 9.34742 54.8926C 9.34742 59.0849 19.5431 62.4834 32.12 62.4834C 44.6969 62.4834 54.8926 59.0849 54.8926 54.8926L 54.8926 54.8926L 54.8926 24.5291' fill='none' stroke='#000000' stroke-linecap='round' stroke-linejoin='round' stroke-miterlimit='10.0375' stroke-width='3.51312'/>
 </g>
-<g transform='matrix(0.996264 0 0 0.996264 56.4094 117.858)'>
-<path d='M 54.8926 -39.7109C 54.8926 -52.2878 44.6969 -62.4834 32.12 -62.4834C 19.5431 -62.4834 9.34742 -52.2878 9.34742 -39.7109' fill='none' stroke='#000000' stroke-linecap='round' stroke-linejoin='round' stroke-miterlimit='10.0375' stroke-width='3.51312'/>
+<g transform='translate(56.4094 117.858)scale(.996264)'>
+<path d='M 54.8926 24.5291C 54.8926 11.9522 44.6969 1.75656 32.12 1.75656C 19.5431 1.75656 9.34742 11.9522 9.34742 24.5291' fill='none' stroke='#000000' stroke-linecap='round' stroke-linejoin='round' stroke-miterlimit='10.0375' stroke-width='3.51312'/>
 </g>
 </g>
 </svg>
\ No newline at end of file

Modified: trunk/Master/texmf-dist/asymptote/GUI/res/icons/center.svg
===================================================================
--- trunk/Master/texmf-dist/asymptote/GUI/res/icons/center.svg	2022-02-27 23:39:53 UTC (rev 62264)
+++ trunk/Master/texmf-dist/asymptote/GUI/res/icons/center.svg	2022-02-27 23:41:11 UTC (rev 62265)
@@ -1,12 +1,12 @@
 <?xml version='1.0' encoding='UTF-8'?>
-<!-- This file was generated by dvisvgm 2.8 -->
-<svg version='1.1' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' width='63.9996pt' height='63.9997pt' viewBox='56.4094 53.8583 63.9996 63.9997'>
+<!-- This file was generated by dvisvgm 2.11.1 -->
+<svg version='1.1' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' width='63.9996pt' height='64pt' viewBox='56.4094 117.858 63.9996 64'>
 <g id='page1'>
-<g transform='matrix(0.996264 0 0 0.996264 56.4094 117.858)'>
-<path d='M 2.0075 -2.0075L 62.2325 -2.0075L 62.2325 -62.2325L 2.0075 -62.2325L 2.0075 -2.0075Z' fill='none' stroke='#000000' stroke-linecap='round' stroke-linejoin='round' stroke-miterlimit='10.0375' stroke-width='4.015'/>
+<g transform='translate(56.4094 117.858)scale(.996264)'>
+<path d='M 2.0075 62.2325L 62.2325 62.2325L 62.2325 2.0075L 2.0075 2.0075L 2.0075 62.2325Z' fill='none' stroke='#000000' stroke-linecap='round' stroke-linejoin='round' stroke-miterlimit='10.0375' stroke-width='4.015'/>
 </g>
-<g transform='matrix(0.996264 0 0 0.996264 56.4094 117.858)'>
-<path d='M 47.1762 -32.12C 47.1762 -40.4353 40.4353 -47.1762 32.12 -47.1762C 23.8047 -47.1762 17.0637 -40.4353 17.0637 -32.12C 17.0637 -23.8047 23.8047 -17.0637 32.12 -17.0637C 40.4353 -17.0637 47.1762 -23.8047 47.1762 -32.12Z' fill='#000000'/>
+<g transform='translate(56.4094 117.858)scale(.996264)'>
+<path d='M 47.1762 32.12C 47.1762 23.8047 40.4353 17.0637 32.12 17.0637C 23.8047 17.0637 17.0637 23.8047 17.0637 32.12C 17.0637 40.4353 23.8047 47.1762 32.12 47.1762C 40.4353 47.1762 47.1762 40.4353 47.1762 32.12Z' fill='#000000'/>
 </g>
 </g>
 </svg>
\ No newline at end of file

Modified: trunk/Master/texmf-dist/asymptote/GUI/res/icons/centerorigin.svg
===================================================================
--- trunk/Master/texmf-dist/asymptote/GUI/res/icons/centerorigin.svg	2022-02-27 23:39:53 UTC (rev 62264)
+++ trunk/Master/texmf-dist/asymptote/GUI/res/icons/centerorigin.svg	2022-02-27 23:41:11 UTC (rev 62265)
@@ -1,15 +1,15 @@
 <?xml version='1.0' encoding='UTF-8'?>
-<!-- This file was generated by dvisvgm 2.8 -->
-<svg version='1.1' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' width='63.9996pt' height='63.9997pt' viewBox='56.4094 53.8583 63.9996 63.9997'>
+<!-- This file was generated by dvisvgm 2.11.1 -->
+<svg version='1.1' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' width='63.9996pt' height='64pt' viewBox='56.4094 117.858 63.9996 64'>
 <g id='page1'>
-<g transform='matrix(0.996264 0 0 0.996264 56.4094 117.858)'>
-<path d='M 2.0075 -2.0075L 62.2325 -2.0075L 62.2325 -62.2325L 2.0075 -62.2325L 2.0075 -2.0075Z' fill='none' stroke='#000000' stroke-linecap='round' stroke-linejoin='round' stroke-miterlimit='10.0375' stroke-width='4.015'/>
+<g transform='translate(56.4094 117.858)scale(.996264)'>
+<path d='M 2.0075 62.2325L 62.2325 62.2325L 62.2325 2.0075L 2.0075 2.0075L 2.0075 62.2325Z' fill='none' stroke='#000000' stroke-linecap='round' stroke-linejoin='round' stroke-miterlimit='10.0375' stroke-width='4.015'/>
 </g>
-<g transform='matrix(0.996264 0 0 0.996264 56.4094 117.858)'>
-<path d='M 2.0075 -32.12L 62.2325 -32.12' fill='none' stroke='#000000' stroke-linecap='round' stroke-linejoin='round' stroke-miterlimit='10.0375' stroke-width='4.015'/>
+<g transform='translate(56.4094 117.858)scale(.996264)'>
+<path d='M 2.0075 32.12L 62.2325 32.12' fill='none' stroke='#000000' stroke-linecap='round' stroke-linejoin='round' stroke-miterlimit='10.0375' stroke-width='4.015'/>
 </g>
-<g transform='matrix(0.996264 0 0 0.996264 56.4094 117.858)'>
-<path d='M 32.12 -2.0075L 32.12 -62.2325' fill='none' stroke='#000000' stroke-linecap='round' stroke-linejoin='round' stroke-miterlimit='10.0375' stroke-width='4.015'/>
+<g transform='translate(56.4094 117.858)scale(.996264)'>
+<path d='M 32.12 62.2325L 32.12 2.0075' fill='none' stroke='#000000' stroke-linecap='round' stroke-linejoin='round' stroke-miterlimit='10.0375' stroke-width='4.015'/>
 </g>
 </g>
 </svg>
\ No newline at end of file

Modified: trunk/Master/texmf-dist/asymptote/GUI/res/icons/closedcurve.svg
===================================================================
--- trunk/Master/texmf-dist/asymptote/GUI/res/icons/closedcurve.svg	2022-02-27 23:39:53 UTC (rev 62264)
+++ trunk/Master/texmf-dist/asymptote/GUI/res/icons/closedcurve.svg	2022-02-27 23:41:11 UTC (rev 62265)
@@ -1,21 +1,21 @@
 <?xml version='1.0' encoding='UTF-8'?>
-<!-- This file was generated by dvisvgm 2.8 -->
-<svg version='1.1' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' width='63.9996pt' height='63.9997pt' viewBox='56.4094 53.8583 63.9996 63.9997'>
+<!-- This file was generated by dvisvgm 2.11.1 -->
+<svg version='1.1' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' width='64.0001pt' height='64pt' viewBox='58.4669 117.858 64.0001 64'>
 <g id='page1'>
-<g transform='matrix(0.996264 0 0 0.996264 58.4669 117.858)'>
-<path d='M 3.95735 -32.12C 2.28922 -39.3113 6.36702 -46.2386 11.9036 -51.3039C 29.6687 -67.5568 55.2292 -60.642 56.1523 -42.5022C 56.6136 -33.4381 49.1132 -26.5959 40.6794 -22.5281C 25.3995 -15.1582 7.19935 -18.1436 3.95735 -32.12Z' fill='none' stroke='#000000' stroke-linecap='round' stroke-linejoin='round' stroke-miterlimit='10.0375' stroke-width='2.50937'/>
+<g transform='translate(58.4669 117.858)scale(.996264)'>
+<path d='M 6.0225 32.12C 4.35438 24.9287 8.43217 18.0014 13.9687 12.9361C 31.7339 -3.31675 57.2943 3.59797 58.2175 21.7378C 58.6788 30.8019 51.1783 37.6441 42.7445 41.7119C 27.4646 49.0818 9.26451 46.0964 6.0225 32.12Z' fill='none' stroke='#000000' stroke-linecap='round' stroke-linejoin='round' stroke-miterlimit='10.0375' stroke-width='2.50937'/>
 </g>
-<g transform='matrix(0.996264 0 0 0.996264 58.4669 117.858)'>
-<circle cx='3.95735' cy='-32.12' fill='#000000' r='6.0225'/>
+<g transform='translate(58.4669 117.858)scale(.996264)'>
+<circle cx='6.0225' cy='32.12' fill='#ff0000' r='6.0225'/>
 </g>
-<g transform='matrix(0.996264 0 0 0.996264 58.4669 117.858)'>
-<circle cx='11.9036' cy='-51.3039' fill='#000000' r='6.0225'/>
+<g transform='translate(58.4669 117.858)scale(.996264)'>
+<circle cx='13.9687' cy='12.9361' fill='#ff0000' r='6.0225'/>
 </g>
-<g transform='matrix(0.996264 0 0 0.996264 58.4669 117.858)'>
-<circle cx='56.1523' cy='-42.5022' fill='#000000' r='6.0225'/>
+<g transform='translate(58.4669 117.858)scale(.996264)'>
+<circle cx='58.2175' cy='21.7378' fill='#ff0000' r='6.0225'/>
 </g>
-<g transform='matrix(0.996264 0 0 0.996264 58.4669 117.858)'>
-<circle cx='40.6794' cy='-22.5281' fill='#000000' r='6.0225'/>
+<g transform='translate(58.4669 117.858)scale(.996264)'>
+<circle cx='42.7445' cy='41.7119' fill='#ff0000' r='6.0225'/>
 </g>
 </g>
 </svg>
\ No newline at end of file

Modified: trunk/Master/texmf-dist/asymptote/GUI/res/icons/closedpolygon.svg
===================================================================
--- trunk/Master/texmf-dist/asymptote/GUI/res/icons/closedpolygon.svg	2022-02-27 23:39:53 UTC (rev 62264)
+++ trunk/Master/texmf-dist/asymptote/GUI/res/icons/closedpolygon.svg	2022-02-27 23:41:11 UTC (rev 62265)
@@ -1,21 +1,21 @@
 <?xml version='1.0' encoding='UTF-8'?>
-<!-- This file was generated by dvisvgm 2.8 -->
-<svg version='1.1' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' width='63.9996pt' height='63.9997pt' viewBox='56.4094 53.8583 63.9996 63.9997'>
+<!-- This file was generated by dvisvgm 2.11.1 -->
+<svg version='1.1' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' width='64.0001pt' height='64pt' viewBox='58.4669 117.858 64.0001 64'>
 <g id='page1'>
-<g transform='matrix(0.996264 0 0 0.996264 58.4669 117.858)'>
-<path d='M 3.95735 -32.12L 11.9036 -51.3039L 56.1523 -42.5022L 40.6794 -22.5281L 3.95735 -32.12Z' fill='none' stroke='#000000' stroke-linecap='round' stroke-linejoin='round' stroke-miterlimit='10.0375' stroke-width='2.50937'/>
+<g transform='translate(58.4669 117.858)scale(.996264)'>
+<path d='M 6.0225 32.12L 13.9687 12.9361L 58.2175 21.7378L 42.7445 41.7119L 6.0225 32.12Z' fill='none' stroke='#000000' stroke-linecap='round' stroke-linejoin='round' stroke-miterlimit='10.0375' stroke-width='2.50937'/>
 </g>
-<g transform='matrix(0.996264 0 0 0.996264 58.4669 117.858)'>
-<circle cx='3.95735' cy='-32.12' fill='#000000' r='6.0225'/>
+<g transform='translate(58.4669 117.858)scale(.996264)'>
+<circle cx='6.0225' cy='32.12' fill='#ff0000' r='6.0225'/>
 </g>
-<g transform='matrix(0.996264 0 0 0.996264 58.4669 117.858)'>
-<circle cx='11.9036' cy='-51.3039' fill='#000000' r='6.0225'/>
+<g transform='translate(58.4669 117.858)scale(.996264)'>
+<circle cx='13.9687' cy='12.9361' fill='#ff0000' r='6.0225'/>
 </g>
-<g transform='matrix(0.996264 0 0 0.996264 58.4669 117.858)'>
-<circle cx='56.1523' cy='-42.5022' fill='#000000' r='6.0225'/>
+<g transform='translate(58.4669 117.858)scale(.996264)'>
+<circle cx='58.2175' cy='21.7378' fill='#ff0000' r='6.0225'/>
 </g>
-<g transform='matrix(0.996264 0 0 0.996264 58.4669 117.858)'>
-<circle cx='40.6794' cy='-22.5281' fill='#000000' r='6.0225'/>
+<g transform='translate(58.4669 117.858)scale(.996264)'>
+<circle cx='42.7445' cy='41.7119' fill='#ff0000' r='6.0225'/>
 </g>
 </g>
 </svg>
\ No newline at end of file

Modified: trunk/Master/texmf-dist/asymptote/GUI/res/icons/filledbucket.svg
===================================================================
--- trunk/Master/texmf-dist/asymptote/GUI/res/icons/filledbucket.svg	2022-02-27 23:39:53 UTC (rev 62264)
+++ trunk/Master/texmf-dist/asymptote/GUI/res/icons/filledbucket.svg	2022-02-27 23:41:11 UTC (rev 62265)
@@ -1,18 +1,18 @@
 <?xml version='1.0' encoding='UTF-8'?>
-<!-- This file was generated by dvisvgm 2.8 -->
-<svg version='1.1' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' width='63.9996pt' height='63.9997pt' viewBox='56.4094 53.8583 63.9996 63.9997'>
+<!-- This file was generated by dvisvgm 2.11.1 -->
+<svg version='1.1' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' width='63.9996pt' height='64pt' viewBox='56.4094 117.858 63.9996 64'>
 <g id='page1'>
-<g transform='matrix(0.996264 0 0 0.996264 56.4094 117.858)'>
-<path d='M 9.34742 -23.011L 9.34742 -9.34742L 9.34742 -9.34742C 9.34742 -9.34742 9.34742 -9.34742 9.34742 -9.34742C 9.34742 -5.15511 19.5431 -1.75656 32.12 -1.75656C 44.6969 -1.75656 54.8926 -5.15511 54.8926 -9.34742L 54.8926 -9.34742L 54.8926 -23.011L 54.8926 -36.6745C 54.8926 -40.8668 44.6969 -44.2654 32.12 -44.2654C 19.5431 -44.2654 9.34742 -40.8668 9.34742 -36.6745L 9.34742 -23.011Z' fill='#7f7f7f'/>
+<g transform='translate(56.4094 117.858)scale(.996264)'>
+<path d='M 9.34742 42.7472L 9.34742 54.8926L 9.34742 54.8926C 9.34742 54.8926 9.34742 54.8926 9.34742 54.8926C 9.34742 59.0849 19.5431 62.4834 32.12 62.4834C 44.6969 62.4834 54.8926 59.0849 54.8926 54.8926L 54.8926 54.8926L 54.8926 42.7472L 54.8926 30.6018C 54.8926 26.4095 44.6969 23.011 32.12 23.011C 19.5431 23.011 9.34742 26.4095 9.34742 30.6018L 9.34742 42.7472Z' fill='#bfbfff'/>
 </g>
-<g transform='matrix(0.996264 0 0 0.996264 56.4094 117.858)'>
-<path d='M 54.8926 -39.7109C 54.8926 -43.9032 44.6969 -47.3017 32.12 -47.3017C 19.5431 -47.3017 9.34742 -43.9032 9.34742 -39.7109C 9.34742 -35.5185 19.5431 -32.12 32.12 -32.12C 44.6969 -32.12 54.8926 -35.5185 54.8926 -39.7109Z' fill='none' stroke='#000000' stroke-linecap='round' stroke-linejoin='round' stroke-miterlimit='10.0375' stroke-width='3.51312'/>
+<g transform='translate(56.4094 117.858)scale(.996264)'>
+<path d='M 54.8926 24.5291C 54.8926 20.3368 44.6969 16.9383 32.12 16.9383C 19.5431 16.9383 9.34742 20.3368 9.34742 24.5291C 9.34742 28.7215 19.5431 32.12 32.12 32.12C 44.6969 32.12 54.8926 28.7215 54.8926 24.5291Z' fill='none' stroke='#000000' stroke-linecap='round' stroke-linejoin='round' stroke-miterlimit='10.0375' stroke-width='3.51312'/>
 </g>
-<g transform='matrix(0.996264 0 0 0.996264 56.4094 117.858)'>
-<path d='M 9.34742 -39.7109L 9.34742 -9.34742L 9.34742 -9.34742C 9.34742 -9.34742 9.34742 -9.34742 9.34742 -9.34742C 9.34742 -5.15511 19.5431 -1.75656 32.12 -1.75656C 44.6969 -1.75656 54.8926 -5.15511 54.8926 -9.34742L 54.8926 -9.34742L 54.8926 -39.7109' fill='none' stroke='#000000' stroke-linecap='round' stroke-linejoin='round' stroke-miterlimit='10.0375' stroke-width='3.51312'/>
+<g transform='translate(56.4094 117.858)scale(.996264)'>
+<path d='M 9.34742 24.5291L 9.34742 54.8926L 9.34742 54.8926C 9.34742 54.8926 9.34742 54.8926 9.34742 54.8926C 9.34742 59.0849 19.5431 62.4834 32.12 62.4834C 44.6969 62.4834 54.8926 59.0849 54.8926 54.8926L 54.8926 54.8926L 54.8926 24.5291' fill='none' stroke='#000000' stroke-linecap='round' stroke-linejoin='round' stroke-miterlimit='10.0375' stroke-width='3.51312'/>
 </g>
-<g transform='matrix(0.996264 0 0 0.996264 56.4094 117.858)'>
-<path d='M 54.8926 -39.7109C 54.8926 -52.2878 44.6969 -62.4834 32.12 -62.4834C 19.5431 -62.4834 9.34742 -52.2878 9.34742 -39.7109' fill='none' stroke='#000000' stroke-linecap='round' stroke-linejoin='round' stroke-miterlimit='10.0375' stroke-width='3.51312'/>
+<g transform='translate(56.4094 117.858)scale(.996264)'>
+<path d='M 54.8926 24.5291C 54.8926 11.9522 44.6969 1.75656 32.12 1.75656C 19.5431 1.75656 9.34742 11.9522 9.34742 24.5291' fill='none' stroke='#000000' stroke-linecap='round' stroke-linejoin='round' stroke-miterlimit='10.0375' stroke-width='3.51312'/>
 </g>
 </g>
 </svg>
\ No newline at end of file

Modified: trunk/Master/texmf-dist/asymptote/GUI/res/icons/opencurve.svg
===================================================================
--- trunk/Master/texmf-dist/asymptote/GUI/res/icons/opencurve.svg	2022-02-27 23:39:53 UTC (rev 62264)
+++ trunk/Master/texmf-dist/asymptote/GUI/res/icons/opencurve.svg	2022-02-27 23:41:11 UTC (rev 62265)
@@ -1,21 +1,21 @@
 <?xml version='1.0' encoding='UTF-8'?>
-<!-- This file was generated by dvisvgm 2.8 -->
-<svg version='1.1' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' width='63.9996pt' height='63.9997pt' viewBox='56.4094 53.8583 63.9996 63.9997'>
+<!-- This file was generated by dvisvgm 2.11.1 -->
+<svg version='1.1' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' width='64.0001pt' height='64pt' viewBox='58.4669 117.858 64.0001 64'>
 <g id='page1'>
-<g transform='matrix(0.996264 0 0 0.996264 58.4669 117.858)'>
-<path d='M 3.95735 -32.12C 4.15556 -39.2745 6.98473 -46.1047 11.9036 -51.3039C 27.4411 -67.7269 53.3021 -61.5405 56.1523 -42.5022C 57.627 -32.6519 50.5856 -23.5621 40.6794 -22.5281' fill='none' stroke='#000000' stroke-linecap='round' stroke-linejoin='round' stroke-miterlimit='10.0375' stroke-width='2.50937'/>
+<g transform='translate(58.4669 117.858)scale(.996264)'>
+<path d='M 6.0225 32.12C 6.22072 24.9655 9.04989 18.1353 13.9687 12.9361C 29.5062 -3.48686 55.3673 2.6995 58.2175 21.7378C 59.6922 31.5881 52.6508 40.6779 42.7445 41.7119' fill='none' stroke='#000000' stroke-linecap='round' stroke-linejoin='round' stroke-miterlimit='10.0375' stroke-width='2.50937'/>
 </g>
-<g transform='matrix(0.996264 0 0 0.996264 58.4669 117.858)'>
-<circle cx='3.95735' cy='-32.12' fill='#000000' r='6.0225'/>
+<g transform='translate(58.4669 117.858)scale(.996264)'>
+<circle cx='6.0225' cy='32.12' fill='#ff0000' r='6.0225'/>
 </g>
-<g transform='matrix(0.996264 0 0 0.996264 58.4669 117.858)'>
-<circle cx='11.9036' cy='-51.3039' fill='#000000' r='6.0225'/>
+<g transform='translate(58.4669 117.858)scale(.996264)'>
+<circle cx='13.9687' cy='12.9361' fill='#ff0000' r='6.0225'/>
 </g>
-<g transform='matrix(0.996264 0 0 0.996264 58.4669 117.858)'>
-<circle cx='56.1523' cy='-42.5022' fill='#000000' r='6.0225'/>
+<g transform='translate(58.4669 117.858)scale(.996264)'>
+<circle cx='58.2175' cy='21.7378' fill='#ff0000' r='6.0225'/>
 </g>
-<g transform='matrix(0.996264 0 0 0.996264 58.4669 117.858)'>
-<circle cx='40.6794' cy='-22.5281' fill='#000000' r='6.0225'/>
+<g transform='translate(58.4669 117.858)scale(.996264)'>
+<circle cx='42.7445' cy='41.7119' fill='#ff0000' r='6.0225'/>
 </g>
 </g>
 </svg>
\ No newline at end of file

Modified: trunk/Master/texmf-dist/asymptote/GUI/res/icons/openpolygon.svg
===================================================================
--- trunk/Master/texmf-dist/asymptote/GUI/res/icons/openpolygon.svg	2022-02-27 23:39:53 UTC (rev 62264)
+++ trunk/Master/texmf-dist/asymptote/GUI/res/icons/openpolygon.svg	2022-02-27 23:41:11 UTC (rev 62265)
@@ -1,21 +1,21 @@
 <?xml version='1.0' encoding='UTF-8'?>
-<!-- This file was generated by dvisvgm 2.8 -->
-<svg version='1.1' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' width='63.9996pt' height='63.9997pt' viewBox='56.4094 53.8583 63.9996 63.9997'>
+<!-- This file was generated by dvisvgm 2.11.1 -->
+<svg version='1.1' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' width='64.0001pt' height='64pt' viewBox='58.4669 117.858 64.0001 64'>
 <g id='page1'>
-<g transform='matrix(0.996264 0 0 0.996264 58.4669 117.858)'>
-<path d='M 3.95735 -32.12L 11.9036 -51.3039L 56.1523 -42.5022L 40.6794 -22.5281' fill='none' stroke='#000000' stroke-linecap='round' stroke-linejoin='round' stroke-miterlimit='10.0375' stroke-width='2.50937'/>
+<g transform='translate(58.4669 117.858)scale(.996264)'>
+<path d='M 6.0225 32.12L 13.9687 12.9361L 58.2175 21.7378L 42.7445 41.7119' fill='none' stroke='#000000' stroke-linecap='round' stroke-linejoin='round' stroke-miterlimit='10.0375' stroke-width='2.50937'/>
 </g>
-<g transform='matrix(0.996264 0 0 0.996264 58.4669 117.858)'>
-<circle cx='3.95735' cy='-32.12' fill='#000000' r='6.0225'/>
+<g transform='translate(58.4669 117.858)scale(.996264)'>
+<circle cx='6.0225' cy='32.12' fill='#ff0000' r='6.0225'/>
 </g>
-<g transform='matrix(0.996264 0 0 0.996264 58.4669 117.858)'>
-<circle cx='11.9036' cy='-51.3039' fill='#000000' r='6.0225'/>
+<g transform='translate(58.4669 117.858)scale(.996264)'>
+<circle cx='13.9687' cy='12.9361' fill='#ff0000' r='6.0225'/>
 </g>
-<g transform='matrix(0.996264 0 0 0.996264 58.4669 117.858)'>
-<circle cx='56.1523' cy='-42.5022' fill='#000000' r='6.0225'/>
+<g transform='translate(58.4669 117.858)scale(.996264)'>
+<circle cx='58.2175' cy='21.7378' fill='#ff0000' r='6.0225'/>
 </g>
-<g transform='matrix(0.996264 0 0 0.996264 58.4669 117.858)'>
-<circle cx='40.6794' cy='-22.5281' fill='#000000' r='6.0225'/>
+<g transform='translate(58.4669 117.858)scale(.996264)'>
+<circle cx='42.7445' cy='41.7119' fill='#ff0000' r='6.0225'/>
 </g>
 </g>
 </svg>
\ No newline at end of file

Added: trunk/Master/texmf-dist/asymptote/GUI/res/icons/redo.svg
===================================================================
--- trunk/Master/texmf-dist/asymptote/GUI/res/icons/redo.svg	                        (rev 0)
+++ trunk/Master/texmf-dist/asymptote/GUI/res/icons/redo.svg	2022-02-27 23:41:11 UTC (rev 62265)
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
+<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+	 viewBox="0 0 423.754 423.754" style="enable-background:new 0 0 423.754 423.754;" xml:space="preserve">
+<path d="M407.516,123.239l-27.717,11.48c18.585,44.869,18.585,94.291,0,139.159c-18.585,44.869-53.531,79.815-98.4,98.4
+	c-22.438,9.293-46.004,13.94-69.579,13.939c-23.569-0.001-47.147-4.647-69.579-13.939c-44.869-18.585-79.815-53.531-98.4-98.4
+	C13.507,200.647,34.758,118.71,90.758,68.644l60.801,60.801V7.521H29.635L69.514,47.4C5.222,105.826-18.985,200.6,16.123,285.359
+	c21.652,52.272,62.364,92.984,114.636,114.636c26.137,10.826,53.599,16.239,81.061,16.239s54.924-5.413,81.06-16.239
+	c52.272-21.652,92.984-62.364,114.637-114.636C429.167,233.087,429.167,175.511,407.516,123.239z"/>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+</svg>

Added: trunk/Master/texmf-dist/asymptote/GUI/res/icons/undo.svg
===================================================================
--- trunk/Master/texmf-dist/asymptote/GUI/res/icons/undo.svg	                        (rev 0)
+++ trunk/Master/texmf-dist/asymptote/GUI/res/icons/undo.svg	2022-02-27 23:41:11 UTC (rev 62265)
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
+<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+	 viewBox="0 0 423.754 423.754" style="enable-background:new 0 0 423.754 423.754;" xml:space="preserve">
+<path d="M354.24,47.4l39.879-39.879H272.196v121.924l60.801-60.801c56,50.066,77.251,132.004,46.918,205.235
+	c-18.585,44.869-53.531,79.815-98.4,98.4c-44.866,18.585-94.288,18.585-139.158,0c-44.869-18.585-79.815-53.531-98.4-98.4
+	c-18.585-44.869-18.585-94.29,0-139.159l-27.717-11.48c-21.651,52.272-21.651,109.848,0,162.12
+	c21.652,52.272,62.364,92.984,114.637,114.636c26.14,10.827,53.595,16.24,81.06,16.239c27.459-0.001,54.927-5.414,81.061-16.239
+	c52.271-21.652,92.983-62.364,114.636-114.636C442.739,200.6,418.532,105.826,354.24,47.4z"/>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+</svg>

Modified: trunk/Master/texmf-dist/asymptote/GUI/res/icons.qrc
===================================================================
--- trunk/Master/texmf-dist/asymptote/GUI/res/icons.qrc	2022-02-27 23:39:53 UTC (rev 62264)
+++ trunk/Master/texmf-dist/asymptote/GUI/res/icons.qrc	2022-02-27 23:41:11 UTC (rev 62265)
@@ -41,5 +41,8 @@
     <file>icons/android-radio-button-off.svg</file>
     <file>icons/android-locate.svg</file>
     <file>icons/close-round.svg</file>
+    <file>icons/brush.svg</file>
+    <file>icons/undo.svg</file>
+    <file>icons/redo.svg</file>
   </qresource>
 </RCC>

Modified: trunk/Master/texmf-dist/asymptote/GUI/setup.py
===================================================================
--- trunk/Master/texmf-dist/asymptote/GUI/setup.py	2022-02-27 23:39:53 UTC (rev 62264)
+++ trunk/Master/texmf-dist/asymptote/GUI/setup.py	2022-02-27 23:41:11 UTC (rev 62265)
@@ -7,7 +7,7 @@
     name="xasy",
     version=xasyVersion.xasyVersion,
     author="Supakorn Rassameemasmuang, Orest Shardt, and John C. Bowman",
-    description="User interface for Asymptote, a vector graphics language", 
+    description="User interface for Asymptote, a vector graphics language",
     url="https://asymptote.sourceforge.io",
     download_url="https://sourceforge.net/projects/asymptote/"
 )

Modified: trunk/Master/texmf-dist/asymptote/GUI/xasy.py
===================================================================
--- trunk/Master/texmf-dist/asymptote/GUI/xasy.py	2022-02-27 23:39:53 UTC (rev 62264)
+++ trunk/Master/texmf-dist/asymptote/GUI/xasy.py	2022-02-27 23:41:11 UTC (rev 62265)
@@ -1,14 +1,15 @@
 #!/usr/bin/env python3
 
-import sys,signal,os
-import PyQt5.QtWidgets as Qw
-import PyQt5.QtCore as Qc
+import sys, signal, os
+import PyQt5.QtWidgets as QtWidgets
+import PyQt5.QtCore as QtCore
 from Window1 import MainWindow1
 
 def main(args):
-    Qw.QApplication.setAttribute(Qc.Qt.AA_UseHighDpiPixmaps,True)
-    Qw.QApplication.setAttribute(Qc.Qt.AA_EnableHighDpiScaling,True)
-    qtApp = Qw.QApplication(args)
+    os.environ["QT_LOGGING_RULES"]="*.debug=false;qt.qpa.*=false"
+    QtWidgets.QApplication.setAttribute(QtCore.Qt.AA_UseHighDpiPixmaps,True)
+    QtWidgets.QApplication.setAttribute(QtCore.Qt.AA_EnableHighDpiScaling,True)
+    qtApp = QtWidgets.QApplication(args)
     signal.signal(signal.SIGINT,signal.SIG_DFL)
     mainWin1 = MainWindow1()
     mainWin1.show()

Modified: trunk/Master/texmf-dist/asymptote/GUI/xasy2asy.py
===================================================================
--- trunk/Master/texmf-dist/asymptote/GUI/xasy2asy.py	2022-02-27 23:39:53 UTC (rev 62264)
+++ trunk/Master/texmf-dist/asymptote/GUI/xasy2asy.py	2022-02-27 23:41:11 UTC (rev 62265)
@@ -9,12 +9,12 @@
 #
 ###########################################################################
 
-import PyQt5.QtWidgets as Qw
-import PyQt5.QtGui as Qg
-import PyQt5.QtCore as Qc
-import PyQt5.QtSvg as Qs
+import PyQt5.QtWidgets as QtWidgets
+import PyQt5.QtGui as QtGui
+import PyQt5.QtCore as QtCore
+import PyQt5.QtSvg as QtSvg
 
-import numpy as np
+import numpy as numpy
 
 import sys
 import os
@@ -37,8 +37,39 @@
 import xasySvg as xs
 
 class AsymptoteEngine:
-    xasy=chr(4)+"\n"
+    """
+    Purpose:
+    --------
+        Class that makes it possible for xasy to communicate with asy
+    through a background pipe. It communicates with asy through a
+    subprocess of an existing xasy process.
 
+    Attributes:
+    -----------
+        istream     : input stream
+        ostream     : output stream
+        keepFiles   : keep communicated files
+        tmpdir      : temporary directory
+        args        : system call arguments to start a required subprocess
+        asyPath     : directory path to asymptote
+        asyProcess  : the subprocess through which xasy communicates with asy
+
+    Virtual Methods: NULL
+    ----------------
+    Static Methods:
+    ---------------  NULL
+    Class Methods:
+    --------------   NULL
+
+    Object Methods:
+    ---------------
+        start()
+        wait()
+        stop()
+        cleanup()
+    """
+
+    xasy=chr(4)+'\n'
     def __init__(self, path=None, keepFiles=DebugFlags.keepFiles, keepDefaultArgs=True):
         if path is None:
             path = xa.getArgs().asypath
@@ -59,7 +90,7 @@
             os.set_inheritable(wa, True)
             self.ostream = os.fdopen(wx, 'w')
             self.istream = os.fdopen(ra, 'r')
-            
+
         self.keepFiles = keepFiles
         if sys.platform[:3] == 'win':
             self.tmpdir = tempfile.mkdtemp(prefix='xasyData_',dir='./')+'/'
@@ -66,12 +97,22 @@
         else:
             self.tmpdir = tempfile.mkdtemp(prefix='xasyData_')+os.sep
 
-        self.args=['-xasy', '-noV', '-q', '-inpipe=' + str(rx), '-outpipe=' + str(wa), '-o', self.tmpdir]
+        if xa.getArgs().render:
+            renderDensity=xa.getArgs().render
+        else:
+            try:
+                renderDensity = xo.BasicConfigs.defaultOpt['renderDensity']
+            except:
+                renderDensity = 2
+        renderDensity=max(renderDensity,1)
 
+        self.args=['-xasy', '-noV', '-q', '-outformat=', '-inpipe=' + str(rx), '-outpipe=' + str(wa), '-render='+str(renderDensity), '-o', self.tmpdir]
+
         self.asyPath = path
         self.asyProcess = None
 
     def start(self):
+        """ starts a subprocess (opens a pipe) """
         try:
             if sys.platform[:3] == 'win':
                 self.asyProcess = subprocess.Popen([self.asyPath] + self.args,
@@ -85,6 +126,7 @@
             atexit.register(self.cleanup)
 
     def wait(self):
+        """ wait for the pipe to finish any outstanding communication """
         if self.asyProcess.returncode is not None:
             return
         else:
@@ -114,10 +156,12 @@
         return self.asyProcess.returncode is None
 
     def stop(self):
+        """ kill an active asyProcess and close the pipe """
         if self.active:
             self.asyProcess.kill()
 
     def cleanup(self):
+        """ terminate processes and cleans up communication files """
         self.stop()
         if self.asyProcess is not None:
             self.asyProcess.wait()
@@ -125,11 +169,46 @@
             if os.path.isdir(self.tempDirName + os.sep):
                 shutil.rmtree(self.tempDirName, ignore_errors=True)
 
-class asyTransform(Qc.QObject):
-    """A python implementation of an asy transform"""
+class asyTransform(QtCore.QObject):
+    """
+    Purpose:
+    --------
+        A python implementation of an asy transform. This class takes care of calibrating asymptote
+        coordinate system with the one used in PyQt to handle all existing inconsistencies.
+        To understand how this class works, having enough acquaintance with asymptote transform
+        feature is required. It is a child class of QtCore.QObject class.
 
+    Attributes:
+    -----------
+        t                       : The tuple
+        x, y, xx, xy, yx, yy    : Coordinates corresponding to 6 entries
+        _deleted                : Private local flag
+
+    Virtual Methods:      NULL
+    ----------------
+    Static Methods:       NULL
+    ---------------
+
+    Class Methods:
+    --------------
+        zero            : Class method that returns an asyTransform object initialized with 6 zero entries
+        fromQTransform  : Class method that converts QTransform object to asyTransform object
+        fromNumpyMatrix : Class method that converts transform matrix object to asyTransform object
+
+    Object Methods:
+    --------------
+        getRawCode      : Returns the tuple entries
+        getCode         : Returns the textual format of the asy code corresponding to the given transform
+        scale           : Returns the scales version of the existing asyTransform
+        toQTransform    : Converts asy transform object to QTransform object
+        identity        : Return Identity asyTransform object
+        isIdentity      : Check whether the asyTransform object is identity object
+        inverted        : Applies the QTransform object's inverted method on the asyTransform object
+        yflip           : Returns y-flipped asyTransform object
+    """
+
     def __init__(self, initTuple, delete=False):
-        """Initialize the transform with a 6 entry tuple"""
+        """ Initialize the transform with a 6 entry tuple """
         super().__init__()
         if isinstance(initTuple, (tuple, list)) and len(initTuple) == 6:
             self.t = initTuple
@@ -151,7 +230,7 @@
         return asyTransform((0, 0, 0, 0, 0, 0))
 
     @classmethod
-    def fromQTransform(cls, transform: Qg.QTransform):
+    def fromQTransform(cls, transform: QtGui.QTransform):
         tx, ty = transform.dx(), transform.dy()
         xx, xy, yx, yy = transform.m11(), transform.m21(), transform.m12(), transform.m22()
 
@@ -158,7 +237,7 @@
         return asyTransform((tx, ty, xx, xy, yx, yy))
 
     @classmethod
-    def fromNumpyMatrix(cls, transform: np.ndarray):
+    def fromNumpyMatrix(cls, transform: numpy.ndarray):
         assert transform.shape == (3, 3)
 
         tx = transform[0, 2]
@@ -171,8 +250,8 @@
     def getRawCode(self):
         return xu.tuple2StrWOspaces(self.t)
 
-    def getCode(self, asy2psmap=None):
-        """Obtain the asy code that represents this transform"""
+    def getCode(self, asy2psmap = None):
+        """ Obtain the asy code that represents this transform """
         if asy2psmap is None:
             asy2psmap = asyTransform((0, 0, 1, 0, 0, 1))
         if self.deleted:
@@ -184,10 +263,10 @@
         return asyTransform((0, 0, s, 0, 0, s)) * self
 
     def toQTransform(self):
-        return Qg.QTransform(self.xx, self.yx, self.xy, self.yy, self.x, self.y)
+        return QtGui.QTransform(self.xx, self.yx, self.xy, self.yy, self.x, self.y)
 
     def __str__(self):
-        """Equivalent functionality to getCode(). It allows the expression str(asyTransform) to be meaningful."""
+        """ Equivalent functionality to getCode(). It allows the expression str(asyTransform) to be meaningful """
         return self.getCode()
 
     def isIdentity(self):
@@ -200,7 +279,7 @@
         return list(self.t) == list(other.t)
 
     def __mul__(self, other):
-        """Define multiplication of transforms as composition."""
+        """ Define multiplication of transforms as composition """
         if isinstance(other, tuple):
             if len(other) == 6:
                 return self * asyTransform(other)
@@ -234,25 +313,88 @@
 def yflip():
     return asyTransform((0, 0, 1, 0, 0, -1))
 
-class asyObj(Qc.QObject):
-    """A base class for asy objects: an item represented by asymptote code."""
+class asyObj(QtCore.QObject):
+    """
+    Purpose:
+    --------
+        A base class to create a Python object which contains all common
+    data and behaviors required during the translation of an xasy
+    object to its Asymptote code.
+
+    Attributes:
+    -----------
+        asyCode         :The corresponding Asymptote code for the asyObj instance
+
+    Virtual Methods:
+    ----------------
+        updateCode      :Must to be re-implemented
+
+    Static Methods:      NULL
+     --------------
+    Class Methods:       NULL
+    --------------
+
+    Object Methods:
+    ---------------
+        getCode         :Return the Asymptote code that corresponds to the passed object
+
+    """
+
     def __init__(self):
-        """Initialize the object"""
+        """ Initialize the object """
         super().__init__()
         self.asyCode = ''
 
-    def updateCode(self, ps2asymap=identity()):
-        """Update the object's code: should be overriden."""
+    def updateCode(self, ps2asymap = identity()):
+        """ Update the object's code: should be overridden """
         raise NotImplementedError
 
-    def getCode(self, ps2asymap=identity()):
-        """Return the code describing the object"""
+    def getCode(self, ps2asymap = identity()):
+        """ Return the code describing the object """
         self.updateCode(ps2asymap)
         return self.asyCode
 
 
 class asyPen(asyObj):
-    """A python wrapper for an asymptote pen"""
+    """
+    Purpose:
+    --------
+        A Python object that corresponds to an Asymptote pen type. It
+    extends the 'asyObj' class to include a pen object. This object
+    will be used to make the corresponding Asymptote pen when
+    an xasy object gets translated to Asymptote code.
+
+    Attributes:
+    -----------
+        color               : The color of Path
+        options             : The options that can be passed to the path
+        width               : The path width
+        _asyengine          : The Asymptote engine that will be used
+        _deferAsyfy         : ?
+
+    Virtual Methods:         NULL
+    ----------------
+    Static Methods:
+    ---------------
+        getColorFromQColor  :
+        convertToQColor     :
+
+    Class Methods:
+    --------------
+        fromAsyPen          :
+
+    Object Methods:
+    ---------------
+        asyEngine           :
+        updateCode          :
+        setWidth            :
+        setColor            :
+        setColorFromQColor  :
+        computeColor        :
+        tkColor             :
+        toQPen              :
+    """
+
     @staticmethod
     def getColorFromQColor(color):
         return color.redF(), color.greenF(), color.blueF()
@@ -260,15 +402,16 @@
     @staticmethod
     def convertToQColor(color):
         r, g, b = color
-        return Qg.QColor.fromRgbF(r, g, b)
+        return QtGui.QColor.fromRgbF(r, g, b)
 
     @classmethod
     def fromAsyPen(cls, pen):
         assert isinstance(pen, cls)
-        return cls(asyengine=pen._asyengine, color=pen.color, width=pen.width, pen_options=pen.options)
+        return cls(asyengine = pen._asyengine, color = pen.color, width = pen.width,
+                   pen_options = pen.options)
 
-    def __init__(self, asyengine=None, color=(0, 0, 0), width=0.5, pen_options=""):
-        """Initialize the pen"""
+    def __init__(self, asyengine = None, color=(0, 0, 0), width = 0.5, pen_options = ""):
+        """ Initialize the pen """
         asyObj.__init__(self)
         self.color = (0, 0, 0)
         self.options = pen_options
@@ -288,8 +431,8 @@
     def asyEngine(self, value):
         self._asyengine = value
 
-    def updateCode(self, asy2psmap=identity()):
-        """Generate the pen's code"""
+    def updateCode(self, asy2psmap = identity()):
+        """ Generate the pen's code """
         if self._deferAsyfy:
             self.computeColor()
         self.asyCode = 'rgb({:g},{:g},{:g})+{:s}'.format(self.color[0], self.color[1], self.color[2], str(self.width))
@@ -297,12 +440,12 @@
             self.asyCode = self.asyCode + '+' + self.options
 
     def setWidth(self, newWidth):
-        """Set the pen's width"""
+        """ Set the pen's width """
         self.width = newWidth
         self.updateCode()
 
     def setColor(self, color):
-        """Set the pen's color"""
+        """ Set the pen's color """
         if isinstance(color, tuple) and len(color) == 3:
             self.color = color
         else:
@@ -313,13 +456,12 @@
         self.setColor(asyPen.getColorFromQColor(color))
 
     def computeColor(self):
-        """Find out the color of an arbitrary asymptote pen."""
+        """ Find out the color of an arbitrary Asymptote pen """
         assert isinstance(self.asyEngine, AsymptoteEngine)
         assert self.asyEngine.active
 
         fout = self.asyEngine.ostream
         fin = self.asyEngine.istream
-
         fout.write("pen p=" + self.getCode() + ';\n')
         fout.write("write(_outpipe,colorspace(p),newl);\n")
         fout.write("write(_outpipe,colors(p));\n")
@@ -347,15 +489,10 @@
         self.color = (r, g, b)
         self._deferAsyfy = False
 
-    def tkColor(self):
-        """Return the tk version of the pen's color"""
-        self.computeColor()
-        return '#{}'.format("".join(["{:02x}".format(min(int(256 * a), 255)) for a in self.color]))
-
     def toQPen(self):
         if self._deferAsyfy:
             self.computeColor()
-        newPen = Qg.QPen()
+        newPen = QtGui.QPen()
         newPen.setColor(asyPen.convertToQColor(self.color))
         newPen.setWidthF(self.width)
 
@@ -363,10 +500,34 @@
 
 
 class asyPath(asyObj):
-    """A python wrapper for an asymptote path"""
+    """
+    Purpose:
+    --------
+        A Python object that corresponds to an Asymptote path type. It
+    extends the 'asyObj' class to include a path object. This object
+    will be used to make the corresponding Asymptote path object when
+    an xasy object gets translated to its Asymptote code.
 
+    Attributes:
+    -----------
+
+    Virtual Methods:
+    ----------------
+
+    Static Methods:
+    ---------------
+
+    Class Methods:
+    --------------
+
+    Object Methods:
+    ---------------
+
+    """
+
+
     def __init__(self, asyengine: AsymptoteEngine=None, forceCurve=False):
-        """Initialize the path to be an empty path: a path with no nodes, control points, or links."""
+        """ Initialize the path to be an empty path: a path with no nodes, control points, or links """
         super().__init__()
         self.nodeSet = []
         self.linkSet = []
@@ -374,6 +535,7 @@
         self.controlSet = []
         self.computed = False
         self.asyengine = asyengine
+        self.fill = False
 
     @classmethod
     def fromPath(cls, oldPath):
@@ -380,6 +542,7 @@
         newObj = asyPath(None)
         newObj.nodeSet = copy.copy(oldPath.nodeSet)
         newObj.linkSet = copy.copy(oldPath.linkSet)
+        newObj.fill = copy.copy(oldPath.fill)
         newObj.controlSet = copy.deepcopy(oldPath.controlSet)
         newObj.computed = oldPath.computed
         newObj.asyengine = oldPath.asyengine
@@ -406,6 +569,7 @@
     def setInfo(self, path):
         self.nodeSet = copy.copy(path.nodeSet)
         self.linkSet = copy.copy(path.linkSet)
+        self.fill = copy.copy(path.fill)
         self.controlSet = copy.deepcopy(path.controlSet)
         self.computed = path.computed
 
@@ -417,12 +581,12 @@
     def isDrawable(self):
         return len(self.nodeSet) >= 2
 
-    def toQPainterPath(self) -> Qg.QPainterPath:
+    def toQPainterPath(self) -> QtGui.QPainterPath:
         return self.toQPainterPathCurve() if self.containsCurve else self.toQPainterPathLine()
 
     def toQPainterPathLine(self):
         baseX, baseY = self.nodeSet[0]
-        painterPath = Qg.QPainterPath(Qc.QPointF(baseX, baseY))
+        painterPath = QtGui.QPainterPath(QtCore.QPointF(baseX, baseY))
 
         for pointIndex in range(1, len(self.nodeSet)):
             node = self.nodeSet[pointIndex]
@@ -439,21 +603,21 @@
             self.computeControls()
 
         baseX, baseY = self.nodeSet[0]
-        painterPath = Qg.QPainterPath(Qc.QPointF(baseX, baseY))
+        painterPath = QtGui.QPainterPath(QtCore.QPointF(baseX, baseY))
 
         for pointIndex in range(1, len(self.nodeSet)):
             node = self.nodeSet[pointIndex]
             if self.nodeSet[pointIndex] == 'cycle':
                 node = self.nodeSet[0]
-            endPoint = Qc.QPointF(node[0], node[1])
-            ctrlPoint1 = Qc.QPointF(self.controlSet[pointIndex-1][0][0], self.controlSet[pointIndex-1][0][1])
-            ctrlPoint2 = Qc.QPointF(self.controlSet[pointIndex-1][1][0], self.controlSet[pointIndex-1][1][1])
+            endPoint = QtCore.QPointF(node[0], node[1])
+            ctrlPoint1 = QtCore.QPointF(self.controlSet[pointIndex-1][0][0], self.controlSet[pointIndex-1][0][1])
+            ctrlPoint2 = QtCore.QPointF(self.controlSet[pointIndex-1][1][0], self.controlSet[pointIndex-1][1][1])
 
             painterPath.cubicTo(ctrlPoint1, ctrlPoint2, endPoint)
         return painterPath
 
     def initFromNodeList(self, nodeSet, linkSet):
-        """Initialize the path from a set of nodes and link types, "--", "..", or "::" """
+        """ Initialize the path from a set of nodes and link types, '--', '..', or '::' """
         if len(nodeSet) > 0:
             self.nodeSet = nodeSet[:]
             self.linkSet = linkSet[:]
@@ -460,22 +624,22 @@
             self.computed = False
 
     def initFromControls(self, nodeSet, controlSet):
-        """Initialize the path from nodes and control points"""
+        """ Initialize the path from nodes and control points """
         self.controlSet = controlSet[:]
         self.nodeSet = nodeSet[:]
         self.computed = True
 
     def makeNodeStr(self, node):
-        """Represent a node as a string"""
+        """ Represent a node as a string """
         if node == 'cycle':
             return node
         else:
             # if really want to, disable this rounding
-            # shouldn't be to much of a problem since 10e-6 is quite small... 
+            # shouldn't be to much of a problem since 10e-6 is quite small...
             return '({:.6g},{:.6g})'.format(node[0], node[1])
 
     def updateCode(self, ps2asymap=identity()):
-        """Generate the code describing the path"""
+        """ Generate the code describing the path """
         # currently at postscript. Convert to asy
         asy2psmap =  ps2asymap.inverted()
         with io.StringIO() as rawAsyCode:
@@ -499,28 +663,28 @@
         return '..' in self.linkSet or self.forceCurve
 
     def getNode(self, index):
-        """Return the requested node"""
+        """ Return the requested node """
         return self.nodeSet[index]
 
     def getLink(self, index):
-        """Return the requested link"""
+        """ Return the requested link """
         return self.linkSet[index]
 
     def setNode(self, index, newNode):
-        """Set a node to a new position"""
+        """ Set a node to a new position """
         self.nodeSet[index] = newNode
 
     def moveNode(self, index, offset):
-        """Translate a node"""
+        """ Translate a node """
         if self.nodeSet[index] != "cycle":
             self.nodeSet[index] = (self.nodeSet[index][0] + offset[0], self.nodeSet[index][1] + offset[1])
 
     def setLink(self, index, ltype):
-        """Change the specified link"""
+        """ Change the specified link """
         self.linkSet[index] = ltype
 
     def addNode(self, point, ltype):
-        """Add a node to the end of a path"""
+        """ Add a node to the end of a path """
         self.nodeSet.append(point)
         if len(self.nodeSet) != 1:
             self.linkSet.append(ltype)
@@ -528,7 +692,7 @@
             self.computeControls()
 
     def insertNode(self, index, point, ltype=".."):
-        """Insert a node, and its corresponding link, at the given index"""
+        """ Insert a node, and its corresponding link, at the given index """
         self.nodeSet.insert(index, point)
         self.linkSet.insert(index, ltype)
         if self.computed:
@@ -535,7 +699,7 @@
             self.computeControls()
 
     def setControl(self, index, position):
-        """Set a control point to a new position"""
+        """ Set a control point to a new position """
         self.controlSet[index] = position
 
     def popNode(self):
@@ -545,11 +709,11 @@
         self.linkSet.pop()
 
     def moveControl(self, index, offset):
-        """Translate a control point"""
+        """ Translate a control point """
         self.controlSet[index] = (self.controlSet[index][0] + offset[0], self.controlSet[index][1] + offset[1])
 
     def computeControls(self):
-        """Evaluate the code of the path to obtain its control points"""
+        """ Evaluate the code of the path to obtain its control points """
         # For now, if no asymptote process is given spawns a new one.
         # Only happens if asyengine is None.
         if self.asyengine is not None:
@@ -595,9 +759,33 @@
             asy.stop()
 
 class asyLabel(asyObj):
-    """A python wrapper for an asy label"""
+    """
+    Purpose:
+    --------
+        A Python object that corresponds to an asymptote label
+    type. It extends the 'asyObj' class to include a label
+    object. This object will be used to make the corresponding
+    Asymptote label object when an xasy object gets translated to its
+    asymptote code.
 
-    def __init__(self, text="", location=(0, 0), pen=None, align=None, fontSize:int=None):
+    Attributes:
+    -----------
+
+    Virtual Methods:
+    ----------------
+
+    Static Methods:
+    ---------------
+
+    Class Methods:
+    --------------
+
+    Object Methods:
+    ---------------
+
+    """
+
+    def __init__(self, text = "", location = (0, 0), pen = None, align = None, fontSize:int = None):
         """Initialize the label with the given test, location, and pen"""
         asyObj.__init__(self)
         self.align = align
@@ -610,8 +798,8 @@
         self.text = text
         self.location = location
 
-    def updateCode(self, asy2psmap=identity()):
-        """Generate the code describing the label"""
+    def updateCode(self, asy2psmap = identity()):
+        """ Generate the code describing the label """
         newLoc = asy2psmap.inverted() * self.location
         locStr = xu.tuple2StrWOspaces(newLoc)
         self.asyCode = 'Label("{0}",{1},p={2}{4},align={3})'.format(self.text, locStr, self.pen.getCode(), self.align,
@@ -624,22 +812,45 @@
             return ''
 
     def setText(self, text):
-        """Set the label's text"""
+        """ Set the label's text """
         self.text = text
         self.updateCode()
 
     def setPen(self, pen):
-        """Set the label's pen"""
+        """ Set the label's pen """
         self.pen = pen
         self.updateCode()
 
     def moveTo(self, newl):
-        """Translate the label's location"""
+        """ Translate the label's location """
         self.location = newl
 
 
 class asyImage:
-    """A structure containing an image and its format, bbox, and IDTag"""
+    """
+    Purpose:
+    --------
+        A Python object that is a container for an image coming from
+    Asymptote that is populated with the format, bounding box, and
+    IDTag, Asymptote key.
+
+    Attributes:
+    -----------
+
+    Virtual Methods:
+    ----------------
+
+    Static Methods:
+    ---------------
+
+    Class Methods:
+    --------------
+
+    Object Methods:
+    ---------------
+
+    """
+
     def __init__(self, image, format, bbox, transfKey=None, keyIndex=0):
         self.image = image
         self.format = format
@@ -648,8 +859,31 @@
         self.key = transfKey
         self.keyIndex = keyIndex
 
-class xasyItem(Qc.QObject):
-    """A base class for items in the xasy GUI"""
+class xasyItem(QtCore.QObject):
+    """
+    Purpose:
+    --------
+        A base class for any xasy object that can be drawn in PyQt. This class takes
+        care of all common behaviors available on any xasy item as well as all common
+        actions that can be done or applied to every xasy item.
+
+    Attributes:
+    -----------
+
+    Virtual Methods:
+    ----------------
+
+    Static Methods:
+    ---------------
+
+    Class Methods:
+    --------------
+
+    Object Methods:
+    ---------------
+
+    """
+
     mapString = 'xmap'
     setKeyFormatStr = string.Template('$map("{:s}",{:s});').substitute(map=mapString)
     setKeyAloneFormatStr = string.Template('$map("{:s}");').substitute(map=mapString)
@@ -656,7 +890,7 @@
     resizeComment="// Resize to initial xasy transform"
     asySize=""
     def __init__(self, canvas=None, asyengine=None):
-        """Initialize the item to an empty item"""
+        """ Initialize the item to an empty item """
         super().__init__()
         self.transfKeymap = {}              # the new keymap.
         # should be a dictionary to a list...
@@ -672,11 +906,10 @@
         self.setKeyed = True
         self.unsetKeys = set()
         self.userKeys = set()
-        self.lineOffset = 0
         self.imageHandleQueue = queue.Queue()
 
-    def updateCode(self, ps2asymap=identity()):
-        """Update the item's code: to be overriden"""
+    def updateCode(self, ps2asymap = identity()):
+        """ Update the item's code: to be overridden """
         with io.StringIO() as rawCode:
             transfCode = self.getTransformCode()
             objCode = self.getObjectCode()
@@ -683,7 +916,7 @@
 
             rawCode.write(transfCode)
             rawCode.write(objCode)
-            self.asyCode = rawCode.getvalue() 
+            self.asyCode = rawCode.getvalue()
 
         return len(transfCode.splitlines()), len(objCode.splitlines())
 
@@ -695,34 +928,32 @@
     def asyengine(self, value):
         self._asyengine = value
 
-    def getCode(self, ps2asymap=identity()):
-        """Return the code describing the item"""
+    def getCode(self, ps2asymap = identity()):
+        """ Return the code describing the item """
         self.updateCode(ps2asymap)
         return self.asyCode
 
-    def getTransformCode(self, asy2psmap=identity()):
+    def getTransformCode(self, asy2psmap = identity()):
         raise NotImplementedError
 
-    def getObjectCode(self, asy2psmap=identity()):
+    def getObjectCode(self, asy2psmap = identity()):
         raise NotImplementedError
 
     def generateDrawObjects(self):
         raise NotImplementedError
 
-    def handleImageReception(self, file, fileformat, bbox, count, key=None, localCount=0, containsClip=False):
-        """Receive an image from an asy deconstruction. It replaces the default n asyProcess."""
+    def handleImageReception(self, file, fileformat, bbox, count, key = None, localCount = 0, containsClip = False):
+        """ Receive an image from an asy deconstruction. It replaces the default n asyProcess """
         # image = Image.open(file).transpose(Image.FLIP_TOP_BOTTOM)
-        if fileformat == 'png':
-            image = Qg.QImage(file)
-        elif fileformat == 'svg':
+        if fileformat == 'svg':
             if containsClip:
                 image = xs.SvgObject(self.asyengine.tempDirName+file)
             else:
-                image = Qs.QSvgRenderer(file)
+                image = QtSvg.QSvgRenderer(file)
                 assert image.isValid()
         else:
-            raise Exception('Format not supported!')
-        self.imageList.append(asyImage(image, fileformat, bbox, transfKey=key, keyIndex=localCount))
+            raise Exception('Format {} not supported!'.format(fileformat))
+        self.imageList.append(asyImage(image, fileformat, bbox, transfKey = key, keyIndex = localCount))
         if self.onCanvas is not None:
             # self.imageList[-1].iqt = ImageTk.PhotoImage(image)
             currImage = self.imageList[-1]
@@ -733,7 +964,7 @@
             currImage.performCanvasTransform = False
 
             # handle this case if transform is not in the map yet.
-            # if deleted - set transform to 0, 0, 0, 0, 0
+            # if deleted - set transform to (0,0,0,0,0,0)
             transfExists = key in self.transfKeymap.keys()
             if transfExists:
                 transfExists = localCount <= len(self.transfKeymap[key]) - 1
@@ -745,7 +976,7 @@
             if (not transfExists) or validKey:
                 currImage.IDTag = str(file)
                 newDrawObj = DrawObject(currImage.iqt, self.onCanvas['canvas'], transform=identity(),
-                                        btmRightanchor=Qc.QPointF(bbox[0], bbox[2]), drawOrder=-1, key=key,
+                                        btmRightanchor=QtCore.QPointF(bbox[0], bbox[2]), drawOrder=-1, key=key,
                                         parentObj=self, keyIndex=localCount)
                 newDrawObj.setBoundingBoxPs(bbox)
                 newDrawObj.setParent(self)
@@ -757,7 +988,8 @@
                 else:
                     self.drawObjectsMap[key].append(newDrawObj)
         return containsClip
-    def asyfy(self, force=False):
+
+    def asyfy(self, force = False):
         if self.asyengine is None:
             return 1
         if self.asyfied and not force:
@@ -772,7 +1004,7 @@
         self.userKeys.clear()
 
         self.imageHandleQueue = queue.Queue()
-        worker = threading.Thread(target=self.asyfyThread, args=[])
+        worker = threading.Thread(target = self.asyfyThread, args = [])
         worker.start()
         item = self.imageHandleQueue.get()
         cwd=os.getcwd();
@@ -797,22 +1029,25 @@
         worker.join()
 
     def asyfyThread(self):
-        """Convert the item to a list of images by deconstructing this item's code"""
+        """
+        Convert the item to a list of images by deconstructing this item's code
+        """
         assert self.asyengine.active
 
         fout = self.asyengine.ostream
         fin = self.asyengine.istream
 
-        self.lineOffset = len(self.getTransformCode().splitlines())
+        self.maxKey=0
 
         fout.write("reset\n")
         fout.flush();
         for line in self.getCode().splitlines():
-            if DebugFlags.printDeconstTranscript:
-                print('fout:', line)
+            if DebugFlags.printAsyTranscript:
+                print(line)
             fout.write(line+"\n")
         fout.write(self.asySize)
-        fout.write("deconstruct();\n")
+
+        fout.write('deconstruct();\n')
         fout.write('write(_outpipe,yscale(-1)*currentpicture.calculateTransform(),endl);\n')
         fout.write(self.asyengine.xasy)
         fout.flush()
@@ -826,21 +1061,21 @@
             for i in range(len(imageInfos)):
                 box, key, localCount, useClip = imageInfos[i]
                 l, b, r, t = [float(a) for a in box.split()]
-                name = "_{:d}.{:s}".format(i, fileformat)
+                name = '_{:d}.{:s}'.format(1+i, fileformat)
 
                 self.imageHandleQueue.put((name, fileformat, (l, -t, r, -b), i, key, localCount, useClip))
 
         # key first, box second.
-        # if key is "Done"
+        # if key is 'Done'
         raw_text = fin.readline()
-        text = ""
+        text = ''
         if DebugFlags.printDeconstTranscript:
+            print(self.asyengine.tmpdir)
             print(raw_text.strip())
 
-        # template=AsyTempDir+"%d_%d.%s"
-        fileformat = 'svg'
+        fileformat = 'svg' # Output format
 
-        while raw_text != "Done\n" and raw_text != "Error\n":
+        while raw_text != 'Done\n' and raw_text != 'Error\n':
 #            print(raw_text)
             text = fin.readline()       # the actual bounding box.
             # print('TESTING:', text)
@@ -847,16 +1082,23 @@
             keydata = raw_text.strip().replace('KEY=', '', 1)  # key
 
             clipflag = keydata[-1] == '1'
+            deleted = keydata[-1] == '2'
             userkey = keydata[-2] == '1'
             keydata = keydata[:-3]
 
             if not userkey:
-                self.unsetKeys.add(keydata)     # the line and column to replace. 
+                self.unsetKeys.add(keydata)     # the line and column to replace.
             else:
+                if keydata.isdigit():
+                    self.maxKey=max(self.maxKey,int(keydata))
                 self.userKeys.add(keydata)
-            
+
 #                print(line, col)
 
+            if deleted:
+                raw_text = fin.readline()
+                continue
+
             if keydata not in keyCounts.keys():
                 keyCounts[keydata] = 0
 
@@ -873,23 +1115,45 @@
 
             n += 1
 
-        if raw_text != "Error\n":
-            if text == "Error\n":
-                self.imageHandleQueue.put(("ERROR", fin.readline()))
+        if raw_text != 'Error\n':
+            if text == 'Error\n':
+                self.imageHandleQueue.put(('ERROR', fin.readline()))
             else:
                 render()
 
             self.asy2psmap = asyTransform(xu.listize(fin.readline().rstrip(),float))
         else:
-            self.asy2psmap = identity()
+            self.asy2psmap = yflip()
         self.imageHandleQueue.put((None,))
         self.asyfied = True
 
 class xasyDrawnItem(xasyItem):
-    """A base class for GUI items was drawn by the user. It combines a path, a pen, and a transform."""
+    """
+    Purpose:
+    --------
+        A base class dedicated to any xasy item that is drawn on GUI. Every object of this class
+        will correspond to a particular drawn xasy item on GUI, which contains all its particular
+        data.
 
-    def __init__(self, path, engine, pen=None, transform=identity(), key=None):
-        """Initialize the item with a path, pen, and transform"""
+    Attributes:
+    -----------
+
+    Virtual Methods:
+    ----------------
+
+    Static Methods:
+    ---------------
+
+    Class Methods:
+    --------------
+
+    Object Methods:
+    ---------------
+
+    """
+
+    def __init__(self, path, engine, pen = None, transform = identity(), key = None):
+        """ Initialize the item with a path, pen, and transform """
         super().__init__(canvas=None, asyengine=engine)
         if pen is None:
             pen = asyPen()
@@ -921,7 +1185,9 @@
         raise NotImplementedError
 
     def appendPoint(self, point, link=None):
-        """Append a point to the path. If the path is cyclic, add this point before the 'cycle' node."""
+        """ Append a point to the path. If the path is cyclic, add this point before the 'cycle'
+            node
+        """
         if self.path.nodeSet[-1] == 'cycle':
             self.path.nodeSet[-1] = point
             self.path.nodeSet.append('cycle')
@@ -933,12 +1199,14 @@
             self.path.linkSet.append(link)
 
     def clearTransform(self):
-        """Reset the item's transform"""
+        """ Reset the item's transform """
         self.transform = [identity()]
         self.asyfied = False
 
     def removeLastPoint(self):
-        """Remove the last point in the path. If the path is cyclic, remove the node before the 'cycle' node."""
+        """ Remove the last point in the path. If the path is cyclic, remove the node before the 'cycle'
+            node
+        """
         if self.path.nodeSet[-1] == 'cycle':
             del self.path.nodeSet[-2]
         else:
@@ -948,7 +1216,9 @@
         self.asyfied = False
 
     def setLastPoint(self, point):
-        """Modify the last point in the path. If the path is cyclic, modify the node before the 'cycle' node."""
+        """ Modify the last point in the path. If the path is cyclic, modify the node before the 'cycle'
+            node
+        """
         if self.path.nodeSet[-1] == 'cycle':
             self.path.nodeSet[-2] = point
         else:
@@ -958,13 +1228,38 @@
 
 
 class xasyShape(xasyDrawnItem):
-    """An outlined shape drawn on the GUI"""
+    """ An outlined shape drawn on the GUI """
+    """
+    Purpose:
+    --------
+
+    Attributes:
+    -----------
+
+    Virtual Methods:
+    ----------------
+
+    Static Methods:
+    ---------------
+
+    Class Methods:
+    --------------
+
+    Object Methods:
+    ---------------
+
+    """
+
+
     def __init__(self, path, asyengine, pen=None, transform=identity()):
         """Initialize the shape with a path, pen, and transform"""
         super().__init__(path=path, engine=asyengine, pen=pen, transform=transform)
 
     def getObjectCode(self, asy2psmap=identity()):
-        return 'draw(KEY="{0}",{1},{2});'.format(self.transfKey, self.path.getCode(asy2psmap), self.pen.getCode())+'\n\n'
+        if self.path.fill:
+            return 'fill(KEY="{0}",{1},{2});'.format(self.transfKey, self.path.getCode(asy2psmap), self.pen.getCode())+'\n\n'
+        else:
+            return 'draw(KEY="{0}",{1},{2});'.format(self.transfKey, self.path.getCode(asy2psmap), self.pen.getCode())+'\n\n'
 
     def getTransformCode(self, asy2psmap=identity()):
         transf = self.transfKeymap[self.transfKey][0]
@@ -982,63 +1277,121 @@
                             key=self.transfKey)
         newObj.originalObj = self
         newObj.setParent(self)
+        newObj.fill=self.path.fill
         return [newObj]
 
     def __str__(self):
-        """Create a string describing this shape"""
+        """ Create a string describing this shape """
         return "xasyShape code:{:s}".format("\n\t".join(self.getCode().splitlines()))
 
+    def swapFill(self):
+        self.path.fill = not self.path.fill
 
+    def copy(self):
+        return type(self)(self.path,self._asyengine,self.pen)
+
+
 class xasyFilledShape(xasyShape):
-    """A filled shape drawn on the GUI"""
+    """ A filled shape drawn on the GUI """
 
-    def __init__(self, path, asyengine, pen=None, transform=identity()):
-        """Initialize this shape with a path, pen, and transform"""
+    """
+    Purpose:
+    --------
+
+    Attributes:
+    -----------
+
+    Virtual Methods:
+    ----------------
+
+    Static Methods:
+    ---------------
+
+    Class Methods:
+    --------------
+
+    Object Methods:
+    ---------------
+
+    """
+
+    def __init__(self, path, asyengine, pen = None, transform = identity()):
+        """ Initialize this shape with a path, pen, and transform """
         if path.nodeSet[-1] != 'cycle':
             raise Exception("Filled paths must be cyclic")
         super().__init__(path, asyengine, pen, transform)
+        self.path.fill=True
 
     def getObjectCode(self, asy2psmap=identity()):
-        return 'fill(KEY="{0}",{1},{2});'.format(self.transfKey, self.path.getCode(asy2psmap), self.pen.getCode())+'\n\n'
+        if self.path.fill:
+            return 'fill(KEY="{0}",{1},{2});'.format(self.transfKey, self.path.getCode(asy2psmap), self.pen.getCode())+'\n\n'
+        else:
+            return 'draw(KEY="{0}",{1},{2});'.format(self.transfKey, self.path.getCode(asy2psmap), self.pen.getCode())+'\n\n'
 
-    def generateDrawObjects(self, forceUpdate=False):
+    def generateDrawObjects(self, forceUpdate = False):
         if self.path.containsCurve:
             self.path.computeControls()
-        newObj = DrawObject(self.path.toQPainterPath(), None, drawOrder=0, transform=self.transfKeymap[self.transfKey][0],
-                            pen=self.pen, key=self.transfKey, fill=True)
+        newObj = DrawObject(self.path.toQPainterPath(), None, drawOrder = 0, transform = self.transfKeymap[self.transfKey][0],
+                            pen = self.pen, key = self.transfKey, fill = True)
         newObj.originalObj = self
         newObj.setParent(self)
+        newObj.fill=self.path.fill
         return [newObj]
 
     def __str__(self):
-        """Return a string describing this shape"""
+        """ Return a string describing this shape """
         return "xasyFilledShape code:{:s}".format("\n\t".join(self.getCode().splitlines()))
 
+    def swapFill(self):
+        self.path.fill = not self.path.fill
 
+
 class xasyText(xasyItem):
-    """Text created by the GUI"""
+    """ Text created by the GUI """
 
-    def __init__(self, text, location, asyengine, pen=None, transform=yflip(), key=None, align=None, fontsize:int=None):
-        """Initialize this item with text, a location, pen, and transform"""
-        super().__init__(asyengine=asyengine)
+    """
+    Purpose:
+    --------
+
+    Attributes:
+    -----------
+
+    Virtual Methods:
+    ----------------
+
+    Static Methods:
+    ---------------
+
+    Class Methods:
+    --------------
+
+    Object Methods:
+    ---------------
+
+    """
+
+    def __init__(self, text, location, asyengine, pen = None, transform = yflip(), key = None, align = None, fontsize:int = None):
+        """ Initialize this item with text, a location, pen, and transform """
+        super().__init__(asyengine = asyengine)
         if pen is None:
-            pen = asyPen(asyengine=asyengine)
+            pen = asyPen(asyengine = asyengine)
         if pen.asyEngine is None:
             pen.asyEngine = asyengine
-        self.label = asyLabel(text, location, pen, align, fontSize=fontsize)
+        self.label = asyLabel(text, location, pen, align, fontSize = fontsize)
         # self.transform = [transform]
         self.transfKey = key
         self.transfKeymap = {self.transfKey: [transform]}
         self.asyfied = False
         self.onCanvas = None
-    
-    def setKey(self, newKey=None):
+        self.pen = pen
+
+    def setKey(self, newKey = None):
         transform = self.transfKeymap[self.transfKey][0]
 
         self.transfKey = newKey
         self.transfKeymap = {self.transfKey: [transform]}
 
-    def getTransformCode(self, asy2psmap=yflip()):
+    def getTransformCode(self, asy2psmap = yflip()):
         transf = self.transfKeymap[self.transfKey][0]
         if transf == yflip():
             # return xasyItem.setKeyAloneFormatStr.format(self.transfKey)
@@ -1046,10 +1399,10 @@
         else:
             return xasyItem.setKeyFormatStr.format(self.transfKey, transf.getCode(asy2psmap))+"\n"
 
-    def getObjectCode(self, asy2psmap=yflip()):
+    def getObjectCode(self, asy2psmap = yflip()):
         return 'label(KEY="{0}",{1});'.format(self.transfKey, self.label.getCode(asy2psmap))+'\n'
 
-    def generateDrawObjects(self, forceUpdate=False):
+    def generateDrawObjects(self, forceUpdate = False):
         self.asyfy(forceUpdate)
         return self.drawObjects
 
@@ -1060,12 +1413,36 @@
     def __str__(self):
         return "xasyText code:{:s}".format("\n\t".join(self.getCode().splitlines()))
 
+    def copy(self):
+        return type(self)(self.label.text,self.label.location,self._asyengine)
 
+
 class xasyScript(xasyItem):
-    """A set of images create from asymptote code. It is always deconstructed."""
+    """ A set of images create from asymptote code. It is always deconstructed """
 
+    """
+    Purpose:
+    --------
+
+    Attributes:
+    -----------
+
+    Virtual Methods:
+    ----------------
+
+    Static Methods:
+    ---------------
+
+    Class Methods:
+    --------------
+
+    Object Methods:
+    ---------------
+
+    """
+
     def __init__(self, canvas, engine, script="", transforms=None, transfKeyMap=None):
-        """Initialize this script item"""
+        """ Initialize this script item """
         super().__init__(canvas, asyengine=engine)
         if transfKeyMap is not None:
             self.transfKeymap = transfKeyMap
@@ -1080,7 +1457,7 @@
         self.updatedPrefix = True
 
     def clearTransform(self):
-        """Reset the transforms for each of the deconstructed images"""
+        """ Reset the transforms for each of the deconstructed images """
         # self.transform = [identity()] * len(self.imageList)
         keyCount = {}
 
@@ -1093,14 +1470,6 @@
         for key in keyCount:
             self.transfKeymap[key] = [identity()] * keyCount[key]
 
-    def getMaxKeyCounter(self):
-        maxCounter = -1
-        for key in self.transfKeymap:
-            testNum = re.match(r'^x(\d+)$', key)
-            if testNum is not None:
-                maxCounter = max(maxCounter, int(testNum.group(1)))
-        return maxCounter + 1
-
     def getTransformCode(self, asy2psmap=identity()):
         with io.StringIO() as rawAsyCode:
             if self.transfKeymap:
@@ -1109,21 +1478,22 @@
 
                     writeval = list(reversed(val))
                     # need to map all transforms in a list if there is any non-identity
-                    # unfortunately, have to check all transformations in the list. 
-                    while not all(checktransf == identity() for checktransf in writeval) and writeval:
+                    # unfortunately, have to check all transformations in the list.
+                    while not all((checktransf == identity() and not checktransf.deleted) for checktransf in writeval) and writeval:
                         transf = writeval.pop()
                         if transf.deleted:
-                            rawAsyCode.write(xasyItem.setKeyFormatStr.format(key, transf.getCode(asy2psmap)) + '\n//')
-                        if transf == identity() and not transf.deleted:
-                            rawAsyCode.write(xasyItem.setKeyAloneFormatStr.format(key))
+                            rawAsyCode.write(xasyItem.setKeyFormatStr.format(key, transf.getCode(asy2psmap)))
                         else:
-                            rawAsyCode.write(xasyItem.setKeyFormatStr.format(key, transf.getCode(asy2psmap)))
+                            if transf == identity():
+                                rawAsyCode.write(xasyItem.setKeyAloneFormatStr.format(key))
+                            else:
+                                rawAsyCode.write(xasyItem.setKeyFormatStr.format(key, transf.getCode(asy2psmap)))
                         rawAsyCode.write('\n')
             result = rawAsyCode.getvalue()
         return result
 
     def findNonIdKeys(self):
-        return {key for key in self.transfKeymap if not all(transf == identity() for transf in self.transfKeymap[key]) }
+        return {key for key in self.transfKeymap if not all(not transf.deleted and transf == identity() for transf in self.transfKeymap[key]) }
 
     def getObjectCode(self, asy2psmap=identity()):
         numeric=r'([-+]?(?:(?:\d*\.\d+)|(?:\d+\.?)))'
@@ -1144,7 +1514,7 @@
             return self.updatedCode
 
     def setScript(self, script):
-        """Sets the content of the script item."""
+        """ Sets the content of the script item """
         self.script = script
         self.updateCode()
 
@@ -1155,7 +1525,7 @@
     def getReplacedKeysCode(self, key2replace: set=None) -> str:
         keylist = {}
         prefix = ''
-        
+
         key2replaceSet = self.unsetKeys if key2replace is None else \
                         self.unsetKeys & key2replace
 
@@ -1180,9 +1550,8 @@
 
         raw_code_lines = self.script.splitlines()
         with io.StringIO() as raw_str:
-            for i_0 in range(len(raw_code_lines)):
-                i = i_0 + self.lineOffset
-                curr_str = raw_code_lines[i_0]
+            for i in range(len(raw_code_lines)):
+                curr_str = raw_code_lines[i]
                 if i + 1 in keylist.keys():
                     # this case, we have a key.
                     with io.StringIO() as raw_line:
@@ -1205,11 +1574,13 @@
             baseCounter += 1
         return newKey
 
-    def asyfy(self, keyOnly=False):
-        """Generate the list of images described by this object and adjust the length of the transform list."""
+    def asyfy(self, keyOnly = False):
+        """ Generate the list of images described by this object and adjust the length of the
+            transform list
+        """
         super().asyfy()
 
-        # Id --> Transf --> asy-fied --> Transf
+        # Id --> Transf --> asyfied --> Transf
         # Transf should keep the original, raw transformation
         # but for all new drawn objects - assign Id as transform.
 
@@ -1246,8 +1617,8 @@
             else:
                 self.key2imagemap[im.key].append(im)
 
-            
 
+
         for key in keyCount:
             if key not in self.transfKeymap.keys():
                 self.transfKeymap[key] = [identity()] * keyCount[key]
@@ -1258,7 +1629,7 @@
                 # while len(self.transfKeymap[key]) > keyCount[key]:
                     # self.transfKeymap[key].pop()
 
-        # change of basis 
+        # change of basis
         for keylist in self.transfKeymap.values():
             for i in range(len(keylist)):
                 if keylist[i] != identity():
@@ -1272,17 +1643,41 @@
         return self.drawObjects
 
     def __str__(self):
-        """Return a string describing this script"""
+        """ Return a string describing this script """
         retVal = "xasyScript\n\tTransforms:\n"
         for xform in self.transform:
             retVal += "\t" + str(xform) + "\n"
-        retVal += "\tCode Ommitted"
+        retVal += "\tCode Omitted"
         return retVal
 
 
-class DrawObject(Qc.QObject):
-    def __init__(self, drawObject, mainCanvas=None, transform=identity(), btmRightanchor=Qc.QPointF(0, 0),
-                 drawOrder=(-1, -1), pen=None, key=None, parentObj=None, fill=False, keyIndex=0):
+class DrawObject(QtCore.QObject):
+    """
+    Purpose:
+    --------
+        The main Python class to draw an object with the help of PyQt graphical library.
+        Every instance of the class is
+
+
+    Attributes:
+    -----------
+
+    Virtual Methods:
+    ----------------
+
+    Static Methods:
+    ---------------
+
+    Class Methods:
+    --------------
+
+    Object Methods:
+    ---------------
+
+    """
+
+    def __init__(self, drawObject, mainCanvas = None, transform = identity(), btmRightanchor = QtCore.QPointF(0, 0),
+                 drawOrder = (-1, -1), pen = None, key = None, parentObj = None, fill = False, keyIndex = 0):
         super().__init__()
         self.drawObject = drawObject
         self.mainCanvas = mainCanvas
@@ -1302,8 +1697,8 @@
         self.fill = fill
 
     def getInteriorScrTransform(self, transform):
-        """Generates the transform with Interior transform applied beforehand."""
-        if isinstance(transform, Qg.QTransform):
+        """ Generates the transform with Interior transform applied beforehand """
+        if isinstance(transform, QtGui.QTransform):
             transform = asyTransform.fromQTransform(transform)
         return self.transform * transform * self.baseTransform.inverted()
 
@@ -1317,26 +1712,37 @@
 
     def setBoundingBoxPs(self, bbox):
         l, b, r, t = bbox
-        self.explicitBoundingBox = Qc.QRectF(Qc.QPointF(l, b), Qc.QPointF(r, t))
-        # self.explicitBoundingBox = Qc.QRectF(0, 0, 100, 100)
+        self.explicitBoundingBox = QtCore.QRectF(QtCore.QPointF(l, b), QtCore.QPointF(r, t))
+        # self.explicitBoundingBox = QtCore.QRectF(0, 0, 100, 100)
 
     @property
     def boundingBox(self):
         if self.explicitBoundingBox is not None:
-            testBbox = self.explicitBoundingBox
+            tempItem = self.baseTransform.toQTransform().mapRect(self.explicitBoundingBox)
+            testBbox = self.getScreenTransform().toQTransform().mapRect(tempItem)
+        elif isinstance(self.drawObject, QtGui.QPainterPath):
+            tempItem = self.baseTransform.toQTransform().map(self.drawObject)
+            testBbox = self.getScreenTransform().toQTransform().map(tempItem).boundingRect()
         else:
-            if isinstance(self.drawObject, Qg.QImage):
-                testBbox = self.drawObject.rect()
-                testBbox.moveTo(self.btmRightAnchor.toPoint())
-            elif isinstance(self.drawObject, Qg.QPainterPath):
-                testBbox = self.baseTransform.toQTransform().mapRect(self.drawObject.boundingRect())
-            else:
-                raise TypeError('drawObject is not a valid type!')
-        pointList = [self.getScreenTransform().toQTransform().map(point) for point in [
-            testBbox.topLeft(), testBbox.topRight(), testBbox.bottomLeft(), testBbox.bottomRight()
-        ]]
-        return Qg.QPolygonF(pointList).boundingRect()
+            raise TypeError('drawObject is not a valid type!')
 
+        if self.pen is not None:
+            lineWidth = self.pen.width
+            const = lineWidth/2
+            bl = QtCore.QPointF(-const, const)
+            br = QtCore.QPointF(const, const)
+            tl = QtCore.QPointF(-const, -const)
+            tr = QtCore.QPointF(const, -const)
+
+            pointList = [testBbox.topLeft(), testBbox.topRight(), testBbox.bottomLeft(), testBbox.bottomRight()
+            ]
+
+        else:
+            pointList = [testBbox.topLeft(), testBbox.topRight(), testBbox.bottomLeft(), testBbox.bottomRight()
+            ]
+
+        return QtGui.QPolygonF(pointList).boundingRect()
+
     @property
     def localBoundingBox(self):
         testBbox = self.drawObject.rect()
@@ -1345,22 +1751,25 @@
 
     def getScreenTransform(self):
         scrTransf = self.baseTransform.toQTransform().inverted()[0] * self.pTransform.toQTransform()
+        # print(asyTransform.fromQTransform(scrTransf).t)
         return asyTransform.fromQTransform(scrTransf)
 
-    def draw(self, additionalTransformation=None, applyReverse=False, canvas: Qg.QPainter=None, dpi=300):
+    def draw(self, additionalTransformation = None, applyReverse = False, canvas: QtGui.QPainter = None, dpi = 300):
         if canvas is None:
             canvas = self.mainCanvas
         if additionalTransformation is None:
-            additionalTransformation = Qg.QTransform()
-            
+            additionalTransformation = QtGui.QTransform()
+
         assert canvas.isActive()
 
         canvas.save()
         if self.pen:
-            oldPen = Qg.QPen(canvas.pen())
-            canvas.setPen(self.pen.toQPen())
+            oldPen = QtGui.QPen(canvas.pen())
+            localPen = self.pen.toQPen()
+            # localPen.setCosmetic(True)
+            canvas.setPen(localPen) #this fixes the object but not the box
         else:
-            oldPen = Qg.QPen()
+            oldPen = QtGui.QPen()
 
         if not applyReverse:
             canvas.setTransform(additionalTransformation, True)
@@ -1371,11 +1780,9 @@
 
         canvas.setTransform(self.baseTransform.toQTransform().inverted()[0], True)
 
-        if isinstance(self.drawObject, Qg.QImage):
-            canvas.drawImage(self.explicitBoundingBox, self.drawObject)
-        elif isinstance(self.drawObject, xs.SvgObject):
+        if isinstance(self.drawObject, xs.SvgObject):
             threshold = 1.44
-            
+
             if self.cachedDPI is None or self.cachedSvgImg is None \
                or dpi > self.maxDPI*threshold:
                 self.cachedDPI = dpi
@@ -1383,15 +1790,15 @@
                 self.cachedSvgImg = self.drawObject.render(dpi)
 
             canvas.drawImage(self.explicitBoundingBox, self.cachedSvgImg)
-        elif isinstance(self.drawObject, Qs.QSvgRenderer):
+        elif isinstance(self.drawObject, QtSvg.QSvgRenderer):
             self.drawObject.render(canvas, self.explicitBoundingBox)
-        elif isinstance(self.drawObject, Qg.QPainterPath):
+        elif isinstance(self.drawObject, QtGui.QPainterPath):
             path = self.baseTransform.toQTransform().map(self.drawObject)
             if self.fill:
                 if self.pen:
                     brush = self.pen.toQPen().brush()
                 else:
-                    brush = Qg.QBrush()
+                    brush = QtGui.QBrush()
                 canvas.fillPath(path, brush)
             else:
                 canvas.drawPath(path)
@@ -1400,14 +1807,14 @@
             canvas.setPen(oldPen)
         canvas.restore()
 
-    def collide(self, coords, canvasCoordinates=True):
-        # modify these values to grow/shrink the fuzz. 
+    def collide(self, coords, canvasCoordinates = True):
+        # modify these values to grow/shrink the fuzz.
         fuzzTolerance = 1
         marginGrowth = 1
         leftMargin = marginGrowth if self.boundingBox.width() < fuzzTolerance else 0
         topMargin = marginGrowth if self.boundingBox.height() < fuzzTolerance else 0
 
-        newMargin = Qc.QMarginsF(leftMargin, topMargin, leftMargin, topMargin)
+        newMargin = QtCore.QMarginsF(leftMargin, topMargin, leftMargin, topMargin)
         return self.boundingBox.marginsAdded(newMargin).contains(coords)
 
     def getID(self):

Modified: trunk/Master/texmf-dist/asymptote/GUI/xasyArgs.py
===================================================================
--- trunk/Master/texmf-dist/asymptote/GUI/xasyArgs.py	2022-02-27 23:39:53 UTC (rev 62264)
+++ trunk/Master/texmf-dist/asymptote/GUI/xasyArgs.py	2022-02-27 23:41:11 UTC (rev 62265)
@@ -1,23 +1,32 @@
 #!/usr/bin/env python3
 import argparse
 import xasyVersion
-import PyQt5.QtCore as Qc
+import PyQt5.QtCore as QtCore
 # Add arguments here.
 
 
 def parseArgs(args):
     parser = argparse.ArgumentParser(args)
-    parser.add_argument('-p', '--asypath', help='Custom Asymptote asy executable')
-    parser.add_argument('-v', '--version', help='Version number', action='version',
+    parser.add_argument('-p', '-asypath', '--asypath',
+                        help='Custom path to asy executable')
+    parser.add_argument('-v', '-version', '--version',
+                        help='Version number', action='version',
                         version='xasy v{0}'.format(xasyVersion.xasyVersion))
-    parser.add_argument('-l', '--language', help='language')
-    parser.add_argument('-x', '--mag', help='Magnification. Defaults to 1', default=1, type=float)
-
+    parser.add_argument('-l', '-language', '--language',
+                        help='language')
+    parser.add_argument('-x', '-mag', '--mag',
+                        help='Initial magnification. Defaults to 1',
+                        default=1, type=float)
+    parser.add_argument('-render', '--render',
+                        help='Number of pixels per bp in 3D rendered bitmaps',
+                        default=None, type=float)
     parser.add_argument(
-            'filename', help='Filename to load. If empty, initializes empty xasy canvas.', nargs='?', default=None)
+        'filename',
+        help='Filename to load (if omitted, initialize blank canvas)',
+        nargs='?', default=None)
 
     return parser.parse_args()
 
 
 def getArgs():
-    return parseArgs(Qc.QCoreApplication.arguments())
+    return parseArgs(QtCore.QCoreApplication.arguments())

Modified: trunk/Master/texmf-dist/asymptote/GUI/xasyBezierInterface.py
===================================================================
--- trunk/Master/texmf-dist/asymptote/GUI/xasyBezierInterface.py	2022-02-27 23:39:53 UTC (rev 62264)
+++ trunk/Master/texmf-dist/asymptote/GUI/xasyBezierInterface.py	2022-02-27 23:41:11 UTC (rev 62265)
@@ -1,16 +1,14 @@
 #!/usr/bin/env python3
 
-import xasy2asy as x2a
-import xasyUtils as xu
 
-import PyQt5.QtCore as Qc
-import PyQt5.QtGui as Qg
-import PyQt5.QtWidgets as Qw
-
+import PyQt5.QtWidgets as QtWidgets
+import PyQt5.QtCore as QtCore
+import PyQt5.QtGui as QtGui
+import xasy2asy as xasy2asy
+import xasyUtils as xasyUtils
 import Widg_editBezier as Web
 
 import InplaceAddObj
-
 import math
 
 class CurrentlySelctedType:
@@ -19,16 +17,16 @@
     ctrlPoint = 1
 
 class InteractiveBezierEditor(InplaceAddObj.InplaceObjProcess):
-    editAccepted = Qc.pyqtSignal()
-    editRejected = Qc.pyqtSignal()
+    editAccepted = QtCore.pyqtSignal()
+    editRejected = QtCore.pyqtSignal()
 
-    def __init__(self, parent: Qc.QObject, obj: x2a.xasyDrawnItem, info: dict={}):
+    def __init__(self, parent: QtCore.QObject, obj: xasy2asy.xasyDrawnItem, info: dict={}):
         super().__init__(parent)
         self.info = info
-        self.asyPathBackup = x2a.asyPath.fromPath(obj.path)
+        self.asyPathBackup = xasy2asy.asyPath.fromPath(obj.path)
         self.asyPath = obj.path
         self.curveMode = self.asyPath.containsCurve
-        assert isinstance(self.asyPath, x2a.asyPath)
+        assert isinstance(self.asyPath, xasy2asy.asyPath)
         self.transf = obj.transfKeymap[obj.transfKey][0]
         self._active = True
 
@@ -47,10 +45,20 @@
         self.inTransformMode = False
 
         self.opt = None
+        self.obj = obj
 
         self.prosectiveNodes = []
         self.prospectiveCtrlPts = []
 
+        #The magnification isn't being set. Here I'm manually setting it to be the square root of the determinant.
+        self.info['magnification'] = math.sqrt(self.transf.xx * self.transf.yy - self.transf.xy * self.transf.yx)
+        self.parent = parent
+        if isinstance(obj,xasy2asy.xasyFilledShape) or isinstance(obj,xasy2asy.xasyShape):
+            parent.ui.btnFill.setChecked(obj.path.fill)
+
+    def swapObjFill(self):
+        self.obj.swapFill() #This may end up being more in the future
+
     def setSelectionBoundaries(self):
         self.nodeSelRects = self.handleNodeSelectionBounds()
 
@@ -66,11 +74,11 @@
                 continue
 
             selEpsilon = 6/self.info['magnification']
-            newRect = Qc.QRect(0, 0, 2 * selEpsilon, 2 * selEpsilon)
+            newRect = QtCore.QRectF(0, 0, 2 * selEpsilon, 2 * selEpsilon)
             x, y = self.transf * node
             x = int(round(x))
             y = int(round(y))
-            newRect.moveCenter(Qc.QPoint(x, y))
+            newRect.moveCenter(QtCore.QPoint(x, y))
 
             nodeSelectionBoundaries.append(newRect)
 
@@ -84,8 +92,8 @@
 
             selEpsilon = 6/self.info['magnification']
 
-            newRect = Qc.QRect(0, 0, 2 * selEpsilon, 2 * selEpsilon)
-            newRectb = Qc.QRect(0, 0, 2 * selEpsilon, 2 * selEpsilon)
+            newRect = QtCore.QRectF(0, 0, 2 * selEpsilon, 2 * selEpsilon)
+            newRectb = QtCore.QRectF(0, 0, 2 * selEpsilon, 2 * selEpsilon)
 
             x, y = self.transf * nodea
             x2, y2 = self.transf * nodeb
@@ -96,18 +104,19 @@
             x2 = int(round(x2))
             y2 = int(round(y2))
 
-            newRect.moveCenter(Qc.QPoint(x, y))
-            newRectb.moveCenter(Qc.QPoint(x2, y2))
+            newRect.moveCenter(QtCore.QPoint(x, y))
+            newRectb.moveCenter(QtCore.QPoint(x2, y2))
 
             ctrlPointSelBoundaries.append((newRect, newRectb))
 
         return ctrlPointSelBoundaries
 
-    def postDrawPreview(self, canvas: Qg.QPainter):
+
+    def postDrawPreview(self, canvas: QtGui.QPainter):
         assert canvas.isActive()
 
-        dashedPen = Qg.QPen(Qc.Qt.DashLine)
-        dashedPen.setWidthF(1/self.info['magnification'])
+        dashedPen = QtGui.QPen(QtCore.Qt.DashLine)
+        dashedPen.setCosmetic(True)
         # draw the base points
         canvas.save()
         canvas.setWorldTransform(self.transf.toQTransform(), True)
@@ -123,27 +132,27 @@
 
         canvas.drawPath(self.asyPath.toQPainterPath())
 
-        nodePen = Qg.QPen(Qg.QColor('blue'))
-        nodePen.setWidthF(1/self.info['magnification'])
+        nodePen = QtGui.QPen(QtGui.QColor('blue'))
+        nodePen.setCosmetic(True)
 
-        ctlPtsPen = Qg.QPen(Qg.QColor(ctrlPtsColor))
-        ctlPtsPen.setWidthF(1/self.info['magnification'])
+        ctlPtsPen = QtGui.QPen(QtGui.QColor(ctrlPtsColor))
+        ctlPtsPen.setCosmetic(True)
 
         for index in range(len(self.asyPath.nodeSet)):
             point = self.asyPath.nodeSet[index]
-            
+
             if point != 'cycle':
-                basePoint = Qc.QPointF(point[0], point[1])
+                basePoint = QtCore.QPointF(point[0], point[1])
                 canvas.setPen(nodePen)
                 canvas.drawEllipse(basePoint, epsilonSize, epsilonSize)
             else:
                 point = self.asyPath.nodeSet[0]
-                basePoint = Qc.QPointF(point[0], point[1])
-            if self.curveMode:   
+                basePoint = QtCore.QPointF(point[0], point[1])
+            if self.curveMode:
                 if index != 0:
                     canvas.setPen(ctlPtsPen)
                     postCtrolSet = self.asyPath.controlSet[index - 1][1]
-                    postCtrlPoint = Qc.QPointF(postCtrolSet[0], postCtrolSet[1])
+                    postCtrlPoint = QtCore.QPointF(postCtrolSet[0], postCtrolSet[1])
                     canvas.drawEllipse(postCtrlPoint, epsilonSize, epsilonSize)
 
                     canvas.setPen(dashedPen)
@@ -152,7 +161,7 @@
                 if index != len(self.asyPath.nodeSet) - 1:
                     canvas.setPen(ctlPtsPen)
                     preCtrlSet = self.asyPath.controlSet[index][0]
-                    preCtrlPoint = Qc.QPointF(preCtrlSet[0], preCtrlSet[1])
+                    preCtrlPoint = QtCore.QPointF(preCtrlSet[0], preCtrlSet[1])
                     canvas.drawEllipse(preCtrlPoint, epsilonSize, epsilonSize)
 
                     canvas.setPen(dashedPen)
@@ -189,7 +198,7 @@
         self.asyPath.setInfo(self.asyPathBackup)
         self.setSelectionBoundaries()
 
-    def mouseDown(self, pos, info, mouseEvent: Qg.QMouseEvent=None):
+    def mouseDown(self, pos, info, mouseEvent: QtGui.QMouseEvent=None):
         self.lastSelPoint = pos
         if self.inTransformMode:
             return
@@ -204,13 +213,13 @@
             self.currentSelIndex = self.prospectiveCtrlPts[0]
             self.inTransformMode = True
             self.parentNodeIndex = self.findLinkingNode(*self.currentSelIndex)
-        
+
         if self.inTransformMode:
             parentNode = self.asyPath.nodeSet[self.parentNodeIndex]
 
             # find the offset of each control point to the node
             if not self.curveMode:
-                return 
+                return
 
             preCtrl, postCtrl = self.getPreAndPostCtrlPts(self.parentNodeIndex)
 
@@ -219,20 +228,20 @@
                 self.parentNodeIndex = 0
 
             if preCtrl is not None:
-                self.preCtrlOffset = xu.funcOnList(
+                self.preCtrlOffset = xasyUtils.funcOnList(
                     preCtrl, parentNode, lambda a, b: a - b)
             else:
                 self.preCtrlOffset = None
 
             if postCtrl is not None:
-                self.postCtrlOffset = xu.funcOnList(
+                self.postCtrlOffset = xasyUtils.funcOnList(
                     postCtrl, parentNode, lambda a, b: a - b)
             else:
                 self.postCtrlOffset = None
 
-    def mouseMove(self, pos, event: Qg.QMouseEvent):
+    def mouseMove(self, pos, event: QtGui.QMouseEvent):
         if self.currentSelMode is None and not self.inTransformMode:
-            # in this case, search for prosective nodes. 
+            # in this case, search for prosective nodes.
             prospectiveNodes = []
             prospectiveCtrlpts = []
 
@@ -262,8 +271,7 @@
 
         if self.inTransformMode:
             index, subindex = self.currentSelIndex
-            deltaPos = pos - self.lastSelPoint
-            newNode = (pos.x(), pos.y())
+            newNode = (self.transf.inverted().toQTransform().map(pos.x(), pos.y()))
             if self.currentSelMode == CurrentlySelctedType.node:
                 # static throughout the moving
                 if self.asyPath.nodeSet[index] == 'cycle':
@@ -270,25 +278,25 @@
                     return
 
                 self.asyPath.setNode(index, newNode)
-                # if also move node: 
+                # if also move node:
 
                 if self.curveMode:
                     checkPre, checkPost = self.getPreAndPostCtrlPts(index)
 
-                    if 1 == 1: # TODO: Replace this with an option to also move control pts. 
+                    if 1 == 1: # TODO: Replace this with an option to also move control pts.
                         if checkPre is not None:
-                            self.asyPath.controlSet[index - 1][1] = xu.funcOnList(
+                            self.asyPath.controlSet[index - 1][1] = xasyUtils.funcOnList(
                                 newNode, self.preCtrlOffset, lambda a, b: a + b
                             )
                         if checkPost is not None:
-                            self.asyPath.controlSet[index][0] = xu.funcOnList(
+                            self.asyPath.controlSet[index][0] = xasyUtils.funcOnList(
                                 newNode, self.postCtrlOffset, lambda a, b: a + b
                             )
 
                     if self.info['autoRecompute']:
                         self.quickRecalculateCtrls()
-                        
 
+
             elif self.currentSelMode == CurrentlySelctedType.ctrlPoint and self.curveMode:
                 self.asyPath.controlSet[index][subindex] = newNode
                 parentNode = self.asyPath.nodeSet[self.parentNodeIndex]
@@ -302,46 +310,46 @@
                 if self.parentNodeIndex == 0 and self.asyPath.nodeSet[-1] == 'cycle':
                     isCycle = True
 
-                rawNewNode = xu.funcOnList(newNode, parentNode, lambda a, b: a - b)
+                rawNewNode = xasyUtils.funcOnList(newNode, parentNode, lambda a, b: a - b)
                 rawAngle = math.atan2(rawNewNode[1], rawNewNode[0])
-                newNorm = xu.twonorm(rawNewNode)
+                newNorm = xasyUtils.twonorm(rawNewNode)
 
 
                 if self.info['editBezierlockMode'] >= Web.LockMode.angleLock:
-                    otherIndex = 1 - subindex       # 1 if 0, 0 otherwise. 
+                    otherIndex = 1 - subindex       # 1 if 0, 0 otherwise.
                     if otherIndex == 0:
                         if index < (len(self.asyPath.controlSet) - 1) or isCycle:
                             newIndex = 0 if isCycle else index + 1
 
-                            oldOtherCtrlPnt = xu.funcOnList(
+                            oldOtherCtrlPnt = xasyUtils.funcOnList(
                                 self.asyPath.controlSet[newIndex][0], parentNode, lambda a, b: a - b)
-                        
+
                             if self.info['editBezierlockMode'] >= Web.LockMode.angleAndScaleLock:
                                 rawNorm = newNorm
                             else:
-                                rawNorm = xu.twonorm(oldOtherCtrlPnt)
+                                rawNorm = xasyUtils.twonorm(oldOtherCtrlPnt)
 
-                            newPnt = (rawNorm * math.cos(rawAngle + math.pi), 
+                            newPnt = (rawNorm * math.cos(rawAngle + math.pi),
                                 rawNorm * math.sin(rawAngle + math.pi))
-                                
-                            self.asyPath.controlSet[newIndex][0] = xu.funcOnList(
+
+                            self.asyPath.controlSet[newIndex][0] = xasyUtils.funcOnList(
                                 newPnt, parentNode, lambda a, b: a + b)
                     else:
                         if index > 0 or isCycle:
                             newIndex = -1 if isCycle else index - 1
-                            oldOtherCtrlPnt = xu.funcOnList(
+                            oldOtherCtrlPnt = xasyUtils.funcOnList(
                                 self.asyPath.controlSet[newIndex][1], parentNode, lambda a, b: a - b)
 
                             if self.info['editBezierlockMode'] >= Web.LockMode.angleAndScaleLock:
                                 rawNorm = newNorm
                             else:
-                                rawNorm = xu.twonorm(oldOtherCtrlPnt)
+                                rawNorm = xasyUtils.twonorm(oldOtherCtrlPnt)
 
                             newPnt = (rawNorm * math.cos(rawAngle + math.pi),
                                       rawNorm * math.sin(rawAngle + math.pi))
-                            self.asyPath.controlSet[newIndex][1] = xu.funcOnList(
+                            self.asyPath.controlSet[newIndex][1] = xasyUtils.funcOnList(
                                 newPnt, parentNode, lambda a, b: a + b)
-        
+
     def recalculateCtrls(self):
         self.quickRecalculateCtrls()
         self.setSelectionBoundaries()
@@ -356,7 +364,7 @@
             self.currentSelMode = None
 
             self.setSelectionBoundaries()
-            
+
     def forceFinalize(self):
         self.objectUpdated.emit()
 

Modified: trunk/Master/texmf-dist/asymptote/GUI/xasyFile.py
===================================================================
--- trunk/Master/texmf-dist/asymptote/GUI/xasyFile.py	2022-02-27 23:39:53 UTC (rev 62264)
+++ trunk/Master/texmf-dist/asymptote/GUI/xasyFile.py	2022-02-27 23:41:11 UTC (rev 62265)
@@ -1,7 +1,7 @@
 #!/usr/bin/env python3
 ###########################################################################
 #
-# xasyFile implements the loading, parsing, and saving of an xasy file.
+# xasyFile implements the loading, parsing, and saving of an asy file.
 #
 #
 # Author: Orest Shardt
@@ -10,7 +10,7 @@
 ############################################################################
 
 from string import *
-import xasy2asy as x2a
+import xasy2asy as xasy2asy
 import io
 import re
 
@@ -28,7 +28,7 @@
 def extractTransform(line):
     """Returns key and the new transform."""
     # see https://regex101.com/r/6DqkRJ/4 for info
-    mapString = x2a.xasyItem.mapString
+    mapString = xasy2asy.xasyItem.mapString
     testMatch = re.match(
         r'^{0:s}\s*\(\s*\"([^\"]+)\"\s*,\s*\(([-\d, .]+)\)\s*\)'.format(mapString), line.strip())
     if testMatch is None:
@@ -37,7 +37,7 @@
             return None
         else:
             key = mapOnlyMatch.group(1)
-            return key, x2a.identity()
+            return key, xasy2asy.identity()
     else:
         key = testMatch.group(1)
         rawStr = testMatch.group(2)
@@ -46,7 +46,7 @@
         if len(rawStrArray) != 6:
             return None
         transf = [float(val.strip()) for val in rawStrArray]
-        return key, x2a.asyTransform(transf)
+        return key, xasy2asy.asyTransform(transf)
 
 
 def extractTransformsFromFile(fileStr):
@@ -62,22 +62,58 @@
                 if key not in transfDict.keys():
                     transfDict[key] = []
                 transfDict[key].append(transf)
+        final_str = rawCode.getvalue()
+    return final_str, transfDict
 
-                # see https://regex101.com/r/RgeBVc/2 for regex
+def xasy2asyCode(xasyItems, asy2psmap):
+    asyCode = ''
+    for item in xasyItems:
+        asyCode += item.getTransformCode(asy2psmap)
+    for item in xasyItems:
+        asyCode += item.getObjectCode(asy2psmap)
 
-                testNum = re.match(r'^x(\d+)($|:.*$)', key)
-                if testNum is not None:
-                    maxItemCount = max(maxItemCount, int(testNum.group(1)))
-        final_str = rawCode.getvalue()
-    return final_str, transfDict, maxItemCount
+    asyCode += 'size('+str(asy2psmap*xasy2asy.yflip())+'); '+ xasy2asy.xasyItem.resizeComment+'\n'
+    return asyCode
 
-
 def saveFile(file, xasyItems, asy2psmap):
     """Write a list of xasyItems to a file"""
-    for item in xasyItems:
-        file.write(item.getTransformCode(asy2psmap))
+    file.write(xasy2asyCode(xasyItems, asy2psmap))
 
+def xasyToDict(file, xasyItems, asy2psmap):
+    fileItems = []
+    asyItems = []
     for item in xasyItems:
-        file.write(item.getObjectCode(asy2psmap))
+        if isinstance(item, xasy2asy.xasyScript):
+            # reusing xasyFile code for objects
+            # imported from asy script.
+            asyItems.append({'item':item, 'type': 'xasyScript'})
 
-    file.write('size('+str(asy2psmap*x2a.yflip())+'); '+ x2a.xasyItem.resizeComment+'\n')
+        elif isinstance(item, xasy2asy.xasyText):
+            # At the moment xasyText cannot be edited
+            # so we treat it the same as xasyScript
+            penData = {'color': item.pen.color, 'width': item.pen.width, 'options': item.pen.options}
+            fileItems.append({'type': 'xasyText',
+                    'align': item.label.align,
+                    'location': item.label.location,
+                    'fontSize': item.label.fontSize,
+                    'text': item.label.text,
+                    'transform': item.transfKeymap[item.transfKey][0].t,
+                    'transfKey': item.transfKey,
+                    'pen': penData
+                    })
+
+        elif isinstance(item, xasy2asy.xasyShape):
+            penData = {'color': item.pen.color, 'width': item.pen.width, 'options': item.pen.options}
+            fileItems.append({'type': 'xasyShape',
+                    'nodes': item.path.nodeSet,
+                    'links': item.path.linkSet,
+                    'transform': item.transfKeymap[item.transfKey][0].t,
+                    'transfKey': item.transfKey,
+                    'pen': penData
+                    })
+
+        else:
+            # DEBUGGING PURPOSES ONLY
+            print(type(item))
+
+    return {'objects': fileItems, 'asy2psmap': asy2psmap.t}, asyItems

Modified: trunk/Master/texmf-dist/asymptote/GUI/xasyOptions.py
===================================================================
--- trunk/Master/texmf-dist/asymptote/GUI/xasyOptions.py	2022-02-27 23:39:53 UTC (rev 62264)
+++ trunk/Master/texmf-dist/asymptote/GUI/xasyOptions.py	2022-02-27 23:41:11 UTC (rev 62265)
@@ -10,26 +10,14 @@
 #
 ###########################################################################
 
-import json
 import sys
 import io
 import os
 import platform
 import shutil
-
 import configs
+import cson
 
-try:
-    import cson
-except ModuleNotFoundError:
-    cson = None
-
-try:
-    pass
-#     import yaml
-except ModuleNotFoundError:
-    yaml = None
-
 class xasyOptions:
     def defaultOptions(self):
         if self._defaultOptions is None:
@@ -49,12 +37,12 @@
 
         for key in self.options[settingsName]:
             self.options[key] = self.options[settingsName][key]
-    
-    
+
+
     def settingsFileLocation(self):
         folder = os.path.expanduser("~/.asy/")
 
-        searchOrder = ['.cson', '.yaml', '.json', '']
+        searchOrder = ['.cson', '']
 
         searchIndex = 0
         found = False
@@ -64,7 +52,7 @@
             if os.path.isfile(currentFile):
                 found = True
             searchIndex += 1
-        
+
         if found:
             return os.path.normcase(currentFile)
         else:
@@ -99,16 +87,7 @@
         f = io.open(fileName, 'r')
         try:
             ext = os.path.splitext(fileName)[1]
-            if ext == '.cson':
-                if cson is None:
-                    raise ModuleNotFoundError
-                newOptions = cson.loads(f.read())
-            elif ext in {'.yml', '.yaml'}:
-                if yaml is None:
-                    raise ModuleNotFoundError
-                newOptions = yaml.load(f)
-            else:
-                newOptions = json.loads(f.read())
+            newOptions = cson.loads(f.read())
         except (IOError, ModuleNotFoundError):
             self.setDefaults()
         else:
@@ -130,8 +109,8 @@
         folder = os.path.expanduser("~/.asy/")
         defaultPath = os.path.join(folder, self.configName + '.cson')
         shutil.copy2(self._defaultOptLocation, defaultPath)
-        
 
+
 # TODO: Figure out how to merge this back.
 """
 def setAsyPathFromWindowsRegistry():
@@ -150,7 +129,73 @@
             registry.CloseKey(key)
 """
 
+class xasyOpenRecent:
+    def __init__(self, configName, defaultConfigLocation):
+        self.configName = configName
+        self.fileName = self.settingsFileLocation()
+        if not os.path.isfile(self.fileName):
+            f = io.open(self.fileName, 'w')
+            f.write('')
+            f.close()
 
+    def settingsFileLocation(self):
+        folder = os.path.expanduser("~/.asy/")
+
+        currentFile = os.path.join(folder, self.configName + '.txt')
+        return os.path.normcase(currentFile)
+
+    def insert(self, path):
+        if not os.path.exists(self.fileName):
+            # make folder
+            thedir = os.path.dirname(self.fileName)
+            if not os.path.exists(thedir):
+                os.makedirs(thedir)
+            if not os.path.isdir(thedir):
+                raise Exception("Configuration folder path does not point to a folder")
+
+        f = io.open(self.fileName, 'r')
+        lines = f.readlines()
+        f.close()
+
+        f = io.open(self.fileName, 'w')
+        f.write(path.strip() + '\n')
+        for line in lines:
+            if line.strip() != path.strip():
+                f.write(line.strip() + '\n')
+        f.close()
+
+    @property
+    def pathList(self):
+        self.findingPaths=True
+        return self.findPath()
+
+    def findPath(self):
+        f = io.open(self.fileName, 'r')
+        paths = [path.strip() for path in f.readlines()]
+        f.close()
+
+        trueFiles = list(map(lambda path: os.path.isfile(os.path.expanduser(path)), paths))
+        if all(trueFiles):
+            return paths
+        else:
+            if self.findingPaths == False:
+                raise RecursionError
+            self.findingPaths = False
+            self.removeNotFound(list(trueFiles), paths)
+            return self.findPath()
+
+    def removeNotFound(self, trueFiles, paths):
+        f = io.open(self.fileName, 'w')
+        for index, path in enumerate(paths):
+            if trueFiles[index] == True:
+                f.write(path + '\n')
+        f.close()
+
+    def clear(self):
+        f = io.open(self.fileName, 'w')
+        f.write('')
+        f.close()
+
 class BasicConfigs:
     _configPath = list(configs.__path__)[0]
     defaultOpt = xasyOptions(
@@ -157,3 +202,4 @@
         'xasyconfig', os.path.join(_configPath, 'xasyconfig.cson'))
     keymaps = xasyOptions('xasykeymap', os.path.join(
         _configPath, 'xasykeymap.cson'))
+    openRecent = xasyOpenRecent('xasyrecents', os.path.join( _configPath, "xasyrecent.txt"))

Modified: trunk/Master/texmf-dist/asymptote/GUI/xasyStrings.py
===================================================================
--- trunk/Master/texmf-dist/asymptote/GUI/xasyStrings.py	2022-02-27 23:39:53 UTC (rev 62264)
+++ trunk/Master/texmf-dist/asymptote/GUI/xasyStrings.py	2022-02-27 23:41:11 UTC (rev 62265)
@@ -8,12 +8,12 @@
     def __init__(self, lang=None):
         s = self
         if lang is None:
-            _ = lambda x:  x 
+            _ = lambda x:  x
         else:
             lng = gettext.translation('base', localedir='GUI/locale', languages=[lang])
             lng.install()
             _ = lng.gettext
-            
+
         s.rotate = _('Rotate')
         s.scale = _('Scale')
         s.translate = _('Translate')

Modified: trunk/Master/texmf-dist/asymptote/GUI/xasySvg.py
===================================================================
--- trunk/Master/texmf-dist/asymptote/GUI/xasySvg.py	2022-02-27 23:39:53 UTC (rev 62264)
+++ trunk/Master/texmf-dist/asymptote/GUI/xasySvg.py	2022-02-27 23:41:11 UTC (rev 62265)
@@ -1,7 +1,7 @@
 #!/usr/bin/env python3
 
-import PyQt5.QtGui as Qg
-import PyQt5.QtWidgets as Qw
+import PyQt5.QtGui as QtGui
+import PyQt5.QtWidgets as QtWidgets
 import io
 import subprocess
 import sys
@@ -10,13 +10,13 @@
     def __init__(self, file: str):
         self.file=file
 
-    def render(self, dpi:int) -> Qg.QImage:
+    def render(self, dpi:int) -> QtGui.QImage:
         try:
             rawDataProc = subprocess.Popen(['rsvg-convert', '--dpi-x', str(dpi),
                                             '--dpi-y', str(dpi), self.file],
                                            stdout=subprocess.PIPE)
         except:
-            Qw.QMessageBox.about(None,'rsvg-convert missing','Please install rsvg-convert version >= 2.40 in your path.')
+            QtWidgets.QMessageBox.about(None,'rsvg-convert missing','Please install rsvg-convert version >= 2.40 in your path.')
             sys.exit(-1)
 
-        return Qg.QImage.fromData(rawDataProc.stdout.read(), 'PNG')
+        return QtGui.QImage.fromData(rawDataProc.stdout.read(), 'PNG')

Modified: trunk/Master/texmf-dist/asymptote/GUI/xasyTransform.py
===================================================================
--- trunk/Master/texmf-dist/asymptote/GUI/xasyTransform.py	2022-02-27 23:39:53 UTC (rev 62264)
+++ trunk/Master/texmf-dist/asymptote/GUI/xasyTransform.py	2022-02-27 23:41:11 UTC (rev 62265)
@@ -1,8 +1,8 @@
 #!/usr/bin/env python3
-import xasy2asy as x2a
-import PyQt5.QtGui as Qg
-import PyQt5.QtCore as Qc
-import numpy as np
+import xasy2asy as xasy2asy
+import PyQt5.QtGui as QtGui
+import PyQt5.QtCore as QtCore
+import numpy as numpy
 import math
 
 
@@ -9,16 +9,16 @@
 class xasyTransform:
     @classmethod
     def makeRotTransform(cls, theta, origin):
-        if isinstance(origin, Qc.QPointF) or isinstance(origin, Qc.QPoint):
+        if isinstance(origin, QtCore.QPointF) or isinstance(origin, QtCore.QPoint):
             origin = (origin.x(), origin.y())
         rotMat = (math.cos(theta), -math.sin(theta), math.sin(theta), math.cos(theta))
-        shift = x2a.asyTransform((0, 0, 1 - rotMat[0], -rotMat[1], -rotMat[2], 1 - rotMat[3])) * origin
-        return x2a.asyTransform((shift[0], shift[1], rotMat[0], rotMat[1], rotMat[2], rotMat[3]))
+        shift = xasy2asy.asyTransform((0, 0, 1 - rotMat[0], -rotMat[1], -rotMat[2], 1 - rotMat[3])) * origin
+        return xasy2asy.asyTransform((shift[0], shift[1], rotMat[0], rotMat[1], rotMat[2], rotMat[3]))
 
     @classmethod
     def makeScaleTransform(cls, sx, sy, origin):
-        if isinstance(origin, Qc.QPointF) or isinstance(origin, Qc.QPoint):
+        if isinstance(origin, QtCore.QPointF) or isinstance(origin, QtCore.QPoint):
             origin = (origin.x(), origin.y())
-        shiftMat = x2a.asyTransform((0, 0, 1 - sx, 0, 0, 1 - sy)) * origin
-        return x2a.asyTransform((shiftMat[0], shiftMat[1], sx, 0, 0, sy))
+        shiftMat = xasy2asy.asyTransform((0, 0, 1 - sx, 0, 0, 1 - sy)) * origin
+        return xasy2asy.asyTransform((shiftMat[0], shiftMat[1], sx, 0, 0, sy))
 

Modified: trunk/Master/texmf-dist/asymptote/GUI/xasyUtils.py
===================================================================
--- trunk/Master/texmf-dist/asymptote/GUI/xasyUtils.py	2022-02-27 23:39:53 UTC (rev 62264)
+++ trunk/Master/texmf-dist/asymptote/GUI/xasyUtils.py	2022-02-27 23:41:11 UTC (rev 62265)
@@ -1,7 +1,7 @@
 #!/usr/bin/env python3
 
 import re
-import typing as ty
+import typing as typing
 import math
 import itertools
 
@@ -15,12 +15,12 @@
     except ValueError:
         return None
 
-def funcOnList(list1: ty.Union[ty.List, ty.Tuple], list2: ty.Union[ty.List, ty.Tuple], func: ty.Callable) -> tuple:
-    """Returns [f(x[i], y[i]) : i in 1, ..., n - 1] in order with f as func 
+def funcOnList(list1: typing.Union[typing.List, typing.Tuple], list2: typing.Union[typing.List, typing.Tuple], func: typing.Callable) -> tuple:
+    """Returns [f(x[i], y[i]) : i in 1, ..., n - 1] in order with f as func
     and x and y as list1 and 2. """
 
     assert len(list1) == len(list2)
-    return tuple([func(list1[i], list2[i]) for i in range(len(list1))]) 
+    return tuple([func(list1[i], list2[i]) for i in range(len(list1))])
 
 
 def listize(str, typ, delim='()') -> list:
@@ -39,7 +39,7 @@
             final_list.append(typ(elem.strip()))
     return final_list
 
-def twonorm(vec: ty.Iterable[ty.Union[float, int]]) -> float:
+def twonorm(vec: typing.Iterable[typing.Union[float, int]]) -> float:
     rawSquared = sum(map(lambda x: x*x, vec))
     return math.sqrt(rawSquared)
 

Modified: trunk/Master/texmf-dist/asymptote/GUI/xasyVersion.py
===================================================================
--- trunk/Master/texmf-dist/asymptote/GUI/xasyVersion.py	2022-02-27 23:39:53 UTC (rev 62264)
+++ trunk/Master/texmf-dist/asymptote/GUI/xasyVersion.py	2022-02-27 23:41:11 UTC (rev 62265)
@@ -1,2 +1,2 @@
 #!/usr/bin/env python3
-xasyVersion = "2.70"
+xasyVersion = "2.78"

Modified: trunk/Master/texmf-dist/asymptote/asy-keywords.el
===================================================================
--- trunk/Master/texmf-dist/asymptote/asy-keywords.el	2022-02-27 23:39:53 UTC (rev 62264)
+++ trunk/Master/texmf-dist/asymptote/asy-keywords.el	2022-02-27 23:41:11 UTC (rev 62265)
@@ -2,7 +2,7 @@
 ;; This file is automatically generated by asy-list.pl.
 ;; Changes will be overwritten.
 ;;
-(defvar asy-keywords-version "2.70")
+(defvar asy-keywords-version "2.78")
 
 (defvar asy-keyword-name '(
 and controls tension atleast curl if else while for do return break continue struct typedef new access import unravel from include quote static public private restricted this explicit true false null cycle newframe operator ))
@@ -11,7 +11,7 @@
 Braid FitResult Label Legend Solution TreeNode abscissa arc arrowhead binarytree binarytreeNode block bool bool3 bounds bqe circle conic coord coordsys cputime ellipse evaluatedpoint file filltype frame grid3 guide horner hsv hyperbola int inversion key light line linefit marginT marker mass node object pair parabola patch path path3 pen picture point position positionedvector projection rational real revolution scaleT scientific segment side simplex slice solution splitface string surface tensionSpecifier ticklocate ticksgridT tickvalues transform transformation tree triangle trilinear triple vector vertex void ))
 
 (defvar asy-function-name '(
-AND Arc ArcArrow ArcArrows Arrow Arrows AtA Automatic AvantGarde B03 B13 B23 B33 BBox BWRainbow BWRainbow2 Bar Bars BeginArcArrow BeginArrow BeginBar BeginDotMargin BeginMargin BeginPenMargin Blank Bookman Bottom BottomTop Bounds Break Broken BrokenLog CLZ CTZ Ceil Circle CircleBarIntervalMarker Cos Courier CrossIntervalMarker DOSendl DOSnewl DefaultFormat DefaultLogFormat Degrees Dir DotMargin DotMargins Dotted Draw Drawline Embed EndArcArrow EndArrow EndBar EndDotMargin EndMargin EndPenMargin Fill FillDraw Finite Floor Format Full Gaussian Gaussrand Gaussrandpair Gradient Grayscale Helvetica Hermite HookHead InOutTicks InTicks Jn Label Landscape Left LeftRight LeftTicks Legend Linear Log LogFormat Margin Margins Mark MidArcArrow MidArrow NOT NewCenturySchoolBook NoBox NoMargin NoModifier NoTicks NoTicks3 NoZero NoZeroFormat None OR OmitFormat OmitTick OmitTickInterval OmitTickIntervals OutTicks Ox Oy Palatino PaletteTicks Pen PenMargin PenMargins Pentype Portrait RGB RadialShade RadialShadeDraw Rainbow Range Relative Right RightTicks Rotate Round SQR Scale ScaleX ScaleY ScaleZ Seascape Shift Sin Slant Spline StickIntervalMarker Straight Symbol Tan TeXify Ticks Ticks3 TildeIntervalMarker TimesRoman Top TrueMargin UnFill UpsideDown Wheel X XEquals XOR XY XYEquals XYZero XYgrid XZEquals XZZero XZero XZgrid Y YEquals YXgrid YZ YZEquals YZZero YZero YZgrid Yn Z ZX ZXgrid ZYgrid ZapfChancery ZapfDingbats _begingroup3 _cputime _draw _eval _findroot _image _labelpath _projection _shipout _strokepath _texpath aCos aSin aTan abort abs abs2 accel acos acosh acot acsc activatequote add addArrow addMargins addSaveFunction addpenarc addpenline addseg adjust alias align all altitude angabscissa angle angledegrees angpoint animate annotate anticomplementary antipedal apply approximate arc arcarrowsize arccircle arcdir arcfromcenter arcfromfocus arclength arcnodesnumber arcpoint arcsubtended arcsubtendedcenter arctime arctopath array arrow arrow2 arrowbase arrowbasepoints arrowsize ascii asec asin asinh ask assert asy!
  asycode asydir asyfigure asyfilecode asyinclude asywrite atan atan2 atanh atbreakpoint atexit attach attract atupdate autoformat autoscale autoscale3 axes axes3 axialshade axis axiscoverage azimuth babel background bangles bar barmarksize barsize basealign baseline bbox beep begin beginclip begingroup beginpoint between bevel bezier bezierP bezierPP bezierPPP bezulate bibliography bibliographystyle binarytree binarytreeNode binomial bins bisector bisectorpoint bispline bispline0 bitreverse blend blockconnector box bqe brace breakpoint breakpoints brick buildRestoreDefaults buildRestoreThunk buildcycle bulletcolor byte calculateScaling canonical canonicalcartesiansystem cartesiansystem case1 case2 case3 cbrt cd ceil center centerToFocus centroid cevian change2 changecoordsys checkSegment check_fpt_zero checkconditionlength checker checkincreasing checklengths checkposition checkpt checkptincube checktriangle choose circle circlebarframe circlemarkradius circlenodesnumber circumcenter circumcircle clamped clear clip clipdraw close cmyk code colatitude collect collinear color colorless colors colorspace comma compassmark complement complementary concat concurrent cone conic conicnodesnumber conictype conj connect containmentTree contains contour contour3 controlSpecifier convert coordinates coordsys copy copyPairOrTriple cos cosh cot countIntersections cputime crop cropcode cross crossframe crosshatch crossmarksize csc cubicroots curabscissa curlSpecifier curpoint currentarrow currentexitfunction currentmomarrow currentpolarconicroutine curve cut cutafter cutbefore cyclic cylinder deactivatequote debugger deconstruct defaultdir defaultformat defaultpen defined degenerate degrees delete deletepreamble determinant diagonal diamond diffdiv dir dirSpecifier dirtime display distance divisors do_overpaint dot dotframe dotsize downcase draw drawAll drawCylinder drawDisk drawDoubleLine drawFermion drawGhost drawGluon drawMomArrow drawPhoton drawScalar drawSphere drawTube drawVertex drawVertexBox drawVertexBoxO drawVertexB!
 oxX drawVertexO drawVertexOX drawVertexTriangle drawVertexTriangleO drawVertexX drawarrow drawarrow2 drawbeziertriangle drawline drawpixel drawstrokepath drawtick duplicate elle ellipse ellipsenodesnumber embed embed3 embedplayer empty enclose end endclip endgroup endgroup3 endl endpoint endpoints eof eol equation equations erase erasestep erf erfc error errorbar errorbars eval excenter excircle exit exitfunction exp expfactors expi expm1 exradius extend extension extouch fabs factorial fermat fft fhorner figure file filecode fill filldraw filloutside fillrule filltype find findall findroot finite finiteDifferenceJacobian firstcut firstframe fit fit2 fixedscaling floor flush fmdefaults fmod focusToCenter font fontcommand fontsize foot format frac frequency fromCenter fromFocus fspline functionshade gamma gcd generate_random_backtrace generateticks gergonne getc getint getpair getreal getstring gettriple gluon gouraudshade graph graphic graphicscale gray grestore grid grid3 gsave halfbox hatch hdiffdiv hermite hex histogram history hline hprojection hsv hyperbola hyperbolanodesnumber hyperlink hypot identity image implicitsurface incenter incentral incircle increasing incrementposition indexedfigure initdefaults initialized input inradius insert inside insphere integrate interactive interior interp interpolate intersect intersection intersectionpoint intersectionpoints intersections intouch inverse inversion invisible is3D isDuplicate isnan isogonal isogonalconjugate isometry isotomic isotomicconjugate isparabola italic item jobname key kurtosis kurtosisexcess label labelaxis labelmargin labelpath labels labeltick labelx labelx3 labely labely3 labelz labelz3 lastcut latex latitude latticeshade layer layout lcm ldexp leastsquares legend legenditem length lexorder lift light limits line linear linecap lineinversion linejoin linemargin lineskip linetype linewidth link list lm_enorm lm_evaluate_default lm_lmdif lm_lmpar lm_minimize lm_print_default lm_print_quiet lm_qrfac lm_qrsolv locale locate locatefile location l!
 og log10 log1p logaxiscoverage longitude lookup make3dgrid makeMappingArray makeNode makecircle makedraw makepen maketriangle map mapArray mapTemplate margin markangle markangleradius markanglespace markarc marker markinterval marknodes markrightangle markthin markuniform mass masscenter massformat math max max3 maxAfterTransform maxbezier maxbound maxcoords maxlength maxratio maxtimes mean medial median midpoint min min3 minAfterTransform minbezier minbound minipage minratio mintimes miterlimit mktemp momArrowPath momarrowsize monotonic multifigure nGrad nativeformat natural newl newpage newslide newton newtree nextframe nextnormal nextpage nib nodabscissa node none norm normalout normalvideo notaknot nowarn numberpage nurb object offset onpath opacity opposite orient orientation origin orthic orthocentercenter outdirectory outformat outline outname outprefix output overloadedMessage overwrite pack pad pairs palette parabola parabolanodesnumber parallel parallelogram partialsum patchwithnormals path path3 pathbetween pathinface pattern pause pdf pedal periodic perp perpendicular perpendicularmark phantom phi1 phi2 phi3 phi4 photon piecewisestraight point polar polarconicroutine polargraph polygon popcount postcontrol postscript pow10 ppoint prc prc0 prconly precision precontrol prepend printBytecode print_random_addresses progress project projection projecttospan projecttospan_findcoeffs purge pwhermite quadpatches quadrant quadraticroots quantize quarticroots quotient radialshade radians radicalcenter radicalline radius rand randompath rationalidentity rd readline realmult realquarticroots rectangle rectangular rectify reflect relabscissa relative relativedistance reldir relpoint reltime remainder remark removeDuplicates rename render replace report resetdefaultpen restore restoredefaults reverse reversevideo rf rfind rgb rgba rgbint rms rotate rotateO rotation round roundbox roundedpath roundrectangle samecoordsys sameside sample save savedefaults saveline scale scale3 scaleO scaleT scaleless scientific searc!
 h searchtree sec secondaryX secondaryY seconds section sector seek seekeof segment segmentlimits sequence setpens sgn sgnd sharpangle sharpdegrees shift shiftless shipout shipout3 show simeq simplex simplexInit simplexPhase1 simplexPhase2 simplexTableau simplexWrite simpson sin sinh size size3 skewness skip slant sleep slice slope slopefield solve solveBVP sort sourceline sphere split sqrt square srand standardizecoordsys stdev step stickframe stickmarksize stickmarkspace stop straight straightness string stripdirectory stripextension stripfile stripsuffix strokepath subdivide subitem subpath substr sum surface symmedial symmedian system tab tableau tan tangent tangential tangents tanh tell tensionSpecifier tensorshade tex texcolor texify texpath texpreamble texreset texshipout texsize texstring textpath thick thin tick tickMax tickMax3 tickMin tickMin3 ticklabelshift ticklocate tildeframe tildemarksize tile tiling time times title titlepage topbox toplocation transform transformation transpose trembleFuzz triangle triangleAbc triangleabc triangletoquads trianglewithnormals triangulate tricoef tridiagonal trilinear trim truepoint tube type uncycle unfill uniform unique unit unitrand unitsize unityroot unstraighten upcase updatefunction uperiodic upscale uptodate usepackage usersetting usetypescript usleep value variance variancebiased vbox vector vectorfield verbatim view vline vperiodic vprojection warn warning windingnumber write xasyKEY xaxis xaxis3 xaxis3At xaxisAt xequals xlimits xmap xpart xscale xscaleO xtick xtick3 xtrans yaxis yaxis3 yaxis3At yaxisAt yequals ylimits ypart yscale yscaleO ytick ytick3 ytrans zaxis3 zaxis3At zero zlimits zpart ztick ztick3 ztrans ))
+AND Align Arc ArcArrow ArcArrows Arrow Arrows AtA Automatic AvantGarde B03 B13 B23 B33 BBox BWRainbow BWRainbow2 Bar Bars BeginArcArrow BeginArrow BeginBar BeginDotMargin BeginMargin BeginPenMargin Blank Bookman Bottom BottomTop Bounds Break Broken BrokenLog CLZ CTZ Ceil Circle CircleBarIntervalMarker Cos Courier CrossIntervalMarker DOSendl DOSnewl DefaultFormat DefaultLogFormat Degrees Dir DotMargin DotMargins Dotted Draw Drawline Embed EndArcArrow EndArrow EndBar EndDotMargin EndMargin EndPenMargin Fill FillDraw Finite Floor Format Full Gaussian Gaussrand Gaussrandpair Gradient Grayscale Helvetica Hermite HookHead InOutTicks InTicks Jn Label Landscape Left LeftRight LeftTicks Legend Linear Log LogFormat Margin Margins Mark MidArcArrow MidArrow NOT NewCenturySchoolBook NoBox NoMargin NoModifier NoTicks NoTicks3 NoZero NoZeroFormat None OR OmitFormat OmitTick OmitTickInterval OmitTickIntervals OutTicks Ox Oy Palatino PaletteTicks Pen PenMargin PenMargins Pentype Portrait RGB RadialShade RadialShadeDraw Rainbow Range Relative Right RightTicks Rotate Round SQR Scale ScaleX ScaleY ScaleZ Seascape Shift Sin Slant Spline StickIntervalMarker Straight Symbol Tan TeXify Ticks Ticks3 TildeIntervalMarker TimesRoman Top TrueMargin UnFill UpsideDown Wheel X XEquals XOR XY XYEquals XYZero XYgrid XZEquals XZZero XZero XZgrid Y YEquals YXgrid YZ YZEquals YZZero YZero YZgrid Yn Z ZX ZXgrid ZYgrid ZapfChancery ZapfDingbats _begingroup3 _cputime _draw _eval _findroot _image _labelpath _projection _shipout _strokepath _texpath aCos aSin aTan abort abs abs2 accel acos acosh acot acsc activatequote add addArrow addMargins addSaveFunction addpenarc addpenline addseg adjust alias align all altitude angabscissa angle angledegrees angpoint animate annotate anticomplementary antipedal apply approximate arc arcarrowsize arccircle arcdir arcfromcenter arcfromfocus arclength arcnodesnumber arcpoint arcsubtended arcsubtendedcenter arctime arctopath array arrow arrow2 arrowbase arrowbasepoints arrowsize ascii asec asin asinh ask asse!
 rt asy asycode asydir asyfigure asyfilecode asyinclude asywrite atan atan2 atanh atbreakpoint atexit attach attract atupdate autoformat autoscale autoscale3 axes axes3 axialshade axis axiscoverage azimuth babel background bangles bar barmarksize barsize basealign baseline bbox beep begin beginclip begingroup beginpoint between bevel bezier bezierP bezierPP bezierPPP bezulate bibliography bibliographystyle binarytree binarytreeNode binomial bins bisector bisectorpoint bispline bispline0 bitreverse blend blockconnector box bqe brace breakpoint breakpoints brick buildRestoreDefaults buildRestoreThunk buildcycle bulletcolor byte byteinv calculateScaling canonical canonicalcartesiansystem cartesiansystem case1 case2 case3 cbrt cd ceil center centerToFocus centroid cevian change2 changecoordsys checkSegment check_fpt_zero checkconditionlength checker checkincreasing checklengths checkposition checkpt checkptincube checktriangle choose circle circlebarframe circlemarkradius circlenodesnumber circumcenter circumcircle clamped clear clip clipdraw close cmyk code colatitude collect collinear color colorless colors colorspace comma compassmark complement complementary concat concurrent cone conic conicnodesnumber conictype conj connect containmentTree contains contour contour3 controlSpecifier convert coordinates coordsys copy copyPairOrTriple cos cosh cot countIntersections cputime crop cropcode cross crossframe crosshatch crossmarksize csc cubicroots curabscissa curlSpecifier curpoint currentarrow currentexitfunction currentmomarrow currentpolarconicroutine curve cut cutafter cutbefore cyclic cylinder deactivatequote debugger deconstruct defaultdir defaultformat defaultpen defined degenerate degrees delete deletepreamble determinant diagonal diamond diffdiv dir dirSpecifier dirtime display distance divisors do_overpaint dot dotframe dotsize downcase draw drawAll drawCylinder drawDisk drawDoubleLine drawFermion drawGhost drawGluon drawMomArrow drawPhoton drawScalar drawSphere drawTube drawVertex drawVertexBox drawVertexBo!
 xO drawVertexBoxX drawVertexO drawVertexOX drawVertexTriangle drawVertexTriangleO drawVertexX drawarrow drawarrow2 drawbeziertriangle drawline drawpixel drawstrokepath drawtick duplicate elle ellipse ellipsenodesnumber embed embed3 embedplayer empty enclose end endclip endgroup endgroup3 endl endpoint endpoints eof eol equation equations erase erasestep erf erfc error errorbar errorbars eval excenter excircle exit exitfunction exp expfactors expi expm1 exradius extend extension extouch fabs factorial fermat fft fhorner figure file filecode fill filldraw filloutside fillrule filltype find findall findroot finite finiteDifferenceJacobian firstcut firstframe fit fit2 fixedscaling floor flush fmdefaults fmod focusToCenter font fontcommand fontsize foot format frac frequency fromCenter fromFocus fspline functionshade gamma gcd generate_random_backtrace generateticks gergonne getc getint getpair getreal getstring gettriple gluon gouraudshade graph graphic graphicscale graphwithderiv gray grestore grid grid3 gsave halfbox hatch hdiffdiv hermite hex histogram history hline hprojection hsv hyperbola hyperbolanodesnumber hyperlink hypot identity image implicitsurface importv3d incenter incentral incircle increasing incrementposition indexedfigure initdefaults initialized input inradius insert inside insphere integrate interactive interior interp interpolate intersect intersection intersectionpoint intersectionpoints intersections intouch inverse inversion invisible is3D isDuplicate isnan isogonal isogonalconjugate isometry isotomic isotomicconjugate isparabola italic item jobname key kurtosis kurtosisexcess label labelaxis labelmargin labelpath labels labeltick labelx labelx3 labely labely3 labelz labelz3 lastcut latex latitude latticeshade layer layout lcm ldexp leastsquares legend legenditem length lexorder lift light limits line linear linecap lineinversion linejoin linemargin lineskip linetype linewidth link list lm_enorm lm_evaluate_default lm_lmdif lm_lmpar lm_minimize lm_print_default lm_print_quiet lm_qrfac lm_qrs!
 olv locale locate locatefile location log log10 log1p logaxiscoverage longitude lookup make3dgrid makeMappingArray makeNode makecircle makedraw makepen maketriangle map mapArray mapTemplate margin markangle markangleradius markanglespace markarc marker markinterval marknodes markrightangle markthin markuniform mass masscenter massformat math max max3 maxAfterTransform maxbezier maxbound maxcoords maxlength maxratio maxtimes mean medial median midpoint min min3 minAfterTransform minbezier minbound minipage minratio mintimes miterlimit mktemp momArrowPath momarrowsize monotonic multifigure nGrad nativeformat natural newl newpage newslide newton newtree nextframe nextnormal nextpage nib nodabscissa node none norm normalout normalvideo notaknot nowarn numberpage nurb object offset onpath opacity opposite orient orientation origin orthic orthocentercenter outdirectory outformat outline outname outprefix output overloadedMessage overwrite pack pad pairs palette parabola parabolanodesnumber parallel parallelogram partialsum patchwithnormals path path3 pathbetween pathinface pattern pause pdf pedal periodic perp perpendicular perpendicularmark phantom phi1 phi2 phi3 phi4 photon piecewisestraight point polar polarconicroutine polargraph polygon popcount postcontrol postscript pow10 ppoint prc prc0 prconly precision precontrol prepend primitive printBytecode print_random_addresses progress project projection projecttospan projecttospan_findcoeffs purge pwhermite quadpatches quadrant quadraticroots quantize quarticroots quotient radialshade radians radicalcenter radicalline radius rand randompath rationalidentity rd readline realmult realquarticroots rectangle rectangular rectify reflect relabscissa relative relativedistance reldir relpoint reltime remainder remark removeDuplicates rename render replace report resetdefaultpen restore restoredefaults reverse reversevideo rf rfind rgb rgba rgbint rms rotate rotateO rotation round roundbox roundedpath roundrectangle samecoordsys sameside sample save savedefaults saveline scal!
 e scale3 scaleO scaleT scaleless scientific search searchtree sec secondaryX secondaryY seconds section sector seek seekeof segment segmentlimits sequence setpens sgn sgnd sharpangle sharpdegrees shift shiftless shipout shipout3 show simeq simplex simplexInit simplexPhase1 simplexPhase2 simplexTableau simplexWrite simpson sin sinh size size3 skewness skip slant sleep slice slope slopefield solve solveBVP sort sourceline sphere split sqrt square srand standardizecoordsys stdev step stickframe stickmarksize stickmarkspace stop straight straightness string stripdirectory stripextension stripfile stripsuffix strokepath subdivide subitem subpath substr sum surface symmedial symmedian system tab tableau tan tangent tangential tangents tanh tell tensionSpecifier tensorshade tex texcolor texify texpath texpreamble texreset texshipout texsize texstring textpath thick thin tick tickMax tickMax3 tickMin tickMin3 ticklabelshift ticklocate tildeframe tildemarksize tile tiling time times title titlepage topbox transform transformation transpose trembleFuzz triangle triangleAbc triangleabc triangletoquads trianglewithnormals triangulate tricoef tridiagonal trilinear trim truepoint tube type uncycle unfill uniform unique unit unitrand unitsize unityroot unstraighten upcase updatefunction uperiodic upscale uptodate usepackage usersetting usetypescript usleep value variance variancebiased vbox vector vectorfield verbatim view vline vperiodic vprojection warn warning windingnumber write xasyKEY xaxis xaxis3 xaxis3At xaxisAt xequals xlimits xmap xpart xscale xscaleO xtick xtick3 xtrans yaxis yaxis3 yaxis3At yaxisAt yequals ylimits ypart yscale yscaleO ytick ytick3 ytrans zaxis3 zaxis3At zero zlimits zpart ztick ztick3 ztrans ))
 
 (defvar asy-variable-name '(
-Accent AliceBlue Align Allow AntiqueWhite Apricot Aqua Aquamarine Aspect Azure BeginPoint Beige Bisque Bittersweet Black BlanchedAlmond Blue BlueGreen BlueViolet Blues Both BrBG Break BrickRed Brown BuGn BuPu BurlyWood BurntOrange CCW CMRmap CW CadetBlue CarnationPink Center Centered Cerulean Chartreuse Chocolate Coeff Coral CornflowerBlue Cornsilk Crimson Crop Cyan Dandelion Dark2 DarkBlue DarkCyan DarkGoldenrod DarkGray DarkGreen DarkKhaki DarkMagenta DarkOliveGreen DarkOrange DarkOrchid DarkRed DarkSalmon DarkSeaGreen DarkSlateBlue DarkSlateGray DarkTurquoise DarkViolet DeepPink DeepSkyBlue DefaultHead DimGray DodgerBlue Dotted Down Draw E ENE EPS ESE E_Euler E_PC E_RK2 E_RK3BS Emerald EndPoint Euler Fill FillDraw FireBrick FloralWhite ForestGreen Fuchsia Gainsboro GhostWhite GnBu Gold Goldenrod Gray Green GreenYellow Greens Greys Honeydew HookHead Horizontal HotPink I IgnoreAspect IndianRed Indigo Infinity Ivory JOIN_IN JOIN_OUT JungleGreen Khaki LM_DWARF LM_MACHEP LM_SQRT_DWARF LM_SQRT_GIANT LM_USERTOL Label Lavender LavenderBlush LawnGreen Left LeftJustified LeftSide LemonChiffon LightBlue LightCoral LightCyan LightGoldenrodYellow LightGreen LightGrey LightPink LightSalmon LightSeaGreen LightSkyBlue LightSlateGray LightSteelBlue LightYellow Lime LimeGreen Linear Linen Log Logarithmic Magenta Mahogany Mark MarkFill MarkPath Maroon Max MediumAquamarine MediumBlue MediumOrchid MediumPurple MediumSeaGreen MediumSlateBlue MediumSpringGreen MediumTurquoise MediumVioletRed Melon MidPoint MidnightBlue Min MintCream MistyRose Moccasin Move MoveQuiet Mulberry N NE NNE NNW NULL_VERTEX NW NavajoWhite Navy NavyBlue NoAlign NoCrop NoFill NoSide OldLace Olive OliveDrab OliveGreen OrRd Orange OrangeRed Oranges Orchid Ox Oy PC PRGn Paired PaleGoldenrod PaleGreen PaleTurquoise PaleVioletRed PapayaWhip Pastel1 Pastel2 Peach PeachPuff Periwinkle Peru PiYG PineGreen Pink Plum PowderBlue ProcessBlue PuBu PuBuGn PuOr PuRd Purple Purples RELEASE RK2 RK3 RK3BS RK4 RK5 RK5DP RK5F RawSienna RdBu RdGy RdPu RdYlBu RdYlGn Red !
 RedOrange RedViolet Reds Rhodamine Right RightJustified RightSide RosyBrown RoyalBlue RoyalPurple RubineRed S SE SSE SSW SW SaddleBrown Salmon SandyBrown SeaGreen Seashell Sepia Set1 Set2 Set3 Sienna Silver SimpleHead SkyBlue SlateBlue SlateGray Snow Spectral SpringGreen SteelBlue Suppress SuppressQuiet Tan TeXHead Teal TealBlue Thistle Ticksize Tomato Turquoise UnFill Up VERSION Value Vertical Violet VioletRed W WNW WSW Wheat White WhiteSmoke WildStrawberry XHIGH XLOW XYAlign YAlign YHIGH YLOW Yellow YellowGreen YellowOrange YlGn YlGnBu YlOrBr YlOrRd ZHIGH ZLOW _outpipe aboveequationskip addpenarc addpenline align allowstepping angularsystem animationdelay appendsuffix arcarrowangle arcarrowfactor arrow2sizelimit arrowangle arrowbarb arrowdir arrowfactor arrowhookfactor arrowlength arrowsizelimit arrowtexfactor authorpen autumn axis axiscoverage axislabelfactor background backgroundcolor backgroundpen barfactor barmarksizefactor basealign baselinetemplate bernstein beveljoin bigvertexpen bigvertexsize binary black blue bm bone bottom bp bracedefaultratio braceinnerangle bracemidangle braceouterangle brg brown bullet bwr byfoci byvertices camerafactor chartreuse circlemarkradiusfactor circlenodesnumberfactor circleprecision circlescale cividis cm codefile codepen codeskip colorPen coloredNodes coloredSegments conditionlength conicnodesfactor cool coolwarm copper count cputimeformat crossmarksizefactor currentcoordsys currentlight currentpatterns currentpen currentpicture currentposition currentprojection curvilinearsystem cuttings cyan darkblue darkbrown darkcyan darkgray darkgreen darkgrey darkmagenta darkolive darkred dashdotted dashed datepen dateskip debuggerlines debugging deepblue deepcyan deepgray deepgreen deepgrey deepmagenta deepred deepyellow default defaultControl defaultS defaultbackpen defaultcoordsys defaultexcursion defaultfilename defaultformat defaultmassformat defaultpen defaultseparator differentlengths dot dotfactor dotfilltype dotframe dotted doublelinepen doublelinespacing down duplicateFu!
 zz ellipsenodesnumberfactor eps epsgeo epsilon evenodd expansionfactor extendcap fermionpen figureborder figuremattpen file3 firstnode firststep foregroundcolor fuchsia fuzz gapfactor ghostpen gist_earth gist_ncar gist_stern gluonamplitude gluonpen gluonratio gray green grey hatchepsilon havepagenumber heavyblue heavycyan heavygray heavygreen heavygrey heavymagenta heavyred hline hot hsv hwratio hyperbolanodesnumberfactor identity identity4 ignore implicitshipout inch inches includegraphicscommand inf inferno infinity institutionpen intMax intMin invert invisible itempen itemskip itemstep jet labelmargin landscape lastnode left legendhskip legendlinelength legendmargin legendmarkersize legendmaxrelativewidth legendvskip lightblue lightcyan lightgray lightgreen lightgrey lightmagenta lightolive lightred lightyellow linemargin lm_infmsg lm_shortmsg longdashdotted longdashed magenta magma magneticRadius mantissaBits markangleradius markangleradiusfactor markanglespace markanglespacefactor maxrefinements mediumblue mediumcyan mediumgray mediumgreen mediumgrey mediummagenta mediumred mediumyellow middle minDistDefault minblockheight minblockwidth mincirclediameter minipagemargin minipagewidth minvertexangle miterjoin mm momarrowfactor momarrowlength momarrowmargin momarrowoffset momarrowpen monoPen morepoints nCircle nan newbulletcolor ngraph nil nipy_spectral nmesh nobasealign nodeMarginDefault nodesystem nomarker nopoint noprimary nullpath nullpen numarray ocgindex oldbulletcolor olive orange origin overpaint page pageheight pagemargin pagenumberalign pagenumberpen pagenumberposition pagewidth paleblue palecyan palegray palegreen palegrey palemagenta palered paleyellow parabolanodesnumberfactor perpfactor phi photonamplitude photonpen photonratio pi pink plain plain_bounds plain_scaling plasma plus preamblenodes pt purple r3 r4a r4b randMax realDigits realEpsilon realMax realMin red relativesystem reverse right roundcap roundjoin royalblue salmon saveFunctions scalarpen seismic sequencereal settings signedtrailingz!
 ero simplex solid spinner spring springgreen sqrtEpsilon squarecap squarepen startposition stdin stdout stepfactor stepfraction steppagenumberpen stepping stickframe stickmarksizefactor stickmarkspacefactor summer swap tab10 tab20 tab20b tab20c textpen ticksize tildeframe tildemarksizefactor tinv titlealign titlepagepen titlepageposition titlepen titleskip top trailingzero treeLevelStep treeMinNodeWidth treeNodeStep trembleAngle trembleFrequency trembleRandom tubegranularity twilight twilight_shifted undefined unitcircle unitsquare up urlpen urlskip version vertexpen vertexsize viewportmargin viewportsize viridis vline white winter wistia wye yellow ylabelwidth zeroTransform zerotickfuzz zerowinding ))
+Accent AliceBlue Align Allow AntiqueWhite Apricot Aqua Aquamarine Aspect Azure BeginPoint Beige Bisque Bittersweet Black BlanchedAlmond Blue BlueGreen BlueViolet Blues Both BrBG Break BrickRed Brown BuGn BuPu BurlyWood BurntOrange CCW CMRmap CW CadetBlue CarnationPink Center Centered Cerulean Chartreuse Chocolate Coeff Coral CornflowerBlue Cornsilk Crimson Crop Cyan Dandelion Dark2 DarkBlue DarkCyan DarkGoldenrod DarkGray DarkGreen DarkKhaki DarkMagenta DarkOliveGreen DarkOrange DarkOrchid DarkRed DarkSalmon DarkSeaGreen DarkSlateBlue DarkSlateGray DarkTurquoise DarkViolet DeepPink DeepSkyBlue DefaultHead DimGray DodgerBlue Dotted Down Draw E ENE EPS ESE E_Euler E_PC E_RK2 E_RK3BS Emerald EndPoint Euler Fill FillDraw FireBrick FloralWhite ForestGreen Fuchsia Gainsboro GhostWhite GnBu Gold Goldenrod Gray Green GreenYellow Greens Greys Honeydew HookHead Horizontal HotPink I IgnoreAspect IndianRed Indigo Infinity Ivory JOIN_IN JOIN_OUT JungleGreen Khaki LM_DWARF LM_MACHEP LM_SQRT_DWARF LM_SQRT_GIANT LM_USERTOL Label Lavender LavenderBlush LawnGreen Left LeftJustified LeftSide LemonChiffon LightBlue LightCoral LightCyan LightGoldenrodYellow LightGreen LightGrey LightPink LightSalmon LightSeaGreen LightSkyBlue LightSlateGray LightSteelBlue LightYellow Lime LimeGreen Linear Linen Log Logarithmic Magenta Mahogany Mark MarkFill MarkFillable MarkPath Maroon Max MediumAquamarine MediumBlue MediumOrchid MediumPurple MediumSeaGreen MediumSlateBlue MediumSpringGreen MediumTurquoise MediumVioletRed Melon MidPoint MidnightBlue Min MintCream MistyRose Moccasin Move MoveQuiet Mulberry N NE NNE NNW NULL_VERTEX NW NavajoWhite Navy NavyBlue NoAlign NoCrop NoFill NoSide OldLace Olive OliveDrab OliveGreen OrRd Orange OrangeRed Oranges Orchid Ox Oy PC PRGn Paired PaleGoldenrod PaleGreen PaleTurquoise PaleVioletRed PapayaWhip Pastel1 Pastel2 Peach PeachPuff Periwinkle Peru PiYG PineGreen Pink Plum PowderBlue ProcessBlue PuBu PuBuGn PuOr PuRd Purple Purples RELEASE RK2 RK3 RK3BS RK4 RK5 RK5DP RK5F RawSienna RdBu RdGy RdPu RdYlB!
 u RdYlGn Red RedOrange RedViolet Reds Rhodamine Right RightJustified RightSide RosyBrown RoyalBlue RoyalPurple RubineRed S SE SSE SSW SW SaddleBrown Salmon SandyBrown SeaGreen Seashell Sepia Set1 Set2 Set3 Sienna Silver SimpleHead SkyBlue SlateBlue SlateGray Snow Spectral SpringGreen SteelBlue Suppress SuppressQuiet Tan TeXHead Teal TealBlue Thistle Ticksize Tomato Turquoise UnFill Up VERSION Value Vertical Violet VioletRed W WNW WSW Wheat White WhiteSmoke WildStrawberry XHIGH XLOW XYAlign YAlign YHIGH YLOW Yellow YellowGreen YellowOrange YlGn YlGnBu YlOrBr YlOrRd ZHIGH ZLOW _outpipe aboveequationskip addpenarc addpenline align allowstepping angularsystem animationdelay appendsuffix arcarrowangle arcarrowfactor arrow2sizelimit arrowangle arrowbarb arrowdir arrowfactor arrowhookfactor arrowlength arrowsizelimit arrowtexfactor authorpen autumn axis axiscoverage axislabelfactor background backgroundcolor backgroundpen barfactor barmarksizefactor basealign baselinetemplate bernstein beveljoin bigvertexpen bigvertexsize binary black blue bm bone bottom bp bracedefaultratio braceinnerangle bracemidangle braceouterangle brg brown bullet bwr byfoci byvertices camerafactor chartreuse circlemarkradiusfactor circlenodesnumberfactor circleprecision circlescale cividis cm codefile codepen codeskip colorPen coloredNodes coloredSegments conditionlength conicnodesfactor cool coolwarm copper count cputimeformat crossmarksizefactor currentcoordsys currentlight currentpatterns currentpen currentpicture currentposition currentprojection curvilinearsystem cuttings cyan darkblue darkbrown darkcyan darkgray darkgreen darkgrey darkmagenta darkolive darkred dashdotted dashed datepen dateskip debuggerlines debugging deepblue deepcyan deepgray deepgreen deepgrey deepmagenta deepred deepyellow default defaultControl defaultS defaultbackpen defaultcoordsys defaultexcursion defaultfilename defaultformat defaultmassformat defaultpen defaultseparator diamond differentlengths dot dotfactor dotfilltype dotframe dotted doublelinepen doublelinespa!
 cing down duplicateFuzz ellipsenodesnumberfactor eps epsgeo epsilon evenodd expansionfactor extendcap fermionpen figureborder figuremattpen file3 firstnode firststep foregroundcolor fuchsia fuzz gapfactor ghostpen gist_earth gist_ncar gist_stern gluonamplitude gluonpen gluonratio gray green grey hatchepsilon havepagenumber heavyblue heavycyan heavygray heavygreen heavygrey heavymagenta heavyred hline hot hsv hwratio hyperbolanodesnumberfactor identity identity4 ignore implicitshipout inch inches includegraphicscommand inf inferno infinity institutionpen intMax intMin invert invisible itempen itemskip itemstep jet labelmargin landscape lastnode left legendhskip legendlinelength legendmargin legendmarkersize legendmaxrelativewidth legendvskip lightblue lightcyan lightgray lightgreen lightgrey lightmagenta lightolive lightred lightyellow linemargin lm_infmsg lm_shortmsg longdashdotted longdashed magenta magma magneticRadius mantissaBits markangleradius markangleradiusfactor markanglespace markanglespacefactor maxrefinements mediumblue mediumcyan mediumgray mediumgreen mediumgrey mediummagenta mediumred mediumyellow middle minDistDefault minblockheight minblockwidth mincirclediameter minipagemargin minipagewidth minvertexangle miterjoin mm momarrowfactor momarrowlength momarrowmargin momarrowoffset momarrowpen monoPen morepoints nCircle nan newbulletcolor ngraph nil nipy_spectral nmesh nobasealign nodeMarginDefault nodesystem nomarker nopoint noprimary nullpath nullpen numarray ocgindex oldbulletcolor olive orange origin overpaint page pageheight pagemargin pagenumberalign pagenumberpen pagenumberposition pagewidth paleblue palecyan palegray palegreen palegrey palemagenta palered paleyellow parabolanodesnumberfactor perpfactor phi photonamplitude photonpen photonratio pi pink plain plain_bounds plain_scaling plasma plus preamblenodes pt purple r3 r4a r4b randMax realDigits realEpsilon realMax realMin red relativesystem reverse right roundcap roundjoin royalblue salmon saveFunctions scalarpen seismic sequencereal set!
 tings signedtrailingzero simplex solid spinner spring springgreen sqrtEpsilon squarecap squarepen startposition stdin stdout stepfactor stepfraction steppagenumberpen stepping stickframe stickmarksizefactor stickmarkspacefactor summer swap tab10 tab20 tab20b tab20c textpen ticksize tildeframe tildemarksizefactor tinv titlealign titlepagepen titlepageposition titlepen titleskip top trailingzero treeLevelStep treeMinNodeWidth treeNodeStep trembleAngle trembleFrequency trembleRandom tubegranularity twilight twilight_shifted undefined unitcircle unitsquare up urlpen urlskip v3dheadertypes v3dtypes version vertexpen vertexsize viewportmargin viewportsize viridis vline white winter wistia wye yellow ylabelwidth zeroTransform zerotickfuzz zerowinding ))

Modified: trunk/Master/texmf-dist/asymptote/asy-mode.el
===================================================================
--- trunk/Master/texmf-dist/asymptote/asy-mode.el	2022-02-27 23:39:53 UTC (rev 62264)
+++ trunk/Master/texmf-dist/asymptote/asy-mode.el	2022-02-27 23:41:11 UTC (rev 62265)
@@ -110,7 +110,7 @@
 
 (require 'font-lock)
 (require 'cc-mode)
-(require 'cl) ;; Common Lisp extensions for Emacs
+(require 'cl-lib) ;; Common Lisp extensions for Emacs
 (require 'compile)
 (require 'wid-edit)
 
@@ -637,6 +637,9 @@
 (if (locate-library "two-mode-mode")
     (progn
 
+;; patch two-mode-mode.el for Emacs >= 23.
+      (defun make-local-hook (func))
+
       (defvar lasy-fontify-asy-p nil
         "Variable to communicate with `font-lock-unfontify-region'.
 Internal use, don't set in any fashion.")
@@ -682,7 +685,8 @@
                  (setq lasy-fontify-asy-p (eq func 'asy-mode))
                  (funcall func)
                  (hack-local-variables)
-                 (two-mode-mode-setup)
+;; avoid infinite loop in two-mode-mode
+;;                 (two-mode-mode-setup)
                  (if two-mode-switch-hook
                      (run-hooks 'two-mode-switch-hook))
                  (if (eq font-lock-mode t)

Modified: trunk/Master/texmf-dist/asymptote/asy.vim
===================================================================
--- trunk/Master/texmf-dist/asymptote/asy.vim	2022-02-27 23:39:53 UTC (rev 62264)
+++ trunk/Master/texmf-dist/asymptote/asy.vim	2022-02-27 23:41:11 UTC (rev 62265)
@@ -1,7 +1,7 @@
 " Vim syntax file
-" Language:	Asymptote
-" Maintainer:	Andy Hammerlindl
-" Last Change:	2005 Aug 23
+" Language:     Asymptote
+" Maintainer:   Andy Hammerlindl
+" Last Change:  2022 Jan 05
 
 " Hacked together from Bram Moolenaar's C syntax file, and Claudio Fleiner's
 " Java syntax file.
@@ -9,133 +9,208 @@
 " For version 5.x: Clear all syntax items
 " For version 6.x: Quit when a syntax file was already loaded
 if version < 600
-  syntax clear
+  syn clear
 elseif exists("b:current_syntax")
   finish
 endif
 
-" A bunch of useful C keywords
-syn keyword	asyStatement	break return continue unravel
-syn keyword	asyConditional	if else
-syn keyword	asyRepeat	while for do
-syn keyword     asyExternal     access from import include
-syn keyword     asyOperator     new operator
+" useful C/C++/Java keywords
+syn keyword     asyStatement     break return continue unravel
+syn keyword     asyConditional   if else
+syn keyword     asyRepeat        while for do
+syn keyword     asyExternal      access from import include
+syn keyword     asyOperator      new operator
 
-syn keyword	asyTodo		contained TODO FIXME XXX
+" basic asymptote keywords
+syn keyword     asyConstant      VERSION
+syn keyword     asyConstant      true false default infinity inf nan
+syn keyword     asyConstant      null nullframe nullpath nullpen
+syn keyword     asyConstant      intMin intMax realMin realMax
+syn keyword     asyConstant      realEpsilon realDigits
+syn keyword     asyPathSpec      and cycle controls tension atleast curl
+syn keyword     asyStorageClass  static public restricted private explicit
+syn keyword     asyStructure     struct typedef
+syn keyword     asyType          void bool bool3 int real string file
+syn keyword     asyType          pair triple transform guide path pen frame
+syn keyword     asyType          picture
 
-" asyCommentGroup allows adding matches for special things in comments
-syn cluster	asyCommentGroup	contains=asyTodo
+" module specific keywords
+if exists("asy_syn_plain")
+  syn keyword   asyConstant      currentpicture currentpen defaultpen
+  syn keyword   asyConstant      inch inches cm mm bp pt up down right left
+  syn keyword   asyConstant      E NE N NW W SW S SE
+  syn keyword   asyConstant      ENE NNE NNW WNW WSW SSW SSE ESE
+  syn keyword   asyConstant      I pi twopi
+  syn keyword   asyConstant      CCW CW
+  syn keyword   asyConstant      undefined sqrtEpsilon Align mantissaBits
+  syn keyword   asyConstant      identity zeroTransform invert
+  syn keyword   asyConstant      stdin stdout
+  syn keyword   asyConstant      unitsquare unitcircle circleprecision
+  syn keyword   asyConstant      solid dotted Dotted dashed dashdotted
+  syn keyword   asyConstant      longdashed longdashdotted
+  syn keyword   asyConstant      squarecap roundcap extendcap
+  syn keyword   asyConstant      miterjoin roundjoin beveljoin
+  syn keyword   asyConstant      zerowinding evenodd basealign nobasealign
+  syn keyword   asyConstant      black white gray red green blue Cyan Magenta
+  syn keyword   asyConstant      Yellow Black cyan magenta yellow palered
+  syn keyword   asyConstant      palegreen paleblue palecyan palemagenta
+  syn keyword   asyConstant      paleyellow palegray lightred lightgreen
+  syn keyword   asyConstant      lightblue lightcyan lightmagenta lightyellow
+  syn keyword   asyConstant      lightgray mediumred mediumgreen mediumblue
+  syn keyword   asyConstant      mediumcyan mediummagenta mediumyellow
+  syn keyword   asyConstant      mediumgray heavyred heavygreen heavyblue
+  syn keyword   asyConstant      heavycyan heavymagenta lightolive heavygray
+  syn keyword   asyConstant      deepred deepgreen deepblue deepcyan
+  syn keyword   asyConstant      deepmagenta deepyellow deepgray darkred
+  syn keyword   asyConstant      darkgreen darkblue darkcyan darkmagenta
+  syn keyword   asyConstant      darkolive darkgray orange fuchsia chartreuse
+  syn keyword   asyConstant      springgreen purple royalblue salmon brown
+  syn keyword   asyConstant      olive darkbrown pink palegrey lightgrey
+  syn keyword   asyConstant      mediumgrey grey heavygrey deepgrey darkgrey
 
-" String and Character constants
-" Highlight special characters (those proceding a double backslash) differently
-syn match	asySpecial	display contained "\\\\."
-" Highlight line continuation slashes
-syn match	asySpecial	display contained "\\$"
-syn region	asyString	start=+"+ skip=+\\\\\|\\"+ end=+"+ contains=asySpecial
-  " asyCppString: same as asyString, but ends at end of line
-if 0
-syn region	asyCppString	start=+"+ skip=+\\\\\|\\"\|\\$+ excludenl end=+"+ end='$' contains=asySpecial
-endif
+  if exists("asy_syn_texcolors")
+    syn keyword asyConstant      GreenYellow Yellow Goldenrod Dandelion
+    syn keyword asyConstant      Apricot Peach Melon YellowOrange Orange
+    syn keyword asyConstant      BurntOrange Bittersweet RedOrange Mahogany
+    syn keyword asyConstant      Maroon BrickRed Red OrangeRed RubineRed
+    syn keyword asyConstant      WildStrawberry Salmon CarnationPink Magenta
+    syn keyword asyConstant      VioletRed Rhodamine Mulberry RedViolet
+    syn keyword asyConstant      Fuchsia Lavender Thistle Orchid DarkOrchid
+    syn keyword asyConstant      Purple Plum Violet RoyalPurple BlueViolet
+    syn keyword asyConstant      Periwinkle CadetBlue CornflowerBlue
+    syn keyword asyConstant      MidnightBlue NavyBlue RoyalBlue Blue
+    syn keyword asyConstant      Cerulean Cyan ProcessBlue SkyBlue Turquoise
+    syn keyword asyConstant      TealBlue Aquamarine BlueGreen Emerald
+    syn keyword asyConstant      JungleGreen SeaGreen Green ForestGreen
+    syn keyword asyConstant      PineGreen LimeGreen YellowGreen SpringGreen
+    syn keyword asyConstant      OliveGreen RawSienna Sepia Brown Tan Gray
+    syn keyword asyConstant      Black White
+  endif
 
-"when wanted, highlight trailing white space
-if exists("asy_space_errors")
-  if !exists("asy_no_trail_space_error")
-    syn match	asySpaceError	display excludenl "\s\+$"
+  if exists("asy_syn_x11colors")
+    syn keyword asyConstant      AliceBlue AntiqueWhite Aqua Aquamarine Azure
+    syn keyword asyConstant      Beige Bisque Black BlanchedAlmond Blue
+    syn keyword asyConstant      BlueViolet Brown BurlyWood CadetBlue
+    syn keyword asyConstant      Chartreuse Chocolate Coral CornflowerBlue
+    syn keyword asyConstant      Cornsilk Crimson Cyan DarkBlue DarkCyan
+    syn keyword asyConstant      DarkGoldenrod DarkGray DarkGreen DarkKhaki
+    syn keyword asyConstant      DarkMagenta DarkOliveGreen DarkOrange
+    syn keyword asyConstant      DarkOrchid DarkRed DarkSalmon DarkSeaGreen
+    syn keyword asyConstant      DarkSlateBlue DarkSlateGray DarkTurquoise
+    syn keyword asyConstant      DarkViolet DeepPink DeepSkyBlue DimGray
+    syn keyword asyConstant      DodgerBlue FireBrick FloralWhite ForestGreen
+    syn keyword asyConstant      Fuchsia Gainsboro GhostWhite Gold Goldenrod
+    syn keyword asyConstant      Gray Green GreenYellow Honeydew HotPink
+    syn keyword asyConstant      IndianRed Indigo Ivory Khaki Lavender
+    syn keyword asyConstant      LavenderBlush LawnGreen LemonChiffon
+    syn keyword asyConstant      LightBlue LightCoral LightCyan
+    syn keyword asyConstant      LightGoldenrodYellow LightGreen LightGrey
+    syn keyword asyConstant      LightPink LightSalmon LightSeaGreen
+    syn keyword asyConstant      LightSkyBlue LightSlateGray LightSteelBlue
+    syn keyword asyConstant      LightYellow Lime LimeGreen Linen Magenta
+    syn keyword asyConstant      Maroon MediumAquamarine MediumBlue
+    syn keyword asyConstant      MediumOrchid MediumPurple MediumSeaGreen
+    syn keyword asyConstant      MediumSlateBlue MediumSpringGreen
+    syn keyword asyConstant      MediumTurquoise MediumVioletRed MidnightBlue
+    syn keyword asyConstant      MintCream MistyRose Moccasin NavajoWhite
+    syn keyword asyConstant      Navy OldLace Olive OliveDrab Orange
+    syn keyword asyConstant      OrangeRed Orchid PaleGoldenrod PaleGreen
+    syn keyword asyConstant      PaleTurquoise PaleVioletRed PapayaWhip
+    syn keyword asyConstant      PeachPuff Peru Pink Plum PowderBlue Purple
+    syn keyword asyConstant      Red RosyBrown RoyalBlue SaddleBrown Salmon
+    syn keyword asyConstant      SandyBrown SeaGreen Seashell Sienna Silver
+    syn keyword asyConstant      SkyBlue SlateBlue SlateGray Snow SpringGreen
+    syn keyword asyConstant      SteelBlue Tan Teal Thistle Tomato Turquoise
+    syn keyword asyConstant      Violet Wheat White WhiteSmoke Yellow
+    syn keyword asyConstant      YellowGreen
   endif
-  if !exists("asy_no_tab_space_error")
-    syn match	asySpaceError	display " \+\t"me=e-1
+
+  if exists("asy_syn_three")
+    syn keyword asyType          path3 guide3 transform3
+    syn keyword asyType          projection light material patch surface tube
+    syn keyword asyConstant      currentprojection currentlight defaultrender
+    syn keyword asyConstant      identity4 O X Y Z
+    syn keyword asyConstant      nolight nullpens
+    syn keyword asyConstant      unitsphere unithemisphere unitplane octant1
+    syn keyword asyConstant      unitcone unitsolidcone unitcube unitcylinder
+    syn keyword asyConstant      unitdisk unittube
   endif
 endif
 
-"catch errors caused by wrong parenthesis and brackets
-syn cluster	asyParenGroup	contains=asyParenError,asyIncluded,asySpecial,asyCommentSkip,asyCommentString,asyComment2String, at asyCommentGroup,asyCommentStartError,asyUserCont,asyUserLabel,asyBitField,asyCommentSkip,asyOctalZero,asyCppOut,asyCppOut2,asyCppSkip,asyFormat,asyNumber,asyFloat,asyOctal,asyOctalError,asyNumbersCom
-if exists("asy_no_bracket_error")
-  syn region	asyParen		transparent start='(' end=')' contains=ALLBUT, at asyParenGroup,asyCppParen,asyCppString
-  " asyCppParen: same as asyParen but ends at end-of-line; used in asyDefine
-  syn region	asyCppParen	transparent start='(' skip='\\$' excludenl end=')' end='$' contained contains=ALLBUT, at asyParenGroup,asyParen,asyString
-  syn match	asyParenError	display ")"
-  syn match	asyErrInParen	display contained "[{}]"
-else
-  syn region	asyParen	transparent start='(' end=')' contains=ALLBUT, at asyParenGroup,asyCppParen,asyErrInBracket,asyCppBracket,asyCppString
-  " asyCppParen: same as asyParen but ends at end-of-line; used in asyDefine
-  syn region	asyCppParen	transparent start='(' skip='\\$' excludenl end=')' end='$' contained contains=ALLBUT, at asyParenGroup,asyErrInBracket,asyParen,asyBracket,asyString
-if 0
-  syn match	asyParenError	display "[\])]"
-  syn match	asyErrInParen	display contained "[\]]"
-endif
-  syn region	asyBracket	transparent start='\[' end=']' contains=ALLBUT, at asyParenGroup,asyErrInParen,asyCppParen,asyCppBracket,asyCppString
-  " asyCppBracket: same as asyParen but ends at end-of-line; used in asyDefine
-  syn region	asyCppBracket	transparent start='\[' skip='\\$' excludenl end=']' end='$' contained contains=ALLBUT, at asyParenGroup,asyErrInParen,asyParen,asyBracket,asyString
-  syn match	asyErrInBracket	display contained "[);]"
-endif
 
-"integer number, or floating point number without a dot and with "f".
-syn case ignore
-syn match	asyNumbers	display transparent "\<\d\|\.\d" contains=asyNumber,asyFloat
-syn match       asyNumber       display contained "\d\+"
-"floating point number, with dot, optional exponent
-syn match	asyFloat	display contained "\d\+\.\d*\(e[-+]\=\d\+\)\="
-"floating point number, starting with a dot, optional exponent
-syn match	asyFloat	display contained "\.\d\+\(e[-+]\=\d\+\)\="
-"floating point number, without dot, with exponent
-syn match	asyFloat	display contained "\d\+e[-+]\=\d\+"
-syn case match
+" string constants
+syn region asyCString start=+'+ end=+'+ skip=+\\\\\|\\'+ contains=asyCSpecial
+syn match  asyCSpecial display contained +\\\(['"?\\abfnrtv]\|\o\{1,3}\)+
+syn match  asyCSpecial display contained +\\\(x[0-9A-F]\{1,2\}\|$\)+
+" double quoted strings only special character is \"
+syn region asyString   start=+"+ end=+"+ skip=+\\\\\|\\"+ contains=asySpecial
+syn match  asySpecial  display contained +\(\\\)\@1<!\(\\\\\)*\zs\\"+
 
+
+" number constants
+syn match  asyNumbers     display transparent "\<\d\|\.\d"
+                        \ contains=asyNumber,asyNumberError
+syn match  asyNumber      display contained "\d*\.\=\d*\(e[-+]\=\d\+\)\="
+" highlight number constants with two '.' or with '.' after an 'e'
+syn match  asyNumberError display contained "\d*\.\(\d\|e[-+]\=\)*\.[0-9.]*"
+syn match  asyNumberError display contained "\d*e[-+]\=\d*\.[0-9.]*"
+syn match  asyNumberError display contained "\d*e[-+]\=\(e[-+]\=\)*\.[0-9.]*"
+
+
+" comments and comment strings
+syn keyword  asyTodo            contained TODO FIXME XXX
+syn sync     ccomment           asyComment minlines=15
 if exists("asy_comment_strings")
-  " A comment can contain asyString, asyCharacter and asyNumber.
-  " But a "*/" inside a asyString in a asyComment DOES end the comment!  So we
-  " need to use a special type of asyString: asyCommentString, which also ends on
+  " A comment can contain asyString, asyCString, and asyNumber. But a "*/"
+  " inside a asy*String in a asyComment DOES end the comment!  So we need to
+  " use a special type of asy*String: asyComment*String, which also ends on
   " "*/", and sees a "*" at the start of the line as comment again.
   " Unfortunately this doesn't very well work for // type of comments :-(
-  syntax match	asyCommentSkip	contained "^\s*\*\($\|\s\+\)"
-  syntax region asyCommentString	contained start=+L\="+ skip=+\\\\\|\\"+ end=+"+ end=+\*/+me=s-1 contains=asySpecial,asyCommentSkip
-  syntax region asyComment2String	contained start=+L\="+ skip=+\\\\\|\\"+ end=+"+ end="$" contains=asySpecial
-  syntax region  asyCommentL	start="//" skip="\\$" end="$" keepend contains=@asyCommentGroup,asyComment2String,asyCharacter,asyNumbersCom,asySpaceError
-  syntax region asyComment	matchgroup=asyCommentStart start="/\*" matchgroup=NONE end="\*/" contains=@asyCommentGroup,asyCommentStartError,asyCommentString,asyCharacter,asyNumbersCom,asySpaceError
+  syn match  asyCommentSkip     contained "^\s*\*\($\|\s\+\)"
+  syn region asyCommentString   contained start=+"+ skip=+\\\\\|\\"+ end=+"+
+                              \ end=+\*/+me=s-1
+                              \ contains=asySpecial,asyCommentSkip
+  syn region asyCommentCString  contained start=+'+ skip=+\\\\\|\\'+ end=+'+
+                              \ end=+\*/+me=s-1
+                              \ contains=asyCSpecial,asyCommentSkip
+  syn region asyCommentLString  contained start=+"+ skip=+\\\\\|\\"+ end=+"+
+                              \ end="$" contains=asySpecial
+  syn region asyCommentLCString contained start=+'+ skip=+\\\\\|\\'+ end=+'+
+                              \ end="$" contains=asyCSpecial
+  syn region asyCommentL        start="//" skip="\\$" end="$" keepend
+                              \ contains=asyTodo,asyCommentLString,
+                              \ asyCommentLCString,asyNumbers
+  syn region asyComment         matchgroup=asyComment start="/\*" end="\*/"
+                              \ contains=asyTodo,asyCommentStartError,
+                              \ asyCommentString,asyCommentCString,asyNumbers
 else
-  syn region	asyCommentL	start="//" skip="\\$" end="$" keepend contains=@asyCommentGroup,asySpaceError
-  syn region	asyComment	matchgroup=asyCommentStart start="/\*" matchgroup=NONE end="\*/" contains=@asyCommentGroup,asyCommentStartError,asySpaceError
+  syn region asyCommentL        start="//" skip="\\$" end="$" keepend
+                              \ contains=asyTodo
+  syn region asyComment         matchgroup=asyComment start="/\*" end="\*/"
+                              \ contains=asyTodo,asyCommentStartError
 endif
-" keep a // comment separately, it terminates a preproc. conditional
-syntax match	asyCommentError	display "\*/"
-syntax match	asyCommentStartError display "/\*"me=e-1 contained
 
-syn keyword	asyType		void bool int real string
-syn keyword	asyType		pair triple transform guide path pen frame
-syn keyword     asyType         picture
+" highlight common errors when starting/ending C comments
+syn match    asyCommentError      display "\*/"
+syn match    asyCommentStartError display "/\*"me=e-1 contained
 
-syn keyword	asyStructure	struct typedef
-syn keyword     asyStorageClass static public readable private explicit
 
-syn keyword     asyPathSpec     and cycle controls tension atleast curl
+" delimiter matching errors
+syn region asyCurly      transparent start='{'  end='}'
+                       \ contains=TOP,asyCurlyError
+syn region asyBrack      transparent start='\[' end='\]' matchgroup=asyError
+                       \ end=';' contains=TOP,asyBrackError
+syn region asyParen      transparent start='('  end=')'  matchgroup=asyError
+                       \ end=';' contains=TOP,asyParenError
+syn match  asyCurlyError display '}'
+syn match  asyBrackError display '\]'
+syn match  asyParenError display ')'
+" for (;;) constructs are exceptions that allow ; inside parenthesis
+syn region asyParen      transparent matchgroup=asyParen
+                       \ start='\(for\s*\)\@<=(' end=')'
+                       \ contains=TOP,asyParenError
 
-syn keyword     asyConstant     true false
-syn keyword     asyConstant     null nullframe nullpath
 
-if exists("asy_syn_plain")
-  syn keyword	asyConstant	currentpicture currentpen currentprojection
-  syn keyword	asyConstant	inch inches cm mm bp pt up down right left 
-  syn keyword	asyConstant	E NE N NW W SW S SE
-  syn keyword	asyConstant	ENE NNE NNW WNW WSW SSW SSE ESE
-  syn keyword	asyConstant	I pi twopi
-  syn keyword	asyConstant	solid dotted dashed dashdotted
-  syn keyword	asyConstant	longdashed longdashdotted
-  syn keyword	asyConstant	squarecap roundcap extendcap
-  syn keyword	asyConstant	miterjoin roundjoin beveljoin
-  syn keyword	asyConstant	zerowinding evenodd
-  syn keyword	asyConstant	invisible black gray grey white
-  syn keyword	asyConstant	lightgray lightgrey
-  syn keyword	asyConstant	red green blue
-  syn keyword	asyConstant	cmyk Cyan Magenta Yellow Black
-  syn keyword	asyConstant	yellow magenta cyan
-  syn keyword	asyConstant	brown darkgreen darkblue
-  syn keyword	asyConstant	orange purple royalblue olive
-  syn keyword	asyConstant	chartreuse fuchsia salmon lightblue springgreen
-  syn keyword	asyConstant	pink
-endif
-
-syn sync ccomment asyComment minlines=15
-
 " Define the default highlighting.
 " For version 5.7 and earlier: only when not done already
 " For version 5.8 and later: only when an item doesn't have highlighting yet
@@ -147,56 +222,39 @@
     command -nargs=+ HiLink hi def link <args>
   endif
 
-  HiLink asyFormat		asySpecial
-  HiLink asyCppString		asyString
-  HiLink asyCommentL		asyComment
-  HiLink asyCommentStart		asyComment
-  HiLink asyLabel			Label
-  HiLink asyUserLabel		Label
-  HiLink asyConditional		Conditional
-  HiLink asyRepeat		Repeat
-  HiLink asyCharacter		Character
-  HiLink asySpecialCharacter	asySpecial
-  HiLink asyNumber		Number
-  HiLink asyOctal			Number
-  HiLink asyOctalZero		PreProc	 " link this to Error if you want
-  HiLink asyFloat			Float
-  HiLink asyOctalError		asyError
-  HiLink asyParenError		asyError
-  HiLink asyErrInParen		asyError
-  HiLink asyErrInBracket		asyError
-  HiLink asyCommentError		asyError
-  HiLink asyCommentStartError	asyError
-  HiLink asySpaceError		asyError
-  HiLink asySpecialError		asyError
-  HiLink asyOperator		Operator
-  HiLink asyStructure		Structure
-  HiLink asyStorageClass		StorageClass
-  HiLink asyExternal		Include
-  HiLink asyPreProc		PreProc
-  HiLink asyDefine		Macro
-  HiLink asyIncluded		asyString
-  HiLink asyError			Error
-  HiLink asyStatement		Statement
-  HiLink asyPreCondit		PreCondit
-  HiLink asyType			Type
-  HiLink asyConstant		Constant
-  HiLink asyCommentString		asyString
-  HiLink asyComment2String	asyString
-  HiLink asyCommentSkip		asyComment
-  HiLink asyString		String
-  HiLink asyComment		Comment
-  HiLink asySpecial		SpecialChar
-  HiLink asyTodo			Todo
-  HiLink asyCppSkip		asyCppOut
-  HiLink asyCppOut2		asyCppOut
-  HiLink asyCppOut		Comment
-  HiLink asyPathSpec		Statement
-		
+  HiLink asyCommentL             asyComment
+  HiLink asyConditional          Conditional
+  HiLink asyRepeat               Repeat
+  HiLink asyNumber               Number
+  HiLink asyNumberError          asyError
+  HiLink asyCurlyError           asyError
+  HiLink asyBracketError         asyError
+  HiLink asyParenError           asyError
+  HiLink asyCommentError         asyError
+  HiLink asyCommentStartError    asyError
+  HiLink asyOperator             Operator
+  HiLink asyStructure            Structure
+  HiLink asyStorageClass         StorageClass
+  HiLink asyExternal             Include
+  HiLink asyDefine               Macro
+  HiLink asyError                Error
+  HiLink asyStatement            Statement
+  HiLink asyType                 Type
+  HiLink asyConstant             Constant
+  HiLink asyCommentString        asyString
+  HiLink asyCommentCString       asyString
+  HiLink asyCommentLString       asyString
+  HiLink asyCommentLCString      asyString
+  HiLink asyCommentSkip          asyComment
+  HiLink asyString               String
+  HiLink asyCString              String
+  HiLink asyComment              Comment
+  HiLink asySpecial              SpecialChar
+  HiLink asyCSpecial             SpecialChar
+  HiLink asyTodo                 Todo
+  HiLink asyPathSpec             Statement
 
   delcommand HiLink
 endif
 
 let b:current_syntax = "c"
-
-" vim: ts=8

Modified: trunk/Master/texmf-dist/asymptote/geometry.asy
===================================================================
--- trunk/Master/texmf-dist/asymptote/geometry.asy	2022-02-27 23:39:53 UTC (rev 62264)
+++ trunk/Master/texmf-dist/asymptote/geometry.asy	2022-02-27 23:41:11 UTC (rev 62265)
@@ -6051,7 +6051,7 @@
   return triangle(A, B, C);
 }
 
-/*<asyxml><function type="triangle" signature="extouch(triangle)"><code></asyxml>*/
+/*<asyxml><function type="triangle" signature="incentral(triangle)"><code></asyxml>*/
 triangle incentral(triangle t)
 {/*<asyxml></code><documentation>Return the incentral triangle of the triangle 't'.
    It is the triangle whose vertices are determined by the intersections of the

Modified: trunk/Master/texmf-dist/asymptote/graph.asy
===================================================================
--- trunk/Master/texmf-dist/asymptote/graph.asy	2022-02-27 23:39:53 UTC (rev 62264)
+++ trunk/Master/texmf-dist/asymptote/graph.asy	2022-02-27 23:41:11 UTC (rev 62265)
@@ -2090,6 +2090,29 @@
     },0,0,n-1);
 }
 
+// Graph a parametric function with the control points specified to match the
+// derivative.
+guide graphwithderiv(pair f(real), pair fprime(real), real a, real b,
+                     int n=ngraph # 10) {
+  guide toreturn;
+  real segmentlen = (b - a) / n;
+  pair[] points = new pair[n+1];
+  pair[] derivs = new pair[n+1];
+  real derivfactor = segmentlen / 3;
+  for (int i = 0; i <= n; ++i) {
+    real t = interp(a, b, i/n);
+    points[i] = f(t);
+    derivs[i] = fprime(t) * derivfactor;
+  }
+
+  toreturn = points[0];
+  for (int i = 1; i <= n; ++i) {
+    toreturn = toreturn .. controls (points[i-1] + derivs[i-1])
+      and (points[i] - derivs[i]) .. points[i];
+  }
+  return toreturn;
+}
+
 void errorbar(picture pic, pair z, pair dp, pair dm, pen p=currentpen,
               real size=0)
 {

Modified: trunk/Master/texmf-dist/asymptote/math.asy
===================================================================
--- trunk/Master/texmf-dist/asymptote/math.asy	2022-02-27 23:39:53 UTC (rev 62264)
+++ trunk/Master/texmf-dist/asymptote/math.asy	2022-02-27 23:41:11 UTC (rev 62265)
@@ -325,9 +325,9 @@
 private string nopoint="point not found";
 
 // Return the nth intersection time of path g with the vertical line through x.
-real time(path g, real x, int n=0)
+real time(path g, real x, int n=0, real fuzz=-1)
 {
-  real[] t=times(g,x);
+  real[] t=times(g,x,fuzz);
   if(t.length <= n) abort(nopoint);
   return t[n];
 }
@@ -334,36 +334,36 @@
 
 // Return the nth intersection time of path g with the horizontal line through
 // (0,z.y).
-real time(path g, explicit pair z, int n=0)
+real time(path g, explicit pair z, int n=0, real fuzz=-1)
 {
-  real[] t=times(g,z);
+  real[] t=times(g,z,fuzz);
   if(t.length <= n) abort(nopoint);
   return t[n];
 }
 
 // Return the nth y value of g at x.
-real value(path g, real x, int n=0)
+real value(path g, real x, int n=0, real fuzz=-1)
 {
-  return point(g,time(g,x,n)).y;
+  return point(g,time(g,x,n,fuzz)).y;
 }
 
 // Return the nth x value of g at y=z.y.
-real value(path g, explicit pair z, int n=0)
+real value(path g, explicit pair z, int n=0, real fuzz=-1)
 {
-  return point(g,time(g,(0,z.y),n)).x;
+  return point(g,time(g,(0,z.y),n,fuzz)).x;
 }
 
 // Return the nth slope of g at x.
-real slope(path g, real x, int n=0)
+real slope(path g, real x, int n=0, real fuzz=-1)
 {
-  pair a=dir(g,time(g,x,n));
+  pair a=dir(g,time(g,x,n,fuzz));
   return a.y/a.x;
 }
 
 // Return the nth slope of g at y=z.y.
-real slope(path g, explicit pair z, int n=0)
+real slope(path g, explicit pair z, int n=0, real fuzz=-1)
 {
-  pair a=dir(g,time(g,(0,z.y),n));
+  pair a=dir(g,time(g,(0,z.y),n,fuzz));
   return a.y/a.x;
 }
 

Modified: trunk/Master/texmf-dist/asymptote/palette.asy
===================================================================
--- trunk/Master/texmf-dist/asymptote/palette.asy	2022-02-27 23:39:53 UTC (rev 62264)
+++ trunk/Master/texmf-dist/asymptote/palette.asy	2022-02-27 23:41:11 UTC (rev 62265)
@@ -65,7 +65,7 @@
 private real[] sequencereal;
 
 bounds image(picture pic=currentpicture, real[][] f, range range=Full,
-             pair initial, pair final, pen[] palette,
+             pair initial, pair final, pen[] palette, int divs=0,
              bool transpose=(initial.x < final.x && initial.y < final.y),
              bool copy=true, bool antialias=false)
 {
@@ -74,6 +74,7 @@
 
   real m=min(f);
   real M=max(f);
+
   bounds bounds=range(pic,m,M);
   real rmin=pic.scale.z.T(bounds.min);
   real rmax=pic.scale.z.T(bounds.max);
@@ -89,6 +90,21 @@
       f[i]=map(new real(real x) {return T(min(max(x,m),M));},f[i]);
   }
 
+  if(divs > 0) {
+    int nx=f.length;
+    int ny=f[0].length;
+    real[][] data=new real[nx][ny];
+    real incr=(M-m)/divs;
+    for(int i=0; i < nx; ++i) {
+      // Take center point of each bin
+      real[] fi=f[i];
+      data[i]=sequence(new real(int j) {
+          return min(m+floor((fi[j]-m)/incr)*incr,M-incr);
+        },ny);
+    }
+    f=data;
+  }
+
   initial=Scale(pic,initial);
   final=Scale(pic,final);
 
@@ -109,7 +125,8 @@
 
 bounds image(picture pic=currentpicture, real f(real, real),
              range range=Full, pair initial, pair final,
-             int nx=ngraph, int ny=nx, pen[] palette, bool antialias=false)
+             int nx=ngraph, int ny=nx, pen[] palette, int divs=0,
+             bool antialias=false)
 {
   // Generate data, taking scaling into account
   real xmin=pic.scale.x.T(initial.x);
@@ -116,6 +133,7 @@
   real xmax=pic.scale.x.T(final.x);
   real ymin=pic.scale.y.T(initial.y);
   real ymax=pic.scale.y.T(final.y);
+
   real[][] data=new real[ny][nx];
   for(int j=0; j < ny; ++j) {
     real y=pic.scale.y.Tinv(interp(ymin,ymax,(j+0.5)/ny));
@@ -125,7 +143,8 @@
         return f(Tinv(interp(xmin,xmax,(i+0.5)/nx)),y);
       },nx);
   }
-  return image(pic,data,range,initial,final,palette,transpose=false,
+
+  return image(pic,data,range,initial,final,palette,divs,transpose=false,
                copy=false,antialias=antialias);
 }
 

Modified: trunk/Master/texmf-dist/asymptote/patterns.asy
===================================================================
--- trunk/Master/texmf-dist/asymptote/patterns.asy	2022-02-27 23:39:53 UTC (rev 62264)
+++ trunk/Master/texmf-dist/asymptote/patterns.asy	2022-02-27 23:41:11 UTC (rev 62265)
@@ -13,7 +13,9 @@
 /XStep "+format(s,pmax.x-pmin.x,"C")+"
 /YStep "+format(s,pmax.y-pmin.y,"C")+"
 /PaintProc {pop");
+  gsave(tiling);
   add(tiling,f);
+  grestore(tiling);
   postscript(tiling,"} >>
  matrix makepattern
 /"+name+" exch def");
@@ -99,4 +101,3 @@
   add(tiling,shift(H*sqrt(2))*rotate(90)*hatch(H,p));
   return tiling;
 }
-

Modified: trunk/Master/texmf-dist/asymptote/plain.asy
===================================================================
--- trunk/Master/texmf-dist/asymptote/plain.asy	2022-02-27 23:39:53 UTC (rev 62264)
+++ trunk/Master/texmf-dist/asymptote/plain.asy	2022-02-27 23:41:11 UTC (rev 62265)
@@ -150,9 +150,15 @@
 // Return the sequence n,...,m
 int[] sequence(int n, int m)
 {
-  return sequence(new int(int x){return x;},m-n+1)+n;
+  return n+sequence(m-n+1);
 }
 
+// Return the sequence n,...,m skipping by skip
+int[] sequence(int n, int m, int skip)
+{
+  return n+skip*sequence((m-n)#skip+1);
+}
+
 int[] reverse(int n) {return sequence(new int(int x){return n-1-x;},n);}
 bool[] reverse(bool[] a) {return a[reverse(a.length)];}
 int[] reverse(int[] a) {return a[reverse(a.length)];}

Modified: trunk/Master/texmf-dist/asymptote/plain_boxes.asy
===================================================================
--- trunk/Master/texmf-dist/asymptote/plain_boxes.asy	2022-02-27 23:39:53 UTC (rev 62264)
+++ trunk/Master/texmf-dist/asymptote/plain_boxes.asy	2022-02-27 23:41:11 UTC (rev 62265)
@@ -28,7 +28,7 @@
   (dw,b)--(a-dw,b){right}..{down}
   (a,b-dw)--(a,dw){down}..{left}
   (a-dw,0)--(dw,0){left}..{up}cycle);
-  
+
   frame F;
   if(above == false) {
     filltype.fill(F,g,p);
@@ -81,7 +81,7 @@
                       filltype filltype=NoFill, bool above=true);
 
 object object(Label L, envelope e, real xmargin=0, real ymargin=xmargin,
-	      pen p=currentpen, filltype filltype=NoFill, bool above=true) 
+	      pen p=currentpen, filltype filltype=NoFill, bool above=true)
 {
   object F;
   F.L=L.copy();
@@ -93,9 +93,9 @@
   return F;
 }
 
-object draw(picture pic=currentpicture, Label L, envelope e, 
+object draw(picture pic=currentpicture, Label L, envelope e,
 	    real xmargin=0, real ymargin=xmargin, pen p=currentpen,
-	    filltype filltype=NoFill, bool above=true) 
+	    filltype filltype=NoFill, bool above=true)
 {
   object F=object(L,e,xmargin,ymargin,p,filltype,above);
   pic.add(new void (frame f, transform t) {
@@ -115,7 +115,7 @@
   return draw(pic,Label(L,position),e,xmargin,ymargin,p,filltype,above);
 }
 
-pair point(object F, pair dir, transform t=identity()) 
+pair point(object F, pair dir, transform t=identity())
 {
   pair m=min(F.g);
   pair M=max(F.g);

Modified: trunk/Master/texmf-dist/asymptote/plain_constants.asy
===================================================================
--- trunk/Master/texmf-dist/asymptote/plain_constants.asy	2022-02-27 23:39:53 UTC (rev 62264)
+++ trunk/Master/texmf-dist/asymptote/plain_constants.asy	2022-02-27 23:41:11 UTC (rev 62265)
@@ -31,9 +31,9 @@
 restricted pair SSW=unit(S+SW);
 restricted pair SSE=unit(S+SE);
 restricted pair ESE=unit(E+SE);
-  
+
 restricted real sqrtEpsilon=sqrt(realEpsilon);
-restricted pair Align=sqrtEpsilon*NE; 
+restricted pair Align=sqrtEpsilon*NE;
 restricted int mantissaBits=ceil(-log(realEpsilon)/log(2))+1;
 
 restricted transform identity;
@@ -108,7 +108,7 @@
   else write("default",suffix);
 }
 
-void write(string s="", bool3 b, suffix suffix=endl) 
+void write(string s="", bool3 b, suffix suffix=endl)
 {
   write(stdout,s,b,suffix);
 }
@@ -128,32 +128,32 @@
   return B;
 }
 
-bool operator == (bool3 a, bool3 b) 
+bool operator == (bool3 a, bool3 b)
 {
   return a.set == b.set && (!a.set || (a.value == b.value));
 }
 
-bool operator != (bool3 a, bool3 b) 
+bool operator != (bool3 a, bool3 b)
 {
   return a.set != b.set || (a.set && (a.value != b.value));
 }
 
-bool operator == (bool3 a, bool b) 
+bool operator == (bool3 a, bool b)
 {
   return a.set && a.value == b;
 }
 
-bool operator != (bool3 a, bool b) 
+bool operator != (bool3 a, bool b)
 {
   return !a.set || a.value != b;
 }
 
-bool operator == (bool a, bool3 b) 
+bool operator == (bool a, bool3 b)
 {
   return b.set && b.value == a;
 }
 
-bool operator != (bool a, bool3 b) 
+bool operator != (bool a, bool3 b)
 {
   return !b.set || b.value != a;
 }

Modified: trunk/Master/texmf-dist/asymptote/plain_filldraw.asy
===================================================================
--- trunk/Master/texmf-dist/asymptote/plain_filldraw.asy	2022-02-27 23:39:53 UTC (rev 62264)
+++ trunk/Master/texmf-dist/asymptote/plain_filldraw.asy	2022-02-27 23:41:11 UTC (rev 62265)
@@ -3,7 +3,7 @@
 {
   if(depth == 0) return;
   --depth;
-  
+
   path n=nib(p);
   for(int i=0; i < size(g); ++i)
     fill(f,shift(point(g,i))*n,p);
@@ -88,7 +88,7 @@
   fill(f,complement(f,g),p+evenodd,copy);
 }
 
-struct filltype 
+struct filltype
 {
   typedef void fill2(frame f, path[] g, pen fillpen);
   fill2 fill2;
@@ -101,7 +101,7 @@
   static int Draw=3;
   static int NoFill=4;
   static int UnFill=5;
-      
+
   void operator init(int type=0, pen fillpen=nullpen, pen drawpen=nullpen,
                      fill2 fill2) {
     this.type=type;
@@ -112,7 +112,7 @@
   void fill(frame f, path[] g, pen p) {fill2(f,g,p);}
 }
 
-path[] margin(path[] g, real xmargin, real ymargin) 
+path[] margin(path[] g, real xmargin, real ymargin)
 {
   if(xmargin != 0 || ymargin != 0) {
     pair M=max(g);
@@ -123,7 +123,7 @@
     real yfactor=height > 0 ? (height+2ymargin)/height : 1;
     g=scale(xfactor,yfactor)*g;
     g=shift(0.5*(M+m)-0.5*(max(g)+min(g)))*g;
-  }   
+  }
   return g;
 }
 
@@ -174,7 +174,7 @@
     });
 }
 
-filltype FillDraw=FillDraw(), Fill=Fill(), Draw=Draw(), UnFill=UnFill(); 
+filltype FillDraw=FillDraw(), Fill=Fill(), Draw=Draw(), UnFill=UnFill();
 
 // Fill varying radially from penc at the center of the bounding box to
 // penr at the edge.

Modified: trunk/Master/texmf-dist/asymptote/plain_margins.asy
===================================================================
--- trunk/Master/texmf-dist/asymptote/plain_margins.asy	2022-02-27 23:39:53 UTC (rev 62264)
+++ trunk/Master/texmf-dist/asymptote/plain_margins.asy	2022-02-27 23:41:11 UTC (rev 62265)
@@ -27,7 +27,7 @@
 }
 
 margin NoMargin()
-{ 
+{
   return new marginT(path g, pen) {
     marginT margin;
     margin.begin=margin.end=0;
@@ -35,9 +35,9 @@
     return margin;
   };
 }
-                                                      
+
 margin Margin(real begin, real end=begin)
-{ 
+{
   return new marginT(path g, pen p) {
     marginT margin;
     real factor=labelmargin(p);
@@ -47,9 +47,9 @@
     return margin;
   };
 }
-                                                           
+
 margin PenMargin(real begin, real end=begin)
-{ 
+{
   return new marginT(path g, pen p) {
     marginT margin;
     real factor=linewidth(p);
@@ -59,9 +59,9 @@
     return margin;
   };
 }
-                                              
+
 margin DotMargin(real begin, real end=begin)
-{ 
+{
   return new marginT(path g, pen p) {
     marginT margin;
     real margindot(real x) {return x > 0 ? dotfactor*x : x;}
@@ -72,9 +72,9 @@
     return margin;
   };
 }
-                                                      
+
 margin TrueMargin(real begin, real end=begin)
-{ 
+{
   return new marginT(path g, pen p) {
     marginT margin;
     margin.begin=begin;
@@ -83,7 +83,7 @@
     return margin;
   };
 }
-                                                      
+
 margin NoMargin=NoMargin(),
   BeginMargin=Margin(1,0),
   Margin=Margin(0,1),

Modified: trunk/Master/texmf-dist/asymptote/plain_markers.asy
===================================================================
--- trunk/Master/texmf-dist/asymptote/plain_markers.asy	2022-02-27 23:39:53 UTC (rev 62264)
+++ trunk/Master/texmf-dist/asymptote/plain_markers.asy	2022-02-27 23:41:11 UTC (rev 62265)
@@ -5,7 +5,7 @@
 real legendmaxrelativewidth=1;
 
 // Return a unit polygon with n sides.
-path polygon(int n) 
+path polygon(int n)
 {
   guide g;
   for(int i=0; i < n; ++i) g=g--expi(2pi*(i+0.5)/n-0.5*pi);
@@ -14,7 +14,7 @@
 
 // Return a unit n-point cyclic cross, with optional inner radius r and
 // end rounding.
-path cross(int n, bool round=true, real r=0) 
+path cross(int n, bool round=true, real r=0)
 {
   assert(n > 1);
   real r=min(r,1);
@@ -41,7 +41,8 @@
   return g--cycle;
 }
 
-path[] plus=(-1,0)--(1,0)^^(0,-1)--(0,1);
+path plus=rotate(45)*cross(4);
+path diamond=rotate(45)*polygon(4);
 
 typedef void markroutine(picture pic=currentpicture, frame f, path g);
 
@@ -98,9 +99,9 @@
     markroutine(pic,f,g);
   };
 }
-  
+
 marker marker(frame f=newframe, markroutine markroutine=marknodes,
-              bool above=true) 
+              bool above=true)
 {
   marker m=new marker;
   m.f=f;
@@ -147,15 +148,18 @@
 
 path[] MarkPath={scale(circlescale)*unitcircle,
                  polygon(3),polygon(4),polygon(5),invert*polygon(3),
-                 cross(4),cross(6)};
+                 cross(4),cross(6),diamond,plus};
 
+int[] MarkFillable={0,1,2,3,4,7};
+
 marker[] Mark=sequence(new marker(int i) {return marker(MarkPath[i]);},
                        MarkPath.length);
 
-marker[] MarkFill=sequence(new marker(int i) {return marker(MarkPath[i],Fill);},
-                           MarkPath.length-2);
+marker[] MarkFill=sequence(new marker(int i) {
+    return marker(MarkPath[MarkFillable[i]],Fill);
+  },MarkFillable.length);
 
-marker Mark(int n) 
+marker Mark(int n)
 {
   n=n % (Mark.length+MarkFill.length);
   if(n < Mark.length) return Mark[n];
@@ -194,7 +198,7 @@
   if(Legend.length == 0)
     return inset;
 
-  // Check for legend entries with lines: 
+  // Check for legend entries with lines:
   bool bLineEntriesAvailable=false;
   for(int i=0; i < Legend.length; ++i) {
     if(Legend[i].p != invisible) {
@@ -231,8 +235,8 @@
       totalwidth += size(pic).x;
     }
   }
-  // Does everything fit into one line? 
-  if(((perline < 1) || (perline >= Legend.length)) && 
+  // Does everything fit into one line?
+  if(((perline < 1) || (perline >= Legend.length)) &&
      (maxwidth >= totalwidth+(totalwidth/Legend.length)*
       (Legend.length-1)*(hskip-1))) {
     // One-line legend
@@ -285,7 +289,7 @@
              real xmargin=legendmargin, real ymargin=xmargin,
              real linelength=legendlinelength,
              real hskip=legendhskip, real vskip=legendvskip,
-             real maxwidth=perline == 0 ? 
+             real maxwidth=perline == 0 ?
              legendmaxrelativewidth*size(pic).x : 0, real maxheight=0,
 	     bool hstretch=false, bool vstretch=false, pen p=currentpen)
 {
@@ -312,7 +316,7 @@
   if(filltype == Fill)
     draw(f,z,dotsize(p)+p);
   else {
-    real s=0.5*(dotsize(p)-linewidth(p));  
+    real s=0.5*(dotsize(p)-linewidth(p));
     if(s <= 0) return;
     path g=shift(z)*scale(s)*unitcircle;
     begingroup(f);
@@ -398,4 +402,4 @@
 }
 
 marker dot=dot();
-    
+

Modified: trunk/Master/texmf-dist/asymptote/plain_paths.asy
===================================================================
--- trunk/Master/texmf-dist/asymptote/plain_paths.asy	2022-02-27 23:39:53 UTC (rev 62264)
+++ trunk/Master/texmf-dist/asymptote/plain_paths.asy	2022-02-27 23:41:11 UTC (rev 62265)
@@ -51,32 +51,32 @@
   return new path[] {(path) g};
 }
 
-path[] operator ^^ (path p, path q) 
+path[] operator ^^ (path p, path q)
 {
   return new path[] {p,q};
 }
 
-path[] operator ^^ (path p, explicit path[] q) 
+path[] operator ^^ (path p, explicit path[] q)
 {
   return concat(new path[] {p},q);
 }
 
-path[] operator ^^ (explicit path[] p, path q) 
+path[] operator ^^ (explicit path[] p, path q)
 {
   return concat(p,new path[] {q});
 }
 
-path[] operator ^^ (explicit path[] p, explicit path[] q) 
+path[] operator ^^ (explicit path[] p, explicit path[] q)
 {
   return concat(p,q);
 }
 
-path[] operator * (transform t, explicit path[] p) 
+path[] operator * (transform t, explicit path[] p)
 {
   return sequence(new path(int i) {return t*p[i];},p.length);
 }
 
-pair[] operator * (transform t, pair[] z) 
+pair[] operator * (transform t, pair[] z)
 {
   return sequence(new pair(int i) {return t*z[i];},z.length);
 }
@@ -93,7 +93,7 @@
   write(file,suffix);
 }
 
-void write(string s="", explicit path[] x, suffix suffix=endl) 
+void write(string s="", explicit path[] x, suffix suffix=endl)
 {
   write(stdout,s,x,suffix);
 }
@@ -110,7 +110,7 @@
   write(file,suffix);
 }
 
-void write(string s="", explicit guide[] x, suffix suffix=endl) 
+void write(string s="", explicit guide[] x, suffix suffix=endl)
 {
   write(stdout,s,x,suffix);
 }
@@ -156,8 +156,8 @@
 struct slice {
   path before,after;
 }
-  
-slice cut(path p, path knife, int n) 
+
+slice cut(path p, path knife, int n)
 {
   slice s;
   real[][] T=intersections(p,knife);
@@ -169,7 +169,7 @@
   return s;
 }
 
-slice firstcut(path p, path knife) 
+slice firstcut(path p, path knife)
 {
   return cut(p,knife,0);
 }
@@ -331,16 +331,16 @@
 }
 
 // Return all intersection times of path g with the vertical line through (x,0).
-real[] times(path p, real x)
+real[] times(path p, real x, real fuzz=-1)
 {
-  return intersections(p,(x,0),(x,1));
+  return intersections(p,(x,0),(x,1),fuzz);
 }
 
 // Return all intersection times of path g with the horizontal line through
 // (0,z.y).
-real[] times(path p, explicit pair z)
+real[] times(path p, explicit pair z, real fuzz=-1)
 {
-  return intersections(p,(0,z.y),(1,z.y));
+  return intersections(p,(0,z.y),(1,z.y),fuzz);
 }
 
 path randompath(int n, bool cumulate=true, interpolate join=operator ..)
@@ -349,7 +349,7 @@
   pair w;
   for(int i=0; i <= n; ++i) {
     pair z=(unitrand()-0.5,unitrand()-0.5);
-    if(cumulate) w += z; 
+    if(cumulate) w += z;
     else w=z;
     g=join(g,w);
   }

Modified: trunk/Master/texmf-dist/asymptote/plain_pens.asy
===================================================================
--- trunk/Master/texmf-dist/asymptote/plain_pens.asy	2022-02-27 23:39:53 UTC (rev 62264)
+++ trunk/Master/texmf-dist/asymptote/plain_pens.asy	2022-02-27 23:41:11 UTC (rev 62265)
@@ -8,7 +8,7 @@
 pen dashdotted=linetype(new real[] {8,8,0,8});
 pen longdashdotted=linetype(new real[] {24,8,0,8});
 
-pen linetype(string pattern, real offset=0, bool scale=true, bool adjust=true) 
+pen linetype(string pattern, real offset=0, bool scale=true, bool adjust=true)
 {
   return linetype((real[]) split(pattern),offset,scale,adjust);
 }
@@ -151,7 +151,7 @@
                longdashdotted};
 monoPen.cyclic=true;
 
-pen Pen(int n) 
+pen Pen(int n)
 {
   return (settings.gray || settings.bw) ? monoPen[n] : colorPen[n];
 }
@@ -161,12 +161,12 @@
   return (settings.gray || settings.bw) ? monoPen[n] : monoPen[n]+colorPen[n];
 }
 
-real dotsize(pen p=currentpen) 
+real dotsize(pen p=currentpen)
 {
   return dotfactor*linewidth(p);
 }
 
-pen fontsize(real size) 
+pen fontsize(real size)
 {
   return fontsize(size,1.2*size);
 }
@@ -189,7 +189,7 @@
   texpreamble(s);
 }
 
-pen font(string name, string options="") 
+pen font(string name, string options="")
 {
   // Work around misalignment in ConTeXt switchtobodyfont if font is not found.
   return fontcommand(settings.tex == "context" ?
@@ -199,7 +199,7 @@
                      "\font\ASYfont="+name+"\ASYfont");
 }
 
-pen font(string name, real size, string options="") 
+pen font(string name, real size, string options="")
 {
   string s=(string) (size/pt)+"pt";
   if(settings.tex == "context")
@@ -207,7 +207,7 @@
   return fontsize(size)+font(name+" at "+s);
 }
 
-pen font(string encoding, string family, string series, string shape) 
+pen font(string encoding, string family, string series, string shape)
 {
   return fontcommand("\usefont{"+encoding+"}{"+family+"}{"+series+"}{"+shape+
                      "}");
@@ -316,6 +316,11 @@
   return a;
 }
 
+pen rgb(real[] a)
+{
+  return rgb(a[0],a[1],a[2]);
+}
+
 pen rgba(real[] a)
 {
   return rgb(a[0],a[1],a[2])+opacity(a[3]);
@@ -322,10 +327,10 @@
 }
 
 // Return a pen corresponding to a given 6-character RGB hexadecimal string.
-pen rgb(string s) 
+pen rgb(string s)
 {
   int offset=substr(s,0,1) == '#' ? 1 : 0;
-  real value(string s, int i) {return hex(substr(s,2i+offset,2))/255;}
+  real value(string s, int i) {return byteinv(hex(substr(s,2i+offset,2)));}
   return rgb(value(s,0),value(s,1),value(s,2));
 }
 

Modified: trunk/Master/texmf-dist/asymptote/plain_picture.asy
===================================================================
--- trunk/Master/texmf-dist/asymptote/plain_picture.asy	2022-02-27 23:39:53 UTC (rev 62264)
+++ trunk/Master/texmf-dist/asymptote/plain_picture.asy	2022-02-27 23:41:11 UTC (rev 62265)
@@ -59,10 +59,10 @@
     }
   }
 }
-  
+
 // scaleT and Legend <<<
 typedef real scalefcn(real x);
-                                              
+
 struct scaleT {
   scalefcn T,Tinv;
   bool logarithmic;
@@ -86,7 +86,7 @@
   scaleT S=scaleT(identity,identity);
   return S;
 }
-                                  
+
 typedef void boundRoutine();
 
 struct autoscaleT {
@@ -97,11 +97,11 @@
   bool automin=false, automax=false;
   bool automin() {return automin && scale.automin;}
   bool automax() {return automax && scale.automax;}
-  
+
   real T(real x) {return postscale.T(scale.T(x));}
   scalefcn T() {return scale.logarithmic ? postscale.T : T;}
   real Tinv(real x) {return scale.Tinv(postscale.Tinv(x));}
-  
+
   autoscaleT copy() {
     autoscaleT dest=new autoscaleT;
     dest.scale=scale.copy();
@@ -120,7 +120,7 @@
   autoscaleT x;
   autoscaleT y;
   autoscaleT z;
-  
+
   ScaleT copy() {
     ScaleT dest=new ScaleT;
     dest.set=set;
@@ -240,15 +240,15 @@
       return b;
     }
   }
-  
+
   bounds bounds;
   bounds3 bounds3;
-    
+
   // Other Fields <<<2
   // Transform to be applied to this picture.
   transform T;
   transform3 T3;
-  
+
   // The internal representation of the 3D user bounds.
   private pairOrTriple umin, umax;
   private bool usetx, usety, usetz;
@@ -267,7 +267,7 @@
   // Fixed unitsizes in the x y, and z directions; zero means use
   // xsize, ysize, and zsize.
   real xunitsize=0, yunitsize=0, zunitsize=0;
-  
+
   // If true, the x and y directions must be scaled by the same amount.
   bool keepAspect=true;
 
@@ -274,7 +274,7 @@
   // A fixed scaling transform.
   bool fixed;
   transform fixedscaling;
-  
+
   // Init and erase <<<2
   void init() {
     umin.init();
@@ -283,7 +283,7 @@
     T3=identity(4);
   }
   init();
-  
+
   // Erase the current picture, retaining bounds.
   void clear() {
     nodes.delete();
@@ -300,7 +300,7 @@
     scale=new ScaleT;
     init();
   }
-  
+
   // Empty <<<2
   bool empty2() {
     return nodes.length == 0;
@@ -313,7 +313,7 @@
   bool empty() {
     return empty2() && empty3();
   }
-  
+
   // User min/max <<<2
   pair userMin2() {return bounds.userMin(); }
   pair userMax2() {return bounds.userMax(); }
@@ -373,27 +373,27 @@
     umin.x=x;
     usetx=true;
   }
-  
+
   void userMiny3(real y) {
     umin.y=y;
     usety=true;
   }
-  
+
   void userMinz3(real z) {
     umin.z=z;
     usetz=true;
   }
-  
+
   void userMaxx3(real x) {
     umax.x=x;
     usetx=true;
   }
-  
+
   void userMaxy3(real y) {
     umax.y=y;
     usety=true;
   }
-  
+
   void userMaxz3(real z) {
     umax.z=z;
     usetz=true;
@@ -409,7 +409,7 @@
   void userMaxy(real y) { userMaxy2(y); userMaxy3(y); }
   void userMinz(real z) = userMinz3;
   void userMaxz(real z) = userMaxz3;
-  
+
   void userCorners3(triple c000, triple c001, triple c010, triple c011,
                     triple c100, triple c101, triple c110, triple c111) {
     umin.x = min(c000.x,c001.x,c010.x,c011.x,c100.x,c101.x,c110.x,c111.x);
@@ -419,7 +419,7 @@
     umax.y = max(c000.y,c001.y,c010.y,c011.y,c100.y,c101.y,c110.y,c111.y);
     umax.z = max(c000.z,c001.z,c010.z,c011.z,c100.z,c101.z,c110.z,c111.z);
   }
-  
+
   // Cache the current user-space bounding box x coodinates
   void userBoxX3(real min, real max, binop m=min, binop M=max) {
     if (usetx) {
@@ -462,7 +462,7 @@
     userBoxY3(min.y,max.y);
     userBoxZ3(min.z,max.z);
   }
-  
+
   // Add drawer <<<2
   void add(drawerBound d, bool exact=false, bool above=true) {
     uptodate=false;
@@ -472,7 +472,7 @@
     else
       nodes.insert(0,node(d));
   }
-  
+
   // Faster implementation of most common case.
   void addExactAbove(drawerBound d) {
     uptodate=false;
@@ -518,13 +518,13 @@
     bounds.addPoint(user,truesize);
     //userBox(user,user);
   }
-  
+
   // Add a point to the sizing, accounting also for the size of the pen.
   void addPoint(pair user, pair truesize=0, pen p) {
     addPoint(user,truesize+min(p));
     addPoint(user,truesize+max(p));
   }
-  
+
   void addPoint(triple user, triple truesize=(0,0,0)) {
     bounds3.point.push(user,truesize);
     userBox3(user,user);
@@ -618,7 +618,7 @@
   }
 
   void append(coords3 point, coords3 min, coords3 max, transform3 t,
-              bounds3 bounds) 
+              bounds3 bounds)
   {
     // Add the coord info to this picture.
     if(t == identity4) {
@@ -638,7 +638,7 @@
       point.push(t,bounds.max,bounds.max,bounds.max);
     }
   }
-  
+
   // Scaling and Fit <<<2
   // Returns the transform for turning user-space pairs into true-space pairs.
   transform scaling(real xsize, real ysize, bool keepAspect=true,
@@ -660,9 +660,9 @@
       return identity(4);
 
     coords3 Coords;
-    
+
     append(Coords,Coords,Coords,T3,bounds3);
-    
+
     real sx;
     if(xunitsize == 0) {
       if(xsize != 0) sx=calculateScaling("x",Coords.x,xsize,warn);
@@ -709,7 +709,7 @@
              triple m, triple M) {
     frame f;
     for(node3 n : nodes3) {
-      xasyKEY(n.key);
+      xasyKEY(nodes3[0].key);
       n.d(f,t,T0,pic,P,m,M);
     }
     return f;
@@ -757,7 +757,7 @@
     frame f=fit(fixedscaling);
     pair d=size(f);
     static real epsilon=100*realEpsilon;
-    if(d.x > xsize*(1+epsilon)) 
+    if(d.x > xsize*(1+epsilon))
       warning("xlimit","frame exceeds xlimit: "+(string) d.x+" > "+
               (string) xsize);
     if(d.y > ysize*(1+epsilon))
@@ -765,7 +765,7 @@
               (string) ysize);
     return f;
   }
-  
+
   // Calculate additional scaling required if only an approximate picture
   // size estimate is available.
   transform scale(frame f, real xsize=this.xsize, real ysize=this.ysize,
@@ -836,24 +836,24 @@
            bool keepAspect=this.keepAspect, bool warn=true) {
     return min(calculateTransform(xsize,ysize,keepAspect,warn));
   }
-  
+
   pair max(real xsize=this.xsize, real ysize=this.ysize,
            bool keepAspect=this.keepAspect, bool warn=true) {
     return max(calculateTransform(xsize,ysize,keepAspect,warn));
   }
-  
+
   triple min3(real xsize=this.xsize3, real ysize=this.ysize3,
               real zsize=this.zsize3, bool keepAspect=this.keepAspect,
               bool warn=true, projection P) {
     return min(calculateTransform3(xsize,ysize,zsize,keepAspect,warn,P));
   }
-  
+
   triple max3(real xsize=this.xsize3, real ysize=this.ysize3,
               real zsize=this.zsize3, bool keepAspect=this.keepAspect,
               bool warn=true, projection P) {
     return max(calculateTransform3(xsize,ysize,zsize,keepAspect,warn,P));
   }
-  
+
   // More Fitting <<<2
   // Returns the 2D picture fit to the requested size.
   frame fit2(real xsize=this.xsize, real ysize=this.ysize,
@@ -880,7 +880,7 @@
       fitter(prefix,this,format,xsize,ysize,keepAspect,view,options,script,
              light,P);
   }
-  
+
   // Fit a 3D picture.
   frame fit3(projection P=currentprojection) {
     if(settings.render == 0) return fit(P);
@@ -895,7 +895,7 @@
 
   // In case only an approximate picture size estimate is available, return the
   // fitted frame slightly scaled (including labels and true size distances)
-  // so that it precisely meets the given size specification. 
+  // so that it precisely meets the given size specification.
   frame scale(real xsize=this.xsize, real ysize=this.ysize,
               bool keepAspect=this.keepAspect) {
     frame f=fit(xsize,ysize,keepAspect);
@@ -905,7 +905,7 @@
   }
 
   // Copying <<<2
-  
+
   // Copies enough information to yield the same userMin/userMax.
   void userCopy2(picture pic) {
     userMinx2(pic.userMin2().x);
@@ -921,12 +921,12 @@
     usety=pic.usety;
     usetz=pic.usetz;
   }
-  
+
   void userCopy(picture pic) {
     userCopy2(pic);
     userCopy3(pic);
   }
-  
+
   // Copies the drawing information, but not the sizing information into a new
   // picture. Fitting this picture will not scale as the original picture would.
   picture drawcopy() {
@@ -954,7 +954,7 @@
     dest.uptodate=uptodate;
     dest.bounds=bounds.copy();
     dest.bounds3=bounds3.copy();
-    
+
     dest.xsize=xsize; dest.ysize=ysize;
     dest.xsize3=xsize; dest.ysize3=ysize3; dest.zsize3=zsize3;
     dest.keepAspect=keepAspect;
@@ -961,7 +961,7 @@
     dest.xunitsize=xunitsize; dest.yunitsize=yunitsize;
     dest.zunitsize=zunitsize;
     dest.fixed=fixed; dest.fixedscaling=fixedscaling;
-    
+
     return dest;
   }
 
@@ -984,7 +984,7 @@
     dest.uptodate=uptodate;
     dest.bounds=bounds.transformed(t);
     dest.bounds3=bounds3.copy();
-    
+
     dest.bounds.exact=false;
 
     dest.xsize=xsize; dest.ysize=ysize;
@@ -993,7 +993,7 @@
     dest.xunitsize=xunitsize; dest.yunitsize=yunitsize;
     dest.zunitsize=zunitsize;
     dest.fixed=fixed; dest.fixedscaling=fixedscaling;
-    
+
     return dest;
   }
 
@@ -1007,7 +1007,7 @@
     // objects added to it that should not be included in this picture.
 
     if(src == this) abort("cannot add picture to itself");
-    
+
     uptodate=false;
 
     picture srcCopy=src.drawcopy();
@@ -1018,7 +1018,7 @@
           add(f,srcCopy.fit(t,T*srcCopy.T,m,M),group,filltype,above);
           }));
     }
-    
+
     if(srcCopy.nodes3.length > 0) {
       nodes3.push(node3(new void(frame f, transform3 t, transform3 T3,
                                  picture pic, projection P, triple m, triple M)
@@ -1026,13 +1026,13 @@
                     add(f,srcCopy.fit3(t,T3*srcCopy.T3,pic,P,m,M),group,above);
                         }));
     }
-    
+
     legend.append(src.legend);
-    
+
     if(src.usetx) userBoxX3(src.umin.x,src.umax.x);
     if(src.usety) userBoxY3(src.umin.y,src.umax.y);
     if(src.usetz) userBoxZ3(src.umin.z,src.umax.z);
-    
+
     bounds.append(srcCopy.T, src.bounds);
     //append(bounds.point,bounds.min,bounds.max,srcCopy.T,src.bounds);
     append(bounds3.point,bounds3.min,bounds3.max,srcCopy.T3,src.bounds3);
@@ -1087,7 +1087,7 @@
   pic.size3(x,y,z,keepAspect);
 }
 
-void unitsize(picture pic=currentpicture, real x, real y=x, real z=y) 
+void unitsize(picture pic=currentpicture, real x, real y=x, real z=y)
 {
   pic.unitsize(x,y,z);
 }
@@ -1113,7 +1113,7 @@
   pair z=pic.min(t);
   return user ? inverse(t)*z : z;
 }
-  
+
 pair max(picture pic, bool user=false)
 {
   transform t=pic.calculateTransform();
@@ -1120,7 +1120,7 @@
   pair z=pic.max(t);
   return user ? inverse(t)*z : z;
 }
-  
+
 pair size(picture pic, bool user=false)
 {
   transform t=pic.calculateTransform();
@@ -1132,7 +1132,7 @@
 }
 
 // Frame Alignment <<<
-pair rectify(pair dir) 
+pair rectify(pair dir)
 {
   real scale=max(abs(dir.x),abs(dir.y));
   if(scale != 0) dir *= 0.5/scale;
@@ -1161,13 +1161,13 @@
 }
 
 // Returns a transform for aligning frame f in the direction align
-transform shift(frame f, pair align) 
+transform shift(frame f, pair align)
 {
   return shift(align-point(f,-align));
 }
 
 // Returns a copy of frame f aligned in the direction align
-frame align(frame f, pair align) 
+frame align(frame f, pair align)
 {
   return shift(f,align)*f;
 }
@@ -1448,7 +1448,7 @@
 }
 
 void beginclip(picture pic=currentpicture, path[] g, bool stroke=false,
-               pen fillrule=currentpen, bool copy=true) 
+               pen fillrule=currentpen, bool copy=true)
 {
   if(copy)
     g=copy(g);
@@ -1505,7 +1505,7 @@
   pic.addPath(g);
 }
 
-// Use a fixed scaling to map user coordinates in box(min,max) to the 
+// Use a fixed scaling to map user coordinates in box(min,max) to the
 // desired picture size.
 transform fixedscaling(picture pic=currentpicture, pair min, pair max,
                        pen p=nullpen, bool warn=false)
@@ -1671,7 +1671,7 @@
 void end(picture pic=currentpicture)
 {
   if(!latex() || !pdf()) return;
-  tex(pic,"\end{ocg}");
+  tex(pic,"\end{ocg}%");
   layer(pic);
 }
 

Modified: trunk/Master/texmf-dist/asymptote/plain_prethree.asy
===================================================================
--- trunk/Master/texmf-dist/asymptote/plain_prethree.asy	2022-02-27 23:39:53 UTC (rev 62264)
+++ trunk/Master/texmf-dist/asymptote/plain_prethree.asy	2022-02-27 23:41:11 UTC (rev 62265)
@@ -76,7 +76,7 @@
   bool center=false;    // Center target within bounding volume?
   int ninterpolate;     // Used for projecting nurbs to 2D Bezier curves.
   bool bboxonly=true;   // Typeset label bounding box only.
-  
+
   transformation T;
 
   void calculate() {
@@ -137,8 +137,8 @@
                 (M.x,m.y,m.z),(M.x,m.y,M.z),(M.x,M.y,m.z),M};
     return max(abs(c-target));
   }
-   
-  
+
+
   // This is redefined here to make projection as self-contained as possible.
   static private real sqrtEpsilon = sqrt(realEpsilon);
 
@@ -161,7 +161,7 @@
 
 struct light {
   real[][] diffuse;
-  real[][] specular;
+  real[][] specular; // For PRC only
   pen background=nullpen; // Background color of the 3D canvas.
   real specularfactor;
   triple[] position; // Only directional lights are currently implemented.
@@ -169,7 +169,7 @@
   transform3 T=identity(4); // Transform to apply to normal vectors.
 
   bool on() {return position.length > 0;}
-  
+
   void operator init(pen[] diffuse,
                      pen[] specular=diffuse, pen background=nullpen,
                      real specularfactor=1,
@@ -176,7 +176,7 @@
                      triple[] position) {
     int n=diffuse.length;
     assert(specular.length == n && position.length == n);
-    
+
     this.diffuse=new real[n][];
     this.specular=new real[n][];
     this.background=background;
@@ -213,4 +213,3 @@
 }
 
 light currentlight;
-

Modified: trunk/Master/texmf-dist/asymptote/plain_scaling.asy
===================================================================
--- trunk/Master/texmf-dist/asymptote/plain_scaling.asy	2022-02-27 23:39:53 UTC (rev 62264)
+++ trunk/Master/texmf-dist/asymptote/plain_scaling.asy	2022-02-27 23:41:11 UTC (rev 62265)
@@ -19,7 +19,7 @@
   coord copy() {
     return build(user, truesize);
   }
-  
+
   void clip(real min, real max) {
     user=min(max(user,min),max);
     truesize=0;
@@ -47,7 +47,7 @@
   coord[] c;
 
   int n=in.length;
-  
+
   if(n == 0)
     return c;
 
@@ -151,15 +151,15 @@
     }
   }
   void xclip(real min, real max) {
-    for(int i=0; i < x.length; ++i) 
+    for(int i=0; i < x.length; ++i)
       x[i].clip(min,max);
   }
   void yclip(real min, real max) {
-    for(int i=0; i < y.length; ++i) 
+    for(int i=0; i < y.length; ++i)
       y[i].clip(min,max);
   }
 }
-  
+
 // The scaling in one dimension:  x --> a*x + b
 struct scaling {
   real a,b;
@@ -211,7 +211,7 @@
     // (a*user + b) + truesize >= 0:
     A.push(new real[] {c.user,1,-1});
     b.push(-c.truesize);
-  }     
+  }
   void addMaxCoord(coord c) {
     // (a*user + b) + truesize <= size:
     A.push(new real[] {-c.user,-1,1});
@@ -239,12 +239,12 @@
         if(coord.user != 0) return false;
       return true;
     }
-    
+
     if((userzero(m) && userzero(M)) || size >= infinity) return 1;
-    
+
     warning("cannotfit","cannot fit picture to "+dir+"size "+(string) size
             +"...enlarging...");
-    
+
     return calculateScaling(dir,m,M,expansionfactor*size,warn);
   }
 }

Modified: trunk/Master/texmf-dist/asymptote/plain_shipout.asy
===================================================================
--- trunk/Master/texmf-dist/asymptote/plain_shipout.asy	2022-02-27 23:39:53 UTC (rev 62264)
+++ trunk/Master/texmf-dist/asymptote/plain_shipout.asy	2022-02-27 23:41:11 UTC (rev 62265)
@@ -11,7 +11,7 @@
   return stripextension(prefix != "" ? prefix : outname());
 }
 
-string outformat(string format="") 
+string outformat(string format="")
 {
   if(format == "") format=settings.outformat;
   if(format == "") format=nativeformat();
@@ -32,6 +32,10 @@
 string Embed(string name, string text="", string options="", real width=0,
              real height=0);
 
+bool primitive() { // Encode primitive objects
+  return settings.outformat == "html" || settings.outformat=="v3d";
+}
+
 bool prconly(string format="")
 {
   return outformat(format) == "prc";
@@ -39,7 +43,7 @@
 
 bool prc0(string format="")
 {
-  return settings.prc && (outformat(format) == "pdf" || prconly() || settings.inlineimage );
+  return settings.outformat == "prc" || (settings.prc && (outformat(format) == "pdf" || prconly() || settings.inlineimage ));
 }
 
 bool prc(string format="") {
@@ -62,6 +66,14 @@
 
 void deconstruct(picture pic=currentpicture)
 {
+  if(currentpicture.nodes3.length > 0) {
+    if(currentpicture.xsize3 == 0 &&
+       currentpicture.ysize3 == 0 &&
+       currentpicture.zsize3 == 0)
+      currentpicture.size3(hypot(currentpicture.xsize,currentpicture.ysize));
+    currentpicture.size(0);
+  }
+
   frame f;
   transform t=pic.calculateTransform();
   if(currentpicture.fitter == null)
@@ -95,7 +107,7 @@
     }
     return;
   }
-  
+
   // Applications like LaTeX cannot handle large PostScript coordinates.
   pair m=min(f);
   int limit=2000;

Modified: trunk/Master/texmf-dist/asymptote/plain_strings.asy
===================================================================
--- trunk/Master/texmf-dist/asymptote/plain_strings.asy	2022-02-27 23:39:53 UTC (rev 62264)
+++ trunk/Master/texmf-dist/asymptote/plain_strings.asy	2022-02-27 23:41:11 UTC (rev 62265)
@@ -49,13 +49,13 @@
 
 // returns a string with all occurrences of string 'before' in string 's'
 // changed to string 'after'.
-string replace(string s, string before, string after) 
+string replace(string s, string before, string after)
 {
   return replace(s,new string[][] {{before,after}});
 }
 
 // Like texify but don't convert embedded TeX commands: \${}
-string TeXify(string s) 
+string TeXify(string s)
 {
   static string[][] t={{"&","\&"},{"%","\%"},{"_","\_"},{"#","\#"},{"<","$<$"},
                        {">","$>$"},{"|","$|$"},{"^","$\hat{\ }$"},
@@ -68,7 +68,7 @@
 private string[][] trans2={{"\backslash ","$\backslash$"}};
 
 // Convert string to TeX
-string texify(string s) 
+string texify(string s)
 {
   return TeXify(replace(replace(s,trans1),trans2));
 }
@@ -93,7 +93,7 @@
     prune=true;
     delimiter=" ";
   }
-  
+
   string[] S;
   int last=0;
   int i;
@@ -130,7 +130,7 @@
   return S;
 }
 
-int system(string s) 
+int system(string s)
 {
   return system(split(s));
 }
@@ -161,8 +161,8 @@
   return s != "" ? "{\it "+s+"}" : s;
 }
 
-string baseline(string s, string template="\strut") 
-{ 
+string baseline(string s, string template="\strut")
+{
   return s != "" && settings.tex != "none" ? "\vphantom{"+template+"}"+s : s;
 }
 
@@ -171,7 +171,7 @@
   return s != "" ? "$"+s+"$" : s;
 }
 
-private void notimplemented(string text) 
+private void notimplemented(string text)
 {
   abort(text+" is not implemented for the '"+settings.tex+"' TeX engine");
 }
@@ -217,7 +217,7 @@
   texpreamble(usepackage+"{"+s+"}");
 }
 
-void pause(string w="Hit enter to continue") 
+void pause(string w="Hit enter to continue")
 {
   write(w);
   w=stdin;

Modified: trunk/Master/texmf-dist/asymptote/pstoedit.asy
===================================================================
--- trunk/Master/texmf-dist/asymptote/pstoedit.asy	2022-02-27 23:39:53 UTC (rev 62264)
+++ trunk/Master/texmf-dist/asymptote/pstoedit.asy	2022-02-27 23:41:11 UTC (rev 62265)
@@ -15,4 +15,4 @@
       grestore(f);
     },true);
 }
-    
+

Modified: trunk/Master/texmf-dist/asymptote/rational.asy
===================================================================
--- trunk/Master/texmf-dist/asymptote/rational.asy	2022-02-27 23:39:53 UTC (rev 62264)
+++ trunk/Master/texmf-dist/asymptote/rational.asy	2022-02-27 23:41:11 UTC (rev 62265)
@@ -11,7 +11,7 @@
     int r=m % n;
     m=n;
     n=r;
-  }       
+  }
   return m;
 }
 

Modified: trunk/Master/texmf-dist/asymptote/roundedpath.asy
===================================================================
--- trunk/Master/texmf-dist/asymptote/roundedpath.asy	2022-02-27 23:39:53 UTC (rev 62264)
+++ trunk/Master/texmf-dist/asymptote/roundedpath.asy	2022-02-27 23:41:11 UTC (rev 62265)
@@ -1,7 +1,7 @@
 // a function to round sharp edges of open and cyclic paths
 // written by stefan knorr
 
-path roundedpath(path A, real R, real S = 1)                   
+path roundedpath(path A, real R, real S = 1)
 // create rounded path from path A with radius R and scale S = 1
 {
   path RoundPath;                   // returned path
@@ -9,20 +9,20 @@
   path LocalCirc;                   // local edge circle for intersection
   real LocalTime;                   // local intersectiontime between . and ..
   pair LocalPair;                   // local point to be added to 'RoundPath'
-            
-  int len=length(A);              // length of given path 'A' 
+
+  int len=length(A);              // length of given path 'A'
   bool PathClosed=cyclic(A);      // true, if given path 'A' is cyclic
 
   // initialisation: define first Point of 'RoundPath' as
   if (PathClosed)                         // ? is 'A' cyclic
-    RoundPath=scale(S)*point(point(A,0)--point(A,1), 0.5);  // centerpoint of first straight subpath of 'A'  
+    RoundPath=scale(S)*point(point(A,0)--point(A,1), 0.5);  // centerpoint of first straight subpath of 'A'
   else
     RoundPath=scale(S)*point(A,0);            // first point of 'A'
 
-  // doing everything between start and end 
-  // create round paths subpath by subpath for every i-th edge 
+  // doing everything between start and end
+  // create round paths subpath by subpath for every i-th edge
   for(int i=1; i < len; ++i)
-    { 
+    {
       // straight subpath towards i-th edge
       LocalPath=point(A,i-1)---point(A,i);
       // circle with radius 'R' around i-th edge
@@ -36,7 +36,7 @@
 	// add straight subpath towards i-th curvature to 'RoundPath'
 	RoundPath=RoundPath--scale(S)*LocalPair;
       }
-    
+
       // straight subpath from i-th edge to (i+1)-th edge
       LocalPath=point(A,i)---point(A,i+1);
       // calculate intersection-time between straight subpath and circle
@@ -43,16 +43,16 @@
       real[] t=intersect(LocalPath, LocalCirc);
       if(t.length > 0) {
 	LocalTime=t[0];
-	// define intersectionpoint between both paths  
+	// define intersectionpoint between both paths
 	LocalPair=point(subpath(LocalPath, 0, LocalTime), 1);
 	// add curvature near i-th edge to 'RoundPath'
 	RoundPath=RoundPath..scale(S)*LocalPair;
       }
-    } 
+    }
 
-  // final steps to have a correct termination 
+  // final steps to have a correct termination
   if(PathClosed) { // Is 'A' cyclic?
-    // straight subpath towards 0-th edge 
+    // straight subpath towards 0-th edge
     LocalPath=point(A,len-1)---point(A,0);
     // circle with radius 'R' around 0-th edge
     LocalCirc=circle(point(A,0),R);
@@ -65,8 +65,8 @@
       // add straight subpath towards 0-th curvature to 'RoundPath'
       RoundPath=RoundPath--scale(S)*LocalPair;
     }
-    
-    
+
+
     // straight subpath from 0-th edge to 1st edge
     LocalPath=point(A,0)---point(A,1);
     // calculate intersection-time between straight subpath and circle
@@ -73,7 +73,7 @@
     real[] t=intersect(LocalPath, LocalCirc);
     if(t.length > 0) {
       LocalTime=t[0];
-      // define intersectionpoint between both paths  
+      // define intersectionpoint between both paths
       LocalPair=point(subpath(LocalPath, 0, LocalTime), 1);
       // add curvature near 0-th edge to 'RoundPath' and close path
       RoundPath=RoundPath..scale(S)*LocalPair--cycle;

Added: trunk/Master/texmf-dist/asymptote/shaders/blend.glsl
===================================================================
--- trunk/Master/texmf-dist/asymptote/shaders/blend.glsl	                        (rev 0)
+++ trunk/Master/texmf-dist/asymptote/shaders/blend.glsl	2022-02-27 23:41:11 UTC (rev 62265)
@@ -0,0 +1,131 @@
+layout(binding=0, std430) buffer sumBuffer {
+  uint sum[];
+};
+
+layout(binding=1, std430) buffer offsetBuffer {
+  uint offset[];
+};
+
+layout(binding=2, std430) buffer countBuffer {
+  uint count[];
+};
+
+layout(binding=3, std430) buffer fragmentBuffer {
+  vec4 fragment[];
+};
+
+layout(binding=4, std430) buffer depthBuffer {
+  float depth[];
+};
+
+layout(binding=5, std430) buffer opaqueBuffer {
+  vec4 opaqueColor[];
+};
+
+layout(binding=6, std430) buffer opaqueDepthBuffer {
+  float opaqueDepth[];
+};
+
+out vec4 outColor;
+
+uniform uint width;
+uniform uint M;
+uniform uint r;
+uniform vec4 background;
+
+vec4 blend(vec4 outColor, vec4 color)
+{
+  return mix(outColor,color,color.a);
+}
+
+void main()
+{
+  uint headIndex=uint(gl_FragCoord.y)*width+uint(gl_FragCoord.x);
+  uint size=count[headIndex];
+  float OpaqueDepth=opaqueDepth[headIndex];
+  if(size == 0u) {
+#ifdef GPUINDEXING
+    offset[headIndex]=0u;
+#endif
+    opaqueDepth[headIndex]=0.0;
+    discard;
+  }
+
+  uint listIndex=
+#ifdef GPUINDEXING
+    sum[headIndex < r*(M+1u) ? headIndex/(M+1u) : (headIndex-r)/M]+
+#endif
+    offset[headIndex];
+  const uint maxSize=16u;
+
+  // Sort the fragments with respect to descending depth
+  if(size < maxSize) {
+    vec4 sortedColor[maxSize];
+    float sortedDepth[maxSize];
+
+    uint k=0u;
+
+    if(OpaqueDepth != 0.0)
+      while(k < size && depth[listIndex+k] >= OpaqueDepth)
+        ++k;
+
+    uint i=0u;
+    if(k < size) {
+      sortedColor[0]=fragment[listIndex+k];
+      sortedDepth[0]=depth[listIndex+k];
+      ++k;
+      i=1u;
+      while(true) {
+        if(OpaqueDepth != 0.0)
+          while(k < size && depth[listIndex+k] >= OpaqueDepth)
+            ++k;
+        if(k == size) break;
+        float D=depth[listIndex+k];
+        uint j=i;
+        float d;
+        while(j > 0u && D > sortedDepth[j-1u]) {
+          sortedColor[j]=sortedColor[j-1u];
+          sortedDepth[j]=sortedDepth[j-1u];
+          --j;
+        }
+        sortedColor[j]=fragment[listIndex+k];
+        sortedDepth[j]=D;
+        ++i;
+        ++k;
+      }
+    }
+    outColor=OpaqueDepth != 0.0 ? opaqueColor[headIndex] : background;
+    for(uint j=0u; j < i; ++j)
+      outColor=blend(outColor,sortedColor[j]);
+  } else {
+    uint k=0u;
+    if(OpaqueDepth != 0.0)
+      while(k < size && depth[listIndex+k] >= OpaqueDepth)
+        ++k;
+    for(uint i=k+1u; i < size; i++) {
+      vec4 temp=fragment[listIndex+i];
+      float D=depth[listIndex+i];
+      uint j=i;
+      while(j > 0u && D > depth[listIndex+j-1u]) {
+        fragment[listIndex+j]=fragment[listIndex+j-1u];
+        depth[listIndex+j]=depth[listIndex+j-1u];
+        --j;
+      }
+      fragment[listIndex+j]=temp;
+      depth[listIndex+j]=D;
+    }
+
+    outColor=OpaqueDepth != 0.0 ? opaqueColor[headIndex] : background;
+    uint stop=listIndex+size;
+    for(uint i=listIndex+k; i < stop; i++) {
+      if(OpaqueDepth == 0.0 || depth[i] < OpaqueDepth)
+        outColor=blend(outColor,fragment[i]);
+    }
+  }
+
+  count[headIndex]=0u;
+  opaqueDepth[headIndex]=0.0;
+#ifdef GPUINDEXING
+  offset[headIndex]=0u;
+#endif
+}


Property changes on: trunk/Master/texmf-dist/asymptote/shaders/blend.glsl
___________________________________________________________________
Added: svn:executable
## -0,0 +1 ##
+*
\ No newline at end of property
Added: trunk/Master/texmf-dist/asymptote/shaders/count.glsl
===================================================================
--- trunk/Master/texmf-dist/asymptote/shaders/count.glsl	                        (rev 0)
+++ trunk/Master/texmf-dist/asymptote/shaders/count.glsl	2022-02-27 23:41:11 UTC (rev 62265)
@@ -0,0 +1,11 @@
+layout(binding=2, std430) buffer countBuffer {
+  uint count[];
+};
+
+uniform uint width;
+
+void main()
+{
+  atomicAdd(count[uint(gl_FragCoord.y)*width+uint(gl_FragCoord.x)],1u);
+  discard;
+}


Property changes on: trunk/Master/texmf-dist/asymptote/shaders/count.glsl
___________________________________________________________________
Added: svn:executable
## -0,0 +1 ##
+*
\ No newline at end of property
Added: trunk/Master/texmf-dist/asymptote/shaders/count0.glsl
===================================================================
--- trunk/Master/texmf-dist/asymptote/shaders/count0.glsl	                        (rev 0)
+++ trunk/Master/texmf-dist/asymptote/shaders/count0.glsl	2022-02-27 23:41:11 UTC (rev 62265)
@@ -0,0 +1,11 @@
+layout(binding=2, std430) buffer countBuffer {
+  uint count[];
+};
+
+uniform uint width;
+
+void main()
+{
+  count[uint(gl_FragCoord.y)*width+uint(gl_FragCoord.x)]=0u;
+  discard;
+}


Property changes on: trunk/Master/texmf-dist/asymptote/shaders/count0.glsl
___________________________________________________________________
Added: svn:executable
## -0,0 +1 ##
+*
\ No newline at end of property
Modified: trunk/Master/texmf-dist/asymptote/shaders/fragment.glsl
===================================================================
--- trunk/Master/texmf-dist/asymptote/shaders/fragment.glsl	2022-02-27 23:39:53 UTC (rev 62264)
+++ trunk/Master/texmf-dist/asymptote/shaders/fragment.glsl	2022-02-27 23:41:11 UTC (rev 62265)
@@ -10,7 +10,7 @@
   vec3 color;
 };
 
-uniform int nlights;
+uniform uint nlights;
 uniform Light lights[max(Nlights,1)];
 
 uniform MaterialBuffer {
@@ -17,18 +17,6 @@
   Material Materials[Nmaterials];
 };
 
-#ifdef NORMAL
-#ifndef ORTHOGRAPHIC
-in vec3 ViewPosition;
-#endif
-in vec3 Normal;
-vec3 normal;
-#endif
-
-#ifdef COLOR
-in vec4 Color; 
-#endif
-
 flat in int materialIndex;
 out vec4 outColor;
 
@@ -38,41 +26,107 @@
 float Metallic; // Metallic/Nonmetals parameter
 float Fresnel0; // Fresnel at zero for nonmetals
 float Roughness2; // roughness squared, for smoothing
+float Roughness;
 
-#ifdef ENABLE_TEXTURE
-uniform sampler2D environmentMap;
-const float PI=acos(-1.0);
-const float twopi=2*PI;
-const float halfpi=PI/2;
+#ifdef HAVE_SSBO
 
-const int numSamples=7;
+layout(binding=0, std430) buffer sumBuffer {
+  uint sum[];
+};
 
+layout(binding=1, std430) buffer offsetBuffer {
+  uint offset[];
+};
+
+layout(binding=2, std430) buffer countBuffer {
+  uint count[];
+};
+
+layout(binding=3, std430) buffer fragmentBuffer {
+  vec4 fragment[];
+};
+
+layout(binding=4, std430) buffer depthBuffer {
+  float depth[];
+};
+
+layout(binding=5, std430) buffer opaqueBuffer {
+  vec4 opaqueColor[];
+};
+
+layout(binding=6, std430) buffer opaqueDepthBuffer {
+  float opaqueDepth[];
+};
+
+uniform uint width;
+uniform uint M;
+uniform uint r;
+#endif
+
+#ifdef NORMAL
+
+#ifndef ORTHOGRAPHIC
+in vec3 ViewPosition;
+#endif
+in vec3 Normal;
+vec3 normal;
+
+#ifdef USE_IBL
+uniform sampler2D reflBRDFSampler;
+uniform sampler2D diffuseSampler;
+uniform sampler3D reflImgSampler;
+
+const float pi=acos(-1.0);
+const float piInv=1.0/pi;
+const float twopi=2.0*pi;
+const float twopiInv=1.0/twopi;
+
 // (x,y,z) -> (r,theta,phi);
-// theta -> [0,\pi]: colatitude
-// phi -> [0, 2\pi]: longitude
+// theta -> [0,pi]: colatitude
+// phi -> [-pi,pi]: longitude
 vec3 cart2sphere(vec3 cart)
 {
-  float x=cart.z;
-  float y=cart.x;
+  float x=cart.x;
+  float y=cart.z;
   float z=cart.y;
 
   float r=length(cart);
+  float theta=r > 0.0 ? acos(z/r) : 0.0;
   float phi=atan(y,x);
-  float theta=acos(z/r);
 
-  return vec3(r,phi,theta);
+  return vec3(r,theta,phi);
 }
 
 vec2 normalizedAngle(vec3 cartVec)
 {
   vec3 sphericalVec=cart2sphere(cartVec);
-  sphericalVec.y=sphericalVec.y/(2*PI)-0.25;
-  sphericalVec.z=sphericalVec.z/PI;
-  return sphericalVec.yz;
+  sphericalVec.y=sphericalVec.y*piInv;
+  sphericalVec.z=0.75-sphericalVec.z*twopiInv;
+
+  return sphericalVec.zy;
 }
-#endif
 
-#ifdef NORMAL
+vec3 IBLColor(vec3 viewDir)
+{
+  //
+  // based on the split sum formula approximation
+  // L(v)=\int_\Omega L(l)f(l,v) \cos \theta_l
+  // which, by the split sum approiximation (assuming independence+GGX distrubition),
+  // roughly equals (within a margin of error)
+  // [\int_\Omega L(l)] * [\int_\Omega f(l,v) \cos \theta_l].
+  // the first term is the reflectance irradiance integral
+
+  vec3 IBLDiffuse=Diffuse*texture(diffuseSampler,normalizedAngle(normal)).rgb;
+  vec3 reflectVec=normalize(reflect(-viewDir,normal));
+  vec2 reflCoord=normalizedAngle(reflectVec);
+  vec3 IBLRefl=texture(reflImgSampler,vec3(reflCoord,Roughness)).rgb;
+  vec2 IBLbrdf=texture(reflBRDFSampler,vec2(dot(normal,viewDir),Roughness)).rg;
+  float specularMultiplier=Fresnel0*IBLbrdf.x+IBLbrdf.y;
+  vec3 dielectric=IBLDiffuse+specularMultiplier*IBLRefl;
+  vec3 metal=Diffuse*IBLRefl;
+  return mix(dielectric,metal,Metallic);
+}
+#else
 // h is the halfway vector between normal and light direction
 // GGX Trowbridge-Reitz Approximation
 float NDF_TRG(vec3 h)
@@ -122,11 +176,17 @@
 
   vec3 dielectric=mix(lambertian,rawReflectance*Specular,F);
   vec3 metal=rawReflectance*Diffuse;
-  
+
   return mix(dielectric,metal,Metallic);
 }
 #endif
 
+#endif
+
+#ifdef COLOR
+in vec4 Color;
+#endif
+
 void main()
 {
   vec4 diffuse;
@@ -133,7 +193,7 @@
   vec4 emissive;
 
   Material m;
-#ifdef TRANSPARENT
+#ifdef GENERAL
   m=Materials[abs(materialIndex)-1];
   emissive=m.emissive;
   if(materialIndex >= 0)
@@ -150,18 +210,18 @@
 #ifdef COLOR
   diffuse=Color;
 #if Nlights == 0
-   emissive += Color;
+  emissive += Color;
 #endif
-#else  
-  diffuse=m.diffuse; 
+#else
+  diffuse=m.diffuse;
 #endif
 #endif
-  
+
 #if defined(NORMAL) && Nlights > 0
   Specular=m.specular.rgb;
   vec4 parameters=m.parameters;
-  Roughness2=1.0-parameters[0];
-  Roughness2=Roughness2*Roughness2;
+  Roughness=1.0-parameters[0];
+  Roughness2=Roughness*Roughness;
   Metallic=parameters[1];
   Fresnel0=parameters[2];
   Diffuse=diffuse.rgb;
@@ -178,9 +238,13 @@
 #else
   vec3 viewDir=-normalize(ViewPosition);
 #endif
+  vec3 color;
+#ifdef USE_IBL
+  color=IBLColor(viewDir);
+#else
   // For a finite point light, the rendering equation simplifies.
-  vec3 color=emissive.rgb;
-  for(int i=0; i < nlights; ++i) {
+  color=emissive.rgb;
+  for(uint i=0u; i < nlights; ++i) {
     Light Li=lights[i];
     vec3 L=Li.direction;
     float cosTheta=max(dot(normal,L),0.0); // $\omega_i \cdot n$ term
@@ -187,41 +251,38 @@
     vec3 radiance=cosTheta*Li.color;
     color += BRDF(viewDir,L)*radiance;
   }
-
-#if defined(ENABLE_TEXTURE) && !defined(COLOR)
-  // Experimental environment radiance using Riemann sums;
-  // can also do importance sampling.
-  vec3 envRadiance=vec3(0.0,0.0,0.0);
-
-  vec3 normalPerp=vec3(-normal.y,normal.x,0.0);
-  if(length(normalPerp) == 0.0)
-    normalPerp=vec3(1.0,0.0,0.0);
-
-  // we now have a normal basis;
-  normalPerp=normalize(normalPerp);
-  vec3 normalPerp2=normalize(cross(normal,normalPerp));
-
-  const float step=1.0/numSamples;
-  const float phistep=twopi*step;
-  const float thetastep=halfpi*step;
-  for (int iphi=0; iphi < numSamples; ++iphi) {
-    float phi=iphi*phistep;
-    for (int itheta=0; itheta < numSamples; ++itheta) {
-      float theta=itheta*thetastep;
-
-      vec3 azimuth=cos(phi)*normalPerp+sin(phi)*normalPerp2;
-      vec3 L=sin(theta)*azimuth+cos(theta)*normal;
-
-      vec3 rawRadiance=texture(environmentMap,normalizedAngle(L)).rgb;
-      vec3 surfRefl=BRDF(Z,L);
-      envRadiance += surfRefl*rawRadiance*sin(2.0*theta);
-    }
-  }
-  envRadiance *= halfpi*step*step;
-  color += envRadiance.rgb;
 #endif
   outColor=vec4(color,diffuse.a);
-#else    
+#else
   outColor=emissive;
-#endif      
+#endif
+
+#ifndef WIDTH
+#ifdef HAVE_SSBO
+  uint headIndex=uint(gl_FragCoord.y)*width+uint(gl_FragCoord.x);
+#if defined(TRANSPARENT) || (!defined(HAVE_INTERLOCK) && !defined(OPAQUE))
+  uint listIndex=
+#ifdef GPUINDEXING
+    sum[headIndex < r*(M+1u) ? headIndex/(M+1u) : (headIndex-r)/M]+
+#endif
+    offset[headIndex]+atomicAdd(count[headIndex],1u);
+  fragment[listIndex]=outColor;
+  depth[listIndex]=gl_FragCoord.z;
+#ifndef WIREFRAME
+  discard;
+#endif
+#else
+#ifndef OPAQUE
+#ifdef HAVE_INTERLOCK
+beginInvocationInterlockARB();
+if(opaqueDepth[headIndex] == 0.0 || gl_FragCoord.z < opaqueDepth[headIndex]) {
+  opaqueDepth[headIndex]=gl_FragCoord.z;
+  opaqueColor[headIndex]=outColor;
 }
+endInvocationInterlockARB();
+#endif
+#endif
+#endif
+#endif
+#endif
+}

Added: trunk/Master/texmf-dist/asymptote/shaders/offset.glsl
===================================================================
--- trunk/Master/texmf-dist/asymptote/shaders/offset.glsl	                        (rev 0)
+++ trunk/Master/texmf-dist/asymptote/shaders/offset.glsl	2022-02-27 23:41:11 UTC (rev 62265)
@@ -0,0 +1,11 @@
+layout(binding=1, std430) buffer offsetBuffer {
+  uint offset[];
+};
+
+uniform uint width;
+
+void main()
+{
+  atomicAdd(offset[uint(gl_FragCoord.y)*width+uint(gl_FragCoord.x)+1u],1u);
+  discard;
+}


Property changes on: trunk/Master/texmf-dist/asymptote/shaders/offset.glsl
___________________________________________________________________
Added: svn:executable
## -0,0 +1 ##
+*
\ No newline at end of property
Added: trunk/Master/texmf-dist/asymptote/shaders/partialsum.glsl
===================================================================
--- trunk/Master/texmf-dist/asymptote/shaders/partialsum.glsl	                        (rev 0)
+++ trunk/Master/texmf-dist/asymptote/shaders/partialsum.glsl	2022-02-27 23:41:11 UTC (rev 62265)
@@ -0,0 +1,37 @@
+layout(local_size_x=PROCESSORS) in;
+
+uniform uint elements;
+
+layout(binding=0, std430) buffer sumBuffer
+{
+  uint sum[];
+};
+
+shared uint sharedData[PROCESSORS];
+
+void main(void)
+{
+  uint id=gl_LocalInvocationID.x;
+  sharedData[id]=sum[id+1u];
+
+  barrier();
+
+  uint index=id << 1u;
+  sharedData[index+1u] += sharedData[index];
+  barrier();
+  for(uint step=1u; step < STEPSM1; step++) {
+    uint mask=(1u << step)-1u;
+    uint index=((id >> step) << (step+1u))+mask;
+    uint windex=index+(id&mask)+1u;
+    sharedData[windex] += sharedData[index];
+    barrier();
+  }
+  uint mask=(1u << STEPSM1)-1u;
+  index=((id >> STEPSM1) << (STEPSM1+1u))+mask;
+  uint windex=index+(id&mask)+1u;
+  if(windex < PROCESSORS)
+    sharedData[windex] += sharedData[index];
+  barrier();
+
+  sum[id+1u]=sharedData[id];
+}


Property changes on: trunk/Master/texmf-dist/asymptote/shaders/partialsum.glsl
___________________________________________________________________
Added: svn:executable
## -0,0 +1 ##
+*
\ No newline at end of property
Added: trunk/Master/texmf-dist/asymptote/shaders/presum.glsl
===================================================================
--- trunk/Master/texmf-dist/asymptote/shaders/presum.glsl	                        (rev 0)
+++ trunk/Master/texmf-dist/asymptote/shaders/presum.glsl	2022-02-27 23:41:11 UTC (rev 62265)
@@ -0,0 +1,37 @@
+layout(local_size_x=1) in;
+
+uniform uint elements;
+
+layout(binding=0, std430) buffer sumBuffer
+{
+  uint sum[];
+};
+
+layout(binding=1, std430) buffer offsetBuffer
+{
+  uint offset[];
+};
+
+void main(void)
+{
+  uint id=gl_GlobalInvocationID.x;
+
+  uint m=elements/gl_NumWorkGroups.x;
+  uint r=elements-m*gl_NumWorkGroups.x;
+  uint row,stop;
+  if(id < r) {
+    row=m*id+id;
+    stop=row+m+1u;
+  } else {
+    row=m*id+r;
+    stop=row+m;
+  }
+
+  uint Sum=offset[row];
+  for(uint i=row+1u; i < stop; ++i) {
+    Sum += offset[i];
+    offset[i]=Sum;
+  }
+
+  sum[id+1u]=Sum;
+}


Property changes on: trunk/Master/texmf-dist/asymptote/shaders/presum.glsl
___________________________________________________________________
Added: svn:executable
## -0,0 +1 ##
+*
\ No newline at end of property
Added: trunk/Master/texmf-dist/asymptote/shaders/screen.glsl
===================================================================
--- trunk/Master/texmf-dist/asymptote/shaders/screen.glsl	                        (rev 0)
+++ trunk/Master/texmf-dist/asymptote/shaders/screen.glsl	2022-02-27 23:41:11 UTC (rev 62265)
@@ -0,0 +1,5 @@
+void main()
+{
+  vec2 vertices[3]=vec2[3](vec2(-1,-1),vec2(3,-1),vec2(-1, 3));
+  gl_Position = vec4(vertices[gl_VertexID],0,1);
+}


Property changes on: trunk/Master/texmf-dist/asymptote/shaders/screen.glsl
___________________________________________________________________
Added: svn:executable
## -0,0 +1 ##
+*
\ No newline at end of property
Modified: trunk/Master/texmf-dist/asymptote/shaders/vertex.glsl
===================================================================
--- trunk/Master/texmf-dist/asymptote/shaders/vertex.glsl	2022-02-27 23:39:53 UTC (rev 62264)
+++ trunk/Master/texmf-dist/asymptote/shaders/vertex.glsl	2022-02-27 23:41:11 UTC (rev 62265)
@@ -1,16 +1,22 @@
 in vec3 position;
 
-uniform mat3 normMat;
+#ifdef NORMAL
 
-#ifdef NORMAL
 #ifndef ORTHOGRAPHIC
+uniform mat4 viewMat;
 out vec3 ViewPosition;
 #endif
+
+uniform mat3 normMat;
 in vec3 normal;
 out vec3 Normal;
+
 #endif
 
+#ifdef MATERIAL
 in int material;
+flat out int materialIndex;
+#endif
 
 #ifdef COLOR
 in vec4 color;
@@ -22,10 +28,7 @@
 #endif
 
 uniform mat4 projViewMat;
-uniform mat4 viewMat;
 
-flat out int materialIndex;
-
 void main()
 {
   vec4 v=vec4(position,1.0);
@@ -45,5 +48,7 @@
   gl_PointSize=width;
 #endif
 
+#ifdef MATERIAL
   materialIndex=material;
+#endif
 }

Modified: trunk/Master/texmf-dist/asymptote/simplex.asy
===================================================================
--- trunk/Master/texmf-dist/asymptote/simplex.asy	2022-02-27 23:39:53 UTC (rev 62264)
+++ trunk/Master/texmf-dist/asymptote/simplex.asy	2022-02-27 23:41:11 UTC (rev 62265)
@@ -219,7 +219,7 @@
 
       basicValues();
       iterate(E,n+k,Bindices);
-  
+
       if(abs(Em[0]) > EpsilonA) {
       case=INFEASIBLE;
       return;
@@ -249,7 +249,7 @@
       for(int i=0; i < m; ++i) {
         int k=Bindices[i];
         if(k > n) continue;
-        Bindices[ip]=k; 
+        Bindices[ip]=k;
         cB[ip]=c[k-1];
         real[] Dip=D[ip];
         real[] Ei=E[i];
@@ -319,7 +319,7 @@
         ai[j]=Ai[j];
       }
     }
-  
+
     int k=0;
 
     bool phase1=false;

Modified: trunk/Master/texmf-dist/asymptote/slide.asy
===================================================================
--- trunk/Master/texmf-dist/asymptote/slide.asy	2022-02-27 23:39:53 UTC (rev 62264)
+++ trunk/Master/texmf-dist/asymptote/slide.asy	2022-02-27 23:41:11 UTC (rev 62265)
@@ -32,7 +32,7 @@
 real minipagewidth=pagewidth-2minipagemargin;
 
 transform tinv=inverse(fixedscaling((-1,-1),(1,1),currentpen));
-  
+
 pen itempen=fontsize(24pt);
 pen codepen=fontsize(20pt);
 pen titlepagepen=fontsize(36pt);
@@ -55,7 +55,7 @@
 string oldbulletcolor;
 string newbulletcolor="red";
 string bullet="{\bulletcolor\textbullet}";
-                                              
+
 pair pagenumberposition=S+E;
 pair pagenumberalign=4NW;
 pen pagenumberpen=fontsize(12);
@@ -90,7 +90,7 @@
   return currentpicture.nodes.length <= preamblenodes;
 }
 
-void background() 
+void background()
 {
   if(!background.empty()) {
     add(background);
@@ -197,7 +197,7 @@
   firststep=true;
 }
 
-void newslide(bool stepping=true) 
+void newslide(bool stepping=true)
 {
   allowstepping=stepping;
   nextpage();
@@ -264,11 +264,11 @@
 
 void remark(bool center=false, string s, pair align=0, pen p=itempen,
             real indent=0, bool minipage=true, real skip=itemskip,
-            filltype filltype=NoFill, bool step=false) 
+            filltype filltype=NoFill, bool step=false)
 {
   checkposition();
   if(minipage) s=minipage(s,minipagewidth);
-  
+
   pair offset;
   if(center) {
     if(align == 0) align=S;
@@ -277,12 +277,12 @@
     if(align == 0) align=SE;
     offset=currentposition;
   }
-  
+
   frame f;
   label(f,s,(indent,0),align,p,filltype);
   pair m=tinv*min(f);
   pair M=tinv*min(f);
-  
+
   if(abs(offset.x+M.x) > 1)
     warning("slidetoowide","slide too wide on page "+(string) page+':\n'+
             (string) s);
@@ -399,7 +399,7 @@
   display(new string[] {s},caption,align,p,figuremattpen, final);
 }
 
-void figure(string[] s, string options="", real margin=0, 
+void figure(string[] s, string options="", real margin=0,
             string[] captions=new string[], string caption="",
             pair align=S, pen p=itempen, pen figuremattpen=figuremattpen,
             bool final=true)
@@ -435,7 +435,7 @@
   firststep=false;
 }
 
-void indexedfigure(string prefix, int first, int last, 
+void indexedfigure(string prefix, int first, int last,
                    string options="", string caption="",
                    pair align=S, pen p=itempen, pen figuremattpen=figuremattpen,
                    bool step=itemstep)
@@ -473,7 +473,7 @@
 
 void code(bool center=false, string s, pen p=codepen,
           real indent=0, real skip=codeskip,
-          filltype filltype=NoFill) 
+          filltype filltype=NoFill)
 {
   remark(center,"{\tt "+verbatim(cropcode(s))+"}",p,indent,skip,filltype);
 }
@@ -569,7 +569,7 @@
   texpreamble("\bibliographystyle{"+name+"}");
 }
 
-void bibliography(string name) 
+void bibliography(string name)
 {
   numberpage();
   havepagenumber=false;

Modified: trunk/Master/texmf-dist/asymptote/slopefield.asy
===================================================================
--- trunk/Master/texmf-dist/asymptote/slopefield.asy	2022-02-27 23:39:53 UTC (rev 62264)
+++ trunk/Master/texmf-dist/asymptote/slopefield.asy	2022-02-27 23:41:11 UTC (rev 62265)
@@ -16,7 +16,7 @@
       pair cp=(x,a.y+j*dy);
       real slope=f(cp.x,cp.y);
       real mp=step/sqrt(1+slope^2);
-      draw(pic,(cp.x-mp,cp.y-mp*slope)--(cp.x+mp,cp.y+mp*slope),p,arrow); 
+      draw(pic,(cp.x-mp,cp.y-mp*slope)--(cp.x+mp,cp.y+mp*slope),p,arrow);
     }
   }
   return pic;
@@ -29,12 +29,12 @@
   return slopefield(new real(real x, real y) {return f(x);},a,b,nx,ny,p,arrow);
 }
 
-path curve(pair c, real f(real,real), pair a, pair b) 
+path curve(pair c, real f(real,real), pair a, pair b)
 {
-  real step=stepfraction*(b.x-a.x);     
+  real step=stepfraction*(b.x-a.x);
   real halfstep=0.5*step;
   real sixthstep=step/6;
-        
+
   path follow(real sign) {
     pair cp=c;
     guide g=cp;

Modified: trunk/Master/texmf-dist/asymptote/smoothcontour3.asy
===================================================================
--- trunk/Master/texmf-dist/asymptote/smoothcontour3.asy	2022-02-27 23:39:53 UTC (rev 62264)
+++ trunk/Master/texmf-dist/asymptote/smoothcontour3.asy	2022-02-27 23:41:11 UTC (rev 62265)
@@ -1,11 +1,11 @@
 // Copyright 2015 Charles Staats III
-// 
+//
 // Licensed under the Apache License, Version 2.0 (the "License");
 // you may not use this file except in compliance with the License.
 // You may obtain a copy of the License at
-// 
+//
 //     http://www.apache.org/licenses/LICENSE-2.0
-// 
+//
 // Unless required by applicable law or agreed to in writing, software
 // distributed under the License is distributed on an "AS IS" BASIS,
 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -72,7 +72,7 @@
   assert(u1normals.length == 3);
   assert(v0normals.length == 3);
   assert(v1normals.length == 3);
-  
+
   triple[][] controlpoints = new triple[4][4];
   controlpoints[0][0] = point(external,0);
   controlpoints[1][0] = postcontrol(external,0);
@@ -217,7 +217,7 @@
           + "on bezier patch. Using coons patch.");
     return patch(external);
   }
-  
+
   for (int i = 1; i <= 2; ++i) {
     for (int j = 1; j <= 2; ++j) {
       int position = 3 * (2 * (i-1) + (j-1));
@@ -268,7 +268,7 @@
   tangent = dir(external, 2.5);
   n3 -= dot(n3,tangent)*tangent;
   n3 = unit(n3);
-  
+
   real wild = 2 * wildnessweight;
   real[][] matrix = { {n1.x, n1.y, n1.z},
                       {n2.x, n2.y, n2.z},
@@ -591,7 +591,7 @@
 path3 pathbetween(path3 edgecycle, int vertex1, int vertex2) {
   triple point1 = point(edgecycle, vertex1);
   triple point2 = point(edgecycle, vertex2);
-  
+
   triple v1 = -dir(edgecycle, vertex1, sign=-1);
   triple v2 =  dir(edgecycle, vertex1, sign= 1);
   triple direction1 = projecttospan(unit(point2-point1), v1, v2);
@@ -802,7 +802,7 @@
 
   return new patch[] {patchwithnormals(quad0, grad),
       patchwithnormals(quad1, grad),
-      patchwithnormals(quad2, grad)};   
+      patchwithnormals(quad2, grad)};
 }
 
 // Attempts to fill the path external (which should by a cyclic path consisting of
@@ -837,7 +837,7 @@
     return new patch[] {beziertriangle};
 
   if (!allowsubdivide) return new patch[0];
-  
+
   positionedvector m1 = positionedvector(m1, n1);
   positionedvector m2 = positionedvector(m2, n2);
   positionedvector m3 = positionedvector(m3, n3);
@@ -855,7 +855,7 @@
   triangles.append(maketriangle(subpath(external, 0.5, 1.5) & reverse(p12) & cycle,
                                 f, grad=grad, allowsubdivide=false));
   if (triangles.length < 3) return new patch[0];
-  
+
   triangles.append(maketriangle(subpath(external, 1.5, 2.5) & reverse(p23) & cycle,
                                 f, grad=grad, allowsubdivide=false));
   if (triangles.length < 4) return new patch[0];
@@ -913,7 +913,7 @@
 
   // The tolerance for considering two points "essentially identical."
   static real tolerance = 2.5 * rootfinder_settings.roottolerance;
-  
+
   // If there are two neighboring vertices that are essentially identical,
   // unify them into one.
   for (int i = 0; i < corners.length; ++i) {
@@ -948,7 +948,7 @@
       return null;
     }
   }
-  
+
   if (length(edgecycle) == 3) {
     patch[] toreturn = usetriangles ? maketriangle(edgecycle, f, grad)
         : triangletoquads(edgecycle, f, grad, a, b);
@@ -961,12 +961,12 @@
 
   int[] bisectorindices;
   path3 middleguide = bisector(edgecycle, bisectorindices);
-  
+
   triple testpoint = point(middleguide, 0.5);
   if (!checkpt(testpoint, f, grad, a, b)) {
     return null;
   }
-  
+
   patch[] toreturn = null;
   path3 firstpatch = subpath(edgecycle, bisectorindices[0], bisectorindices[1])
     & reverse(middleguide) & cycle;
@@ -1328,7 +1328,7 @@
       }
       return null;
     }
-    
+
     currentface = XLOW;
     nextface = YHIGH;
     pushifnonnull(zdirzeros[0][1][0]);
@@ -1393,12 +1393,12 @@
       if (!checkpt(testpoint, f, grad, corners[0][0][0], corners[1][1][1])) {
         return subdividecube();
       }
-       
+
       edgecycle = edgecycle & currentpath;
     }
     edgecycle = edgecycle & cycle;
 
-    
+
     {  // Ensure the outward normals are pointing in the same direction as the gradient.
       triple tangentin = patchcorners[0].position - precontrol(edgecycle, 0);
       triple tangentout = postcontrol(edgecycle, 0) - patchcorners[0].position;
@@ -1482,7 +1482,7 @@
         if (k >= nz) reportactive[ZHIGH] = true;
       }
     }
-    
+
     for (int i = 0; i < nx+1; ++i) {
       for (int j = 0; j < ny+1; ++j) {
         for (int k = 0; k < nz+1; ++k) {
@@ -1532,7 +1532,7 @@
   };
 }
 
-// The external interface of this whole module. Accepts exactly one 
+// The external interface of this whole module. Accepts exactly one
 // function (throws an error if two or zero functions are specified).
 // The function should be differentiable. (Whatever you do, do not
 // pass in an indicator function!) Ideally, the zero locus of the

Modified: trunk/Master/texmf-dist/asymptote/solids.asy
===================================================================
--- trunk/Master/texmf-dist/asymptote/solids.asy	2022-02-27 23:39:53 UTC (rev 62264)
+++ trunk/Master/texmf-dist/asymptote/solids.asy	2022-02-27 23:41:11 UTC (rev 62265)
@@ -5,11 +5,11 @@
 // A solid geometry package.
 
 // Try to find a bounding tangent line between two paths.
-real[] tangent(path p, path q, bool side) 
+real[] tangent(path p, path q, bool side)
 {
   static real fuzz=1.0e-5;
 
-  if((cyclic(p) && inside(p,point(q,0)) || 
+  if((cyclic(p) && inside(p,point(q,0)) ||
       cyclic(q) && inside(q,point(p,0))) &&
      intersect(p,q,fuzz).length == 0) return new real[];
 
@@ -28,7 +28,7 @@
   return new real[];
 }
 
-path line(path p, path q, real[] t) 
+path line(path p, path q, real[] t)
 {
   return point(p,t[0])--point(q,t[1]);
 }
@@ -35,7 +35,7 @@
 
 // Return the projection of a generalized cylinder of height h constructed
 // from area base in the XY plane and aligned with axis.
-path[] cylinder(path3 base, real h, triple axis=Z, projection P) 
+path[] cylinder(path3 base, real h, triple axis=Z, projection P)
 {
   base=rotate(-colatitude(axis),cross(axis,Z))*base;
   path3 top=shift(h*axis)*base;
@@ -71,7 +71,7 @@
   triple m;
 
   static real epsilon=10*sqrtEpsilon;
-  
+
   void operator init(triple c=O, path3 g, triple axis=Z, real angle1=0,
                      real angle2=360) {
     this.c=c;
@@ -82,12 +82,12 @@
     M=max(g);
     m=min(g);
   }
-  
 
+
   revolution copy() {
     return revolution(c,g,axis,angle1,angle2);
   }
-  
+
   triple vertex(int i, real j) {
     triple v=point(g,i);
     triple center=c+dot(v-c,axis)*axis;
@@ -114,7 +114,7 @@
     path3 p=Arc(center,v1,v2,axis,n);
     return (angle2-angle1) % 360 == 0 ? p&cycle : p;
   }
-  
+
   // add transverse slice to skeleton s;
   void transverse(skeleton s, real t, int n=nslice, projection P) {
     skeleton.curve s=s.transverse;
@@ -196,7 +196,7 @@
     int M=(m == 0) ? N : m;
     real factor=m == 1 ? 0 : 1/(m-1);
     int n=nslice;
-    
+
     real tfirst=-1;
     real tlast;
     for(int i=0; i < M; ++i) {
@@ -238,7 +238,7 @@
 	G=sfirst.transverse.back[0]..G;
       }
     }
-    
+
     skeleton slast;
     transverse(slast,tlast,n,P);
     if(dot(delta,axis) == 0 || (tlast >= L-epsilon && sign > 0)) {
@@ -287,7 +287,7 @@
 	path3 p1=subpath(p,0,t);
 	path3 p2=subpath(p,t,length(p));
 	if(length(p1) > 0 &&
-           (length(p2) == 0 || 
+           (length(p2) == 0 ||
             abs(midpoint(p1)-P.camera) <= abs(midpoint(p2)-P.camera))) {
 	  s.longitudinal.front.push(p1);
           s.longitudinal.back.push(p2);
@@ -300,7 +300,7 @@
     push(t1);
     push(t2);
   }
-  
+
   skeleton skeleton(int m=0, int n=nslice, projection P) {
     skeleton s;
     transverse(s,m,n,P);

Modified: trunk/Master/texmf-dist/asymptote/stats.asy
===================================================================
--- trunk/Master/texmf-dist/asymptote/stats.asy	2022-02-27 23:39:53 UTC (rev 62264)
+++ trunk/Master/texmf-dist/asymptote/stats.asy	2022-02-27 23:41:11 UTC (rev 62265)
@@ -287,6 +287,6 @@
     real s=sqrt(arg/(n-2));
     L.dm=s*sqrt(1/sxx);
     L.db=s*sqrt(1+sx^2/sxx)/n;
-  }  
+  }
   return L;
 }

Modified: trunk/Master/texmf-dist/asymptote/syzygy.asy
===================================================================
--- trunk/Master/texmf-dist/asymptote/syzygy.asy	2022-02-27 23:39:53 UTC (rev 62264)
+++ trunk/Master/texmf-dist/asymptote/syzygy.asy	2022-02-27 23:41:11 UTC (rev 62265)
@@ -78,7 +78,7 @@
   return new guide[] {(centre+offset*NW){NW}..z[0]+h*N,
                                                 ins[0]..centre{NE}..z[1]+h*N};
 };
-    
+
 Component bm=new Component;
 bm.in=2; bm.out=2;
 bm.connections=new int[] {1,0};
@@ -99,7 +99,7 @@
   return new guide[] {ins[1]..centre{NW}..z[0]+h*N,
                                             (centre+offset*NE){NE}..z[1]+h*N};
 };
-    
+
 Component phi=new Component;
 phi.in=2; phi.out=1;
 phi.connections=new int[] {0,0};
@@ -442,7 +442,7 @@
       p.place + p.c.in <= place ? 0 : // The string doesn't touch it.
       place-p.place+2;*/
   }
-                
+
   int[] pullbackWindow(int step, int w_place, int w_size) {
     int[] a={1};
     for (int place=0; place<n; ++place)
@@ -735,7 +735,7 @@
   bool showall=false;
   bool number=false;  // Number the diagrams when drawn.
 
-  string lsym, codename; 
+  string lsym, codename;
 
   bool watched=false;
   bool uptodate=true;

Modified: trunk/Master/texmf-dist/asymptote/three.asy
===================================================================
--- trunk/Master/texmf-dist/asymptote/three.asy	2022-02-27 23:39:53 UTC (rev 62264)
+++ trunk/Master/texmf-dist/asymptote/three.asy	2022-02-27 23:41:11 UTC (rev 62265)
@@ -1,8 +1,5 @@
 private import math;
 
-if(settings.xasy)
-  settings.render=0;
-
 if(prc0()) {
   if(!latex()) settings.prc=false;
   else {
@@ -11,8 +8,9 @@
   }
 }
 
-// Useful lossy compression values.
+// Useful lossy PRC compression values.
 restricted real Zero=0;
+restricted real Single=0.000001;
 restricted real Low=0.0001;
 restricted real Medium=0.001;
 restricted real High=0.01;
@@ -20,6 +18,27 @@
 restricted int PRCsphere=0;   // Renders slowly but produces smaller PRC files.
 restricted int NURBSsphere=1; // Renders fast but produces larger PRC files.
 
+struct interaction
+{
+  int type;
+  triple center;  // position to rotate billboard objects about
+  bool targetsize;
+  static interaction defaultinteraction;
+
+  void operator init(interaction interaction=defaultinteraction,
+                     int type=interaction.type,
+                     triple center=interaction.center, bool targetsize=interaction.targetsize) {
+    this.type=type;
+    this.center=center;
+    this.targetsize=targetsize;
+  }
+}
+
+interaction.defaultinteraction=new interaction;
+
+restricted interaction Embedded=interaction();
+restricted interaction Billboard=interaction(1);
+
 struct render
 {
   // PRC parameters:
@@ -37,23 +56,23 @@
 
   // General parameters:
   real margin;          // shrink amount for rendered openGL viewport, in bp.
-  bool labelfill;       // fill PRC subdivision cracks in unlighted labels
-
   bool partnames;       // assign part name indices to compound objects
   bool defaultnames;    // assign default names to unnamed objects
+  interaction interaction; // billboard interaction mode
 
   static render defaultrender;
-  
-  void operator init(real compression=defaultrender.compression,
-                     real granularity=defaultrender.granularity,
-                     bool closed=defaultrender.closed,
-                     bool tessellate=defaultrender.tessellate,
-                     bool3 merge=defaultrender.merge,
-                     int sphere=defaultrender.sphere,
-                     real margin=defaultrender.margin,
-                     bool labelfill=defaultrender.labelfill,
-                     bool partnames=defaultrender.partnames,
-                     bool defaultnames=defaultrender.defaultnames)
+
+  void operator init(render render=defaultrender,
+                     real compression=render.compression,
+                     real granularity=render.granularity,
+                     bool closed=render.closed,
+                     bool tessellate=render.tessellate,
+                     bool3 merge=render.merge,
+                     int sphere=render.sphere,
+                     real margin=render.margin,
+                     bool partnames=render.partnames,
+                     bool defaultnames=render.defaultnames,
+                     interaction interaction=render.interaction)
   {
     this.compression=compression;
     this.granularity=granularity;
@@ -62,9 +81,9 @@
     this.merge=merge;
     this.sphere=sphere;
     this.margin=margin;
-    this.labelfill=labelfill;
     this.partnames=partnames;
     this.defaultnames=defaultnames;
+    this.interaction=interaction;
   }
 }
 
@@ -78,9 +97,9 @@
 defaultrender.merge=false;
 defaultrender.margin=0.02;
 defaultrender.sphere=NURBSsphere;
-defaultrender.labelfill=true;
 defaultrender.partnames=false;
 defaultrender.defaultnames=true;
+defaultrender.interaction=Embedded;
 
 real defaultshininess=0.7;
 real defaultmetallic=0.0;
@@ -95,7 +114,7 @@
 string defaultembed3Dscript;
 real defaulteyetoview=63mm/1000mm;
 
-string partname(int i, render render=defaultrender) 
+string partname(int i, render render=defaultrender)
 {
   return render.partnames ? string(i+1) : "";
 }
@@ -158,8 +177,8 @@
   v=unit(v);
   s -= 1;
   return new real[][] {
-    {1+s*v.x^2, s*v.x*v.y, s*v.x*v.z, 0}, 
-      {s*v.x*v.y, 1+s*v.y^2, s*v.y*v.z, 0}, 
+    {1+s*v.x^2, s*v.x*v.y, s*v.x*v.z, 0},
+      {s*v.x*v.y, 1+s*v.y^2, s*v.y*v.z, 0},
         {s*v.x*v.z, s*v.y*v.z, 1+s*v.z^2, 0},
           {0, 0, 0, 1}};
 }
@@ -248,7 +267,7 @@
 }
 
 // Return a matrix to do perspective distortion based on a triple v.
-transform3 distort(triple v) 
+transform3 distort(triple v)
 {
   transform3 t=identity(4);
   real d=length(v);
@@ -410,7 +429,7 @@
 
 currentprojection=perspective(5,4,2);
 
-projection projection() 
+projection projection()
 {
   projection P;
   real[] a=_projection();
@@ -467,8 +486,8 @@
 }
 
 control nocontrol;
-  
-control operator * (transform3 t, control c) 
+
+control operator * (transform3 t, control c)
 {
   control C;
   C.post=t*c.post;
@@ -485,7 +504,7 @@
   write(file," and ");
   write(file,c.pre);
 }
-  
+
 struct Tension {
   real out,in;
   bool atLeast;
@@ -510,7 +529,7 @@
 
 Tension noTension;
 noTension.active=false;
-  
+
 void write(file file, Tension t)
 {
   write(file,"..tension ");
@@ -519,7 +538,7 @@
   write(file," and ");
   write(file,t.in);
 }
-  
+
 struct dir {
   triple dir;
   real gamma=1; // endpoint curl
@@ -561,8 +580,8 @@
     write(file,"{curl "); write(file,d.gamma); write(file,"}");
   }
 }
-  
-dir operator * (transform3 t, dir d) 
+
+dir operator * (transform3 t, dir d)
 {
   dir D=d.copy();
   D.init(unit(shiftless(t)*d.dir));
@@ -596,11 +615,11 @@
 
   bool cyclic() {int n=cyclic.length; return n > 0 ? cyclic[n-1] : false;}
   bool precyclic() {int i=find(cyclic); return i >= 0 && i < cyclic.length-1;}
-  
+
   int size() {
     return cyclic() ? nodes.length-1 : nodes.length;
   }
-  
+
   void node(triple v, bool b=false) {
     nodes.push(v);
     control.push(nocontrol);
@@ -650,7 +669,7 @@
     if(nodes.length > 0)
       node(nodes[0],true);
   }
-  
+
   // Return true if outgoing direction at node i is known.
   bool solved(int i) {
     return out[i].active() || control[i].active;
@@ -705,13 +724,13 @@
   };
 }
 
-guide3 operator controls(triple post, triple pre) 
+guide3 operator controls(triple post, triple pre)
 {
   return new void(flatguide3 f) {
     f.control(post,pre);
   };
 };
-  
+
 guide3 operator controls(triple v)
 {
   return operator controls(v,v);
@@ -743,7 +762,7 @@
       abort("invalid direction specifier");
   };
 }
-  
+
 guide3 operator -- (... guide3[] g)
 {
   return new void(flatguide3 f) {
@@ -805,13 +824,13 @@
 {
   return asin(min(max(x,-1),1));
 }
-  
+
 // A version of acos that tolerates numerical imprecision
 real acos1(real x)
 {
   return acos(min(max(x,-1),1));
 }
-  
+
 struct Controls {
   triple c0,c1;
 
@@ -840,7 +859,7 @@
   triple normal=cross(d0,d1);
   return normal == O ? reference : normal;
 }
-                                        
+
 private triple dir(real theta, triple d0, triple d1, triple reference)
 {
   triple normal=cross(d0,d1,reference);
@@ -860,7 +879,7 @@
 // beta[i] is the tension for segment i, and in[i] is the incoming
 // direction for segment i (where segment i begins at node i).
 
-real[] theta(triple[] v, real[] alpha, real[] beta, 
+real[] theta(triple[] v, real[] alpha, real[] beta,
              triple dir0, triple dirn, real g0, real gn, triple reference)
 {
   real[] a,b,c,f,l,psi;
@@ -905,7 +924,7 @@
       f[n]=angle(v[n]-v[n-1],dirn,reference);
     }
   }
-  
+
   for(int i=i0; i < n; ++i) {
     real in=beta[i-1]^2*l[i-1];
     real A=in/alpha[i-1];
@@ -917,7 +936,7 @@
     c[i]=C;
     f[i]=-B*psi[i-1]-C*psi[i];
   }
-  
+
   return tridiagonal(a,b,c,f);
 }
 
@@ -924,7 +943,7 @@
 triple reference(triple[] v, int n, triple d0, triple d1)
 {
   triple[] V=sequence(new triple(int i) {
-      return cross(v[i+1]-v[i],v[i+2]-v[i+1]); 
+      return cross(v[i+1]-v[i],v[i+2]-v[i+1]);
     },n-1);
   if(n > 0) {
     V.push(cross(d0,v[1]-v[0]));
@@ -952,11 +971,11 @@
 }
 
 // Fill in missing directions for n cyclic nodes.
-void aim(flatguide3 g, int N) 
+void aim(flatguide3 g, int N)
 {
   bool cyclic=true;
   int start=0, end=0;
-  
+
   // If the cycle contains one or more direction specifiers, break the loop.
   for(int k=0; k < N; ++k)
     if(g.solved(k)) {cyclic=false; end=k; break;}
@@ -963,7 +982,7 @@
   for(int k=N-1; k >= 0; --k)
     if(g.solved(k)) {cyclic=false; start=k; break;}
   while(start < N && g.control[start].active) ++start;
-  
+
   int n=N-(start-end);
   if(n <= 1 || (cyclic && n <= 2)) return;
 
@@ -993,7 +1012,7 @@
 
   v.cyclic=true;
   theta.cyclic=true;
-    
+
   for(int k=1; k < (cyclic ? n+1 : n); ++k) {
     triple w=dir(theta[k],v[k]-v[k-1],v[k+1]-v[k],reference);
     g.in[(start+k-1) % N].init(w);
@@ -1008,7 +1027,7 @@
 }
 
 // Fill in missing directions for the sequence of nodes i...n.
-void aim(flatguide3 g, int i, int n) 
+void aim(flatguide3 g, int i, int n)
 {
   int j=n-i;
   if(j > 1 || g.out[i].dir != O || g.in[i].dir != O) {
@@ -1021,7 +1040,7 @@
       beta[k]=g.Tension[i+k].in;
     }
     v[j]=g.nodes[n];
-    
+
     triple d0=g.out[i].dir;
     triple d1=g.in[n-1].dir;
 
@@ -1029,7 +1048,7 @@
 
     real[] theta=theta(v,alpha,beta,d0,d1,g.out[i].gamma,g.in[n-1].gamma,
                        reference);
-    
+
     for(int k=1; k < j; ++k) {
       triple w=dir(theta[k],v[k]-v[k-1],v[k+1]-v[k],reference);
       g.in[i+k-1].init(w);
@@ -1175,7 +1194,7 @@
   for(int i=1; i < n; ++i)
     g=straight(p,i-1) ? g--P(point(p,i)) :
       g..controls P(postcontrol(p,i-1)) and P(precontrol(p,i))..P(point(p,i));
-  
+
   if(straight(p,n-1))
     return cyclic(p) ? g--cycle : g--P(point(p,n));
 
@@ -1241,8 +1260,8 @@
   for(int i=0; i < n; ++i) {
     if(g.nodes[i] == g.nodes[i+1] && !g.control[i].active)
       g.control[i]=control(g.nodes[i],g.nodes[i],straight=true);
-  }  
-  
+  }
+
   // Fill in empty direction specifiers inherited from explicit control points.
   for(int i=0; i < n; ++i) {
     if(g.control[i].active) {
@@ -1249,8 +1268,8 @@
       g.out[i].init(g.control[i].post-g.nodes[i]);
       g.in[i].init(g.nodes[i+1]-g.control[i].pre);
     }
-  }  
-  
+  }
+
   // Propagate directions across nodes.
   for(int i=0; i < n; ++i) {
     int next=g.cyclic[i+1] ? 0 : i+1;
@@ -1260,8 +1279,8 @@
       g.out[next].default(g.in[i]);
       g.out[i+1].default(g.in[i]);
     }
-  }  
-    
+  }
+
   // Compute missing 3D directions.
   // First, resolve cycles
   int i=find(g.cyclic);
@@ -1278,7 +1297,7 @@
       }
     }
   }
-    
+
   // Next, resolve sequences.
   int i=0;
   int start=0;
@@ -1288,13 +1307,13 @@
     if(i > n) break;
     // Look for the end of the sequence.
     while(i < n && !g.solved(i)) ++i;
-    
+
     while(start < i && g.control[start].active) ++start;
-    
-    if(start < i) 
+
+    if(start < i)
       aim(g,start,i);
   }
-  
+
   // Compute missing 3D control points.
   for(int i=0; i < n; ++i) {
     int next=g.cyclic[i+1] ? 0 : i+1;
@@ -1344,7 +1363,7 @@
       straight[n-1]=false;
     }
   }
-  
+
   return path3(pre,point,post,straight,cyclic);
 }
 
@@ -1385,7 +1404,7 @@
 
   int last=length(p);
   if(last < 0) return g;
-  
+
   transform3 t=P.t;
 
   if(ninterpolate == 1 || piecewisestraight(p)) {
@@ -1401,7 +1420,7 @@
       }
     }
   } else return nurb(p,P);
-  
+
   if(cyclic(p))
     g=straight(p,last-1) ? g--cycle :
       g..controls project(postcontrol(p,last-1),t) and
@@ -1418,11 +1437,11 @@
 {
   return sequence(new path(int i) {return project(g[i],P);},g.length);
 }
-  
+
 guide3 operator cast(path3 p)
 {
   int last=length(p);
-  
+
   bool cyclic=cyclic(p);
   int stop=cyclic ? last-1 : last;
   return new void(flatguide3 f) {
@@ -1456,7 +1475,7 @@
   real fuzz=sqrtEpsilon*abs(max(p)-min(p));
   real absnormal;
   real theta;
-  
+
   bool Cross(triple a, triple b) {
     if(abs(a) >= fuzz && abs(b) >= fuzz) {
       triple n=cross(unit(a),unit(b));
@@ -1478,7 +1497,7 @@
     }
     return false;
   }
-  
+
   int L=length(p);
   if(L <= 0) return O;
 
@@ -1505,7 +1524,7 @@
   real fuzz=sqrtEpsilon*abs(maxbound(p)-minbound(p));
   real absnormal;
   real theta;
-  
+
   bool Cross(triple a, triple b) {
     if(abs(a) >= fuzz && abs(b) >= fuzz) {
       triple n=cross(unit(a),unit(b));
@@ -1526,7 +1545,7 @@
     }
     return false;
   }
-  
+
   if(p.length <= 0) return O;
 
   triple zi=p[0];
@@ -1642,7 +1661,7 @@
               projection P=currentprojection) {
   Label L=L.copy();
   L.position=project(O,P.t);
-  L.transform(transform(u,v,O,P)); 
+  L.transform(transform(u,v,O,P));
   return L;
 }
 
@@ -1674,7 +1693,7 @@
   write(file,s,(path3[]) x,suffix);
 }
 
-void write(string s="", explicit guide3[] x, suffix suffix=endl) 
+void write(string s="", explicit guide3[] x, suffix suffix=endl)
 {
   write(stdout,s,(path3[]) x,suffix);
 }
@@ -1850,7 +1869,7 @@
 }
 
 // return the linear transformation that maps X,Y,Z to u,v,w.
-transform3 transform3(triple u, triple v, triple w=cross(u,v)) 
+transform3 transform3(triple u, triple v, triple w=cross(u,v))
 {
   return new real[][] {
     {u.x,v.x,w.x,0},
@@ -1915,37 +1934,37 @@
   return new path3[] {(path3) g};
 }
 
-path3[] operator ^^ (path3 p, path3  q) 
+path3[] operator ^^ (path3 p, path3  q)
 {
   return new path3[] {p,q};
 }
 
-path3[] operator ^^ (path3 p, explicit path3[] q) 
+path3[] operator ^^ (path3 p, explicit path3[] q)
 {
   return concat(new path3[] {p},q);
 }
 
-path3[] operator ^^ (explicit path3[] p, path3 q) 
+path3[] operator ^^ (explicit path3[] p, path3 q)
 {
   return concat(p,new path3[] {q});
 }
 
-path3[] operator ^^ (explicit path3[] p, explicit path3[] q) 
+path3[] operator ^^ (explicit path3[] p, explicit path3[] q)
 {
   return concat(p,q);
 }
 
-path3[] operator * (transform3 t, explicit path3[] p) 
+path3[] operator * (transform3 t, explicit path3[] p)
 {
   return sequence(new path3(int i) {return t*p[i];},p.length);
 }
 
-triple[] operator * (transform3 t, triple[] v) 
+triple[] operator * (transform3 t, triple[] v)
 {
   return sequence(new triple(int i) {return t*v[i];},v.length);
 }
 
-triple[][] operator * (transform3 t, triple[][] v) 
+triple[][] operator * (transform3 t, triple[][] v)
 {
   triple[][] V=new triple[v.length][];
   for(int i=0; i < v.length; ++i) {
@@ -1979,7 +1998,7 @@
   triple w;
   for(int i=0; i <= n; ++i) {
     triple z=(unitrand()-0.5,unitrand()-0.5,unitrand()-0.5);
-    if(cumulate) w += z; 
+    if(cumulate) w += z;
     else w=z;
     g=join(g,w);
   }
@@ -2040,15 +2059,15 @@
     v1=Tinv*v1;
     v2=Tinv*v2;
   }
-  
+
   string invalidnormal="invalid normal vector";
   real fuzz=sqrtEpsilon;
   if(abs(v1.z) > fuzz || abs(v2.z) > fuzz)
     abort(invalidnormal);
-  
+
   real[] t1=intersect(unitcircle3,O--2*(v1.x,v1.y,0));
   real[] t2=intersect(unitcircle3,O--2*(v2.x,v2.y,0));
-  
+
   if(t1.length == 0 || t2.length == 0)
     abort(invalidnormal);
 
@@ -2102,21 +2121,19 @@
           string name="", render render=defaultrender,
           projection P=currentprojection);
 
-void begingroup3(frame f, string name="", render render=defaultrender,
-                 triple center=O, int interaction=0)
+void begingroup3(frame f, string name="", render render=defaultrender)
 {
   _begingroup3(f,name,render.compression,render.granularity,render.closed,
                render.tessellate,render.merge == false,
-               render.merge == true,center,interaction);
+               render.merge == true,render.interaction.center,render.interaction.type);
 }
 
 void begingroup3(picture pic=currentpicture, string name="",
-                 render render=defaultrender,
-                 triple center=O, int interaction=0)
+                 render render=defaultrender)
 {
   pic.add(new void(frame f, transform3, picture pic, projection) {
       if(is3D())
-        begingroup3(f,name,render,center,interaction);
+        begingroup3(f,name,render);
       if(pic != null)
         begingroup(pic);
     },true);
@@ -2141,7 +2158,7 @@
 include three_surface;
 include three_margins;
 
-pair min(path3 p, projection P) 
+pair min(path3 p, projection P)
 {
   path3 q=P.T.modelview*p;
   if(P.infinity)
@@ -2149,7 +2166,7 @@
   return maxratio(q)/P.T.projection[3][2];
 }
 
-pair max(path3 p, projection P) 
+pair max(path3 p, projection P)
 {
   path3 q=P.T.modelview*p;
   if(P.infinity)
@@ -2157,7 +2174,7 @@
   return minratio(q)/P.T.projection[3][2];
 }
 
-pair min(frame f, projection P) 
+pair min(frame f, projection P)
 {
   frame g=P.T.modelview*f;
   if(P.infinity)
@@ -2165,7 +2182,7 @@
   return maxratio(g)/P.T.projection[3][2];
 }
 
-pair max(frame f, projection P) 
+pair max(frame f, projection P)
 {
   frame g=P.T.modelview*f;
   if(P.infinity)
@@ -2210,7 +2227,7 @@
     void drawthick(path3 g) {
       if(settings.thick && width > 0) {
         bool prc=prc();
-        bool webgl=settings.outformat == "html";
+        bool primitive=primitive();
         real linecap=linecap(q);
         real r=0.5*width;
         bool open=!cyclic(g);
@@ -2256,7 +2273,7 @@
             }
           }
 // Draw central core for better small-scale rendering.
-          if((!prc || piecewisestraight(g)) && !webgl && opacity(q) == 1)
+          if((!prc || piecewisestraight(g)) && !primitive && opacity(q) == 1)
             _draw(f,c,p,light);
         }
         for(surface s : T.s)
@@ -2319,7 +2336,7 @@
 
 include three_arrows;
 
-void draw(picture pic=currentpicture, Label L="", path3 g, 
+void draw(picture pic=currentpicture, Label L="", path3 g,
           align align=NoAlign, material p=currentpen, arrowbar3 arrow,
           arrowbar3 bar=None, margin3 margin=NoMargin3, light light=nolight,
           light arrowheadlight=currentlight, string name="",
@@ -2409,12 +2426,12 @@
 {
   return pic.min3(P);
 }
-  
+
 triple max3(picture pic, projection P=currentprojection)
 {
   return pic.max3(P);
 }
-  
+
 triple size3(picture pic, bool user=false, projection P=currentprojection)
 {
   transform3 t=pic.calculateTransform3(P);
@@ -2635,7 +2652,7 @@
   transform3 T=identity4;
   picture pic2;
   bool keepAspect=true;
-  
+
   void operator init(frame f, real width, real height,
                      projection P=currentprojection) {
     this.f=f;
@@ -2644,7 +2661,7 @@
     this.width=width;
     this.height=height;
   }
-  
+
   void operator init(picture pic, real xsize=pic.xsize, real ysize=pic.ysize,
                      bool keepAspect=pic.keepAspect, bool is3D=true,
                      projection P=currentprojection) {
@@ -2651,7 +2668,7 @@
     real xsize3=pic.xsize3, ysize3=pic.ysize3, zsize3=pic.zsize3;
     bool warn=true;
     this.keepAspect=keepAspect;
-        
+
     if(xsize3 == 0 && ysize3 == 0 && zsize3 == 0) {
       xsize3=ysize3=zsize3=max(xsize,ysize);
       warn=false;
@@ -2787,6 +2804,7 @@
   triple orthoshift;
   modelview=P.T.modelview;
   transform3 inv;
+  bool prc=prc(format);
   if(P.absolute) {
     Q=modelview*P;
     inv=inverse(modelview);
@@ -2798,12 +2816,13 @@
 
     if(Q.t[2][3] == -1) // PRC can't handle oblique projections
       Q=orthographic(P.camera,P.up,P.target,P.zoom,P.viewportshift,
-                     P.showtarget,P.center);     
+                     P.showtarget,P.center);
+
     if(P.infinity) {
       triple m=min3(S.f);
       triple M=max3(S.f);
       triple lambda=M-m;
-      if(S.keepAspect) {
+      if(S.keepAspect || prc) {
         S.viewportmargin=viewportmargin((lambda.x,lambda.y));
         S.width=ceil(lambda.x+2*S.viewportmargin.x);
         S.height=ceil(lambda.y+2*S.viewportmargin.y);
@@ -2821,7 +2840,7 @@
       inv=inverse(modelview);
       Q.angle=P.angle;
       if(settings.verbose > 0) {
-        if(S.adjusted) 
+        if(S.adjusted)
           write("adjusting camera to ",tinv*inv*P.camera);
         target=inv*P.target;
       }
@@ -2835,7 +2854,6 @@
   light Light=modelview*light;
 
   if(prefix == "") prefix=outprefix();
-  bool prc=prc(format);
   bool preview=settings.render > 0 && !prconly();
   if(prc) {
     // The media9.sty package cannot handle spaces or dots in filenames.
@@ -2868,12 +2886,12 @@
 
     if(P.infinity) {
       triple margin=(S.viewportmargin.x,S.viewportmargin.y,0);
-      M += margin; 
+      M += margin;
       m -= margin;
     } else if(M.z >= 0) abort("camera too close");
 
-    if(settings.outformat == "html")
-      format="html";
+    if(primitive())
+      format=settings.outformat;
 
     shipout3(prefix,f,preview ? nativeformat() : format,
              S.width-defaultrender.margin,S.height-defaultrender.margin,
@@ -2893,7 +2911,7 @@
       transform T=S.pic2.scaling(S.width,S.height);
       _shipout(image,S.pic2.fit(T),newframe,nativeformat(),false,false);
     }
-    
+
     image += "."+nativeformat();
     if(!settings.inlinetex) file3.push(image);
     image=graphic(image,"hiresbb");
@@ -2924,7 +2942,7 @@
       if(P.infinity) {
         triple lambda=max3(S.f)-min3(S.f);
         pair margin=viewportmargin((lambda.x,lambda.y));
-        viewplanesize=(max(lambda.x+2*margin.x,lambda.y+2*margin.y))/(Q.zoom);
+        viewplanesize=(max(lambda.x+2*margin.x,lambda.y+2*margin.y))/Q.zoom;
         transform3 t=inv*shift(-orthoshift);
         Q=t*Q;
         S.f=t*S.f;
@@ -2948,7 +2966,7 @@
 {
   bool is3D=is3D(format);
   scene S=scene(pic,xsize,ysize,keepAspect,is3D,P);
-  if(is3D)
+  if(is3D && !(settings.xasy && format == ""))
     return embed(prefix,label,text,S,format,view,options,script,light);
   else {
     object F;
@@ -3002,7 +3020,8 @@
       if(light.background != nullpen)
         box(f,light.background,Fill,above=false);
     } else if(!view)
-      label(f,graphic(prefix,"hiresbb"));
+      label(f,settings.inlinetex ?
+            "\input{"+prefix+"}" : graphic(prefix,"hiresbb"));
   }
   return f;
 }
@@ -3017,7 +3036,9 @@
       return embed(prefix=prefix,pic,format,xsize,ysize,keepAspect,view,
                    options,script,light,P);
     },prefix,format,view,light);
-  if(is3D(format) || empty3) add(f,pic.fit2(xsize,ysize,keepAspect));
+
+  if(is3D(format) || empty3)
+    add(f,pic.fit2(xsize,ysize,keepAspect));
   return f;
 };
 
@@ -3056,7 +3077,7 @@
   frame[][] F=array(views.length,new frame[]);
   pair[][] M=array(views.length,new pair[]);
   pair[][] m=array(views.length,new pair[]);
-  
+
   for(int i=0; i < views.length; ++i) {
     projection[] viewsi=views[i];
     frame[] Fi=F[i];
@@ -3076,10 +3097,10 @@
       }
     }
   }
-  
+
   real[] my=new real[views.length];
   real[] My=new real[views.length];
-  
+
   int Nj=0;
   for(int i=0; i < views.length; ++i) {
     my[i]=minbound(m[i]).y;
@@ -3086,7 +3107,7 @@
     My[i]=maxbound(M[i]).y;
     Nj=max(Nj,views[i].length);
   }
-  
+
   real[] mx=array(Nj,infinity);
   real[] Mx=array(Nj,-infinity);
   for(int i=0; i < views.length; ++i) {
@@ -3179,10 +3200,10 @@
       frame f=embedder(prefix,out[i],format,S.width,S.height,view,options,
                        script,light,S.P);
       if(!settings.loop) out[i]=f;
-    }   
+    }
     if(!settings.loop) break;
   }
-  
+
   settings.animating=false;
   settings.interrupt=false;
   settings.reverse=reverse;

Modified: trunk/Master/texmf-dist/asymptote/three_arrows.asy
===================================================================
--- trunk/Master/texmf-dist/asymptote/three_arrows.asy	2022-02-27 23:39:53 UTC (rev 62264)
+++ trunk/Master/texmf-dist/asymptote/three_arrows.asy	2022-02-27 23:41:11 UTC (rev 62265)
@@ -37,7 +37,7 @@
   return bend(g,arctime(g,arclength(g)+p.z-scale))*(p.x,p.y,0);
 }
 
-void bend(surface s, path3 g, real L) 
+void bend(surface s, path3 g, real L)
 {
   for(patch p : s.s) {
     for(int i=0; i < 4; ++i) {
@@ -140,7 +140,7 @@
 
   path3 r=subpath(g,position,0);
   path3 s=subpath(r,arctime(r,size),0);
-  int n=length(s);      
+  int n=length(s);
   bool straight1=n == 1 && straight(g,0);
   real aspect=Tan(angle);
   real width=size*aspect;
@@ -186,7 +186,7 @@
                      filltype filltype=null, bool forwards=true,
                      projection P=currentprojection) {
     if(size == 0) size=a.size(p);
-    
+
     bool relative=position.relative;
     real position=position.position.x;
     if(relative) position=reltime(g,position);
@@ -198,7 +198,7 @@
                   YZplane);
     surface head=surface(O,reverse(approach(subpath(H,1,0),7,1.5))&
                          approach(subpath(H,1,2),4,2),Z);
-  
+
     if(straight1) {
       triple v=point(s,0);
       triple u=point(s,1)-v;
@@ -324,7 +324,7 @@
     position *= arclength(g);
     if(center) position += 0.5*size;
     position=arctime(g,position);
-  } else if(center) 
+  } else if(center)
     position=arctime(g,arclength(subpath(g,0,position))+0.5*size);
   return position;
 }
@@ -450,7 +450,7 @@
                path3 g, material p=currentpen, material arrowheadpen=p,
                real size=0, real angle=arrowangle, filltype filltype=null,
                margin3 margin=NoMargin3, light light=nolight,
-               light arrowheadlight=currentlight) 
+               light arrowheadlight=currentlight)
 {
   pen q=(pen) p;
   if(size == 0) size=arrowhead.size(q);
@@ -539,7 +539,7 @@
   pic.addPoint(a,v-M);
   pic.addPoint(a,v+M);
 }
-                                                      
+
 picture bar(triple a, triple dir, triple perp=O, material p=currentpen)
 {
   picture pic;
@@ -620,11 +620,11 @@
                          material arrowheadpen=nullpen)
 {
   return new bool(picture pic, path3 g, material p, margin3 margin,
-                  light light, light arrowheadlight) { 
+                  light light, light arrowheadlight) {
     real size=size == 0 ? arrowhead.arcsize((pen) p) : size;
     add(pic,arrowhead,size,angle,filltype,position,arrowheadpen,g,p,
         forwards=false,margin,light,arrowheadlight);
-    return false; 
+    return false;
   };
 }
 
@@ -685,7 +685,7 @@
   };
 }
 
-arrowbar3 Bar3(real size=0, triple dir=O) 
+arrowbar3 Bar3(real size=0, triple dir=O)
 {
   return new bool(picture pic, path3 g, material p, margin3 margin, light light,
                   light) {
@@ -696,9 +696,9 @@
   };
 }
 
-arrowbar3 EndBar3(real size=0, triple dir=O)=Bar3; 
+arrowbar3 EndBar3(real size=0, triple dir=O)=Bar3;
 
-arrowbar3 Bars3(real size=0, triple dir=O) 
+arrowbar3 Bars3(real size=0, triple dir=O)
 {
   return new bool(picture pic, path3 g, material p, margin3 margin, light light,
                   light) {

Modified: trunk/Master/texmf-dist/asymptote/three_light.asy
===================================================================
--- trunk/Master/texmf-dist/asymptote/three_light.asy	2022-02-27 23:39:53 UTC (rev 62264)
+++ trunk/Master/texmf-dist/asymptote/three_light.asy	2022-02-27 23:41:11 UTC (rev 62265)
@@ -1,7 +1,7 @@
 struct material {
   pen[] p; // diffusepen,emissivepen,specularpen
   real opacity;
-  real shininess;  
+  real shininess;
   real metallic;
   real fresnel0; // Reflectance rate at a perfect normal angle.
 
@@ -34,7 +34,7 @@
   void specular(pen q) {p[2]=q;}
 }
 
-material operator init() 
+material operator init()
 {
   return material();
 }
@@ -57,7 +57,7 @@
 {
   write(stdout,s,x,suffix);
 }
-  
+
 bool operator == (material m, material n)
 {
   return all(m.p == n.p) && m.opacity == n.opacity &&

Modified: trunk/Master/texmf-dist/asymptote/three_margins.asy
===================================================================
--- trunk/Master/texmf-dist/asymptote/three_margins.asy	2022-02-27 23:39:53 UTC (rev 62264)
+++ trunk/Master/texmf-dist/asymptote/three_margins.asy	2022-02-27 23:41:11 UTC (rev 62265)
@@ -27,7 +27,7 @@
 }
 
 margin3 NoMargin3()
-{ 
+{
   return new marginT3(path3 g, pen) {
     marginT3 margin;
     margin.begin=margin.end=0;
@@ -35,9 +35,9 @@
     return margin;
   };
 }
-                                                      
+
 margin3 Margin3(real begin, real end)
-{ 
+{
   return new marginT3(path3 g, pen p) {
     marginT3 margin;
     real factor=labelmargin(p);
@@ -48,9 +48,9 @@
     return margin;
   };
 }
-                                                           
+
 margin3 PenMargin3(real begin, real end)
-{ 
+{
   return new marginT3(path3 g, pen p) {
     marginT3 margin;
     real factor=linewidth(p);
@@ -60,9 +60,9 @@
     return margin;
   };
 }
-                                              
+
 margin3 DotMargin3(real begin, real end)
-{ 
+{
   return new marginT3(path3 g, pen p) {
     marginT3 margin;
     real margindot(real x) {return x > 0 ? dotfactor*x : x;}
@@ -73,9 +73,9 @@
     return margin;
   };
 }
-                                                      
+
 margin3 TrueMargin3(real begin, real end)
-{ 
+{
   return new marginT3(path3 g, pen p) {
     marginT3 margin;
     margin.begin=begin;
@@ -84,7 +84,7 @@
     return margin;
   };
 }
-                                                      
+
 margin3 NoMargin3=NoMargin3(),
   BeginMargin3=Margin3(1,0),
   Margin3=Margin3(0,1),

Modified: trunk/Master/texmf-dist/asymptote/three_surface.asy
===================================================================
--- trunk/Master/texmf-dist/asymptote/three_surface.asy	2022-02-27 23:39:53 UTC (rev 62264)
+++ trunk/Master/texmf-dist/asymptote/three_surface.asy	2022-02-27 23:41:11 UTC (rev 62265)
@@ -34,7 +34,7 @@
   }
 
   path3 externaltriangular() {
-    return 
+    return
       P[0][0]..controls P[1][0] and P[2][0]..
       P[3][0]..controls P[3][1] and P[3][2]..
       P[3][3]..controls P[2][2] and P[1][1]..cycle;
@@ -91,7 +91,7 @@
                  new triple[] {Bv(1,v),z1},new bool[] {straight,false},false);
   }
 
-  triple point(real u, real v) {        
+  triple point(real u, real v) {
     return bezier(Bu(0,u),Bu(1,u),Bu(2,u),Bu(3,u),v);
   }
 
@@ -237,7 +237,7 @@
         color(normal11(),nocolors ? m : colors[2],light),
         color(normal01(),nocolors ? m : colors[3],light)};
   }
-  
+
   pen[] colorstriangular(material m, light light=currentlight) {
     bool nocolors=colors.length == 0;
     if(planar) {
@@ -250,7 +250,7 @@
         color(normal10(),nocolors ? m : colors[1],light),
         color(normal01(),nocolors ? m : colors[2],light)};
   }
-  
+
   triple min3,max3;
   bool havemin3,havemax3;
 
@@ -332,7 +332,7 @@
   void operator init(patch s) {
     operator init(s.P,s.colors,s.straight,s.planar,s.triangular);
    }
-  
+
   // A constructor for a cyclic path3 of length 3 with a specified
   // internal point, corner normals, and pens (rendered as a Bezier triangle).
   void operator init(path3 external, triple internal, pen[] colors=new pen[],
@@ -406,51 +406,65 @@
     };
   }
 
-  // A constructor for a convex quadrilateral.
+  // A constructor for a triangle or convex quadrilateral.
   void operator init(triple[] external, triple[] internal=new triple[],
                      pen[] colors=new pen[], bool3 planar=default) {
     init();
 
-    if(internal.length == 0 && planar == default)
-      this.planar=normal(external) != O;
-    else this.planar=planar;
+    straight=true;
 
     if(colors.length != 0)
       this.colors=copy(colors);
 
-    if(internal.length == 0) {
-      internal=new triple[4];
-      for(int j=0; j < 4; ++j)
-        internal[j]=nineth*(4*external[j]+2*external[(j+1)%4]+
-                            external[(j+2)%4]+2*external[(j+3)%4]);
-    }
+    if(external.length == 3) {
+      P=new triple[][] {
+        {external[0]},
+        {interp(external[0],external[1],1/3),
+         interp(external[2],external[0],2/3)},
+        {interp(external[0],external[1],2/3),sum(external)/3,
+         interp(external[2],external[0],1/3)},
+        {external[1],interp(external[1],external[2],1/3),
+         interp(external[1],external[2],2/3),external[2]}
+      };
+      planar=true;
+      triangular=true;
+    } else {
+      if(internal.length == 0 && planar == default)
+        this.planar=normal(external) != O;
+      else this.planar=planar;
 
-    straight=true;
+      if(internal.length == 0) {
+        internal=new triple[4];
+        for(int j=0; j < 4; ++j)
+          internal[j]=nineth*(4*external[j]+2*external[(j+1)%4]+
+                              external[(j+2)%4]+2*external[(j+3)%4]);
+      }
 
-    triple delta[]=new triple[4];
-    for(int j=0; j < 4; ++j)
-      delta[j]=(external[(j+1)% 4]-external[j])/3;
+      triple delta[]=new triple[4];
+      for(int j=0; j < 4; ++j)
+        delta[j]=(external[(j+1)% 4]-external[j])/3;
 
-    P=new triple[][] {
-      {external[0],external[0]-delta[3],external[3]+delta[3],external[3]},
-      {external[0]+delta[0],internal[0],internal[3],external[3]-delta[2]},
-      {external[1]-delta[0],internal[1],internal[2],external[2]+delta[2]},
-      {external[1],external[1]+delta[1],external[2]-delta[1],external[2]}
-    };
+      P=new triple[][] {
+        {external[0],external[0]-delta[3],external[3]+delta[3],external[3]},
+        {external[0]+delta[0],internal[0],internal[3],external[3]-delta[2]},
+        {external[1]-delta[0],internal[1],internal[2],external[2]+delta[2]},
+        {external[1],external[1]+delta[1],external[2]-delta[1],external[2]}
+      };
+    }
   }
 }
 
 patch operator * (transform3 t, patch s)
-{ 
+{
   patch S;
   S.P=new triple[s.P.length][];
-  for(int i=0; i < s.P.length; ++i) { 
+  for(int i=0; i < s.P.length; ++i) {
     triple[] si=s.P[i];
     triple[] Si=S.P[i];
     for(int j=0; j < si.length; ++j)
-      Si[j]=t*si[j]; 
+      Si[j]=t*si[j];
   }
-  
+
   S.colors=copy(s.colors);
   S.planar=s.planar;
   S.straight=s.straight;
@@ -458,8 +472,8 @@
   S.init();
   return S;
 }
- 
-patch reverse(patch s) 
+
+patch reverse(patch s)
 {
   assert(!s.triangular);
   patch S;
@@ -505,7 +519,7 @@
     p=p--cycle--cycle;
   else if(L == 3)
     p=p--cycle;
- 
+
   pair[] internal=new pair[4];
   for(int j=0; j < 4; ++j) {
     internal[j]=nineth*(-4*point(p,j)
@@ -533,12 +547,12 @@
       s.append(regularize(g,checkboundary));
     return s;
   }
-        
+
   bool straight=piecewisestraight(p);
   if(L <= 3 && straight) {
     return new path[] {p};
   }
-    
+
   // Split p along the angle bisector at t.
   bool split(path p, real t) {
     pair dir=dir(p,t);
@@ -574,7 +588,7 @@
 
   if(straight)
     return new path[] {p};
-    
+
   pair[][] P=coons(p);
 
   // Check for degeneracy.
@@ -585,12 +599,12 @@
     for(int j=0; j < 4; ++j)
       U[i][j]=P[i+1][j]-P[i][j];
   }
-      
+
   for(int i=0; i < 4; ++i) {
     for(int j=0; j < 3; ++j)
       V[i][j]=P[i][j+1]-P[i][j];
   }
-      
+
   int[] choose2={1,2,1};
   int[] choose3={1,3,3,1};
 
@@ -670,7 +684,7 @@
         c[3] += w*(conj(P[0][j]-P[1][j])*P[0][i]).y;   // u=0
       }
     }
-    
+
     pair BuP(int j, real u) {
       return bezierP(P[0][j],P[1][j],P[2][j],P[3][j],u);
     }
@@ -709,7 +723,7 @@
     // Split at the worst boundary degeneracy.
     if(M < 0 && split(p,cut)) return s;
   }
-    
+
   // Split arbitrarily to resolve any remaining (internal) degeneracy.
   checkboundary=false;
   for(int i=0; i < L; ++i)
@@ -730,7 +744,7 @@
   int index[][];// Position of patch corresponding to major U,V parameter in s.
   bool vcyclic;
   transform3 T=identity4;
-  
+
   drawfcn draw;
   bool PRCprimitive=true; // True unless no PRC primitive is available.
 
@@ -790,7 +804,7 @@
     int V=floor(v);
     int index=index.length == 0 ? U+V : index[U][V];
     return s[index].point(u-U,v-V);
-  }    
+  }
 
   triple normal(real u, real v) {
     int U=floor(u);
@@ -798,25 +812,25 @@
     int index=index.length == 0 ? U+V : index[U][V];
     return s[index].normal(u-U,v-V);
   }
-  
-  void ucyclic(bool f) 
+
+  void ucyclic(bool f)
   {
     index.cyclic=f;
   }
-  
-  void vcyclic(bool f) 
+
+  void vcyclic(bool f)
   {
     for(int[] i : index)
       i.cyclic=f;
     vcyclic=f;
   }
-  
-  bool ucyclic() 
+
+  bool ucyclic()
   {
     return index.cyclic;
   }
-  
-  bool vcyclic() 
+
+  bool vcyclic()
   {
     return vcyclic;
   }
@@ -830,7 +844,7 @@
       g=g&s[i].uequals(u-U);
     return vcyclic() ? g&cycle : g;
   }
-  
+
   path3 vequals(real v) {
     if(index.length == 0) return nullpath3;
     int V=floor(v);
@@ -839,7 +853,7 @@
       g=g&s[i[V]].vequals(v-V);
     return ucyclic() ? g&cycle : g;
   }
-  
+
   // A constructor for a possibly nonconvex simple cyclic path in a given
   // plane.
   void operator init(path p, triple plane(pair)=XYplane) {
@@ -880,12 +894,12 @@
         return;
       }
     }
-    
+
     if(L <= 4 || internal.length > 0) {
       s.push(patch(external,internal,colors,planar));
       return;
     }
-      
+
     // Path is not planar; split into patches.
     real factor=1/L;
     pen[] p;
@@ -968,7 +982,7 @@
 
     typedef pen colorfcn(int i, real j);
     bool defaultcolors=(colorfcn) color == null;
-    
+
     for(int i=0; i < L; ++i) {
       path3 h=subpath(g,i,i+1);
       path3 r=reverse(h);
@@ -985,7 +999,7 @@
       }
       test(maxtimes(H));
       test(mintimes(H));
-      
+
       perp=unit(perp);
       triple normal=unit(cross(axis,perp));
       triple dir(real j) {return Cos(j)*normal-Sin(j)*perp;}
@@ -1023,7 +1037,7 @@
 }
 
 surface operator * (transform3 t, surface s)
-{ 
+{
   surface S;
   S.s=new patch[s.s.length];
   for(int i=0; i < s.s.length; ++i)
@@ -1033,7 +1047,7 @@
   S.T=t*s.T;
   S.draw=s.draw;
   S.PRCprimitive=s.PRCprimitive;
-  
+
   return S;
 }
 
@@ -1048,7 +1062,7 @@
     bound=s.s[i].min(bound);
   return bound;
 }
-  
+
 triple max(surface s)
 {
   if(s.s.length == 0)
@@ -1068,7 +1082,7 @@
     bound=s.s[i].min(P,bound);
   return bound;
 }
-  
+
 pair max(surface s, projection P)
 {
   if(s.s.length == 0)
@@ -1153,13 +1167,13 @@
   triple[] P1=P[1];
   triple[] P2=P[2];
   triple[] P3=P[3];
-  
+
   // slice horizontally
   triple[] c0=split(P0[0],P0[1],P0[2],P0[3],v);
   triple[] c1=split(P1[0],P1[1],P1[2],P1[3],v);
   triple[] c2=split(P2[0],P2[1],P2[2],P2[3],v);
   triple[] c3=split(P3[0],P3[1],P3[2],P3[3],v);
-  
+
   // bottom patch
   triple[] c4=split(P0[0],P1[0],P2[0],P3[0],u);
   triple[] c5=split(c0[0],c1[0],c2[0],c3[0],u);
@@ -1242,7 +1256,7 @@
           {c4[2],c5[2],c6[2],c7[2]}};
 }
 
-triple[][] subpatch(triple[][] P, pair a, pair b) 
+triple[][] subpatch(triple[][] P, pair a, pair b)
 {
   return subpatchend(subpatchbegin(P,b.x,b.y),a.x/b.x,a.y/b.y);
 }
@@ -1294,7 +1308,7 @@
 
   static real Fuzz=1000*realEpsilon;
   real fuzz=max(10*fuzz,Fuzz*max(abs(min(s)),abs(max(s))));
-  
+
   // Remove intrapatch duplicate points.
   for(int i=0; i < T.length; ++i) {
     triple v=point(p,T[i][0]);
@@ -1331,7 +1345,7 @@
 
   if(fuzz == -1)
     fuzz=1000*realEpsilon*max(abs(pmin),abs(pmax),abs(qmin),abs(qmax));
-  
+
   return
     pmax.x+fuzz >= qmin.x &&
     pmax.y+fuzz >= qmin.y &&
@@ -1346,19 +1360,6 @@
   return s.point(u,v);
 }
 
-struct interaction
-{
-  int type;
-  bool targetsize;
-  void operator init(int type, bool targetsize=false) {
-    this.type=type;
-    this.targetsize=targetsize;
-  }
-}
-
-restricted interaction Embedded=interaction(0);
-restricted interaction Billboard=interaction(1);
-
 interaction LabelInteraction()
 {
   return settings.autobillboard ? Billboard : Embedded;
@@ -1369,8 +1370,8 @@
   return light.on() || invisible((pen) m) ? m : emissive(m,colors);
 }
 
-void draw3D(frame f, patch s, triple center=O, material m,
-            light light=currentlight, interaction interaction=Embedded,
+void draw3D(frame f, patch s, material m,
+            light light=currentlight, render render=defaultrender,
             bool primitive=false)
 {
   bool straight=s.straight && s.planar;
@@ -1379,15 +1380,18 @@
   int digits=s.planar && !straight ? 12 : settings.digits;
 
   if(s.colors.length > 0) {
+    primitive=false;
     if(prc() && light.on())
         straight=false; // PRC vertex colors (for quads only) ignore lighting
+    m=material(m);
     m.diffuse(mean(s.colors));
   }
   m=material(m,light,s.colors.length > 0);
-  
-  (s.triangular ? drawbeziertriangle : draw)
-    (f,s.P,center,straight,m.p,m.opacity,m.shininess,
-     m.metallic,m.fresnel0,s.colors,interaction.type,digits,primitive);
+
+ (s.triangular ? drawbeziertriangle : draw)
+    (f,s.P,render.interaction.center,straight,m.p,m.opacity,m.shininess,
+     m.metallic,m.fresnel0,s.colors,render.interaction.type,digits,
+     primitive);
 }
 
 void _draw(frame f, path3 g, triple center=O, material m,
@@ -1417,7 +1421,7 @@
 // Draw triangles on a frame.
 void draw(frame f, triple[] v, int[][] vi,
           triple[] n={}, int[][] ni={}, material m=currentpen, pen[] p={},
-          int[][] pi={}, light light=currentlight)
+          int[][] pi={}, light light=currentlight, render render=defaultrender)
 {
   bool normals=n.length > 0;
   if(!normals) {
@@ -1427,13 +1431,15 @@
   if(p.length > 0)
     m=mean(p);
   m=material(m,light);
-  draw(f,v,vi,n,ni,m.p,m.opacity,m.shininess,m.metallic,m.fresnel0,p,pi);
+  draw(f,v,vi,render.interaction.center,n,ni,
+       m.p,m.opacity,m.shininess,m.metallic,m.fresnel0,p,pi,
+       render.interaction.type);
 }
-  
+
 // Draw triangles on a picture.
 void draw(picture pic=currentpicture, triple[] v, int[][] vi,
           triple[] n={}, int[][] ni={}, material m=currentpen, pen[] p={},
-          int[][] pi={}, light light=currentlight)
+          int[][] pi={}, light light=currentlight, render render=defaultrender)
 {
   bool prc=prc();
   bool normals=n.length > 0;
@@ -1448,7 +1454,9 @@
       triple[] n=t*n;
 
       if(is3D()) {
-        draw(f,v,vi,n,ni,m,p,pi,light);
+        render Render=render(render,interaction(render.interaction,
+                                                t*render.interaction.center));
+        draw(f,v,vi,n,ni,m,p,pi,light,Render);
         if(pic != null) {
           for(int[] vii : vi)
             for(int viij : vii)
@@ -1482,12 +1490,10 @@
                 project(v[vii[2]],P)--cycle;
               pen p=color(n[ni[i][0]],m,light);
               fill(pic,g,p);
-              if(prc && opacity(m.diffuse()) == 1) // Fill subdivision cracks
-                draw(pic,g,p);
             }
           }
         }
-      }   
+      }
     },true);
 
   for(int[] vii : vi)
@@ -1502,11 +1508,11 @@
   if(s.triangular) {
     p=s.colorstriangular(m,light);
     p.push(p[0]);
-    s=tensor(s);        
+    s=tensor(s);
   } else p=s.colors(m,light);
   path g=t*project(s.external(),P,1);
   pair[] internal=t*project(s.internal(),P);
-  pen fillrule=m.diffuse();
+  pen fillrule=fillrule(fillrule(m.diffuse()));
   if(inside(g,internal[0],fillrule) && inside(g,internal[1],fillrule) &&
      inside(g,internal[2],fillrule) && inside(g,internal[3],fillrule)) {
     if(p[0] == p[1] && p[1] == p[2] && p[2] == p[3])
@@ -1529,11 +1535,15 @@
   bool is3D=is3D();
   if(is3D) {
     bool prc=prc();
-    if(s.draw != null && (settings.outformat == "html" ||
-                          (prc && s.PRCprimitive))) {
-      for(int k=0; k < s.s.length; ++k)
-        draw3D(f,s.s[k],surfacepen[k],light,primitive=true);
-      s.draw(f,s.T,surfacepen,light,render);
+    if(s.draw != null && (primitive() || (prc && s.PRCprimitive))) {
+      bool noprerender=settings.prerender == 0;
+      for(int k=0; k < s.s.length; ++k) {
+        patch p=s.s[k];
+        draw3D(f,p,surfacepen[k],light,render,primitive=noprerender);
+        if(p.colors.length > 0) noprerender=false;
+      }
+      if(noprerender)
+        s.draw(f,s.T,surfacepen,light,render);
     } else {
       bool group=name != "" || render.defaultnames;
       if(group)
@@ -1557,7 +1567,7 @@
       for(int p=depth.length-1; p >= 0; --p) {
         real[] a=depth[p];
         int k=round(a[1]);
-        draw3D(f,s.s[k],surfacepen[k],light);
+        draw3D(f,s.s[k],surfacepen[k],light,render);
       }
 
       if(group)
@@ -1646,8 +1656,11 @@
 
   pic.add(new void(frame f, transform3 t, picture pic, projection P) {
       surface S=t*s;
-      if(is3D())
-        draw(f,S,nu,nv,surfacepen,meshpen,light,meshlight,name,render);
+      if(is3D()) {
+        render Render=render(render,interaction(render.interaction,
+                                                t*render.interaction.center));
+        draw(f,S,nu,nv,surfacepen,meshpen,light,meshlight,name,Render);
+      }
       if(pic != null) {
         pic.add(new void(frame f, transform T) {
             draw(T,f,S,nu,nv,surfacepen,meshpen,light,meshlight,P);
@@ -1724,7 +1737,7 @@
   return s;
 }
 
-triple rectify(triple dir) 
+triple rectify(triple dir)
 {
   real scale=max(abs(dir.x),abs(dir.y),abs(dir.z));
   if(scale != 0) dir *= 0.5/scale;
@@ -1832,20 +1845,16 @@
       transform3 positioning=
         shift(L.align.is3D ? position+L.align.dir3*labelmargin(L.p) : position);
       frame f1,f2,f3;
-          begingroup3(f1,name,render);
-          if(L.defaulttransform3)
-            begingroup3(f3,render,position,interaction.type);
-          else {
-            begingroup3(f2,render,position,interaction.type);
-            begingroup3(f3,render,position);
-          }
-      for(patch S : s.s) {
-        S=centering*S;
-        draw3D(f3,S,position,L.p,light,interaction);
-        // Fill subdivision cracks
-        if(prc && render.labelfill && opacity(L.p) == 1 && !lighton)
-          _draw(f3,S.external(),position,L.p,light,interaction);
+      render Render=render(render,interaction(interaction,position));
+      begingroup3(f1,name,render);
+      if(L.defaulttransform3)
+        begingroup3(f3,Render);
+      else {
+        begingroup3(f2,Render);
+        begingroup3(f3,Render);
       }
+      for(patch S : s.s)
+        draw3D(f3,centering*S,L.p,light,Render);
       endgroup3(f3);
           if(L.defaulttransform3)
             add(f1,T*f3);
@@ -1861,10 +1870,7 @@
       for(patch S : surface(L,position).s) {
         triple V=L.align.is3D ? position+L.align.dir3*labelmargin(L.p) :
           position;
-        draw3D(f,S,V,L.p,light,interaction);
-        // Fill subdivision cracks
-        if(prc && render.labelfill && opacity(L.p) == 1 && !lighton)
-          _draw(f,S.external(),V,L.p,light,interaction);
+        draw3D(f,S,L.p,light,render(interaction(interaction,center=V)));
       }
       endgroup3(f);
     }
@@ -1894,7 +1900,7 @@
   L.align(align);
   L.p(p);
   L.position(0);
-  
+
   pic.add(new void(frame f, transform3 t, picture pic2, projection P) {
       // Handle relative projected 3D alignments.
       bool prc=prc();
@@ -1903,7 +1909,7 @@
       if(!align.is3D && L.align.relative && L.align.dir3 != O &&
          determinant(P.t) != 0)
         L.align(L.align.dir*unit(project(v+L.align.dir3,P.t)-project(v,P.t)));
-      
+
       if(interaction.targetsize && settings.render != 0)
         L.T=L.T*scale(abs(P.camera-v)/abs(P.vector()));
       transform3 T=transform3(P);
@@ -1922,19 +1928,15 @@
               shift(L.align.is3D ? v+L.align.dir3*labelmargin(L.p) : v);
             frame f1,f2,f3;
             begingroup3(f1,name,render);
+            render Render=render(render,interaction(interaction,v));
             if(L.defaulttransform3)
-              begingroup3(f3,render,v,interaction.type);
+              begingroup3(f3,Render);
             else {
-              begingroup3(f2,render,v,interaction.type);
-              begingroup3(f3,render,v);
+              begingroup3(f2,Render);
+              begingroup3(f3,Render);
             }
-            for(patch S : s.s) {
-              S=centering*S;
-              draw3D(f3,S,v,L.p,light,interaction);
-              // Fill subdivision cracks
-              if(prc && render.labelfill && opacity(L.p) == 1 && !lighton)
-                _draw(f3,S.external(),v,L.p,light,interaction);
-            }
+            for(patch S : s.s)
+              draw3D(f3,centering*S,L.p,light,Render);
             endgroup3(f3);
             if(L.defaulttransform3)
               add(f1,T*f3);
@@ -1950,15 +1952,12 @@
           begingroup3(f,name,render);
           for(patch S : surface(L,v,bbox=P.bboxonly).s) {
             triple V=L.align.is3D ? v+L.align.dir3*labelmargin(L.p) : v;
-            draw3D(f,S,V,L.p,light,interaction);
-            // Fill subdivision cracks
-            if(prc && render.labelfill && opacity(L.p) == 1 && !lighton)
-              _draw(f,S.external(),V,L.p,light,interaction);
+            draw3D(f,S,L.p,light,render(render,interaction(interaction,V)));
           }
           endgroup3(f);
         }
       }
-      
+
       if(pic2 != null) {
         pen p=color(L.T3*Z,L.p,light,shiftless(P.T.modelview));
         if(L.defaulttransform3) {
@@ -1975,11 +1974,11 @@
                 fill(f,T*project(S.external(),P,1),p);
             });
       }
-      
+
     },!L.defaulttransform3);
 
   Label L=L.copy();
-  
+
   if(interaction.targetsize && settings.render != 0)
     L.T=L.T*scale(abs(currentprojection.camera-position)/
                   abs(currentprojection.vector()));
@@ -2008,7 +2007,7 @@
     a.init(-I*(position <= sqrtEpsilon ? S :
                position >= length(g)-sqrtEpsilon ? N : E),relative=true);
     a.dir3=dir(g,position); // Pass 3D direction via unused field.
-    L.align(a);             
+    L.align(a);
   }
   label(pic,L,point(g,position),light,name,interaction);
 }
@@ -2063,7 +2062,7 @@
     for(path g : regularize(p)) {
       path3 b;
       bool extrude=height > 0;
-      if(bottom || extrude) 
+      if(bottom || extrude)
         b=transpath(g,0);
       if(bottom) s.s.push(patch(b));
       if(top || extrude) {
@@ -2390,7 +2389,7 @@
   return b;
 }
 
-triple[][] operator / (triple[][] a, real[][] b) 
+triple[][] operator / (triple[][] a, real[][] b)
 {
   triple[][] A=new triple[a.length][];
   for(int i=0; i < a.length; ++i) {

Modified: trunk/Master/texmf-dist/asymptote/three_tube.asy
===================================================================
--- trunk/Master/texmf-dist/asymptote/three_tube.asy	2022-02-27 23:39:53 UTC (rev 62264)
+++ trunk/Master/texmf-dist/asymptote/three_tube.asy	2022-02-27 23:41:11 UTC (rev 62265)
@@ -100,6 +100,17 @@
   return R;
 }
 
+
+drawfcn drawTube(triple[] g, real w, triple min, triple max) {
+  return new void(frame f, transform3 t=identity4, material[] m,
+                  light light=currentlight, render render=defaultrender)
+    {
+      material m=material(m[0],light);
+      drawTube(f,t*g,w,m.p,m.opacity,m.shininess,m.metallic,m.fresnel0,
+               t*min,t*max,m.opacity == 1);
+    };
+}
+
 surface tube(triple z0, triple c0, triple c1, triple z1, real w)
 {
   surface s;
@@ -125,13 +136,7 @@
   f(t3);
 
   s.PRCprimitive=false;
-  s.draw=new void(frame f, transform3 t=identity4, material[] m,
-                  light light=currentlight, render render=defaultrender)
-    {
-     material m=material(m[0],light);
-     drawTube(f,t*g,w,m.p,m.opacity,m.shininess,m.metallic,m.fresnel0,
-              t*min(s),t*max(s),m.opacity == 1);
-    };
+  s.draw=drawTube(g,w,min(s),max(s));
   return s;
 }
 
@@ -153,7 +158,7 @@
 
   void Null(transform3) {}
   void Null(transform3, bool) {}
-  
+
   surface[] render(path3 g, real r) {
     triple z0=point(g,0);
     triple c0=postcontrol(g,0);
@@ -174,7 +179,7 @@
         pair a0=threshold(z0,c0,c1);
         pair a1=threshold(z1,c1,c0);
         real rL=r*arclength(z0,c0,c1,z1)*tubethreshold;
-        if((a0.x >= norm && rL*a0.y^2 > a0.x^8) || 
+        if((a0.x >= norm && rL*a0.y^2 > a0.x^8) ||
            (a1.x >= norm && rL*a1.y^2 > a1.x^8)) {
           triple m0=0.5*(z0+c0);
           triple m1=0.5*(c0+c1);
@@ -214,7 +219,7 @@
           s.append(render(subpath(p,i,i+1),r));
       }
     }
-    
+
     transform3 t=scale3(r);
     bool cyclic=cyclic(p);
     int begin=0;

Modified: trunk/Master/texmf-dist/asymptote/trembling.asy
===================================================================
--- trunk/Master/texmf-dist/asymptote/trembling.asy	2022-02-27 23:39:53 UTC (rev 62264)
+++ trunk/Master/texmf-dist/asymptote/trembling.asy	2022-02-27 23:41:11 UTC (rev 62265)
@@ -17,14 +17,14 @@
 // along with this program; if not, write to the Free Software
 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 
-// COMMENTARY: 
+// COMMENTARY:
 
-// THANKS: 
+// THANKS:
 
-// BUGS: 
+// BUGS:
 // magnetic points are experimental...
 
-// CODE: 
+// CODE:
 
 real magneticRadius=1; // unit is bp in postscript coordinates.
 real trembleFuzz(){return min(1e-3,magneticRadius/10);}
@@ -34,7 +34,7 @@
 struct tremble
 {
   static real test=5;
-  
+
   real angle,frequency,random,fuzz;
 
   pair[] single(pair[] P)
@@ -141,7 +141,7 @@
     this.random=random;
     this.fuzz=fuzz;
   }
-  
+
   path deform(path g...pair[] magneticPoints) {
     /* Return g as it was handwriting.
        The postcontrols and precontrols of the nodes of g will be rotated

Added: trunk/Master/texmf-dist/asymptote/v3d.asy
===================================================================
--- trunk/Master/texmf-dist/asymptote/v3d.asy	                        (rev 0)
+++ trunk/Master/texmf-dist/asymptote/v3d.asy	2022-02-27 23:41:11 UTC (rev 62265)
@@ -0,0 +1,645 @@
+// Supakorn "Jamie" Rassameemasuang <jamievlin at outlook.com> and
+// John C. Bowman
+
+import three;
+import v3dtypes;
+import v3dheadertypes;
+
+struct triangleGroup
+{
+  triple[] positions;
+  triple[] normals;
+  pen[] colors;
+
+  int[][] positionIndices;
+  int[][] normalIndices;
+  int[][] colorIndices;
+}
+
+struct pixel
+{
+  triple point;
+  real width;
+}
+
+struct CameraInformation
+{
+  int canvasWidth;
+  int canvasHeight;
+  bool absolute;
+
+  triple b;
+  triple B;
+  bool orthographic;
+  real angle;
+  real Zoom0;
+  pair viewportshift;
+  pair viewportmargin;
+
+  light light;
+
+  void setCameraInfo()
+  {
+    size(canvasWidth,canvasHeight);
+    triple center=0.5*(b.z+B.z)*Z;
+
+    if(orthographic)
+      currentprojection=orthographic(Z,target=center,Zoom0,
+                                     viewportshift=viewportshift);
+    else
+      currentprojection=perspective(Z,Y,target=center,Zoom0,
+                                    degrees(2.0*atan(tan(0.5*angle)/Zoom0)),
+                                    viewportshift=viewportshift,
+                                    autoadjust=false);
+    light.specular=light.diffuse;
+    currentlight=light;
+  }
+}
+
+transform3 Align(real polar, real azimuth)
+{
+  return align(dir(degrees(polar),degrees(azimuth)));
+}
+
+struct v3dfile
+{
+  file xdrfile;
+  int version;
+  bool hasCameraInfo=false;
+  CameraInformation info;
+  bool singleprecision=false;
+
+  triple[] centers;
+  material[] materials;
+
+  surface[][][] surfaces;
+  path3[][][] paths3;
+  triangleGroup[][][] triangles;
+  pixel[][] pixels;
+
+  void initSurface(int center, int material) {
+    if(!surfaces.initialized(center))
+      surfaces[center]=new surface[][];
+    if(!surfaces[center].initialized(material))
+      surfaces[center][material]=new surface[] {new surface};
+  }
+
+  void initPath3(int center, int material) {
+    if(!paths3.initialized(center))
+      paths3[center]=new path3[][];
+    if(!paths3[center].initialized(material))
+      paths3[center][material]=new path3[];
+  }
+
+  void initTriangleGroup(int center, int material) {
+    if (!triangles.initialized(center))
+      triangles[center]=new triangleGroup[][];
+    if(!triangles[center].initialized(material))
+      triangles[center][material]=new triangleGroup[];
+  }
+
+  void initPixel(int material) {
+    if(!pixels.initialized(material))
+      pixels[material]=new pixel[];
+  }
+
+  void surface(int center, int material, patch p) {
+    initSurface(center,material);
+    surfaces[center][material][0].s.push(p);
+  }
+
+  void primitive(int center, int material, surface s) {
+    initSurface(center,material);
+    surfaces[center][material].push(s);
+  }
+
+  void path3(int center, int material, path3 p) {
+    initPath3(center,material);
+    paths3[center][material].push(p);
+  }
+
+  void triangleGroup(int center, int material, triangleGroup g) {
+    initTriangleGroup(center,material);
+    triangles[center][material].push(g);
+  }
+
+  void pixel(int material, pixel P) {
+    initPixel(material);
+    pixels[material].push(P);
+  }
+
+  void operator init(string name)
+  {
+    xdrfile=input(name, mode="xdrgz");
+    version=xdrfile;
+
+    int doubleprecision=xdrfile;
+    singleprecision=doubleprecision == 0;
+    xdrfile.singlereal(singleprecision);
+  }
+
+  int getType()
+  {
+    return xdrfile;
+  }
+
+  void setCameraInfo()
+  {
+    if(hasCameraInfo)
+      info.setCameraInfo();
+  }
+
+  pen[] readColorData(int size=4, bool alpha=true)
+  {
+    xdrfile.singlereal(true);
+
+    xdrfile.dimension(alpha ? 4 : 3);
+    pen[] newPen=new pen[size];
+    for (int i=0; i < size; ++i)
+      {
+        newPen[i]=alpha ? rgba(xdrfile) : rgb((real[]) xdrfile);
+      }
+
+    xdrfile.singlereal(singleprecision);
+
+    return newPen;
+  }
+
+  CameraInformation processHeader()
+  {
+    CameraInformation ci;
+
+    int entryCount=xdrfile;
+    for (int i=0;i<entryCount;++i)
+      {
+        int headerKey=xdrfile;
+        int headerSz=xdrfile;
+
+        if (headerKey == v3dheadertypes.canvasWidth)
+          {
+            ci.canvasWidth=xdrfile;
+          }
+        else if (headerKey == v3dheadertypes.canvasHeight)
+          {
+            ci.canvasHeight=xdrfile;
+          }
+        else if (headerKey == v3dheadertypes.absolute)
+          {
+            int val=xdrfile;
+            ci.absolute=(val != 0);
+          }
+        else if (headerKey == v3dheadertypes.minBound)
+          {
+            ci.b=xdrfile;
+          }
+        else if (headerKey == v3dheadertypes.maxBound)
+          {
+            ci.B=xdrfile;
+          }
+        else if (headerKey == v3dheadertypes.orthographic)
+          {
+            int val=xdrfile;
+            ci.orthographic=(val != 0);
+          }
+        else if (headerKey == v3dheadertypes.angleOfView)
+          {
+            ci.angle=xdrfile;
+          }
+        else if (headerKey == v3dheadertypes.initialZoom)
+          {
+            ci.Zoom0=xdrfile;
+          }
+        else if (headerKey==v3dheadertypes.viewportShift)
+          {
+            ci.viewportshift=xdrfile;
+          }
+        else if (headerKey==v3dheadertypes.viewportMargin)
+          {
+            ci.viewportmargin=xdrfile;
+          }
+        else if (headerKey==v3dheadertypes.background)
+          {
+            ci.light.background=readColorData(1)[0];
+          }
+        else if (headerKey==v3dheadertypes.light)
+          {
+            triple position=xdrfile;
+            ci.light.position.push(position);
+            ci.light.diffuse.push(rgba(readColorData(1,false)[0]));
+          }
+        else
+          {
+            xdrfile.dimension(headerSz);
+            int[] _dmp=xdrfile;
+          }
+      }
+    return ci;
+  }
+
+  material readMaterial() {
+    xdrfile.dimension(4);
+    xdrfile.singlereal(true);
+
+    pen diffusePen=rgba(xdrfile);
+    pen emissivePen=rgba(xdrfile);
+    pen specularPen=rgba(xdrfile);
+
+    xdrfile.dimension(3);
+    real[] params=xdrfile;
+    real shininess=params[0];
+    real metallic=params[1];
+    real F0=params[2];
+
+    xdrfile.singlereal(singleprecision);
+
+    return material(diffusePen,emissivePen,specularPen,1,shininess,
+                    metallic,F0);
+  }
+
+  triple[][] readRawPatchData() {
+    triple[][] val;
+    xdrfile.dimension(4,4);
+    val=xdrfile;
+    return val;
+  }
+
+  triple[][] readRawTriangleData() {
+    triple[][] val;
+
+    for(int i=0; i < 4; ++i) {
+      xdrfile.dimension(i+1);
+      triple[] v=xdrfile;
+      val.push(v);
+    }
+    return val;
+  }
+
+  void readBezierPatch() {
+    triple[][] val=readRawPatchData();
+    int center=xdrfile;
+    int material=xdrfile;
+    surface(center,material,patch(val));
+  }
+
+  void readBezierTriangle() {
+    triple[][] val=readRawTriangleData();
+    int center=xdrfile;
+    int material=xdrfile;
+    surface(center,material,patch(val,triangular=true));
+  }
+
+  triple[] readCenters() {
+    int centerCount=xdrfile;
+    xdrfile.dimension(centerCount);
+    triple[] centersFetched;
+    if (centerCount>0)
+      centersFetched=xdrfile;
+    return centersFetched;
+  }
+
+  void readBezierPatchColor() {
+    triple[][] val=readRawPatchData();
+    int center=xdrfile;
+    int material=xdrfile;
+    pen[] colors=readColorData(4);
+    surface(center,material,patch(val,colors=colors));
+  }
+
+  void readBezierTriangleColor() {
+    triple[][] val=readRawTriangleData();
+    int center=xdrfile;
+    int material=xdrfile;
+    pen[] colors=readColorData(3);
+    surface(center,material,patch(val,triangular=true,colors=colors));
+  }
+
+  void readSphere() {
+    triple origin=xdrfile;
+    real radius=xdrfile;
+
+    int center=xdrfile;
+    int material=xdrfile;
+
+    surface s=shift(origin)*scale3(radius)*unitsphere;
+    s.draw=unitsphere.draw;
+    primitive(center,material,s);
+  }
+
+  void readHemisphere() {
+    triple origin=xdrfile;
+    real radius=xdrfile;
+
+    int center=xdrfile;
+    int material=xdrfile;
+
+    real polar=xdrfile;
+    real azimuth=xdrfile;
+
+    surface s=shift(origin)*Align(polar,azimuth)*scale3(radius)*unithemisphere;
+    s.draw=unithemisphere.draw;
+    primitive(center,material,s);
+  }
+
+  void readDisk() {
+    triple origin=xdrfile;
+    real radius=xdrfile;
+
+    int center=xdrfile;
+    int material=xdrfile;
+
+    real polar=xdrfile;
+    real azimuth=xdrfile;
+
+    surface s=shift(origin)*Align(polar,azimuth)*scale3(radius)*unitdisk;
+    s.draw=unitdisk.draw;
+    primitive(center,material,s);
+  }
+
+  void readPolygon(int n)
+  {
+    xdrfile.dimension(n);
+    triple[] val=xdrfile;
+
+    int center=xdrfile;
+    int material=xdrfile;
+    surface(center,material,patch(val));
+  }
+
+  void readPolygonColor(int n)
+  {
+    xdrfile.dimension(n);
+    triple[] val=xdrfile;
+
+    int center=xdrfile;
+    int material=xdrfile;
+
+    pen[] colors=readColorData(n);
+    surface(center,material,patch(val,colors=colors));
+  }
+
+  void readCylinder() {
+    triple origin=xdrfile;
+    real radius=xdrfile;
+    real height=xdrfile;
+
+    int center=xdrfile;
+    int material=xdrfile;
+
+    real polar=xdrfile;
+    real azimuth=xdrfile;
+
+    int core=xdrfile;
+
+    transform3 T=shift(origin)*Align(polar,azimuth)*
+      scale(radius,radius,height);
+    if(core != 0)
+      path3(center,material,T*(O--Z));
+
+    surface s=T*unitcylinder;
+    s.draw=unitcylinder.draw;
+    primitive(center,material,s);
+  }
+
+  void readTube() {
+    xdrfile.dimension(4);
+    triple[] g=xdrfile;
+
+    real width=xdrfile;
+    int center=xdrfile;
+    int material=xdrfile;
+
+    int core=xdrfile;
+
+    if(core != 0)
+      path3(center,material,g[0]..controls g[1] and g[2]..g[3]);
+
+    surface s=tube(g[0],g[1],g[2],g[3],width);
+    s.draw=drawTube(g,width,info.b,info.B);
+    primitive(center,material,s);
+  }
+
+  void readCurve() {
+    xdrfile.dimension(4);
+    triple[] points=xdrfile;
+
+    int center=xdrfile;
+    int material=xdrfile;
+
+    path3(center,material,
+          points[0]..controls points[1] and points[2]..points[3]);
+  }
+
+  void readLine() {
+    xdrfile.dimension(2);
+    triple[] points=xdrfile;
+
+    int center=xdrfile;
+    int material=xdrfile;
+
+    path3(center,material,points[0]--points[1]);
+  }
+
+  void readTriangles() {
+    triangleGroup g;
+
+    int nI=xdrfile;
+
+    int nP=xdrfile;
+    xdrfile.dimension(nP);
+    g.positions=xdrfile;
+
+    int nN=xdrfile;
+    xdrfile.dimension(nN);
+    g.normals=xdrfile;
+
+    int explicitNI=xdrfile;
+
+    int nC=xdrfile;
+    int explicitCI;
+    if (nC > 0) {
+      g.colors=readColorData(nC);
+      explicitCI=xdrfile;
+    }
+
+    g.positionIndices=new int[nI][3];
+    g.normalIndices=new int[nI][3];
+    int[][] colorIndices;
+    if (nC > 0)
+      g.colorIndices=new int[nI][3];
+
+    for (int i=0; i < nI; ++i) {
+      xdrfile.dimension(3);
+      g.positionIndices[i]=xdrfile;
+      g.normalIndices[i]=explicitNI != 0 ? xdrfile :
+        g.positionIndices[i];
+      g.colorIndices[i]=nC > 0 && explicitCI != 0 ? xdrfile :
+        g.positionIndices[i];
+    }
+    int center=xdrfile;
+    int material=xdrfile;
+    triangleGroup(center,material,g);
+  }
+
+  void readPixel() {
+    pixel P;
+    P.point=xdrfile;
+    P.width=xdrfile;
+    int material=xdrfile;
+    pixel(material,P);
+  }
+
+  void process()
+  {
+    static bool processed;
+    if(processed) return;
+
+    while (!eof(xdrfile))
+      {
+        int ty=getType();
+        if(ty == v3dtypes.header)
+          {
+            hasCameraInfo=true;
+            info=processHeader();
+          }
+        else if(ty == v3dtypes.material)
+          {
+            materials.push(readMaterial());
+          }
+        else if(ty == v3dtypes.bezierPatch)
+          {
+            readBezierPatch();
+          }
+        else if(ty == v3dtypes.bezierTriangle)
+          {
+            readBezierTriangle();
+          }
+        else if(ty == v3dtypes.bezierPatchColor)
+          {
+            readBezierPatchColor();
+          }
+        else if(ty == v3dtypes.bezierTriangleColor)
+          {
+            readBezierTriangleColor();
+          }
+        else if(ty == v3dtypes.quad)
+          {
+            readPolygon(4);
+          }
+        else if(ty == v3dtypes.quadColor)
+          {
+            readPolygonColor(4);
+          }
+        else if(ty == v3dtypes.triangle)
+          {
+            readPolygon(3);
+          }
+        else if(ty == v3dtypes.triangleColor)
+          {
+            readPolygonColor(3);
+          }
+        else if(ty == v3dtypes.sphere)
+          {
+            readSphere();
+          }
+        else if(ty == v3dtypes.halfSphere)
+          {
+            readHemisphere();
+          }
+        else if(ty == v3dtypes.cylinder)
+          {
+            readCylinder();
+          }
+        else if(ty == v3dtypes.tube)
+          {
+            readTube();
+          }
+        else if(ty == v3dtypes.disk)
+          {
+            readDisk();
+          }
+        else if(ty == v3dtypes.curve)
+          {
+            readCurve();
+          }
+        else if(ty == v3dtypes.line)
+          {
+            readLine();
+          }
+        else if(ty == v3dtypes.triangles)
+          {
+            readTriangles();
+          }
+        else if(ty == v3dtypes.centers)
+          {
+            centers=readCenters();
+          }
+        else if(ty == v3dtypes.pixel)
+          {
+            readPixel();
+          }
+        else
+          {
+            //  abort("Unknown type:"+string(ty));
+          }
+      }
+    processed=true;
+  }
+}
+
+void importv3d(string name)
+{
+  if(name == stripextension(name)) name += ".v3d";
+  v3dfile xf=v3dfile(name);
+  xf.process();
+  xf.setCameraInfo();
+
+  for(int c=0; c < xf.surfaces.length; ++c) {
+    triple center=c > 0 ? xf.centers[c-1] : O;
+    render r=render(interaction(c == 0 ? Embedded : Billboard,center=center));
+    surface[][] S=xf.surfaces[c];
+    for(int m=0; m < S.length; ++m)
+      if(S.initialized(m))
+        draw(S[m],xf.materials[m],r);
+  }
+
+  for(int c=0; c < xf.paths3.length; ++c) {
+    triple center=c > 0 ? xf.centers[c-1] : O;
+    render r=render(interaction(c == 0 ? Embedded : Billboard,center=center));
+    path3[][] G=xf.paths3[c];
+    for(int m=0; m < G.length; ++m)
+      if(G.initialized(m)) {
+        material material=material(xf.materials[m]);
+        material.p[0] += thin();
+        draw(G[m],material,currentlight,r);
+      }
+  }
+
+  for(int c=0;c < xf.triangles.length; ++c) {
+    triple center=c > 0 ? xf.centers[c-1] : O;
+    render r=render(interaction(c == 0 ? Embedded : Billboard,center=center));
+    triangleGroup[][] groups=xf.triangles[c];
+    for(int m=0; m < groups.length; ++m) {
+      if(groups.initialized(m)) {
+        material material=xf.materials[m];
+        triangleGroup[] triangleGroups=groups[m];
+        for(triangleGroup g : triangleGroups) {
+          if(g.colors.length > 0)
+            draw(g.positions,g.positionIndices,g.normals,g.normalIndices,
+                 g.colors,g.colorIndices,r);
+          else
+            draw(g.positions,g.positionIndices,g.normals,g.normalIndices,
+                 material,r);
+        }
+      }
+    }
+  }
+
+  for(int m=0; m < xf.pixels.length; ++m) {
+    if(xf.pixels.initialized(m)) {
+      material material=xf.materials[m];
+      pixel[] pixels=xf.pixels[m];
+      for(pixel P : pixels)
+        pixel(P.point,material.p[0],P.width);
+    }
+  }
+}

Added: trunk/Master/texmf-dist/asymptote/v3dheadertypes.asy
===================================================================
--- trunk/Master/texmf-dist/asymptote/v3dheadertypes.asy	                        (rev 0)
+++ trunk/Master/texmf-dist/asymptote/v3dheadertypes.asy	2022-02-27 23:41:11 UTC (rev 62265)
@@ -0,0 +1,66 @@
+// Enum class for v3dheadertypes
+// AUTO-GENERATED from v3dheadertypes.csv
+// Generated at 2022-02-04 23:53:49.222250
+
+struct v3dheadertypes
+{
+  int canvasWidth=1;
+// UINT  Canvas width
+
+  int canvasHeight=2;
+// UINT  Canvas heighot
+
+  int absolute=3;
+// BOOL  true: absolute size; false: scale to canvas
+
+  int minBound=4;
+// TRIPLE  Scene minimum bounding box corners
+
+  int maxBound=5;
+// TRIPLE  Scene maximum bounding box corners
+
+  int orthographic=6;
+// BOOL  true: orthographic; false: perspective
+
+  int angleOfView=7;
+// REAL  Field of view angle (in radians)
+
+  int initialZoom=8;
+// REAL  Initial zoom
+
+  int viewportShift=9;
+// PAIR  Viewport shift (for perspective projection)
+
+  int viewportMargin=10;
+// PAIR  Margin around viewport
+
+  int light=11;
+// RGB  Direction and color of each point light source
+
+  int background=12;
+// RGBA  Background color
+
+  int zoomFactor=13;
+// REAL  Zoom base factor
+
+  int zoomPinchFactor=14;
+// REAL  Zoom pinch factor
+
+  int zoomPinchCap=15;
+// REAL  Zoom pinch limit
+
+  int zoomStep=16;
+// REAL  Zoom power step
+
+  int shiftHoldDistance=17;
+// REAL  Shift-mode maximum hold distance (pixels)
+
+  int shiftWaitTime=18;
+// REAL  Shift-mode hold time (milliseconds)
+
+  int vibrateTime=19;
+// REAL  Shift-mode vibrate time (milliseconds)
+
+};
+
+v3dheadertypes v3dheadertypes;// End of File

Added: trunk/Master/texmf-dist/asymptote/v3dtypes.asy
===================================================================
--- trunk/Master/texmf-dist/asymptote/v3dtypes.asy	                        (rev 0)
+++ trunk/Master/texmf-dist/asymptote/v3dtypes.asy	2022-02-27 23:41:11 UTC (rev 62265)
@@ -0,0 +1,34 @@
+// Enum class for v3dtypes
+// AUTO-GENERATED from v3dtypes.csv
+// Generated at 2022-02-04 23:53:49.158592
+
+struct v3dtypes
+{
+  int material=1;
+  int transform=2;
+  int element=3;
+  int centers=4;
+  int header=5;
+  int line=64;
+  int triangle=65;
+  int quad=66;
+  int curve=128;
+  int bezierTriangle=129;
+  int bezierPatch=130;
+  int lineColor=192;
+  int triangleColor=193;
+  int quadColor=194;
+  int curveColor=256;
+  int bezierTriangleColor=257;
+  int bezierPatchColor=258;
+  int triangles=512;
+  int disk=1024;
+  int cylinder=1025;
+  int tube=1026;
+  int sphere=1027;
+  int halfSphere=1028;
+  int animation=2048;
+  int pixel=4096;
+};
+
+v3dtypes v3dtypes;// End of File

Modified: trunk/Master/texmf-dist/asymptote/version.asy
===================================================================
--- trunk/Master/texmf-dist/asymptote/version.asy	2022-02-27 23:39:53 UTC (rev 62264)
+++ trunk/Master/texmf-dist/asymptote/version.asy	2022-02-27 23:41:11 UTC (rev 62265)
@@ -1 +1 @@
-string VERSION="2.70";
+string VERSION="2.78";

Modified: trunk/Master/texmf-dist/asymptote/webgl/asygl.js
===================================================================
--- trunk/Master/texmf-dist/asymptote/webgl/asygl.js	2022-02-27 23:39:53 UTC (rev 62264)
+++ trunk/Master/texmf-dist/asymptote/webgl/asygl.js	2022-02-27 23:41:11 UTC (rev 62265)
@@ -1,6 +1,6 @@
 /*@license
  AsyGL: Render Bezier patches and triangles via subdivision with WebGL.
-  Copyright 2019-2020: John C. Bowman and Supakorn "Jamie" Rassameemasmuang
+  Copyright 2019-2022: John C. Bowman and Supakorn "Jamie" Rassameemasmuang
   University of Alberta
 
 This program is free software; you can redistribute it and/or modify
@@ -36,4 +36,4 @@
 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 THE SOFTWARE.*/
-let vertex="\nattribute vec3 position;\n#ifdef WIDTH\nattribute float width;\n#endif\n#ifdef NORMAL\nattribute vec3 normal;\n#endif\nattribute float materialIndex;\n#ifdef COLOR\nattribute vec4 color;\n#endif\n\nuniform mat3 normMat;\nuniform mat4 viewMat;\nuniform mat4 projViewMat;\n\n#ifdef NORMAL\n#ifndef ORTHOGRAPHIC\nvarying vec3 ViewPosition;\n#endif\nvarying vec3 Normal;\n#endif\nvarying vec4 diffuse;\nvarying vec3 specular;\nvarying float roughness,metallic,fresnel0;\nvarying vec4 emissive;\n\nstruct Material {\n  vec4 diffuse,emissive,specular;\n  vec4 parameters;\n};\n\nuniform Material Materials[Nmaterials];\n\nvoid main(void)\n{\n  vec4 v=vec4(position,1.0);\n  gl_Position=projViewMat*v;\n#ifdef NORMAL\n#ifndef ORTHOGRAPHIC\n  ViewPosition=(viewMat*v).xyz;\n#endif      \n  Normal=normalize(normal*normMat);\n        \n  Material m;\n#ifdef TRANSPARENT\n  m=Materials[int(abs(materialIndex))-1];\n  emissive=m.emissive;\n  if(materialIndex >= 0.0) {\n    diffuse=m.diffuse;\n  } else {\n    diffuse=color;\n#if nlights == 0\n    emissive += color;\n#endif\n  }\n#else\n  m=Materials[int(materialIndex)];\n  emissive=m.emissive;\n#ifdef COLOR\n  diffuse=color;\n#if nlights == 0\n    emissive += color;\n#endif\n#else\n  diffuse=m.diffuse;\n#endif\n#endif\n  specular=m.specular.rgb;\n  vec4 parameters=m.parameters;\n  roughness=1.0-parameters[0];\n  metallic=parameters[1];\n  fresnel0=parameters[2];\n#else\n  emissive=Materials[int(materialIndex)].emissive;\n#endif\n#ifdef WIDTH\n  gl_PointSize=width;\n#endif\n}\n",fragment="\n#ifdef NORMAL\n#ifndef ORTHOGRAPHIC\nvarying vec3 ViewPosition;\n#endif\nvarying vec3 Normal;\nvarying vec4 diffuse;\nvarying vec3 specular;\nvarying float roughness,metallic,fresnel0;\n\nfloat Roughness2;\nvec3 normal;\n\nstruct Light {\n  vec3 direction;\n  vec3 color;\n};\n\nuniform Light Lights[Nlights];\n\nfloat NDF_TRG(vec3 h)\n{\n  float ndoth=max(dot(normal,h),0.0);\n  float alpha2=Roughness2*Roughness2;\n  float denom=ndoth*ndoth*(alpha2-1.0)+1.0;\n  return denom != 0.0 !
 ? alpha2/(denom*denom) : 0.0;\n}\n    \nfloat GGX_Geom(vec3 v)\n{\n  float ndotv=max(dot(v,normal),0.0);\n  float ap=1.0+Roughness2;\n  float k=0.125*ap*ap;\n  return ndotv/((ndotv*(1.0-k))+k);\n}\n    \nfloat Geom(vec3 v, vec3 l)\n{\n  return GGX_Geom(v)*GGX_Geom(l);\n}\n    \nfloat Fresnel(vec3 h, vec3 v, float fresnel0)\n{\n  float a=1.0-max(dot(h,v),0.0);\n  float b=a*a;\n  return fresnel0+(1.0-fresnel0)*b*b*a;\n}\n    \n// physical based shading using UE4 model.\nvec3 BRDF(vec3 viewDirection, vec3 lightDirection)\n{\n  vec3 lambertian=diffuse.rgb;\n  vec3 h=normalize(lightDirection+viewDirection);\n      \n  float omegain=max(dot(viewDirection,normal),0.0);\n  float omegali=max(dot(lightDirection,normal),0.0);\n      \n  float D=NDF_TRG(h);\n  float G=Geom(viewDirection,lightDirection);\n  float F=Fresnel(h,viewDirection,fresnel0);\n      \n  float denom=4.0*omegain*omegali;\n  float rawReflectance=denom > 0.0 ? (D*G)/denom : 0.0;\n      \n  vec3 dielectric=mix(lambertian,rawReflectance*specular,F);\n  vec3 metal=rawReflectance*diffuse.rgb;\n      \n  return mix(dielectric,metal,metallic);\n}\n#endif\nvarying vec4 emissive;\n    \nvoid main(void)\n{\n#if defined(NORMAL) && nlights > 0\n  normal=normalize(Normal);\n  normal=gl_FrontFacing ? normal : -normal;\n#ifdef ORTHOGRAPHIC\n  vec3 viewDir=vec3(0.0,0.0,1.0);\n#else\n  vec3 viewDir=-normalize(ViewPosition);\n#endif\n  Roughness2=roughness*roughness;\n  vec3 color=emissive.rgb;\n  for(int i=0; i < nlights; ++i) {\n    Light Li=Lights[i];\n    vec3 L=Li.direction;\n    float cosTheta=max(dot(normal,L),0.0);\n    vec3 radiance=cosTheta*Li.color;\n    color += BRDF(viewDir,L)*radiance;\n  }\n  gl_FragColor=vec4(color,diffuse.a);\n#else\n  gl_FragColor=emissive;\n#endif\n}\n";!function(t,e){if("object"==typeof exports&&"object"==typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{var i=e();for(var a in i)("object"==typeof exports?exports:t)[a]=i[a]}}("undefined"!=typeof self?self:this,(function(){return function(t)!
 {var e={};function i(a){if(e[a])return e[a].exports;var r=e[a]={i:a,l:!1,exports:{}};return t[a].call(r.exports,r,r.exports,i),r.l=!0,r.exports}return i.m=t,i.c=e,i.d=function(t,e,a){i.o(t,e)||Object.defineProperty(t,e,{configurable:!1,enumerable:!0,get:a})},i.n=function(t){var e=t&&t.__esModule?function(){return t.default}:function(){return t};return i.d(e,"a",e),e},i.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},i.p="",i(i.s=1)}([function(t,e,i){"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.setMatrixArrayType=function(t){e.ARRAY_TYPE=t},e.toRadian=function(t){return t*r},e.equals=function(t,e){return Math.abs(t-e)<=a*Math.max(1,Math.abs(t),Math.abs(e))};var a=e.EPSILON=1e-6;e.ARRAY_TYPE="undefined"!=typeof Float32Array?Float32Array:Array,e.RANDOM=Math.random;var r=Math.PI/180},function(t,e,i){"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.mat4=e.mat3=void 0;var a=n(i(2)),r=n(i(3));function n(t){if(t&&t.__esModule)return t;var e={};if(null!=t)for(var i in t)Object.prototype.hasOwnProperty.call(t,i)&&(e[i]=t[i]);return e.default=t,e}e.mat3=a,e.mat4=r},function(t,e,i){"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.create=function(){var t=new a.ARRAY_TYPE(9);return t[0]=1,t[1]=0,t[2]=0,t[3]=0,t[4]=1,t[5]=0,t[6]=0,t[7]=0,t[8]=1,t},e.fromMat4=function(t,e){return t[0]=e[0],t[1]=e[1],t[2]=e[2],t[3]=e[4],t[4]=e[5],t[5]=e[6],t[6]=e[8],t[7]=e[9],t[8]=e[10],t},e.invert=function(t,e){var i=e[0],a=e[1],r=e[2],n=e[3],s=e[4],o=e[5],h=e[6],l=e[7],c=e[8],d=c*s-o*l,m=-c*n+o*h,f=l*n-s*h,u=i*d+a*m+r*f;if(!u)return null;return u=1/u,t[0]=d*u,t[1]=(-c*a+r*l)*u,t[2]=(o*a-r*s)*u,t[3]=m*u,t[4]=(c*i-r*h)*u,t[5]=(-o*i+r*n)*u,t[6]=f*u,t[7]=(-l*i+a*h)*u,t[8]=(s*i-a*n)*u,t};var a=function(t){if(t&&t.__esModule)return t;var e={};if(null!=t)for(var i in t)Object.prototype.hasOwnProperty.call(t,i)&&(e[i]=t[i]);return e.default=t,e}(i(0))},function(t,e,i){"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.create=function(){var t=new a.ARRAY_TYPE(16);return t[0!
 ]=1,t[1]=0,t[2]=0,t[3]=0,t[4]=0,t[5]=1,t[6]=0,t[7]=0,t[8]=0,t[9]=0,t[10]=1,t[11]=0,t[12]=0,t[13]=0,t[14]=0,t[15]=1,t},e.identity=function(t){return t[0]=1,t[1]=0,t[2]=0,t[3]=0,t[4]=0,t[5]=1,t[6]=0,t[7]=0,t[8]=0,t[9]=0,t[10]=1,t[11]=0,t[12]=0,t[13]=0,t[14]=0,t[15]=1,t},e.invert=function(t,e){var i=e[0],a=e[1],r=e[2],n=e[3],s=e[4],o=e[5],h=e[6],l=e[7],c=e[8],d=e[9],m=e[10],f=e[11],u=e[12],p=e[13],v=e[14],g=e[15],x=i*o-a*s,w=i*h-r*s,M=i*l-n*s,b=a*h-r*o,S=a*l-n*o,P=r*l-n*h,A=c*p-d*u,y=c*v-m*u,T=c*g-f*u,R=d*v-m*p,D=d*g-f*p,I=m*g-f*v,z=x*I-w*D+M*R+b*T-S*y+P*A;if(!z)return null;return z=1/z,t[0]=(o*I-h*D+l*R)*z,t[1]=(r*D-a*I-n*R)*z,t[2]=(p*P-v*S+g*b)*z,t[3]=(m*S-d*P-f*b)*z,t[4]=(h*T-s*I-l*y)*z,t[5]=(i*I-r*T+n*y)*z,t[6]=(v*M-u*P-g*w)*z,t[7]=(c*P-m*M+f*w)*z,t[8]=(s*D-o*T+l*A)*z,t[9]=(a*T-i*D-n*A)*z,t[10]=(u*S-p*M+g*x)*z,t[11]=(d*M-c*S-f*x)*z,t[12]=(o*y-s*R-h*A)*z,t[13]=(i*R-a*y+r*A)*z,t[14]=(p*w-u*b-v*x)*z,t[15]=(c*b-d*w+m*x)*z,t},e.multiply=r,e.translate=function(t,e,i){var a=i[0],r=i[1],n=i[2],s=void 0,o=void 0,h=void 0,l=void 0,c=void 0,d=void 0,m=void 0,f=void 0,u=void 0,p=void 0,v=void 0,g=void 0;e===t?(t[12]=e[0]*a+e[4]*r+e[8]*n+e[12],t[13]=e[1]*a+e[5]*r+e[9]*n+e[13],t[14]=e[2]*a+e[6]*r+e[10]*n+e[14],t[15]=e[3]*a+e[7]*r+e[11]*n+e[15]):(s=e[0],o=e[1],h=e[2],l=e[3],c=e[4],d=e[5],m=e[6],f=e[7],u=e[8],p=e[9],v=e[10],g=e[11],t[0]=s,t[1]=o,t[2]=h,t[3]=l,t[4]=c,t[5]=d,t[6]=m,t[7]=f,t[8]=u,t[9]=p,t[10]=v,t[11]=g,t[12]=s*a+c*r+u*n+e[12],t[13]=o*a+d*r+p*n+e[13],t[14]=h*a+m*r+v*n+e[14],t[15]=l*a+f*r+g*n+e[15]);return t},e.rotate=function(t,e,i,r){var n,s,o,h,l,c,d,m,f,u,p,v,g,x,w,M,b,S,P,A,y,T,R,D,I=r[0],z=r[1],L=r[2],N=Math.sqrt(I*I+z*z+L*L);if(Math.abs(N)<a.EPSILON)return null;I*=N=1/N,z*=N,L*=N,n=Math.sin(i),s=Math.cos(i),o=1-s,h=e[0],l=e[1],c=e[2],d=e[3],m=e[4],f=e[5],u=e[6],p=e[7],v=e[8],g=e[9],x=e[10],w=e[11],M=I*I*o+s,b=z*I*o+L*n,S=L*I*o-z*n,P=I*z*o-L*n,A=z*z*o+s,y=L*z*o+I*n,T=I*L*o+z*n,R=z*L*o-I*n,D=L*L*o+s,t[0]=h*M+m*b+v*S,t[1]=l*M+f*b+g*S,t[2]=c*M+u*b+x*S,t[3]=d*M+p*b+w*S,t[4]=h*P+m*A+v*y,t[5]=l*P+f*A+g*y,t[6]=c*P+u!
 *A+x*y,t[7]=d*P+p*A+w*y,t[8]=h*T+m*R+v*D,t[9]=l*T+f*R+g*D,t[10]=c*T+u*R+x*D,t[11]=d*T+p*R+w*D,e!==t&&(t[12]=e[12],t[13]=e[13],t[14]=e[14],t[15]=e[15]);return t},e.fromTranslation=function(t,e){return t[0]=1,t[1]=0,t[2]=0,t[3]=0,t[4]=0,t[5]=1,t[6]=0,t[7]=0,t[8]=0,t[9]=0,t[10]=1,t[11]=0,t[12]=e[0],t[13]=e[1],t[14]=e[2],t[15]=1,t},e.fromRotation=function(t,e,i){var r,n,s,o=i[0],h=i[1],l=i[2],c=Math.sqrt(o*o+h*h+l*l);if(Math.abs(c)<a.EPSILON)return null;return o*=c=1/c,h*=c,l*=c,r=Math.sin(e),n=Math.cos(e),s=1-n,t[0]=o*o*s+n,t[1]=h*o*s+l*r,t[2]=l*o*s-h*r,t[3]=0,t[4]=o*h*s-l*r,t[5]=h*h*s+n,t[6]=l*h*s+o*r,t[7]=0,t[8]=o*l*s+h*r,t[9]=h*l*s-o*r,t[10]=l*l*s+n,t[11]=0,t[12]=0,t[13]=0,t[14]=0,t[15]=1,t},e.frustum=function(t,e,i,a,r,n,s){var o=1/(i-e),h=1/(r-a),l=1/(n-s);return t[0]=2*n*o,t[1]=0,t[2]=0,t[3]=0,t[4]=0,t[5]=2*n*h,t[6]=0,t[7]=0,t[8]=(i+e)*o,t[9]=(r+a)*h,t[10]=(s+n)*l,t[11]=-1,t[12]=0,t[13]=0,t[14]=s*n*2*l,t[15]=0,t},e.ortho=function(t,e,i,a,r,n,s){var o=1/(e-i),h=1/(a-r),l=1/(n-s);return t[0]=-2*o,t[1]=0,t[2]=0,t[3]=0,t[4]=0,t[5]=-2*h,t[6]=0,t[7]=0,t[8]=0,t[9]=0,t[10]=2*l,t[11]=0,t[12]=(e+i)*o,t[13]=(r+a)*h,t[14]=(s+n)*l,t[15]=1,t};var a=function(t){if(t&&t.__esModule)return t;var e={};if(null!=t)for(var i in t)Object.prototype.hasOwnProperty.call(t,i)&&(e[i]=t[i]);return e.default=t,e}(i(0));function r(t,e,i){var a=e[0],r=e[1],n=e[2],s=e[3],o=e[4],h=e[5],l=e[6],c=e[7],d=e[8],m=e[9],f=e[10],u=e[11],p=e[12],v=e[13],g=e[14],x=e[15],w=i[0],M=i[1],b=i[2],S=i[3];return t[0]=w*a+M*o+b*d+S*p,t[1]=w*r+M*h+b*m+S*v,t[2]=w*n+M*l+b*f+S*g,t[3]=w*s+M*c+b*u+S*x,w=i[4],M=i[5],b=i[6],S=i[7],t[4]=w*a+M*o+b*d+S*p,t[5]=w*r+M*h+b*m+S*v,t[6]=w*n+M*l+b*f+S*g,t[7]=w*s+M*c+b*u+S*x,w=i[8],M=i[9],b=i[10],S=i[11],t[8]=w*a+M*o+b*d+S*p,t[9]=w*r+M*h+b*m+S*v,t[10]=w*n+M*l+b*f+S*g,t[11]=w*s+M*c+b*u+S*x,w=i[12],M=i[13],b=i[14],S=i[15],t[12]=w*a+M*o+b*d+S*p,t[13]=w*r+M*h+b*m+S*v,t[14]=w*n+M*l+b*f+S*g,t[15]=w*s+M*c+b*u+S*x,t}}])}));let canvasWidth,canvasHeight,canvasWidth0,canvasHeight0,b,B,angle,Zoom0,zoom0,viewportmargin,zoomFactor,zoomPinchFact!
 or,zoomPinchCap,zoomStep,shiftHoldDistance,shiftWaitTime,vibrateTime,embedded,canvas,gl,alpha,offscreen,context,maxMaterials,halfCanvasWidth,halfCanvasHeight,Zoom,maxViewportWidth,maxViewportHeight,P=[],Materials=[],Lights=[],Centers=[],Background=[1,1,1,1],absolute=!1,viewportshift=[0,0],nlights=0,Nmaterials=2,materials=[],pixel=.75,zoomRemeshFactor=1.5,FillFactor=.1;const windowTrim=10;let lastZoom,H,zmin,zmax,size2,ArcballFactor,third=1/3,rotMat=mat4.create(),projMat=mat4.create(),viewMat=mat4.create(),projViewMat=mat4.create(),normMat=mat3.create(),viewMat3=mat3.create(),cjMatInv=mat4.create(),T=mat4.create(),center={x:0,y:0,z:0},shift={x:0,y:0},viewParam={xmin:0,xmax:0,ymin:0,ymax:0,zmin:0,zmax:0},remesh=!0,wireframe=0,mouseDownOrTouchActive=!1,lastMouseX=null,lastMouseY=null,touchID=null,Positions=[],Normals=[],Colors=[],Indices=[];class Material{constructor(t,e,i,a,r,n){this.diffuse=t,this.emissive=e,this.specular=i,this.shininess=a,this.metallic=r,this.fresnel0=n}setUniform(t,e){let i=i=>gl.getUniformLocation(t,"Materials["+e+"]."+i);gl.uniform4fv(i("diffuse"),new Float32Array(this.diffuse)),gl.uniform4fv(i("emissive"),new Float32Array(this.emissive)),gl.uniform4fv(i("specular"),new Float32Array(this.specular)),gl.uniform4f(i("parameters"),this.shininess,this.metallic,this.fresnel0,0)}}let indexExt,TRIANGLES,material0Data,material1Data,materialData,colorData,transparentData,triangleData,materialIndex,enumPointLight=1,enumDirectionalLight=2;class Light{constructor(t,e){this.direction=t,this.color=e}setUniform(t,e){let i=i=>gl.getUniformLocation(t,"Lights["+e+"]."+i);gl.uniform3fv(i("direction"),new Float32Array(this.direction)),gl.uniform3fv(i("color"),new Float32Array(this.color))}}function initShaders(){let t=gl.getParameter(gl.MAX_VERTEX_UNIFORM_VECTORS);maxMaterials=Math.floor((t-14)/4),Nmaterials=Math.min(Math.max(Nmaterials,Materials.length),maxMaterials),pixelShader=initShader(["WIDTH"]),materialShader=initShader(["NORMAL"]),colorShader=initShader(["NORMAL","COLOR"]),transparentShader=initShader(["!
 NORMAL","COLOR","TRANSPARENT"])}function deleteShaders(){gl.deleteProgram(transparentShader),gl.deleteProgram(colorShader),gl.deleteProgram(materialShader),gl.deleteProgram(pixelShader)}function noGL(){gl||alert("Could not initialize WebGL")}function saveAttributes(){let t=window.top.document.asygl[alpha];t.gl=gl,t.nlights=Lights.length,t.Nmaterials=Nmaterials,t.maxMaterials=maxMaterials,t.pixelShader=pixelShader,t.materialShader=materialShader,t.colorShader=colorShader,t.transparentShader=transparentShader}function restoreAttributes(){let t=window.top.document.asygl[alpha];gl=t.gl,nlights=t.nlights,Nmaterials=t.Nmaterials,maxMaterials=t.maxMaterials,pixelShader=t.pixelShader,materialShader=t.materialShader,colorShader=t.colorShader,transparentShader=t.transparentShader}function initGL(){if(alpha=Background[3]<1,embedded){let t=window.top.document;null==t.asygl&&(t.asygl=Array(2)),context=canvas.getContext("2d"),offscreen=t.offscreen,offscreen||(offscreen=t.createElement("canvas"),t.offscreen=offscreen),t.asygl[alpha]&&t.asygl[alpha].gl?(restoreAttributes(),(Lights.length!=nlights||Math.min(Materials.length,maxMaterials)>Nmaterials)&&(initShaders(),saveAttributes())):(gl=offscreen.getContext("webgl",{alpha:alpha}),gl||noGL(),initShaders(),t.asygl[alpha]={},saveAttributes())}else gl=canvas.getContext("webgl",{alpha:alpha}),gl||noGL(),initShaders();indexExt=gl.getExtension("OES_element_index_uint"),TRIANGLES=gl.TRIANGLES,material0Data=new vertexBuffer(gl.POINTS),material1Data=new vertexBuffer(gl.LINES),materialData=new vertexBuffer,colorData=new vertexBuffer,transparentData=new vertexBuffer,triangleData=new vertexBuffer}function getShader(t,e,i,a=[]){let r=`#version 100\n#ifdef GL_FRAGMENT_PRECISION_HIGH\n  precision highp float;\n#else\n  precision mediump float;\n#endif\n  #define nlights ${0==wireframe?Lights.length:0}\n\n  const int Nlights=${Math.max(Lights.length,1)};\n\n  #define Nmaterials ${Nmaterials}\n`;orthographic&&(r+="#define ORTHOGRAPHIC\n"),a.forEach(t=>r+="#define "+t+"\n");let n=t.createShader(i!
 );return t.shaderSource(n,r+e),t.compileShader(n),t.getShaderParameter(n,t.COMPILE_STATUS)?n:(alert(t.getShaderInfoLog(n)),null)}function registerBuffer(t,e,i,a=gl.ARRAY_BUFFER){return t.length>0&&(0==e&&(e=gl.createBuffer(),i=!0),gl.bindBuffer(a,e),i&&gl.bufferData(a,t,gl.STATIC_DRAW)),e}function drawBuffer(t,e,i=t.indices){if(0==t.indices.length)return;let a=e!=pixelShader;setUniforms(t,e);let r=remesh||t.partial||!t.rendered;t.verticesBuffer=registerBuffer(new Float32Array(t.vertices),t.verticesBuffer,r),gl.vertexAttribPointer(positionAttribute,3,gl.FLOAT,!1,a?24:16,0),a&&Lights.length>0?gl.vertexAttribPointer(normalAttribute,3,gl.FLOAT,!1,24,12):pixel&&gl.vertexAttribPointer(widthAttribute,1,gl.FLOAT,!1,16,12),t.materialsBuffer=registerBuffer(new Int16Array(t.materialIndices),t.materialsBuffer,r),gl.vertexAttribPointer(materialAttribute,1,gl.SHORT,!1,2,0),e!=colorShader&&e!=transparentShader||(t.colorsBuffer=registerBuffer(new Uint8Array(t.colors),t.colorsBuffer,r),gl.vertexAttribPointer(colorAttribute,4,gl.UNSIGNED_BYTE,!0,0,0)),t.indicesBuffer=registerBuffer(indexExt?new Uint32Array(i):new Uint16Array(i),t.indicesBuffer,r,gl.ELEMENT_ARRAY_BUFFER),t.rendered=!0,gl.drawElements(a?wireframe?gl.LINES:t.type:gl.POINTS,i.length,indexExt?gl.UNSIGNED_INT:gl.UNSIGNED_SHORT,0)}class vertexBuffer{constructor(t){this.type=t||TRIANGLES,this.verticesBuffer=0,this.materialsBuffer=0,this.colorsBuffer=0,this.indicesBuffer=0,this.rendered=!1,this.partial=!1,this.clear()}clear(){this.vertices=[],this.materialIndices=[],this.colors=[],this.indices=[],this.nvertices=0,this.materials=[],this.materialTable=[]}vertex(t,e){return this.vertices.push(t[0]),this.vertices.push(t[1]),this.vertices.push(t[2]),this.vertices.push(e[0]),this.vertices.push(e[1]),this.vertices.push(e[2]),this.materialIndices.push(materialIndex),this.nvertices++}Vertex(t,e,i=[0,0,0,0]){return this.vertices.push(t[0]),this.vertices.push(t[1]),this.vertices.push(t[2]),this.vertices.push(e[0]),this.vertices.push(e[1]),this.vertices.push(e[2]),this.materialIndice!
 s.push(materialIndex),this.colors.push(i[0]),this.colors.push(i[1]),this.colors.push(i[2]),this.colors.push(i[3]),this.nvertices++}vertex0(t,e){return this.vertices.push(t[0]),this.vertices.push(t[1]),this.vertices.push(t[2]),this.vertices.push(e),this.materialIndices.push(materialIndex),this.nvertices++}iVertex(t,e,i,a=[0,0,0,0]){let r=6*t;this.vertices[r]=e[0],this.vertices[r+1]=e[1],this.vertices[r+2]=e[2],this.vertices[r+3]=i[0],this.vertices[r+4]=i[1],this.vertices[r+5]=i[2],this.materialIndices[t]=materialIndex;let n=4*t;this.colors[n]=a[0],this.colors[n+1]=a[1],this.colors[n+2]=a[2],this.colors[n+3]=a[3],this.indices.push(t)}append(t){append(this.vertices,t.vertices),append(this.materialIndices,t.materialIndices),append(this.colors,t.colors),appendOffset(this.indices,t.indices,this.nvertices),this.nvertices+=t.nvertices}}function append(t,e){let i=t.length,a=e.length;t.length+=a;for(let r=0;r<a;++r)t[i+r]=e[r]}function appendOffset(t,e,i){let a=t.length,r=e.length;t.length+=e.length;for(let n=0;n<r;++n)t[a+n]=e[n]+i}class Geometry{constructor(){this.data=new vertexBuffer,this.Onscreen=!1,this.m=[]}offscreen(t){let e=projViewMat,i=t[0],a=i[0],r=i[1],n=i[2],s=1/(e[3]*a+e[7]*r+e[11]*n+e[15]);this.x=this.X=(e[0]*a+e[4]*r+e[8]*n+e[12])*s,this.y=this.Y=(e[1]*a+e[5]*r+e[9]*n+e[13])*s;for(let i=1,a=t.length;i<a;++i){let a=t[i],r=a[0],n=a[1],s=a[2],o=1/(e[3]*r+e[7]*n+e[11]*s+e[15]),h=(e[0]*r+e[4]*n+e[8]*s+e[12])*o,l=(e[1]*r+e[5]*n+e[9]*s+e[13])*o;h<this.x?this.x=h:h>this.X&&(this.X=h),l<this.y?this.y=l:l>this.Y&&(this.Y=l)}return(this.X<-1.01||this.x>1.01||this.Y<-1.01||this.y>1.01)&&(this.Onscreen=!1,!0)}T(t){let e=this.c[0],i=this.c[1],a=this.c[2],r=t[0]-e,n=t[1]-i,s=t[2]-a;return[r*normMat[0]+n*normMat[3]+s*normMat[6]+e,r*normMat[1]+n*normMat[4]+s*normMat[7]+i,r*normMat[2]+n*normMat[5]+s*normMat[8]+a]}Tcorners(t,e){return[this.T(t),this.T([t[0],t[1],e[2]]),this.T([t[0],e[1],t[2]]),this.T([t[0],e[1],e[2]]),this.T([e[0],t[1],t[2]]),this.T([e[0],t[1],e[2]]),this.T([e[0],e[1],t[2]]),this.T(e)]}setMaterial(t,e){null!
 ==t.materialTable[this.MaterialIndex]&&(t.materials.length>=Nmaterials&&(t.partial=!0,e()),t.materialTable[this.MaterialIndex]=t.materials.length,t.materials.push(Materials[this.MaterialIndex])),materialIndex=t.materialTable[this.MaterialIndex]}render(){let t;if(this.setMaterialIndex(),0==this.CenterIndex?t=corners(this.Min,this.Max):(this.c=Centers[this.CenterIndex-1],t=this.Tcorners(this.Min,this.Max)),this.offscreen(t))return this.data.clear(),void this.notRendered();let e,i=this.controlpoints;if(0==this.CenterIndex){if(!remesh&&this.Onscreen)return void this.append();e=i}else{let t=i.length;e=Array(t);for(let a=0;a<t;++a)e[a]=this.T(i[a])}let a=orthographic?1:this.Min[2]/B[2],r=pixel*Math.hypot(a*(viewParam.xmax-viewParam.xmin),a*(viewParam.ymax-viewParam.ymin))/size2;this.res2=r*r,this.Epsilon=FillFactor*r,this.data.clear(),this.notRendered(),this.Onscreen=!0,this.process(e)}}class BezierPatch extends Geometry{constructor(t,e,i,a,r,n){super(),this.controlpoints=t,this.Min=a,this.Max=r,this.color=n,this.CenterIndex=e;let s=t.length;if(n){let t=n[0][3]+n[1][3]+n[2][3];this.transparent=16==s||4==s?t+n[3][3]<1020:t<765}else this.transparent=Materials[i].diffuse[3]<1;this.MaterialIndex=i,this.vertex=this.transparent?this.data.Vertex.bind(this.data):this.data.vertex.bind(this.data),this.L2norm(this.controlpoints)}setMaterialIndex(){this.transparent?this.setMaterial(transparentData,drawTransparent):this.color?this.setMaterial(colorData,drawColor):this.setMaterial(materialData,drawMaterial)}L2norm(t){let e=t[0];this.epsilon=0;let i=t.length;for(let a=1;a<i;++a)this.epsilon=Math.max(this.epsilon,abs2([t[a][0]-e[0],t[a][1]-e[1],t[a][2]-e[2]]));this.epsilon*=Number.EPSILON}processTriangle(t){let e=t[0],i=t[1],a=t[2],r=unit(cross([i[0]-e[0],i[1]-e[1],i[2]-e[2]],[a[0]-e[0],a[1]-e[1],a[2]-e[2]]));if(!this.offscreen([e,i,a])){let t,n,s;this.color?(t=this.data.Vertex(e,r,this.color[0]),n=this.data.Vertex(i,r,this.color[1]),s=this.data.Vertex(a,r,this.color[2])):(t=this.vertex(e,r),n=this.vertex(i,r),s=this.vertex(a,r)),0==!
 wireframe?(this.data.indices.push(t),this.data.indices.push(n),this.data.indices.push(s)):(this.data.indices.push(t),this.data.indices.push(n),this.data.indices.push(n),this.data.indices.push(s),this.data.indices.push(s),this.data.indices.push(t)),this.append()}}processQuad(t){let e=t[0],i=t[1],a=t[2],r=t[3],n=cross([i[0]-e[0],i[1]-e[1],i[2]-e[2]],[a[0]-i[0],a[1]-i[1],a[2]-i[2]]),s=cross([a[0]-r[0],a[1]-r[1],a[2]-r[2]],[r[0]-e[0],r[1]-e[1],r[2]-e[2]]),o=unit([n[0]+s[0],n[1]+s[1],n[2]+s[2]]);if(!this.offscreen([e,i,a,r])){let t,n,s,h;this.color?(t=this.data.Vertex(e,o,this.color[0]),n=this.data.Vertex(i,o,this.color[1]),s=this.data.Vertex(a,o,this.color[2]),h=this.data.Vertex(r,o,this.color[3])):(t=this.vertex(e,o),n=this.vertex(i,o),s=this.vertex(a,o),h=this.vertex(r,o)),0==wireframe?(this.data.indices.push(t),this.data.indices.push(n),this.data.indices.push(s),this.data.indices.push(t),this.data.indices.push(s),this.data.indices.push(h)):(this.data.indices.push(t),this.data.indices.push(n),this.data.indices.push(n),this.data.indices.push(s),this.data.indices.push(s),this.data.indices.push(h),this.data.indices.push(h),this.data.indices.push(t)),this.append()}}curve(t,e,i,a,r){new BezierCurve([t[e],t[i],t[a],t[r]],0,materialIndex,this.Min,this.Max).render()}process(t){if(this.transparent&&1!=wireframe&&(materialIndex=this.color?-1-materialIndex:1+materialIndex),10==t.length)return this.process3(t);if(3==t.length)return this.processTriangle(t);if(4==t.length)return this.processQuad(t);if(1==wireframe)return this.curve(t,0,4,8,12),this.curve(t,12,13,14,15),this.curve(t,15,11,7,3),void this.curve(t,3,2,1,0);let e=t[0],i=t[3],a=t[12],r=t[15],n=this.normal(i,t[2],t[1],e,t[4],t[8],a);abs2(n)<this.epsilon&&(n=this.normal(i,t[2],t[1],e,t[13],t[14],r),abs2(n)<this.epsilon&&(n=this.normal(r,t[11],t[7],i,t[4],t[8],a)));let s=this.normal(e,t[4],t[8],a,t[13],t[14],r);abs2(s)<this.epsilon&&(s=this.normal(e,t[4],t[8],a,t[11],t[7],i),abs2(s)<this.epsilon&&(s=this.normal(i,t[2],t[1],e,t[13],t[14],r)));let o=this.normal(a,t[13],t[!
 14],r,t[11],t[7],i);abs2(o)<this.epsilon&&(o=this.normal(a,t[13],t[14],r,t[2],t[1],e),abs2(o)<this.epsilon&&(o=this.normal(e,t[4],t[8],a,t[11],t[7],i)));let h=this.normal(r,t[11],t[7],i,t[2],t[1],e);if(abs2(h)<this.epsilon&&(h=this.normal(r,t[11],t[7],i,t[4],t[8],a),abs2(h)<this.epsilon&&(h=this.normal(a,t[13],t[14],r,t[2],t[1],e))),this.color){let l=this.color[0],c=this.color[1],d=this.color[2],m=this.color[3],f=this.data.Vertex(e,n,l),u=this.data.Vertex(a,s,c),p=this.data.Vertex(r,o,d),v=this.data.Vertex(i,h,m);this.Render(t,f,u,p,v,e,a,r,i,!1,!1,!1,!1,l,c,d,m)}else{let l=this.vertex(e,n),c=this.vertex(a,s),d=this.vertex(r,o),m=this.vertex(i,h);this.Render(t,l,c,d,m,e,a,r,i,!1,!1,!1,!1)}this.data.indices.length>0&&this.append()}append(){this.transparent?transparentData.append(this.data):this.color?colorData.append(this.data):materialData.append(this.data)}notRendered(){this.transparent?transparentData.rendered=!1:this.color?colorData.rendered=!1:materialData.rendered=!1}Render(t,e,i,a,r,n,s,o,h,l,c,d,m,f,u,p,v){let g=this.Distance(t);if(g[0]<this.res2&&g[1]<this.res2)this.offscreen([n,s,o])||(0==wireframe?(this.data.indices.push(e),this.data.indices.push(i),this.data.indices.push(a)):(this.data.indices.push(e),this.data.indices.push(i),this.data.indices.push(i),this.data.indices.push(a))),this.offscreen([n,o,h])||(0==wireframe?(this.data.indices.push(e),this.data.indices.push(a),this.data.indices.push(r)):(this.data.indices.push(a),this.data.indices.push(r),this.data.indices.push(r),this.data.indices.push(e)));else{if(this.offscreen(t))return;let x=t[0],w=t[3],M=t[12],b=t[15];if(g[0]<this.res2){let g=new Split3(x,t[1],t[2],w),S=new Split3(t[4],t[5],t[6],t[7]),P=new Split3(t[8],t[9],t[10],t[11]),A=new Split3(M,t[13],t[14],b),y=[x,g.m0,g.m3,g.m5,t[4],S.m0,S.m3,S.m5,t[8],P.m0,P.m3,P.m5,M,A.m0,A.m3,A.m5],T=[g.m5,g.m4,g.m2,w,S.m5,S.m4,S.m2,t[7],P.m5,P.m4,P.m2,t[11],A.m5,A.m4,A.m2,b],R=this.normal(y[12],y[13],y[14],y[15],y[11],y[7],y[3]);abs2(R)<=this.epsilon&&(R=this.normal(y[12],y[13],y[14],y[15],y[2],y[1],y[0]),a!
 bs2(R)<=this.epsilon&&(R=this.normal(y[0],y[4],y[8],y[12],y[11],y[7],y[3])));let D=this.normal(T[3],T[2],T[1],T[0],T[4],T[8],T[12]);abs2(D)<=this.epsilon&&(D=this.normal(T[3],T[2],T[1],T[0],T[13],T[14],T[15]),abs2(D)<=this.epsilon&&(D=this.normal(T[15],T[11],T[7],T[3],T[4],T[8],T[12])));let I=this.Epsilon,z=[.5*(s[0]+o[0]),.5*(s[1]+o[1]),.5*(s[2]+o[2])];if(!c)if(c=Straightness(M,t[13],t[14],b)<this.res2){let t=unit(this.differential(T[12],T[8],T[4],T[0]));z=[z[0]-I*t[0],z[1]-I*t[1],z[2]-I*t[2]]}else z=y[15];let L=[.5*(h[0]+n[0]),.5*(h[1]+n[1]),.5*(h[2]+n[2])];if(!m)if(m=Straightness(x,t[1],t[2],w)<this.res2){let t=unit(this.differential(y[3],y[7],y[11],y[15]));L=[L[0]-I*t[0],L[1]-I*t[1],L[2]-I*t[2]]}else L=T[0];if(f){let t=Array(4),g=Array(4);for(let e=0;e<4;++e)t[e]=.5*(u[e]+p[e]),g[e]=.5*(v[e]+f[e]);let x=this.data.Vertex(z,R,t),w=this.data.Vertex(L,D,g);this.Render(y,e,i,x,w,n,s,z,L,l,c,!1,m,f,u,t,g),this.Render(T,w,x,a,r,L,z,o,h,!1,c,d,m,g,t,p,v)}else{let t=this.vertex(z,R),f=this.vertex(L,D);this.Render(y,e,i,t,f,n,s,z,L,l,c,!1,m),this.Render(T,f,t,a,r,L,z,o,h,!1,c,d,m)}return}if(g[1]<this.res2){let g=new Split3(x,t[4],t[8],M),S=new Split3(t[1],t[5],t[9],t[13]),P=new Split3(t[2],t[6],t[10],t[14]),A=new Split3(w,t[7],t[11],b),y=[x,t[1],t[2],w,g.m0,S.m0,P.m0,A.m0,g.m3,S.m3,P.m3,A.m3,g.m5,S.m5,P.m5,A.m5],T=[g.m5,S.m5,P.m5,A.m5,g.m4,S.m4,P.m4,A.m4,g.m2,S.m2,P.m2,A.m2,M,t[13],t[14],b],R=this.normal(y[0],y[4],y[8],y[12],y[13],y[14],y[15]);abs2(R)<=this.epsilon&&(R=this.normal(y[0],y[4],y[8],y[12],y[11],y[7],y[3]),abs2(R)<=this.epsilon&&(R=this.normal(y[3],y[2],y[1],y[0],y[13],y[14],y[15])));let D=this.normal(T[15],T[11],T[7],T[3],T[2],T[1],T[0]);abs2(D)<=this.epsilon&&(D=this.normal(T[15],T[11],T[7],T[3],T[4],T[8],T[12]),abs2(D)<=this.epsilon&&(D=this.normal(T[12],T[13],T[14],T[15],T[2],T[1],T[0])));let I=this.Epsilon,z=[.5*(n[0]+s[0]),.5*(n[1]+s[1]),.5*(n[2]+s[2])];if(!l)if(l=Straightness(x,t[4],t[8],M)<this.res2){let t=unit(this.differential(T[0],T[1],T[2],T[3]));z=[z[0]-I*t[0],z[1]-I*t[1],z[2]-I*t[2]]}else z=y!
 [12];let L=[.5*(o[0]+h[0]),.5*(o[1]+h[1]),.5*(o[2]+h[2])];if(!d)if(d=Straightness(b,t[11],t[7],w)<this.res2){let t=unit(this.differential(y[15],y[14],y[13],y[12]));L=[L[0]-I*t[0],L[1]-I*t[1],L[2]-I*t[2]]}else L=T[3];if(f){let t=Array(4),g=Array(4);for(let e=0;e<4;++e)t[e]=.5*(f[e]+u[e]),g[e]=.5*(p[e]+v[e]);let x=this.data.Vertex(z,R,t),w=this.data.Vertex(L,D,g);this.Render(y,e,x,w,r,n,z,L,h,l,!1,d,m,f,t,g,v),this.Render(T,x,i,a,w,z,s,o,L,l,c,d,!1,t,u,p,g)}else{let t=this.vertex(z,R),f=this.vertex(L,D);this.Render(y,e,t,f,r,n,z,L,h,l,!1,d,m),this.Render(T,t,i,a,f,z,s,o,L,l,c,d,!1)}return}let S=new Split3(x,t[1],t[2],w),P=new Split3(t[4],t[5],t[6],t[7]),A=new Split3(t[8],t[9],t[10],t[11]),y=new Split3(M,t[13],t[14],b),T=new Split3(x,t[4],t[8],M),R=new Split3(S.m0,P.m0,A.m0,y.m0),D=new Split3(S.m3,P.m3,A.m3,y.m3),I=new Split3(S.m5,P.m5,A.m5,y.m5),z=new Split3(S.m4,P.m4,A.m4,y.m4),L=new Split3(S.m2,P.m2,A.m2,y.m2),N=new Split3(w,t[7],t[11],b),E=[x,S.m0,S.m3,S.m5,T.m0,R.m0,D.m0,I.m0,T.m3,R.m3,D.m3,I.m3,T.m5,R.m5,D.m5,I.m5],O=[T.m5,R.m5,D.m5,I.m5,T.m4,R.m4,D.m4,I.m4,T.m2,R.m2,D.m2,I.m2,M,y.m0,y.m3,y.m5],V=[I.m5,z.m5,L.m5,N.m5,I.m4,z.m4,L.m4,N.m4,I.m2,z.m2,L.m2,N.m2,y.m5,y.m4,y.m2,b],C=[S.m5,S.m4,S.m2,w,I.m0,z.m0,L.m0,N.m0,I.m3,z.m3,L.m3,N.m3,I.m5,z.m5,L.m5,N.m5],B=E[15],H=this.normal(E[0],E[4],E[8],E[12],E[13],E[14],E[15]);abs2(H)<this.epsilon&&(H=this.normal(E[0],E[4],E[8],E[12],E[11],E[7],E[3]),abs2(H)<this.epsilon&&(H=this.normal(E[3],E[2],E[1],E[0],E[13],E[14],E[15])));let _=this.normal(O[12],O[13],O[14],O[15],O[11],O[7],O[3]);abs2(_)<this.epsilon&&(_=this.normal(O[12],O[13],O[14],O[15],O[2],O[1],O[0]),abs2(_)<this.epsilon&&(_=this.normal(O[0],O[4],O[8],O[12],O[11],O[7],O[3])));let F=this.normal(V[15],V[11],V[7],V[3],V[2],V[1],V[0]);abs2(F)<this.epsilon&&(F=this.normal(V[15],V[11],V[7],V[3],V[4],V[8],V[12]),abs2(F)<this.epsilon&&(F=this.normal(V[12],V[13],V[14],V[15],V[2],V[1],V[0])));let G=this.normal(C[3],C[2],C[1],C[0],C[4],C[8],C[12]);abs2(G)<this.epsilon&&(G=this.normal(C[3],C[2],C[1],C[0],C[13],C[14],C[15]),!
 abs2(G)<this.epsilon&&(G=this.normal(C[15],C[11],C[7],C[3],C[4],C[8],C[12])));let W=this.normal(V[3],V[2],V[1],B,V[4],V[8],V[12]),U=this.Epsilon,Z=[.5*(n[0]+s[0]),.5*(n[1]+s[1]),.5*(n[2]+s[2])];if(!l)if(l=Straightness(x,t[4],t[8],M)<this.res2){let t=unit(this.differential(O[0],O[1],O[2],O[3]));Z=[Z[0]-U*t[0],Z[1]-U*t[1],Z[2]-U*t[2]]}else Z=E[12];let j=[.5*(s[0]+o[0]),.5*(s[1]+o[1]),.5*(s[2]+o[2])];if(!c)if(c=Straightness(M,t[13],t[14],b)<this.res2){let t=unit(this.differential(V[12],V[8],V[4],V[0]));j=[j[0]-U*t[0],j[1]-U*t[1],j[2]-U*t[2]]}else j=O[15];let k=[.5*(o[0]+h[0]),.5*(o[1]+h[1]),.5*(o[2]+h[2])];if(!d)if(d=Straightness(b,t[11],t[7],w)<this.res2){let t=unit(this.differential(C[15],C[14],C[13],C[12]));k=[k[0]-U*t[0],k[1]-U*t[1],k[2]-U*t[2]]}else k=V[3];let Y=[.5*(h[0]+n[0]),.5*(h[1]+n[1]),.5*(h[2]+n[2])];if(!m)if(m=Straightness(x,t[1],t[2],w)<this.res2){let t=unit(this.differential(E[3],E[7],E[11],E[15]));Y=[Y[0]-U*t[0],Y[1]-U*t[1],Y[2]-U*t[2]]}else Y=C[0];if(f){let t=Array(4),g=Array(4),x=Array(4),w=Array(4),M=Array(4);for(let e=0;e<4;++e)t[e]=.5*(f[e]+u[e]),g[e]=.5*(u[e]+p[e]),x[e]=.5*(p[e]+v[e]),w[e]=.5*(v[e]+f[e]),M[e]=.5*(t[e]+x[e]);let b=this.data.Vertex(Z,H,t),S=this.data.Vertex(j,_,g),P=this.data.Vertex(k,F,x),A=this.data.Vertex(Y,G,w),y=this.data.Vertex(B,W,M);this.Render(E,e,b,y,A,n,Z,B,Y,l,!1,!1,m,f,t,M,w),this.Render(O,b,i,S,y,Z,s,j,B,l,c,!1,!1,t,u,g,M),this.Render(V,y,S,a,P,B,j,o,k,!1,c,d,!1,M,g,p,x),this.Render(C,A,y,P,r,Y,B,k,h,!1,!1,d,m,w,M,x,v)}else{let t=this.vertex(Z,H),f=this.vertex(j,_),u=this.vertex(k,F),p=this.vertex(Y,G),v=this.vertex(B,W);this.Render(E,e,t,v,p,n,Z,B,Y,l,!1,!1,m),this.Render(O,t,i,f,v,Z,s,j,B,l,c,!1,!1),this.Render(V,v,f,a,u,B,j,o,k,!1,c,d,!1),this.Render(C,p,v,u,r,Y,B,k,h,!1,!1,d,m)}}}process3(t){if(1==wireframe)return this.curve(t,0,1,3,6),this.curve(t,6,7,8,9),void this.curve(t,9,5,2,0);let e=t[0],i=t[6],a=t[9],r=this.normal(a,t[5],t[2],e,t[1],t[3],i),n=this.normal(e,t[1],t[3],i,t[7],t[8],a),s=this.normal(i,t[7],t[8],a,t[5],t[2],e);if(this.color){let o=this.color!
 [0],h=this.color[1],l=this.color[2],c=this.data.Vertex(e,r,o),d=this.data.Vertex(i,n,h),m=this.data.Vertex(a,s,l);this.Render3(t,c,d,m,e,i,a,!1,!1,!1,o,h,l)}else{let o=this.vertex(e,r),h=this.vertex(i,n),l=this.vertex(a,s);this.Render3(t,o,h,l,e,i,a,!1,!1,!1)}this.data.indices.length>0&&this.append()}Render3(t,e,i,a,r,n,s,o,h,l,c,d,m){if(this.Distance3(t)<this.res2)this.offscreen([r,n,s])||(0==wireframe?(this.data.indices.push(e),this.data.indices.push(i),this.data.indices.push(a)):(this.data.indices.push(e),this.data.indices.push(i),this.data.indices.push(i),this.data.indices.push(a),this.data.indices.push(a),this.data.indices.push(e)));else{if(this.offscreen(t))return;let f=t[0],u=t[1],p=t[2],v=t[3],g=t[4],x=t[5],w=t[6],M=t[7],b=t[8],S=t[9],P=[.5*(S[0]+x[0]),.5*(S[1]+x[1]),.5*(S[2]+x[2])],A=[.5*(S[0]+b[0]),.5*(S[1]+b[1]),.5*(S[2]+b[2])],y=[.5*(x[0]+p[0]),.5*(x[1]+p[1]),.5*(x[2]+p[2])],T=[.5*(b[0]+g[0]),.5*(b[1]+g[1]),.5*(b[2]+g[2])],R=[.5*(b[0]+M[0]),.5*(b[1]+M[1]),.5*(b[2]+M[2])],D=[.5*(p[0]+g[0]),.5*(p[1]+g[1]),.5*(p[2]+g[2])],I=[.5*(p[0]+f[0]),.5*(p[1]+f[1]),.5*(p[2]+f[2])],z=[.5*(g[0]+v[0]),.5*(g[1]+v[1]),.5*(g[2]+v[2])],L=[.5*(M[0]+w[0]),.5*(M[1]+w[1]),.5*(M[2]+w[2])],N=[.5*(f[0]+u[0]),.5*(f[1]+u[1]),.5*(f[2]+u[2])],E=[.5*(u[0]+v[0]),.5*(u[1]+v[1]),.5*(u[2]+v[2])],O=[.5*(v[0]+w[0]),.5*(v[1]+w[1]),.5*(v[2]+w[2])],V=[.5*(P[0]+y[0]),.5*(P[1]+y[1]),.5*(P[2]+y[2])],C=[.5*(A[0]+R[0]),.5*(A[1]+R[1]),.5*(A[2]+R[2])],B=[.5*(y[0]+I[0]),.5*(y[1]+I[1]),.5*(y[2]+I[2])],H=[.5*T[0]+.25*(g[0]+u[0]),.5*T[1]+.25*(g[1]+u[1]),.5*T[2]+.25*(g[2]+u[2])],_=[.5*(R[0]+L[0]),.5*(R[1]+L[1]),.5*(R[2]+L[2])],F=[.5*D[0]+.25*(g[0]+M[0]),.5*D[1]+.25*(g[1]+M[1]),.5*D[2]+.25*(g[2]+M[2])],G=[.25*(x[0]+g[0])+.5*z[0],.25*(x[1]+g[1])+.5*z[1],.25*(x[2]+g[2])+.5*z[2]],W=[.5*(N[0]+E[0]),.5*(N[1]+E[1]),.5*(N[2]+E[2])],U=[.5*(E[0]+O[0]),.5*(E[1]+O[1]),.5*(E[2]+O[2])],Z=[.5*(F[0]+W[0]),.5*(F[1]+W[1]),.5*(F[2]+W[2])],j=[.5*(F[0]+U[0]),.5*(F[1]+U[1]),.5*(F[2]+U[2])],k=[.5*(W[0]+U[0]),.5*(W[1]+U[1]),.5*(W[2]+U[2])],Y=[.5*(G[0]+_[0]),.5*(G[1]+_[1]),.5*(!
 G[2]+_[2])],X=[.5*(C[0]+G[0]),.5*(C[1]+G[1]),.5*(C[2]+G[2])],q=[.5*(C[0]+_[0]),.5*(C[1]+_[1]),.5*(C[2]+_[2])],K=[.5*(V[0]+H[0]),.5*(V[1]+H[1]),.5*(V[2]+H[2])],$=[.5*(B[0]+H[0]),.5*(B[1]+H[1]),.5*(B[2]+H[2])],Q=[.5*(V[0]+B[0]),.5*(V[1]+B[1]),.5*(V[2]+B[2])],J=[f,N,I,W,[.5*(D[0]+N[0]),.5*(D[1]+N[1]),.5*(D[2]+N[2])],B,k,Z,$,Q],tt=[k,U,j,O,[.5*(z[0]+L[0]),.5*(z[1]+L[1]),.5*(z[2]+L[2])],Y,w,L,_,q],et=[Q,K,V,X,[.5*(P[0]+T[0]),.5*(P[1]+T[1]),.5*(P[2]+T[2])],P,q,C,A,S],it=[q,X,Y,K,[.25*(y[0]+R[0]+E[0]+g[0]),.25*(y[1]+R[1]+E[1]+g[1]),.25*(y[2]+R[2]+E[2]+g[2])],j,Q,$,Z,k],at=this.normal(k,j,Y,q,X,K,Q),rt=this.normal(q,X,K,Q,$,Z,k),nt=this.normal(Q,$,Z,k,j,Y,q),st=this.Epsilon,ot=[.5*(n[0]+s[0]),.5*(n[1]+s[1]),.5*(n[2]+s[2])];if(!o)if(o=Straightness(w,M,b,S)<this.res2){let t=unit(this.sumdifferential(it[0],it[2],it[5],it[9],it[1],it[3],it[6]));ot=[ot[0]-st*t[0],ot[1]-st*t[1],ot[2]-st*t[2]]}else ot=q;let ht=[.5*(s[0]+r[0]),.5*(s[1]+r[1]),.5*(s[2]+r[2])];if(!h)if(h=Straightness(f,p,x,S)<this.res2){let t=unit(this.sumdifferential(it[6],it[3],it[1],it[0],it[7],it[8],it[9]));ht=[ht[0]-st*t[0],ht[1]-st*t[1],ht[2]-st*t[2]]}else ht=Q;let lt=[.5*(r[0]+n[0]),.5*(r[1]+n[1]),.5*(r[2]+n[2])];if(!l)if(l=Straightness(f,u,v,w)<this.res2){let t=unit(this.sumdifferential(it[9],it[8],it[7],it[6],it[5],it[2],it[0]));lt=[lt[0]-st*t[0],lt[1]-st*t[1],lt[2]-st*t[2]]}else lt=k;if(c){let t=Array(4),f=Array(4),u=Array(4);for(let e=0;e<4;++e)t[e]=.5*(d[e]+m[e]),f[e]=.5*(m[e]+c[e]),u[e]=.5*(c[e]+d[e]);let p=this.data.Vertex(ot,at,t),v=this.data.Vertex(ht,rt,f),g=this.data.Vertex(lt,nt,u);this.Render3(J,e,g,v,r,lt,ht,!1,h,l,c,u,f),this.Render3(tt,g,i,p,lt,n,ot,o,!1,l,u,d,t),this.Render3(et,v,p,a,ht,ot,s,o,h,!1,f,t,m),this.Render3(it,p,v,g,ot,ht,lt,!1,!1,!1,t,f,u)}else{let t=this.vertex(ot,at),c=this.vertex(ht,rt),d=this.vertex(lt,nt);this.Render3(J,e,d,c,r,lt,ht,!1,h,l),this.Render3(tt,d,i,t,lt,n,ot,o,!1,l),this.Render3(et,c,t,a,ht,ot,s,o,h,!1),this.Render3(it,t,c,d,ot,ht,lt,!1,!1,!1)}}}Distance(t){let e=t[0],i=t[3],a=t[12],r=t[15],n=Flatness(e,a,i,r);!
 n=Math.max(Straightness(e,t[4],t[8],a)),n=Math.max(n,Straightness(t[1],t[5],t[9],t[13])),n=Math.max(n,Straightness(i,t[7],t[11],r)),n=Math.max(n,Straightness(t[2],t[6],t[10],t[14]));let s=Flatness(e,i,a,r);return s=Math.max(s,Straightness(e,t[1],t[2],i)),s=Math.max(s,Straightness(t[4],t[5],t[6],t[7])),s=Math.max(s,Straightness(t[8],t[9],t[10],t[11])),s=Math.max(s,Straightness(a,t[13],t[14],r)),[n,s]}Distance3(t){let e=t[0],i=t[4],a=t[6],r=t[9],n=abs2([(e[0]+a[0]+r[0])*third-i[0],(e[1]+a[1]+r[1])*third-i[1],(e[2]+a[2]+r[2])*third-i[2]]);return n=Math.max(n,Straightness(e,t[1],t[3],a)),n=Math.max(n,Straightness(e,t[2],t[5],r)),Math.max(n,Straightness(a,t[7],t[8],r))}differential(t,e,i,a){let r=[3*(e[0]-t[0]),3*(e[1]-t[1]),3*(e[2]-t[2])];return abs2(r)>this.epsilon?r:(r=bezierPP(t,e,i),abs2(r)>this.epsilon?r:bezierPPP(t,e,i,a))}sumdifferential(t,e,i,a,r,n,s){let o=this.differential(t,e,i,a),h=this.differential(t,r,n,s);return[o[0]+h[0],o[1]+h[1],o[2]+h[2]]}normal(t,e,i,a,r,n,s){let o=3*(r[0]-a[0]),h=3*(r[1]-a[1]),l=3*(r[2]-a[2]),c=3*(i[0]-a[0]),d=3*(i[1]-a[1]),m=3*(i[2]-a[2]),f=[h*m-l*d,l*c-o*m,o*d-h*c];if(abs2(f)>this.epsilon)return f;let u=[c,d,m],p=[o,h,l],v=bezierPP(a,i,e),g=bezierPP(a,r,n),x=cross(g,u),w=cross(p,v);if(f=[x[0]+w[0],x[1]+w[1],x[2]+w[2]],abs2(f)>this.epsilon)return f;let M=bezierPPP(a,i,e,t),b=bezierPPP(a,r,n,s);x=cross(p,M),w=cross(b,u);let S=cross(g,v);return f=[x[0]+w[0]+S[0],x[1]+w[1]+S[1],x[2]+w[2]+S[2]],abs2(f)>this.epsilon?f:(x=cross(b,v),w=cross(g,M),f=[x[0]+w[0],x[1]+w[1],x[2]+w[2]],abs2(f)>this.epsilon?f:cross(b,M))}}class BezierCurve extends Geometry{constructor(t,e,i,a,r){super(),this.controlpoints=t,this.Min=a,this.Max=r,this.CenterIndex=e,this.MaterialIndex=i}setMaterialIndex(){this.setMaterial(material1Data,drawMaterial1)}processLine(t){let e=t[0],i=t[1];if(!this.offscreen([e,i])){let t=[0,0,1];this.data.indices.push(this.data.vertex(e,t)),this.data.indices.push(this.data.vertex(i,t)),this.append()}}process(t){if(2==t.length)return this.processLine(t);let e=t[0],i=t[1],a=t[2],r=t[3!
 ],n=this..normal(bezierP(e,i),bezierPP(e,i,a)),s=this.normal(bezierP(a,r),bezierPP(r,a,i)),o=this.data.vertex(e,n),h=this.data.vertex(r,s);this.Render(t,o,h),this.data.indices.length>0&&this.append()}append(){material1Data.append(this.data)}notRendered(){material1Data.rendered=!1}Render(t,e,i){let a=t[0],r=t[1],n=t[2],s=t[3];if(Straightness(a,r,n,s)<this.res2)this.offscreen([a,s])||(this.data.indices.push(e),this.data.indices.push(i));else{if(this.offscreen(t))return;let o=[.5*(a[0]+r[0]),.5*(a[1]+r[1]),.5*(a[2]+r[2])],h=[.5*(r[0]+n[0]),.5*(r[1]+n[1]),.5*(r[2]+n[2])],l=[.5*(n[0]+s[0]),.5*(n[1]+s[1]),.5*(n[2]+s[2])],c=[.5*(o[0]+h[0]),.5*(o[1]+h[1]),.5*(o[2]+h[2])],d=[.5*(h[0]+l[0]),.5*(h[1]+l[1]),.5*(h[2]+l[2])],m=[.5*(c[0]+d[0]),.5*(c[1]+d[1]),.5*(c[2]+d[2])],f=[a,o,c,m],u=[m,d,l,s],p=this.normal(bezierPh(a,r,n,s),bezierPPh(a,r,n,s)),v=this.data.vertex(m,p);this.Render(f,e,v),this.Render(u,v,i)}}normal(t,e){let i=dot(t,t),a=dot(t,e);return[i*e[0]-a*t[0],i*e[1]-a*t[1],i*e[2]-a*t[2]]}}class Pixel extends Geometry{constructor(t,e,i,a,r){super(),this.controlpoint=t,this.width=e,this.CenterIndex=0,this.MaterialIndex=i,this.Min=a,this.Max=r}setMaterialIndex(){this.setMaterial(material0Data,drawMaterial0)}process(t){this.data.indices.push(this.data.vertex0(this.controlpoint,this.width)),this.append()}append(){material0Data.append(this.data)}notRendered(){material0Data.rendered=!1}}class Triangles extends Geometry{constructor(t,e,i){super(),this.CenterIndex=0,this.MaterialIndex=t,this.Min=e,this.Max=i,this.Positions=Positions,this.Normals=Normals,this.Colors=Colors,this.Indices=Indices,Positions=[],Normals=[],Colors=[],Indices=[],this.transparent=Materials[t].diffuse[3]<1}setMaterialIndex(){this.transparent?this.setMaterial(transparentData,drawTransparent):this.setMaterial(triangleData,drawTriangle)}process(t){materialIndex=this.Colors.length>0?-1-materialIndex:1+materialIndex;for(let t=0,e=this.Indices.length;t<e;++t){let e=this.Indices[t],i=e[0],a=this.Positions[i[0]],r=this.Positions[i[1]],n=this.Positions[i[2]];if(!t!
 his.offscreen([a,r,n])){let t=e.length>1?e[1]:i;if(t&&0!=t.length||(t=i),this.Colors.length>0){let s=e.length>2?e[2]:i;s&&0!=s.length||(s=i);let o=this.Colors[s[0]],h=this.Colors[s[1]],l=this.Colors[s[2]];this.transparent|=o[3]+h[3]+l[3]<765,0==wireframe?(this.data.iVertex(i[0],a,this.Normals[t[0]],o),this.data.iVertex(i[1],r,this.Normals[t[1]],h),this.data.iVertex(i[2],n,this.Normals[t[2]],l)):(this.data.iVertex(i[0],a,this.Normals[t[0]],o),this.data.iVertex(i[1],r,this.Normals[t[1]],h),this.data.iVertex(i[1],r,this.Normals[t[1]],h),this.data.iVertex(i[2],n,this.Normals[t[2]],l),this.data.iVertex(i[2],n,this.Normals[t[2]],l),this.data.iVertex(i[0],a,this.Normals[t[0]],o))}else 0==wireframe?(this.data.iVertex(i[0],a,this.Normals[t[0]]),this.data.iVertex(i[1],r,this.Normals[t[1]]),this.data.iVertex(i[2],n,this.Normals[t[2]])):(this.data.iVertex(i[0],a,this.Normals[t[0]]),this.data.iVertex(i[1],r,this.Normals[t[1]]),this.data.iVertex(i[1],r,this.Normals[t[1]]),this.data.iVertex(i[2],n,this.Normals[t[2]]),this.data.iVertex(i[2],n,this.Normals[t[2]]),this.data.iVertex(i[0],a,this.Normals[t[0]]))}}this.data.nvertices=this.Positions.length,this.data.indices.length>0&&this.append()}append(){this.transparent?transparentData.append(this.data):triangleData.append(this.data)}notRendered(){this.transparent?transparentData.rendered=!1:triangleData.rendered=!1}}function redraw(){initProjection(),setProjection(),remesh=!0,draw()}function home(){mat4.identity(rotMat),redraw()}let positionAttribute=0,normalAttribute=1,materialAttribute=2,colorAttribute=3,widthAttribute=4;function initShader(t=[]){let e=getShader(gl,vertex,gl.VERTEX_SHADER,t),i=getShader(gl,fragment,gl.FRAGMENT_SHADER,t),a=gl.createProgram();return gl.attachShader(a,e),gl.attachShader(a,i),gl.bindAttribLocation(a,positionAttribute,"position"),gl.bindAttribLocation(a,normalAttribute,"normal"),gl.bindAttribLocation(a,materialAttribute,"materialIndex"),gl.bindAttribLocation(a,colorAttribute,"color"),gl.bindAttribLocation(a,widthAttribute,"width"),gl.linkProgram(a),g!
 l.getProgramParameter(a,gl.LINK_STATUS)||alert("Could not initialize shaders"),a}class Split3{constructor(t,e,i,a){this.m0=[.5*(t[0]+e[0]),.5*(t[1]+e[1]),.5*(t[2]+e[2])];let r=.5*(e[0]+i[0]),n=.5*(e[1]+i[1]),s=.5*(e[2]+i[2]);this.m2=[.5*(i[0]+a[0]),.5*(i[1]+a[1]),.5*(i[2]+a[2])],this.m3=[.5*(this.m0[0]+r),.5*(this.m0[1]+n),.5*(this.m0[2]+s)],this.m4=[.5*(r+this.m2[0]),.5*(n+this.m2[1]),.5*(s+this.m2[2])],this.m5=[.5*(this.m3[0]+this.m4[0]),.5*(this.m3[1]+this.m4[1]),.5*(this.m3[2]+this.m4[2])]}}function unit(t){let e=1/(Math.sqrt(t[0]*t[0]+t[1]*t[1]+t[2]*t[2])||1);return[t[0]*e,t[1]*e,t[2]*e]}function abs2(t){return t[0]*t[0]+t[1]*t[1]+t[2]*t[2]}function dot(t,e){return t[0]*e[0]+t[1]*e[1]+t[2]*e[2]}function cross(t,e){return[t[1]*e[2]-t[2]*e[1],t[2]*e[0]-t[0]*e[2],t[0]*e[1]-t[1]*e[0]]}function bezierP(t,e){return[e[0]-t[0],e[1]-t[1],e[2]-t[2]]}function bezierPP(t,e,i){return[3*(t[0]+i[0])-6*e[0],3*(t[1]+i[1])-6*e[1],3*(t[2]+i[2])-6*e[2]]}function bezierPPP(t,e,i,a){return[a[0]-t[0]+3*(e[0]-i[0]),a[1]-t[1]+3*(e[1]-i[1]),a[2]-t[2]+3*(e[2]-i[2])]}function bezierPh(t,e,i,a){return[i[0]+a[0]-t[0]-e[0],i[1]+a[1]-t[1]-e[1],i[2]+a[2]-t[2]-e[2]]}function bezierPPh(t,e,i,a){return[3*t[0]-5*e[0]+i[0]+a[0],3*t[1]-5*e[1]+i[1]+a[1],3*t[2]-5*e[2]+i[2]+a[2]]}function Straightness(t,e,i,a){let r=[third*(a[0]-t[0]),third*(a[1]-t[1]),third*(a[2]-t[2])];return Math.max(abs2([e[0]-r[0]-t[0],e[1]-r[1]-t[1],e[2]-r[2]-t[2]]),abs2([a[0]-r[0]-i[0],a[1]-r[1]-i[1],a[2]-r[2]-i[2]]))}function Flatness(t,e,i,a){let r=[e[0]-t[0],e[1]-t[1],e[2]-t[2]],n=[a[0]-i[0],a[1]-i[1],a[2]-i[2]];return Math.max(abs2(cross(r,unit(n))),abs2(cross(n,unit(r))))/9}function corners(t,e){return[t,[t[0],t[1],e[2]],[t[0],e[1],t[2]],[t[0],e[1],e[2]],[e[0],t[1],t[2]],[e[0],t[1],e[2]],[e[0],e[1],t[2]],e]}function minbound(t){return[Math.min(t[0][0],t[1][0],t[2][0],t[3][0],t[4][0],t[5][0],t[6][0],t[7][0]),Math.min(t[0][1],t[1][1],t[2][1],t[3][1],t[4][1],t[5][1],t[6][1],t[7][1]),Math.min(t[0][2],t[1][2],t[2][2],t[3][2],t[4][2],t[5][2],t[6][2],t[7][2])]}function maxboun!
 d(t){return[Math.max(t[0][0],t[1][0],t[2][0],t[3][0],t[4][0],t[5][0],t[6][0],t[7][0]),Math.max(t[0][1],t[1][1],t[2][1],t[3][1],t[4][1],t[5][1],t[6][1],t[7][1]),Math.max(t[0][2],t[1][2],t[2][2],t[3][2],t[4][2],t[5][2],t[6][2],t[7][2])]}function COBTarget(t,e){mat4.fromTranslation(T,[center.x,center.y,center.z]),mat4.invert(cjMatInv,T),mat4.multiply(t,e,cjMatInv),mat4.multiply(t,T,t)}function setUniforms(t,e){let i=e==pixelShader;gl.useProgram(e),gl.enableVertexAttribArray(positionAttribute),i&&gl.enableVertexAttribArray(widthAttribute);let a=!i&&Lights.length>0;if(a&&gl.enableVertexAttribArray(normalAttribute),gl.enableVertexAttribArray(materialAttribute),e.projViewMatUniform=gl.getUniformLocation(e,"projViewMat"),e.viewMatUniform=gl.getUniformLocation(e,"viewMat"),e.normMatUniform=gl.getUniformLocation(e,"normMat"),e!=colorShader&&e!=transparentShader||gl.enableVertexAttribArray(colorAttribute),a)for(let t=0;t<Lights.length;++t)Lights[t].setUniform(e,t);for(let i=0;i<t.materials.length;++i)t.materials[i].setUniform(e,i);gl.uniformMatrix4fv(e.projViewMatUniform,!1,projViewMat),gl.uniformMatrix4fv(e.viewMatUniform,!1,viewMat),gl.uniformMatrix3fv(e.normMatUniform,!1,normMat)}function handleMouseDown(t){zoomEnabled||enableZoom(),mouseDownOrTouchActive=!0,lastMouseX=t.clientX,lastMouseY=t.clientY}let pinchStart,touchStartTime,pinch=!1;function pinchDistance(t){return Math.hypot(t[0].pageX-t[1].pageX,t[0].pageY-t[1].pageY)}function handleTouchStart(t){t.preventDefault(),zoomEnabled||enableZoom();let e=t.targetTouches;swipe=rotate=pinch=!1,zooming||(1!=e.length||mouseDownOrTouchActive||(touchStartTime=(new Date).getTime(),touchId=e[0].identifier,lastMouseX=e[0].pageX,lastMouseY=e[0].pageY),2!=e.length||mouseDownOrTouchActive||(touchId=e[0].identifier,pinchStart=pinchDistance(e),pinch=!0))}function handleMouseUpOrTouchEnd(t){mouseDownOrTouchActive=!1}function rotateScene(t,e,i,a,r){if(t==i&&e==a)return;let[n,s]=arcball([t,-e],[i,-a]);mat4.fromRotation(T,2*r*ArcballFactor*n/Zoom,s),mat4.multiply(rotMat,T,rotMat)}function!
  shiftScene(t,e,i,a){let r=1/Zoom;shift.x+=(i-t)*r*halfCanvasWidth,shift.y-=(a-e)*r*halfCanvasHeight}function panScene(t,e,i,a){orthographic?shiftScene(t,e,i,a):(center.x+=(i-t)*(viewParam.xmax-viewParam.xmin),center.y-=(a-e)*(viewParam.ymax-viewParam.ymin))}function updateViewMatrix(){COBTarget(viewMat,rotMat),mat4.translate(viewMat,viewMat,[center.x,center.y,0]),mat3.fromMat4(viewMat3,viewMat),mat3.invert(normMat,viewMat3),mat4.multiply(projViewMat,projMat,viewMat)}function capzoom(){let t=Math.sqrt(Number.MAX_VALUE),e=1/t;Zoom<=e&&(Zoom=e),Zoom>=t&&(Zoom=t),(zoomRemeshFactor*Zoom<lastZoom||Zoom>zoomRemeshFactor*lastZoom)&&(remesh=!0,lastZoom=Zoom)}function zoomImage(t){let e=zoomStep*halfCanvasHeight*t;const i=Math.log(.1*Number.MAX_VALUE)/Math.log(zoomFactor);Math.abs(e)<i&&(Zoom*=zoomFactor**e,capzoom())}function normMouse(t){let e=t[0],i=t[1],a=Math.hypot(e,i);return a>1&&(denom=1/a,e*=denom,i*=denom),[e,i,Math.sqrt(Math.max(1-i*i-e*e,0))]}function arcball(t,e){let i=normMouse(t),a=normMouse(e),r=dot(i,a);return[r>1?0:r<-1?pi:Math.acos(r),unit(cross(i,a))]}function zoomScene(t,e,i,a){zoomImage(e-a)}const DRAGMODE_ROTATE=1,DRAGMODE_SHIFT=2,DRAGMODE_ZOOM=3,DRAGMODE_PAN=4;function processDrag(t,e,i,a=1){let r;switch(i){case 1:r=rotateScene;break;case 2:r=shiftScene;break;case 3:r=zoomScene;break;case 4:r=panScene;break;default:r=(t,e,i,a)=>{}}r((lastMouseX-halfCanvasWidth)/halfCanvasWidth,(lastMouseY-halfCanvasHeight)/halfCanvasHeight,(t-halfCanvasWidth)/halfCanvasWidth,(e-halfCanvasHeight)/halfCanvasHeight,a),lastMouseX=t,lastMouseY=e,setProjection(),draw()}let zoomEnabled=0;function enableZoom(){zoomEnabled=1,canvas.addEventListener("wheel",handleMouseWheel,!1)}function disableZoom(){zoomEnabled=0,canvas.removeEventListener("wheel",handleMouseWheel,!1)}function handleKey(t){if(zoomEnabled||enableZoom(),embedded&&zoomEnabled&&27==t.keyCode)return void disableZoom();let e=[];switch(t.key){case"x":e=[1,0,0];break;case"y":e=[0,1,0];break;case"z":e=[0,0,1];break;case"h":home();break;case"m":++wireframe,3==wirefr!
 ame&&(wireframe=0),2!=wireframe&&(embedded||deleteShaders(),initShaders()),remesh=!0,draw();break;case"+":case"=":case">":expand();break;case"-":case"_":case"<":shrink()}e.length>0&&(mat4.rotate(rotMat,rotMat,.1,e),updateViewMatrix(),draw())}function setZoom(){capzoom(),setProjection(),draw()}function handleMouseWheel(t){t.preventDefault(),t.deltaY<0?Zoom*=zoomFactor:Zoom/=zoomFactor,setZoom()}function handleMouseMove(t){if(!mouseDownOrTouchActive)return;let e,i=t.clientX,a=t.clientY;e=t.getModifierState("Control")?2:t.getModifierState("Shift")?3:t.getModifierState("Alt")?4:1,processDrag(i,a,e)}let zooming=!1,swipe=!1,rotate=!1;function handleTouchMove(t){if(t.preventDefault(),zooming)return;let e=t.targetTouches;if(!pinch&&1==e.length&&touchId==e[0].identifier){let t=e[0].pageX,i=e[0].pageY,a=t-lastMouseX,r=i-lastMouseY,n=a*a+r*r<=shiftHoldDistance*shiftHoldDistance;if(n&&!swipe&&!rotate&&(new Date).getTime()-touchStartTime>shiftWaitTime&&(navigator.vibrate&&window.navigator.vibrate(vibrateTime),swipe=!0),swipe)processDrag(t,i,2);else if(!n){rotate=!0,processDrag(e[0].pageX,e[0].pageY,1,.5)}}if(pinch&&!swipe&&2==e.length&&touchId==e[0].identifier){let t=pinchDistance(e),i=t-pinchStart;zooming=!0,i*=zoomPinchFactor,i>zoomPinchCap&&(i=zoomPinchCap),i<-zoomPinchCap&&(i=-zoomPinchCap),zoomImage(i/size2),pinchStart=t,swipe=rotate=zooming=!1,setProjection(),draw()}}let pixelShader,materialShader,colorShader,transparentShader,zbuffer=[];function transformVertices(t){let e=viewMat[2],i=viewMat[6],a=viewMat[10];zbuffer.length=t.length;for(let r=0;r<t.length;++r){let n=6*r;zbuffer[r]=e*t[n]+i*t[n+1]+a*t[n+2]}}function drawMaterial0(){drawBuffer(material0Data,pixelShader),material0Data.clear()}function drawMaterial1(){drawBuffer(material1Data,materialShader),material1Data.clear()}function drawMaterial(){drawBuffer(materialData,materialShader),materialData.clear()}function drawColor(){drawBuffer(colorData,colorShader),colorData.clear()}function drawTriangle(){drawBuffer(triangleData,transparentShader),triangleData.rendered!
 =!1,triangleData.clear()}function drawTransparent(){let t=transparentData.indices;if(wireframe>0)return drawBuffer(transparentData,transparentShader,t),void transparentData.clear();if(t.length>0){transformVertices(transparentData.vertices);let e=t.length/3,i=Array(e).fill().map((t,e)=>e);i.sort((function(e,i){let a=3*e;Ia=t[a],Ib=t[a+1],Ic=t[a+2];let r=3*i;return IA=t[r],IB=t[r+1],IC=t[r+2],zbuffer[Ia]+zbuffer[Ib]+zbuffer[Ic]<zbuffer[IA]+zbuffer[IB]+zbuffer[IC]?-1:1}));let a=Array(t.length);for(let r=0;r<e;++r){let e=3*i[r];a[3*r]=t[e],a[3*r+1]=t[e+1],a[3*r+2]=t[e+2]}gl.depthMask(!1),drawBuffer(transparentData,transparentShader,a),transparentData.rendered=!1,gl.depthMask(!0)}transparentData.clear()}function drawBuffers(){drawMaterial0(),drawMaterial1(),drawMaterial(),drawColor(),drawTriangle(),drawTransparent()}function draw(){embedded&&(offscreen.width=canvasWidth,offscreen.height=canvasHeight,setViewport()),gl.clearColor(Background[0],Background[1],Background[2],Background[3]),gl.clear(gl.COLOR_BUFFER_BIT|gl.DEPTH_BUFFER_BIT);for(let t=0;t<P.length;++t)P[t].render();drawBuffers(),embedded&&(context.clearRect(0,0,canvasWidth,canvasHeight),context.drawImage(offscreen,0,0)),0==wireframe&&(remesh=!1)}function setDimensions(t,e,i,a){let r=t/e,n=1/Zoom,s=(i/t+viewportshift[0])*Zoom,o=(a/e+viewportshift[1])*Zoom;if(orthographic){let t=B[0]-b[0],e=B[1]-b[1];if(t<e*r){let t=.5*e*r*n,i=2*t*s,a=e*n*o;viewParam.xmin=-t-i,viewParam.xmax=t-i,viewParam.ymin=b[1]*n-a,viewParam.ymax=B[1]*n-a}else{let e=.5*t/(r*Zoom),i=t*n*s,a=2*e*o;viewParam.xmin=b[0]*n-i,viewParam.xmax=B[0]*n-i,viewParam.ymin=-e-a,viewParam.ymax=e-a}}else{let t=H*n,e=t*r,i=2*e*s,a=2*t*o;viewParam.xmin=-e-i,viewParam.xmax=e-i,viewParam.ymin=-t-a,viewParam.ymax=t-a}}function setProjection(){setDimensions(canvasWidth,canvasHeight,shift.x,shift.y),(orthographic?mat4.ortho:mat4.frustum)(projMat,viewParam.xmin,viewParam.xmax,viewParam.ymin,viewParam.ymax,-viewParam.zmax,-viewParam.zmin),updateViewMatrix()}function initProjection(){H=-Math.tan(.5*angle)*B[2],center.!
 x=center..y=0,center.z=.5*(b[2]+B[2]),lastZoom=Zoom=zoom0,viewParam.zmin=b[2],viewParam.zmax=B[2],shift.x=shift.y=0}function setViewport(){gl.viewportWidth=canvasWidth,gl.viewportHeight=canvasHeight,gl.viewport(.5*(canvas.width-canvasWidth),.5*(canvas.height-canvasHeight),canvasWidth,canvasHeight),gl.scissor(0,0,canvas.width,canvas.height)}function setCanvas(){embedded&&(canvas.width=offscreen.width=canvasWidth,canvas.height=offscreen.height=canvasHeight),size2=Math.hypot(canvasWidth,canvasHeight),halfCanvasWidth=.5*canvas.width,halfCanvasHeight=.5*canvas.height,ArcballFactor=1+8*Math.hypot(viewportmargin[0],viewportmargin[1])/size2}function setsize(t,e){t>maxViewportWidth&&(t=maxViewportWidth),e>maxViewportHeight&&(e=maxViewportHeight),shift.x*=t/canvasWidth,shift.y*=e/canvasHeight,canvasWidth=t,canvasHeight=e,setCanvas(),setViewport(),setProjection(),remesh=!0}function resize(){if(zoom0=Zoom0,absolute&&!embedded)canvasWidth=canvasWidth0*window.devicePixelRatio,canvasHeight=canvasHeight0*window.devicePixelRatio;else{let t=canvasWidth0/canvasHeight0;canvasWidth=Math.max(window.innerWidth-10,10),canvasHeight=Math.max(window.innerHeight-10,10),!orthographic&&canvasWidth<canvasHeight*t&&(zoom0*=canvasWidth/(canvasHeight*t))}canvas.width=canvasWidth,canvas.height=canvasHeight;window.innerWidth,window.innerHeight;viewportshift[0]/=zoom0,viewportshift[1]/=zoom0,setsize(canvasWidth,canvasHeight),redraw()}function expand(){Zoom*=zoomFactor,setZoom()}function shrink(){Zoom/=zoomFactor,setZoom()}class Align{constructor(t,e){if(this.center=t,e){let t=e[0],i=e[1];this.ct=Math.cos(t),this.st=Math.sin(t),this.cp=Math.cos(i),this.sp=Math.sin(i)}}T0(t){return[t[0]+this.center[0],t[1]+this.center[1],t[2]+this.center[2]]}T(t){let e=t[0],i=t[1],a=t[2],r=e*this.ct+a*this.st;return[r*this.cp-i*this.sp+this.center[0],r*this.sp+i*this.cp+this.center[1],-e*this.st+a*this.ct+this.center[2]]}}function Tcorners(t,e,i){let a=[t(e),t([e[0],e[1],i[2]]),t([e[0],i[1],e[2]]),t([e[0],i[1],i[2]]),t([i[0],e[1],e[2]]),t([i[0],e[1],i[2]]),t([i[0],i[1!
 ],e[2]]),t(i)];return[minbound(a),maxbound(a)]}function sphere(t,e,i,r,n){let s,o,h,l,c,d,m=.524670512339254,f=.595936986722291,u=.954967051233925,p=.0820155480083437,v=.996685028842544,g=.0549670512339254,x=.998880711874577,w=.0405017186586849,M=[[[1,0,0],[1,0,m],[f,0,u],[p,0,v],[1,a,0],[1,a,m],[f,a*f,u],[p,a*p,v],[a,1,0],[a,1,m],[a*f,f,u],[a*p,p,v],[0,1,0],[0,1,m],[0,f,u],[0,p,v]],[[p,0,v],[p,a*p,v],[g,0,x],[a*p,p,v],[w,w,1],[.05*a,0,1],[0,p,v],[0,g,x],[0,.05*a,1],[0,0,1]]],b=new Align(t,n);function S(t){let e=Array(t.length);for(let i=0;i<t.length;++i){let a=t[i];e[i]=c([s*a[0],o*a[1],h*a[2]])}return e}n?(l=1,d=0,c=b.T.bind(b)):(l=-1,d=-e,c=b.T0.bind(b));let A=Tcorners(c,[-e,-e,d],[e,e,e]),y=A[0],T=A[1];for(let t=-1;t<=1;t+=2){s=t*e;for(let t=-1;t<=1;t+=2){o=t*e;for(let t=l;t<=1;t+=2){h=t*e;for(let t=0;t<2;++t)P.push(new BezierPatch(S(M[t]),i,r,y,T))}}}}let a=4/3*(Math.sqrt(2)-1);function disk(t,e,i,r,n){let s=1-2*a/3,o=[[1,0,0],[1,-a,0],[a,-1,0],[0,-1,0],[1,a,0],[s,0,0],[0,-s,0],[-a,-1,0],[a,1,0],[0,s,0],[-s,0,0],[-1,-a,0],[0,1,0],[-a,1,0],[-1,a,0],[-1,0,0]],h=new Align(t,n);let l=Tcorners(h.T.bind(h),[-e,-e,0],[e,e,0]);P.push(new BezierPatch(function(t){let i=Array(t.length);for(let a=0;a<t.length;++a){let r=t[a];i[a]=h.T([e*r[0],e*r[1],0])}return i}(o),i,r,l[0],l[1]))}function cylinder(t,e,i,r,n,s,o){let h,l,c=[[1,0,0],[1,0,1/3],[1,0,2/3],[1,0,1],[1,a,0],[1,a,1/3],[1,a,2/3],[1,a,1],[a,1,0],[a,1,1/3],[a,1,2/3],[a,1,1],[0,1,0],[0,1,1/3],[0,1,2/3],[0,1,1]],d=new Align(t,s);function m(t){let e=Array(t.length);for(let a=0;a<t.length;++a){let r=t[a];e[a]=d.T([h*r[0],l*r[1],i*r[2]])}return e}let f=Tcorners(d.T.bind(d),[-e,-e,0],[e,e,i]),u=f[0],p=f[1];for(let t=-1;t<=1;t+=2){h=t*e;for(let t=-1;t<=1;t+=2)l=t*e,P.push(new BezierPatch(m(c),r,n,u,p))}if(o){let e=d.T([0,0,i]);P.push(new BezierCurve([t,e],r,n,t,e))}}function rmf(t,e,i,a,r){class n{constructor(t,e,i){this.p=t,this.r=e,this.t=i,this.s=cross(i,e)}}let s=Number.EPSILON*Math.max(abs2(t),abs2(e),abs2(i),abs2(a));function o(r){if(1==r){let r=[a[0]-i[0],a[1]-i[!
 1],a[2]-i[2]];return abs2(r)>s?unit(r):(r=[2*i[0]-e[0]-a[0],2*i[1]-e[1]-a[1],2*i[2]-e[2]-a[2]],abs2(r)>s?unit(r):[a[0]-t[0]+3*(e[0]-i[0]),a[1]-t[1]+3*(e[1]-i[1]),a[2]-t[2]+3*(e[2]-i[2])])}let n=[a[0]-t[0]+3*(e[0]-i[0]),a[1]-t[1]+3*(e[1]-i[1]),a[2]-t[2]+3*(e[2]-i[2])],o=[2*(t[0]+i[0])-4*e[0],2*(t[1]+i[1])-4*e[1],2*(t[2]+i[2])-4*e[2]],h=[e[0]-t[0],e[1]-t[1],e[2]-t[2]],l=r*r,c=[n[0]*l+o[0]*r+h[0],n[1]*l+o[1]*r+h[1],n[2]*l+o[2]*r+h[2]];return abs2(c)>s?unit(c):(l=2*r,c=[n[0]*l+o[0],n[1]*l+o[1],n[2]*l+o[2]],abs2(c)>s?unit(c):unit(n))}let h=Array(r.length),l=[e[0]-t[0],e[1]-t[1],e[2]-t[2]];abs2(l)<s&&(l=[t[0]-2*e[0]+i[0],t[1]-2*e[1]+i[1],t[2]-2*e[2]+i[2]],abs2(l)<s&&(l=[a[0]-t[0]+3*(e[0]-i[0]),a[1]-t[1]+3*(e[1]-i[1]),a[2]-t[2]+3*(e[2]-i[2])])),l=unit(l);let c=function(t){let e=cross(t,[0,1,0]),i=Number.EPSILON*abs2(t);return abs2(e)>i?unit(e):(e=cross(t,[0,0,1]),abs2(e)>i?unit(e):[1,0,0])}(l);h[0]=new n(t,c,l);for(let s=1;s<r.length;++s){let l=h[s-1],c=r[s],d=1-c,m=d*d,f=m*d,u=3*c;m*=u,d*=u*c;let p=c*c*c,v=[f*t[0]+m*e[0]+d*i[0]+p*a[0],f*t[1]+m*e[1]+d*i[1]+p*a[1],f*t[2]+m*e[2]+d*i[2]+p*a[2]],g=[v[0]-l.p[0],v[1]-l.p[1],v[2]-l.p[2]];if(0!=g[0]||0!=g[1]||0!=g[2]){let t=l.r,e=unit(g),i=l.t,a=dot(e,i),r=[i[0]-2*a*e[0],i[1]-2*a*e[1],i[2]-2*a*e[2]];i=o(c);let d=2*dot(e,t),m=[t[0]-d*e[0],t[1]-d*e[1],t[2]-d*e[2]],f=unit([i[0]-r[0],i[1]-r[1],i[2]-r[2]]),u=2*dot(f,m);m=[m[0]-u*f[0],m[1]-u*f[1],m[2]-u*f[2]],h[s]=new n(v,unit(m),unit(i))}else h[s]=h[s-1]}return h}function tube(t,e,i,r,n,s,o){let h=rmf(t[0],t[1],t[2],t[3],[0,1/3,2/3,1]),l=a*e,c=[[e,0],[e,l],[l,e],[0,e]];function d(e,a,o,l){let d=Array(16);for(let i=0;i<4;++i){let r=h[i],n=r.r[0],s=r.s[0],m=n*e+s*a,f=n*o+s*l;n=r.r[1],s=r.s[1];let u=n*e+s*a,p=n*o+s*l;n=r.r[2],s=r.s[2];let v=n*e+s*a,g=n*o+s*l,x=t[i],w=x[0];w1=x[1],w2=x[2];for(let t=0;t<4;++t){let e=c[t],a=e[0],r=e[1];d[4*i+t]=[m*a+f*r+w,u*a+p*r+w1,v*a+g*r+w2]}}P.push(new BezierPatch(d,i,r,n,s))}d(1,0,0,1),d(0,-1,1,0),d(-1,0,0,-1),d(0,1,-1,0),o&&P.push(new BezierCurve(t,i,r,n,s))}function webGLStart(){canvas=document.ge!
 tElementById("Asymptote"),embedded=window.top.document!=document,initGL(),gl.enable(gl.BLEND),gl.blendFunc(gl.SRC_ALPHA,gl.ONE_MINUS_SRC_ALPHA),gl.enable(gl.DEPTH_TEST),gl.enable(gl.SCISSOR_TEST),canvas.onmousedown=handleMouseDown,document.onmouseup=handleMouseUpOrTouchEnd,document.onmousemove=handleMouseMove,canvas.onkeydown=handleKey,embedded||enableZoom(),canvas.addEventListener("touchstart",handleTouchStart,!1),canvas.addEventListener("touchend",handleMouseUpOrTouchEnd,!1),canvas.addEventListener("touchcancel",handleMouseUpOrTouchEnd,!1),canvas.addEventListener("touchleave",handleMouseUpOrTouchEnd,!1),canvas.addEventListener("touchmove",handleTouchMove,!1),document.addEventListener("keydown",handleKey,!1),canvasWidth0=canvasWidth,canvasHeight0=canvasHeight,mat4.identity(rotMat),0!=window.innerWidth&&0!=window.innerHeight&&resize(),window.addEventListener("resize",resize,!1)}
+let vertex="\n#ifdef WEBGL2\n#define IN in\n#define OUT out\n#else\n#define IN attribute\n#define OUT varying\n#endif\n\nIN vec3 position;\n#ifdef WIDTH\nIN float width;\n#endif\n#ifdef NORMAL\nIN vec3 normal;\n#endif\n\nIN float materialIndex;\n\n#ifdef WEBGL2\nflat out int MaterialIndex;\n#ifdef COLOR\nOUT vec4 Color;\n#endif\n\n#else\nOUT vec4 diffuse;\nOUT vec3 specular;\nOUT float roughness,metallic,fresnel0;\nOUT vec4 emissive;\n\nstruct Material {\n  vec4 diffuse,emissive,specular;\n  vec4 parameters;\n};\n\nuniform Material Materials[Nmaterials];\n#endif\n\n#ifdef COLOR\nIN vec4 color;\n#endif\n\nuniform mat3 normMat;\nuniform mat4 viewMat;\nuniform mat4 projViewMat;\n\n#ifdef NORMAL\n#ifndef ORTHOGRAPHIC\nOUT vec3 ViewPosition;\n#endif\nOUT vec3 Normal;\n#endif\n\nvoid main(void)\n{\n  vec4 v=vec4(position,1.0);\n  gl_Position=projViewMat*v;\n\n#ifdef NORMAL\n#ifndef ORTHOGRAPHIC\n  ViewPosition=(viewMat*v).xyz;\n#endif\n  Normal=normalize(normal*normMat);\n#endif\n\n#ifdef WEBGL2\n  MaterialIndex=int(materialIndex);\n#ifdef COLOR\n  Color=color;\n#endif\n#else\n#ifdef NORMAL\n  Material m;\n#ifdef TRANSPARENT\n  m=Materials[int(abs(materialIndex))-1];\n  emissive=m.emissive;\n  if(materialIndex >= 0.0)\n    diffuse=m.diffuse;\n  else {\n    diffuse=color;\n#if nlights == 0\n    emissive += color;\n#endif\n  }\n#else\n  m=Materials[int(materialIndex)];\n  emissive=m.emissive;\n#ifdef COLOR\n  diffuse=color;\n#if nlights == 0\n    emissive += color;\n#endif\n#else\n  diffuse=m.diffuse;\n#endif // COLOR\n#endif // TRANSPARENT\n  specular=m.specular.rgb;\n  vec4 parameters=m.parameters;\n  roughness=1.0-parameters[0];\n  metallic=parameters[1];\n  fresnel0=parameters[2];\n#else\n  emissive=Materials[int(materialIndex)].emissive;\n#endif // NORMAL\n#endif // WEBGL2\n\n#ifdef WIDTH\n  gl_PointSize=width;\n#endif\n}\n",fragment="\n#ifdef WEBGL2\n#define IN in\nout vec4 outValue;\n#define OUTVALUE outValue\n#else\n#define IN varying\n#define OUTVALUE gl_FragColor\n#endif\n\n#ifdef WEBGL2\nflat in int !
 MaterialIndex;\n\nstruct Material {\n  vec4 diffuse,emissive,specular;\n  vec4 parameters;\n};\n\nuniform Material Materials[Nmaterials];\n\nvec4 diffuse;\nvec3 specular;\nfloat roughness,metallic,fresnel0;\nvec4 emissive;\n\n#ifdef COLOR\nin vec4 Color;\n#endif\n\n#else\nIN vec4 diffuse;\nIN vec3 specular;\nIN float roughness,metallic,fresnel0;\nIN vec4 emissive;\n#endif\n\n#ifdef NORMAL\n\n#ifndef ORTHOGRAPHIC\nIN vec3 ViewPosition;\n#endif\nIN vec3 Normal;\n\nvec3 normal;\n\nstruct Light {\n  vec3 direction;\n  vec3 color;\n};\n\nuniform Light Lights[Nlights];\n\n#ifdef USE_IBL\nuniform sampler2D reflBRDFSampler;\nuniform sampler2D diffuseSampler;\nuniform sampler2D reflImgSampler;\n\nconst float pi=acos(-1.0);\nconst float piInv=1.0/pi;\nconst float twopi=2.0*pi;\nconst float twopiInv=1.0/twopi;\n\n// (x,y,z) -> (r,theta,phi);\n// theta -> [0,pi]: colatitude\n// phi -> [-pi,pi]: longitude\nvec3 cart2sphere(vec3 cart)\n{\n  float x=cart.x;\n  float y=cart.z;\n  float z=cart.y;\n\n  float r=length(cart);\n  float theta=r > 0.0 ? acos(z/r) : 0.0;\n  float phi=atan(y,x);\n\n  return vec3(r,theta,phi);\n}\n\nvec2 normalizedAngle(vec3 cartVec)\n{\n  vec3 sphericalVec=cart2sphere(cartVec);\n  sphericalVec.y=sphericalVec.y*piInv;\n  sphericalVec.z=0.75-sphericalVec.z*twopiInv;\n  return sphericalVec.zy;\n}\n\nvec3 IBLColor(vec3 viewDir)\n{\n  vec3 IBLDiffuse=diffuse.rgb*texture(diffuseSampler,normalizedAngle(normal)).rgb;\n  vec3 reflectVec=normalize(reflect(-viewDir,normal));\n  vec2 reflCoord=normalizedAngle(reflectVec);\n  vec3 IBLRefl=textureLod(reflImgSampler,reflCoord,roughness*ROUGHNESS_STEP_COUNT).rgb;\n  vec2 IBLbrdf=texture(reflBRDFSampler,vec2(dot(normal,viewDir),roughness)).rg;\n  float specularMultiplier=fresnel0*IBLbrdf.x+IBLbrdf.y;\n  vec3 dielectric=IBLDiffuse+specularMultiplier*IBLRefl;\n  vec3 metal=diffuse.rgb*IBLRefl;\n  return mix(dielectric,metal,metallic);\n}\n#else\nfloat Roughness2;\nfloat NDF_TRG(vec3 h)\n{\n  float ndoth=max(dot(normal,h),0.0);\n  float alpha2=Roughness2*Roughness2;\n  flo!
 at denom=ndoth*ndoth*(alpha2-1.0)+1.0;\n  return denom != 0.0 ? alpha2/(denom*denom) : 0.0;\n}\n\nfloat GGX_Geom(vec3 v)\n{\n  float ndotv=max(dot(v,normal),0.0);\n  float ap=1.0+Roughness2;\n  float k=0.125*ap*ap;\n  return ndotv/((ndotv*(1.0-k))+k);\n}\n\nfloat Geom(vec3 v, vec3 l)\n{\n  return GGX_Geom(v)*GGX_Geom(l);\n}\n\nfloat Fresnel(vec3 h, vec3 v, float fresnel0)\n{\n  float a=1.0-max(dot(h,v),0.0);\n  float b=a*a;\n  return fresnel0+(1.0-fresnel0)*b*b*a;\n}\n\n// physical based shading using UE4 model.\nvec3 BRDF(vec3 viewDirection, vec3 lightDirection)\n{\n  vec3 lambertian=diffuse.rgb;\n  vec3 h=normalize(lightDirection+viewDirection);\n\n  float omegain=max(dot(viewDirection,normal),0.0);\n  float omegaln=max(dot(lightDirection,normal),0.0);\n\n  float D=NDF_TRG(h);\n  float G=Geom(viewDirection,lightDirection);\n  float F=Fresnel(h,viewDirection,fresnel0);\n\n  float denom=4.0*omegain*omegaln;\n  float rawReflectance=denom > 0.0 ? (D*G)/denom : 0.0;\n\n  vec3 dielectric=mix(lambertian,rawReflectance*specular,F);\n  vec3 metal=rawReflectance*diffuse.rgb;\n\n  return mix(dielectric,metal,metallic);\n}\n#endif\n\n#endif\n\nvoid main(void)\n{\n#ifdef WEBGL2\n#ifdef NORMAL\n  Material m;\n#ifdef TRANSPARENT\n  m=Materials[abs(MaterialIndex)-1];\n  emissive=m.emissive;\n  if(MaterialIndex >= 0)\n    diffuse=m.diffuse;\n  else {\n    diffuse=Color;\n#if nlights == 0\n    emissive += Color;\n#endif\n  }\n#else\n  m=Materials[MaterialIndex];\n  emissive=m.emissive;\n#ifdef COLOR\n  diffuse=Color;\n#if nlights == 0\n    emissive += Color;\n#endif\n#else\n  diffuse=m.diffuse;\n#endif // COLOR\n#endif // TRANSPARENT\n  specular=m.specular.rgb;\n  vec4 parameters=m.parameters;\n  roughness=1.0-parameters[0];\n  metallic=parameters[1];\n  fresnel0=parameters[2];\n#else\n  emissive=Materials[MaterialIndex].emissive;\n#endif // NORMAL\n#endif // WEBGL2\n\n#if defined(NORMAL) && nlights > 0\n  normal=normalize(Normal);\n  normal=gl_FrontFacing ? normal : -normal;\n#ifdef ORTHOGRAPHIC\n  vec3 viewDir=vec3(0.0,0.0,1.!
 0);\n#else\n  vec3 viewDir=-normalize(ViewPosition);\n#endif\n\nvec3 color;\n#ifdef USE_IBL\n  color=IBLColor(viewDir);\n#else\n  Roughness2=roughness*roughness;\n  color=emissive.rgb;\n  for(int i=0; i < nlights; ++i) {\n    Light Li=Lights[i];\n    vec3 L=Li.direction;\n    float cosTheta=max(dot(normal,L),0.0);\n    vec3 radiance=cosTheta*Li.color;\n    color += BRDF(viewDir,L)*radiance;\n  }\n#endif\n  OUTVALUE=vec4(color,diffuse.a);\n#else\n  OUTVALUE=emissive;\n#endif\n}\n";!function(e,t){if("object"==typeof exports&&"object"==typeof module)module.exports=t();else if("function"==typeof define&&define.amd)define([],t);else{var i=t();for(var a in i)("object"==typeof exports?exports:e)[a]=i[a]}}("undefined"!=typeof self?self:this,(function(){return function(e){var t={};function i(a){if(t[a])return t[a].exports;var n=t[a]={i:a,l:!1,exports:{}};return e[a].call(n.exports,n,n.exports,i),n.l=!0,n.exports}return i.m=e,i.c=t,i.d=function(e,t,a){i.o(e,t)||Object.defineProperty(e,t,{configurable:!1,enumerable:!0,get:a})},i.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return i.d(t,"a",t),t},i.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},i.p="",i(i.s=1)}([function(e,t,i){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.setMatrixArrayType=function(e){t.ARRAY_TYPE=e},t.toRadian=function(e){return e*n},t.equals=function(e,t){return Math.abs(e-t)<=a*Math.max(1,Math.abs(e),Math.abs(t))};var a=t.EPSILON=1e-6;t.ARRAY_TYPE="undefined"!=typeof Float32Array?Float32Array:Array,t.RANDOM=Math.random;var n=Math.PI/180},function(e,t,i){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.mat4=t.mat3=void 0;var a=r(i(2)),n=r(i(3));function r(e){if(e&&e.__esModule)return e;var t={};if(null!=e)for(var i in e)Object.prototype.hasOwnProperty.call(e,i)&&(t[i]=e[i]);return t.default=e,t}t.mat3=a,t.mat4=n},function(e,t,i){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.create=function(){var e=new a.ARRAY_TYPE(9);return e[0]=1,e[1]=0,e[2]=0!
 ,e[3]=0,e[4]=1,e[5]=0,e[6]=0,e[7]=0,e[8]=1,e},t.fromMat4=function(e,t){return e[0]=t[0],e[1]=t[1],e[2]=t[2],e[3]=t[4],e[4]=t[5],e[5]=t[6],e[6]=t[8],e[7]=t[9],e[8]=t[10],e},t.invert=function(e,t){var i=t[0],a=t[1],n=t[2],r=t[3],s=t[4],o=t[5],l=t[6],h=t[7],c=t[8],d=c*s-o*h,m=-c*r+o*l,f=h*r-s*l,u=i*d+a*m+n*f;if(!u)return null;return u=1/u,e[0]=d*u,e[1]=(-c*a+n*h)*u,e[2]=(o*a-n*s)*u,e[3]=m*u,e[4]=(c*i-n*l)*u,e[5]=(-o*i+n*r)*u,e[6]=f*u,e[7]=(-h*i+a*l)*u,e[8]=(s*i-a*r)*u,e};var a=function(e){if(e&&e.__esModule)return e;var t={};if(null!=e)for(var i in e)Object.prototype.hasOwnProperty.call(e,i)&&(t[i]=e[i]);return t.default=e,t}(i(0))},function(e,t,i){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.create=function(){var e=new a.ARRAY_TYPE(16);return e[0]=1,e[1]=0,e[2]=0,e[3]=0,e[4]=0,e[5]=1,e[6]=0,e[7]=0,e[8]=0,e[9]=0,e[10]=1,e[11]=0,e[12]=0,e[13]=0,e[14]=0,e[15]=1,e},t.identity=function(e){return e[0]=1,e[1]=0,e[2]=0,e[3]=0,e[4]=0,e[5]=1,e[6]=0,e[7]=0,e[8]=0,e[9]=0,e[10]=1,e[11]=0,e[12]=0,e[13]=0,e[14]=0,e[15]=1,e},t.invert=function(e,t){var i=t[0],a=t[1],n=t[2],r=t[3],s=t[4],o=t[5],l=t[6],h=t[7],c=t[8],d=t[9],m=t[10],f=t[11],u=t[12],p=t[13],g=t[14],v=t[15],x=i*o-a*s,w=i*l-n*s,M=i*h-r*s,b=a*l-n*o,T=a*h-r*o,S=n*h-r*l,R=c*p-d*u,A=c*g-m*u,I=c*v-f*u,P=d*g-m*p,E=d*v-f*p,y=m*v-f*g,L=x*y-w*E+M*P+b*I-T*A+S*R;if(!L)return null;return L=1/L,e[0]=(o*y-l*E+h*P)*L,e[1]=(n*E-a*y-r*P)*L,e[2]=(p*S-g*T+v*b)*L,e[3]=(m*T-d*S-f*b)*L,e[4]=(l*I-s*y-h*A)*L,e[5]=(i*y-n*I+r*A)*L,e[6]=(g*M-u*S-v*w)*L,e[7]=(c*S-m*M+f*w)*L,e[8]=(s*E-o*I+h*R)*L,e[9]=(a*I-i*E-r*R)*L,e[10]=(u*T-p*M+v*x)*L,e[11]=(d*M-c*T-f*x)*L,e[12]=(o*A-s*P-l*R)*L,e[13]=(i*P-a*A+n*R)*L,e[14]=(p*w-u*b-g*x)*L,e[15]=(c*b-d*w+m*x)*L,e},t.multiply=n,t.translate=function(e,t,i){var a=i[0],n=i[1],r=i[2],s=void 0,o=void 0,l=void 0,h=void 0,c=void 0,d=void 0,m=void 0,f=void 0,u=void 0,p=void 0,g=void 0,v=void 0;t===e?(e[12]=t[0]*a+t[4]*n+t[8]*r+t[12],e[13]=t[1]*a+t[5]*n+t[9]*r+t[13],e[14]=t[2]*a+t[6]*n+t[10]*r+t[14],e[15]=t[3]*a+t[7]*n+t[11]*r+t[15]):(s=t[0],o=t[1],l=t[2],!
 h=t[3],c=t[4],d=t[5],m=t[6],f=t[7],u=t[8],p=t[9],g=t[10],v=t[11],e[0]=s,e[1]=o,e[2]=l,e[3]=h,e[4]=c,e[5]=d,e[6]=m,e[7]=f,e[8]=u,e[9]=p,e[10]=g,e[11]=v,e[12]=s*a+c*n+u*r+t[12],e[13]=o*a+d*n+p*r+t[13],e[14]=l*a+m*n+g*r+t[14],e[15]=h*a+f*n+v*r+t[15]);return e},t.rotate=function(e,t,i,n){var r,s,o,l,h,c,d,m,f,u,p,g,v,x,w,M,b,T,S,R,A,I,P,E,y=n[0],L=n[1],D=n[2],O=Math.sqrt(y*y+L*L+D*D);if(Math.abs(O)<a.EPSILON)return null;y*=O=1/O,L*=O,D*=O,r=Math.sin(i),s=Math.cos(i),o=1-s,l=t[0],h=t[1],c=t[2],d=t[3],m=t[4],f=t[5],u=t[6],p=t[7],g=t[8],v=t[9],x=t[10],w=t[11],M=y*y*o+s,b=L*y*o+D*r,T=D*y*o-L*r,S=y*L*o-D*r,R=L*L*o+s,A=D*L*o+y*r,I=y*D*o+L*r,P=L*D*o-y*r,E=D*D*o+s,e[0]=l*M+m*b+g*T,e[1]=h*M+f*b+v*T,e[2]=c*M+u*b+x*T,e[3]=d*M+p*b+w*T,e[4]=l*S+m*R+g*A,e[5]=h*S+f*R+v*A,e[6]=c*S+u*R+x*A,e[7]=d*S+p*R+w*A,e[8]=l*I+m*P+g*E,e[9]=h*I+f*P+v*E,e[10]=c*I+u*P+x*E,e[11]=d*I+p*P+w*E,t!==e&&(e[12]=t[12],e[13]=t[13],e[14]=t[14],e[15]=t[15]);return e},t.fromTranslation=function(e,t){return e[0]=1,e[1]=0,e[2]=0,e[3]=0,e[4]=0,e[5]=1,e[6]=0,e[7]=0,e[8]=0,e[9]=0,e[10]=1,e[11]=0,e[12]=t[0],e[13]=t[1],e[14]=t[2],e[15]=1,e},t.fromRotation=function(e,t,i){var n,r,s,o=i[0],l=i[1],h=i[2],c=Math.sqrt(o*o+l*l+h*h);if(Math.abs(c)<a.EPSILON)return null;return o*=c=1/c,l*=c,h*=c,n=Math.sin(t),r=Math.cos(t),s=1-r,e[0]=o*o*s+r,e[1]=l*o*s+h*n,e[2]=h*o*s-l*n,e[3]=0,e[4]=o*l*s-h*n,e[5]=l*l*s+r,e[6]=h*l*s+o*n,e[7]=0,e[8]=o*h*s+l*n,e[9]=l*h*s-o*n,e[10]=h*h*s+r,e[11]=0,e[12]=0,e[13]=0,e[14]=0,e[15]=1,e},t.frustum=function(e,t,i,a,n,r,s){var o=1/(i-t),l=1/(n-a),h=1/(r-s);return e[0]=2*r*o,e[1]=0,e[2]=0,e[3]=0,e[4]=0,e[5]=2*r*l,e[6]=0,e[7]=0,e[8]=(i+t)*o,e[9]=(n+a)*l,e[10]=(s+r)*h,e[11]=-1,e[12]=0,e[13]=0,e[14]=s*r*2*h,e[15]=0,e},t.ortho=function(e,t,i,a,n,r,s){var o=1/(t-i),l=1/(a-n),h=1/(r-s);return e[0]=-2*o,e[1]=0,e[2]=0,e[3]=0,e[4]=0,e[5]=-2*l,e[6]=0,e[7]=0,e[8]=0,e[9]=0,e[10]=2*h,e[11]=0,e[12]=(t+i)*o,e[13]=(n+a)*l,e[14]=(s+r)*h,e[15]=1,e};var a=function(e){if(e&&e.__esModule)return e;var t={};if(null!=e)for(var i in e)Object.prototype.hasOwnProperty.call(e,i)&&!
 (t[i]=e[i]);return t.default=e,t}(i(0));function n(e,t,i){var a=t[0],n=t[1],r=t[2],s=t[3],o=t[4],l=t[5],h=t[6],c=t[7],d=t[8],m=t[9],f=t[10],u=t[11],p=t[12],g=t[13],v=t[14],x=t[15],w=i[0],M=i[1],b=i[2],T=i[3];return e[0]=w*a+M*o+b*d+T*p,e[1]=w*n+M*l+b*m+T*g,e[2]=w*r+M*h+b*f+T*v,e[3]=w*s+M*c+b*u+T*x,w=i[4],M=i[5],b=i[6],T=i[7],e[4]=w*a+M*o+b*d+T*p,e[5]=w*n+M*l+b*m+T*g,e[6]=w*r+M*h+b*f+T*v,e[7]=w*s+M*c+b*u+T*x,w=i[8],M=i[9],b=i[10],T=i[11],e[8]=w*a+M*o+b*d+T*p,e[9]=w*n+M*l+b*m+T*g,e[10]=w*r+M*h+b*f+T*v,e[11]=w*s+M*c+b*u+T*x,w=i[12],M=i[13],b=i[14],T=i[15],e[12]=w*a+M*o+b*d+T*p,e[13]=w*n+M*l+b*m+T*g,e[14]=w*r+M*h+b*f+T*v,e[15]=w*s+M*c+b*u+T*x,e}}])}));let Transform,canvasWidth,canvasHeight,imageURL,image,minBound,maxBound,orthographic,angleOfView,initialZoom,viewportMargin,zoomFactor,zoomPinchFactor,zoomPinchCap,zoomStep,shiftHoldDistance,shiftWaitTime,vibrateTime,canvasWidth0,canvasHeight0,zoom0,embedded,canvas,gl,alpha,offscreen,context,maxMaterials,halfCanvasWidth,halfCanvasHeight,P=[],Materials=[],Lights=[],Centers=[],Background=[1,1,1,1],absolute=!1,ibl=!1,viewportShift=[0,0],webgl2=!1,nlights=0,Nmaterials=2,materials=[];const pixelResolution=.75,zoomRemeshFactor=1.5,FillFactor=.1,windowTrim=10,third=1/3,pi=Math.acos(-1),radians=pi/180;let Zoom,lastZoom,xshift,yshift,maxViewportWidth,maxViewportHeight,H,zmin,zmax,size2,ArcballFactor,rotMat=mat4.create(),projMat=mat4.create(),viewMat=mat4.create(),projViewMat=mat4.create(),normMat=mat3.create(),viewMat3=mat3.create(),cjMatInv=mat4.create(),Temp=mat4.create(),center={x:0,y:0,z:0},shift={x:0,y:0},viewParam={xmin:0,xmax:0,ymin:0,ymax:0,zmin:0,zmax:0},remesh=!0,wireframe=0,mouseDownOrTouchActive=!1,lastMouseX=null,lastMouseY=null,touchID=null,Positions=[],Normals=[],Colors=[],Indices=[],IBLReflMap=null,IBLDiffuseMap=null,IBLbdrfMap=null;function IBLReady(){return null!==IBLReflMap&&null!==IBLDiffuseMap&&null!==IBLbdrfMap}function SetIBL(){embedded||deleteShaders(),initShaders(ibl)}let roughnessStepCount=8;class Material{constructor(e,t,i,a,n,r){this.diffuse=e,this.e!
 missive=t,this.specular=i,this.shininess=a,this.metallic=n,this.fresnel0=r}setUniform(e,t){let i=i=>gl.getUniformLocation(e,"Materials["+t+"]."+i);gl.uniform4fv(i("diffuse"),new Float32Array(this.diffuse)),gl.uniform4fv(i("emissive"),new Float32Array(this.emissive)),gl.uniform4fv(i("specular"),new Float32Array(this.specular)),gl.uniform4f(i("parameters"),this.shininess,this.metallic,this.fresnel0,0)}}let indexExt,TRIANGLES,material0Data,material1Data,materialData,colorData,transparentData,triangleData,materialIndex,enumPointLight=1,enumDirectionalLight=2;class Light{constructor(e,t){this.direction=e,this.color=t}setUniform(e,t){let i=i=>gl.getUniformLocation(e,"Lights["+t+"]."+i);gl.uniform3fv(i("direction"),new Float32Array(this.direction)),gl.uniform3fv(i("color"),new Float32Array(this.color))}}function initShaders(e=!1){let t=gl.getParameter(gl.MAX_VERTEX_UNIFORM_VECTORS);maxMaterials=Math.floor((t-14)/4),Nmaterials=Math.min(Math.max(Nmaterials,Materials.length),maxMaterials),pixelOpt=["WIDTH"],materialOpt=["NORMAL"],colorOpt=["NORMAL","COLOR"],transparentOpt=["NORMAL","COLOR","TRANSPARENT"],e&&(materialOpt.push("USE_IBL"),transparentOpt.push("USE_IBL")),pixelShader=initShader(pixelOpt),materialShader=initShader(materialOpt),colorShader=initShader(colorOpt),transparentShader=initShader(transparentOpt)}function deleteShaders(){gl.deleteProgram(transparentShader),gl.deleteProgram(colorShader),gl.deleteProgram(materialShader),gl.deleteProgram(pixelShader)}function saveAttributes(){let e=webgl2?window.top.document.asygl2[alpha]:window.top.document.asygl[alpha];e.gl=gl,e.nlights=Lights.length,e.Nmaterials=Nmaterials,e.maxMaterials=maxMaterials,e.pixelShader=pixelShader,e.materialShader=materialShader,e.colorShader=colorShader,e.transparentShader=transparentShader}function restoreAttributes(){let e=webgl2?window.top.document.asygl2[alpha]:window.top.document.asygl[alpha];gl=e.gl,nlights=e.nlights,Nmaterials=e.Nmaterials,maxMaterials=e.maxMaterials,pixelShader=e.pixelShader,materialShader=e.materialShader,colorShade!
 r=e.colorShader,transparentShader=e.transparentShader}function webGL(e,t){let i;return webgl2&&(i=e.getContext("webgl2",{alpha:t}),embedded&&!i)?(webgl2=!1,ibl=!1,initGL(!1),null):(i||(webgl2=!1,ibl=!1,i=e.getContext("webgl",{alpha:t})),i||alert("Could not initialize WebGL"),i)}function initGL(e=!0){if(ibl&&(webgl2=!0),alpha=Background[3]<1,embedded){let t=window.top.document;if(e&&(context=canvas.getContext("2d")),offscreen=webgl2?t.offscreen2:t.offscreen,offscreen||(offscreen=t.createElement("canvas"),webgl2?t.offscreen2=offscreen:t.offscreen=offscreen),webgl2?t.asygl2||(t.asygl2=Array(2)):t.asygl||(t.asygl=Array(2)),asygl=webgl2?t.asygl2:t.asygl,asygl[alpha]&&asygl[alpha].gl)restoreAttributes(),(Lights.length!=nlights||Math.min(Materials.length,maxMaterials)>Nmaterials)&&(initShaders(),saveAttributes());else{if(rc=webGL(offscreen,alpha),!rc)return;gl=rc,initShaders(),webgl2?t.asygl2[alpha]={}:t.asygl[alpha]={},saveAttributes()}}else gl=webGL(canvas,alpha),initShaders();indexExt=gl.getExtension("OES_element_index_uint"),TRIANGLES=gl.TRIANGLES,material0Data=new vertexBuffer(gl.POINTS),material1Data=new vertexBuffer(gl.LINES),materialData=new vertexBuffer,colorData=new vertexBuffer,transparentData=new vertexBuffer,triangleData=new vertexBuffer}function getShader(e,t,i,a=[]){let n=webgl2?"300 es":"100",r=Array(...a),s=[["nlights",0==wireframe?Lights.length:0],["Nmaterials",Nmaterials]],o=[["int","Nlights",Math.max(Lights.length,1)]];webgl2&&r.push("WEBGL2"),ibl&&s.push(["ROUGHNESS_STEP_COUNT",roughnessStepCount.toFixed(2)]),orthographic&&r.push("ORTHOGRAPHIC"),macros_str=s.map(e=>`#define ${e[0]} ${e[1]}`).join("\n"),define_str=r.map(e=>"#define "+e).join("\n"),const_str=o.map(e=>`const ${e[0]} ${e[1]}=${e[2]};`).join("\n"),ext_str=[].map(e=>`#extension ${e}: enable`).join("\n"),shaderSrc=`#version ${n}\n${ext_str}\n${define_str}\n${const_str}\n${macros_str}\n\n\n#ifdef GL_FRAGMENT_PRECISION_HIGH\nprecision highp float;\n#else\nprecision mediump float;\n#endif\n  \n${t}\n  `;let l=e.createShader(i);return e.shade!
 rSource(l,shaderSrc),e.compileShader(l),e.getShaderParameter(l,e.COMPILE_STATUS)?l:(alert(e.getShaderInfoLog(l)),null)}function registerBuffer(e,t,i,a=gl.ARRAY_BUFFER){return e.length>0&&(0==t&&(t=gl.createBuffer(),i=!0),gl.bindBuffer(a,t),i&&gl.bufferData(a,e,gl.STATIC_DRAW)),t}function drawBuffer(e,t,i=e.indices){if(0==e.indices.length)return;let a=t!=pixelShader;setUniforms(e,t),null!=IBLDiffuseMap&&(gl.activeTexture(gl.TEXTURE0),gl.bindTexture(gl.TEXTURE_2D,IBLbdrfMap),gl.uniform1i(gl.getUniformLocation(t,"reflBRDFSampler"),0),gl.activeTexture(gl.TEXTURE1),gl.bindTexture(gl.TEXTURE_2D,IBLDiffuseMap),gl.uniform1i(gl.getUniformLocation(t,"diffuseSampler"),1),gl.activeTexture(gl.TEXTURE2),gl.bindTexture(gl.TEXTURE_2D,IBLReflMap),gl.uniform1i(gl.getUniformLocation(t,"reflImgSampler"),2));let n=remesh||e.partial||!e.rendered;e.verticesBuffer=registerBuffer(new Float32Array(e.vertices),e.verticesBuffer,n),gl.vertexAttribPointer(positionAttribute,3,gl.FLOAT,!1,a?24:16,0),a?Lights.length>0&&gl.vertexAttribPointer(normalAttribute,3,gl.FLOAT,!1,24,12):gl.vertexAttribPointer(widthAttribute,1,gl.FLOAT,!1,16,12),e.materialsBuffer=registerBuffer(new Int16Array(e.materialIndices),e.materialsBuffer,n),gl.vertexAttribPointer(materialAttribute,1,gl.SHORT,!1,2,0),t!=colorShader&&t!=transparentShader||(e.colorsBuffer=registerBuffer(new Uint8Array(e.colors),e.colorsBuffer,n),gl.vertexAttribPointer(colorAttribute,4,gl.UNSIGNED_BYTE,!0,0,0)),e.indicesBuffer=registerBuffer(indexExt?new Uint32Array(i):new Uint16Array(i),e.indicesBuffer,n,gl.ELEMENT_ARRAY_BUFFER),e.rendered=!0,gl.drawElements(a?wireframe?gl.LINES:e.type:gl.POINTS,i.length,indexExt?gl.UNSIGNED_INT:gl.UNSIGNED_SHORT,0)}class vertexBuffer{constructor(e){this.type=e||TRIANGLES,this.verticesBuffer=0,this.materialsBuffer=0,this.colorsBuffer=0,this.indicesBuffer=0,this.rendered=!1,this.partial=!1,this.clear()}clear(){this.vertices=[],this.materialIndices=[],this.colors=[],this.indices=[],this.nvertices=0,this.materials=[],this.materialTable=[]}vertex(e,t){return this.vertic!
 es.push(e[0]),this.vertices.push(e[1]),this.vertices.push(e[2]),this.vertices.push(t[0]),this.vertices.push(t[1]),this.vertices.push(t[2]),this.materialIndices.push(materialIndex),this.nvertices++}Vertex(e,t,i=[0,0,0,0]){return this.vertices.push(e[0]),this.vertices.push(e[1]),this.vertices.push(e[2]),this.vertices.push(t[0]),this.vertices.push(t[1]),this.vertices.push(t[2]),this.materialIndices.push(materialIndex),this.colors.push(i[0]),this.colors.push(i[1]),this.colors.push(i[2]),this.colors.push(i[3]),this.nvertices++}vertex0(e,t){return this.vertices.push(e[0]),this.vertices.push(e[1]),this.vertices.push(e[2]),this.vertices.push(t),this.materialIndices.push(materialIndex),this.nvertices++}iVertex(e,t,i,a=[0,0,0,0]){let n=6*e;this.vertices[n]=t[0],this.vertices[n+1]=t[1],this.vertices[n+2]=t[2],this.vertices[n+3]=i[0],this.vertices[n+4]=i[1],this.vertices[n+5]=i[2],this.materialIndices[e]=materialIndex;let r=4*e;this.colors[r]=a[0],this.colors[r+1]=a[1],this.colors[r+2]=a[2],this.colors[r+3]=a[3],this.indices.push(e)}append(e){append(this.vertices,e.vertices),append(this.materialIndices,e.materialIndices),append(this.colors,e.colors),appendOffset(this.indices,e.indices,this.nvertices),this.nvertices+=e.nvertices}}function append(e,t){let i=e.length,a=t.length;e.length+=a;for(let n=0;n<a;++n)e[i+n]=t[n]}function appendOffset(e,t,i){let a=e.length,n=t.length;e.length+=t.length;for(let r=0;r<n;++r)e[a+r]=t[r]+i}class Geometry{constructor(){this.data=new vertexBuffer,this.Onscreen=!1,this.m=[]}offscreen(e){let t=projViewMat,i=e[0],a=i[0],n=i[1],r=i[2],s=1/(t[3]*a+t[7]*n+t[11]*r+t[15]);this.x=this.X=(t[0]*a+t[4]*n+t[8]*r+t[12])*s,this.y=this.Y=(t[1]*a+t[5]*n+t[9]*r+t[13])*s;for(let i=1,a=e.length;i<a;++i){let a=e[i],n=a[0],r=a[1],s=a[2],o=1/(t[3]*n+t[7]*r+t[11]*s+t[15]),l=(t[0]*n+t[4]*r+t[8]*s+t[12])*o,h=(t[1]*n+t[5]*r+t[9]*s+t[13])*o;l<this.x?this.x=l:l>this.X&&(this.X=l),h<this.y?this.y=h:h>this.Y&&(this.Y=h)}return(this.X<-1.01||this.x>1.01||this.Y<-1.01||this.y>1.01)&&(this.Onscreen=!1,!0)}T(e){let t=this.c[0!
 ],i=this..c[1],a=this.c[2],n=e[0]-t,r=e[1]-i,s=e[2]-a;return[n*normMat[0]+r*normMat[3]+s*normMat[6]+t,n*normMat[1]+r*normMat[4]+s*normMat[7]+i,n*normMat[2]+r*normMat[5]+s*normMat[8]+a]}Tcorners(e,t){return[this.T(e),this.T([e[0],e[1],t[2]]),this.T([e[0],t[1],e[2]]),this.T([e[0],t[1],t[2]]),this.T([t[0],e[1],e[2]]),this.T([t[0],e[1],t[2]]),this.T([t[0],t[1],e[2]]),this.T(t)]}setMaterial(e,t){null==e.materialTable[this.MaterialIndex]&&(e.materials.length>=Nmaterials&&(e.partial=!0,t()),e.materialTable[this.MaterialIndex]=e.materials.length,e.materials.push(Materials[this.MaterialIndex])),materialIndex=e.materialTable[this.MaterialIndex]}render(){let e;if(this.setMaterialIndex(),0==this.CenterIndex?e=corners(this.Min,this.Max):(this.c=Centers[this.CenterIndex-1],e=this.Tcorners(this.Min,this.Max)),this.offscreen(e))return this.data.clear(),void this.notRendered();let t,i=this.controlpoints;if(0==this.CenterIndex){if(!remesh&&this.Onscreen)return void this.append();t=i}else{let e=i.length;t=Array(e);for(let a=0;a<e;++a)t[a]=this.T(i[a])}let a=orthographic?1:this.Min[2]/maxBound[2],n=.75*Math.hypot(a*(viewParam.xmax-viewParam.xmin),a*(viewParam.ymax-viewParam.ymin))/size2;this.res2=n*n,this.Epsilon=.1*n,this.data.clear(),this.notRendered(),this.Onscreen=!0,this.process(t)}}class BezierPatch extends Geometry{constructor(e,t,i,a,n,r){super(),this.controlpoints=e,this.CenterIndex=t,this.MaterialIndex=i,this.Min=a,this.Max=n,this.color=r;let s=e.length;if(r){let e=r[0][3]+r[1][3]+r[2][3];this.transparent=16==s||4==s?e+r[3][3]<1020:e<765}else this.transparent=Materials[i].diffuse[3]<1;this.vertex=this.transparent?this.data.Vertex.bind(this.data):this.data.vertex.bind(this.data),this.L2norm(this.controlpoints)}setMaterialIndex(){this.transparent?this.setMaterial(transparentData,drawTransparent):this.color?this.setMaterial(colorData,drawColor):this.setMaterial(materialData,drawMaterial)}L2norm(e){let t=e[0];this.epsilon=0;let i=e.length;for(let a=1;a<i;++a)this.epsilon=Math.max(this.epsilon,abs2([e[a][0]-t[0],e[a][1]-t[1],e[!
 a][2]-t[2]]));this.epsilon*=Number.EPSILON}processTriangle(e){let t=e[0],i=e[1],a=e[2],n=unit(cross([i[0]-t[0],i[1]-t[1],i[2]-t[2]],[a[0]-t[0],a[1]-t[1],a[2]-t[2]]));if(!this.offscreen([t,i,a])){let e,r,s;this.color?(e=this.data.Vertex(t,n,this.color[0]),r=this.data.Vertex(i,n,this.color[1]),s=this.data.Vertex(a,n,this.color[2])):(e=this.vertex(t,n),r=this.vertex(i,n),s=this.vertex(a,n)),0==wireframe?(this.data.indices.push(e),this.data.indices.push(r),this.data.indices.push(s)):(this.data.indices.push(e),this.data.indices.push(r),this.data.indices.push(r),this.data.indices.push(s),this.data.indices.push(s),this.data.indices.push(e)),this.append()}}processQuad(e){let t=e[0],i=e[1],a=e[2],n=e[3],r=cross([i[0]-t[0],i[1]-t[1],i[2]-t[2]],[a[0]-i[0],a[1]-i[1],a[2]-i[2]]),s=cross([a[0]-n[0],a[1]-n[1],a[2]-n[2]],[n[0]-t[0],n[1]-t[1],n[2]-t[2]]),o=unit([r[0]+s[0],r[1]+s[1],r[2]+s[2]]);if(!this.offscreen([t,i,a,n])){let e,r,s,l;this.color?(e=this.data.Vertex(t,o,this.color[0]),r=this.data.Vertex(i,o,this.color[1]),s=this.data.Vertex(a,o,this.color[2]),l=this.data.Vertex(n,o,this.color[3])):(e=this.vertex(t,o),r=this.vertex(i,o),s=this.vertex(a,o),l=this.vertex(n,o)),0==wireframe?(this.data.indices.push(e),this.data.indices.push(r),this.data.indices.push(s),this.data.indices.push(e),this.data.indices.push(s),this.data.indices.push(l)):(this.data.indices.push(e),this.data.indices.push(r),this.data.indices.push(r),this.data.indices.push(s),this.data.indices.push(s),this.data.indices.push(l),this.data.indices.push(l),this.data.indices.push(e)),this.append()}}curve(e,t,i,a,n){new BezierCurve([e[t],e[i],e[a],e[n]],0,materialIndex,this.Min,this.Max).render()}process(e){if(this.transparent&&1!=wireframe&&(materialIndex=this.color?-1-materialIndex:1+materialIndex),10==e.length)return this.process3(e);if(3==e.length)return this.processTriangle(e);if(4==e.length)return this.processQuad(e);if(1==wireframe)return this.curve(e,0,4,8,12),this.curve(e,12,13,14,15),this.curve(e,15,11,7,3),void this.curve(e,3,2,1,0);let t=e[0],i=e[3],a=e[!
 12],n=e[15],r=this.normal(i,e[2],e[1],t,e[4],e[8],a);abs2(r)<this.epsilon&&(r=this.normal(i,e[2],e[1],t,e[13],e[14],n),abs2(r)<this.epsilon&&(r=this.normal(n,e[11],e[7],i,e[4],e[8],a)));let s=this.normal(t,e[4],e[8],a,e[13],e[14],n);abs2(s)<this.epsilon&&(s=this.normal(t,e[4],e[8],a,e[11],e[7],i),abs2(s)<this.epsilon&&(s=this.normal(i,e[2],e[1],t,e[13],e[14],n)));let o=this.normal(a,e[13],e[14],n,e[11],e[7],i);abs2(o)<this.epsilon&&(o=this.normal(a,e[13],e[14],n,e[2],e[1],t),abs2(o)<this.epsilon&&(o=this.normal(t,e[4],e[8],a,e[11],e[7],i)));let l=this.normal(n,e[11],e[7],i,e[2],e[1],t);if(abs2(l)<this.epsilon&&(l=this.normal(n,e[11],e[7],i,e[4],e[8],a),abs2(l)<this.epsilon&&(l=this.normal(a,e[13],e[14],n,e[2],e[1],t))),this.color){let h=this.color[0],c=this.color[1],d=this.color[2],m=this.color[3],f=this.data.Vertex(t,r,h),u=this.data.Vertex(a,s,c),p=this.data.Vertex(n,o,d),g=this.data.Vertex(i,l,m);this.Render(e,f,u,p,g,t,a,n,i,!1,!1,!1,!1,h,c,d,m)}else{let h=this.vertex(t,r),c=this.vertex(a,s),d=this.vertex(n,o),m=this.vertex(i,l);this.Render(e,h,c,d,m,t,a,n,i,!1,!1,!1,!1)}this.data.indices.length>0&&this.append()}append(){this.transparent?transparentData.append(this.data):this.color?colorData.append(this.data):materialData.append(this.data)}notRendered(){this.transparent?transparentData.rendered=!1:this.color?colorData.rendered=!1:materialData.rendered=!1}Render(e,t,i,a,n,r,s,o,l,h,c,d,m,f,u,p,g){let v=this.Distance(e);if(v[0]<this.res2&&v[1]<this.res2)this.offscreen([r,s,o])||(0==wireframe?(this.data.indices.push(t),this.data.indices.push(i),this.data.indices.push(a)):(this.data.indices.push(t),this.data.indices.push(i),this.data.indices.push(i),this.data.indices.push(a))),this.offscreen([r,o,l])||(0==wireframe?(this.data.indices.push(t),this.data.indices.push(a),this.data.indices.push(n)):(this.data.indices.push(a),this.data.indices.push(n),this.data.indices.push(n),this.data.indices.push(t)));else{if(this.offscreen(e))return;let x=e[0],w=e[3],M=e[12],b=e[15];if(v[0]<this.res2){let v=new Split3(x,e[1],e[2],!
 w),T=new Split3(e[4],e[5],e[6],e[7]),S=new Split3(e[8],e[9],e[10],e[11]),R=new Split3(M,e[13],e[14],b),A=[x,v.m0,v.m3,v.m5,e[4],T.m0,T.m3,T.m5,e[8],S.m0,S.m3,S.m5,M,R.m0,R.m3,R.m5],I=[v.m5,v.m4,v.m2,w,T.m5,T.m4,T.m2,e[7],S.m5,S.m4,S.m2,e[11],R.m5,R.m4,R.m2,b],P=this.normal(A[12],A[13],A[14],A[15],A[11],A[7],A[3]);abs2(P)<=this.epsilon&&(P=this.normal(A[12],A[13],A[14],A[15],A[2],A[1],A[0]),abs2(P)<=this.epsilon&&(P=this.normal(A[0],A[4],A[8],A[12],A[11],A[7],A[3])));let E=this.normal(I[3],I[2],I[1],I[0],I[4],I[8],I[12]);abs2(E)<=this.epsilon&&(E=this.normal(I[3],I[2],I[1],I[0],I[13],I[14],I[15]),abs2(E)<=this.epsilon&&(E=this.normal(I[15],I[11],I[7],I[3],I[4],I[8],I[12])));let y=this.Epsilon,L=[.5*(s[0]+o[0]),.5*(s[1]+o[1]),.5*(s[2]+o[2])];if(!c)if(c=Straightness(M,e[13],e[14],b)<this.res2){let e=unit(this.differential(I[12],I[8],I[4],I[0]));L=[L[0]-y*e[0],L[1]-y*e[1],L[2]-y*e[2]]}else L=A[15];let D=[.5*(l[0]+r[0]),.5*(l[1]+r[1]),.5*(l[2]+r[2])];if(!m)if(m=Straightness(x,e[1],e[2],w)<this.res2){let e=unit(this.differential(A[3],A[7],A[11],A[15]));D=[D[0]-y*e[0],D[1]-y*e[1],D[2]-y*e[2]]}else D=I[0];if(f){let e=Array(4),v=Array(4);for(let t=0;t<4;++t)e[t]=.5*(u[t]+p[t]),v[t]=.5*(g[t]+f[t]);let x=this.data.Vertex(L,P,e),w=this.data.Vertex(D,E,v);this.Render(A,t,i,x,w,r,s,L,D,h,c,!1,m,f,u,e,v),this.Render(I,w,x,a,n,D,L,o,l,!1,c,d,m,v,e,p,g)}else{let e=this.vertex(L,P),f=this.vertex(D,E);this.Render(A,t,i,e,f,r,s,L,D,h,c,!1,m),this.Render(I,f,e,a,n,D,L,o,l,!1,c,d,m)}return}if(v[1]<this.res2){let v=new Split3(x,e[4],e[8],M),T=new Split3(e[1],e[5],e[9],e[13]),S=new Split3(e[2],e[6],e[10],e[14]),R=new Split3(w,e[7],e[11],b),A=[x,e[1],e[2],w,v.m0,T.m0,S.m0,R.m0,v.m3,T.m3,S.m3,R.m3,v.m5,T.m5,S.m5,R.m5],I=[v.m5,T.m5,S.m5,R.m5,v.m4,T.m4,S.m4,R.m4,v.m2,T.m2,S.m2,R.m2,M,e[13],e[14],b],P=this.normal(A[0],A[4],A[8],A[12],A[13],A[14],A[15]);abs2(P)<=this.epsilon&&(P=this.normal(A[0],A[4],A[8],A[12],A[11],A[7],A[3]),abs2(P)<=this.epsilon&&(P=this.normal(A[3],A[2],A[1],A[0],A[13],A[14],A[15])));let E=this.normal(I[15],I[11],I[7],I!
 [3],I[2],I[1],I[0]);abs2(E)<=this.epsilon&&(E=this.normal(I[15],I[11],I[7],I[3],I[4],I[8],I[12]),abs2(E)<=this.epsilon&&(E=this.normal(I[12],I[13],I[14],I[15],I[2],I[1],I[0])));let y=this.Epsilon,L=[.5*(r[0]+s[0]),.5*(r[1]+s[1]),.5*(r[2]+s[2])];if(!h)if(h=Straightness(x,e[4],e[8],M)<this.res2){let e=unit(this.differential(I[0],I[1],I[2],I[3]));L=[L[0]-y*e[0],L[1]-y*e[1],L[2]-y*e[2]]}else L=A[12];let D=[.5*(o[0]+l[0]),.5*(o[1]+l[1]),.5*(o[2]+l[2])];if(!d)if(d=Straightness(b,e[11],e[7],w)<this.res2){let e=unit(this.differential(A[15],A[14],A[13],A[12]));D=[D[0]-y*e[0],D[1]-y*e[1],D[2]-y*e[2]]}else D=I[3];if(f){let e=Array(4),v=Array(4);for(let t=0;t<4;++t)e[t]=.5*(f[t]+u[t]),v[t]=.5*(p[t]+g[t]);let x=this.data.Vertex(L,P,e),w=this.data.Vertex(D,E,v);this.Render(A,t,x,w,n,r,L,D,l,h,!1,d,m,f,e,v,g),this.Render(I,x,i,a,w,L,s,o,D,h,c,d,!1,e,u,p,v)}else{let e=this.vertex(L,P),f=this.vertex(D,E);this.Render(A,t,e,f,n,r,L,D,l,h,!1,d,m),this.Render(I,e,i,a,f,L,s,o,D,h,c,d,!1)}return}let T=new Split3(x,e[1],e[2],w),S=new Split3(e[4],e[5],e[6],e[7]),R=new Split3(e[8],e[9],e[10],e[11]),A=new Split3(M,e[13],e[14],b),I=new Split3(x,e[4],e[8],M),P=new Split3(T.m0,S.m0,R.m0,A.m0),E=new Split3(T.m3,S.m3,R.m3,A.m3),y=new Split3(T.m5,S.m5,R.m5,A.m5),L=new Split3(T.m4,S.m4,R.m4,A.m4),D=new Split3(T.m2,S.m2,R.m2,A.m2),O=new Split3(w,e[7],e[11],b),B=[x,T.m0,T.m3,T.m5,I.m0,P.m0,E.m0,y.m0,I.m3,P.m3,E.m3,y.m3,I.m5,P.m5,E.m5,y.m5],N=[I.m5,P.m5,E.m5,y.m5,I.m4,P.m4,E.m4,y.m4,I.m2,P.m2,E.m2,y.m2,M,A.m0,A.m3,A.m5],z=[y.m5,L.m5,D.m5,O.m5,y.m4,L.m4,D.m4,O.m4,y.m2,L.m2,D.m2,O.m2,A.m5,A.m4,A.m2,b],_=[T.m5,T.m4,T.m2,w,y.m0,L.m0,D.m0,O.m0,y.m3,L.m3,D.m3,O.m3,y.m5,L.m5,D.m5,O.m5],C=B[15],V=this.normal(B[0],B[4],B[8],B[12],B[13],B[14],B[15]);abs2(V)<this.epsilon&&(V=this.normal(B[0],B[4],B[8],B[12],B[11],B[7],B[3]),abs2(V)<this.epsilon&&(V=this.normal(B[3],B[2],B[1],B[0],B[13],B[14],B[15])));let U=this.normal(N[12],N[13],N[14],N[15],N[11],N[7],N[3]);abs2(U)<this.epsilon&&(U=this.normal(N[12],N[13],N[14],N[15],N[2],N[1],N[0]),abs2(U)<this.epsilon&&(U=!
 this.normal(N[0],N[4],N[8],N[12],N[11],N[7],N[3])));let H=this.normal(z[15],z[11],z[7],z[3],z[2],z[1],z[0]);abs2(H)<this.epsilon&&(H=this.normal(z[15],z[11],z[7],z[3],z[4],z[8],z[12]),abs2(H)<this.epsilon&&(H=this.normal(z[12],z[13],z[14],z[15],z[2],z[1],z[0])));let G=this.normal(_[3],_[2],_[1],_[0],_[4],_[8],_[12]);abs2(G)<this.epsilon&&(G=this.normal(_[3],_[2],_[1],_[0],_[13],_[14],_[15]),abs2(G)<this.epsilon&&(G=this.normal(_[15],_[11],_[7],_[3],_[4],_[8],_[12])));let F=this.normal(z[3],z[2],z[1],C,z[4],z[8],z[12]),W=this.Epsilon,X=[.5*(r[0]+s[0]),.5*(r[1]+s[1]),.5*(r[2]+s[2])];if(!h)if(h=Straightness(x,e[4],e[8],M)<this.res2){let e=unit(this.differential(N[0],N[1],N[2],N[3]));X=[X[0]-W*e[0],X[1]-W*e[1],X[2]-W*e[2]]}else X=B[12];let j=[.5*(s[0]+o[0]),.5*(s[1]+o[1]),.5*(s[2]+o[2])];if(!c)if(c=Straightness(M,e[13],e[14],b)<this.res2){let e=unit(this.differential(z[12],z[8],z[4],z[0]));j=[j[0]-W*e[0],j[1]-W*e[1],j[2]-W*e[2]]}else j=N[15];let Z=[.5*(o[0]+l[0]),.5*(o[1]+l[1]),.5*(o[2]+l[2])];if(!d)if(d=Straightness(b,e[11],e[7],w)<this.res2){let e=unit(this.differential(_[15],_[14],_[13],_[12]));Z=[Z[0]-W*e[0],Z[1]-W*e[1],Z[2]-W*e[2]]}else Z=z[3];let k=[.5*(l[0]+r[0]),.5*(l[1]+r[1]),.5*(l[2]+r[2])];if(!m)if(m=Straightness(x,e[1],e[2],w)<this.res2){let e=unit(this.differential(B[3],B[7],B[11],B[15]));k=[k[0]-W*e[0],k[1]-W*e[1],k[2]-W*e[2]]}else k=_[0];if(f){let e=Array(4),v=Array(4),x=Array(4),w=Array(4),M=Array(4);for(let t=0;t<4;++t)e[t]=.5*(f[t]+u[t]),v[t]=.5*(u[t]+p[t]),x[t]=.5*(p[t]+g[t]),w[t]=.5*(g[t]+f[t]),M[t]=.5*(e[t]+x[t]);let b=this.data.Vertex(X,V,e),T=this.data.Vertex(j,U,v),S=this.data.Vertex(Z,H,x),R=this.data.Vertex(k,G,w),A=this.data.Vertex(C,F,M);this.Render(B,t,b,A,R,r,X,C,k,h,!1,!1,m,f,e,M,w),this.Render(N,b,i,T,A,X,s,j,C,h,c,!1,!1,e,u,v,M),this.Render(z,A,T,a,S,C,j,o,Z,!1,c,d,!1,M,v,p,x),this.Render(_,R,A,S,n,k,C,Z,l,!1,!1,d,m,w,M,x,g)}else{let e=this.vertex(X,V),f=this.vertex(j,U),u=this.vertex(Z,H),p=this.vertex(k,G),g=this.vertex(C,F);this.Render(B,t,e,g,p,r,X,C,k,h,!1,!1,m),this.Render(N,e,!
 i,f,g,X,s,j,C,h,c,!1,!1),this.Render(z,g,f,a,u,C,j,o,Z,!1,c,d,!1),this.Render(_,p,g,u,n,k,C,Z,l,!1,!1,d,m)}}}process3(e){if(1==wireframe)return this.curve(e,0,1,3,6),this.curve(e,6,7,8,9),void this.curve(e,9,5,2,0);let t=e[0],i=e[6],a=e[9],n=this.normal(a,e[5],e[2],t,e[1],e[3],i),r=this.normal(t,e[1],e[3],i,e[7],e[8],a),s=this.normal(i,e[7],e[8],a,e[5],e[2],t);if(this.color){let o=this.color[0],l=this.color[1],h=this.color[2],c=this.data.Vertex(t,n,o),d=this.data.Vertex(i,r,l),m=this.data.Vertex(a,s,h);this.Render3(e,c,d,m,t,i,a,!1,!1,!1,o,l,h)}else{let o=this.vertex(t,n),l=this.vertex(i,r),h=this.vertex(a,s);this.Render3(e,o,l,h,t,i,a,!1,!1,!1)}this.data.indices.length>0&&this.append()}Render3(e,t,i,a,n,r,s,o,l,h,c,d,m){if(this.Distance3(e)<this.res2)this.offscreen([n,r,s])||(0==wireframe?(this.data.indices.push(t),this.data.indices.push(i),this.data.indices.push(a)):(this.data.indices.push(t),this.data.indices.push(i),this.data.indices.push(i),this.data.indices.push(a),this.data.indices.push(a),this.data.indices.push(t)));else{if(this.offscreen(e))return;let f=e[0],u=e[1],p=e[2],g=e[3],v=e[4],x=e[5],w=e[6],M=e[7],b=e[8],T=e[9],S=[.5*(T[0]+x[0]),.5*(T[1]+x[1]),.5*(T[2]+x[2])],R=[.5*(T[0]+b[0]),.5*(T[1]+b[1]),.5*(T[2]+b[2])],A=[.5*(x[0]+p[0]),.5*(x[1]+p[1]),.5*(x[2]+p[2])],I=[.5*(b[0]+v[0]),.5*(b[1]+v[1]),.5*(b[2]+v[2])],P=[.5*(b[0]+M[0]),.5*(b[1]+M[1]),.5*(b[2]+M[2])],E=[.5*(p[0]+v[0]),.5*(p[1]+v[1]),.5*(p[2]+v[2])],y=[.5*(p[0]+f[0]),.5*(p[1]+f[1]),.5*(p[2]+f[2])],L=[.5*(v[0]+g[0]),.5*(v[1]+g[1]),.5*(v[2]+g[2])],D=[.5*(M[0]+w[0]),.5*(M[1]+w[1]),.5*(M[2]+w[2])],O=[.5*(f[0]+u[0]),.5*(f[1]+u[1]),.5*(f[2]+u[2])],B=[.5*(u[0]+g[0]),.5*(u[1]+g[1]),.5*(u[2]+g[2])],N=[.5*(g[0]+w[0]),.5*(g[1]+w[1]),.5*(g[2]+w[2])],z=[.5*(S[0]+A[0]),.5*(S[1]+A[1]),.5*(S[2]+A[2])],_=[.5*(R[0]+P[0]),.5*(R[1]+P[1]),.5*(R[2]+P[2])],C=[.5*(A[0]+y[0]),.5*(A[1]+y[1]),.5*(A[2]+y[2])],V=[.5*I[0]+.25*(v[0]+u[0]),.5*I[1]+.25*(v[1]+u[1]),.5*I[2]+.25*(v[2]+u[2])],U=[.5*(P[0]+D[0]),.5*(P[1]+D[1]),.5*(P[2]+D[2])],H=[.5*E[0]+.25*(v[0]+M[0]),.5*E[1]+.25*(!
 v[1]+M[1]),.5*E[2]+.25*(v[2]+M[2])],G=[.25*(x[0]+v[0])+.5*L[0],.25*(x[1]+v[1])+.5*L[1],.25*(x[2]+v[2])+.5*L[2]],F=[.5*(O[0]+B[0]),.5*(O[1]+B[1]),.5*(O[2]+B[2])],W=[.5*(B[0]+N[0]),.5*(B[1]+N[1]),.5*(B[2]+N[2])],X=[.5*(H[0]+F[0]),.5*(H[1]+F[1]),.5*(H[2]+F[2])],j=[.5*(H[0]+W[0]),.5*(H[1]+W[1]),.5*(H[2]+W[2])],Z=[.5*(F[0]+W[0]),.5*(F[1]+W[1]),.5*(F[2]+W[2])],k=[.5*(G[0]+U[0]),.5*(G[1]+U[1]),.5*(G[2]+U[2])],Y=[.5*(_[0]+G[0]),.5*(_[1]+G[1]),.5*(_[2]+G[2])],q=[.5*(_[0]+U[0]),.5*(_[1]+U[1]),.5*(_[2]+U[2])],$=[.5*(z[0]+V[0]),.5*(z[1]+V[1]),.5*(z[2]+V[2])],K=[.5*(C[0]+V[0]),.5*(C[1]+V[1]),.5*(C[2]+V[2])],Q=[.5*(z[0]+C[0]),.5*(z[1]+C[1]),.5*(z[2]+C[2])],J=[f,O,y,F,[.5*(E[0]+O[0]),.5*(E[1]+O[1]),.5*(E[2]+O[2])],C,Z,X,K,Q],ee=[Z,W,j,N,[.5*(L[0]+D[0]),.5*(L[1]+D[1]),.5*(L[2]+D[2])],k,w,D,U,q],te=[Q,$,z,Y,[.5*(S[0]+I[0]),.5*(S[1]+I[1]),.5*(S[2]+I[2])],S,q,_,R,T],ie=[q,Y,k,$,[.25*(A[0]+P[0]+B[0]+v[0]),.25*(A[1]+P[1]+B[1]+v[1]),.25*(A[2]+P[2]+B[2]+v[2])],j,Q,K,X,Z],ae=this.normal(Z,j,k,q,Y,$,Q),ne=this.normal(q,Y,$,Q,K,X,Z),re=this.normal(Q,K,X,Z,j,k,q),se=this.Epsilon,oe=[.5*(r[0]+s[0]),.5*(r[1]+s[1]),.5*(r[2]+s[2])];if(!o)if(o=Straightness(w,M,b,T)<this.res2){let e=unit(this.sumdifferential(ie[0],ie[2],ie[5],ie[9],ie[1],ie[3],ie[6]));oe=[oe[0]-se*e[0],oe[1]-se*e[1],oe[2]-se*e[2]]}else oe=q;let le=[.5*(s[0]+n[0]),.5*(s[1]+n[1]),.5*(s[2]+n[2])];if(!l)if(l=Straightness(f,p,x,T)<this.res2){let e=unit(this.sumdifferential(ie[6],ie[3],ie[1],ie[0],ie[7],ie[8],ie[9]));le=[le[0]-se*e[0],le[1]-se*e[1],le[2]-se*e[2]]}else le=Q;let he=[.5*(n[0]+r[0]),.5*(n[1]+r[1]),.5*(n[2]+r[2])];if(!h)if(h=Straightness(f,u,g,w)<this.res2){let e=unit(this.sumdifferential(ie[9],ie[8],ie[7],ie[6],ie[5],ie[2],ie[0]));he=[he[0]-se*e[0],he[1]-se*e[1],he[2]-se*e[2]]}else he=Z;if(c){let e=Array(4),f=Array(4),u=Array(4);for(let t=0;t<4;++t)e[t]=.5*(d[t]+m[t]),f[t]=.5*(m[t]+c[t]),u[t]=.5*(c[t]+d[t]);let p=this.data.Vertex(oe,ae,e),g=this.data.Vertex(le,ne,f),v=this.data.Vertex(he,re,u);this.Render3(J,t,v,g,n,he,le,!1,l,h,c,u,f),this.Render3(ee,v,i,p,he,r,oe,o,!1,!
 h,u,d,e),this.Render3(te,g,p,a,le,oe,s,o,l,!1,f,e,m),this.Render3(ie,p,g,v,oe,le,he,!1,!1,!1,e,f,u)}else{let e=this.vertex(oe,ae),c=this.vertex(le,ne),d=this.vertex(he,re);this.Render3(J,t,d,c,n,he,le,!1,l,h),this.Render3(ee,d,i,e,he,r,oe,o,!1,h),this.Render3(te,c,e,a,le,oe,s,o,l,!1),this.Render3(ie,e,c,d,oe,le,he,!1,!1,!1)}}}Distance(e){let t=e[0],i=e[3],a=e[12],n=e[15],r=Flatness(t,a,i,n);r=Math.max(Straightness(t,e[4],e[8],a)),r=Math.max(r,Straightness(e[1],e[5],e[9],e[13])),r=Math.max(r,Straightness(i,e[7],e[11],n)),r=Math.max(r,Straightness(e[2],e[6],e[10],e[14]));let s=Flatness(t,i,a,n);return s=Math.max(s,Straightness(t,e[1],e[2],i)),s=Math.max(s,Straightness(e[4],e[5],e[6],e[7])),s=Math.max(s,Straightness(e[8],e[9],e[10],e[11])),s=Math.max(s,Straightness(a,e[13],e[14],n)),[r,s]}Distance3(e){let t=e[0],i=e[4],a=e[6],n=e[9],r=abs2([(t[0]+a[0]+n[0])*(1/3)-i[0],(t[1]+a[1]+n[1])*(1/3)-i[1],(t[2]+a[2]+n[2])*(1/3)-i[2]]);return r=Math.max(r,Straightness(t,e[1],e[3],a)),r=Math.max(r,Straightness(t,e[2],e[5],n)),Math.max(r,Straightness(a,e[7],e[8],n))}differential(e,t,i,a){let n=[3*(t[0]-e[0]),3*(t[1]-e[1]),3*(t[2]-e[2])];return abs2(n)>this.epsilon?n:(n=bezierPP(e,t,i),abs2(n)>this.epsilon?n:bezierPPP(e,t,i,a))}sumdifferential(e,t,i,a,n,r,s){let o=this.differential(e,t,i,a),l=this.differential(e,n,r,s);return[o[0]+l[0],o[1]+l[1],o[2]+l[2]]}normal(e,t,i,a,n,r,s){let o=3*(n[0]-a[0]),l=3*(n[1]-a[1]),h=3*(n[2]-a[2]),c=3*(i[0]-a[0]),d=3*(i[1]-a[1]),m=3*(i[2]-a[2]),f=[l*m-h*d,h*c-o*m,o*d-l*c];if(abs2(f)>this.epsilon)return f;let u=[c,d,m],p=[o,l,h],g=bezierPP(a,i,t),v=bezierPP(a,n,r),x=cross(v,u),w=cross(p,g);if(f=[x[0]+w[0],x[1]+w[1],x[2]+w[2]],abs2(f)>this.epsilon)return f;let M=bezierPPP(a,i,t,e),b=bezierPPP(a,n,r,s);x=cross(p,M),w=cross(b,u);let T=cross(v,g);return f=[x[0]+w[0]+T[0],x[1]+w[1]+T[1],x[2]+w[2]+T[2]],abs2(f)>this.epsilon?f:(x=cross(b,g),w=cross(v,M),f=[x[0]+w[0],x[1]+w[1],x[2]+w[2]],abs2(f)>this.epsilon?f:cross(b,M))}}class BezierCurve extends Geometry{constructor(e,t,i,a,n){super(),this.controlpoints!
 =e,this.CenterIndex=t,this.MaterialIndex=i,this.Min=a,this.Max=n}setMaterialIndex(){this.setMaterial(material1Data,drawMaterial1)}processLine(e){let t=e[0],i=e[1];if(!this.offscreen([t,i])){let e=[0,0,1];this.data.indices.push(this.data.vertex(t,e)),this.data.indices.push(this.data.vertex(i,e)),this.append()}}process(e){if(2==e.length)return this.processLine(e);let t=e[0],i=e[1],a=e[2],n=e[3],r=this.normal(bezierP(t,i),bezierPP(t,i,a)),s=this.normal(bezierP(a,n),bezierPP(n,a,i)),o=this.data.vertex(t,r),l=this.data.vertex(n,s);this.Render(e,o,l),this.data.indices.length>0&&this.append()}append(){material1Data.append(this.data)}notRendered(){material1Data.rendered=!1}Render(e,t,i){let a=e[0],n=e[1],r=e[2],s=e[3];if(Straightness(a,n,r,s)<this.res2)this.offscreen([a,s])||(this.data.indices.push(t),this.data.indices.push(i));else{if(this.offscreen(e))return;let o=[.5*(a[0]+n[0]),.5*(a[1]+n[1]),.5*(a[2]+n[2])],l=[.5*(n[0]+r[0]),.5*(n[1]+r[1]),.5*(n[2]+r[2])],h=[.5*(r[0]+s[0]),.5*(r[1]+s[1]),.5*(r[2]+s[2])],c=[.5*(o[0]+l[0]),.5*(o[1]+l[1]),.5*(o[2]+l[2])],d=[.5*(l[0]+h[0]),.5*(l[1]+h[1]),.5*(l[2]+h[2])],m=[.5*(c[0]+d[0]),.5*(c[1]+d[1]),.5*(c[2]+d[2])],f=[a,o,c,m],u=[m,d,h,s],p=this.normal(bezierPh(a,n,r,s),bezierPPh(a,n,r,s)),g=this.data.vertex(m,p);this.Render(f,t,g),this.Render(u,g,i)}}normal(e,t){let i=dot(e,e),a=dot(e,t);return[i*t[0]-a*e[0],i*t[1]-a*e[1],i*t[2]-a*e[2]]}}class Pixel extends Geometry{constructor(e,t,i,a,n){super(),this.controlpoint=e,this.width=t,this.CenterIndex=0,this.MaterialIndex=i,this.Min=a,this.Max=n}setMaterialIndex(){this.setMaterial(material0Data,drawMaterial0)}process(e){this.data.indices.push(this.data.vertex0(this.controlpoint,this.width)),this.append()}append(){material0Data.append(this.data)}notRendered(){material0Data.rendered=!1}}class Triangles extends Geometry{constructor(e,t,i,a){super(),this.CenterIndex=e,this.MaterialIndex=t,this.Min=i,this.Max=a,this.controlpoints=Positions,this.Normals=Normals,this.Colors=Colors,this.Indices=Indices,Positions=[],Normals=[],Colors=[],Indices=[!
 ],this.transparent=Materials[this.MaterialIndex].diffuse[3]<1}setMaterialIndex(){this.transparent?this.setMaterial(transparentData,drawTransparent):this.setMaterial(triangleData,drawTriangle)}process(e){this.data.vertices=new Array(6*e.length),materialIndex=this.Colors.length>0?-1-materialIndex:1+materialIndex;for(let t=0,i=this.Indices.length;t<i;++t){let i=this.Indices[t],a=i[0],n=e[a[0]],r=e[a[1]],s=e[a[2]];if(!this.offscreen([n,r,s])){let e=i.length>1?i[1]:a;if(e&&0!=e.length||(e=a),this.Colors.length>0){let t=i.length>2?i[2]:a;t&&0!=t.length||(t=a);let o=this.Colors[t[0]],l=this.Colors[t[1]],h=this.Colors[t[2]];this.transparent|=o[3]+l[3]+h[3]<765,0==wireframe?(this.data.iVertex(a[0],n,this.Normals[e[0]],o),this.data.iVertex(a[1],r,this.Normals[e[1]],l),this.data.iVertex(a[2],s,this.Normals[e[2]],h)):(this.data.iVertex(a[0],n,this.Normals[e[0]],o),this.data.iVertex(a[1],r,this.Normals[e[1]],l),this.data.iVertex(a[1],r,this.Normals[e[1]],l),this.data.iVertex(a[2],s,this.Normals[e[2]],h),this.data.iVertex(a[2],s,this.Normals[e[2]],h),this.data.iVertex(a[0],n,this.Normals[e[0]],o))}else 0==wireframe?(this.data.iVertex(a[0],n,this.Normals[e[0]]),this.data.iVertex(a[1],r,this.Normals[e[1]]),this.data.iVertex(a[2],s,this.Normals[e[2]])):(this.data.iVertex(a[0],n,this.Normals[e[0]]),this.data.iVertex(a[1],r,this.Normals[e[1]]),this.data.iVertex(a[1],r,this.Normals[e[1]]),this.data.iVertex(a[2],s,this.Normals[e[2]]),this.data.iVertex(a[2],s,this.Normals[e[2]]),this.data.iVertex(a[0],n,this.Normals[e[0]]))}}this.data.nvertices=e.length,this.data.indices.length>0&&this.append()}append(){this.transparent?transparentData.append(this.data):triangleData.append(this.data)}notRendered(){this.transparent?transparentData.rendered=!1:triangleData.rendered=!1}}function redrawScene(){initProjection(),setProjection(),remesh=!0,drawScene()}function home(){mat4.identity(rotMat),redrawScene(),window.top.asyWebApplication&&window.top.asyWebApplication.setProjection(""),window.parent.asyProjection=!1}let positionAttribute=0,normalAtt!
 ribute=1,materialAttribute=2,colorAttribute=3,widthAttribute=4;function initShader(e=[]){let t=getShader(gl,vertex,gl.VERTEX_SHADER,e),i=getShader(gl,fragment,gl.FRAGMENT_SHADER,e),a=gl.createProgram();return gl.attachShader(a,t),gl.attachShader(a,i),gl.bindAttribLocation(a,positionAttribute,"position"),gl.bindAttribLocation(a,normalAttribute,"normal"),gl.bindAttribLocation(a,materialAttribute,"materialIndex"),gl.bindAttribLocation(a,colorAttribute,"color"),gl.bindAttribLocation(a,widthAttribute,"width"),gl.linkProgram(a),gl.getProgramParameter(a,gl.LINK_STATUS)||alert("Could not initialize shaders"),a}class Split3{constructor(e,t,i,a){this.m0=[.5*(e[0]+t[0]),.5*(e[1]+t[1]),.5*(e[2]+t[2])];let n=.5*(t[0]+i[0]),r=.5*(t[1]+i[1]),s=.5*(t[2]+i[2]);this.m2=[.5*(i[0]+a[0]),.5*(i[1]+a[1]),.5*(i[2]+a[2])],this.m3=[.5*(this.m0[0]+n),.5*(this.m0[1]+r),.5*(this.m0[2]+s)],this.m4=[.5*(n+this.m2[0]),.5*(r+this.m2[1]),.5*(s+this.m2[2])],this.m5=[.5*(this.m3[0]+this.m4[0]),.5*(this.m3[1]+this.m4[1]),.5*(this.m3[2]+this.m4[2])]}}function unit(e){let t=1/(Math.sqrt(e[0]*e[0]+e[1]*e[1]+e[2]*e[2])||1);return[e[0]*t,e[1]*t,e[2]*t]}function abs2(e){return e[0]*e[0]+e[1]*e[1]+e[2]*e[2]}function dot(e,t){return e[0]*t[0]+e[1]*t[1]+e[2]*t[2]}function cross(e,t){return[e[1]*t[2]-e[2]*t[1],e[2]*t[0]-e[0]*t[2],e[0]*t[1]-e[1]*t[0]]}function bezierP(e,t){return[t[0]-e[0],t[1]-e[1],t[2]-e[2]]}function bezierPP(e,t,i){return[3*(e[0]+i[0])-6*t[0],3*(e[1]+i[1])-6*t[1],3*(e[2]+i[2])-6*t[2]]}function bezierPPP(e,t,i,a){return[a[0]-e[0]+3*(t[0]-i[0]),a[1]-e[1]+3*(t[1]-i[1]),a[2]-e[2]+3*(t[2]-i[2])]}function bezierPh(e,t,i,a){return[i[0]+a[0]-e[0]-t[0],i[1]+a[1]-e[1]-t[1],i[2]+a[2]-e[2]-t[2]]}function bezierPPh(e,t,i,a){return[3*e[0]-5*t[0]+i[0]+a[0],3*e[1]-5*t[1]+i[1]+a[1],3*e[2]-5*t[2]+i[2]+a[2]]}function Straightness(e,t,i,a){let n=[1/3*(a[0]-e[0]),1/3*(a[1]-e[1]),1/3*(a[2]-e[2])];return Math.max(abs2([t[0]-n[0]-e[0],t[1]-n[1]-e[1],t[2]-n[2]-e[2]]),abs2([a[0]-n[0]-i[0],a[1]-n[1]-i[1],a[2]-n[2]-i[2]]))}function Flatness(e,t,i,a){let n=[t[0]-e[0],!
 t[1]-e[1],t[2]-e[2]],r=[a[0]-i[0],a[1]-i[1],a[2]-i[2]];return Math.max(abs2(cross(n,unit(r))),abs2(cross(r,unit(n))))/9}function corners(e,t){return[e,[e[0],e[1],t[2]],[e[0],t[1],e[2]],[e[0],t[1],t[2]],[t[0],e[1],e[2]],[t[0],e[1],t[2]],[t[0],t[1],e[2]],t]}function minbound(e){return[Math.min(e[0][0],e[1][0],e[2][0],e[3][0],e[4][0],e[5][0],e[6][0],e[7][0]),Math.min(e[0][1],e[1][1],e[2][1],e[3][1],e[4][1],e[5][1],e[6][1],e[7][1]),Math.min(e[0][2],e[1][2],e[2][2],e[3][2],e[4][2],e[5][2],e[6][2],e[7][2])]}function maxbound(e){return[Math.max(e[0][0],e[1][0],e[2][0],e[3][0],e[4][0],e[5][0],e[6][0],e[7][0]),Math.max(e[0][1],e[1][1],e[2][1],e[3][1],e[4][1],e[5][1],e[6][1],e[7][1]),Math.max(e[0][2],e[1][2],e[2][2],e[3][2],e[4][2],e[5][2],e[6][2],e[7][2])]}function COBTarget(e,t){mat4.fromTranslation(Temp,[center.x,center.y,center.z]),mat4.invert(cjMatInv,Temp),mat4.multiply(e,t,cjMatInv),mat4.multiply(e,Temp,e)}function setUniforms(e,t){let i=t==pixelShader;gl.useProgram(t),gl.enableVertexAttribArray(positionAttribute),i&&gl.enableVertexAttribArray(widthAttribute);let a=!i&&Lights.length>0;if(a&&gl.enableVertexAttribArray(normalAttribute),gl.enableVertexAttribArray(materialAttribute),t.projViewMatUniform=gl.getUniformLocation(t,"projViewMat"),t.viewMatUniform=gl.getUniformLocation(t,"viewMat"),t.normMatUniform=gl.getUniformLocation(t,"normMat"),t!=colorShader&&t!=transparentShader||gl.enableVertexAttribArray(colorAttribute),a)for(let e=0;e<Lights.length;++e)Lights[e].setUniform(t,e);for(let i=0;i<e.materials.length;++i)e.materials[i].setUniform(t,i);gl.uniformMatrix4fv(t.projViewMatUniform,!1,projViewMat),gl.uniformMatrix4fv(t.viewMatUniform,!1,viewMat),gl.uniformMatrix3fv(t.normMatUniform,!1,normMat)}function handleMouseDown(e){zoomEnabled||enableZoom(),mouseDownOrTouchActive=!0,lastMouseX=e.clientX,lastMouseY=e.clientY}let pinchStart,touchStartTime,pinch=!1;function pinchDistance(e){return Math.hypot(e[0].pageX-e[1].pageX,e[0].pageY-e[1].pageY)}function handleTouchStart(e){e.preventDefault(),zoomEnabled||enableZoom();!
 let t=e.targetTouches;swipe=rotate=pinch=!1,zooming||(1!=t.length||mouseDownOrTouchActive||(touchStartTime=(new Date).getTime(),touchId=t[0].identifier,lastMouseX=t[0].pageX,lastMouseY=t[0].pageY),2!=t.length||mouseDownOrTouchActive||(touchId=t[0].identifier,pinchStart=pinchDistance(t),pinch=!0))}function handleMouseUpOrTouchEnd(e){mouseDownOrTouchActive=!1}function rotateScene(e,t,i,a,n){if(e==i&&t==a)return;let[r,s]=arcball([e,-t],[i,-a]);mat4.fromRotation(Temp,2*n*ArcballFactor*r/Zoom,s),mat4.multiply(rotMat,Temp,rotMat)}function shiftScene(e,t,i,a){let n=1/Zoom;shift.x+=(i-e)*n*halfCanvasWidth,shift.y-=(a-t)*n*halfCanvasHeight}function panScene(e,t,i,a){orthographic?shiftScene(e,t,i,a):(center.x+=(i-e)*(viewParam.xmax-viewParam.xmin),center.y-=(a-t)*(viewParam.ymax-viewParam.ymin))}function updateViewMatrix(){COBTarget(viewMat,rotMat),mat4.translate(viewMat,viewMat,[center.x,center.y,0]),mat3.fromMat4(viewMat3,viewMat),mat3.invert(normMat,viewMat3),mat4.multiply(projViewMat,projMat,viewMat)}function capzoom(){let e=Math.sqrt(Number.MAX_VALUE),t=1/e;Zoom<=t&&(Zoom=t),Zoom>=e&&(Zoom=e),(1.5*Zoom<lastZoom||Zoom>1.5*lastZoom)&&(remesh=!0,lastZoom=Zoom)}function zoomImage(e){let t=zoomStep*halfCanvasHeight*e;const i=Math.log(.1*Number.MAX_VALUE)/Math.log(zoomFactor);Math.abs(t)<i&&(Zoom*=zoomFactor**t,capzoom())}function normMouse(e){let t=e[0],i=e[1],a=Math.hypot(t,i);return a>1&&(denom=1/a,t*=denom,i*=denom),[t,i,Math.sqrt(Math.max(1-i*i-t*t,0))]}function arcball(e,t){let i=normMouse(e),a=normMouse(t),n=dot(i,a);return[n>1?0:n<-1?pi:Math.acos(n),unit(cross(i,a))]}function zoomScene(e,t,i,a){zoomImage(t-a)}const DRAGMODE_ROTATE=1,DRAGMODE_SHIFT=2,DRAGMODE_ZOOM=3,DRAGMODE_PAN=4;function processDrag(e,t,i,a=1){let n;switch(i){case 1:n=rotateScene;break;case 2:n=shiftScene;break;case 3:n=zoomScene;break;case 4:n=panScene;break;default:n=(e,t,i,a)=>{}}n((lastMouseX-halfCanvasWidth)/halfCanvasWidth,(lastMouseY-halfCanvasHeight)/halfCanvasHeight,(e-halfCanvasWidth)/halfCanvasWidth,(t-halfCanvasHeight)/halfCanvasHeight!
 ,a),lastMouseX=e,lastMouseY=t,setProjection(),drawScene()}let zoomEnabled=0;function enableZoom(){zoomEnabled=1,canvas.addEventListener("wheel",handleMouseWheel,!1)}function disableZoom(){zoomEnabled=0,canvas.removeEventListener("wheel",handleMouseWheel,!1)}function Camera(){let e=Array(3),t=Array(3),i=Array(3),a=center.x,n=center.y,r=.5*(viewParam.zmin+viewParam.zmax);for(let s=0;s<3;++s){let o=0,l=0,h=0,c=4*s;for(let e=0;e<4;++e){let t=4*e,i=rotMat[t],s=rotMat[t+1],d=rotMat[t+2],m=rotMat[t+3],f=Transform[c+e];o+=f*(m-a*i-n*s-r*d),h+=f*s,l+=f*(m-a*i-n*s)}e[s]=o,t[s]=h,i[s]=l}return[e,t,i]}function projection(){if(null==Transform)return"";let e,t,i;[e,t,i]=Camera();let a=orthographic?"  orthographic(":"  perspective(",n="".padStart(a.length),r="currentprojection=\n"+a+"camera=("+e+"),\n"+n+"up=("+t+"),\n"+n+"target=("+i+"),\n"+n+"zoom="+Zoom*initialZoom/zoom0;return orthographic||(r+=",\n"+n+"angle="+2*Math.atan(Math.tan(.5*angleOfView)/Zoom)/radians),0==xshift&&0==yshift||(r+=",\n"+n+"viewportshift=("+xshift+","+yshift+")"),orthographic||(r+=",\n"+n+"autoadjust=false"),r+=");\n",window.parent.asyProjection=!0,r}function handleKey(e){if(zoomEnabled||enableZoom(),embedded&&zoomEnabled&&27==e.keyCode)return void disableZoom();let t=[];switch(e.key){case"x":t=[1,0,0];break;case"y":t=[0,1,0];break;case"z":t=[0,0,1];break;case"h":home();break;case"m":++wireframe,3==wireframe&&(wireframe=0),2!=wireframe&&(embedded||deleteShaders(),initShaders(ibl)),remesh=!0,drawScene();break;case"+":case"=":case">":expand();break;case"-":case"_":case"<":shrink();break;case"c":showCamera()}t.length>0&&(mat4.rotate(rotMat,rotMat,.1,t),updateViewMatrix(),drawScene())}function setZoom(){capzoom(),setProjection(),drawScene()}function handleMouseWheel(e){e.preventDefault(),e.deltaY<0?Zoom*=zoomFactor:Zoom/=zoomFactor,setZoom()}function handleMouseMove(e){if(!mouseDownOrTouchActive)return;let t,i=e.clientX,a=e.clientY;t=e.getModifierState("Control")?2:e.getModifierState("Shift")?3:e.getModifierState("Alt")?4:1,processDrag(i,a,t)}let zooming!
 =!1,swipe=!1,rotate=!1;function handleTouchMove(e){if(e.preventDefault(),zooming)return;let t=e.targetTouches;if(!pinch&&1==t.length&&touchId==t[0].identifier){let e=t[0].pageX,i=t[0].pageY,a=e-lastMouseX,n=i-lastMouseY,r=a*a+n*n<=shiftHoldDistance*shiftHoldDistance;if(r&&!swipe&&!rotate&&(new Date).getTime()-touchStartTime>shiftWaitTime&&(navigator.vibrate&&window.navigator.vibrate(vibrateTime),swipe=!0),swipe)processDrag(e,i,2);else if(!r){rotate=!0,processDrag(t[0].pageX,t[0].pageY,1,.5)}}if(pinch&&!swipe&&2==t.length&&touchId==t[0].identifier){let e=pinchDistance(t),i=e-pinchStart;zooming=!0,i*=zoomPinchFactor,i>zoomPinchCap&&(i=zoomPinchCap),i<-zoomPinchCap&&(i=-zoomPinchCap),zoomImage(i/size2),pinchStart=e,swipe=rotate=zooming=!1,setProjection(),drawScene()}}let pixelShader,materialShader,colorShader,transparentShader,zbuffer=[];function transformVertices(e){let t=viewMat[2],i=viewMat[6],a=viewMat[10];zbuffer.length=e.length;for(let n=0;n<e.length;++n){let r=6*n;zbuffer[n]=t*e[r]+i*e[r+1]+a*e[r+2]}}function drawMaterial0(){drawBuffer(material0Data,pixelShader),material0Data.clear()}function drawMaterial1(){drawBuffer(material1Data,materialShader),material1Data.clear()}function drawMaterial(){drawBuffer(materialData,materialShader),materialData.clear()}function drawColor(){drawBuffer(colorData,colorShader),colorData.clear()}function drawTriangle(){drawBuffer(triangleData,transparentShader),triangleData.rendered=!1,triangleData.clear()}function drawTransparent(){let e=transparentData.indices;if(wireframe>0)return drawBuffer(transparentData,transparentShader,e),void transparentData.clear();if(e.length>0){transformVertices(transparentData.vertices);let t=e.length/3,i=Array(t).fill().map((e,t)=>t);i.sort((function(t,i){let a=3*t;Ia=e[a],Ib=e[a+1],Ic=e[a+2];let n=3*i;return IA=e[n],IB=e[n+1],IC=e[n+2],zbuffer[Ia]+zbuffer[Ib]+zbuffer[Ic]<zbuffer[IA]+zbuffer[IB]+zbuffer[IC]?-1:1}));let a=Array(e.length);for(let n=0;n<t;++n){let t=3*i[n];a[3*n]=e[t],a[3*n+1]=e[t+1],a[3*n+2]=e[t+2]}gl.depthMask(!1),drawBuffer(transp!
 arentData,transparentShader,a),transparentData.rendered=!1,gl.depthMask(!0)}transparentData.clear()}function drawBuffers(){drawMaterial0(),drawMaterial1(),drawMaterial(),drawColor(),drawTriangle(),drawTransparent(),requestAnimationFrame(drawBuffers)}function drawScene(){embedded&&(offscreen.width=canvasWidth,offscreen.height=canvasHeight,setViewport()),gl.clearColor(Background[0],Background[1],Background[2],Background[3]),gl.clear(gl.COLOR_BUFFER_BIT|gl.DEPTH_BUFFER_BIT);for(let e=0;e<P.length;++e)P[e].render();drawBuffers(),embedded&&(context.clearRect(0,0,canvasWidth,canvasHeight),context.drawImage(offscreen,0,0)),0==wireframe&&(remesh=!1)}function setDimensions(e,t,i,a){let n=e/t;xshift=(i/e+viewportShift[0])*Zoom,yshift=(a/t+viewportShift[1])*Zoom;let r=1/Zoom;if(orthographic){let e=maxBound[0]-minBound[0],t=maxBound[1]-minBound[1];if(e<t*n){let e=.5*t*n*r,i=2*e*xshift,a=t*r*yshift;viewParam.xmin=-e-i,viewParam.xmax=e-i,viewParam.ymin=minBound[1]*r-a,viewParam.ymax=maxBound[1]*r-a}else{let t=.5*e*r/n,i=e*r*xshift,a=2*t*yshift;viewParam.xmin=minBound[0]*r-i,viewParam.xmax=maxBound[0]*r-i,viewParam.ymin=-t-a,viewParam.ymax=t-a}}else{let e=H*r,t=e*n,i=2*t*xshift,a=2*e*yshift;viewParam.xmin=-t-i,viewParam.xmax=t-i,viewParam.ymin=-e-a,viewParam.ymax=e-a}}function setProjection(){setDimensions(canvasWidth,canvasHeight,shift.x,shift.y),(orthographic?mat4.ortho:mat4.frustum)(projMat,viewParam.xmin,viewParam.xmax,viewParam.ymin,viewParam.ymax,-viewParam.zmax,-viewParam.zmin),updateViewMatrix(),window.top.asyWebApplication&&window.top.asyWebApplication.setProjection(projection())}function showCamera(){window.top.asyWebApplication||prompt("Ctrl+c Enter to copy currentprojection to clipboard; then append to asy file:",projection())}function initProjection(){H=-Math.tan(.5*angleOfView)*maxBound[2],center.x=center.y=0,center.z=.5*(minBound[2]+maxBound[2]),lastZoom=Zoom=zoom0,viewParam.zmin=minBound[2],viewParam.zmax=maxBound[2],shift.x=shift.y=0}function setViewport(){gl.viewportWidth=canvasWidth,gl.viewportHeight=canvasH!
 eight,gl..viewport(.5*(canvas.width-canvasWidth),.5*(canvas.height-canvasHeight),canvasWidth,canvasHeight),gl.scissor(0,0,canvas.width,canvas.height)}function setCanvas(){embedded&&(canvas.width=offscreen.width=canvasWidth,canvas.height=offscreen.height=canvasHeight),size2=Math.hypot(canvasWidth,canvasHeight),halfCanvasWidth=.5*canvas.width,halfCanvasHeight=.5*canvas.height,ArcballFactor=1+8*Math.hypot(viewportMargin[0],viewportMargin[1])/size2}function setsize(e,t){e>maxViewportWidth&&(e=maxViewportWidth),t>maxViewportHeight&&(t=maxViewportHeight),shift.x*=e/canvasWidth,shift.y*=t/canvasHeight,canvasWidth=e,canvasHeight=t,setCanvas(),setViewport(),setProjection(),remesh=!0}function resize(){if(zoom0=initialZoom,window.top.asyWebApplication&&""==window.top.asyWebApplication.getProjection()&&(window.parent.asyProjection=!1),absolute&&!embedded)canvasWidth=canvasWidth0*window.devicePixelRatio,canvasHeight=canvasHeight0*window.devicePixelRatio;else{let e=canvasWidth0/canvasHeight0;canvasWidth=Math.max(window.innerWidth-10,10),canvasHeight=Math.max(window.innerHeight-10,10),!orthographic&&!window.parent.asyProjection&&canvasWidth<canvasHeight*e&&(zoom0*=canvasWidth/(canvasHeight*e))}canvas.width=canvasWidth,canvas.height=canvasHeight;window.innerWidth,window.innerHeight;let e=1/zoom0;viewportShift[0]*=e,viewportShift[1]*=e,setsize(canvasWidth,canvasHeight),redrawScene()}function expand(){Zoom*=zoomFactor,setZoom()}function shrink(){Zoom/=zoomFactor,setZoom()}class Align{constructor(e,t){if(this.center=e,t){let e=t[0],i=t[1];this.ct=Math.cos(e),this.st=Math.sin(e),this.cp=Math.cos(i),this.sp=Math.sin(i)}}T0(e){return[e[0]+this.center[0],e[1]+this.center[1],e[2]+this.center[2]]}T(e){let t=e[0],i=e[1],a=e[2],n=t*this.ct+a*this.st;return[n*this.cp-i*this.sp+this.center[0],n*this.sp+i*this.cp+this.center[1],-t*this.st+a*this.ct+this.center[2]]}}function Tcorners(e,t,i){let a=[e(t),e([t[0],t[1],i[2]]),e([t[0],i[1],t[2]]),e([t[0],i[1],i[2]]),e([i[0],t[1],t[2]]),e([i[0],t[1],i[2]]),e([i[0],i[1],t[2]]),e(i)];return[minbound(a!
 ),maxbound(a)]}function material(e,t,i,a,n,r){Materials.push(new Material(e,t,i,a,n,r))}function patch(e,t,i,a,n,r){P.push(new BezierPatch(e,t,i,a,n,r))}function curve(e,t,i,a,n){P.push(new BezierCurve(e,t,i,a,n))}function pixel(e,t,i,a,n){P.push(new Pixel(e,t,i,a,n))}function triangles(e,t,i,a){P.push(new Triangles(e,t,i,a))}function sphere(e,t,i,n,r){let s,o,l,h,c,d,m=.524670512339254,f=.595936986722291,u=.954967051233925,p=.0820155480083437,g=.996685028842544,v=.0549670512339254,x=.998880711874577,w=.0405017186586849,M=[[[1,0,0],[1,0,m],[f,0,u],[p,0,g],[1,a,0],[1,a,m],[f,a*f,u],[p,a*p,g],[a,1,0],[a,1,m],[a*f,f,u],[a*p,p,g],[0,1,0],[0,1,m],[0,f,u],[0,p,g]],[[p,0,g],[p,a*p,g],[v,0,x],[a*p,p,g],[w,w,1],[.05*a,0,1],[0,p,g],[0,v,x],[0,.05*a,1],[0,0,1]]],b=new Align(e,r);function T(e){let t=Array(e.length);for(let i=0;i<e.length;++i){let a=e[i];t[i]=c([s*a[0],o*a[1],l*a[2]])}return t}r?(h=1,d=0,c=b.T.bind(b)):(h=-1,d=-t,c=b.T0.bind(b));let S=Tcorners(c,[-t,-t,d],[t,t,t]),R=S[0],A=S[1];for(let e=-1;e<=1;e+=2){s=e*t;for(let e=-1;e<=1;e+=2){o=e*t;for(let e=h;e<=1;e+=2){l=e*t;for(let e=0;e<2;++e)P.push(new BezierPatch(T(M[e]),i,n,R,A))}}}}let a=4/3*(Math.sqrt(2)-1);function disk(e,t,i,n,r){let s=1-2*a/3,o=[[1,0,0],[1,-a,0],[a,-1,0],[0,-1,0],[1,a,0],[s,0,0],[0,-s,0],[-a,-1,0],[a,1,0],[0,s,0],[-s,0,0],[-1,-a,0],[0,1,0],[-a,1,0],[-1,a,0],[-1,0,0]],l=new Align(e,r);let h=Tcorners(l.T.bind(l),[-t,-t,0],[t,t,0]);P.push(new BezierPatch(function(e){let i=Array(e.length);for(let a=0;a<e.length;++a){let n=e[a];i[a]=l.T([t*n[0],t*n[1],0])}return i}(o),i,n,h[0],h[1]))}function cylinder(e,t,i,n,r,s,o){let l,h,c=[[1,0,0],[1,0,1/3],[1,0,2/3],[1,0,1],[1,a,0],[1,a,1/3],[1,a,2/3],[1,a,1],[a,1,0],[a,1,1/3],[a,1,2/3],[a,1,1],[0,1,0],[0,1,1/3],[0,1,2/3],[0,1,1]],d=new Align(e,s);function m(e){let t=Array(e.length);for(let a=0;a<e.length;++a){let n=e[a];t[a]=d.T([l*n[0],h*n[1],i*n[2]])}return t}let f=Tcorners(d.T.bind(d),[-t,-t,0],[t,t,i]),u=f[0],p=f[1];for(let e=-1;e<=1;e+=2){l=e*t;for(let e=-1;e<=1;e+=2)h=e*t,P.push(new BezierPatch(m(c),n!
 ,r,u,p))}if(o){let t=d.T([0,0,i]);P.push(new BezierCurve([e,t],n,r,e,t))}}function rmf(e,t,i,a,n){class r{constructor(e,t,i){this.p=e,this.r=t,this.t=i,this.s=cross(i,t)}}let s=Number.EPSILON*Math.max(abs2(e),abs2(t),abs2(i),abs2(a));function o(n){if(1==n){let n=[a[0]-i[0],a[1]-i[1],a[2]-i[2]];return abs2(n)>s?unit(n):(n=[2*i[0]-t[0]-a[0],2*i[1]-t[1]-a[1],2*i[2]-t[2]-a[2]],abs2(n)>s?unit(n):[a[0]-e[0]+3*(t[0]-i[0]),a[1]-e[1]+3*(t[1]-i[1]),a[2]-e[2]+3*(t[2]-i[2])])}let r=[a[0]-e[0]+3*(t[0]-i[0]),a[1]-e[1]+3*(t[1]-i[1]),a[2]-e[2]+3*(t[2]-i[2])],o=[2*(e[0]+i[0])-4*t[0],2*(e[1]+i[1])-4*t[1],2*(e[2]+i[2])-4*t[2]],l=[t[0]-e[0],t[1]-e[1],t[2]-e[2]],h=n*n,c=[r[0]*h+o[0]*n+l[0],r[1]*h+o[1]*n+l[1],r[2]*h+o[2]*n+l[2]];return abs2(c)>s?unit(c):(h=2*n,c=[r[0]*h+o[0],r[1]*h+o[1],r[2]*h+o[2]],abs2(c)>s?unit(c):unit(r))}let l=Array(n.length),h=[t[0]-e[0],t[1]-e[1],t[2]-e[2]];abs2(h)<s&&(h=[e[0]-2*t[0]+i[0],e[1]-2*t[1]+i[1],e[2]-2*t[2]+i[2]],abs2(h)<s&&(h=[a[0]-e[0]+3*(t[0]-i[0]),a[1]-e[1]+3*(t[1]-i[1]),a[2]-e[2]+3*(t[2]-i[2])])),h=unit(h);let c=function(e){let t=cross(e,[0,1,0]),i=Number.EPSILON*abs2(e);return abs2(t)>i?unit(t):(t=cross(e,[0,0,1]),abs2(t)>i?unit(t):[1,0,0])}(h);l[0]=new r(e,c,h);for(let s=1;s<n.length;++s){let h=l[s-1],c=n[s],d=1-c,m=d*d,f=m*d,u=3*c;m*=u,d*=u*c;let p=c*c*c,g=[f*e[0]+m*t[0]+d*i[0]+p*a[0],f*e[1]+m*t[1]+d*i[1]+p*a[1],f*e[2]+m*t[2]+d*i[2]+p*a[2]],v=[g[0]-h.p[0],g[1]-h.p[1],g[2]-h.p[2]];if(0!=v[0]||0!=v[1]||0!=v[2]){let e=h.r,t=unit(v),i=h.t,a=dot(t,i),n=[i[0]-2*a*t[0],i[1]-2*a*t[1],i[2]-2*a*t[2]];i=o(c);let d=2*dot(t,e),m=[e[0]-d*t[0],e[1]-d*t[1],e[2]-d*t[2]],f=unit([i[0]-n[0],i[1]-n[1],i[2]-n[2]]),u=2*dot(f,m);m=[m[0]-u*f[0],m[1]-u*f[1],m[2]-u*f[2]],l[s]=new r(g,unit(m),unit(i))}else l[s]=l[s-1]}return l}function tube(e,t,i,n,r,s,o){let l=rmf(e[0],e[1],e[2],e[3],[0,1/3,2/3,1]),h=a*t,c=[[t,0],[t,h],[h,t],[0,t]];function d(t,a,o,h){let d=Array(16);for(let i=0;i<4;++i){let n=l[i],r=n.r[0],s=n.s[0],m=r*t+s*a,f=r*o+s*h;r=n.r[1],s=n.s[1];let u=r*t+s*a,p=r*o+s*h;r=n.r[2],s=n.s[2];let g=r*t+s*a,v=r*o+s*h,!
 x=e[i],w=x[0];w1=x[1],w2=x[2];for(let e=0;e<4;++e){let t=c[e],a=t[0],n=t[1];d[4*i+e]=[m*a+f*n+w,u*a+p*n+w1,g*a+v*n+w2]}}P.push(new BezierPatch(d,i,n,r,s))}d(1,0,0,1),d(0,-1,1,0),d(-1,0,0,-1),d(0,1,-1,0),o&&P.push(new BezierCurve(e,i,n,r,s))}async function getReq(e){return(await fetch(e)).arrayBuffer()}function rgb(e){return e.getBytes().filter((e,t)=>t%4!=3)}function createTexture(e,t,i=gl.RGB16F){let a=e.width(),n=e.height(),r=gl.createTexture();return gl.activeTexture(gl.TEXTURE0+t),gl.bindTexture(gl.TEXTURE_2D,r),gl.pixelStorei(gl.UNPACK_ALIGNMENT,1),gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_MIN_FILTER,gl.LINEAR),gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_MAG_FILTER,gl.LINEAR),gl.texImage2D(gl.TEXTURE_2D,0,i,a,n,0,gl.RGB,gl.FLOAT,rgb(e)),r}async function initIBL(){let e=imageURL+image+"/";function t(e){return new Promise(t=>setTimeout(t,e))}for(;!Module.EXRLoader;)await t(0);promises=[getReq(imageURL+"refl.exr").then(e=>{let t=new Module.EXRLoader(e);IBLbdrfMap=createTexture(t,0)}),getReq(e+"diffuse.exr").then(e=>{let t=new Module.EXRLoader(e);IBLDiffuseMap=createTexture(t,1)})],refl_promise=[],refl_promise.push(getReq(e+"refl0.exr"));for(let t=1;t<=roughnessStepCount;++t)refl_promise.push(getReq(e+"refl"+t+"w.exr"));finished_promise=Promise.all(refl_promise).then(e=>{let t=gl.createTexture();gl.activeTexture(gl.TEXTURE0+2),gl.pixelStorei(gl.UNPACK_ALIGNMENT,1),gl.bindTexture(gl.TEXTURE_2D,t),gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_MAX_LEVEL,e.length-1),gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_MIN_FILTER,gl.LINEAR_MIPMAP_LINEAR),gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_MAG_FILTER,gl.LINEAR),gl.texParameterf(gl.TEXTURE_2D,gl.TEXTURE_MIN_LOD,0),gl.texParameterf(gl.TEXTURE_2D,gl.TEXTURE_MAX_LOD,roughnessStepCount);for(let t=0;t<e.length;++t){let i=new Module.EXRLoader(e[t]);gl.texImage2D(gl.TEXTURE_2D,t,gl.RGB16F,i.width(),i.height(),0,gl.RGB,gl.FLOAT,rgb(i))}IBLReflMap=t}),promises.push(finished_promise),await Promise.all(promises)}function webGLStart(){canvas=document.getElementById("Asymptote"),embedded=wi!
 ndow.top.document!=document,initGL(),gl.enable(gl.BLEND),gl.blendFunc(gl.SRC_ALPHA,gl.ONE_MINUS_SRC_ALPHA),gl.enable(gl.DEPTH_TEST),gl.enable(gl.SCISSOR_TEST),canvas.onmousedown=handleMouseDown,document.onmouseup=handleMouseUpOrTouchEnd,document.onmousemove=handleMouseMove,canvas.onkeydown=handleKey,embedded||enableZoom(),canvas.addEventListener("touchstart",handleTouchStart,!1),canvas.addEventListener("touchend",handleMouseUpOrTouchEnd,!1),canvas.addEventListener("touchcancel",handleMouseUpOrTouchEnd,!1),canvas.addEventListener("touchleave",handleMouseUpOrTouchEnd,!1),canvas.addEventListener("touchmove",handleTouchMove,!1),document.addEventListener("keydown",handleKey,!1),canvasWidth0=canvasWidth,canvasHeight0=canvasHeight,mat4.identity(rotMat),0!=window.innerWidth&&0!=window.innerHeight&&resize(),window.addEventListener("resize",resize,!1),ibl&&initIBL().then(SetIBL).then(redrawScene)}

Modified: trunk/Master/texmf-dist/asymptote/x11colors.asy
===================================================================
--- trunk/Master/texmf-dist/asymptote/x11colors.asy	2022-02-27 23:39:53 UTC (rev 62264)
+++ trunk/Master/texmf-dist/asymptote/x11colors.asy	2022-02-27 23:41:11 UTC (rev 62265)
@@ -1,4 +1,4 @@
-pen rgbint(int r, int g, int b) 
+pen rgbint(int r, int g, int b)
 {
   return rgb(r/255,g/255,b/255);
 }

Modified: trunk/Master/texmf-dist/doc/asymptote/CAD.pdf
===================================================================
(Binary files differ)

Modified: trunk/Master/texmf-dist/doc/asymptote/TeXShopAndAsymptote.pdf
===================================================================
(Binary files differ)

Modified: trunk/Master/texmf-dist/doc/asymptote/asy-latex.pdf
===================================================================
(Binary files differ)

Modified: trunk/Master/texmf-dist/doc/asymptote/asyRefCard.pdf
===================================================================
(Binary files differ)

Modified: trunk/Master/texmf-dist/doc/asymptote/asymptote.pdf
===================================================================
(Binary files differ)

Modified: trunk/Master/texmf-dist/doc/asymptote/examples/1overx.asy
===================================================================
--- trunk/Master/texmf-dist/doc/asymptote/examples/1overx.asy	2022-02-27 23:39:53 UTC (rev 62264)
+++ trunk/Master/texmf-dist/doc/asymptote/examples/1overx.asy	2022-02-27 23:41:11 UTC (rev 62265)
@@ -1,16 +1,11 @@
 import graph;
 size(200,IgnoreAspect);
 
-real f(real x) {return 1/x;};
+real f(real x) {return 1/x;}
 
 bool3 branch(real x)
 {
-  static int lastsign=0;
-  if(x == 0) return false;
-  int sign=sgn(x);
-  bool b=lastsign == 0 || sign == lastsign;
-  lastsign=sign;
-  return b ? true : default;
+  return x != 0;
 }
 
 draw(graph(f,-1,1,branch));

Modified: trunk/Master/texmf-dist/doc/asymptote/examples/NURBScurve.asy
===================================================================
--- trunk/Master/texmf-dist/doc/asymptote/examples/NURBScurve.asy	2022-02-27 23:39:53 UTC (rev 62264)
+++ trunk/Master/texmf-dist/doc/asymptote/examples/NURBScurve.asy	2022-02-27 23:41:11 UTC (rev 62265)
@@ -1,3 +1,6 @@
+settings.outformat="pdf";
+settings.prc=true;
+
 import three;
 
 size(10cm);
@@ -31,4 +34,3 @@
 weights[2]=5;
 
 draw(P,knot,weights,red);
-

Modified: trunk/Master/texmf-dist/doc/asymptote/examples/NURBSsphere.asy
===================================================================
--- trunk/Master/texmf-dist/doc/asymptote/examples/NURBSsphere.asy	2022-02-27 23:39:53 UTC (rev 62264)
+++ trunk/Master/texmf-dist/doc/asymptote/examples/NURBSsphere.asy	2022-02-27 23:41:11 UTC (rev 62265)
@@ -1,3 +1,6 @@
+settings.outformat="pdf";
+settings.prc=true;
+
 import three;
 
 /* Reference:

Modified: trunk/Master/texmf-dist/doc/asymptote/examples/NURBSsurface.asy
===================================================================
--- trunk/Master/texmf-dist/doc/asymptote/examples/NURBSsurface.asy	2022-02-27 23:39:53 UTC (rev 62264)
+++ trunk/Master/texmf-dist/doc/asymptote/examples/NURBSsurface.asy	2022-02-27 23:41:11 UTC (rev 62265)
@@ -1,3 +1,6 @@
+settings.outformat="pdf";
+settings.prc=true;
+
 import three;
 
 size(10cm);
@@ -59,7 +62,7 @@
 // udegree=3, vdegree=3, nu=4, nv=4;
 real[] uknot={0,0,0,0,1,1,1,1};
 real[] vknot={0,0,0,0,1,1,1,1};
-triple[][] P=scale3(20)*octant1.P;
+triple[][] P=scale3(20)*octant1x.P;
 
 // Optional weights:
 real[][] weights=array(P.length,array(P[0].length,1.0));

Modified: trunk/Master/texmf-dist/doc/asymptote/examples/alignedaxis.asy
===================================================================
--- trunk/Master/texmf-dist/doc/asymptote/examples/alignedaxis.asy	2022-02-27 23:39:53 UTC (rev 62264)
+++ trunk/Master/texmf-dist/doc/asymptote/examples/alignedaxis.asy	2022-02-27 23:41:11 UTC (rev 62265)
@@ -91,7 +91,7 @@
 draw(pic2p,graph(pic2p,Aerr2,1e-4,1),black+1.2);
 
 ylimits(pic2p,-5,95);
-yaxis(pic2p,"phase (deg)",LeftRight,RightTicks(new real[] {0,45.1,90}));
+yaxis(pic2p,"phase (deg)",LeftRight,RightTicks(new real[] {0,50,90}));
 xaxis(pic2p,"$f/f_\mathrm{Ny}$",BottomTop,LeftTicks(N=5));
 yequals(pic2p,0,Dotted);
 yequals(pic2p,45,Dotted);

Modified: trunk/Master/texmf-dist/doc/asymptote/examples/fillcontour.asy
===================================================================
--- trunk/Master/texmf-dist/doc/asymptote/examples/fillcontour.asy	2022-02-27 23:39:53 UTC (rev 62264)
+++ trunk/Master/texmf-dist/doc/asymptote/examples/fillcontour.asy	2022-02-27 23:41:11 UTC (rev 62265)
@@ -2,28 +2,40 @@
 import palette;
 import contour;
 
-size(12cm,IgnoreAspect);
+size(10cm,10cm);
 
-pair a=(pi/2,0);
-pair b=(3pi/2,2pi);
+pair a=(0,0);
+pair b=(2pi,2pi);
 
 real f(real x, real y) {return cos(x)*sin(y);}
 
-int N=100;
+int N=200;
 int Divs=10;
+int divs=1;
+int n=Divs*divs;
 
 defaultpen(1bp);
+pen Tickpen=black;
+pen tickpen=gray+0.5*linewidth(currentpen);
+pen[] Palette=quantize(BWRainbow(),n);
 
-bounds range=bounds(-1,1);
+bounds range=image(f,Automatic,a,b,3N,Palette,n);
 
 real[] Cvals=uniform(range.min,range.max,Divs);
-guide[][] g=contour(f,a,b,Cvals,N,operator --);
+draw(contour(f,a,b,Cvals,N,operator --),Tickpen+squarecap+beveljoin);
 
-pen[] Palette=quantize(Rainbow(),Divs);
+// Major contours
+real[] Cvals=uniform(range.min,range.max,Divs);
+draw(contour(f,a,b,Cvals,N,operator --),Tickpen+squarecap+beveljoin);
 
-pen[][] interior=interior(g,extend(Palette,grey,black));
-fill(g,interior);
-draw(g);
+// Minor contours (if divs > 1)
+real[] cvals;
+for(int i=0; i < Cvals.length-1; ++i)
+  cvals.append(uniform(Cvals[i],Cvals[i+1],divs)[1:divs]);
+draw(contour(f,a,b,cvals,N,operator --),tickpen);
 
+xaxis("$x$",BottomTop,LeftTicks,above=true);
+yaxis("$y$",LeftRight,RightTicks,above=true);
+
 palette("$f(x,y)$",range,point(SE)+(0.5,0),point(NE)+(1,0),Right,Palette,
-        PaletteTicks("$%+#0.1f$",N=Divs));
+        PaletteTicks("$%+#0.1f$",N=Divs,n=divs,Tickpen,tickpen));

Added: trunk/Master/texmf-dist/doc/asymptote/examples/graphwithderiv.asy
===================================================================
--- trunk/Master/texmf-dist/doc/asymptote/examples/graphwithderiv.asy	                        (rev 0)
+++ trunk/Master/texmf-dist/doc/asymptote/examples/graphwithderiv.asy	2022-02-27 23:41:11 UTC (rev 62265)
@@ -0,0 +1,11 @@
+unitsize(2cm);
+import graph;
+pair F(real t) {
+  return (1.3*t,-4.5*t^2+3.0*t+1.0);
+}
+pair Fprime(real t) {
+  return (1.3,-9.0*t+3.0);
+}
+path g=graphwithderiv(F,Fprime,0,0.9,4);
+dot(g,red);
+draw(g,arrow=Arrow(TeXHead));

Modified: trunk/Master/texmf-dist/doc/asymptote/examples/imagecontour.asy
===================================================================
--- trunk/Master/texmf-dist/doc/asymptote/examples/imagecontour.asy	2022-02-27 23:39:53 UTC (rev 62264)
+++ trunk/Master/texmf-dist/doc/asymptote/examples/imagecontour.asy	2022-02-27 23:41:11 UTC (rev 62265)
@@ -2,7 +2,7 @@
 import palette;
 import contour;
 
-size(10cm,10cm,IgnoreAspect);
+size(10cm,10cm);
 
 pair a=(0,0);
 pair b=(2pi,2pi);
@@ -11,7 +11,7 @@
 
 int N=200;
 int Divs=10;
-int divs=2;
+int divs=1;
 
 defaultpen(1bp);
 pen Tickpen=black;
@@ -21,18 +21,17 @@
 bounds range=image(f,Automatic,a,b,N,Palette);
 
 // Major contours
-
 real[] Cvals=uniform(range.min,range.max,Divs);
-draw(contour(f,a,b,Cvals,N,operator --),Tickpen);
+draw(contour(f,a,b,Cvals,N,operator --),Tickpen+squarecap+beveljoin);
 
-// Minor contours
+// Minor contours (if divs > 1)
 real[] cvals;
 for(int i=0; i < Cvals.length-1; ++i)
   cvals.append(uniform(Cvals[i],Cvals[i+1],divs)[1:divs]);
-draw(contour(f,a,b,cvals,N,operator --),tickpen);
+draw(contour(f,a,b,cvals,N,operator --),tickpen+squarecap+beveljoin);
 
 xaxis("$x$",BottomTop,LeftTicks,above=true);
 yaxis("$y$",LeftRight,RightTicks,above=true);
 
-palette("$f(x,y)$",range,point(NW)+(0,0.5),point(NE)+(0,1),Top,Palette,
-        PaletteTicks(N=Divs,n=divs,Tickpen,tickpen));
+palette("$f(x,y)$",range,point(SE)+(0.5,0),point(NE)+(1,0),Right,Palette,
+        PaletteTicks("$%+#0.1f$",N=Divs,n=divs,Tickpen,tickpen));

Modified: trunk/Master/texmf-dist/doc/asymptote/examples/interpolate1.asy
===================================================================
--- trunk/Master/texmf-dist/doc/asymptote/examples/interpolate1.asy	2022-02-27 23:39:53 UTC (rev 62264)
+++ trunk/Master/texmf-dist/doc/asymptote/examples/interpolate1.asy	2022-02-27 23:41:11 UTC (rev 62265)
@@ -1,5 +1,5 @@
 // Lagrange and Hermite interpolation in Asymptote
-// Author: Olivier Guib\xE9
+// Author: Olivier Guibé
 
 import interpolate;
 import graph;

Modified: trunk/Master/texmf-dist/doc/asymptote/examples/latexusage.tex
===================================================================
--- trunk/Master/texmf-dist/doc/asymptote/examples/latexusage.tex	2022-02-27 23:39:53 UTC (rev 62264)
+++ trunk/Master/texmf-dist/doc/asymptote/examples/latexusage.tex	2022-02-27 23:41:11 UTC (rev 62265)
@@ -21,6 +21,7 @@
 
 \begin{asydef}
 // Global Asymptote definitions can be put here.
+settings.prc=true;
 import three;
 usepackage("bm");
 texpreamble("\def\V#1{\bm{#1}}");

Modified: trunk/Master/texmf-dist/doc/asymptote/examples/layers.asy
===================================================================
--- trunk/Master/texmf-dist/doc/asymptote/examples/layers.asy	2022-02-27 23:39:53 UTC (rev 62264)
+++ trunk/Master/texmf-dist/doc/asymptote/examples/layers.asy	2022-02-27 23:41:11 UTC (rev 62265)
@@ -1,4 +1,4 @@
-usepackage("ocg");
+usepackage("ocgx2");
 settings.tex="pdflatex";
 
 size(0,150);

Modified: trunk/Master/texmf-dist/doc/asymptote/examples/legend.asy
===================================================================
--- trunk/Master/texmf-dist/doc/asymptote/examples/legend.asy	2022-02-27 23:39:53 UTC (rev 62264)
+++ trunk/Master/texmf-dist/doc/asymptote/examples/legend.asy	2022-02-27 23:41:11 UTC (rev 62265)
@@ -4,7 +4,7 @@
 typedef real realfcn(real);
 realfcn F(real p) {
   return new real(real x) {return sin(p*x);};
-};
+}
 
 for(int i=1; i < 5; ++i)
   draw(graph(F(i*pi),0,1),Pen(i),

Modified: trunk/Master/texmf-dist/doc/asymptote/examples/markregular.asy
===================================================================
--- trunk/Master/texmf-dist/doc/asymptote/examples/markregular.asy	2022-02-27 23:39:53 UTC (rev 62264)
+++ trunk/Master/texmf-dist/doc/asymptote/examples/markregular.asy	2022-02-27 23:41:11 UTC (rev 62265)
@@ -7,11 +7,11 @@
 
 real f(real x) {return x^2;}
 
-marker cross=marker(scale(4)*rotate(45)*cross(4),
+marker mark=marker(scale(4)*plus,
                     markuniform(new pair(real t) {return Scale((t,f(t)));},
                                 xmin,xmax,round(2*(xmax-xmin))),1bp+red);
 
-draw(graph(f,xmin,xmax,n=400),linewidth(1bp),cross);
+draw(graph(f,xmin,xmax,n=400),linewidth(1bp),mark);
 
 ylimits(-2.5,10,Crop);
 

Modified: trunk/Master/texmf-dist/doc/asymptote/examples/orthocenter.asy
===================================================================
--- trunk/Master/texmf-dist/doc/asymptote/examples/orthocenter.asy	2022-02-27 23:39:53 UTC (rev 62264)
+++ trunk/Master/texmf-dist/doc/asymptote/examples/orthocenter.asy	2022-02-27 23:41:11 UTC (rev 62265)
@@ -2,9 +2,8 @@
 import math;
 
 size(7cm,0);
+settings.tex="pdflatex";
 
-if(!settings.xasy && settings.outformat != "svg") settings.tex="pdflatex";
-
 real theta=degrees(asin(0.5/sqrt(7)));
 
 pair B=(0,sqrt(7));

Modified: trunk/Master/texmf-dist/doc/asymptote/examples/secondaryaxis.asy
===================================================================
--- trunk/Master/texmf-dist/doc/asymptote/examples/secondaryaxis.asy	2022-02-27 23:39:53 UTC (rev 62264)
+++ trunk/Master/texmf-dist/doc/asymptote/examples/secondaryaxis.asy	2022-02-27 23:41:11 UTC (rev 62265)
@@ -11,7 +11,7 @@
 real[][] a=in;
 a=transpose(a);
 real[] t=a[0], susceptible=a[1], infectious=a[2], dead=a[3], larvae=a[4];
-real[] susceptibleM=a[5], exposed=a[6],infectiousM=a[7];
+real[] susceptibleM=a[5], exposed=a[6], infectiousM=a[7];
 
 scale(true);
 
@@ -29,4 +29,3 @@
 
 add(secondary);
 label(shift(5mm*N)*"Proportion of crows",point(NW),E);
-

Modified: trunk/Master/texmf-dist/doc/asymptote/examples/spectrum.asy
===================================================================
--- trunk/Master/texmf-dist/doc/asymptote/examples/spectrum.asy	2022-02-27 23:39:53 UTC (rev 62264)
+++ trunk/Master/texmf-dist/doc/asymptote/examples/spectrum.asy	2022-02-27 23:41:11 UTC (rev 62265)
@@ -1,5 +1,5 @@
 import graph;
-usepackage("ocg");
+usepackage("ocgx2");
 settings.tex="pdflatex";
 
 // Dan Bruton algorithm

Modified: trunk/Master/texmf-dist/doc/asymptote/examples/strokepath.asy
===================================================================
--- trunk/Master/texmf-dist/doc/asymptote/examples/strokepath.asy	2022-02-27 23:39:53 UTC (rev 62264)
+++ trunk/Master/texmf-dist/doc/asymptote/examples/strokepath.asy	2022-02-27 23:41:11 UTC (rev 62265)
@@ -5,7 +5,6 @@
 // Equivalent to draw(f,g,p):
 fill(f,strokepath(g,p),red);
 shipout("strokepathframe",f);
-shipped=false;
 
 size(400);
 

Modified: trunk/Master/texmf-dist/doc/asymptote/examples/teapot.asy
===================================================================
--- trunk/Master/texmf-dist/doc/asymptote/examples/teapot.asy	2022-02-27 23:39:53 UTC (rev 62264)
+++ trunk/Master/texmf-dist/doc/asymptote/examples/teapot.asy	2022-02-27 23:41:11 UTC (rev 62265)
@@ -1,204 +1,232 @@
 import three;
-import settings;
 size(20cm);
 
 currentprojection=perspective(250,-250,250);
 currentlight=Viewport;
 
-triple[][][] Q=
+triple[][][] Q={
   {
-   {
     {(39.68504,0,68.0315),(37.91339,0,71.75197),(40.74803,0,71.75197),(42.51969,0,68.0315)},
     {(39.68504,-22.22362,68.0315),(37.91339,-21.2315,71.75197),(40.74803,-22.8189,71.75197),(42.51969,-23.81102,68.0315)},
     {(22.22362,-39.68504,68.0315),(21.2315,-37.91339,71.75197),(22.8189,-40.74803,71.75197),(23.81102,-42.51969,68.0315)},
     {(0,-39.68504,68.0315),(0,-37.91339,71.75197),(0,-40.74803,71.75197),(0,-42.51969,68.0315)}
-   },
-   {
+  },
+  {
     {(0,-39.68504,68.0315),(0,-37.91339,71.75197),(0,-40.74803,71.75197),(0,-42.51969,68.0315)},
     {(-22.22362,-39.68504,68.0315),(-21.2315,-37.91339,71.75197),(-22.8189,-40.74803,71.75197),(-23.81102,-42.51969,68.0315)},
     {(-39.68504,-22.22362,68.0315),(-37.91339,-21.2315,71.75197),(-40.74803,-22.8189,71.75197),(-42.51969,-23.81102,68.0315)},
     {(-39.68504,0,68.0315),(-37.91339,0,71.75197),(-40.74803,0,71.75197),(-42.51969,0,68.0315)}
-   },
-   {
+  },
+  {
     {(-39.68504,0,68.0315),(-37.91339,0,71.75197),(-40.74803,0,71.75197),(-42.51969,0,68.0315)},
     {(-39.68504,22.22362,68.0315),(-37.91339,21.2315,71.75197),(-40.74803,22.8189,71.75197),(-42.51969,23.81102,68.0315)},
     {(-22.22362,39.68504,68.0315),(-21.2315,37.91339,71.75197),(-22.8189,40.74803,71.75197),(-23.81102,42.51969,68.0315)},
     {(0,39.68504,68.0315),(0,37.91339,71.75197),(0,40.74803,71.75197),(0,42.51969,68.0315)}
-   },
-   {
+  },
+  {
     {(0,39.68504,68.0315),(0,37.91339,71.75197),(0,40.74803,71.75197),(0,42.51969,68.0315)},
     {(22.22362,39.68504,68.0315),(21.2315,37.91339,71.75197),(22.8189,40.74803,71.75197),(23.81102,42.51969,68.0315)},
     {(39.68504,22.22362,68.0315),(37.91339,21.2315,71.75197),(40.74803,22.8189,71.75197),(42.51969,23.81102,68.0315)},
     {(39.68504,0,68.0315),(37.91339,0,71.75197),(40.74803,0,71.75197),(42.51969,0,68.0315)}
-   },
-   {
+  },
+  {
     {(42.51969,0,68.0315),(49.60629,0,53.1496),(56.69291,0,38.26771),(56.69291,0,25.51181)},
     {(42.51969,-23.81102,68.0315),(49.60629,-27.77952,53.1496),(56.69291,-31.74803,38.26771),(56.69291,-31.74803,25.51181)},
     {(23.81102,-42.51969,68.0315),(27.77952,-49.60629,53.1496),(31.74803,-56.69291,38.26771),(31.74803,-56.69291,25.51181)},
     {(0,-42.51969,68.0315),(0,-49.60629,53.1496),(0,-56.69291,38.26771),(0,-56.69291,25.51181)}
-   },
-   {
+  },
+  {
     {(0,-42.51969,68.0315),(0,-49.60629,53.1496),(0,-56.69291,38.26771),(0,-56.69291,25.51181)},
     {(-23.81102,-42.51969,68.0315),(-27.77952,-49.60629,53.1496),(-31.74803,-56.69291,38.26771),(-31.74803,-56.69291,25.51181)},
     {(-42.51969,-23.81102,68.0315),(-49.60629,-27.77952,53.1496),(-56.69291,-31.74803,38.26771),(-56.69291,-31.74803,25.51181)},
     {(-42.51969,0,68.0315),(-49.60629,0,53.1496),(-56.69291,0,38.26771),(-56.69291,0,25.51181)}
-   },
-   {
+  },
+  {
     {(-42.51969,0,68.0315),(-49.60629,0,53.1496),(-56.69291,0,38.26771),(-56.69291,0,25.51181)},
     {(-42.51969,23.81102,68.0315),(-49.60629,27.77952,53.1496),(-56.69291,31.74803,38.26771),(-56.69291,31.74803,25.51181)},
     {(-23.81102,42.51969,68.0315),(-27.77952,49.60629,53.1496),(-31.74803,56.69291,38.26771),(-31.74803,56.69291,25.51181)},
     {(0,42.51969,68.0315),(0,49.60629,53.1496),(0,56.69291,38.26771),(0,56.69291,25.51181)}
-   },
-   {
+  },
+  {
     {(0,42.51969,68.0315),(0,49.60629,53.1496),(0,56.69291,38.26771),(0,56.69291,25.51181)},
     {(23.81102,42.51969,68.0315),(27.77952,49.60629,53.1496),(31.74803,56.69291,38.26771),(31.74803,56.69291,25.51181)},
     {(42.51969,23.81102,68.0315),(49.60629,27.77952,53.1496),(56.69291,31.74803,38.26771),(56.69291,31.74803,25.51181)},
     {(42.51969,0,68.0315),(49.60629,0,53.1496),(56.69291,0,38.26771),(56.69291,0,25.51181)}
-   },
-   {
+  },
+  {
     {(56.69291,0,25.51181),(56.69291,0,12.7559),(42.51969,0,6.377957),(42.51969,0,4.251961)},
     {(56.69291,-31.74803,25.51181),(56.69291,-31.74803,12.7559),(42.51969,-23.81102,6.377957),(42.51969,-23.81102,4.251961)},
     {(31.74803,-56.69291,25.51181),(31.74803,-56.69291,12.7559),(23.81102,-42.51969,6.377957),(23.81102,-42.51969,4.251961)},
     {(0,-56.69291,25.51181),(0,-56.69291,12.7559),(0,-42.51969,6.377957),(0,-42.51969,4.251961)}
-   },
-   {
+  },
+  {
     {(0,-56.69291,25.51181),(0,-56.69291,12.7559),(0,-42.51969,6.377957),(0,-42.51969,4.251961)},
     {(-31.74803,-56.69291,25.51181),(-31.74803,-56.69291,12.7559),(-23.81102,-42.51969,6.377957),(-23.81102,-42.51969,4.251961)},
     {(-56.69291,-31.74803,25.51181),(-56.69291,-31.74803,12.7559),(-42.51969,-23.81102,6.377957),(-42.51969,-23.81102,4.251961)},
     {(-56.69291,0,25.51181),(-56.69291,0,12.7559),(-42.51969,0,6.377957),(-42.51969,0,4.251961)}
-   },
-   {
+  },
+  {
     {(-56.69291,0,25.51181),(-56.69291,0,12.7559),(-42.51969,0,6.377957),(-42.51969,0,4.251961)},
     {(-56.69291,31.74803,25.51181),(-56.69291,31.74803,12.7559),(-42.51969,23.81102,6.377957),(-42.51969,23.81102,4.251961)},
     {(-31.74803,56.69291,25.51181),(-31.74803,56.69291,12.7559),(-23.81102,42.51969,6.377957),(-23.81102,42.51969,4.251961)},
     {(0,56.69291,25.51181),(0,56.69291,12.7559),(0,42.51969,6.377957),(0,42.51969,4.251961)}
-   },
-   {
+  },
+  {
     {(0,56.69291,25.51181),(0,56.69291,12.7559),(0,42.51969,6.377957),(0,42.51969,4.251961)},
     {(31.74803,56.69291,25.51181),(31.74803,56.69291,12.7559),(23.81102,42.51969,6.377957),(23.81102,42.51969,4.251961)},
     {(56.69291,31.74803,25.51181),(56.69291,31.74803,12.7559),(42.51969,23.81102,6.377957),(42.51969,23.81102,4.251961)},
     {(56.69291,0,25.51181),(56.69291,0,12.7559),(42.51969,0,6.377957),(42.51969,0,4.251961)}
-   },
-   {
+  },
+  {
     {(-45.35433,0,57.40157),(-65.19685,0,57.40157),(-76.53543,0,57.40157),(-76.53543,0,51.02362)},
     {(-45.35433,-8.503932,57.40157),(-65.19685,-8.503932,57.40157),(-76.53543,-8.503932,57.40157),(-76.53543,-8.503932,51.02362)},
     {(-42.51969,-8.503932,63.77952),(-70.86614,-8.503932,63.77952),(-85.03937,-8.503932,63.77952),(-85.03937,-8.503932,51.02362)},
     {(-42.51969,0,63.77952),(-70.86614,0,63.77952),(-85.03937,0,63.77952),(-85.03937,0,51.02362)}
-   },
-   {
+  },
+  {
     {(-42.51969,0,63.77952),(-70.86614,0,63.77952),(-85.03937,0,63.77952),(-85.03937,0,51.02362)},
     {(-42.51969,8.503932,63.77952),(-70.86614,8.503932,63.77952),(-85.03937,8.503932,63.77952),(-85.03937,8.503932,51.02362)},
     {(-45.35433,8.503932,57.40157),(-65.19685,8.503932,57.40157),(-76.53543,8.503932,57.40157),(-76.53543,8.503932,51.02362)},
     {(-45.35433,0,57.40157),(-65.19685,0,57.40157),(-76.53543,0,57.40157),(-76.53543,0,51.02362)}
-   },
-   {
+  },
+  {
     {(-76.53543,0,51.02362),(-76.53543,0,44.64566),(-70.86614,0,31.88976),(-56.69291,0,25.51181)},
     {(-76.53543,-8.503932,51.02362),(-76.53543,-8.503932,44.64566),(-70.86614,-8.503932,31.88976),(-56.69291,-8.503932,25.51181)},
     {(-85.03937,-8.503932,51.02362),(-85.03937,-8.503932,38.26771),(-75.11811,-8.503932,26.5748),(-53.85826,-8.503932,17.00787)},
     {(-85.03937,0,51.02362),(-85.03937,0,38.26771),(-75.11811,0,26.5748),(-53.85826,0,17.00787)}
-   },
-   {
+  },
+  {
     {(-85.03937,0,51.02362),(-85.03937,0,38.26771),(-75.11811,0,26.5748),(-53.85826,0,17.00787)},
     {(-85.03937,8.503932,51.02362),(-85.03937,8.503932,38.26771),(-75.11811,8.503932,26.5748),(-53.85826,8.503932,17.00787)},
     {(-76.53543,8.503932,51.02362),(-76.53543,8.503932,44.64566),(-70.86614,8.503932,31.88976),(-56.69291,8.503932,25.51181)},
     {(-76.53543,0,51.02362),(-76.53543,0,44.64566),(-70.86614,0,31.88976),(-56.69291,0,25.51181)}
-   },
-   {
+  },
+  {
     {(48.18897,0,40.3937),(73.70078,0,40.3937),(65.19685,0,59.52755),(76.53543,0,68.0315)},
     {(48.18897,-18.70866,40.3937),(73.70078,-18.70866,40.3937),(65.19685,-7.086619,59.52755),(76.53543,-7.086619,68.0315)},
     {(48.18897,-18.70866,17.00787),(87.87401,-18.70866,23.38582),(68.0315,-7.086619,57.40157),(93.5433,-7.086619,68.0315)},
     {(48.18897,0,17.00787),(87.87401,0,23.38582),(68.0315,0,57.40157),(93.5433,0,68.0315)}
-   },
-   {
+  },
+  {
     {(48.18897,0,17.00787),(87.87401,0,23.38582),(68.0315,0,57.40157),(93.5433,0,68.0315)},
     {(48.18897,18.70866,17.00787),(87.87401,18.70866,23.38582),(68.0315,7.086619,57.40157),(93.5433,7.086619,68.0315)},
     {(48.18897,18.70866,40.3937),(73.70078,18.70866,40.3937),(65.19685,7.086619,59.52755),(76.53543,7.086619,68.0315)},
     {(48.18897,0,40.3937),(73.70078,0,40.3937),(65.19685,0,59.52755),(76.53543,0,68.0315)}
-   },
-   {
+  },
+  {
     {(76.53543,0,68.0315),(79.37007,0,70.15748),(82.20472,0,70.15748),(79.37007,0,68.0315)},
     {(76.53543,-7.086619,68.0315),(79.37007,-7.086619,70.15748),(82.20472,-4.251961,70.15748),(79.37007,-4.251961,68.0315)},
     {(93.5433,-7.086619,68.0315),(99.92125,-7.086619,70.68897),(97.79527,-4.251961,71.22047),(90.70866,-4.251961,68.0315)},
     {(93.5433,0,68.0315),(99.92125,0,70.68897),(97.79527,0,71.22047),(90.70866,0,68.0315)}
-   },
-   {
+  },
+  {
     {(93.5433,0,68.0315),(99.92125,0,70.68897),(97.79527,0,71.22047),(90.70866,0,68.0315)},
     {(93.5433,7.086619,68.0315),(99.92125,7.086619,70.68897),(97.79527,4.251961,71.22047),(90.70866,4.251961,68.0315)},
     {(76.53543,7.086619,68.0315),(79.37007,7.086619,70.15748),(82.20472,4.251961,70.15748),(79.37007,4.251961,68.0315)},
     {(76.53543,0,68.0315),(79.37007,0,70.15748),(82.20472,0,70.15748),(79.37007,0,68.0315)}
-   },
-   {
+  },
+  {
+    {(5.669294,0,76.53543),(11.33858,0,72.28346),(36.85039,0,72.28346),(36.85039,0,68.0315)},
+    {(5.669294,-3.174809,76.53543),(11.33858,-6.349609,72.28346),(36.85039,-20.63622,72.28346),(36.85039,-20.63622,68.0315)},
+    {(3.174809,-5.669294,76.53543),(6.349609,-11.33858,72.28346),(20.63622,-36.85039,72.28346),(20.63622,-36.85039,68.0315)},
+    {(0,-5.669294,76.53543),(0,-11.33858,72.28346),(0,-36.85039,72.28346),(0,-36.85039,68.0315)}
+  },
+  {
+    {(0,-5.669294,76.53543),(0,-11.33858,72.28346),(0,-36.85039,72.28346),(0,-36.85039,68.0315)},
+    {(-3.174809,-5.669294,76.53543),(-6.349609,-11.33858,72.28346),(-20.63622,-36.85039,72.28346),(-20.63622,-36.85039,68.0315)},
+    {(-5.669294,-3.174809,76.53543),(-11.33858,-6.349609,72.28346),(-36.85039,-20.63622,72.28346),(-36.85039,-20.63622,68.0315)},
+    {(-5.669294,0,76.53543),(-11.33858,0,72.28346),(-36.85039,0,72.28346),(-36.85039,0,68.0315)},
+  },
+  {
+    {(-5.669294,0,76.53543),(-11.33858,0,72.28346),(-36.85039,0,72.28346),(-36.85039,0,68.0315)},
+    {(-5.669294,3.174809,76.53543),(-11.33858,6.349609,72.28346),(-36.85039,20.63622,72.28346),(-36.85039,20.63622,68.0315)},
+    {(-3.174809,5.669294,76.53543),(-6.349609,11.33858,72.28346),(-20.63622,36.85039,72.28346),(-20.63622,36.85039,68.0315)},
+    {(0,5.669294,76.53543),(0,11.33858,72.28346),(0,36.85039,72.28346),(0,36.85039,68.0315)}
+  },
+  {
+    {(0,5.669294,76.53543),(0,11.33858,72.28346),(0,36.85039,72.28346),(0,36.85039,68.0315)},
+    {(3.174809,5.669294,76.53543),(6.349609,11.33858,72.28346),(20.63622,36.85039,72.28346),(20.63622,36.85039,68.0315)},
+    {(5.669294,3.174809,76.53543),(11.33858,6.349609,72.28346),(36.85039,20.63622,72.28346),(36.85039,20.63622,68.0315)},
+    {(5.669294,0,76.53543),(11.33858,0,72.28346),(36.85039,0,72.28346),(36.85039,0,68.0315)}
+  }
+};
+
+triple[][][] Q0={
+  {
     {(0,0,89.29133),(22.67716,0,89.29133),(0,0,80.7874),(5.669294,0,76.53543)},
     {(0,0,89.29133),(22.67716,-12.7559,89.29133),(0,0,80.7874),(5.669294,-3.174809,76.53543)},
     {(0,0,89.29133),(12.7559,-22.67716,89.29133),(0,0,80.7874),(3.174809,-5.669294,76.53543)},
     {(0,0,89.29133),(0,-22.67716,89.29133),(0,0,80.7874),(0,-5.669294,76.53543)}
-   },
-   {
+  },
+  {
     {(0,0,89.29133),(0,-22.67716,89.29133),(0,0,80.7874),(0,-5.669294,76.53543)},
     {(0,0,89.29133),(-12.7559,-22.67716,89.29133),(0,0,80.7874),(-3.174809,-5.669294,76.53543)},
     {(0,0,89.29133),(-22.67716,-12.7559,89.29133),(0,0,80.7874),(-5.669294,-3.174809,76.53543)},
     {(0,0,89.29133),(-22.67716,0,89.29133),(0,0,80.7874),(-5.669294,0,76.53543)}
-   },
-   {
+  },
+  {
     {(0,0,89.29133),(-22.67716,0,89.29133),(0,0,80.7874),(-5.669294,0,76.53543)},
     {(0,0,89.29133),(-22.67716,12.7559,89.29133),(0,0,80.7874),(-5.669294,3.174809,76.53543)},
     {(0,0,89.29133),(-12.7559,22.67716,89.29133),(0,0,80.7874),(-3.174809,5.669294,76.53543)},
     {(0,0,89.29133),(0,22.67716,89.29133),(0,0,80.7874),(0,5.669294,76.53543)}
-   },
-   {
+  },
+  {
     {(0,0,89.29133),(0,22.67716,89.29133),(0,0,80.7874),(0,5.669294,76.53543)},
     {(0,0,89.29133),(12.7559,22.67716,89.29133),(0,0,80.7874),(3.174809,5.669294,76.53543)},
     {(0,0,89.29133),(22.67716,12.7559,89.29133),(0,0,80.7874),(5.669294,3.174809,76.53543)},
     {(0,0,89.29133),(22.67716,0,89.29133),(0,0,80.7874),(5.669294,0,76.53543)}
-   },
-   {
-    {(5.669294,0,76.53543),(11.33858,0,72.28346),(36.85039,0,72.28346),(36.85039,0,68.0315)},
-    {(5.669294,-3.174809,76.53543),(11.33858,-6.349609,72.28346),(36.85039,-20.63622,72.28346),(36.85039,-20.63622,68.0315)},
-    {(3.174809,-5.669294,76.53543),(6.349609,-11.33858,72.28346),(20.63622,-36.85039,72.28346),(20.63622,-36.85039,68.0315)},
-    {(0,-5.669294,76.53543),(0,-11.33858,72.28346),(0,-36.85039,72.28346),(0,-36.85039,68.0315)}
-   },
-   {
-    {(0,-5.669294,76.53543),(0,-11.33858,72.28346),(0,-36.85039,72.28346),(0,-36.85039,68.0315)},
-    {(-3.174809,-5.669294,76.53543),(-6.349609,-11.33858,72.28346),(-20.63622,-36.85039,72.28346),(-20.63622,-36.85039,68.0315)},
-    {(-5.669294,-3.174809,76.53543),(-11.33858,-6.349609,72.28346),(-36.85039,-20.63622,72.28346),(-36.85039,-20.63622,68.0315)},
-    {(-5.669294,0,76.53543),(-11.33858,0,72.28346),(-36.85039,0,72.28346),(-36.85039,0,68.0315)},
-   },
-   {
-    {(-5.669294,0,76.53543),(-11.33858,0,72.28346),(-36.85039,0,72.28346),(-36.85039,0,68.0315)},
-    {(-5.669294,3.174809,76.53543),(-11.33858,6.349609,72.28346),(-36.85039,20.63622,72.28346),(-36.85039,20.63622,68.0315)},
-    {(-3.174809,5.669294,76.53543),(-6.349609,11.33858,72.28346),(-20.63622,36.85039,72.28346),(-20.63622,36.85039,68.0315)},
-    {(0,5.669294,76.53543),(0,11.33858,72.28346),(0,36.85039,72.28346),(0,36.85039,68.0315)}
-   },
-   {
-    {(0,5.669294,76.53543),(0,11.33858,72.28346),(0,36.85039,72.28346),(0,36.85039,68.0315)},
-    {(3.174809,5.669294,76.53543),(6.349609,11.33858,72.28346),(20.63622,36.85039,72.28346),(20.63622,36.85039,68.0315)},
-    {(5.669294,3.174809,76.53543),(11.33858,6.349609,72.28346),(36.85039,20.63622,72.28346),(36.85039,20.63622,68.0315)},
-    {(5.669294,0,76.53543),(11.33858,0,72.28346),(36.85039,0,72.28346),(36.85039,0,68.0315)},
-   },
-   {
+  },
+  {
     {(0,0,0),(40.3937,0,0),(42.51969,0,2.12598),(42.51969,0,4.251961)},
     {(0,0,0),(40.3937,22.62047,0),(42.51969,23.81102,2.12598),(42.51969,23.81102,4.251961)},
     {(0,0,0),(22.62047,40.3937,0),(23.81102,42.51969,2.12598),(23.81102,42.51969,4.251961)},
     {(0,0,0),(0,40.3937,0),(0,42.51969,2.12598),(0,42.51969,4.251961)}
-   },
-   {
+  },
+  {
     {(0,0,0),(0,40.3937,0),(0,42.51969,2.12598),(0,42.51969,4.251961)},
     {(0,0,0),(-22.62047,40.3937,0),(-23.81102,42.51969,2.12598),(-23.81102,42.51969,4.251961)},
     {(0,0,0),(-40.3937,22.62047,0),(-42.51969,23.81102,2.12598),(-42.51969,23.81102,4.251961)},
     {(0,0,0),(-40.3937,0,0),(-42.51969,0,2.12598),(-42.51969,0,4.251961)}
-   },
-   {
+  },
+  {
     {(0,0,0),(-40.3937,0,0),(-42.51969,0,2.12598),(-42.51969,0,4.251961)},
     {(0,0,0),(-40.3937,-22.62047,0),(-42.51969,-23.81102,2.12598),(-42.51969,-23.81102,4.251961)},
     {(0,0,0),(-22.62047,-40.3937,0),(-23.81102,-42.51969,2.12598),(-23.81102,-42.51969,4.251961)},
     {(0,0,0),(0,-40.3937,0),(0,-42.51969,2.12598),(0,-42.51969,4.251961)}
-   },
-   {
+  },
+  {
     {(0,0,0),(0,-40.3937,0),(0,-42.51969,2.12598),(0,-42.51969,4.251961)},
     {(0,0,0),(22.62047,-40.3937,0),(23.81102,-42.51969,2.12598),(23.81102,-42.51969,4.251961)},
     {(0,0,0),(40.3937,-22.62047,0),(42.51969,-23.81102,2.12598),(42.51969,-23.81102,4.251961)},
     {(0,0,0),(40.3937,0,0),(42.51969,0,2.12598),(42.51969,0,4.251961)}
-   }
-  };
+  }
+};
 
-draw(surface(Q),material(blue, shininess=0.85, metallic=0),render(compression=Low));
+surface regularize(triple[][] P, real fraction=0.02)
+{
+  triple[][][] B=hsplit(P,fraction);
+  triple[][] T=B[0];
+  surface s=surface(T[0][0]..controls T[0][1] and T[0][2]..
+                    T[0][3]..controls T[1][3] and T[2][3]..
+                    T[3][3]..controls T[3][2] and T[3][1]..cycle);
+  s.append(surface(patch(B[1])));
+  return s;
+}
+
+surface S=surface(Q);
+for(triple[][] q : Q0)
+  S.append(regularize(q));
+
+pen color;
+real metallic;
+
+if(settings.ibl) {
+  color=white;
+  metallic=1;
+} else {
+  color=blue;
+  metallic=0;
+}
+
+draw(S,material(color,shininess=0.85,metallic=metallic),
+     render(compression=Single));

Added: trunk/Master/texmf-dist/doc/asymptote/examples/teapotIBL.asy
===================================================================
--- trunk/Master/texmf-dist/doc/asymptote/examples/teapotIBL.asy	                        (rev 0)
+++ trunk/Master/texmf-dist/doc/asymptote/examples/teapotIBL.asy	2022-02-27 23:41:11 UTC (rev 62265)
@@ -0,0 +1,2 @@
+settings.ibl=true;
+import teapot;

Modified: trunk/Master/texmf-dist/doc/asymptote/examples/transparency.asy
===================================================================
--- trunk/Master/texmf-dist/doc/asymptote/examples/transparency.asy	2022-02-27 23:39:53 UTC (rev 62264)
+++ trunk/Master/texmf-dist/doc/asymptote/examples/transparency.asy	2022-02-27 23:41:11 UTC (rev 62265)
@@ -1,8 +1,5 @@
 size(0,150);
 
-if(settings.outformat == "")
-  settings.outformat="pdf";
-
 begingroup();
 fill(shift(1.5dir(120))*unitcircle,green+opacity(0.75));
 fill(shift(1.5dir(60))*unitcircle,red+opacity(0.75));

Added: trunk/Master/texmf-dist/doc/asymptote/examples/twoSpheres.asy
===================================================================
--- trunk/Master/texmf-dist/doc/asymptote/examples/twoSpheres.asy	                        (rev 0)
+++ trunk/Master/texmf-dist/doc/asymptote/examples/twoSpheres.asy	2022-02-27 23:41:11 UTC (rev 62265)
@@ -0,0 +1,17 @@
+import three;
+import palette;
+
+size(20cm);
+
+currentprojection=orthographic(1,1,1);
+
+draw(box((-2,-2,-1),(2,2,1)));
+
+draw(shift(-Z)*surface(box((-2,-2),(2,2))),blue);
+draw(shift(Z)*surface(box((-2,-2),(2,2))),orange+opacity(0.5));
+
+surface s=unitsphere;
+s.colors(palette(s.map(zpart),Gradient(green+opacity(0.6),white,
+                                       green+opacity(0.6))));
+draw(shift(0.5X+0.5Y)*s);
+draw(shift(-0.5X-0.5Y)*s);

Modified: trunk/Master/texmf-dist/doc/asymptote/examples/workcone.asy
===================================================================
--- trunk/Master/texmf-dist/doc/asymptote/examples/workcone.asy	2022-02-27 23:39:53 UTC (rev 62264)
+++ trunk/Master/texmf-dist/doc/asymptote/examples/workcone.asy	2022-02-27 23:41:11 UTC (rev 62265)
@@ -20,7 +20,7 @@
 
 draw(scale(x1,x1,-s1)*shift(-Z)*unitcone,lightblue+opacity(0.5),render);
 
-path3 p=(x2,0,s2)--(x,0,s+0.005);
+path3 p=(x2,0,s2)--(x,0,s);
 revolution a=revolution(p,Z);
 draw(surface(a),lightblue+opacity(0.5),render);
 

Modified: trunk/Master/texmf-dist/doc/info/asy-faq.info
===================================================================
--- trunk/Master/texmf-dist/doc/info/asy-faq.info	2022-02-27 23:39:53 UTC (rev 62264)
+++ trunk/Master/texmf-dist/doc/info/asy-faq.info	2022-02-27 23:41:11 UTC (rev 62265)
@@ -10,7 +10,7 @@
 File: asy-faq.info, Node: Top, Next: Question 1.1, Up: (dir)
 
             ASYMPTOTE FREQUENTLY ASKED QUESTIONS
-                            2021-03-15
+                            2022-02-05
                           
 This is the list of Frequently Asked Questions about Asymptote (asy).
 

Modified: trunk/Master/texmf-dist/doc/info/asymptote.info
===================================================================
--- trunk/Master/texmf-dist/doc/info/asymptote.info	2022-02-27 23:39:53 UTC (rev 62264)
+++ trunk/Master/texmf-dist/doc/info/asymptote.info	2022-02-27 23:41:11 UTC (rev 62265)
@@ -1,11 +1,11 @@
-This is asymptote.info, produced by makeinfo version 6.6 from
+This is asymptote.info, produced by makeinfo version 6.7 from
 asymptote.texi.
 
-This file documents 'Asymptote', version 2.70.
+This file documents 'Asymptote', version 2.78.
 
    <https://asymptote.sourceforge.io>
 
-   Copyright (C) 2004-20 Andy Hammerlindl, John Bowman, and Tom Prince.
+   Copyright (C) 2004-22 Andy Hammerlindl, John Bowman, and Tom Prince.
 
      Permission is granted to copy, distribute and/or modify this
      document under the terms of the GNU Lesser General Public License
@@ -22,11 +22,11 @@
 Asymptote
 *********
 
-This file documents 'Asymptote', version 2.70.
+This file documents 'Asymptote', version 2.78.
 
    <https://asymptote.sourceforge.io>
 
-   Copyright (C) 2004-20 Andy Hammerlindl, John Bowman, and Tom Prince.
+   Copyright (C) 2004-22 Andy Hammerlindl, John Bowman, and Tom Prince.
 
      Permission is granted to copy, distribute and/or modify this
      document under the terms of the GNU Lesser General Public License
@@ -45,6 +45,8 @@
 * Options::                     Command-line options
 * Interactive mode::            Typing 'Asymptote' commands interactively
 * GUI::                         Graphical user interface
+* Command-Line Interface::      Remote command-line interface
+* Language server protocol::    Help when writing code
 * PostScript to Asymptote::     'Asymptote' backend to 'pstoedit'
 * Help::                        Where to get help and submit bug reports
 * Debugger::                    Squish those bugs!
@@ -174,13 +176,17 @@
 drawing.  Labels and equations are typeset with 'LaTeX', for overall
 document consistency, yielding the same high-quality level of
 typesetting that 'LaTeX' provides for scientific text.  By default it
-produces 'PostScript' output, but it can also generate 'PDF', 'SVG',
-'WebGL', 'PRC', and any format that the 'ImageMagick' package can
-produce.  You can even try it out in your Web browser without installing
-it, using the 'Asymptote Web Application':
+produces 'PostScript' output, but it can also generate 'OpenGL', 'PDF',
+'SVG', 'WebGL', 'V3D', and 'PRC' vector graphics, along with any format
+that the 'ImageMagick' package can produce.  You can even try it out in
+your Web browser without installing it, using the 'Asymptote Web
+Application'
 
    <http://asymptote.ualberta.ca>
 
+   It is also possible to send remote commands to this server via the
+curl utility (*note Command-Line Interface::).
+
    A major advantage of 'Asymptote' over other graphics packages is that
 it is a high-level programming language, as opposed to just a graphics
 program: it can therefore exploit the best features of the script
@@ -342,8 +348,8 @@
 Ghostscript' version 9.52 or later from
 <http://downloads.ghostscript.com/public>.
 
-   To view 'PostScript' output, you can install the program 'gsview'
-available from <http://www.cs.wisc.edu/~ghost/gsview/>.
+   To view 'PostScript' output, you can install the program 'Sumatra
+PDF' available from <https://www.sumatrapdfreader.org/>.
 
    The 'ImageMagick' package from
 <https://www.imagemagick.org/script/binary-releases.php>
@@ -406,7 +412,7 @@
 Explorer' does not support 'WebGL'; 'Microsoft Windows' users should set
 their default html browser to 'chrome' or 'microsoft-edge'.  By default,
 2D and 3D 'HTML' images expand to the enclosing canvas; this can be
-disabled by setting the configuation variable 'absolute' to 'true'.
+disabled by setting the configuration variable 'absolute' to 'true'.
 
    On 'UNIX' systems, to support automatic document reloading of 'PDF'
 files in 'Adobe Reader', we recommend copying the file 'reload.js' from
@@ -971,7 +977,7 @@
              real xmargin=legendmargin, real ymargin=xmargin,
              real linelength=legendlinelength,
              real hskip=legendhskip, real vskip=legendvskip,
-             real maxwidth=0, real maxheight=0, 
+             real maxwidth=0, real maxheight=0,
              bool hstretch=false, bool vstretch=false, pen p=currentpen);
 Here 'xmargin' and 'ymargin' specify the surrounding x and y margins,
 'perline' specifies the number of entries per line (default 1; 0 means
@@ -1257,7 +1263,7 @@
 frame pack(pair align=2S ... object inset[]);
 To draw or fill a box (or ellipse or other path) around a Label and
 return the bounding object, use one of the routines
-object draw(picture pic=currentpicture, Label L, envelope e, 
+object draw(picture pic=currentpicture, Label L, envelope e,
             real xmargin=0, real ymargin=xmargin, pen p=currentpen,
             filltype filltype=NoFill, bool above=true);
 object draw(picture pic=currentpicture, Label L, envelope e, pair position,
@@ -2016,11 +2022,11 @@
 
      'path subpath(path p, int a, int b);'
           returns the subpath of 'p' running from node 'a' to node 'b'.
-          If 'a' < 'b', the direction of the subpath is reversed.
+          If 'a' > 'b', the direction of the subpath is reversed.
 
      'path subpath(path p, real a, real b);'
           returns the subpath of 'p' running from path time 'a' to path
-          time 'b', in the sense of 'point(path, real)'.  If 'a' < 'b',
+          time 'b', in the sense of 'point(path, real)'.  If 'a' > 'b',
           the direction of the subpath is reversed.
 
      'real[] intersect(path p, path q, real fuzz=-1);'
@@ -3018,7 +3024,7 @@
      The routine
      void usepackage(string s, string options="");
      provides a convenient abbreviation for
-     texpreamble("\usepackage["+options+"]{"+s+"}"); 
+     texpreamble("\usepackage["+options+"]{"+s+"}");
      that can be used for importing 'LaTeX' packages.
 
 
@@ -3436,7 +3442,7 @@
 and 'change.clock' indicate the change in the corresponding fields since
 the last call to 'cputime()'.  The function
 void write(file file=stdout, string s="", cputime c,
-           string format=cputimeformat, suffix suffix=none); 
+           string format=cputimeformat, suffix suffix=none);
 displays the incremental user cputime followed by "u", the incremental
 system cputime followed by "s", the total user cputime followed by "U",
 and the total system cputime followed by "S".
@@ -3451,7 +3457,7 @@
 }
 
 void write(parent p) {write(p.x);}
-  
+
 struct child {
   parent parent;
   real y=3;
@@ -3462,7 +3468,7 @@
 }
 
 parent operator cast(child child) {return child.parent;}
-  
+
 parent p=parent(1);
 child c=child(2);
 
@@ -3683,13 +3689,13 @@
 
   1. Variables with signatures (functions) and without signatures
      (nonfunction variables) are distinct:
-     int x, x();           
+     int x, x();
      x=5;
      x=new int() {return 17;};
      x=x();              // calls x() and puts the result, 17, in the scalar x
 
   2. Traditional function definitions are allowed:
-     int sqr(int x)  
+     int sqr(int x)
      {
        return x*x;
      }
@@ -3721,22 +3727,22 @@
      version of 'f', as illustrated in this example:
      void f() {
        write("hi");
-     }  
-      
+     }
+     
      void g() {
        f();
-     } 
-      
-     g(); // writes "hi" 
-      
-     f=new void() {write("bye");}; 
+     }
      
-     g(); // writes "bye" 
-      
-     void f() {write("overloaded");}; 
+     g(); // writes "hi"
      
+     f=new void() {write("bye");};
+     
+     g(); // writes "bye"
+     
+     void f() {write("overloaded");};
+     
      f(); // writes "overloaded"
-     g(); // writes "bye" 
+     g(); // writes "bye"
 
   6. Anonymous functions can be used to redefine a function variable
      that has been declared (and implicitly initialized to the null
@@ -3855,7 +3861,7 @@
 of arguments:
 // This function sums its arguments.
 int sum(... int[] nums) {
-  int total=0; 
+  int total=0;
   for(int i=0; i < nums.length; ++i)
     total += nums[i];
   return total;
@@ -4145,6 +4151,10 @@
      if 'm >= n' returns an array '{n,n+1,...,m}' (otherwise returns a
      null array);
 
+'int[] sequence(int n, int m, int skip)'
+     if 'm >= n' returns an array '{n,n+1,...,m}' skipping by 'skip'
+     (otherwise returns a null array);
+
 'T[] sequence(T f(int), int n)'
      if 'n >= 1' returns the sequence '{f_i :i=0,1,...n-1}' given a
      function 'T f(int)' and integer 'int n' (otherwise returns a null
@@ -4606,19 +4616,19 @@
 
    Similarly, one can add the non-private fields and types of a
 structure to the local environment with the 'unravel' keyword:
-struct matrix { 
-  real a,b,c,d; 
-} 
- 
-real det(matrix m) { 
-  unravel m; 
-  return a*d-b*c; 
-} 
+struct matrix {
+  real a,b,c,d;
+}
+
+real det(matrix m) {
+  unravel m;
+  return a*d-b*c;
+}
    Alternatively, one can unravel selective fields:
-real det(matrix m) { 
+real det(matrix m) {
   from m unravel a,b,c as C,d;
-  return a*d-b*C; 
-} 
+  return a*d-b*C;
+}
 
    The command
 import graph;
@@ -4927,6 +4937,7 @@
 
 \begin{asydef}
 // Global Asymptote definitions can be put here.
+settings.prc=true;
 import three;
 usepackage("bm");
 texpreamble("\def\V#1{\bm{#1}}");
@@ -5127,24 +5138,24 @@
      returns the four complex roots of the quartic equation
      ax^4+bx^3+cx^2+dx+e=0.
 
-'real time(path g, real x, int n=0)'
+'real time(path g, real x, int n=0, real fuzz=-1)'
      returns the 'n'th intersection time of path 'g' with the vertical
      line through x.
 
-'real time(path g, explicit pair z, int n=0)'
+'real time(path g, explicit pair z, int n=0, real fuzz=-1)'
      returns the 'n'th intersection time of path 'g' with the horizontal
      line through '(0,z.y)'.
 
-'real value(path g, real x, int n=0)'
+'real value(path g, real x, int n=0, real fuzz=-1)'
      returns the 'n'th 'y' value of 'g' at 'x'.
 
-'real value(path g, explicit pair z, int n=0)'
+'real value(path g, explicit pair z, int n=0, real fuzz=-1)'
      returns the 'n'th 'x' value of 'g' at 'y=z.y'.
 
-'real slope(path g, real x, int n=0)'
+'real slope(path g, real x, int n=0, real fuzz=-1)'
      returns the 'n'th slope of 'g' at 'x'.
 
-'real slope(path g, explicit pair z, int n=0)'
+'real slope(path g, explicit pair z, int n=0, real fuzz=-1)'
      returns the 'n'th slope of 'g' at 'y=z.y'.
 
      int[][] segment(bool[] b) returns the indices of consecutive
@@ -5223,7 +5234,7 @@
 convenient pattern generation routines.
 
 
-File: asymptote.info,  Node: markers,  Next: tree,  Prev: patterns,  Up: Base modules
+File: asymptote.info,  Node: markers,  Next: map,  Prev: patterns,  Up: Base modules
 
 8.9 'markers'
 =============
@@ -5290,7 +5301,7 @@
 write(M.lookup("y"));
 
 
-File: asymptote.info,  Node: tree,  Next: binarytree,  Prev: markers,  Up: Base modules
+File: asymptote.info,  Node: tree,  Next: binarytree,  Prev: map,  Up: Base modules
 
 8.11 'tree'
 ===========
@@ -5617,7 +5628,7 @@
    An axis can be drawn on a picture with one of the following commands:
 
    * void xaxis(picture pic=currentpicture, Label L="", axis axis=YZero,
-                real xmin=-infinity, real xmax=infinity, pen p=currentpen, 
+                real xmin=-infinity, real xmax=infinity, pen p=currentpen,
                 ticks ticks=NoTicks, arrowbar arrow=None, bool above=false);
 
      Draw an x axis on picture 'pic' from x='xmin' to x='xmax' using pen
@@ -5746,8 +5757,8 @@
      'LeftTicks', 'RightTicks', and 'Ticks' by passing explicit real
      arrays 'Ticks' and (optionally) 'ticks' containing the locations of
      the major and minor ticks, respectively:
-     ticks LeftTicks(Label format="", ticklabel ticklabel=null, 
-                     bool beginlabel=true, bool endlabel=true, 
+     ticks LeftTicks(Label format="", ticklabel ticklabel=null,
+                     bool beginlabel=true, bool endlabel=true,
                      real[] Ticks, real[] ticks=new real[],
                      real Size=0, real size=0, bool extend=false,
                      pen pTick=nullpen, pen ptick=nullpen)
@@ -5940,7 +5951,7 @@
      typedef real realfcn(real);
      realfcn F(real p) {
        return new real(real x) {return sin(p*x);};
-     };
+     }
      
      for(int i=1; i < 5; ++i)
        draw(graph(F(i*pi),0,1),Pen(i),
@@ -5992,7 +6003,7 @@
   5. The next example draws two graphs of an array of coordinate pairs,
      using frame alignment and data markers.  In the left-hand graph,
      the markers, constructed with
-     marker marker(path g, markroutine markroutine=marknodes, 
+     marker marker(path g, markroutine markroutine=marknodes,
                    pen p=currentpen, filltype filltype=NoFill,
                    bool above=true);
      using the path 'unitcircle' (*note filltype::), are drawn below
@@ -6018,13 +6029,13 @@
        marker(scale(circlescale)*unitcircle),
        marker(polygon(3)),marker(polygon(4)),
        marker(polygon(5)),marker(invert*polygon(3)),
-       marker(cross(4)),marker(cross(6))
+       marker(cross(4)),marker(cross(6)),marker(diamond),marker(plus);
      };
      
      marker[] MarkFill={
        marker(scale(circlescale)*unitcircle,Fill),marker(polygon(3),Fill),
        marker(polygon(4),Fill),marker(polygon(5),Fill),
-       marker(invert*polygon(3),Fill)
+       marker(invert*polygon(3),Fill),marker(diamond,Fill)
      };
 
      The example also illustrates the 'errorbar' routines:
@@ -6179,6 +6190,26 @@
 
                           [./parametricgraph]
 
+     The function
+     guide graphwithderiv(pair f(real), pair fprime(real), real a, real b,
+                          int n=ngraph#10);
+     can be used to construct the graph of the parametric function 'f'
+     on '[a,b]' with the control points of the 'n' Bezier segments
+     determined by the specified derivative 'fprime':
+     unitsize(2cm);
+     import graph;
+     pair F(real t) {
+       return (1.3*t,-4.5*t^2+3.0*t+1.0);
+     }
+     pair Fprime(real t) {
+       return (1.3,-9.0*t+3.0);
+     }
+     path g=graphwithderiv(F,Fprime,0,0.9,4);
+     dot(g,red);
+     draw(g,arrow=Arrow(TeXHead));
+
+                          [./graphwithderiv]
+
      The next example illustrates how one can extract a common axis
      scaling factor.
      import graph;
@@ -6392,7 +6423,7 @@
      real[][] a=in;
      a=transpose(a);
      real[] t=a[0], susceptible=a[1], infectious=a[2], dead=a[3], larvae=a[4];
-     real[] susceptibleM=a[5], exposed=a[6],infectiousM=a[7];
+     real[] susceptibleM=a[5], exposed=a[6], infectiousM=a[7];
      
      scale(true);
      
@@ -6410,7 +6441,6 @@
      
      add(secondary);
      label(shift(5mm*N)*"Proportion of crows",point(NW),E);
-     
 
                            [./secondaryaxis]
 
@@ -6617,12 +6647,14 @@
 function 'f'(x,y) and added to a picture 'pic':
 bounds image(picture pic=currentpicture, real f(real, real),
              range range=Full, pair initial, pair final,
-             int nx=ngraph, int ny=nx, pen[] palette, bool antialias=false)
+             int nx=ngraph, int ny=nx, pen[] palette, int divs=0,
+             bool antialias=false)
    The function 'f' will be sampled at 'nx' and 'ny' evenly spaced
 points over a rectangle defined by the points 'initial' and 'final',
 respecting the current graphical scaling of 'pic'.  The color space is
-scaled according to the z axis scaling (*note automatic scaling::).  A
-bounds structure for the function values is returned:
+scaled according to the z axis scaling (*note automatic scaling::).  If
+'divs' > 1, the palette is quantized to 'divs'-1 values.  A 'bounds'
+structure for the function values is returned:
 struct bounds {
   real min;
   real max;
@@ -6634,14 +6666,15 @@
 the argument 'range', which can be 'Full', 'Automatic', or an explicit
 range 'Range(real min, real max)'.  Here 'Full' specifies a range
 varying from the minimum to maximum values of the function over the
-sampling interval, while 'Automatic' selects "nice" limits.  The example
-'imagecontour.asy' illustrates how level sets (contour lines) can be
-drawn on a color density plot (*note contour::).
+sampling interval, while 'Automatic' selects "nice" limits.  The
+examples 'fillcontour.asy' and 'imagecontour.asy' illustrate how level
+sets (contour lines) can be drawn on a color density plot (*note
+contour::).
 
    A color density plot can also be generated from an explicit real[][]
 array 'data':
 bounds image(picture pic=currentpicture, real[][] f, range range=Full,
-             pair initial, pair final, pen[] palette,
+             pair initial, pair final, pen[] palette, int divs=0,
              bool transpose=(initial.x < final.x && initial.y < final.y),
              bool copy=true, bool antialias=false);
 If the initial point is to the left and below the final point, by
@@ -6861,7 +6894,7 @@
 struct material {
   pen[] p; // diffusepen,emissivepen,specularpen
   real opacity;
-  real shininess;  
+  real shininess;
   real metallic;
   real fresnel0;
 }
@@ -6895,11 +6928,21 @@
 transparent background for 3D 'WebGL' images with
 'currentlight.background=black+opacity(0.0);'
 
+   Asymptote also supports image-based lighting with the setting
+'settings.ibl=true'.  This uses pre-rendered EXR images from the
+directory specified by '-imageDir' (which defaults to 'ibl') or, for
+'WebGL' rendering, the URL specified by '-imageURL' (which defaults to
+<https://vectorgraphics.gitlab.io/asymptote/ibl>).  Additional rendered
+images can be generated on an 'NVIDIA' GPU using the 'reflect' program
+in the 'cudareflect' subdirectory of the 'Asymptote' source directory.
+
    Sample Bezier surfaces are contained in the example files
-'BezierSurface.asy', 'teapot.asy', and 'parametricsurface.asy'.  The
-structure 'render' contains specialized rendering options documented at
-the beginning of module 'three'.
+'BezierSurface.asy', 'teapot.asy', 'teapotIBL.asy', and
+'parametricsurface.asy'.
 
+   The structure 'render' contains specialized rendering options
+documented at the beginning of module 'three'.
+
    The examples 'elevation.asy' and 'sphericalharmonic.asy' illustrate
 how to draw a surface with patch-dependent colors.  The examples
 'vertexshading.asy' and 'smoothelevation.asy' illustrate
@@ -6963,7 +7006,7 @@
 pens 'thin()' and 'thick()' defined in 'plain_pens.asy' can also be used
 to override these defaults for specific draw commands.
 
-There are five choices for viewing 3D 'Asymptote' output:
+There are six choices for viewing 3D 'Asymptote' output:
 
   1. Use the native 'Asymptote' adaptive 'OpenGL'-based renderer (with
      the command-line option '-V' and the default settings
@@ -6992,7 +7035,7 @@
         * Ctrl Right: rotate about the Y axis
         * Alt Right: rotate about the Z axis
 
-     The keyboard shortcuts are:
+     The keyboard bindings are:
         * h: home
         * f: toggle fitscreen
         * x: spin about the X axis
@@ -7019,11 +7062,8 @@
      'outformat="html"').  The resulting 3D HTML file can then be viewed
      directly in any modern desktop or mobile browser, or even embedded
      within another web page:
-     <div>
-     <object data="logo3.html"
-             style="width:210;height:140;position:relative;top:0;left:0;">
-     </object>
-     </div>
+     <iframe src="logo3.html" width="561" height="321" frameborder="0">
+     </iframe>
 
      Normally, 'WebGL' files generated by 'Asymptote' are dynamically
      remeshed to fit the browser window dimensions.  However, the
@@ -7059,35 +7099,48 @@
      setting the horizontal and vertical components of 'maxtiles' to
      something less than your screen dimensions.  The tile size is also
      limited by the setting 'maxviewport', which restricts the maximum
-     width and height of the viewport.  On 'UNIX' systems some graphics
-     drivers support batch mode ('-noV') rendering in an iconified
-     window; this can be enabled with the setting 'iconify=true'.
+     width and height of the viewport.  Some graphics drivers support
+     batch mode ('-noV') rendering in an iconified window; this can be
+     enabled with the setting 'iconify=true'.
 
   4. Embed the 3D PRC format in a PDF file and view the resulting PDF
-     file with version '9.0' or later of 'Adobe Reader'.  In addition to
-     the default 'settings.prc=true', this requires
-     'settings.outformat="pdf"', which can be specified by the command
-     line option '-f pdf', put in the 'Asymptote' configuration file
-     (*note configuration file::), or specified in the script before
-     module 'three' (or 'graph3') is imported.  The 'media9' LaTeX
-     package is also required (*note embed::).  The example '100d.asy'
-     illustrates how one can generate a list of predefined views (see
-     '100d.views').  A stationary preview image with a resolution of 'n'
-     pixels per 'bp' can be embedded with the setting 'render=n'; this
-     allows the file to be viewed with other 'PDF' viewers.
-     Alternatively, the file 'externalprc.tex' illustrates how the
-     resulting PRC and rendered image files can be extracted and
-     processed in a separate 'LaTeX' file.  However, see *note LaTeX
-     usage:: for an easier way to embed three-dimensional 'Asymptote'
-     pictures within 'LaTeX'.  For specialized applications where only
-     the raw PRC file is required, specify 'settings.outformat="prc"'.
-     The PRC specification is available from
+     file with version '9.0' or later of 'Adobe Reader'.  This requires
+     'settings.outformat="pdf"' and 'settings.prc=true', which can be
+     specified by the command-line options '-f pdf' and '-f prc', put in
+     the 'Asymptote' configuration file (*note configuration file::), or
+     specified in the script before module 'three' (or 'graph3') is
+     imported.  The 'media9' LaTeX package is also required (*note
+     embed::).  The example '100d.asy' illustrates how one can generate
+     a list of predefined views (see '100d.views').  A stationary
+     preview image with a resolution of 'n' pixels per 'bp' can be
+     embedded with the setting 'render=n'; this allows the file to be
+     viewed with other 'PDF' viewers.  Alternatively, the file
+     'externalprc.tex' illustrates how the resulting PRC and rendered
+     image files can be extracted and processed in a separate 'LaTeX'
+     file.  However, see *note LaTeX usage:: for an easier way to embed
+     three-dimensional 'Asymptote' pictures within 'LaTeX'.  For
+     specialized applications where only the raw PRC file is required,
+     specify 'settings.outformat="prc"'.  The PRC specification is
+     available from
      <https://web.archive.org/web/20081204104459/http://livedocs.adobe.com/acrobat_sdk/9/Acrobat9_HTMLHelp/API_References/PRCReference/PRC_Format_Specification/>
 
-  5. Project the scene to a two-dimensional vector (EPS or PDF) format
-     with 'render=0'.  Only limited hidden surface removal facilities
-     are currently available with this approach (*note PostScript3D::).
+  5. Output a 'V3D' portable compressed binary file for viewing with an
+     external viewer or conversion to an alternate 3D format with the
+     Python 'pyv3d' library.  The 'V3D' specification and the 'pyv3d'
+     library are available at <https://gitlab.com/vectorgraphics/v3d>.
+     A 'V3D' file 'file.v3d' may be imported and viewed by 'Asymptote'
+     either by specifying 'file.v3d' on the command line
+     asy -V file.v3d
+     or using the 'v3d' module and 'importv3d' function in interactive
+     mode (or within an 'Asymptote' file):
+     import v3d;
+     importv3d("file.v3d");
 
+  6. Project the scene to a two-dimensional vector (EPS or PDF) format
+     with 'render=0'.  Only limited support for hidden surface removal,
+     lighting, and transparency is available with this approach (*note
+     PostScript3D::).
+
    Automatic picture sizing in three dimensions is accomplished with
 double deferred drawing.  The maximal desired dimensions of the scene in
 each of the three dimensions can optionally be specified with the
@@ -7196,11 +7249,7 @@
      This projects from three to two dimensions, taking account of
      perspective, as seen from the location 'camera' looking at
      'target', orienting the camera so that, if possible, the vector
-     'up' points upwards.  If 'render=0', projection of
-     three-dimensional cubic Bezier splines is implemented by
-     approximating a two-dimensional nonuniform rational B-spline
-     (NURBS) with a two-dimensional Bezier curve containing additional
-     nodes and control points.  If 'autoadjust=true', the camera will
+     'up' points upwards.  If 'autoadjust=true', the camera will
      automatically be adjusted to lie outside the bounding volume for
      all possible interactive rotations about 'target'.  If
      'center=true', the target will be adjusted to the center of the
@@ -7499,7 +7548,7 @@
 in three dimensions.  There is also a routine for drawing all three
 axis:
 void axes3(picture pic=currentpicture,
-           Label xlabel="", Label ylabel="", Label zlabel="", 
+           Label xlabel="", Label ylabel="", Label zlabel="",
            bool extend=false,
            triple min=(-infinity,-infinity,-infinity),
            triple max=(infinity,infinity,infinity),
@@ -7957,13 +8006,13 @@
 
                            [./multicontour]
 
-   The next example illustrates how contour lines can be drawn on color
-density images:
+   The next examples illustrates how contour lines can be drawn on color
+density images, with and without palette quantization:
 import graph;
 import palette;
 import contour;
 
-size(10cm,10cm,IgnoreAspect);
+size(10cm,10cm);
 
 pair a=(0,0);
 pair b=(2pi,2pi);
@@ -7972,31 +8021,74 @@
 
 int N=200;
 int Divs=10;
-int divs=2;
+int divs=1;
+int n=Divs*divs;
 
 defaultpen(1bp);
 pen Tickpen=black;
 pen tickpen=gray+0.5*linewidth(currentpen);
+pen[] Palette=quantize(BWRainbow(),n);
+
+bounds range=image(f,Automatic,a,b,3N,Palette,n);
+
+real[] Cvals=uniform(range.min,range.max,Divs);
+draw(contour(f,a,b,Cvals,N,operator --),Tickpen+squarecap+beveljoin);
+
+// Major contours
+real[] Cvals=uniform(range.min,range.max,Divs);
+draw(contour(f,a,b,Cvals,N,operator --),Tickpen+squarecap+beveljoin);
+
+// Minor contours (if divs > 1)
+real[] cvals;
+for(int i=0; i < Cvals.length-1; ++i)
+  cvals.append(uniform(Cvals[i],Cvals[i+1],divs)[1:divs]);
+draw(contour(f,a,b,cvals,N,operator --),tickpen);
+
+xaxis("$x$",BottomTop,LeftTicks,above=true);
+yaxis("$y$",LeftRight,RightTicks,above=true);
+
+palette("$f(x,y)$",range,point(SE)+(0.5,0),point(NE)+(1,0),Right,Palette,
+        PaletteTicks("$%+#0.1f$",N=Divs,n=divs,Tickpen,tickpen));
+
+                            [./fillcontour]
+
+import graph;
+import palette;
+import contour;
+
+size(10cm,10cm);
+
+pair a=(0,0);
+pair b=(2pi,2pi);
+
+real f(real x, real y) {return cos(x)*sin(y);}
+
+int N=200;
+int Divs=10;
+int divs=1;
+
+defaultpen(1bp);
+pen Tickpen=black;
+pen tickpen=gray+0.5*linewidth(currentpen);
 pen[] Palette=BWRainbow();
 
 bounds range=image(f,Automatic,a,b,N,Palette);
 
 // Major contours
-
 real[] Cvals=uniform(range.min,range.max,Divs);
-draw(contour(f,a,b,Cvals,N,operator --),Tickpen);
+draw(contour(f,a,b,Cvals,N,operator --),Tickpen+squarecap+beveljoin);
 
-// Minor contours
+// Minor contours (if divs > 1)
 real[] cvals;
 for(int i=0; i < Cvals.length-1; ++i)
   cvals.append(uniform(Cvals[i],Cvals[i+1],divs)[1:divs]);
-draw(contour(f,a,b,cvals,N,operator --),tickpen);
+draw(contour(f,a,b,cvals,N,operator --),tickpen+squarecap+beveljoin);
 
 xaxis("$x$",BottomTop,LeftTicks,above=true);
 yaxis("$y$",LeftRight,RightTicks,above=true);
 
-palette("$f(x,y)$",range,point(NW)+(0,0.5),point(NE)+(0,1),Top,Palette,
-        PaletteTicks(N=Divs,n=divs,Tickpen,tickpen));
+palette("$f(x,y)$",range,point(SE)+(0.5,0),point(NE)+(1,0),Right,Palette,
+        PaletteTicks("$%+#0.1f$",N=Divs,n=divs,Tickpen,tickpen));
 
                            [./imagecontour]
 
@@ -8087,9 +8179,9 @@
 
    To construct the null surface of a function 'f(triple)' or
 'ff(real,real,real)' over 'box(a,b)', use the routine
-surface implicitsurface(real f(triple)=null, 
+surface implicitsurface(real f(triple)=null,
                         real ff(real,real,real)=null,
-                        triple a, 
+                        triple a,
                         triple b,
                         int n=nmesh,
                         bool keyword overlapedges=false,
@@ -8115,7 +8207,7 @@
 To draw a slope field for the differential equation dy/dx=f(x,y) (or
 dy/dx=f(x)), use:
 picture slopefield(real f(real,real), pair a, pair b,
-                   int nx=nmesh, int ny=nx, 
+                   int nx=nmesh, int ny=nx,
                    real tickfactor=0.5, pen p=currentpen,
                    arrowbar arrow=None);
 Here, the points 'a' and 'b' are the lower left and upper right corners
@@ -8170,6 +8262,8 @@
 
 Options (negate by replacing - with -no): 
 
+-GPUindexing           Compute indexing partial sums on GPU [true]
+-GPUinterlock          Use fragment shader interlock [true]
 -V,-View               View output; command-line only
 -absolute              Use absolute WebGL dimensions [false]
 -a,-align C|B|T|Z      Center, Bottom, Top, or Zero page alignment [C]
@@ -8194,8 +8288,8 @@
 -devicepixelratio n    Ratio of physical to logical pixels [1]
 -digits n              Default output file precision [7]
 -divisor n             Garbage collect using purge(divisor=n) [2]
+-dvisvgmMultipleFiles  dvisvgm supports multiple files [false]
 -embed                 Embed rendered preview image [true]
--envmap                Enable environment map image-based lighting (Experimental) [false]
 -exitonEOF             Exit interactive mode on EOF [true]
 -fitscreen             Fit rendered image to screen [true]
 -framedelay ms         Additional frame delay [0]
@@ -8205,7 +8299,10 @@
 -gray                  Convert all colors to grayscale [false]
 -h,-help               Show summary of options; command-line only
 -historylines n        Retain n lines of history [1000]
+-ibl                   Enable environment map image-based lighting [false]
 -iconify               Iconify rendering window [false]
+-image string          Environment image name [snowyField]
+-imageDir string       Environment image library directory [ibl]
 -inlineimage           Generate inline embedded image [false]
 -inlinetex             Generate inline TeX code [false]
 -interactiveMask       Mask fpu exceptions in interactive mode [true]
@@ -8217,6 +8314,8 @@
 -l,-listvariables      List available global functions and variables [false]
 -localhistory          Use a local interactive history file [false]
 -loop                  Loop 3D animations [false]
+-lossy                 Use single precision for V3D reals [false]
+-lsp                   Interactive mode for the Language Server Protocol [false]
 -m,-mask               Mask fpu exceptions; command-line only
 -maxtile pair          Maximum rendering tile size [(1024,768)]
 -maxviewport pair      Maximum viewport size [(0,0)]
@@ -8231,7 +8330,8 @@
 -pdfreload             Automatically reload document in pdfviewer [false]
 -pdfreloaddelay usec   Delay before attempting initial pdf reload [750000]
 -position pair         Initial 3D rendering screen position [(0,0)]
--prc                   Embed 3D PRC graphics in PDF output [true]
+-prc                   Embed 3D PRC graphics in PDF output [false]
+-prerender resolution  Prerender V3D objects (0 implies vector output) [0]
 -prompt string         Prompt [> ]
 -prompt2 string        Continuation prompt for multiline input  [..]
 -q,-quiet              Suppress welcome text and noninteractive stdout [false]
@@ -8261,8 +8361,10 @@
 -viewportmargin pair   Horizontal and vertical 3D viewport margin [(0.5,0.5)]
 -wait                  Wait for child processes to finish before exiting [false]
 -warn string           Enable warning; command-line only
+-webgl2                Use webgl2 if available [false]
 -where                 Show where listed variables are declared [false]
--xasy                  Special interactive mode for xasy [false]
+-wsl                   Run asy under the Windows Subsystem for Linux. [false]
+-xasy                  Interactive mode for xasy [false]
 -zoomPinchCap limit    WebGL maximum zoom pinch [100]
 -zoomPinchFactor n     WebGL zoom pinch sensitivity [10]
 -zoomfactor factor     Zoom step factor [1.05]
@@ -8357,7 +8459,7 @@
 'Asymptote' code on the command line as a string.  It is not necessary
 to terminate the string with a semicolon.  Multiple '-c' options are
 executed in the order they are given.  For example
-asy -c 2+2 -c "sin(1)" -c "size(100); draw(unitsquare)" 
+asy -c 2+2 -c "sin(1)" -c "size(100); draw(unitsquare)"
 produces the output
 4
 0.841470984807897
@@ -8423,7 +8525,7 @@
 > currentpicture
 <picture currentpicture>
 > %.size(200,0)
-> 
+>
 
    The '%' symbol, when used as a variable, is shorthand for the
 identifier 'operator answer', which is set by the prompt after each
@@ -8476,7 +8578,7 @@
 g.label("\"$O$\", (0,0), SW")
 
 
-File: asymptote.info,  Node: GUI,  Next: PostScript to Asymptote,  Prev: Interactive mode,  Up: Top
+File: asymptote.info,  Node: GUI,  Next: Command-Line Interface,  Prev: Interactive mode,  Up: Top
 
 11 Graphical User Interface
 ***************************
@@ -8536,9 +8638,99 @@
 elements will be individually deconstructed (*note add::).
 
 
-File: asymptote.info,  Node: PostScript to Asymptote,  Next: Help,  Prev: GUI,  Up: Top
+File: asymptote.info,  Node: Command-Line Interface,  Next: PostScript to Asymptote,  Prev: GUI,  Up: Top
 
-12 'PostScript' to 'Asymptote'
+12 Command-Line Interface
+*************************
+
+'Asymptote' code may be sent to the <http://asymptote.ualberta.ca>
+server directly from the command line, specifying any options directly
+in the URL:
+
+   * SVG output:
+
+     'curl --data-binary 'import venn;'
+     'asymptote.ualberta.ca:10007?f=svg' | display -'
+
+   * HTML output:
+
+     'curl --data-binary
+     @/usr/local/share/doc/asymptote/examples/Klein.asy
+     'asymptote.ualberta.ca:10007' -o Klein.html'
+
+   * V3D output:
+
+     'curl --data-binary 'import teapot;'
+     'asymptote.ualberta.ca:10007?f=v3d' -o teapot.v3d'
+
+   * PDF output with rendered bitmap at 2 pixels per bp:
+
+     'curl --data-binary 'import teapot;'
+     'asymptote.ualberta.ca:10007?f=pdf' -o teapot.pdf'
+
+   * PDF output with rendered bitmap at 4 pixels per bp:
+
+     'curl --data-binary 'import teapot;'
+     'asymptote.ualberta.ca:10007?f=pdf&render=4' -o teapot.pdf'
+
+   * PRC output:
+
+     'curl --data-binary 'import teapot;'
+     'asymptote.ualberta.ca:10007?f=pdf&prc' -o teapot.pdf'
+
+   * PRC output with rendered preview bitmap at 4 pixels per bp:
+
+     'curl --data-binary 'import teapot;'
+     'asymptote.ualberta.ca:10007?f=pdf&prc&render=4' -o teapot.pdf'
+
+   The source code for the command-line interface is available at
+<https://github.com/vectorgraphics/asymptote-http-server>.
+
+
+File: asymptote.info,  Node: Language server protocol,  Next: PostScript to Asymptote,  Prev: Command-Line Interface,  Up: Top
+
+13 Language server protocol
+***************************
+
+Under 'UNIX' and 'MacOS X', 'Asymptote' supports features of the
+Language Server Protocol (LSP)
+(https://en.wikipedia.org/wiki/Language_Server_Protocol), including
+function signature and variable matching.  Under 'MSWindows',
+'Asymptote' currently supports LSP only when compiled within the
+'Windows Subsystem for Linux'.
+
+   'Emacs' users can enable the 'Asymptote' language server protocol by
+installing 'lsp-mode' using the following procedure:
+
+   * Add to the '.emacs' initialization file:
+     (require 'package)
+     (add-to-list 'package-archives '("melpa" . "https://melpa.org/packages/") t)
+     (package-initialize)
+
+   * Launch emacs and execute
+     M-x package-refresh-contents
+     M-x package-install
+     and select 'lsp-mode'.
+
+   * Add to the '.emacs' initialization file:
+     (require 'lsp-mode)
+     (add-to-list 'lsp-language-id-configuration '(asy-mode . "asymptote"))
+     
+     (lsp-register-client
+      (make-lsp-client :new-connection (lsp-stdio-connection '("asy" "-lsp"))
+                       :activation-fn (lsp-activate-on "asymptote")
+                       :major-modes '(asy-mode)
+                       :server-id 'asyls
+                       )
+      )
+
+   * Launch emacs and execute
+     M-x lsp
+
+
+File: asymptote.info,  Node: PostScript to Asymptote,  Next: Help,  Prev: Command-Line Interface,  Up: Top
+
+14 'PostScript' to 'Asymptote'
 ******************************
 
 The excellent 'PostScript' editor 'pstoedit' (version 3.50 or later;
@@ -8557,7 +8749,7 @@
 
 File: asymptote.info,  Node: Help,  Next: Debugger,  Prev: PostScript to Asymptote,  Up: Top
 
-13 Help
+15 Help
 *******
 
 A list of frequently asked questions (FAQ) is maintained at
@@ -8591,7 +8783,7 @@
 
 File: asymptote.info,  Node: Debugger,  Next: Credits,  Prev: Help,  Up: Top
 
-14 Debugger
+16 Debugger
 ***********
 
 Asymptote now includes a line-based (as opposed to code-based) debugger
@@ -8657,7 +8849,7 @@
 
 File: asymptote.info,  Node: Credits,  Next: Index,  Prev: Debugger,  Up: Top
 
-15 Acknowledgments
+17 Acknowledgments
 ******************
 
 Financial support for the development of 'Asymptote' was generously
@@ -8673,12 +8865,14 @@
    The authors of 'Asymptote' are Andy Hammerlindl, John Bowman, and Tom
 Prince.  Sean Healy designed the 'Asymptote' logo.  Other contributors
 include Orest Shardt, Jesse Frohlich, Michail Vidiassov, Charles Staats,
-Philippe Ivaldi, Olivier Guibe', Radoslav Marinov, Jeff Samuelson, Chris
+Philippe Ivaldi, Olivier Guibé, Radoslav Marinov, Jeff Samuelson, Chris
 Savage, Jacques Pienaar, Mark Henning, Steve Melenchuk, Martin Wiebusch,
-Stefan Knorr, and Supakorn "Jamie" Rassameemasmuang.  Pedram Emami
-developed the 'Asymptote Web Application' at
-<http://asymptote.ualberta.ca>.
+Stefan Knorr, Supakorn "Jamie" Rassameemasmuang, Jacob Skitsko, Joseph
+Chaumont, and Oliver Cheng.  Pedram Emami developed the 'Asymptote Web
+Application' hosted at <http://asymptote.ualberta.ca>:
 
+   <https://github.com/vectorgraphics/asymptoteWebApplication>
+
 
 File: asymptote.info,  Node: Index,  Prev: Credits,  Up: Top
 
@@ -8727,9 +8921,9 @@
 * ---:                                   Bezier curves.      (line   84)
 * -=:                                    Self & prefix operators.
                                                              (line    6)
-* -c:                                    Options.            (line  195)
-* -l:                                    Options.            (line  214)
-* -u:                                    Options.            (line  205)
+* -c:                                    Options.            (line  205)
+* -l:                                    Options.            (line  224)
+* -u:                                    Options.            (line  215)
 * -V:                                    Configuring.        (line    6)
 * -V <1>:                                Drawing in batch mode.
                                                              (line   16)
@@ -8742,7 +8936,7 @@
 * 2D graphs:                             graph.              (line    6)
 * 3D graphs:                             graph3.             (line    6)
 * 3D grids:                              grid3.              (line    6)
-* 3D PostScript:                         three.              (line  639)
+* 3D PostScript:                         three.              (line  655)
 * ::                                     Arithmetic & logical.
                                                              (line   61)
 * :::                                    Bezier curves.      (line   70)
@@ -8779,9 +8973,10 @@
 * abs2:                                  Data types.         (line   65)
 * abs2 <1>:                              Data types.         (line  144)
 * absolute:                              Configuring.        (line   43)
+* absolute <1>:                          three.              (line  241)
 * accel:                                 Paths and guides.   (line  126)
 * accel <1>:                             Paths and guides.   (line  132)
-* accel <2>:                             three.              (line  540)
+* accel <2>:                             three.              (line  556)
 * access:                                Import.             (line    6)
 * access <1>:                            Import.             (line   45)
 * acknowledgments:                       Credits.            (line    6)
@@ -8795,8 +8990,8 @@
                                                              (line  217)
 * add <1>:                               Frames and pictures.
                                                              (line  231)
-* add <2>:                               three.              (line  312)
-* addViews:                              three.              (line  433)
+* add <2>:                               three.              (line  332)
+* addViews:                              three.              (line  449)
 * adjust:                                Pens.               (line  123)
 * Ai:                                    Mathematical functions.
                                                              (line   48)
@@ -8805,10 +9000,10 @@
 * Ai_deriv:                              Mathematical functions.
                                                              (line   48)
 * alias:                                 Structures.         (line   62)
-* alias <1>:                             Arrays.             (line  179)
+* alias <1>:                             Arrays.             (line  183)
 * Align:                                 label.              (line   12)
-* aligndir:                              Options.            (line  187)
-* all:                                   Arrays.             (line  338)
+* aligndir:                              Options.            (line  197)
+* all:                                   Arrays.             (line  341)
 * Allow:                                 Pens.               (line  363)
 * and:                                   Bezier curves.      (line   56)
 * AND:                                   Arithmetic & logical.
@@ -8820,22 +9015,22 @@
 * animation:                             animation.          (line    6)
 * animation <1>:                         animation.          (line    6)
 * annotate:                              annotate.           (line    6)
-* antialias:                             three.              (line  254)
-* antialias <1>:                         Options.            (line  157)
+* antialias:                             three.              (line  261)
+* antialias <1>:                         Options.            (line  167)
 * append:                                Files.              (line   38)
 * append <1>:                            Arrays.             (line   39)
 * arc:                                   Paths and guides.   (line   24)
 * Arc:                                   Paths and guides.   (line   37)
-* arc <1>:                               three.              (line  323)
+* arc <1>:                               three.              (line  343)
 * ArcArrow:                              draw.               (line   26)
-* ArcArrow3:                             three.              (line  606)
+* ArcArrow3:                             three.              (line  622)
 * ArcArrows:                             draw.               (line   26)
-* ArcArrows3:                            three.              (line  606)
+* ArcArrows3:                            three.              (line  622)
 * arclength:                             Paths and guides.   (line  153)
-* arclength <1>:                         three.              (line  540)
+* arclength <1>:                         three.              (line  556)
 * arcpoint:                              Paths and guides.   (line  163)
 * arctime:                               Paths and guides.   (line  157)
-* arctime <1>:                           three.              (line  540)
+* arctime <1>:                           three.              (line  556)
 * arguments:                             Default arguments.  (line    6)
 * arithmetic operators:                  Arithmetic & logical.
                                                              (line    6)
@@ -8849,10 +9044,10 @@
 * arrow keys:                            Drawing in interactive mode.
                                                              (line   11)
 * arrow keys <1>:                        GUI usage.          (line    6)
-* Arrow3:                                three.              (line  606)
+* Arrow3:                                three.              (line  622)
 * arrows:                                draw.               (line   26)
 * Arrows:                                draw.               (line   26)
-* Arrows3:                               three.              (line  606)
+* Arrows3:                               three.              (line  622)
 * as:                                    Import.             (line   67)
 * ascii:                                 Data types.         (line  309)
 * ascii <1>:                             Data types.         (line  309)
@@ -8875,7 +9070,7 @@
 * Asymptote Web Application:             Description.        (line    6)
 * asymptote.sty:                         LaTeX usage.        (line    6)
 * asymptote.xml:                         Editing modes.      (line   48)
-* ASYMPTOTE_CONFIG:                      Options.            (line  128)
+* ASYMPTOTE_CONFIG:                      Options.            (line  138)
 * atan:                                  Mathematical functions.
                                                              (line    6)
 * aTan:                                  Mathematical functions.
@@ -8889,13 +9084,13 @@
                                                              (line  276)
 * attach <1>:                            LaTeX usage.        (line   50)
 * attach <2>:                            graph.              (line  406)
-* autoadjust:                            three.              (line  398)
-* autoimport:                            Options.            (line  124)
-* automatic scaling:                     graph.              (line  690)
-* automatic scaling <1>:                 graph.              (line  690)
+* autoadjust:                            three.              (line  418)
+* autoimport:                            Options.            (line  134)
+* automatic scaling:                     graph.              (line  710)
+* automatic scaling <1>:                 graph.              (line  710)
 * axialshade:                            fill.               (line   43)
-* axis:                                  graph.              (line  905)
-* axis <1>:                              graph.              (line  988)
+* axis:                                  graph.              (line  924)
+* axis <1>:                              graph.              (line 1007)
 * axis <2>:                              graph3.             (line   66)
 * axis <3>:                              graph3.             (line   82)
 * azimuth:                               Data types.         (line  154)
@@ -8904,11 +9099,11 @@
 * background <1>:                        three.              (line   97)
 * background color:                      Frames and pictures.
                                                              (line  180)
-* BackView:                              three.              (line  426)
+* BackView:                              three.              (line  442)
 * Bar:                                   draw.               (line   19)
-* Bar3:                                  three.              (line  606)
+* Bar3:                                  three.              (line  622)
 * Bars:                                  draw.               (line   19)
-* Bars3:                                 three.              (line  606)
+* Bars3:                                 three.              (line  622)
 * barsize:                               draw.               (line   19)
 * base modules:                          Base modules.       (line    6)
 * basealign:                             Pens.               (line  181)
@@ -8917,18 +9112,18 @@
                                                              (line    6)
 * beep:                                  Data types.         (line  382)
 * BeginArcArrow:                         draw.               (line   26)
-* BeginArcArrow3:                        three.              (line  606)
+* BeginArcArrow3:                        three.              (line  622)
 * BeginArrow:                            draw.               (line   26)
-* BeginArrow3:                           three.              (line  606)
+* BeginArrow3:                           three.              (line  622)
 * BeginBar:                              draw.               (line   19)
-* BeginBar3:                             three.              (line  606)
+* BeginBar3:                             three.              (line  622)
 * BeginDotMargin:                        draw.               (line   42)
-* BeginDotMargin3:                       three.              (line  622)
+* BeginDotMargin3:                       three.              (line  638)
 * BeginMargin:                           draw.               (line   42)
-* BeginMargin3:                          three.              (line  622)
+* BeginMargin3:                          three.              (line  638)
 * BeginPenMargin:                        draw.               (line   42)
-* BeginPenMargin2:                       three.              (line  622)
-* BeginPenMargin3:                       three.              (line  622)
+* BeginPenMargin2:                       three.              (line  638)
+* BeginPenMargin3:                       three.              (line  638)
 * BeginPoint:                            label.              (line   55)
 * Bessel:                                Mathematical functions.
                                                              (line   48)
@@ -8935,12 +9130,12 @@
 * bevel:                                 flowchart.          (line   72)
 * beveljoin:                             Pens.               (line  149)
 * Bezier curves:                         Bezier curves.      (line    6)
-* Bezier patch:                          three.              (line  118)
-* Bezier triangle:                       three.              (line  118)
-* bezulate:                              three.              (line  136)
+* Bezier patch:                          three.              (line  128)
+* Bezier triangle:                       three.              (line  128)
+* bezulate:                              three.              (line  146)
 * Bi:                                    Mathematical functions.
                                                              (line   48)
-* Billboard:                             three.              (line  510)
+* Billboard:                             three.              (line  526)
 * binary:                                Files.              (line   80)
 * binary format:                         Files.              (line   80)
 * binary operators:                      Arithmetic & logical.
@@ -8948,7 +9143,7 @@
 * binarytree:                            binarytree.         (line    6)
 * Bi_deriv:                              Mathematical functions.
                                                              (line   48)
-* black stripes:                         three.              (line  254)
+* black stripes:                         three.              (line  261)
 * Blank:                                 draw.               (line   26)
 * block.bottom:                          flowchart.          (line   19)
 * block.bottomleft:                      flowchart.          (line   19)
@@ -8967,16 +9162,17 @@
                                                              (line    6)
 * Bottom:                                graph.              (line  132)
 * BottomTop:                             graph.              (line  138)
-* BottomView:                            three.              (line  426)
+* BottomView:                            three.              (line  442)
 * bounding box:                          Frames and pictures.
                                                              (line  180)
+* bounds:                                palette.            (line   43)
 * Bounds:                                graph3.             (line   21)
 * box:                                   Frames and pictures.
                                                              (line   25)
 * box <1>:                               Frames and pictures.
                                                              (line  130)
-* box <2>:                               three.              (line  345)
-* box <3>:                               three.              (line  347)
+* box <2>:                               three.              (line  365)
+* box <3>:                               three.              (line  367)
 * bp:                                    Drawing in batch mode.
                                                              (line   23)
 * brace:                                 Paths and guides.   (line   51)
@@ -8983,7 +9179,7 @@
 * break:                                 Programming.        (line   48)
 * breakpoints:                           Debugger.           (line   21)
 * brick:                                 Pens.               (line  285)
-* broken axis:                           graph.              (line  801)
+* broken axis:                           graph.              (line  821)
 * bug reports:                           Help.               (line   19)
 * buildcycle:                            Paths and guides.   (line  270)
 * Button-1:                              GUI.                (line    6)
@@ -8994,7 +9190,7 @@
 * CAD:                                   CAD.                (line    6)
 * calculateTransform:                    Frames and pictures.
                                                              (line  118)
-* camera:                                three.              (line  392)
+* camera:                                three.              (line  412)
 * casts:                                 Casts.              (line    6)
 * cbrt:                                  Mathematical functions.
                                                              (line    6)
@@ -9002,7 +9198,7 @@
 * ceil:                                  Mathematical functions.
                                                              (line   26)
 * Center:                                label.              (line   60)
-* center:                                three.              (line  375)
+* center:                                three.              (line  395)
 * checker:                               Pens.               (line  285)
 * Chinese:                               Pens.               (line  244)
 * choose:                                Mathematical functions.
@@ -9011,7 +9207,7 @@
                                                              (line   48)
 * circle:                                Paths and guides.   (line   10)
 * Circle:                                Paths and guides.   (line   18)
-* circle <1>:                            three.              (line  319)
+* circle <1>:                            three.              (line  339)
 * circle <2>:                            flowchart.          (line   61)
 * circlebarframe:                        markers.            (line   18)
 * CJK:                                   Pens.               (line  244)
@@ -9034,7 +9230,9 @@
 * colorless:                             Pens.               (line   57)
 * colors:                                Pens.               (line   54)
 * comma:                                 Files.              (line   65)
-* comma-separated-value mode:            Arrays.             (line  370)
+* comma-separated-value mode:            Arrays.             (line  374)
+* command-line interface:                Command-Line Interface.
+                                                             (line    6)
 * command-line options:                  Configuring.        (line   91)
 * command-line options <1>:              Options.            (line    6)
 * comment character:                     Files.              (line   16)
@@ -9041,19 +9239,19 @@
 * compass directions:                    Labels.             (line   18)
 * Compiling from UNIX source:            Compiling from UNIX source.
                                                              (line    6)
-* complement:                            Arrays.             (line  145)
-* concat:                                Arrays.             (line  175)
+* complement:                            Arrays.             (line  149)
+* concat:                                Arrays.             (line  179)
 * conditional:                           Programming.        (line   26)
 * conditional <1>:                       Arithmetic & logical.
                                                              (line   61)
 * config:                                Configuring.        (line   74)
-* config <1>:                            Options.            (line  128)
+* config <1>:                            Options.            (line  138)
 * configuration file:                    Configuring.        (line   20)
-* configuration file <1>:                Options.            (line  128)
+* configuration file <1>:                Options.            (line  138)
 * configuring:                           Configuring.        (line    6)
 * conj:                                  Data types.         (line   62)
 * constructors:                          Structures.         (line   91)
-* context:                               Options.            (line  157)
+* context:                               Options.            (line  167)
 * continue:                              Programming.        (line   48)
 * continue <1>:                          Debugger.           (line   31)
 * contour:                               contour.            (line    6)
@@ -9064,10 +9262,10 @@
 * convert:                               Configuring.        (line   74)
 * convert <1>:                           Files.              (line  159)
 * convert <2>:                           animation.          (line    6)
-* convert <3>:                           Options.            (line  157)
-* convertOptions:                        Options.            (line  143)
+* convert <3>:                           Options.            (line  167)
+* convertOptions:                        Options.            (line  153)
 * Coons shading:                         fill.               (line   78)
-* copy:                                  Arrays.             (line  172)
+* copy:                                  Arrays.             (line  176)
 * cos:                                   Mathematical functions.
                                                              (line    6)
 * Cos:                                   Mathematical functions.
@@ -9082,16 +9280,16 @@
 * cross <2>:                             graph.              (line  480)
 * crossframe:                            markers.            (line   22)
 * crosshatch:                            Pens.               (line  302)
-* csv:                                   Arrays.             (line  370)
+* csv:                                   Arrays.             (line  374)
 * CTZ:                                   Arithmetic & logical.
                                                              (line   68)
-* cubicroots:                            Arrays.             (line  327)
+* cubicroots:                            Arrays.             (line  331)
 * curl:                                  Bezier curves.      (line   66)
 * curl <1>:                              three.              (line    6)
 * curlSpecifier:                         Paths and guides.   (line  408)
 * currentlight:                          three.              (line   76)
 * currentpen:                            Pens.               (line    6)
-* currentprojection:                     three.              (line  423)
+* currentprojection:                     three.              (line  439)
 * curve:                                 slopefield.         (line   20)
 * custom axis types:                     graph.              (line  141)
 * custom mark routine:                   graph.              (line  577)
@@ -9103,7 +9301,7 @@
 * cyclic:                                Paths and guides.   (line   85)
 * cyclic <1>:                            Paths and guides.   (line  376)
 * cyclic <2>:                            Arrays.             (line   39)
-* cyclic <3>:                            three.              (line  540)
+* cyclic <3>:                            three.              (line  556)
 * Cyrillic:                              Pens.               (line  237)
 * dashdotted:                            Pens.               (line  102)
 * dashed:                                Pens.               (line  102)
@@ -9117,7 +9315,7 @@
 * default arguments:                     Default arguments.  (line    6)
 * defaultformat:                         graph.              (line  175)
 * DefaultHead:                           draw.               (line   26)
-* DefaultHead3:                          three.              (line  606)
+* DefaultHead3:                          three.              (line  622)
 * defaultpen:                            Pens.               (line   49)
 * defaultpen <1>:                        Pens.               (line  122)
 * defaultpen <2>:                        Pens.               (line  127)
@@ -9135,17 +9333,17 @@
 * delete:                                Files.              (line  154)
 * delete <1>:                            Arrays.             (line   39)
 * description:                           Description.        (line    6)
-* devicepixelratio:                      three.              (line  174)
-* diagonal:                              Arrays.             (line  312)
+* devicepixelratio:                      three.              (line  184)
+* diagonal:                              Arrays.             (line  316)
 * diamond:                               flowchart.          (line   54)
 * diffuse:                               three.              (line   76)
 * diffusepen:                            three.              (line   66)
-* dimension:                             Arrays.             (line  375)
+* dimension:                             Arrays.             (line  379)
 * dir:                                   Search paths.       (line    9)
 * dir <1>:                               Data types.         (line   90)
 * dir <2>:                               Data types.         (line  181)
 * dir <3>:                               Paths and guides.   (line  109)
-* dir <4>:                               three.              (line  540)
+* dir <4>:                               three.              (line  556)
 * direction specifier:                   Bezier curves.      (line    6)
 * directory:                             Files.              (line   26)
 * dirSpecifier:                          Paths and guides.   (line  390)
@@ -9157,14 +9355,14 @@
 * dot:                                   draw.               (line   83)
 * dot <1>:                               Data types.         (line  103)
 * dot <2>:                               Data types.         (line  194)
-* dot <3>:                               Arrays.             (line  267)
-* dot <4>:                               Arrays.             (line  270)
+* dot <3>:                               Arrays.             (line  271)
+* dot <4>:                               Arrays.             (line  274)
 * DotMargin:                             draw.               (line   42)
-* DotMargin3:                            three.              (line  622)
+* DotMargin3:                            three.              (line  638)
 * DotMargins:                            draw.               (line   42)
-* DotMargins3:                           three.              (line  622)
+* DotMargins3:                           three.              (line  638)
 * dotted:                                Pens.               (line  102)
-* double deferred drawing:               three.              (line  297)
+* double deferred drawing:               three.              (line  317)
 * double precision:                      Files.              (line   80)
 * draw:                                  Drawing commands.   (line   34)
 * draw <1>:                              draw.               (line    6)
@@ -9172,15 +9370,15 @@
 * draw <2>:                              draw.               (line  113)
 * Draw <1>:                              Frames and pictures.
                                                              (line  160)
-* draw <3>:                              three.              (line  144)
+* draw <3>:                              three.              (line  154)
 * drawing commands:                      Drawing commands.   (line    6)
 * drawline:                              math.               (line    9)
 * drawtree:                              drawtree.           (line    6)
 * dvips:                                 Configuring.        (line   74)
-* dvipsOptions:                          Options.            (line  143)
+* dvipsOptions:                          Options.            (line  153)
 * dvisvgm:                               Configuring.        (line   74)
-* dvisvgm <1>:                           Options.            (line  162)
-* dvisvgmOptions:                        Options.            (line  143)
+* dvisvgm <1>:                           Options.            (line  172)
+* dvisvgmOptions:                        Options.            (line  153)
 * E:                                     Labels.             (line   18)
 * E <1>:                                 Mathematical functions.
                                                              (line   48)
@@ -9195,34 +9393,34 @@
 * else:                                  Programming.        (line   26)
 * emacs:                                 Editing modes.      (line    6)
 * embed:                                 embed.              (line    6)
-* Embedded:                              three.              (line  510)
+* Embedded:                              three.              (line  526)
 * emissivepen:                           three.              (line   66)
 * empty:                                 Frames and pictures.
                                                              (line    7)
 * EndArcArrow:                           draw.               (line   26)
-* EndArcArrow3:                          three.              (line  606)
+* EndArcArrow3:                          three.              (line  622)
 * EndArrow:                              draw.               (line   26)
-* EndArrow3:                             three.              (line  606)
+* EndArrow3:                             three.              (line  622)
 * EndBar:                                draw.               (line   19)
-* EndBar3:                               three.              (line  606)
+* EndBar3:                               three.              (line  622)
 * EndDotMargin:                          draw.               (line   42)
-* EndDotMargin3:                         three.              (line  622)
+* EndDotMargin3:                         three.              (line  638)
 * endl:                                  Files.              (line   65)
 * EndMargin:                             draw.               (line   42)
-* EndMargin3:                            three.              (line  622)
+* EndMargin3:                            three.              (line  638)
 * EndPenMargin:                          draw.               (line   42)
-* EndPenMargin2:                         three.              (line  622)
-* EndPenMargin3:                         three.              (line  622)
+* EndPenMargin2:                         three.              (line  638)
+* EndPenMargin3:                         three.              (line  638)
 * EndPoint:                              label.              (line   55)
 * envelope:                              Frames and pictures.
                                                              (line   25)
 * environment variables:                 Configuring.        (line   95)
 * eof:                                   Files.              (line   97)
-* eof <1>:                               Arrays.             (line  352)
+* eof <1>:                               Arrays.             (line  356)
 * eol:                                   Files.              (line   97)
-* eol <1>:                               Arrays.             (line  352)
+* eol <1>:                               Arrays.             (line  356)
 * EPS:                                   label.              (line   78)
-* EPS <1>:                               Options.            (line  157)
+* EPS <1>:                               Options.            (line  167)
 * erase:                                 Drawing in interactive mode.
                                                              (line   11)
 * erase <1>:                             Data types.         (line  257)
@@ -9259,20 +9457,20 @@
 * extension:                             Paths and guides.   (line  246)
 * extension <1>:                         MetaPost.           (line   10)
 * external:                              embed.              (line   11)
-* extrude:                               three.              (line  534)
+* extrude:                               three.              (line  550)
 * F:                                     Mathematical functions.
                                                              (line   48)
 * fabs:                                  Mathematical functions.
                                                              (line    6)
-* face:                                  three.              (line  646)
+* face:                                  three.              (line  662)
 * factorial:                             Mathematical functions.
                                                              (line   39)
 * Fedora:                                UNIX binary distributions.
                                                              (line   15)
 * feynman:                               feynman.            (line    6)
-* fft:                                   Arrays.             (line  245)
-* fft <1>:                               Arrays.             (line  259)
-* fft <2>:                               Arrays.             (line  263)
+* fft:                                   Arrays.             (line  249)
+* fft <1>:                               Arrays.             (line  263)
+* fft <2>:                               Arrays.             (line  267)
 * FFTW:                                  Compiling from UNIX source.
                                                              (line   62)
 * file:                                  Files.              (line    6)
@@ -9290,12 +9488,12 @@
 * filloutside:                           fill.               (line   27)
 * fillrule:                              Pens.               (line  164)
 * find:                                  Data types.         (line  242)
-* find <1>:                              Arrays.             (line  154)
-* findall:                               Arrays.             (line  159)
+* find <1>:                              Arrays.             (line  158)
+* findall:                               Arrays.             (line  163)
 * firstcut:                              Paths and guides.   (line  262)
 * fit:                                   Frames and pictures.
                                                              (line  113)
-* fit3:                                  three.              (line  310)
+* fit3:                                  three.              (line  330)
 * fixedscaling:                          Frames and pictures.
                                                              (line   81)
 * floor:                                 Mathematical functions.
@@ -9313,13 +9511,13 @@
 * fontsize:                              Pens.               (line  192)
 * for:                                   Programming.        (line   26)
 * format:                                Data types.         (line  290)
-* format <1>:                            Options.            (line  157)
+* format <1>:                            Options.            (line  167)
 * forum:                                 Help.               (line    6)
 * frame:                                 Frames and pictures.
                                                              (line    7)
 * freshnel0:                             three.              (line   66)
 * from:                                  Import.             (line   16)
-* FrontView:                             three.              (line  426)
+* FrontView:                             three.              (line  442)
 * function declarations:                 Functions.          (line   79)
 * Function shading:                      fill.               (line  100)
 * function shading:                      fill.               (line  100)
@@ -9340,8 +9538,8 @@
 * git:                                   Git.                (line    6)
 * globalwrite:                           Files.              (line   40)
 * globalwrite <1>:                       Files.              (line  154)
-* glOptions:                             three.              (line  254)
-* glOptions <1>:                         Options.            (line  143)
+* glOptions:                             three.              (line  261)
+* glOptions <1>:                         Options.            (line  153)
 * GNU Scientific Library:                Mathematical functions.
                                                              (line   48)
 * gouraudshade:                          fill.               (line   63)
@@ -9350,13 +9548,14 @@
 * graph:                                 graph.              (line    6)
 * graph3:                                graph3.             (line    6)
 * graphic:                               label.              (line   78)
-* graphic <1>:                           Options.            (line  162)
+* graphic <1>:                           Options.            (line  172)
 * graphical user interface:              GUI.                (line    6)
+* graphwithderiv:                        graph.              (line  670)
 * gray:                                  Pens.               (line   25)
 * grayscale:                             Pens.               (line   25)
 * Grayscale:                             palette.            (line    9)
 * grid:                                  Pens.               (line  285)
-* grid <1>:                              graph.              (line  746)
+* grid <1>:                              graph.              (line  766)
 * grid3:                                 grid3.              (line    6)
 * gs:                                    Configuring.        (line   20)
 * GSL:                                   Compiling from UNIX source.
@@ -9363,7 +9562,7 @@
                                                              (line   62)
 * gsl:                                   Mathematical functions.
                                                              (line   48)
-* gsOptions:                             Options.            (line  143)
+* gsOptions:                             Options.            (line  153)
 * GUI:                                   GUI.                (line    6)
 * GUI installation:                      GUI installation.   (line    6)
 * GUI usage:                             GUI usage.          (line    6)
@@ -9381,7 +9580,7 @@
 * hex <1>:                               Pens.               (line   64)
 * hexadecimal:                           Data types.         (line  306)
 * hexadecimal <1>:                       Pens.               (line   62)
-* hidden surface removal:                three.              (line  646)
+* hidden surface removal:                three.              (line  662)
 * histogram:                             Mathematical functions.
                                                              (line   39)
 * history:                               Files.              (line  147)
@@ -9388,31 +9587,33 @@
 * history <1>:                           Interactive mode.   (line   54)
 * historylines:                          Interactive mode.   (line   57)
 * HookHead:                              draw.               (line   26)
-* HookHead3:                             three.              (line  606)
+* HookHead3:                             three.              (line  622)
 * Horizontal:                            flowchart.          (line   77)
-* HTML5:                                 three.              (line  223)
+* HTML5:                                 three.              (line  233)
 * htmlviewer:                            Configuring.        (line   20)
 * htmlviewer <1>:                        Configuring.        (line   43)
-* htmlviewerOptions:                     Options.            (line  143)
-* hyperrefOptions:                       Options.            (line  143)
+* htmlviewerOptions:                     Options.            (line  153)
+* hyperrefOptions:                       Options.            (line  153)
 * hypot:                                 Mathematical functions.
                                                              (line    6)
 * I:                                     Mathematical functions.
                                                              (line   48)
-* iconify:                               three.              (line  254)
+* ibl:                                   three.              (line  104)
+* iconify:                               three.              (line  261)
 * identity:                              Transforms.         (line   24)
 * identity <1>:                          Mathematical functions.
                                                              (line    6)
-* identity <2>:                          Arrays.             (line  309)
-* identity4:                             three.              (line  478)
+* identity <2>:                          Arrays.             (line  313)
+* identity4:                             three.              (line  494)
 * if:                                    Programming.        (line   26)
 * IgnoreAspect:                          Frames and pictures.
                                                              (line   63)
 * image:                                 palette.            (line   33)
-* image <1>:                             palette.            (line   58)
+* image <1>:                             palette.            (line   61)
+* image-based lighting:                  three.              (line  104)
 * ImageMagick:                           Configuring.        (line   74)
 * ImageMagick <1>:                       animation.          (line    6)
-* ImageMagick <2>:                       Options.            (line  157)
+* ImageMagick <2>:                       Options.            (line  167)
 * images:                                palette.            (line    6)
 * implicit casts:                        Casts.              (line    6)
 * implicit linear solver:                MetaPost.           (line   10)
@@ -9419,6 +9620,7 @@
 * implicit scaling:                      Implicit scaling.   (line    6)
 * implicitsurface:                       smoothcontour3.     (line   16)
 * import:                                Import.             (line   45)
+* importv3d:                             three.              (line  308)
 * inches:                                Figure size.        (line   18)
 * incircle:                              Data types.         (line  120)
 * include:                               Import.             (line  134)
@@ -9441,7 +9643,7 @@
 * inside:                                Paths and guides.   (line  294)
 * inside <1>:                            Paths and guides.   (line  299)
 * inside <2>:                            Paths and guides.   (line  305)
-* insphere:                              three.              (line  569)
+* insphere:                              three.              (line  585)
 * inst:                                  Debugger.           (line   35)
 * installation:                          Installation.       (line    6)
 * int:                                   Data types.         (line   30)
@@ -9460,23 +9662,23 @@
 * interpolate:                           interpolate.        (line    6)
 * intersect:                             Paths and guides.   (line  195)
 * intersect <1>:                         math.               (line   13)
-* intersect <2>:                         three.              (line  540)
+* intersect <2>:                         three.              (line  556)
 * intersectionpoint:                     Paths and guides.   (line  238)
 * intersectionpoint <1>:                 math.               (line   17)
-* intersectionpoint <2>:                 three.              (line  540)
+* intersectionpoint <2>:                 three.              (line  556)
 * intersectionpoints:                    Paths and guides.   (line  242)
-* intersectionpoints <1>:                three.              (line  540)
-* intersectionpoints <2>:                three.              (line  553)
+* intersectionpoints <1>:                three.              (line  556)
+* intersectionpoints <2>:                three.              (line  569)
 * intersections:                         Paths and guides.   (line  206)
 * intersections <1>:                     Paths and guides.   (line  213)
-* intersections <2>:                     three.              (line  540)
-* intersections <3>:                     three.              (line  546)
+* intersections <2>:                     three.              (line  556)
+* intersections <3>:                     three.              (line  562)
 * InTicks:                               graph3.             (line   35)
 * intMax:                                Data types.         (line   30)
 * intMin:                                Data types.         (line   30)
 * inverse:                               Transforms.         (line   16)
-* inverse <1>:                           Arrays.             (line  315)
-* invert:                                three.              (line  468)
+* inverse <1>:                           Arrays.             (line  319)
+* invert:                                three.              (line  484)
 * invisible:                             Pens.               (line   43)
 * isnan:                                 Data types.         (line   35)
 * i_scaled:                              Mathematical functions.
@@ -9495,7 +9697,7 @@
 * keepAspect <1>:                        Frames and pictures.
                                                              (line   63)
 * keepAspect <2>:                        LaTeX usage.        (line   50)
-* keyboard bindings::                    three.              (line  201)
+* keyboard bindings::                    three.              (line  211)
 * keys:                                  Arrays.             (line   39)
 * keyword:                               Named arguments.    (line   37)
 * keyword-only:                          Named arguments.    (line   37)
@@ -9508,7 +9710,7 @@
 * label <1>:                             label.              (line    6)
 * Label <1>:                             label.              (line   14)
 * Label <2>:                             graph.              (line  330)
-* label <2>:                             three.              (line  504)
+* label <2>:                             three.              (line  520)
 * labelpath:                             labelpath.          (line    6)
 * labelpath3:                            labelpath3.         (line    6)
 * labelx:                                graph.              (line  330)
@@ -9516,9 +9718,11 @@
 * Landscape:                             Frames and pictures.
                                                              (line  104)
 * language context:                      Pens.               (line  235)
+* language server protocol:              Language server protocol.
+                                                             (line    6)
 * lastcut:                               Paths and guides.   (line  266)
 * lasy-mode:                             Editing modes.      (line    6)
-* latex:                                 Options.            (line  157)
+* latex:                                 Options.            (line  167)
 * LaTeX NFSS fonts:                      Pens.               (line  206)
 * LaTeX usage:                           LaTeX usage.        (line    6)
 * latexmk:                               LaTeX usage.        (line   30)
@@ -9526,13 +9730,13 @@
 * latticeshade:                          fill.               (line   32)
 * layer:                                 Drawing commands.   (line   16)
 * leastsquares:                          stats.              (line    6)
-* leastsquares <1>:                      graph.              (line  929)
+* leastsquares <1>:                      graph.              (line  948)
 * Left:                                  graph.              (line  269)
 * LeftRight:                             graph.              (line  275)
 * LeftSide:                              label.              (line   60)
 * LeftTicks:                             graph.              (line  160)
 * LeftTicks <1>:                         graph.              (line  233)
-* LeftView:                              three.              (line  426)
+* LeftView:                              three.              (line  442)
 * legend:                                Drawing commands.   (line   34)
 * legend <1>:                            draw.               (line   65)
 * legend <2>:                            graph.              (line  424)
@@ -9544,12 +9748,12 @@
 * length <3>:                            Paths and guides.   (line   76)
 * length <4>:                            Paths and guides.   (line  373)
 * length <5>:                            Arrays.             (line   39)
-* length <6>:                            three.              (line  540)
+* length <6>:                            three.              (line  556)
 * letter:                                Configuring.        (line   68)
 * lexorder:                              math.               (line   63)
 * lexorder <1>:                          math.               (line   66)
 * libcurl:                               Import.             (line   94)
-* libgs:                                 Options.            (line  162)
+* libgs:                                 Options.            (line  172)
 * libm routines:                         Mathematical functions.
                                                              (line    6)
 * libsigsegv:                            Functions.          (line  100)
@@ -9556,10 +9760,10 @@
 * libsigsegv <1>:                        Help.               (line   27)
 * light:                                 three.              (line   76)
 * limits:                                graph.              (line  639)
-* line:                                  Arrays.             (line  352)
-* line <1>:                              Arrays.             (line  356)
-* line mode:                             Arrays.             (line  352)
-* Linear:                                graph.              (line  690)
+* line:                                  Arrays.             (line  356)
+* line <1>:                              Arrays.             (line  360)
+* line mode:                             Arrays.             (line  356)
+* Linear:                                graph.              (line  710)
 * linecap:                               Pens.               (line  139)
 * linejoin:                              Pens.               (line  149)
 * lineskip:                              Pens.               (line  192)
@@ -9568,14 +9772,14 @@
 * locale:                                Data types.         (line  316)
 * log:                                   Mathematical functions.
                                                              (line    6)
-* Log:                                   graph.              (line  690)
-* log-log graph:                         graph.              (line  724)
+* Log:                                   graph.              (line  710)
+* log-log graph:                         graph.              (line  744)
 * log10:                                 Mathematical functions.
                                                              (line    6)
 * log1p:                                 Mathematical functions.
                                                              (line    6)
-* log2 graph:                            graph.              (line  780)
-* logarithmic graph:                     graph.              (line  724)
+* log2 graph:                            graph.              (line  800)
+* logarithmic graph:                     graph.              (line  744)
 * logical operators:                     Arithmetic & logical.
                                                              (line    6)
 * longdashdotted:                        Pens.               (line  102)
@@ -9582,23 +9786,25 @@
 * longdashed:                            Pens.               (line  102)
 * longitude:                             Data types.         (line  169)
 * loop:                                  Programming.        (line   26)
-* lualatex:                              Options.            (line  157)
-* luatex:                                Options.            (line  157)
+* LSP:                                   Language server protocol.
+                                                             (line    6)
+* lualatex:                              Options.            (line  167)
+* luatex:                                Options.            (line  167)
 * MacOS X binary distributions:          MacOS X binary distributions.
                                                              (line    6)
 * MacOS X configuration:                 Compiling from UNIX source.
                                                              (line   48)
 * makepen:                               Pens.               (line  338)
-* map:                                   Arrays.             (line  131)
-* map <1>:                               Arrays.             (line  136)
+* map:                                   Arrays.             (line  135)
+* map <1>:                               Arrays.             (line  140)
 * map <2>:                               map.                (line    6)
 * Margin:                                draw.               (line   42)
 * Margin <1>:                            draw.               (line   42)
-* Margin3:                               three.              (line  622)
-* Margin3 <1>:                           three.              (line  622)
+* Margin3:                               three.              (line  638)
+* Margin3 <1>:                           three.              (line  638)
 * Margins:                               draw.               (line   42)
-* margins:                               three.              (line  303)
-* Margins3:                              three.              (line  622)
+* margins:                               three.              (line  323)
+* Margins3:                              three.              (line  638)
 * mark:                                  graph.              (line  480)
 * markangle:                             markers.            (line   35)
 * marker:                                graph.              (line  480)
@@ -9613,14 +9819,14 @@
 * max:                                   Paths and guides.   (line  279)
 * max <1>:                               Frames and pictures.
                                                              (line    7)
-* max <2>:                               Arrays.             (line  226)
-* max <3>:                               Arrays.             (line  236)
-* max <4>:                               three.              (line  540)
+* max <2>:                               Arrays.             (line  230)
+* max <3>:                               Arrays.             (line  240)
+* max <4>:                               three.              (line  556)
 * maxbound:                              Data types.         (line  134)
 * maxbound <1>:                          Data types.         (line  205)
-* maxtile:                               three.              (line  254)
+* maxtile:                               three.              (line  261)
 * maxtimes:                              Paths and guides.   (line  233)
-* maxviewport:                           three.              (line  254)
+* maxviewport:                           three.              (line  261)
 * metallic:                              three.              (line   66)
 * MetaPost:                              MetaPost.           (line    6)
 * MetaPost ... :                         Bezier curves.      (line   70)
@@ -9630,17 +9836,17 @@
 * MetaPost whatever:                     MetaPost.           (line   10)
 * Microsoft Windows:                     Microsoft Windows.  (line    6)
 * MidArcArrow:                           draw.               (line   26)
-* MidArcArrow3:                          three.              (line  606)
+* MidArcArrow3:                          three.              (line  622)
 * MidArrow:                              draw.               (line   26)
-* MidArrow3:                             three.              (line  606)
+* MidArrow3:                             three.              (line  622)
 * MidPoint:                              label.              (line   55)
 * midpoint:                              Paths and guides.   (line  180)
 * min:                                   Paths and guides.   (line  275)
 * min <1>:                               Frames and pictures.
                                                              (line    7)
-* min <2>:                               Arrays.             (line  221)
-* min <3>:                               Arrays.             (line  231)
-* min <4>:                               three.              (line  540)
+* min <2>:                               Arrays.             (line  225)
+* min <3>:                               Arrays.             (line  235)
+* min <4>:                               three.              (line  556)
 * minbound:                              Data types.         (line  131)
 * minbound <1>:                          Data types.         (line  202)
 * minipage:                              label.              (line  116)
@@ -9649,16 +9855,16 @@
 * miterlimit:                            Pens.               (line  159)
 * mktemp:                                Files.              (line   48)
 * mm:                                    Figure size.        (line   18)
-* mobile browser:                        three.              (line  223)
+* mobile browser:                        three.              (line  233)
 * mode:                                  Files.              (line   80)
 * mode <1>:                              Files.              (line   93)
 * monotonic:                             graph.              (line   36)
 * mouse:                                 GUI.                (line    6)
-* mouse bindings:                        three.              (line  182)
+* mouse bindings:                        three.              (line  192)
 * mouse wheel:                           GUI usage.          (line    6)
 * Move:                                  Pens.               (line  375)
 * MoveQuiet:                             Pens.               (line  381)
-* multisample:                           three.              (line  174)
+* multisample:                           three.              (line  184)
 * N:                                     Labels.             (line   18)
 * name:                                  Files.              (line   93)
 * named arguments:                       Named arguments.    (line    6)
@@ -9684,12 +9890,12 @@
 * noglobalread <1>:                      Files.              (line   40)
 * nolight:                               three.              (line   76)
 * NoMargin:                              draw.               (line   42)
-* NoMargin3:                             three.              (line  622)
+* NoMargin3:                             three.              (line  638)
 * None:                                  draw.               (line   19)
 * None <1>:                              draw.               (line   26)
 * none:                                  Files.              (line   65)
-* normal:                                three.              (line  526)
-* nosafe:                                Options.            (line  182)
+* normal:                                three.              (line  542)
+* nosafe:                                Options.            (line  192)
 * NOT:                                   Arithmetic & logical.
                                                              (line   68)
 * notaknot:                              graph.              (line   36)
@@ -9701,16 +9907,16 @@
                                                              (line  140)
 * nullpen <2>:                           Frames and pictures.
                                                              (line  149)
-* NURBS:                                 three.              (line  402)
-* O:                                     three.              (line  315)
+* NURBS:                                 three.              (line  422)
+* O:                                     three.              (line  335)
 * obj:                                   obj.                (line    6)
-* oblique:                               three.              (line  358)
-* obliqueX:                              three.              (line  365)
-* obliqueY:                              three.              (line  371)
-* obliqueZ:                              three.              (line  358)
+* oblique:                               three.              (line  378)
+* obliqueX:                              three.              (line  385)
+* obliqueY:                              three.              (line  391)
+* obliqueZ:                              three.              (line  378)
 * ode:                                   ode.                (line    6)
 * offset:                                Pens.               (line  123)
-* offset <1>:                            Options.            (line  187)
+* offset <1>:                            Options.            (line  197)
 * OmitTick:                              graph.              (line  223)
 * OmitTickInterval:                      graph.              (line  223)
 * OmitTickIntervals:                     graph.              (line  223)
@@ -9717,7 +9923,7 @@
 * opacity:                               Pens.               (line  254)
 * opacity <1>:                           three.              (line   66)
 * open:                                  Files.              (line   12)
-* OpenGL:                                three.              (line  174)
+* OpenGL:                                three.              (line  184)
 * operator:                              User-defined operators.
                                                              (line    6)
 * operator +(...string[] a).:            Data types.         (line  284)
@@ -9734,15 +9940,15 @@
 * OR:                                    Arithmetic & logical.
                                                              (line   68)
 * orient:                                Data types.         (line  108)
-* orient <1>:                            three.              (line  557)
+* orient <1>:                            three.              (line  573)
 * orientation:                           Frames and pictures.
                                                              (line  104)
-* orthographic:                          three.              (line  375)
-* outformat:                             three.              (line  174)
+* orthographic:                          three.              (line  395)
+* outformat:                             three.              (line  184)
 * outprefix:                             Frames and pictures.
                                                              (line   91)
 * output:                                Files.              (line   38)
-* output <1>:                            Options.            (line  157)
+* output <1>:                            Options.            (line  167)
 * OutTicks:                              graph3.             (line   35)
 * overloading functions:                 Functions.          (line   55)
 * overwrite:                             Pens.               (line  360)
@@ -9754,7 +9960,7 @@
                                                              (line  186)
 * pair:                                  Figure size.        (line    6)
 * pair <1>:                              Data types.         (line   46)
-* pairs:                                 Arrays.             (line  241)
+* pairs:                                 Arrays.             (line  245)
 * paperheight:                           Configuring.        (line   68)
 * papertype:                             Configuring.        (line   68)
 * paperwidth:                            Configuring.        (line   68)
@@ -9763,7 +9969,7 @@
 * parametrized curve:                    graph.              (line  639)
 * partialsum:                            math.               (line   49)
 * partialsum <1>:                        math.               (line   52)
-* patch-dependent colors:                three.              (line  109)
+* patch-dependent colors:                three.              (line  119)
 * path:                                  Paths.              (line    6)
 * path <1>:                              Paths and guides.   (line    7)
 * path <2>:                              three.              (line   42)
@@ -9775,22 +9981,22 @@
 * patterns:                              Pens.               (line  271)
 * patterns <1>:                          patterns.           (line    6)
 * PBR:                                   three.              (line   74)
-* PDF:                                   Options.            (line  157)
-* pdflatex:                              Options.            (line  157)
-* pdfreloadOptions:                      Options.            (line  143)
+* PDF:                                   Options.            (line  167)
+* pdflatex:                              Options.            (line  167)
+* pdfreloadOptions:                      Options.            (line  153)
 * pdfviewer:                             Configuring.        (line   20)
-* pdfviewerOptions:                      Options.            (line  143)
+* pdfviewerOptions:                      Options.            (line  153)
 * pen:                                   Pens.               (line    6)
 * PenMargin:                             draw.               (line   42)
-* PenMargin2:                            three.              (line  622)
-* PenMargin3:                            three.              (line  622)
+* PenMargin2:                            three.              (line  638)
+* PenMargin3:                            three.              (line  638)
 * PenMargins:                            draw.               (line   42)
-* PenMargins2:                           three.              (line  622)
-* PenMargins3:                           three.              (line  622)
+* PenMargins2:                           three.              (line  638)
+* PenMargins3:                           three.              (line  638)
 * periodic:                              graph.              (line   36)
 * perl:                                  LaTeX usage.        (line   30)
 * perpendicular:                         geometry.           (line    6)
-* perspective:                           three.              (line  402)
+* perspective:                           three.              (line  422)
 * physically based rendering:            three.              (line   74)
 * picture:                               Frames and pictures.
                                                              (line   39)
@@ -9797,16 +10003,16 @@
 * picture alignment:                     Frames and pictures.
                                                              (line  231)
 * piecewisestraight:                     Paths and guides.   (line   92)
-* pixel:                                 three.              (line  629)
+* pixel:                                 three.              (line  645)
 * Pl:                                    Mathematical functions.
                                                              (line   48)
 * plain:                                 plain.              (line    6)
-* planar:                                three.              (line  118)
-* plane:                                 three.              (line  341)
-* planeproject:                          three.              (line  523)
+* planar:                                three.              (line  128)
+* plane:                                 three.              (line  361)
+* planeproject:                          three.              (line  539)
 * point:                                 Paths and guides.   (line   95)
 * point <1>:                             Paths and guides.   (line  379)
-* point <2>:                             three.              (line  540)
+* point <2>:                             three.              (line  556)
 * polar:                                 Data types.         (line  149)
 * polargraph:                            graph.              (line   88)
 * polygon:                               graph.              (line  480)
@@ -9814,9 +10020,9 @@
 * Portrait:                              Frames and pictures.
                                                              (line  104)
 * position:                              three.              (line   76)
-* position <1>:                          three.              (line  174)
+* position <1>:                          three.              (line  184)
 * postcontrol:                           Paths and guides.   (line  146)
-* postcontrol <1>:                       three.              (line  540)
+* postcontrol <1>:                       three.              (line  556)
 * postfix operators:                     Self & prefix operators.
                                                              (line   19)
 * postscript:                            Frames and pictures.
@@ -9825,10 +10031,10 @@
 * PostScript subpath:                    Paths.              (line   23)
 * pow10:                                 Mathematical functions.
                                                              (line    6)
-* prc:                                   three.              (line  272)
+* prc:                                   three.              (line  279)
 * precision:                             Files.              (line   97)
 * precontrol:                            Paths and guides.   (line  139)
-* precontrol <1>:                        three.              (line  540)
+* precontrol <1>:                        three.              (line  556)
 * prefix operators:                      Self & prefix operators.
                                                              (line    6)
 * private:                               Structures.         (line    6)
@@ -9836,15 +10042,15 @@
 * pstoedit:                              PostScript to Asymptote.
                                                              (line    6)
 * psviewer:                              Configuring.        (line   20)
-* psviewerOptions:                       Options.            (line  143)
+* psviewerOptions:                       Options.            (line  153)
 * pt:                                    Figure size.        (line   18)
 * public:                                Structures.         (line    6)
 * push:                                  Arrays.             (line   39)
 * Python usage:                          Interactive mode.   (line   72)
-* quadraticroots:                        Arrays.             (line  318)
-* quadraticroots <1>:                    Arrays.             (line  323)
+* quadraticroots:                        Arrays.             (line  322)
+* quadraticroots <1>:                    Arrays.             (line  327)
 * quarticroots:                          math.               (line   22)
-* quick reference:                       Description.        (line   88)
+* quick reference:                       Description.        (line   92)
 * quit:                                  Drawing in interactive mode.
                                                              (line   11)
 * quit <1>:                              Interactive mode.   (line   54)
@@ -9860,15 +10066,15 @@
 * radians:                               Mathematical functions.
                                                              (line   17)
 * radius:                                Paths and guides.   (line  135)
-* radius <1>:                            three.              (line  540)
+* radius <1>:                            three.              (line  556)
 * Rainbow:                               palette.            (line   12)
 * rand:                                  Mathematical functions.
                                                              (line   39)
 * randMax:                               Mathematical functions.
                                                              (line   39)
-* read:                                  Arrays.             (line  392)
+* read:                                  Arrays.             (line  396)
 * reading:                               Files.              (line   12)
-* reading string arrays:                 Arrays.             (line  362)
+* reading string arrays:                 Arrays.             (line  366)
 * readline:                              Files.              (line  139)
 * real:                                  Data types.         (line   35)
 * realDigits:                            Data types.         (line   35)
@@ -9878,7 +10084,7 @@
 * realmult:                              Data types.         (line  100)
 * rectangle:                             flowchart.          (line   34)
 * recursion:                             Functions.          (line  100)
-* reference:                             Description.        (line   88)
+* reference:                             Description.        (line   92)
 * reflect:                               Transforms.         (line   42)
 * Relative:                              label.              (line   50)
 * Relative <1>:                          label.              (line   60)
@@ -9888,8 +10094,8 @@
                                                              (line    6)
 * rename:                                Files.              (line  156)
 * render:                                three.              (line   46)
-* render <1>:                            three.              (line  174)
-* render <2>:                            Options.            (line  157)
+* render <1>:                            three.              (line  184)
+* render <2>:                            Options.            (line  167)
 * replace:                               Data types.         (line  270)
 * resetdefaultpen:                       Pens.               (line  387)
 * rest arguments:                        Rest arguments.     (line    6)
@@ -9900,8 +10106,8 @@
 * reverse:                               Data types.         (line  266)
 * reverse <1>:                           Paths and guides.   (line  183)
 * reverse <2>:                           Paths and guides.   (line  382)
-* reverse <3>:                           Arrays.             (line  141)
-* reverse <4>:                           three.              (line  540)
+* reverse <3>:                           Arrays.             (line  145)
+* reverse <4>:                           three.              (line  556)
 * rewind:                                Files.              (line   97)
 * rfind:                                 Data types.         (line  247)
 * rgb:                                   Pens.               (line   30)
@@ -9913,9 +10119,9 @@
 * RightSide:                             label.              (line   60)
 * RightTicks:                            graph.              (line  160)
 * RightTicks <1>:                        graph.              (line  233)
-* RightView:                             three.              (line  426)
+* RightView:                             three.              (line  442)
 * Rotate:                                label.              (line   36)
-* rotate:                                three.              (line  494)
+* rotate:                                three.              (line  510)
 * Rotate(pair z):                        label.              (line   39)
 * round:                                 Mathematical functions.
                                                              (line   26)
@@ -9928,7 +10134,7 @@
 * runtime imports:                       Import.             (line  102)
 * Russian:                               Pens.               (line  237)
 * S:                                     Labels.             (line   18)
-* safe:                                  Options.            (line  182)
+* safe:                                  Options.            (line  192)
 * save:                                  Frames and pictures.
                                                              (line  288)
 * saveline:                              Files.              (line  139)
@@ -9936,21 +10142,21 @@
 * scale:                                 Pens.               (line  123)
 * scale <1>:                             Transforms.         (line   34)
 * scale <2>:                             Transforms.         (line   36)
-* scale <3>:                             graph.              (line  690)
-* Scale <1>:                             graph.              (line  707)
-* scale <4>:                             three.              (line  493)
-* scale3:                                three.              (line  491)
-* scaled graph:                          graph.              (line  670)
+* scale <3>:                             graph.              (line  710)
+* Scale <1>:                             graph.              (line  727)
+* scale <4>:                             three.              (line  509)
+* scale3:                                three.              (line  507)
+* scaled graph:                          graph.              (line  690)
 * scientific graph:                      graph.              (line  387)
 * scroll:                                Files.              (line  113)
-* search:                                Arrays.             (line  162)
-* search <1>:                            Arrays.             (line  168)
+* search:                                Arrays.             (line  166)
+* search <1>:                            Arrays.             (line  172)
 * search paths:                          Search paths.       (line    6)
 * Seascape:                              Frames and pictures.
                                                              (line  110)
-* secondary axis:                        graph.              (line  833)
-* secondaryX:                            graph.              (line  833)
-* secondaryY:                            graph.              (line  833)
+* secondary axis:                        graph.              (line  853)
+* secondaryX:                            graph.              (line  853)
+* secondaryY:                            graph.              (line  853)
 * seconds:                               Data types.         (line  330)
 * seek:                                  Files.              (line   97)
 * seekeof:                               Files.              (line   97)
@@ -9960,7 +10166,7 @@
                                                              (line    6)
 * sequence:                              Arrays.             (line  118)
 * settings:                              Configuring.        (line   20)
-* settings <1>:                          Options.            (line  128)
+* settings <1>:                          Options.            (line  138)
 * sgn:                                   Mathematical functions.
                                                              (line   26)
 * shading:                               fill.               (line   32)
@@ -9968,12 +10174,12 @@
 * shift:                                 Transforms.         (line   26)
 * shift <1>:                             Transforms.         (line   28)
 * shift <2>:                             Transforms.         (line   46)
-* shift <3>:                             three.              (line  483)
+* shift <3>:                             three.              (line  499)
 * shiftless:                             Transforms.         (line   46)
 * shininess:                             three.              (line   66)
 * shipout:                               Frames and pictures.
                                                              (line   91)
-* showtarget:                            three.              (line  375)
+* showtarget:                            three.              (line  395)
 * Si:                                    Mathematical functions.
                                                              (line   48)
 * signedint:                             Files.              (line   80)
@@ -9993,9 +10199,9 @@
 * singlereal <1>:                        Files.              (line   93)
 * sinh:                                  Mathematical functions.
                                                              (line    6)
-* SixViews:                              three.              (line  441)
-* SixViewsFR:                            three.              (line  441)
-* SixViewsUS:                            three.              (line  441)
+* SixViews:                              three.              (line  457)
+* SixViewsFR:                            three.              (line  457)
+* SixViewsUS:                            three.              (line  457)
 * size:                                  Figure size.        (line    6)
 * size <1>:                              Paths and guides.   (line   81)
 * size <2>:                              Paths and guides.   (line  370)
@@ -10003,9 +10209,9 @@
                                                              (line   48)
 * size <4>:                              Frames and pictures.
                                                              (line   74)
-* size <5>:                              three.              (line  540)
-* size <6>:                              Options.            (line  157)
-* size3:                                 three.              (line  300)
+* size <5>:                              three.              (line  556)
+* size <6>:                              Options.            (line  167)
+* size3:                                 three.              (line  320)
 * Slant:                                 label.              (line   42)
 * slant:                                 Transforms.         (line   38)
 * sleep:                                 Data types.         (line  376)
@@ -10021,11 +10227,11 @@
                                                              (line   48)
 * solid:                                 Pens.               (line  102)
 * solids:                                solids.             (line    6)
-* solve:                                 Arrays.             (line  287)
-* solve <1>:                             Arrays.             (line  303)
-* sort:                                  Arrays.             (line  182)
-* sort <1>:                              Arrays.             (line  186)
-* sort <2>:                              Arrays.             (line  201)
+* solve:                                 Arrays.             (line  291)
+* solve <1>:                             Arrays.             (line  307)
+* sort:                                  Arrays.             (line  186)
+* sort <1>:                              Arrays.             (line  190)
+* sort <2>:                              Arrays.             (line  205)
 * specular:                              three.              (line   76)
 * specularfactor:                        three.              (line   76)
 * specularpen:                           three.              (line   66)
@@ -10049,7 +10255,7 @@
 * stop:                                  Debugger.           (line   10)
 * straight:                              Paths and guides.   (line   88)
 * Straight:                              graph.              (line   30)
-* straight <1>:                          three.              (line  540)
+* straight <1>:                          three.              (line  556)
 * strftime:                              Data types.         (line  321)
 * strftime <1>:                          Data types.         (line  346)
 * string:                                Data types.         (line  208)
@@ -10061,21 +10267,22 @@
 * struct:                                Structures.         (line    6)
 * structures:                            Structures.         (line    6)
 * subpath:                               Paths and guides.   (line  186)
-* subpath <1>:                           three.              (line  540)
+* subpath <1>:                           three.              (line  556)
 * subpictures:                           Frames and pictures.
                                                              (line  113)
 * substr:                                Data types.         (line  262)
-* sum:                                   Arrays.             (line  216)
+* sum:                                   Arrays.             (line  220)
 * superpath:                             Paths.              (line   23)
 * Suppress:                              Pens.               (line  367)
 * SuppressQuiet:                         Pens.               (line  371)
 * surface:                               three.              (line   46)
-* surface <1>:                           three.              (line  118)
-* surface <2>:                           three.              (line  132)
-* surface <3>:                           graph3.             (line   99)
-* SVG:                                   Options.            (line  162)
+* surface <1>:                           three.              (line  104)
+* surface <2>:                           three.              (line  128)
+* surface <3>:                           three.              (line  142)
+* surface <4>:                           graph3.             (line   99)
+* SVG:                                   Options.            (line  172)
 * system:                                Data types.         (line  354)
-* system <1>:                            Options.            (line  182)
+* system <1>:                            Options.            (line  192)
 * syzygy:                                syzygy.             (line    6)
 * tab:                                   Files.              (line   65)
 * tab completion:                        Drawing in interactive mode.
@@ -10086,7 +10293,7 @@
                                                              (line   20)
 * tanh:                                  Mathematical functions.
                                                              (line    6)
-* target:                                three.              (line  375)
+* target:                                three.              (line  395)
 * tell:                                  Files.              (line   97)
 * tension:                               Bezier curves.      (line   56)
 * tension <1>:                           three.              (line    6)
@@ -10093,15 +10300,15 @@
 * tensionSpecifier:                      Paths and guides.   (line  402)
 * tensor product shading:                fill.               (line   78)
 * tensorshade:                           fill.               (line   78)
-* tessellation:                          three.              (line  144)
+* tessellation:                          three.              (line  154)
 * tex:                                   Frames and pictures.
                                                              (line  305)
-* tex <1>:                               Options.            (line  157)
+* tex <1>:                               Options.            (line  167)
 * TeX fonts:                             Pens.               (line  213)
 * TeX string:                            Data types.         (line  208)
 * texcommand:                            Configuring.        (line   74)
 * TeXHead:                               draw.               (line   26)
-* TeXHead3:                              three.              (line  606)
+* TeXHead3:                              three.              (line  622)
 * texpath:                               Configuring.        (line   74)
 * texpath <1>:                           label.              (line  113)
 * texpreamble:                           Frames and pictures.
@@ -10111,13 +10318,13 @@
 * textbook graph:                        graph.              (line  360)
 * tgz:                                   UNIX binary distributions.
                                                              (line    6)
-* thick:                                 three.              (line  156)
-* thin:                                  three.              (line  156)
+* thick:                                 three.              (line  166)
+* thin:                                  three.              (line  166)
 * this:                                  Structures.         (line    6)
 * three:                                 three.              (line    6)
-* ThreeViews:                            three.              (line  441)
-* ThreeViewsFR:                          three.              (line  441)
-* ThreeViewsUS:                          three.              (line  441)
+* ThreeViews:                            three.              (line  457)
+* ThreeViewsFR:                          three.              (line  457)
+* ThreeViewsUS:                          three.              (line  457)
 * tick:                                  graph.              (line  330)
 * ticks:                                 graph.              (line  160)
 * Ticks:                                 graph.              (line  160)
@@ -10132,28 +10339,28 @@
 * times:                                 Paths and guides.   (line  220)
 * times <1>:                             Paths and guides.   (line  224)
 * Top:                                   graph.              (line  135)
-* TopView:                               three.              (line  426)
+* TopView:                               three.              (line  442)
 * trace:                                 Debugger.           (line   50)
 * trailingzero:                          graph.              (line  175)
 * transform:                             Transforms.         (line    6)
-* transform <1>:                         three.              (line  515)
-* transform3:                            three.              (line  478)
+* transform <1>:                         three.              (line  531)
+* transform3:                            three.              (line  494)
 * transparency:                          Pens.               (line  254)
 * transparent:                           three.              (line   97)
-* transpose:                             Arrays.             (line  208)
-* transpose <1>:                         Arrays.             (line  211)
+* transpose:                             Arrays.             (line  212)
+* transpose <1>:                         Arrays.             (line  215)
 * tree:                                  tree.               (line    6)
 * trembling:                             trembling.          (line    6)
 * triangle:                              geometry.           (line    6)
-* triangles:                             three.              (line  144)
-* triangulate:                           contour.            (line  149)
-* tridiagonal:                           Arrays.             (line  274)
+* triangles:                             three.              (line  154)
+* triangulate:                           contour.            (line  192)
+* tridiagonal:                           Arrays.             (line  278)
 * trigonometric integrals:               Mathematical functions.
                                                              (line   48)
 * triple:                                Data types.         (line  137)
 * TrueMargin:                            draw.               (line   42)
-* TrueMargin3:                           three.              (line  622)
-* tube:                                  three.              (line  156)
+* TrueMargin3:                           three.              (line  638)
+* tube:                                  three.              (line  166)
 * tube <1>:                              tube.               (line    6)
 * tutorial:                              Tutorial.           (line    6)
 * type1cm:                               Pens.               (line  192)
@@ -10167,16 +10374,16 @@
                                                              (line  165)
 * UnFill <2>:                            Frames and pictures.
                                                              (line  168)
-* uniform:                               Arrays.             (line  150)
+* uniform:                               Arrays.             (line  154)
 * uninstall:                             Uninstall.          (line    6)
 * unique:                                math.               (line   59)
 * unit:                                  Data types.         (line   83)
 * unit <1>:                              Data types.         (line  174)
 * unitbox:                               Paths.              (line   44)
-* unitbox <1>:                           three.              (line  347)
+* unitbox <1>:                           three.              (line  367)
 * unitcircle:                            Paths.              (line   17)
 * unitcircle <1>:                        Paths.              (line   17)
-* unitcircle <2>:                        three.              (line  315)
+* unitcircle <2>:                        three.              (line  335)
 * unitrand:                              Mathematical functions.
                                                              (line   39)
 * unitsize:                              Figure size.        (line   39)
@@ -10186,7 +10393,7 @@
                                                              (line    6)
 * unpacking:                             Rest arguments.     (line   39)
 * unravel:                               Import.             (line   29)
-* up:                                    three.              (line  375)
+* up:                                    three.              (line  395)
 * update:                                Files.              (line   38)
 * UpsideDown:                            Frames and pictures.
                                                              (line  104)
@@ -10199,6 +10406,7 @@
 * user-defined operators:                User-defined operators.
                                                              (line    6)
 * usleep:                                Data types.         (line  379)
+* v3d:                                   three.              (line  300)
 * value:                                 math.               (line   34)
 * value <1>:                             math.               (line   37)
 * var:                                   Variable initializers.
@@ -10205,41 +10413,41 @@
                                                              (line   55)
 * variable initializers:                 Variable initializers.
                                                              (line    6)
-* vectorfield:                           graph.              (line 1004)
-* vectorfield <1>:                       graph.              (line 1043)
+* vectorfield:                           graph.              (line 1023)
+* vectorfield <1>:                       graph.              (line 1062)
 * vectorfield3:                          graph3.             (line  157)
-* vectorization:                         Arrays.             (line  331)
+* vectorization:                         Arrays.             (line  335)
 * verbatim:                              Frames and pictures.
                                                              (line  297)
-* vertex-dependent colors:               three.              (line  109)
+* vertex-dependent colors:               three.              (line  119)
 * Vertical:                              flowchart.          (line   77)
 * Viewport:                              three.              (line   76)
 * viewportheight:                        LaTeX usage.        (line   50)
-* viewportmargin:                        three.              (line  303)
-* viewportsize:                          three.              (line  303)
+* viewportmargin:                        three.              (line  323)
+* viewportsize:                          three.              (line  323)
 * viewportwidth:                         LaTeX usage.        (line   50)
-* views:                                 three.              (line  272)
+* views:                                 three.              (line  279)
 * vim:                                   Editing modes.      (line   32)
 * virtual functions:                     Structures.         (line  182)
 * void:                                  Data types.         (line   10)
 * W:                                     Labels.             (line   18)
-* WebGL:                                 three.              (line  223)
+* WebGL:                                 three.              (line  233)
 * whatever:                              Paths and guides.   (line  246)
 * Wheel:                                 palette.            (line   22)
 * wheel mouse:                           GUI.                (line    6)
 * while:                                 Programming.        (line   48)
 * White:                                 three.              (line   76)
-* white-space string delimiter mode:     Arrays.             (line  362)
+* white-space string delimiter mode:     Arrays.             (line  366)
 * width:                                 LaTeX usage.        (line   50)
 * windingnumber:                         Paths and guides.   (line  283)
-* word:                                  Arrays.             (line  362)
+* word:                                  Arrays.             (line  366)
 * write:                                 Files.              (line   57)
-* write <1>:                             Arrays.             (line  401)
-* X:                                     three.              (line  315)
+* write <1>:                             Arrays.             (line  405)
+* X:                                     three.              (line  335)
 * xasy:                                  GUI.                (line    6)
 * xaxis3:                                graph3.             (line    7)
 * xdr:                                   Files.              (line   80)
-* xelatex:                               Options.            (line  157)
+* xelatex:                               Options.            (line  167)
 * XEquals:                               graph.              (line  265)
 * xequals:                               graph.              (line  278)
 * xlimits:                               graph.              (line  639)
@@ -10248,10 +10456,10 @@
 * xpart:                                 Data types.         (line   94)
 * xpart <1>:                             Data types.         (line  185)
 * xscale:                                Transforms.         (line   30)
-* xscale3:                               three.              (line  485)
+* xscale3:                               three.              (line  501)
 * xtick:                                 graph.              (line  330)
-* XY:                                    three.              (line  500)
-* XY <1>:                                three.              (line  515)
+* XY:                                    three.              (line  516)
+* XY <1>:                                three.              (line  531)
 * XYEquals:                              graph3.             (line   21)
 * XYZero:                                graph3.             (line   21)
 * XZEquals:                              graph3.             (line   21)
@@ -10261,7 +10469,7 @@
                                                              (line    6)
 * Y <1>:                                 Mathematical functions.
                                                              (line   48)
-* Y <2>:                                 three.              (line  315)
+* Y <2>:                                 three.              (line  335)
 * yaxis3:                                graph3.             (line    7)
 * YEquals:                               graph.              (line  128)
 * yequals:                               graph.              (line  278)
@@ -10269,14 +10477,14 @@
 * ypart:                                 Data types.         (line   97)
 * ypart <1>:                             Data types.         (line  188)
 * yscale:                                Transforms.         (line   32)
-* yscale3:                               three.              (line  487)
+* yscale3:                               three.              (line  503)
 * ytick:                                 graph.              (line  330)
-* YX:                                    three.              (line  515)
-* YZ:                                    three.              (line  515)
+* YX:                                    three.              (line  531)
+* YZ:                                    three.              (line  531)
 * YZEquals:                              graph3.             (line   21)
 * YZero:                                 graph.              (line  123)
 * YZZero:                                graph3.             (line   21)
-* Z:                                     three.              (line  315)
+* Z:                                     three.              (line  335)
 * zaxis3:                                graph3.             (line    7)
 * zeroTransform:                         Transforms.         (line   44)
 * zerowinding:                           Pens.               (line  164)
@@ -10293,158 +10501,165 @@
 * zeta:                                  Mathematical functions.
                                                              (line   48)
 * zpart:                                 Data types.         (line  191)
-* zscale3:                               three.              (line  489)
-* ZX:                                    three.              (line  515)
-* ZX <1>:                                three.              (line  515)
-* ZY:                                    three.              (line  515)
+* zscale3:                               three.              (line  505)
+* ZX:                                    three.              (line  531)
+* ZX <1>:                                three.              (line  531)
+* ZY:                                    three.              (line  531)
 
 
 
 Tag Table:
 Node: Top570
-Node: Description7200
-Node: Installation11286
-Node: UNIX binary distributions12332
-Node: MacOS X binary distributions13455
-Node: Microsoft Windows14043
-Node: Configuring15250
-Node: Search paths19862
-Node: Compiling from UNIX source20870
-Node: Editing modes24021
-Node: Git26443
-Node: Uninstall26950
-Node: Tutorial27296
-Node: Drawing in batch mode28143
-Node: Drawing in interactive mode29019
-Node: Figure size30051
-Node: Labels31646
-Node: Paths32474
-Ref: unitcircle33090
-Node: Drawing commands34988
-Node: draw36796
-Ref: arrows37978
-Node: fill43494
-Ref: gradient shading44540
-Node: clip49154
-Node: label49903
-Ref: Label50503
-Node: Bezier curves56361
-Node: Programming60261
-Ref: array iteration62014
-Node: Data types62181
-Ref: format72949
-Node: Paths and guides77395
-Ref: circle77649
-Ref: extension87349
-Node: Pens94159
-Ref: fillrule101850
-Ref: basealign102754
-Ref: transparency106436
-Ref: makepen110030
-Ref: overwrite110914
-Node: Transforms112128
-Node: Frames and pictures114067
-Ref: envelope115225
-Ref: size116318
-Ref: unitsize117305
-Ref: shipout118378
-Ref: filltype120729
-Ref: add124142
-Ref: add about125084
-Ref: tex128114
-Node: Files129010
-Ref: cd130067
-Ref: scroll134969
-Node: Variable initializers137887
-Node: Structures140604
-Node: Operators148182
-Node: Arithmetic & logical148496
-Node: Self & prefix operators150866
-Node: User-defined operators151660
-Node: Implicit scaling152573
-Node: Functions153136
-Ref: stack overflow156278
-Node: Default arguments156560
-Node: Named arguments157316
-Node: Rest arguments159886
-Node: Mathematical functions163008
-Node: Arrays167665
-Ref: sort174954
-Ref: tridiagonal177865
-Ref: solve179096
-Node: Slices183236
-Node: Casts187144
-Node: Import189414
-Node: Static194995
-Node: LaTeX usage197881
-Node: Base modules204376
-Node: plain206853
-Node: simplex207527
-Node: math207800
-Node: interpolate210383
-Node: geometry210662
-Node: trembling211256
-Node: stats211525
-Node: patterns211784
-Node: markers212019
-Node: map213878
-Node: tree214302
-Node: binarytree214486
-Node: drawtree215153
-Node: syzygy215354
-Node: feynman215628
-Node: roundedpath215902
-Node: animation216184
-Ref: animate216605
-Node: embed217717
-Node: slide218671
-Node: MetaPost219002
-Node: babel219718
-Node: labelpath219950
-Node: labelpath3220770
-Node: annotate221081
-Node: CAD221551
-Node: graph221861
-Ref: ticks229021
-Ref: pathmarkers242746
-Ref: marker243217
-Ref: markuniform243571
-Ref: errorbars245379
-Ref: automatic scaling249858
-Node: palette261573
-Ref: images261691
-Ref: image265865
-Ref: logimage266386
-Ref: penimage267492
-Ref: penfunctionimage267755
-Node: three268527
-Ref: PostScript3D298054
-Node: obj299792
-Node: graph3300041
-Ref: GaussianSurface305324
-Node: grid3306474
-Node: solids307259
-Node: tube308251
-Node: flowchart310481
-Node: contour315124
-Node: contour3320439
-Node: smoothcontour3320751
-Node: slopefield322472
-Node: ode323962
-Node: Options324219
-Ref: configuration file331127
-Ref: settings331127
-Ref: texengines332391
-Ref: convert332391
-Node: Interactive mode335835
-Ref: history337985
-Node: GUI339288
-Node: GUI installation339839
-Node: GUI usage340572
-Node: PostScript to Asymptote341635
-Node: Help342394
-Node: Debugger344068
-Node: Credits345824
-Node: Index346932
+Node: Description7317
+Node: Installation11564
+Node: UNIX binary distributions12610
+Node: MacOS X binary distributions13733
+Node: Microsoft Windows14321
+Node: Configuring15529
+Node: Search paths20142
+Node: Compiling from UNIX source21150
+Node: Editing modes24301
+Node: Git26723
+Node: Uninstall27230
+Node: Tutorial27576
+Node: Drawing in batch mode28423
+Node: Drawing in interactive mode29299
+Node: Figure size30331
+Node: Labels31926
+Node: Paths32754
+Ref: unitcircle33370
+Node: Drawing commands35268
+Node: draw37076
+Ref: arrows38258
+Node: fill43773
+Ref: gradient shading44819
+Node: clip49433
+Node: label50182
+Ref: Label50782
+Node: Bezier curves56639
+Node: Programming60539
+Ref: array iteration62292
+Node: Data types62459
+Ref: format73227
+Node: Paths and guides77673
+Ref: circle77927
+Ref: extension87627
+Node: Pens94437
+Ref: fillrule102128
+Ref: basealign103032
+Ref: transparency106714
+Ref: makepen110308
+Ref: overwrite111192
+Node: Transforms112406
+Node: Frames and pictures114345
+Ref: envelope115503
+Ref: size116596
+Ref: unitsize117583
+Ref: shipout118656
+Ref: filltype121007
+Ref: add124420
+Ref: add about125362
+Ref: tex128392
+Node: Files129287
+Ref: cd130344
+Ref: scroll135246
+Node: Variable initializers138164
+Node: Structures140881
+Node: Operators148454
+Node: Arithmetic & logical148768
+Node: Self & prefix operators151138
+Node: User-defined operators151932
+Node: Implicit scaling152845
+Node: Functions153408
+Ref: stack overflow156525
+Node: Default arguments156807
+Node: Named arguments157563
+Node: Rest arguments160133
+Node: Mathematical functions163254
+Node: Arrays167911
+Ref: sort175350
+Ref: tridiagonal178261
+Ref: solve179492
+Node: Slices183632
+Node: Casts187540
+Node: Import189810
+Node: Static195380
+Node: LaTeX usage198266
+Node: Base modules204780
+Node: plain207257
+Node: simplex207931
+Node: math208204
+Node: interpolate210871
+Node: geometry211150
+Node: trembling211744
+Node: stats212013
+Node: patterns212272
+Node: markers212507
+Node: map214365
+Node: tree214789
+Node: binarytree214969
+Node: drawtree215636
+Node: syzygy215837
+Node: feynman216111
+Node: roundedpath216385
+Node: animation216667
+Ref: animate217088
+Node: embed218200
+Node: slide219154
+Node: MetaPost219485
+Node: babel220201
+Node: labelpath220433
+Node: labelpath3221253
+Node: annotate221564
+Node: CAD222034
+Node: graph222344
+Ref: ticks229503
+Ref: pathmarkers243225
+Ref: marker243695
+Ref: markuniform244049
+Ref: errorbars245908
+Ref: automatic scaling251037
+Node: palette262747
+Ref: images262865
+Ref: image267161
+Ref: logimage267682
+Ref: penimage268788
+Ref: penfunctionimage269051
+Node: three269823
+Ref: PostScript3D300123
+Node: obj301861
+Node: graph3302110
+Ref: GaussianSurface307392
+Node: grid3308542
+Node: solids309327
+Node: tube310319
+Node: flowchart312549
+Node: contour317192
+Node: contour3323700
+Node: smoothcontour3324012
+Node: slopefield325731
+Node: ode327220
+Node: Options327477
+Ref: configuration file335032
+Ref: settings335032
+Ref: texengines336296
+Ref: convert336296
+Node: Interactive mode339739
+Ref: history341888
+Node: GUI343191
+Node: GUI installation343741
+Node: GUI usage344474
+Node: Command-Line Interface345537
+Node: Language server protocol346979
+Node: PostScript to Asymptote348404
+Node: Help349182
+Node: Debugger350856
+Node: Credits352612
+Node: Index353837
 
 End Tag Table
+
+
+Local Variables:
+coding: utf-8
+End:

Modified: trunk/Master/texmf-dist/doc/man/man1/asy.1
===================================================================
--- trunk/Master/texmf-dist/doc/man/man1/asy.1	2022-02-27 23:39:53 UTC (rev 62264)
+++ trunk/Master/texmf-dist/doc/man/man1/asy.1	2022-02-27 23:41:11 UTC (rev 62265)
@@ -31,6 +31,12 @@
 For a complete
 description, see the Info files.
 .TP
+.B \-GPUindexing         
+Compute indexing partial sums on GPU [true].
+.TP
+.B \-GPUinterlock        
+Use fragment shader interlock [true].
+.TP
 .B \-V,\-View             
 View output; command-line only.
 .TP
@@ -103,12 +109,12 @@
 .B \-divisor n           
 Garbage collect using purge(divisor=n) [2].
 .TP
+.B \-dvisvgmMultipleFiles
+dvisvgm supports multiple files [false].
+.TP
 .B \-embed               
 Embed rendered preview image [true].
 .TP
-.B \-envmap              
-Enable environment map image-based lighting (Experimental) [false].
-.TP
 .B \-exitonEOF           
 Exit interactive mode on EOF [true].
 .TP
@@ -136,9 +142,18 @@
 .B \-historylines n      
 Retain n lines of history [1000].
 .TP
+.B \-ibl                 
+Enable environment map image-based lighting [false].
+.TP
 .B \-iconify             
 Iconify rendering window [false].
 .TP
+.B \-image string        
+Environment image name [snowyField].
+.TP
+.B \-imageDir string     
+Environment image library directory [ibl].
+.TP
 .B \-inlineimage         
 Generate inline embedded image [false].
 .TP
@@ -172,6 +187,12 @@
 .B \-loop                
 Loop 3D animations [false].
 .TP
+.B \-lossy               
+Use single precision for V3D reals [false].
+.TP
+.B \-lsp                 
+Interactive mode for the Language Server Protocol [false].
+.TP
 .B \-m,\-mask             
 Mask fpu exceptions; command-line only.
 .TP
@@ -215,8 +236,11 @@
 Initial 3D rendering screen position [(0,0)].
 .TP
 .B \-prc                 
-Embed 3D PRC graphics in PDF output [true].
+Embed 3D PRC graphics in PDF output [false].
 .TP
+.B \-prerender resolution
+Prerender V3D objects (0 implies vector output) [0].
+.TP
 .B \-prompt string       
 Prompt [> ].
 .TP
@@ -304,11 +328,17 @@
 .B \-warn string         
 Enable warning; command-line only.
 .TP
+.B \-webgl2              
+Use webgl2 if available [false].
+.TP
 .B \-where               
 Show where listed variables are declared [false].
 .TP
+.B \-wsl                 
+Run asy under the Windows Subsystem for Linux. [false].
+.TP
 .B \-xasy                
-Special interactive mode for xasy [false].
+Interactive mode for xasy [false].
 .TP
 .B \-zoomPinchCap limit  
 WebGL maximum zoom pinch [100].

Modified: trunk/Master/texmf-dist/doc/man/man1/asy.man1.pdf
===================================================================
(Binary files differ)

Added: trunk/Master/texmf-dist/doc/man/man1/twill.man1.pdf
===================================================================
(Binary files differ)

Index: trunk/Master/texmf-dist/doc/man/man1/twill.man1.pdf
===================================================================
--- trunk/Master/texmf-dist/doc/man/man1/twill.man1.pdf	2022-02-27 23:39:53 UTC (rev 62264)
+++ trunk/Master/texmf-dist/doc/man/man1/twill.man1.pdf	2022-02-27 23:41:11 UTC (rev 62265)

Property changes on: trunk/Master/texmf-dist/doc/man/man1/twill.man1.pdf
___________________________________________________________________
Added: svn:mime-type
## -0,0 +1 ##
+application/pdf
\ No newline at end of property
Modified: trunk/Master/texmf-dist/doc/man/man1/xasy.man1.pdf
===================================================================
(Binary files differ)

Modified: trunk/Master/texmf-dist/tex/latex/asymptote/asymptote.sty
===================================================================
--- trunk/Master/texmf-dist/tex/latex/asymptote/asymptote.sty	2022-02-27 23:39:53 UTC (rev 62264)
+++ trunk/Master/texmf-dist/tex/latex/asymptote/asymptote.sty	2022-02-27 23:41:11 UTC (rev 62265)
@@ -17,7 +17,7 @@
 %% Licence: GPL2+
 %% 
 \ProvidesPackage{asymptote}
-  [2021/02/06 v1.36 Asymptote style file for LaTeX]
+  [2021/12/29 v1.37 Asymptote style file for LaTeX]
 \def\Asymptote{{\tt Asymptote}}
 \InputIfFileExists{\jobname.pre}{}{}
 \newbox\ASYbox
@@ -31,7 +31,7 @@
 \ASYkeepAspecttrue
 \RequirePackage{keyval}
 \RequirePackage{ifthen}
-\RequirePackage{color,graphicx}
+\RequirePackage{graphicx}
 \IfFileExists{ifpdf.sty}{
   \RequirePackage{ifpdf}
 }{

Modified: trunk/Master/tlpkg/asymptote/asy.exe
===================================================================
(Binary files differ)

Modified: trunk/Master/tlpkg/asymptote64/asy.exe
===================================================================
(Binary files differ)



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