diff options
author | Norbert Preining <norbert@preining.info> | 2019-09-02 13:46:59 +0900 |
---|---|---|
committer | Norbert Preining <norbert@preining.info> | 2019-09-02 13:46:59 +0900 |
commit | e0c6872cf40896c7be36b11dcc744620f10adf1d (patch) | |
tree | 60335e10d2f4354b0674ec22d7b53f0f8abee672 /graphics/asymptote/GUI |
Initial commit
Diffstat (limited to 'graphics/asymptote/GUI')
97 files changed, 13677 insertions, 0 deletions
diff --git a/graphics/asymptote/GUI/CustMatTransform.py b/graphics/asymptote/GUI/CustMatTransform.py new file mode 100644 index 0000000000..563907fc50 --- /dev/null +++ b/graphics/asymptote/GUI/CustMatTransform.py @@ -0,0 +1,102 @@ +#!/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 +from pyUIClass.custMatTransform import Ui_Dialog + + +class CustMatTransform(Qw.QDialog): + def __init__(self): + super().__init__() + self.ui = Ui_Dialog() + self.ui.setupUi(self) + + self.ui.btnAccept.clicked.connect(self.accept) + self.ui.btnCancel.clicked.connect(self.reject) + self.ui.btnReset.clicked.connect(self.resetDialog) + + self.mainTransformation = Qg.QTransform() + self.mainTransformation.scale(1, -1) + + self.matrixLineInputs = [ + self.ui.lineMat00, self.ui.lineMat01, self.ui.lineMatTx, + self.ui.lineMat10, self.ui.lineMat11, self.ui.lineMatTy] + + validator = Qg.QDoubleValidator() + for lineInput in self.matrixLineInputs: + lineInput.setValidator(validator) + lineInput.textChanged.connect(self.handleUpdateText) + + def show(self): + super().show() + self.createCanvas() + self.updatePreview() + + def createCanvas(self): + self.canvSize = self.ui.imgPreview.size() + self.previewPixmap = Qg.QPixmap(self.canvSize) + tx, ty = self.canvSize.width() / 2, self.canvSize.height() / 2 + self.mainTransformation.translate(tx, -ty) + + def handleUpdateText(self, text): + if str(text) not in {'.', '-', '.-', '-.'} and str(text): + self.updatePreview() + self.ui.btnAccept.setEnabled(True) + else: + self.previewPixmap.fill() + self.ui.imgPreview.setPixmap(self.previewPixmap) + self.ui.btnAccept.setEnabled(False) + + def updatePreview(self): + self.previewPixmap.fill() + canvas = Qg.QPainter(self.previewPixmap) + if not canvas.isActive(): + return + canvas.setTransform(self.mainTransformation) + + canvas.save() + canvas.setPen(Qc.Qt.lightGray) + self.drawBasicGrid(canvas) + transform = x2a.asyTransform.fromNumpyMatrix(self.getTransformationMatrix()) + canvTransform = transform.toQTransform() + canvas.setTransform(canvTransform, True) + + canvas.setPen(Qc.Qt.black) + + if canvTransform.isInvertible(): + self.drawBasicGrid(canvas, False) + + if canvTransform.determinant() <= 0: + canvas.setPen(Qc.Qt.red) + + canvas.drawRect(Qc.QRect(Qc.QPoint(0, 0), Qc.QSize(20, 20))) + + self.ui.imgPreview.setPixmap(self.previewPixmap) + + def resetDialog(self): + self.ui.lineMatTx.setText('0') + self.ui.lineMatTx.setText('0') + + self.ui.lineMat00.setText('1') + self.ui.lineMat01.setText('0') + self.ui.lineMat10.setText('0') + 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)) + + 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)) + + def getTransformationMatrix(self): + rawMatrixNum = [float(lineInput.text()) for lineInput in self.matrixLineInputs] + rawMatrixNum.extend([0, 0, 1]) + return np.matrix(rawMatrixNum).reshape((3, 3)) diff --git a/graphics/asymptote/GUI/DebugFlags.py b/graphics/asymptote/GUI/DebugFlags.py new file mode 100644 index 0000000000..8a7eb4b282 --- /dev/null +++ b/graphics/asymptote/GUI/DebugFlags.py @@ -0,0 +1,6 @@ +#!/usr/bin/env python3 + +keepFiles = False +printFoutTranscript = False +printDeconstTranscript = False +forceRasterizationSVG = False diff --git a/graphics/asymptote/GUI/GuidesManager.py b/graphics/asymptote/GUI/GuidesManager.py new file mode 100644 index 0000000000..5467843377 --- /dev/null +++ b/graphics/asymptote/GUI/GuidesManager.py @@ -0,0 +1,52 @@ +#!/usr/bin/env python3 +import PyQt5.QtWidgets as Qw +import PyQt5.QtGui as Qg +import PyQt5.QtCore as Qc +import numpy as np + +class Guide: + def __init__(self, pen=None): + if pen is None: + pen = Qg.QPen() + assert isinstance(pen, Qg.QPen) + self.pen = pen + + def drawShape(self, pen): + assert isinstance(pen, Qg.QPainter) + pen.save() + pen.setPen(self.pen) + +class LineGuide(Guide): + def __init__(self, origin, direction, pen=None): + super().__init__(pen) + self.origin = origin + self.direction = direction + + 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)) + pen.restore() + +class ArcGuide(Guide): + @classmethod + def radTo16Deg(cls, radians): + return int(round(np.rad2deg(radians) * 16)) + + def __init__(self, center=None, radius=1, startAng=0, endAng=(2*np.pi), pen=None): + if center is None: + center = Qc.QPointF(0, 0) + super().__init__(pen) + self.center = center + self.radius = int(radius) + self.startAng = startAng + self.endAng = endAng + + def drawShape(self, pen): + super().drawShape(pen) + assert isinstance(pen, Qg.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)) + pen.restore() diff --git a/graphics/asymptote/GUI/InplaceAddObj.py b/graphics/asymptote/GUI/InplaceAddObj.py new file mode 100644 index 0000000000..132969dad1 --- /dev/null +++ b/graphics/asymptote/GUI/InplaceAddObj.py @@ -0,0 +1,356 @@ +#!/usr/bin/env python3 + +import PyQt5.QtCore as Qc +import PyQt5.QtGui as Qg +import xasy2asy as x2a + +import PrimitiveShape +import math + +import Widg_addPolyOpt +import Widg_addLabel + + +class InplaceObjProcess(Qc.QObject): + objectCreated = Qc.pyqtSignal(Qc.QObject) + objectUpdated = Qc.pyqtSignal() + + def __init__(self, parent=None): + super().__init__(parent) + self._active = False + pass + + @property + def active(self): + return self._active + + def mouseDown(self, pos, info, mouseEvent: Qg.QMouseEvent=None): + raise NotImplementedError + + def mouseMove(self, pos, event: Qg.QMouseEvent): + raise NotImplementedError + + def mouseRelease(self): + raise NotImplementedError + + def forceFinalize(self): + raise NotImplementedError + + def getPreview(self): + return None + + def getObject(self): + raise NotImplementedError + + def getXasyObject(self): + raise NotImplementedError + + def postDrawPreview(self, canvas: Qg.QPainter): + pass + + def createOptWidget(self, info): + return None + + +class AddCircle(InplaceObjProcess): + def __init__(self, parent=None): + super().__init__(parent) + self.center = Qc.QPointF(0, 0) + self.radius = 0 + + def mouseDown(self, pos, info, mouseEvent: Qg.QMouseEvent=None): + x, y = PrimitiveShape.PrimitiveShape.pos_to_tuple(pos) + self.radius = 0 + self.center.setX(x) + self.center.setY(y) + self.fill = info['fill'] + self._active = True + + def mouseMove(self, pos, event): + self.radius = PrimitiveShape.PrimitiveShape.euclideanNorm(pos, self.center) + + def mouseRelease(self): + self.objectCreated.emit(self.getXasyObject()) + self._active = False + + 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) + # because the internal image is flipped... + newPath = Qg.QPainterPath() + newPath.addEllipse(boundRect) + # newPath.addRect(boundRect) + return newPath + + def getObject(self): + return PrimitiveShape.PrimitiveShape.circle(self.center, self.radius) + + def getXasyObject(self): + if self.fill: + newObj = x2a.xasyFilledShape(self.getObject(), None) + else: + newObj = x2a.xasyShape(self.getObject(), None) + return newObj + + def forceFinalize(self): + self.mouseRelease() + + +class AddLabel(InplaceObjProcess): + def __init__(self, parent=None): + super().__init__(parent) + self.alignMode = None + self.opt = None + self.text = None + self.anchor = Qc.QPointF(0, 0) + self._active = False + + def createOptWidget(self, info): + self.opt = Widg_addLabel.Widg_addLabel(info) + return self.opt + + def getPreview(self): + return None + + def mouseRelease(self): + self.objectCreated.emit(self.getXasyObject()) + self._active = False + + def mouseMove(self, pos, event): + x, y = PrimitiveShape.PrimitiveShape.pos_to_tuple(pos) + self.anchor.setX(x) + self.anchor.setY(y) + + def mouseDown(self, pos, info, mouseEvent: Qg.QMouseEvent=None): + if self.opt is not None: + self.text = self.opt.labelText + x, y = PrimitiveShape.PrimitiveShape.pos_to_tuple(pos) + self.anchor.setX(x) + self.anchor.setY(y) + + self.alignMode = info['align'] + self.fontSize = info['fontSize'] + self._active = True + + def getObject(self): + finalTuple = PrimitiveShape.PrimitiveShape.pos_to_tuple(self.anchor) + return {'txt': self.text, 'align': str(self.alignMode), 'anchor': finalTuple} + + def getXasyObject(self): + text = self.text + align = str(self.alignMode) + anchor = PrimitiveShape.PrimitiveShape.pos_to_tuple(self.anchor) + newLabel = x2a.xasyText(text=text, location=anchor, pen=None, + align=align, asyengine=None, fontsize=self.fontSize) + newLabel.asyfied = False + return newLabel + + def forceFinalize(self): + self.mouseRelease() + + +class AddBezierShape(InplaceObjProcess): + 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 = Qc.QPointF(0, 0) + self.pendingPoint = None + self.useLegacy = False + + def mouseDown(self, pos, info, mouseEvent: Qg.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) + else: + self.forceFinalize() + + + def createOptWidget(self, info): + return None + # self.opt = Widg_addBezierInPlace.Widg_addBezierInplace(info) + # return self.opt + + def finalizeClosure(self): + if self.active: + self.closedPath = True + self.forceFinalize() + + def mouseRelease(self): + x, y = self.currentPoint.x(), self.currentPoint.y() + self.pointsList.append((x, y, self._getLinkType())) + # self.updateBasePath() + + def updateBasePath(self): + self.basePath = x2a.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 = x2a.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 forceFinalize(self): + self.updateBasePath() + self._active = False + self.pointsList.clear() + self.objectCreated.emit(self.getXasyObject()) + self.basePath = None + + 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): + if self.fill: + return x2a.xasyFilledShape(self.getObject(), None) + else: + return x2a.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.sides = None + self.inscribed = None + self.centermode = None + self.asyengine = None + self.fill = None + self.opt = None + + def mouseDown(self, pos, info, mouseEvent: Qg.QMouseEvent=None): + self._active = True + self.sides = info['sides'] + self.inscribed = info['inscribed'] + 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) + + def mouseMove(self, pos, event): + x, y = PrimitiveShape.PrimitiveShape.pos_to_tuple(pos) + self.currPos.setX(x) + self.currPos.setY(y) + + def mouseRelease(self): + if self.active: + self.objectCreated.emit(self.getXasyObject()) + self._active = False + + def forceFinalize(self): + self.mouseRelease() + + def getObject(self): + if self.inscribed: + return PrimitiveShape.PrimitiveShape.inscribedRegPolygon(self.sides, self.center, self._rad(), + self._angle()) + else: + return PrimitiveShape.PrimitiveShape.exscribedRegPolygon(self.sides, self.center, self._rad(), + self._angle()) + + def getPreview(self): + if self.inscribed: + poly = PrimitiveShape.PrimitiveShape.inscribedRegPolygon(self.sides, self.center, self._rad(), + self._angle(), qpoly=True) + else: + poly = PrimitiveShape.PrimitiveShape.exscribedRegPolygon(self.sides, self.center, self._rad(), + self._angle(), qpoly=True) + newPath = Qg.QPainterPath() + newPath.addPolygon(poly) + return newPath + + def createOptWidget(self, info): + self.opt = Widg_addPolyOpt.Widg_addPolyOpt(info) + return self.opt + + def _rad(self): + return PrimitiveShape.PrimitiveShape.euclideanNorm(self.currPos, self.center) + + def _angle(self): + dist_x = self.currPos.x() - self.center.x() + dist_y = self.currPos.y() - self.center.y() + if dist_x == 0 and dist_y == 0: + return 0 + else: + return math.atan2(dist_y, dist_x) + + def getXasyObject(self): + if self.fill: + newObj = x2a.xasyFilledShape(self.getObject(), None) + else: + newObj = x2a.xasyShape(self.getObject(), None) + return newObj diff --git a/graphics/asymptote/GUI/PrimitiveShape.py b/graphics/asymptote/GUI/PrimitiveShape.py new file mode 100644 index 0000000000..c75e014079 --- /dev/null +++ b/graphics/asymptote/GUI/PrimitiveShape.py @@ -0,0 +1,66 @@ +#!/usr/bin/env python3 + +import xasy2asy as x2a +import numpy as np +import math +import PyQt5.QtCore as Qc +import PyQt5.QtGui as Qg + + +class PrimitiveShape: + # The magic number. + # see https://www.desmos.com/calculator/lw6j7khikj for unitcircle + # optimal_ctl_pt = 0.5447 + + @staticmethod + def pos_to_tuple(pos): + if isinstance(pos, tuple) or isinstance(pos, np.ndarray): + return pos + elif isinstance(pos, Qc.QPoint) or isinstance(pos, Qc.QPointF): + return pos.x(), pos.y() + else: + raise TypeError("Position must be a valid type!") + + @staticmethod + def euclideanNorm(p1, p2): + x1, y1 = PrimitiveShape.pos_to_tuple(p1) + x2, y2 = PrimitiveShape.pos_to_tuple(p2) + + normSq = ((x1 - x2) ** 2) + ((y1 - y2) ** 2) + return math.sqrt(normSq) + + @classmethod + def circle(cls, position, radius): + pos_x, pos_y = PrimitiveShape.pos_to_tuple(position) + newCircle = x2a.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. + lkList = ['..', '..', '..', '..'] + newCircle.initFromNodeList(ptsList, lkList) + return newCircle + + @classmethod + def inscribedRegPolygon(cls, sides, position, radius, starting_rad, qpoly=False): + 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): + 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) + else: + ptsList.append('cycle') + newPoly = x2a.asyPath() + newPoly.initFromNodeList(ptsList, lkList) + return newPoly + + @classmethod + def exscribedRegPolygon(cls, sides, position, length, starting_rad, qpoly=False): + ang = math.tau/sides + # see notes + adjusted_radius = length / math.cos(ang/2) + return cls.inscribedRegPolygon(sides, position, adjusted_radius, starting_rad - ang/2, qpoly) diff --git a/graphics/asymptote/GUI/SetCustomAnchor.py b/graphics/asymptote/GUI/SetCustomAnchor.py new file mode 100644 index 0000000000..ad5925cddb --- /dev/null +++ b/graphics/asymptote/GUI/SetCustomAnchor.py @@ -0,0 +1,44 @@ +#!/usr/bin/env python3 + +import PyQt5.QtWidgets as Qw +import PyQt5.QtGui as Qg +import PyQt5.QtCore as Qc +from pyUIClass.setCustomAnchor import Ui_Dialog + + +class CustomAnchorDialog(Qw.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) + + validator = Qg.QDoubleValidator() + + self.ui.lineEditX.setValidator(validator) + self.ui.lineEditY.setValidator(validator) + + self.ui.lineEditX.textChanged.connect(self.checkTextChanged) + self.ui.lineEditY.textChanged.connect(self.checkTextChanged) + + def checkTextChanged(self, text): + if str(text) not in {'.', '-', '.-', '-.'} and str(text): + self.ui.buttonBox.button(Qw.QDialogButtonBox.Ok).setEnabled(True) + else: + self.ui.buttonBox.button(Qw.QDialogButtonBox.Ok).setEnabled(False) + + def getPoint(self): + xPoint = float(self.ui.lineEditX.text()) + yPoint = float(self.ui.lineEditY.text()) + + return Qc.QPointF(xPoint, yPoint) + + def handleBtnBoxClick(self, button): + assert isinstance(button, Qw.QAbstractButton) + if button.text() == 'Reset': + self.resetDialog() + + def resetDialog(self): + self.ui.lineEditX.setText('0') + self.ui.lineEditY.setText('0') diff --git a/graphics/asymptote/GUI/UndoRedoStack.py b/graphics/asymptote/GUI/UndoRedoStack.py new file mode 100755 index 0000000000..7285b15ff2 --- /dev/null +++ b/graphics/asymptote/GUI/UndoRedoStack.py @@ -0,0 +1,132 @@ +#!/usr/bin/env python3 +########################################################################### +# +# UndoRedoStack implements the usual undo/redo capabilities of a GUI +# +# Author: Orest Shardt +# Created: July 23, 2007 +# +########################################################################### + + +class action: + def __init__(self, actions): + act, inv = actions + self.act = act + self.inv = inv + + def undo(self): + # print ("Undo:",self) + self.inv() + + def redo(self): + # print ("Redo:",self) + self.act() + + def __str__(self): + return "A generic action" + + +class beginActionGroup: + pass + + +class endActionGroup: + pass + + +class actionStack: + def __init__(self): + self.clear() + + def add(self, action): + self.undoStack.append(action) + # print ("Added",action) + self.redoStack = [] + + def undo(self): + if len(self.undoStack) > 0: + op = self.undoStack.pop() + if op is beginActionGroup: + level = 1 + self.redoStack.append(endActionGroup) + while level > 0: + op = self.undoStack.pop() + if op is endActionGroup: + level -= 1 + self.redoStack.append(beginActionGroup) + elif op is beginActionGroup: + level += 1 + self.redoStack.append(endActionGroup) + else: + op.undo() + self.redoStack.append(op) + elif op is endActionGroup: + raise Exception("endActionGroup without previous beginActionGroup") + else: + self.redoStack.append(op) + op.undo() + # print ("undid",op) + else: + pass # print ("nothing to undo") + + def redo(self): + if len(self.redoStack) > 0: + op = self.redoStack.pop() + if op is beginActionGroup: + level = 1 + self.undoStack.append(endActionGroup) + while level > 0: + op = self.redoStack.pop() + if op is endActionGroup: + level -= 1 + self.undoStack.append(beginActionGroup) + elif op is beginActionGroup: + level += 1 + self.undoStack.append(endActionGroup) + else: + op.redo() + self.undoStack.append(op) + elif op is endActionGroup: + raise Exception("endActionGroup without previous beginActionGroup") + else: + self.undoStack.append(op) + op.redo() + # print ("redid",op) + else: + pass # print ("nothing to redo") + + def setCommitLevel(self): + self.commitLevel = len(self.undoStack) + + def changesMade(self): + if len(self.undoStack) != self.commitLevel: + return True + else: + return False + + def clear(self): + self.redoStack = [] + self.undoStack = [] + self.commitLevel = 0 + + +if __name__ == '__main__': + import sys + + + def opq(): + print("action1") + + + def unopq(): + print("inverse1") + + + q = action(opq, unopq) + w = action(lambda: sys.stdout.write("action2\n"), lambda: sys.stdout.write("inverse2\n")) + e = action(lambda: sys.stdout.write("action3\n"), lambda: sys.stdout.write("inverse3\n")) + s = actionStack() + s.add(q) + s.add(w) + s.add(e) diff --git a/graphics/asymptote/GUI/Widg_addLabel.py b/graphics/asymptote/GUI/Widg_addLabel.py new file mode 100644 index 0000000000..776d3e02df --- /dev/null +++ b/graphics/asymptote/GUI/Widg_addLabel.py @@ -0,0 +1,96 @@ +#!/usr/bin/env python3 + +from pyUIClass.widg_addLabel import Ui_Form +import PyQt5.QtWidgets as Qw +import PyQt5.QtGui as Qg + +import labelEditor +import xasyUtils as xu + + +class Widg_addLabel(Qw.QWidget): + def __init__(self, info): + super().__init__() + self.ui = Ui_Form() + self.info = info + self.ui.setupUi(self) + self.setFixedSize(self.size()) + + if 'alignIndex' not in self.info.keys(): + self.info['alignIndex'] = 0 + + if 'shift_x' not in self.info.keys(): + self.info['shift_x'] = None + + if 'shift_y' not in self.info.keys(): + self.info['shift_y'] = None + + if 'align' not in self.info.keys(): + self.info['align'] = (0, 0) + + if self.info['shift_x'] is not None: + self.ui.txtShiftX.setText(str(self.info['shift_x'])) + + 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() + + self.ui.txtShiftX.setValidator(validator) + self.ui.txtShiftY.setValidator(validator) + self.ui.cmbFontSize.setValidator(validator) + + self.ui.cmbAlign.currentTextChanged.connect(self.updateCheck) + self.ui.cmbAlign.currentIndexChanged.connect(self.cmbIndexUpdate) + self.ui.txtShiftX.textEdited.connect(self.shftXUpdate) + self.ui.txtShiftY.textEdited.connect(self.shftYUpdate) + self.ui.btnAdvancedEdit.clicked.connect(self.btnAdvancedEditClicked) + self.ui.cmbFontSize.currentTextChanged.connect(self.cmbFontSizeTextChanged) + + self.updateCheck(self.ui.cmbAlign.currentText()) + + def cmbFontSizeTextChanged(self, text: str): + tryParseVal = xu.tryParse(text, float) + self.info['fontSize'] = tryParseVal + + def btnAdvancedEditClicked(self): + advancedEditDialog = labelEditor.labelEditor(self.ui.txtLabelText.text()) + advancedEditDialog.show() + result = advancedEditDialog.exec_() + if result == Qw.QDialog.Accepted: + self.ui.txtLabelText.setText(advancedEditDialog.getText()) + + @property + def labelText(self): + return self.ui.txtLabelText.text() + + def updateCheck(self, a0): + self.ui.txtShiftX.setEnabled(a0 == 'Custom') + self.ui.txtShiftY.setEnabled(a0 == 'Custom') + + def shftXUpdate(self, text): + if text: + self.info['shift_x'] = float(text) + self.updateAlign() + + def shftYUpdate(self, text): + if text: + self.info['shift_y'] = float(text) + self.updateAlign() + + def updateAlign(self): + index = self.ui.cmbAlign.currentIndex() + self.info['alignIndex'] = index + if self.ui.cmbAlign.currentText() == 'Custom': + self.info['align'] = (self.info['shift_x'], self.info['shift_y']) + elif self.ui.cmbAlign.currentText() == 'None': + self.info['align'] = (0, 0) + else: + self.info['align'] = self.ui.cmbAlign.currentText() + + def cmbIndexUpdate(self, index): + self.updateAlign() diff --git a/graphics/asymptote/GUI/Widg_addPolyOpt.py b/graphics/asymptote/GUI/Widg_addPolyOpt.py new file mode 100644 index 0000000000..b9b9a77f7a --- /dev/null +++ b/graphics/asymptote/GUI/Widg_addPolyOpt.py @@ -0,0 +1,31 @@ +#!/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 sys + + +class Widg_addPolyOpt(Qw.QWidget): + def __init__(self, info): + super().__init__() + self.ui = Ui_Form() + self.info = info + self.ui.setupUi(self) + self.setFixedSize(self.size()) + + self.ui.chkInscribed.setChecked(self.info['inscribed']) + self.ui.txtSides.setText(str(self.info['sides'])) + self.ui.txtSides.setValidator(Qg.QIntValidator()) + + self.ui.chkInscribed.stateChanged.connect(self.chkInscribedUpdate) + self.ui.txtSides.textChanged.connect(self.txtSidesUpdate) + + def chkInscribedUpdate(self, checked): + self.info['inscribed'] = checked + + def txtSidesUpdate(self, text): + if text: + self.info['sides'] = int(text) diff --git a/graphics/asymptote/GUI/Widg_editBezier.py b/graphics/asymptote/GUI/Widg_editBezier.py new file mode 100644 index 0000000000..3a3cbab94a --- /dev/null +++ b/graphics/asymptote/GUI/Widg_editBezier.py @@ -0,0 +1,53 @@ +#!/usr/bin/env python3 + +from pyUIClass.widg_editBezier import Ui_Form + +import PyQt5.QtCore as Qc +import PyQt5.QtWidgets as Qw +import PyQt5.QtGui as Qg + +class LockMode: + noLock = 0 + angleLock = 1 + angleAndScaleLock = 2 + +class Widg_editBezier(Qw.QWidget): + def __init__(self, info: dict, enableCurveFeatures: bool=True): + super().__init__() + self.ui = Ui_Form() + self.ui.setupUi(self) + self.info = info + + self.ui.chkRecompute.setChecked(self.info['autoRecompute']) + self.ui.cmbLockMode.setCurrentIndex(self.info['editBezierlockMode']) + + self.ui.cmbLockMode.currentIndexChanged[int].connect(self.cmbLockIndexChange) + self.ui.chkRecompute.stateChanged.connect(self.chkRecomputeChanged) + + self.disableOnAutoRecompute = {self.ui.cmbLockMode, self.ui.btnForceRecompute} + self.curveBtnsOnly = {self.ui.cmbLockMode, self.ui.btnForceRecompute, self.ui.chkRecompute} + + for elem in self.curveBtnsOnly: + elem.setEnabled(enableCurveFeatures) + + @property + def autoRecompute(self) -> bool: + return self.ui.chkRecompute.isChecked() + + @property + def lockMode(self) -> int: + return self.ui.cmbLockMode.currentIndex() + + @Qc.pyqtSlot(int) + def cmbLockIndexChange(self, index: int): + self.info['editBezierlockMode'] = index + + @Qc.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() diff --git a/graphics/asymptote/GUI/Window1.py b/graphics/asymptote/GUI/Window1.py new file mode 100644 index 0000000000..7fda2bfc35 --- /dev/null +++ b/graphics/asymptote/GUI/Window1.py @@ -0,0 +1,1900 @@ +#!/usr/bin/env python3 + +from pyUIClass.window1 import Ui_MainWindow + +import PyQt5.QtWidgets as Qw +import PyQt5.QtGui as Qg +import PyQt5.QtCore as Qc +import xasyVersion + +import numpy as np +import os +import json +import io +import pathlib +import webbrowser +import subprocess +import tempfile +import datetime +import string +import atexit + +import xasyUtils as xu +import xasy2asy as x2a +import xasyFile as xf +import xasyOptions as xo +import UndoRedoStack as Urs +import xasyArgs as xa +import xasyBezierInterface as xbi +from xasyTransform import xasyTransform as xT +import xasyStrings as xs + +import PrimitiveShape +import InplaceAddObj + +import CustMatTransform +import SetCustomAnchor +import GuidesManager + + +class ActionChanges: + pass + + +# State Invariance: When ActionChanges is at the top, all state of the program & file +# is exactly like what it was the event right after that ActionChanges was created. + +class TransformationChanges(ActionChanges): + def __init__(self, objIndex, transformation, isLocal=False): + self.objIndex = objIndex + self.transformation = transformation + self.isLocal = isLocal + + +class ObjCreationChanges(ActionChanges): + def __init__(self, obj): + self.object = obj + +class HardDeletionChanges(ActionChanges): + def __init__(self, obj, pos): + self.item = obj + self.objIndex = pos + +class AnchorMode: + origin = 0 + center = 1 + topLeft = 2 + topRight = 3 + bottomRight = 4 + bottomLeft = 5 + customAnchor = 6 + + +class GridMode: + cartesian = 0 + polar = 1 + + +class SelectionMode: + select = 0 + pan = 1 + translate = 2 + rotate = 3 + scale = 4 + delete = 5 + setAnchor = 6 + selectEdit = 7 + +class AddObjectMode: + Circle = 0 + Arc = 1 + Polygon = 2 + +class MainWindow1(Qw.QMainWindow): + defaultFrameStyle = """ + QFrame{{ + padding: 4.0; + border-radius: 3.0; + background: rgb({0}, {1}, {2}) + }} + """ + + def __init__(self): + super().__init__() + self.ui = Ui_MainWindow() + self.ui.setupUi(self) + self.ui.menubar.setNativeMenuBar(False) + + self.settings = xo.BasicConfigs.defaultOpt + self.keyMaps = xo.BasicConfigs.keymaps + + self.raw_args = Qc.QCoreApplication.arguments() + self.args = xa.parseArgs(self.raw_args) + + self.strings = xs.xasyString(self.args.language) + self.asy2psmap = x2a.identity() + + if self.settings['asyBaseLocation'] is not None: + os.environ['ASYMPTOTE_DIR'] = self.settings['asyBaseLocation'] + + if self.args.asypath is not None: + asyPath = self.args.asypath + else: + asyPath = self.settings['asyPath'] + + self.asyPath = asyPath + self.asyEngine = x2a.AsymptoteEngine(self.asyPath) + + try: + self.asyEngine.start() + finally: + atexit.register(self.asyEngine.cleanup) + + # For initialization purposes + self.canvSize = Qc.QSize() + self.filename = None + self.currDir = None + self.mainCanvas = None + self.dpi = 300 + self.canvasPixmap = None + + # Actions + # <editor-fold> Connecting Actions + self.ui.txtLineWidth.setValidator(Qg.QDoubleValidator()) + + self.connectActions() + self.connectButtons() + + self.ui.txtLineWidth.returnPressed.connect(self.btnTerminalCommandOnClick) + # </editor-fold> + + # Base Transformations + + self.mainTransformation = Qg.QTransform() + self.mainTransformation.scale(1, 1) + self.localTransform = Qg.QTransform() + self.screenTransformation = Qg.QTransform() + self.panTranslation = Qg.QTransform() + + # Internal Settings + self.magnification = self.args.mag + self.inMidTransformation = False + self.addMode = None + self.currentlySelectedObj = {'key': None, 'allSameKey': set(), 'selectedIndex': None, 'keyIndex': None} + self.pendingSelectedObjList = [] + self.pendingSelectedObjIndex = -1 + + self.savedMousePosition = None + self.currentBoundingBox = None + self.selectionDelta = None + self.newTransform = None + self.origBboxTransform = None + self.deltaAngle = 0 + self.scaleFactor = 1 + self.panOffset = [0, 0] + + super().setMouseTracking(True) + # setMouseTracking(True) + + self.undoRedoStack = Urs.actionStack() + + self.lockX = False + self.lockY = False + self.anchorMode = AnchorMode.center + self.currentAnchor = Qc.QPointF(0, 0) + self.customAnchor = None + self.useGlobalCoords = True + self.drawAxes = True + self.drawGrid = False + self.gridSnap = False # TODO: for now. turn it on later + + self.fileChanged = False + + self.terminalPythonMode = self.ui.btnTogglePython.isChecked() + + self.savedWindowMousePos = None + + self.finalPixmap = None + self.preCanvasPixmap = None + self.postCanvasPixmap = None + self.previewCurve = None + self.mouseDown = False + + self.globalObjectCounter = 0 + + self.fileItems = [] + self.drawObjects = [] + self.xasyDrawObj = {'drawDict': self.drawObjects} + + 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.objButtons = {self.ui.btnCustTransform, self.ui.actionTransform, self.ui.btnSendForwards, + self.ui.btnSendBackwards, self.ui.btnToggleVisible + } + + self.globalTransformOnlyButtons = (self.ui.comboAnchor, self.ui.btnAnchor) + + self.ui.txtTerminalPrompt.setFont(Qg.QFont(self.settings['terminalFont'])) + + self.currAddOptionsWgt = None + self.currAddOptions = { + 'options': self.settings, + 'inscribed': True, + 'sides': 3, + 'centermode': True, + 'fontSize': None, + 'asyengine': self.asyEngine, + 'fill': self.ui.btnFill.isChecked(), + 'closedPath': False, + 'useBezier': True, + 'magnification': self.magnification, + 'editBezierlockMode': xbi.Web.LockMode.angleLock, + 'autoRecompute': False + } + + + self.currentModeStack = [SelectionMode.translate] + self.drawGridMode = GridMode.cartesian + self.setAllInSetEnabled(self.objButtons, False) + self._currentPen = x2a.asyPen() + self.currentGuides = [] + self.selectAsGroup = self.settings['groupObjDefault'] + + # commands switchboard + self.commandsFunc = { + 'quit': Qc.QCoreApplication.quit, + 'undo': self.btnUndoOnClick, + 'redo': self.btnRedoOnClick, + 'manual': self.actionManual, + 'about': self.actionAbout, + 'loadFile': self.btnLoadFileonClick, + 'save': self.actionSave, + 'saveAs': self.actionSaveAs, + 'transform': self.btnCustTransformOnClick, + 'commandPalette': self.enterCustomCommand, + 'clearGuide': self.clearGuides, + 'finalizeAddObj': self.finalizeAddObj, + 'finalizeCurve': self.finalizeCurve, + 'finalizeCurveClosed': self.finalizeCurveClosed, + 'setMag': self.setMagPrompt, + 'deleteObject': self.btnSelectiveDeleteOnClick, + 'anchorMode': self.switchToAnchorMode, + 'moveUp': lambda: self.arrowButtons(0, 1, False), + 'moveDown': lambda: self.arrowButtons(0, -1, False), + + '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), + + 'zoomIn': lambda: self.arrowButtons(0, 1, False, True), + 'zoomOut': lambda: self.arrowButtons(0, -1, False, True) + } + + self.hiddenKeys = set() + + # Coordinates Label + + self.coordLabel = Qw.QLabel(self.ui.statusbar) + self.ui.statusbar.addPermanentWidget(self.coordLabel) + + # Settings Initialization + # from xasyoptions config file + self.loadKeyMaps() + self.setupXasyOptions() + + self.colorDialog = Qw.QColorDialog(x2a.asyPen.convertToQColor(self._currentPen.color), self) + self.initPenInterface() + + def arrowButtons(self, x:int , y:int, shift: bool=False, ctrl: bool=False): + "x, y indicates update button orientation on the cartesian plane." + if not (shift or ctrl): + self.changeSelection(y) + elif not (shift and ctrl): + self.mouseWheel(30*x, 30*y) + self.quickUpdate() + + def cleanup(self): + self.asyengine.cleanup() + + def getScrsTransform(self): + # pipeline: + # assuming origin <==> top left + # (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) + cx, cy = self.canvSize.width() / 2, self.canvSize.height() / 2 + + newTransf = Qg.QTransform() + newTransf.translate(*self.panOffset) + newTransf.translate(cx, cy) + newTransf.scale(1, 1) + newTransf.scale(self.magnification, self.magnification) + + return newTransf + + def finalizeCurve(self): + if self.addMode is not None: + if self.addMode.active and isinstance(self.addMode, InplaceAddObj.AddBezierShape): + self.addMode.forceFinalize() + self.fileChanged = True + + def finalizeCurveClosed(self): + if self.addMode is not None: + if self.addMode.active and isinstance(self.addMode, InplaceAddObj.AddBezierShape): + self.addMode.finalizeClosure() + self.fileChanged = True + + def getAllBoundingBox(self) -> Qc.QRectF: + newRect = Qc.QRectF() + for majitem in self.drawObjects: + for minitem in majitem: + newRect = newRect.united(minitem.boundingBox) + return newRect + + def finalizeAddObj(self): + if self.addMode is not None: + if self.addMode.active: + self.addMode.forceFinalize() + self.fileChanged = True + + def openAndReloadSettings(self): + settingsFile = self.settings.settingsFileLocation() + subprocess.run(args=self.getExternalEditor(asypath=settingsFile)) + self.settings.load() + self.quickUpdate() + + def setMagPrompt(self): + commandText, result = Qw.QInputDialog.getText(self, '', 'Enter magnification:') + if result: + self.magnification = float(commandText) + self.currAddOptions['magnification'] = self.magnification + self.quickUpdate() + + def btnTogglePythonOnClick(self, checked): + self.terminalPythonMode = checked + + def internationalize(self): + self.ui.btnRotate.setToolTip(self.strings.rotate) + + def handleArguments(self): + if self.args.filename is not None: + self.loadFile(self.args.filename) + else: + self.initializeEmptyFile() + + if self.args.language != 'en': + self.internationalize() + + def initPenInterface(self): + self.ui.txtLineWidth.setText(str(self._currentPen.width)) + self.updateFrameDispColor() + + def updateFrameDispColor(self): + r, g, b = [int(x * 255) for x in self._currentPen.color] + self.ui.frameCurrColor.setStyleSheet(MainWindow1.defaultFrameStyle.format(r, g, b)) + + def initDebug(self): + debugFunc = { + } + self.commandsFunc = {**self.commandsFunc, **debugFunc} + + def dbgRecomputeCtrl(self): + if isinstance(self.addMode, xbi.InteractiveBezierEditor): + self.addMode.recalculateCtrls() + self.quickUpdate() + + def objectUpdated(self): + self.removeAddMode() + self.clearSelection() + self.asyfyCanvas() + + def connectActions(self): + self.ui.actionQuit.triggered.connect(lambda: self.execCustomCommand('quit')) + self.ui.actionUndo.triggered.connect(lambda: self.execCustomCommand('undo')) + self.ui.actionRedo.triggered.connect(lambda: self.execCustomCommand('redo')) + self.ui.actionTransform.triggered.connect(lambda: self.execCustomCommand('transform')) + + self.ui.actionOpen.triggered.connect(self.actionOpen) + 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.actionEnterCommand.triggered.connect(self.enterCustomCommand) + self.ui.actionExportAsymptote.triggered.connect(self.btnExportAsyOnClick) + + def setupXasyOptions(self): + if self.settings['debugMode']: + self.initDebug() + newColor = Qg.QColor(self.settings['defaultPenColor']) + newWidth = self.settings['defaultPenWidth'] + + self._currentPen.setColorFromQColor(newColor) + self._currentPen.setWidth(newWidth) + + def connectButtons(self): + # Button initialization + self.ui.btnUndo.clicked.connect(self.btnUndoOnClick) + self.ui.btnRedo.clicked.connect(self.btnRedoOnClick) + self.ui.btnLoadFile.clicked.connect(self.btnLoadFileonClick) + self.ui.btnSave.clicked.connect(self.btnSaveonClick) + self.ui.btnQuickScreenshot.clicked.connect(self.btnQuickScreenshotOnClick) + + # self.ui.btnExportAsy.clicked.connect(self.btnExportAsyOnClick) + + self.ui.btnDrawAxes.clicked.connect(self.btnDrawAxesOnClick) +# self.ui.btnAsyfy.clicked.connect(lambda: self.asyfyCanvas(True)) + self.ui.btnSetZoom.clicked.connect(self.setMagPrompt) + self.ui.btnResetPan.clicked.connect(self.resetPan) + self.ui.btnPanCenter.clicked.connect(self.btnPanCenterOnClick) + + self.ui.btnTranslate.clicked.connect(self.btnTranslateonClick) + self.ui.btnRotate.clicked.connect(self.btnRotateOnClick) + self.ui.btnScale.clicked.connect(self.btnScaleOnClick) + # self.ui.btnSelect.clicked.connect(self.btnSelectOnClick) + self.ui.btnPan.clicked.connect(self.btnPanOnClick) + + # self.ui.btnDebug.clicked.connect(self.pauseBtnOnClick) + self.ui.btnAlignX.clicked.connect(self.btnAlignXOnClick) + self.ui.btnAlignY.clicked.connect(self.btnAlignYOnClick) + self.ui.comboAnchor.currentIndexChanged.connect(self.handleAnchorComboIndex) + self.ui.btnCustTransform.clicked.connect(self.btnCustTransformOnClick) + self.ui.btnViewCode.clicked.connect(self.btnLoadEditorOnClick) + + self.ui.btnAnchor.clicked.connect(self.btnAnchorModeOnClick) + + self.ui.btnSelectColor.clicked.connect(self.btnColorSelectOnClick) + self.ui.txtLineWidth.textEdited.connect(self.txtLineWithEdited) + + # self.ui.btnCreateCurve.clicked.connect(self.btnCreateCurveOnClick) + self.ui.btnDrawGrid.clicked.connect(self.btnDrawGridOnClick) + + self.ui.btnAddCircle.clicked.connect(self.btnAddCircleOnClick) + self.ui.btnAddPoly.clicked.connect(self.btnAddPolyOnClick) + self.ui.btnAddLabel.clicked.connect(self.btnAddLabelOnClick) + # self.ui.btnAddBezierInplace.clicked.connect(self.btnAddBezierInplaceOnClick) + self.ui.btnClosedCurve.clicked.connect(self.btnAddClosedCurveOnClick) + self.ui.btnOpenCurve.clicked.connect(self.btnAddOpenCurveOnClick) + self.ui.btnClosedPoly.clicked.connect(self.btnAddClosedLineOnClick) + self.ui.btnOpenPoly.clicked.connect(self.btnAddOpenLineOnClick) + + self.ui.btnFill.clicked.connect(self.btnFillOnClick) + + self.ui.btnSendBackwards.clicked.connect(self.btnSendBackwardsOnClick) + self.ui.btnSendForwards.clicked.connect(self.btnSendForwardsOnClick) + # self.ui.btnDelete.clicked.connect(self.btnSelectiveDeleteOnClick) + 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() + + def btnTerminalCommandOnClick(self): + if self.terminalPythonMode: + exec(self.ui.txtTerminalPrompt.text()) + self.fileChanged = True + else: + pass + # TODO: How to handle this case? + # Like AutoCAD? + self.ui.txtTerminalPrompt.clear() + + def btnFillOnClick(self, checked): + 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() + + @property + def currentPen(self): + return x2a.asyPen.fromAsyPen(self._currentPen) + pass + def debug(self): + print('Put a breakpoint here.') + + def execPythonCmd(self): + commandText, result = Qw.QInputDialog.getText(self, '', 'enter python cmd') + if result: + exec(commandText) + + def deleteAddOptions(self): + if self.currAddOptionsWgt is not None: + self.currAddOptionsWgt.hide() + self.ui.addOptionLayout.removeWidget(self.currAddOptionsWgt) + self.currAddOptionsWgt = None + + def updateOptionWidget(self): + try: + self.addMode.objectCreated.disconnect() + except Exception: + pass + + self.currentModeStack[-1] = None + self.addMode.objectCreated.connect(self.addInPlace) + self.updateModeBtnsOnly() + + + self.deleteAddOptions() + + self.currAddOptionsWgt = self.addMode.createOptWidget(self.currAddOptions) + if self.currAddOptionsWgt is not None: + self.ui.addOptionLayout.addWidget(self.currAddOptionsWgt) + + def addInPlace(self, obj): + obj.asyengine = self.asyEngine + obj.pen = self.currentPen + obj.onCanvas = self.xasyDrawObj + obj.setKey(str(self.globalObjectCounter)) + self.globalObjectCounter = self.globalObjectCounter + 1 + + self.fileItems.append(obj) + self.fileChanged = True + self.addObjCreationUrs(obj) + self.asyfyCanvas() + + def addObjCreationUrs(self, obj): + newAction = self.createAction(ObjCreationChanges(obj)) + self.undoRedoStack.add(newAction) + self.checkUndoRedoButtons() + + def clearGuides(self): + 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.' + + def drawHint(self): + if self.settings['useLegacyDrawMode']: + self.ui.statusbar.showMessage(self.LegacyHint+'.') + else: + self.ui.statusbar.showMessage(self.Hint+'.') + + def drawHintOpen(self): + if self.settings['useLegacyDrawMode']: + self.ui.statusbar.showMessage(self.LegacyHint+self.HintClose) + else: + self.ui.statusbar.showMessage(self.Hint+self.HintClose) + + def btnAddBezierInplaceOnClick(self): + self.addMode = InplaceAddObj.AddBezierShape(self) + self.updateOptionWidget() + + def btnAddOpenLineOnClick(self): + self.currAddOptions['useBezier'] = False + self.currAddOptions['closedPath'] = False + self.drawHintOpen() + self.btnAddBezierInplaceOnClick() + + def btnAddClosedLineOnClick(self): + self.currAddOptions['useBezier'] = False + self.currAddOptions['closedPath'] = True + self.drawHint() + self.btnAddBezierInplaceOnClick() + + def btnAddOpenCurveOnClick(self): + self.currAddOptions['useBezier'] = True + self.currAddOptions['closedPath'] = False + self.drawHintOpen() + self.btnAddBezierInplaceOnClick() + + def btnAddClosedCurveOnClick(self): + self.currAddOptions['useBezier'] = True + self.currAddOptions['closedPath'] = True + self.drawHint() + self.btnAddBezierInplaceOnClick() + + def btnAddPolyOnClick(self): + self.addMode = InplaceAddObj.AddPoly(self) + self.ui.statusbar.showMessage('') + self.updateOptionWidget() + + def btnAddLabelOnClick(self): + self.addMode = InplaceAddObj.AddLabel(self) + self.ui.statusbar.showMessage('') + self.updateOptionWidget() + + def updateCurve(self, valid, newCurve): + self.previewCurve = newCurve + self.quickUpdate() + + def addTransformationChanges(self, objIndex, transform, isLocal=False): + self.undoRedoStack.add(self.createAction(TransformationChanges(objIndex, + transform, isLocal))) + self.checkUndoRedoButtons() + + def btnSendForwardsOnClick(self): + if self.currentlySelectedObj['selectedIndex'] is not None: + maj, minor = self.currentlySelectedObj['selectedIndex'] + selectedObj = self.drawObjects[maj][minor] + index = self.fileItems.index(selectedObj.parent()) + + self.clearSelection() + if index == len(self.fileItems) - 1: + return + else: + self.fileItems[index], self.fileItems[index + 1] = self.fileItems[index + 1], self.fileItems[index] + self.asyfyCanvas() + + def btnSelectiveDeleteOnClick(self): + if self.currentlySelectedObj['selectedIndex'] is not None: + maj, minor = self.currentlySelectedObj['selectedIndex'] + selectedObj = self.drawObjects[maj][minor] + + parent = selectedObj.parent() + + if isinstance(parent, x2a.xasyScript): + self.hiddenKeys.add((selectedObj.key, selectedObj.keyIndex)) + self.softDeleteObj((maj, minor)) + else: + index = self.fileItems.index(selectedObj.parent()) + + self.undoRedoStack.add(self.createAction( + HardDeletionChanges(selectedObj.parent(), index) + )) + self.checkUndoRedoButtons() + + self.fileItems.remove(selectedObj.parent()) + + self.fileChanged = True + self.clearSelection() + self.asyfyCanvas() + else: + result = self.selectOnHover() + if result: + self.btnSelectiveDeleteOnClick() + + def btnSetVisibilityOnClick(self): + if self.currentlySelectedObj['selectedIndex'] is not None: + maj, minor = self.currentlySelectedObj['selectedIndex'] + selectedObj = self.drawObjects[maj][minor] + + self.hiddenKeys.symmetric_difference_update({(selectedObj.key, selectedObj.keyIndex)}) + self.clearSelection() + self.quickUpdate() + + def btnSendBackwardsOnClick(self): + if self.currentlySelectedObj['selectedIndex'] is not None: + maj, minor = self.currentlySelectedObj['selectedIndex'] + selectedObj = self.drawObjects[maj][minor] + index = self.fileItems.index(selectedObj.parent()) + + self.clearSelection() + if index == 0: + return + else: + self.fileItems[index], self.fileItems[index - 1] = self.fileItems[index - 1], self.fileItems[index] + self.asyfyCanvas() + + + def btnUndoOnClick(self): + self.undoRedoStack.undo() + self.checkUndoRedoButtons() + + def btnRedoOnClick(self): + self.undoRedoStack.redo() + self.checkUndoRedoButtons() + + def checkUndoRedoButtons(self): + self.ui.btnUndo.setEnabled(self.undoRedoStack.changesMade()) + self.ui.actionUndo.setEnabled(self.undoRedoStack.changesMade()) + + self.ui.btnRedo.setEnabled(len(self.undoRedoStack.redoStack) > 0) + self.ui.actionRedo.setEnabled(len(self.undoRedoStack.redoStack) > 0) + + def handleUndoChanges(self, change): + assert isinstance(change, ActionChanges) + if isinstance(change, TransformationChanges): + self.transformObject(change.objIndex, change.transformation.inverted(), change.isLocal) + elif isinstance(change, ObjCreationChanges): + self.fileItems.pop() + elif isinstance(change, HardDeletionChanges): + self.fileItems.insert(change.objIndex, change.item) + self.asyfyCanvas() + + def handleRedoChanges(self, change): + assert isinstance(change, ActionChanges) + if isinstance(change, TransformationChanges): + self.transformObject( + change.objIndex, change.transformation, change.isLocal) + elif isinstance(change, ObjCreationChanges): + self.fileItems.append(change.object) + elif isinstance(change, HardDeletionChanges): + self.fileItems.remove(change.item) + self.asyfyCanvas() + + # is this a "pythonic" way? + def createAction(self, changes): + def _change(): + return self.handleRedoChanges(changes) + + def _undoChange(): + return self.handleUndoChanges(changes) + + return Urs.action((_change, _undoChange)) + + def execCustomCommand(self, command): + if command in self.commandsFunc: + self.commandsFunc[command]() + else: + self.ui.statusbar.showMessage('Command {0} not found'.format(command)) + + def enterCustomCommand(self): + commandText, result = Qw.QInputDialog.getText(self, 'Enter Custom Command', 'Enter Custom Command') + if result: + self.execCustomCommand(commandText) + + def addItemFromPath(self, path): + newItem = x2a.xasyShape(path, self.asyEngine, pen=self.currentPen) + self.fileItems.append(newItem) + self.fileChanged = True + self.asyfyCanvas() + + def actionManual(self): + asyManualURL = 'http://asymptote.sourceforge.net/asymptote.pdf' + webbrowser.open_new(asyManualURL) + + def actionAbout(self): + Qw.QMessageBox.about(self,"xasy","This is xasy "+xasyVersion.xasyVersion+"; a graphical front end to the Asymptote vector graphics language: http://asymptote.sourceforge.net/") + + def btnExportAsyOnClick(self): + diag = Qw.QFileDialog(self) + diag.setAcceptMode(Qw.QFileDialog.AcceptSave) + + formatId = { + 'pdf': { + 'name': 'PDF Files', + 'ext': ['*.pdf'] + }, + 'svg': { + 'name': 'Scalable Vector Graphics', + 'ext': ['*.svg'] + }, + 'eps': { + 'name': 'Postscript Files', + 'ext': ['*.eps'] + }, + 'png': { + 'name': 'Portable Network Graphics', + 'ext': ['*.png'] + }, + '*': { + 'name': 'Any Files', + 'ext': ['*.*'] + } + } + + formats = ['pdf', 'svg', 'eps', 'png', '*'] + + formatText = ';;'.join('{0:s} ({1:s})'.format(formatId[form]['name'], ' '.join(formatId[form]['ext'])) + for form in formats) + + if self.currDir is not None: + diag.setDirectory(self.currDir) + rawFile = os.path.splitext(os.path.basename(self.filename))[0] + '.pdf' + diag.selectFile(rawFile) + + diag.setNameFilter(formatText) + diag.show() + result = diag.exec_() + + if result != diag.Accepted: + return + + finalFiles = diag.selectedFiles() + + 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' + else: + ext = ext[1][1:] + + 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) + + + def loadKeyMaps(self): + """Inverts the mapping of the key + Input map is in format 'Action' : 'Key Sequence' """ + for action, key in self.keyMaps.options.items(): + shortcut = Qw.QShortcut(self) + shortcut.setKey(Qg.QKeySequence(key)) + + # hate doing this, but python doesn't have explicit way to pass a + # string to a lambda without an identifier + # attached to it. + exec('shortcut.activated.connect(lambda: self.execCustomCommand("{0}"))'.format(action), + {'self': self, 'shortcut': shortcut}) + + def initializeButtons(self): + self.ui.btnDrawAxes.setChecked(self.settings['defaultShowAxes']) + self.btnDrawAxesOnClick(self.settings['defaultShowAxes']) + + self.ui.btnDrawGrid.setChecked(self.settings['defaultShowGrid']) + self.btnDrawGridOnClick(self.settings['defaultShowGrid']) + + def erase(self): + self.fileItems.clear() + self.fileChanged = False + + def actionOpen(self): + 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() + + filename = Qw.QFileDialog.getOpenFileName(self, 'Open Asymptote File','', '*.asy') + if filename[0]: + self.loadFile(filename[0]) + + def actionSave(self): + if self.filename is None: + self.actionSaveAs() + else: + saveFile = io.open(self.filename, 'w') + xf.saveFile(saveFile, self.fileItems, self.asy2psmap) + saveFile.close() + self.updateScript() + + def updateScript(self): + for item in self.fileItems: + if isinstance(item, x2a.xasyScript): + if item.updatedCode: + item.setScript(item.updatedCode) + item.updatedCode = None + + def actionSaveAs(self): + saveLocation = Qw.QFileDialog.getSaveFileName(self, 'Save File')[0] + if saveLocation: + saveFile = io.open(saveLocation, 'w') + xf.saveFile(saveFile, self.fileItems, self.asy2psmap) + saveFile.close() + self.filename = saveLocation + self.updateScript() + + + def btnQuickScreenshotOnClick(self): + saveLocation = Qw.QFileDialog.getSaveFileName(self, 'Save Screenshot','') + if saveLocation[0]: + self.ui.imgLabel.pixmap().save(saveLocation[0]) + + def btnLoadFileonClick(self): + self.actionOpen() + + def btnSaveonClick(self): + self.actionSave() + + @Qc.pyqtSlot(int) + def handleAnchorComboIndex(self, index: int): + self.anchorMode = index + if self.anchorMode == AnchorMode.customAnchor: + if self.customAnchor is not None: + self.anchorMode = AnchorMode.customAnchor + else: + self.ui.comboAnchor.setCurrentIndex(AnchorMode.center) + self.anchorMode = AnchorMode.center + self.quickUpdate() + def btnColorSelectOnClick(self): + self.colorDialog.show() + result = self.colorDialog.exec() + if result == Qw.QDialog.Accepted: + self._currentPen.setColorFromQColor(self.colorDialog.selectedColor()) + self.updateFrameDispColor() + + def txtLineWithEdited(self, text): + new_val = xu.tryParse(text, float) + if new_val is not None: + if new_val > 0: + self._currentPen.setWidth(new_val) + + def isReady(self): + return self.mainCanvas is not None + + def resizeEvent(self, resizeEvent): + # super().resizeEvent(resizeEvent) + assert isinstance(resizeEvent, Qg.QResizeEvent) + + if self.isReady(): + if self.mainCanvas.isActive(): + self.mainCanvas.end() + self.canvSize = self.ui.imgFrame.size() + self.ui.imgFrame.setSizePolicy(Qw.QSizePolicy.Ignored, Qw.QSizePolicy.Ignored) + self.canvasPixmap = Qg.QPixmap(self.canvSize) + # self.canvasPixmap.setDevicePixelRatio(3) + self.postCanvasPixmap = Qg.QPixmap(self.canvSize) + + self.quickUpdate() + + def show(self): + super().show() + self.createMainCanvas() # somehow, the coordinates doesn't get updated until after showing. + self.initializeButtons() + self.postShow() + + def postShow(self): + self.handleArguments() + + def roundPositionSnap(self, oldPoint): + minorGridSize = self.settings['gridMajorAxesSpacing'] / (self.settings['gridMinorAxesCount'] + 1) + if isinstance(oldPoint, list) or isinstance(oldPoint, tuple): + return [round(val / minorGridSize) * minorGridSize for val in oldPoint] + elif isinstance(oldPoint, Qc.QPoint) or isinstance(oldPoint, Qc.QPointF): + x, y = oldPoint.x(), oldPoint.y() + x = round(x / minorGridSize) * minorGridSize + y = round(y / minorGridSize) * minorGridSize + return Qc.QPointF(x, y) + else: + raise Exception + + def getAsyCoordinates(self): + canvasPosOrig = self.getCanvasCoordinates() + return canvasPosOrig, canvasPosOrig + + def mouseMoveEvent(self, mouseEvent: Qg.QMouseEvent): # TODO: Actually refine grid snapping... + if not self.ui.imgLabel.underMouse() and not self.mouseDown: + return + + self.updateMouseCoordLabel() + asyPos, canvasPos = self.getAsyCoordinates() + + # add mode + if self.addMode is not None: + if self.addMode.active: + self.addMode.mouseMove(asyPos, mouseEvent) + self.quickUpdate() + return + + # pan mode + if self.currentModeStack[-1] == SelectionMode.pan and int(mouseEvent.buttons()) and self.savedWindowMousePos is not None: + mousePos = self.getWindowCoordinates() + newPos = mousePos - self.savedWindowMousePos + + tx, ty = newPos.x(), newPos.y() + + if self.lockX: + tx = 0 + if self.lockY: + ty = 0 + + self.panOffset[0] += tx + self.panOffset[1] += ty + + self.savedWindowMousePos = self.getWindowCoordinates() + self.quickUpdate() + return + + # otherwise, in transformation + if self.inMidTransformation: + if self.currentModeStack[-1] == SelectionMode.translate: + newPos = canvasPos - self.savedMousePosition + if self.gridSnap: + newPos = self.roundPositionSnap(newPos) # actually round to the nearest minor grid afterwards... + + self.tx, self.ty = newPos.x(), newPos.y() + + if self.lockX: + self.tx = 0 + if self.lockY: + self.ty = 0 + self.newTransform = Qg.QTransform.fromTranslate(self.tx, self.ty) + + elif self.currentModeStack[-1] == SelectionMode.rotate: + if self.gridSnap: + canvasPos = self.roundPositionSnap(canvasPos) + + adjustedSavedMousePos = self.savedMousePosition - self.currentAnchor + adjustedCanvasCoords = canvasPos - self.currentAnchor + + origAngle = np.arctan2(adjustedSavedMousePos.y(), adjustedSavedMousePos.x()) + newAng = np.arctan2(adjustedCanvasCoords.y(), adjustedCanvasCoords.x()) + self.deltaAngle = newAng - origAngle + self.newTransform = xT.makeRotTransform(self.deltaAngle, self.currentAnchor).toQTransform() + + elif self.currentModeStack[-1] == SelectionMode.scale: + if self.gridSnap: + canvasPos = self.roundPositionSnap(canvasPos) + x, y = int(round(canvasPos.x())), int(round(canvasPos.y())) # otherwise it crashes... + canvasPos = Qc.QPoint(x, y) + + originalDeltaPts = self.savedMousePosition - self.currentAnchor + scaleFactor = Qc.QPointF.dotProduct(canvasPos - self.currentAnchor, originalDeltaPts) /\ + (xu.twonorm((originalDeltaPts.x(), originalDeltaPts.y())) ** 2) + if not self.lockX: + self.scaleFactorX = scaleFactor + else: + self.scaleFactorX = 1 + + if not self.lockY: + self.scaleFactorY = scaleFactor + else: + self.scaleFactorY = 1 + + self.newTransform = xT.makeScaleTransform(self.scaleFactorX, self.scaleFactorY, self.currentAnchor).\ + toQTransform() + + self.quickUpdate() + return + + # otherwise, select a candinate for selection + + if self.currentlySelectedObj['selectedIndex'] is None: + selectedIndex, selKeyList = self.selectObject() + if selectedIndex is not None: + if self.pendingSelectedObjList != selKeyList: + self.pendingSelectedObjList = selKeyList + self.pendingSelectedObjIndex = -1 + else: + self.pendingSelectedObjList.clear() + self.pendingSelectedObjIndex = -1 + self.quickUpdate() + return + + + def mouseReleaseEvent(self, mouseEvent): + assert isinstance(mouseEvent, Qg.QMouseEvent) + if not self.mouseDown: + return + + self.mouseDown = False + if self.addMode is not None: + self.addMode.mouseRelease() + if self.inMidTransformation: + self.clearSelection() + self.inMidTransformation = False + self.quickUpdate() + + def clearSelection(self): + if self.currentlySelectedObj['selectedIndex'] is not None: + self.releaseTransform() + self.setAllInSetEnabled(self.objButtons, False) + self.currentlySelectedObj['selectedIndex'] = None + self.currentlySelectedObj['key'] = None + + self.currentlySelectedObj['allSameKey'].clear() + self.newTransform = Qg.QTransform() + self.currentBoundingBox = None + self.quickUpdate() + + def changeSelection(self, offset): + if self.pendingSelectedObjList: + if offset > 0: + if self.pendingSelectedObjIndex + offset <= -1: + self.pendingSelectedObjIndex = self.pendingSelectedObjIndex + offset + else: + if self.pendingSelectedObjIndex + offset >= -len(self.pendingSelectedObjList): + self.pendingSelectedObjIndex = self.pendingSelectedObjIndex + offset + + def mouseWheel(self, rawAngleX: float, rawAngle: float, defaultModifiers: int=0): + keyModifiers = int(Qw.QApplication.keyboardModifiers()) + keyModifiers = keyModifiers | defaultModifiers + if keyModifiers & int(Qc.Qt.ControlModifier): + oldMag = self.magnification + + cx, cy = self.canvSize.width() / 2, self.canvSize.height() / 2 + centerPoint = Qc.QPointF(cx, cy) * self.getScrsTransform().inverted()[0] + + self.magnification += (rawAngle/100) + + if self.magnification < self.settings['minimumMagnification']: + self.magnification = self.settings['minimumMagnification'] + elif self.magnification > self.settings['maximumMagnification']: + self.magnification = self.settings['maximumMagnification'] + + # set the new pan. Let c be the fixed point (center point), + # Let m the old mag, n the new mag + + # find t2 such that + # mc + t1 = nc + t2 ==> t2 = (m - n)c + t1 + + centerPoint = (oldMag - self.magnification) * centerPoint + + self.panOffset = [ + self.panOffset[0] + centerPoint.x(), + self.panOffset[1] + centerPoint.y() + ] + + self.currAddOptions['magnification'] = self.magnification + + if self.addMode is xbi.InteractiveBezierEditor: + self.addMode.setSelectionBoundaries() + + elif keyModifiers & (int(Qc.Qt.ShiftModifier) | int(Qc.Qt.AltModifier)): + self.panOffset[1] += rawAngle/1 + self.panOffset[0] -= rawAngleX/1 + # handle scrolling + else: + # process selection layer change + if rawAngle >= 15: + self.changeSelection(1) + elif rawAngle <= -15: + self.changeSelection(-1) + self.quickUpdate() + + def wheelEvent(self, event: Qg.QWheelEvent): + rawAngle = event.angleDelta().y() / 8 + rawAngleX = event.angleDelta().x() / 8 + self.mouseWheel(rawAngleX, rawAngle) + + def selectOnHover(self): + """Returns True if selection happened, False otherwise. + """ + if self.pendingSelectedObjList: + selectedIndex = self.pendingSelectedObjList[self.pendingSelectedObjIndex] + self.pendingSelectedObjList.clear() + + maj, minor = selectedIndex + + self.currentlySelectedObj['selectedIndex'] = selectedIndex + self.currentlySelectedObj['key'], self.currentlySelectedObj['allSameKey'] = self.selectObjectSet( + ) + + self.currentBoundingBox = self.drawObjects[maj][minor].boundingBox + + if self.selectAsGroup: + for selItems in self.currentlySelectedObj['allSameKey']: + obj = self.drawObjects[selItems[0]][selItems[1]] + self.currentBoundingBox = self.currentBoundingBox.united(obj.boundingBox) + + self.origBboxTransform = self.drawObjects[maj][minor].transform.toQTransform() + self.newTransform = Qg.QTransform() + return True + else: + return False + + def mousePressEvent(self, mouseEvent: Qg.QMouseEvent): + # we make an exception for bezier curve + bezierException = False + 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 + + self.mouseDown = True + asyPos, self.savedMousePosition = self.getAsyCoordinates() + + if self.addMode is not None: + self.addMode.mouseDown(asyPos, self.currAddOptions, mouseEvent) + elif self.currentModeStack[-1] == SelectionMode.pan: + self.savedWindowMousePos = self.getWindowCoordinates() + elif self.currentModeStack[-1] == SelectionMode.setAnchor: + self.customAnchor = self.savedMousePosition + self.currentModeStack.pop() + + self.anchorMode = AnchorMode.customAnchor + self.ui.comboAnchor.setCurrentIndex(AnchorMode.customAnchor) + self.updateChecks() + self.quickUpdate() + elif self.inMidTransformation: + pass + elif self.pendingSelectedObjList: + self.selectOnHover() + + if self.currentModeStack[-1] in {SelectionMode.translate, SelectionMode.rotate, SelectionMode.scale}: + self.setAllInSetEnabled(self.objButtons, False) + self.inMidTransformation = True + self.setAnchor() + elif self.currentModeStack[-1] == SelectionMode.delete: + self.btnSelectiveDeleteOnClick() + elif self.currentModeStack[-1] == SelectionMode.selectEdit: + self.setupSelectEdit() + else: + self.setAllInSetEnabled(self.objButtons, True) + self.inMidTransformation = False + self.setAnchor() + + else: + self.setAllInSetEnabled(self.objButtons, False) + self.currentBoundingBox = None + self.inMidTransformation = False + self.clearSelection() + + self.quickUpdate() + + def removeAddMode(self): + self.addMode = None + self.deleteAddOptions() + + def editFinalized(self): + self.addMode.forceFinalize() + self.removeAddMode() + self.fileChanged = True + self.quickUpdate() + + def editRejected(self): + self.addMode.resetObj() + self.editFinalized() + + def setupSelectEdit(self): + """For Select-Edit mode. For now, if the object selected is a bezier curve, opens up a bezier editor""" + maj, minor = self.currentlySelectedObj['selectedIndex'] + obj = self.fileItems[maj] + if isinstance(obj, x2a.xasyDrawnItem): + # bezier path + self.addMode = xbi.InteractiveBezierEditor(self, obj, self.currAddOptions) + self.addMode.objectUpdated.connect(self.objectUpdated) + self.addMode.editAccepted.connect(self.editFinalized) + self.addMode.editRejected.connect(self.editRejected) + self.updateOptionWidget() + self.currentModeStack[-1] = SelectionMode.selectEdit + self.fileChanged = True + else: + self.clearSelection() + self.quickUpdate() + + def setAnchor(self): + if self.anchorMode == AnchorMode.center: + self.currentAnchor = self.currentBoundingBox.center() + elif self.anchorMode == AnchorMode.topLeft: + self.currentAnchor = self.currentBoundingBox.bottomLeft() # due to internal image being flipped + elif self.anchorMode == AnchorMode.topRight: + self.currentAnchor = self.currentBoundingBox.bottomRight() + elif self.anchorMode == AnchorMode.bottomLeft: + self.currentAnchor = self.currentBoundingBox.topLeft() + elif self.anchorMode == AnchorMode.bottomRight: + self.currentAnchor = self.currentBoundingBox.topRight() + elif self.anchorMode == AnchorMode.customAnchor: + self.currentAnchor = self.customAnchor + else: + self.currentAnchor = Qc.QPointF(0, 0) + + if self.anchorMode != AnchorMode.origin: + pass + # TODO: Record base points/bbox before hand and use that for + # anchor? + # adjTransform = + # self.drawObjects[selectedIndex].transform.toQTransform() + # self.currentAnchor = adjTransform.map(self.currentAnchor) + + + def releaseTransform(self): + if self.newTransform.isIdentity(): + return + newTransform = x2a.asyTransform.fromQTransform(self.newTransform) + objKey = self.currentlySelectedObj['selectedIndex'] + self.addTransformationChanges(objKey, newTransform, not self.useGlobalCoords) + self.transformObject(objKey, newTransform, not self.useGlobalCoords) + + def adjustTransform(self, appendTransform): + self.screenTransformation = self.screenTransformation * appendTransform + + def createMainCanvas(self): + self.canvSize = self.ui.imgFrame.size() + self.ui.imgFrame.setSizePolicy(Qw.QSizePolicy.Ignored, Qw.QSizePolicy.Ignored) + x, y = self.canvSize.width() / 2, self.canvSize.height() / 2 + + self.canvasPixmap = Qg.QPixmap(self.canvSize) + self.canvasPixmap.fill() + + self.finalPixmap = Qg.QPixmap(self.canvSize) + + self.preCanvasPixmap = Qg.QPixmap(self.canvSize) + self.postCanvasPixmap = Qg.QPixmap(self.canvSize) + + self.mainCanvas = Qg.QPainter(self.canvasPixmap) + self.mainCanvas.setRenderHint(Qg.QPainter.Antialiasing) + self.mainCanvas.setRenderHint(Qg.QPainter.SmoothPixmapTransform) + self.mainCanvas.setRenderHint(Qg.QPainter.HighQualityAntialiasing) + self.xasyDrawObj['canvas'] = self.mainCanvas + + self.mainTransformation = Qg.QTransform() + self.mainTransformation.scale(1, 1) + self.mainTransformation.translate(x, y) + + self.mainCanvas.setTransform(self.getScrsTransform(), True) + + self.ui.imgLabel.setPixmap(self.canvasPixmap) + + def resetPan(self): + self.panOffset = [0, 0] + self.quickUpdate() + + def btnPanCenterOnClick(self): + newCenter = self.getAllBoundingBox().center() + + # adjust to new magnification + # technically, doable through getscrstransform() + # and subtract pan offset and center points + # but it's much more work... + newCenter = self.magnification * newCenter + self.panOffset = [-newCenter.x(), newCenter.y()] + + self.quickUpdate() + + def selectObject(self): + if not self.ui.imgLabel.underMouse(): + return None, [] + canvasCoords = self.getCanvasCoordinates() + highestDrawPriority = -np.inf + collidedObjKey = None + rawObjNumList = [] + for objKeyMaj in range(len(self.drawObjects)): + for objKeyMin in range(len(self.drawObjects[objKeyMaj])): + obj = self.drawObjects[objKeyMaj][objKeyMin] + if obj.collide(canvasCoords) and (obj.key, obj.keyIndex) not in self.hiddenKeys: + rawObjNumList.append(((objKeyMaj, objKeyMin), obj.drawOrder)) + if obj.drawOrder > highestDrawPriority: + collidedObjKey = (objKeyMaj, objKeyMin) + if collidedObjKey is not None: + rawKey = self.drawObjects[collidedObjKey[0]][collidedObjKey[1]].key +# self.ui.statusbar.showMessage('Collide with {0}, Key is {1}'.format(str(collidedObjKey), rawKey), 2500) + self.ui.statusbar.showMessage('Key: {0}'.format(rawKey), 2500) + return collidedObjKey, [rawObj[0] for rawObj in sorted(rawObjNumList, key=lambda ordobj: ordobj[1])] + else: + return None, [] + + def selectObjectSet(self): + objKey = self.currentlySelectedObj['selectedIndex'] + if objKey is None: + return set() + assert isinstance(objKey, (tuple, list)) and len(objKey) == 2 + rawObj = self.drawObjects[objKey[0]][objKey[1]] + rawKey = rawObj.key + rawSet = {objKey} + for objKeyMaj in range(len(self.drawObjects)): + for objKeyMin in range(len(self.drawObjects[objKeyMaj])): + obj = self.drawObjects[objKeyMaj][objKeyMin] + if obj.key == rawKey: + rawSet.add((objKeyMaj, objKeyMin)) + return rawKey, rawSet + + def getCanvasCoordinates(self): + # assert self.ui.imgLabel.underMouse() + uiPos = self.mapFromGlobal(Qg.QCursor.pos()) + canvasPos = self.ui.imgLabel.mapFrom(self, uiPos) + + # Issue: For magnification, should xasy treats this at xasy level, or asy level? + return canvasPos * self.getScrsTransform().inverted()[0] + + def getWindowCoordinates(self): + # assert self.ui.imgLabel.underMouse() + return self.mapFromGlobal(Qg.QCursor.pos()) + + def refreshCanvas(self): + if self.mainCanvas.isActive(): + self.mainCanvas.end() + self.mainCanvas.begin(self.canvasPixmap) + self.mainCanvas.setTransform(self.getScrsTransform()) + + def asyfyCanvas(self, force=False): + self.drawObjects = [] + self.populateCanvasWithItems(force) + self.quickUpdate() + if self.currentModeStack[-1] == SelectionMode.translate: + self.ui.statusbar.showMessage(self.strings.asyfyComplete) + + def updateMouseCoordLabel(self): + *args, canvasPos = self.getAsyCoordinates() + nx, ny = self.asy2psmap.inverted() * (canvasPos.x(), canvasPos.y()) + self.coordLabel.setText('{0:.2f}, {1:.2f} '.format(nx, ny)) + + def quickUpdate(self): + self.updateMouseCoordLabel() + self.refreshCanvas() + + self.preDraw(self.mainCanvas) + self.quickDraw() + + self.mainCanvas.end() + self.postDraw() + self.updateScreen() + + def quickDraw(self): + assert self.isReady() + dpi = self.magnification * self.dpi + activeItem = None + for majorItem in self.drawObjects: + for item in majorItem: + # hidden objects - toggleable + if (item.key, item.keyIndex) in self.hiddenKeys: + continue + isSelected = item.key == self.currentlySelectedObj['key'] + if not self.selectAsGroup and isSelected and self.currentlySelectedObj['selectedIndex'] is not None: + maj, min_ = self.currentlySelectedObj['selectedIndex'] + isSelected = isSelected and item is self.drawObjects[maj][min_] + if isSelected and self.settings['enableImmediatePreview']: + activeItem = item + if self.useGlobalCoords: + item.draw(self.newTransform, canvas=self.mainCanvas, dpi=dpi) + else: + item.draw(self.newTransform, applyReverse=True, canvas=self.mainCanvas, dpi=dpi) + else: + item.draw(canvas=self.mainCanvas, dpi=dpi) + + if self.settings['drawSelectedOnTop']: + if self.pendingSelectedObjList: + maj, minor = self.pendingSelectedObjList[self.pendingSelectedObjIndex] + self.drawObjects[maj][minor].draw(canvas=self.mainCanvas, dpi=dpi) + # and apply the preview too... + elif activeItem is not None: + if self.useGlobalCoords: + activeItem.draw(self.newTransform, canvas=self.mainCanvas, dpi=dpi) + else: + activeItem.draw(self.newTransform, applyReverse=True, canvas=self.mainCanvas, dpi=dpi) + activeItem = None + + def updateScreen(self): + self.finalPixmap = Qg.QPixmap(self.canvSize) + self.finalPixmap.fill(Qc.Qt.black) + with Qg.QPainter(self.finalPixmap) as finalPainter: + drawPoint = Qc.QPoint(0, 0) + # finalPainter.drawPixmap(drawPoint, self.preCanvasPixmap) + finalPainter.drawPixmap(drawPoint, self.canvasPixmap) + finalPainter.drawPixmap(drawPoint, self.postCanvasPixmap) + self.ui.imgLabel.setPixmap(self.finalPixmap) + + def drawCartesianGrid(self, preCanvas): + majorGrid = self.settings['gridMajorAxesSpacing'] * self.asy2psmap.xx + minorGridCount = self.settings['gridMinorAxesCount'] + + majorGridCol = Qg.QColor(self.settings['gridMajorAxesColor']) + minorGridCol = Qg.QColor(self.settings['gridMinorAxesColor']) + + panX, panY = self.panOffset + + x_range = (self.canvSize.width() / 2 + (2 * abs(panX)))/self.magnification + y_range = (self.canvSize.height() / 2 + (2 * abs(panY)))/self.magnification + + for x in np.arange(0, 2 * x_range + 1, majorGrid): # have to do + # this in two stages... + preCanvas.setPen(minorGridCol) + for xMinor in range(1, minorGridCount + 1): + xCoord = x + ((xMinor / (minorGridCount + 1)) * majorGrid) + preCanvas.drawLine(Qc.QLine(xCoord, -9999, xCoord, 9999)) + preCanvas.drawLine(Qc.QLine(-xCoord, -9999, -xCoord, 9999)) + + for y in np.arange(0, 2 * y_range + 1, majorGrid): + preCanvas.setPen(minorGridCol) + for yMinor in range(1, minorGridCount + 1): + yCoord = y + ((yMinor / (minorGridCount + 1)) * majorGrid) + preCanvas.drawLine(Qc.QLine(-9999, yCoord, 9999, yCoord)) + preCanvas.drawLine(Qc.QLine(-9999, -yCoord, 9999, -yCoord)) + + preCanvas.setPen(majorGridCol) + 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) + preCanvas.drawLine(Qc.QLine(x, -9999, x, 9999)) + preCanvas.drawLine(Qc.QLine(-x, -9999, -x, 9999)) + + def drawPolarGrid(self, preCanvas): + center = Qc.QPointF(0, 0) + majorGridCol = Qg.QColor(self.settings['gridMajorAxesColor']) + minorGridCol = Qg.QColor(self.settings['gridMinorAxesColor']) + majorGrid = self.settings['gridMajorAxesSpacing'] + minorGridCount = self.settings['gridMinorAxesCount'] + + majorAxisAng = (np.pi/4) # 45 degrees - for now. + minorAxisCount = 2 # 15 degrees each + + subRadiusSize = int(round((majorGrid / (minorGridCount + 1)))) + subAngleSize = majorAxisAng / (minorAxisCount + 1) + + for radius in range(majorGrid, 9999 + 1, majorGrid): + preCanvas.setPen(majorGridCol) + preCanvas.drawEllipse(center, radius, radius) + + preCanvas.setPen(minorGridCol) + + for minorRing in range(minorGridCount): + subRadius = round(radius - (subRadiusSize * (minorRing + 1))) + preCanvas.drawEllipse(center, subRadius, subRadius) + + currAng = majorAxisAng + while currAng <= (2 * np.pi): + preCanvas.setPen(majorGridCol) + p1 = center + (9999 * Qc.QPointF(np.cos(currAng), np.sin(currAng))) + preCanvas.drawLine(Qc.QLineF(center, p1)) + + preCanvas.setPen(minorGridCol) + for minorAngLine in range(minorAxisCount): + newAng = currAng - (subAngleSize * (minorAngLine + 1)) + p1 = center + (9999 * Qc.QPointF(np.cos(newAng), np.sin(newAng))) + preCanvas.drawLine(Qc.QLineF(center, p1)) + + currAng = currAng + majorAxisAng + + def preDraw(self, painter): + # self.preCanvasPixmap.fill(Qc.Qt.white) + self.canvasPixmap.fill() + preCanvas = painter + + # preCanvas = Qg.QPainter(self.preCanvasPixmap) + preCanvas.setTransform(self.getScrsTransform()) + + if self.drawAxes: + preCanvas.setPen(Qc.Qt.gray) + preCanvas.drawLine(Qc.QLine(-9999, 0, 9999, 0)) + preCanvas.drawLine(Qc.QLine(0, -9999, 0, 9999)) + + if self.drawGrid: + if self.drawGridMode == GridMode.cartesian: + self.drawCartesianGrid(painter) + elif self.drawGridMode == GridMode.polar: + self.drawPolarGrid(painter) + + if self.currentGuides: + for guide in self.currentGuides: + guide.drawShape(preCanvas) + # preCanvas.end() + + def drawAddModePreview(self, painter): + if self.addMode is not None: + if self.addMode.active: + # Preview Object + if self.addMode.getPreview() is not None: + 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] + if not self.useGlobalCoords: + painter.save() + painter.setTransform( + selObj.transform.toQTransform(), True) + # painter.setTransform(selObj.baseTransform.toQTransform(), True) + painter.setPen(Qc.Qt.gray) + painter.drawLine(Qc.QLine(-9999, 0, 9999, 0)) + painter.drawLine(Qc.QLine(0, -9999, 0, 9999)) + painter.setPen(Qc.Qt.black) + painter.restore() + + painter.setTransform(selObj.getInteriorScrTransform( + self.newTransform).toQTransform(), True) + painter.drawRect(selObj.localBoundingBox) + else: + painter.setTransform(self.newTransform, True) + painter.drawRect(self.currentBoundingBox) + painter.restore() + + def postDraw(self): + self.postCanvasPixmap.fill(Qc.Qt.transparent) + with Qg.QPainter(self.postCanvasPixmap) as postCanvas: + postCanvas.setRenderHints(self.mainCanvas.renderHints()) + postCanvas.setTransform(self.getScrsTransform()) + + self.drawTransformPreview(postCanvas) + + 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: + self.drawAnchorCursor(postCanvas) + + # postCanvas.drawRect(self.getAllBoundingBox()) + + def drawAnchorCursor(self, painter): + painter.drawEllipse(self.customAnchor, 6, 6) + newCirclePath = Qg.QPainterPath() + newCirclePath.addEllipse(self.customAnchor, 2, 2) + + painter.fillPath(newCirclePath, Qg.QColor.fromRgb(0, 0, 0)) + + def updateModeBtnsOnly(self): + if self.currentModeStack[-1] == SelectionMode.translate: + activeBtn = self.ui.btnTranslate + elif self.currentModeStack[-1] == SelectionMode.rotate: + activeBtn = self.ui.btnRotate + elif self.currentModeStack[-1] == SelectionMode.scale: + activeBtn = self.ui.btnScale + elif self.currentModeStack[-1] == SelectionMode.pan: + activeBtn = self.ui.btnPan + elif self.currentModeStack[-1] == SelectionMode.setAnchor: + activeBtn = self.ui.btnAnchor + elif self.currentModeStack[-1] == SelectionMode.delete: + activeBtn = self.ui.btnDeleteMode + elif self.currentModeStack[-1] == SelectionMode.selectEdit: + activeBtn = self.ui.btnSelectEdit + else: + activeBtn = None + + + disableFill = isinstance(self.addMode, InplaceAddObj.AddBezierShape) and not self.currAddOptions['closedPath'] + self.ui.btnFill.setEnabled(not disableFill) + if disableFill and self.ui.btnFill.isEnabled(): + self.ui.btnFill.setChecked(not disableFill) + + + for button in self.modeButtons: + button.setChecked(button is activeBtn) + + def updateChecks(self): + self.removeAddMode() + self.updateModeBtnsOnly() + self.quickUpdate() + + def btnAlignXOnClick(self, checked): + 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) + + def btnAnchorModeOnClick(self): + if self.currentModeStack[-1] != SelectionMode.setAnchor: + self.currentModeStack.append(SelectionMode.setAnchor) + self.updateChecks() + + def switchToAnchorMode(self): + if self.currentModeStack[-1] != SelectionMode.setAnchor: + self.currentModeStack.append(SelectionMode.setAnchor) + self.updateChecks() + + def btnTranslateonClick(self): + self.currentModeStack = [SelectionMode.translate] + self.ui.statusbar.showMessage('Translate mode') + self.clearSelection() + self.updateChecks() + + def btnRotateOnClick(self): + self.currentModeStack = [SelectionMode.rotate] + self.ui.statusbar.showMessage('Rotate mode') + self.clearSelection() + self.updateChecks() + + def btnScaleOnClick(self): + self.currentModeStack = [SelectionMode.scale] + self.ui.statusbar.showMessage('Scale mode') + self.clearSelection() + self.updateChecks() + + def btnPanOnClick(self): + self.currentModeStack = [SelectionMode.pan] + self.ui.statusbar.showMessage('Pan mode') + self.clearSelection() + self.updateChecks() + + def btnWorldCoordsOnClick(self, checked): + self.useGlobalCoords = checked + if not self.useGlobalCoords: + self.ui.comboAnchor.setCurrentIndex(AnchorMode.origin) + self.setAllInSetEnabled(self.globalTransformOnlyButtons, checked) + + def setAllInSetEnabled(self, widgetSet, enabled): + for widget in widgetSet: + widget.setEnabled(enabled) + + def btnDrawAxesOnClick(self, checked): + self.drawAxes = checked + self.quickUpdate() + + def btnDrawGridOnClick(self, checked): + self.drawGrid = checked + self.quickUpdate() + + def btnCustTransformOnClick(self): + matrixDialog = CustMatTransform.CustMatTransform() + matrixDialog.show() + result = matrixDialog.exec_() + if result == Qw.QDialog.Accepted: + objKey = self.currentlySelectedObj['selectedIndex'] + self.transformObject(objKey, + matrixDialog.getTransformationMatrix(), not + self.useGlobalCoords) + + # for now, unless we update the bouding box transformation. + self.clearSelection() + self.quickUpdate() + + def btnLoadEditorOnClick(self): + 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() + + rawExternalEditor = self.settings['externalEditor'] + rawExtEditorArgs = self.settings['externalEditorArgs'] + execEditor = [rawExternalEditor] + + for arg in rawExtEditorArgs: + execEditor.append(string.Template( + arg).substitute(asypath=(self.filename))) + + subprocess.Popen(args=execEditor) + + def btnAddCodeOnClick(self): + header = """ +// xasy object created at $time +// Object Number: $uid +// 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') + f.write(header) + f.close() + + subprocess.run(args=self.getExternalEditor(asypath=newPath)) + + f = io.open(newPath, 'r') + newItem = x2a.xasyScript(engine=self.asyEngine, canvas=self.xasyDrawObj) + newItem.setScript(f.read()) + f.close() + + # newItem.replaceKey(str(self.globalObjectCounter) + ':') + self.fileItems.append(newItem) + self.addObjCreationUrs(newItem) + self.asyfyCanvas() + + self.globalObjectCounter = self.globalObjectCounter + 1 + def softDeleteObj(self, objKey): + maj, minor = objKey + drawObj = self.drawObjects[maj][minor] + item = drawObj.originalObj + key = drawObj.key + keyIndex = drawObj.keyIndex + + + item.transfKeymap[key][keyIndex].deleted = True + # item.asyfied = False + + def getSelectedObjInfo(self, objIndex): + maj, minor = objIndex + drawObj = self.drawObjects[maj][minor] + item = drawObj.originalObj + key = drawObj.key + keyIndex = drawObj.keyIndex + + return item, key, keyIndex + + def transformObjKey(self, item, key, keyIndex, transform, applyFirst=False, drawObj=None): + if isinstance(transform, np.ndarray): + obj_transform = x2a.asyTransform.fromNumpyMatrix(transform) + elif isinstance(transform, Qg.QTransform): + assert transform.isAffine() + obj_transform = x2a.asyTransform.fromQTransform(transform) + else: + obj_transform = transform + + scr_transform = obj_transform + + if not applyFirst: + item.transfKeymap[key][keyIndex] = obj_transform * \ + item.transfKeymap[key][keyIndex] + if drawObj is not None: + drawObj.transform = scr_transform * drawObj.transform + else: + item.transfKeymap[key][keyIndex] = item.transfKeymap[key][keyIndex] * obj_transform + if drawObj is not None: + drawObj.transform = drawObj.transform * scr_transform + + if self.selectAsGroup: + for (maj2, min2) in self.currentlySelectedObj['allSameKey']: + if (maj2, min2) == (maj, minor): + continue + obj = self.drawObjects[maj2][min2] + newIndex = obj.keyIndex + if not applyFirst: + item.transfKeymap[key][newIndex] = obj_transform * \ + item.transfKeymap[key][newIndex] + obj.transform = scr_transform * obj.transform + else: + item.transfKeymap[key][newIndex] = item.transfKeymap[key][newIndex] * obj_transform + obj.transform = obj.transform * scr_transform + + self.fileChanged = True + self.quickUpdate() + + def transformObject(self, objKey, transform, applyFirst=False): + maj, minor = objKey + drawObj = self.drawObjects[maj][minor] + item, key, keyIndex = self.getSelectedObjInfo(objKey) + self.transformObjKey(item, key, keyIndex, transform, applyFirst, drawObj) + + def initializeEmptyFile(self): + pass + + def getExternalEditor(self, **kwargs) -> str: + editor = os.getenv("VISUAL") + if(editor == None) : + editor = os.getenv("EDITOR") + if(editor == None) : + rawExternalEditor = self.settings['externalEditor'] + rawExtEditorArgs = self.settings['externalEditorArgs'] + else: + s = editor.split() + rawExternalEditor = s[0] + rawExtEditorArgs = s[1:]+["$asypath"] + + execEditor = [rawExternalEditor] + + for arg in rawExtEditorArgs: + execEditor.append(string.Template(arg).substitute(**kwargs)) + + return execEditor + + + def loadFile(self, name): + filename = os.path.abspath(name) + if not os.path.isfile(filename): + filename = filename + '.asy' + + if not os.path.isfile(filename): + self.ui.statusbar.showMessage('File {0} not found'.format(filename)) + return + + self.ui.statusbar.showMessage('Load {0}'.format(filename)) + self.filename = filename + self.currDir = os.path.dirname(self.filename) + + self.erase() + + 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) + item = x2a.xasyScript(canvas=self.xasyDrawObj, engine=self.asyEngine, transfKeyMap=transfDict) + + item.setScript(rawText) + self.fileItems.append(item) + self.asyfyCanvas(True) + + maxKey2 = item.getMaxKeyCounter() + self.asy2psmap = item.asy2psmap + self.globalObjectCounter = max(maxKey + 1, maxKey2) + finally: + f.close() + + def populateCanvasWithItems(self, forceUpdate=False): + self.itemCount = 0 + for item in self.fileItems: + self.drawObjects.append(item.generateDrawObjects(forceUpdate)) diff --git a/graphics/asymptote/GUI/__init__.py b/graphics/asymptote/GUI/__init__.py new file mode 100644 index 0000000000..e5a0d9b483 --- /dev/null +++ b/graphics/asymptote/GUI/__init__.py @@ -0,0 +1 @@ +#!/usr/bin/env python3 diff --git a/graphics/asymptote/GUI/configs/__init__.py b/graphics/asymptote/GUI/configs/__init__.py new file mode 100644 index 0000000000..5f7ce86af6 --- /dev/null +++ b/graphics/asymptote/GUI/configs/__init__.py @@ -0,0 +1 @@ +#!/usr/bin/env python3
\ No newline at end of file diff --git a/graphics/asymptote/GUI/configs/xasyconfig.cson b/graphics/asymptote/GUI/configs/xasyconfig.cson new file mode 100644 index 0000000000..0b5d8bfc02 --- /dev/null +++ b/graphics/asymptote/GUI/configs/xasyconfig.cson @@ -0,0 +1,62 @@ +# Default Options for xasy + +# External editor. $asypath will be replaced by the current file. +externalEditor: "emacs" +externalEditorArgs: ["$asypath"] + +# Path to Asymptote executable +asyPath: "asy" + +# Overwrites the ASYMPTOTE_DIR Environment variable if set. Otherwise, leaves asymptote to decide. +asyBaseLocation: null + +# Show Debugging Information +showDebug: false + +# Default Pen Options +defaultPenOptions: "" + +# Default Pen Color +defaultPenColor: "#000000" + +# +defaultPenWidth: 0.5 +useLegacyDrawMode: false +enableImmediatePreview: true +useDegrees: false +groupObjDefault: false + +# +terminalFont: "Courier" +terminalFontSize: 9 + +# +defaultShowAxes: true +defaultShowGrid: false +defaultGridSnap: false + +# Draw Selected Objects on top of the frame +drawSelectedOnTop: true + +# Grid Settings + +gridMajorAxesColor: "#858585" +gridMinorAxesColor: "#dddddd" +gridMajorAxesSpacing: 5 +gridMinorAxesCount: 9 + +# Magnification Settings +minimumMagnification: 0.01 +maximumMagnification: 100 + +# Debug Mode +debugMode: true + +# Overrides + +windows: + externalEditor: "notepad.exe" + +Darwin: + externalEditor: "open" + externalEditorArgs: ["-a","TextEdit","$asypath"] diff --git a/graphics/asymptote/GUI/configs/xasykeymap.cson b/graphics/asymptote/GUI/configs/xasykeymap.cson new file mode 100644 index 0000000000..7ab1b34a2f --- /dev/null +++ b/graphics/asymptote/GUI/configs/xasykeymap.cson @@ -0,0 +1,24 @@ +# Default Keymaps for xasy + +commandPalette: "Ctrl+P" +quit: "Ctrl+Q" +deleteObject: "Del" + +finalizeCurve: "Space" +finalizeCurveClosed: "c" + +anchorMode: "Ctrl+A" + +undo: 'Ctrl+Z' +redo: 'Ctrl+Y' + +moveUp: 'Up' +moveDown: 'Down' + +scrollUp: 'Shift+Up' +scrollDown: 'Shift+Down' +scrollLeft: 'Shift+Left' +scrollRight: 'Shift+Right' + +zoomIn: 'Ctrl+Up' +zoomOut: 'Ctrl+Down'
\ No newline at end of file diff --git a/graphics/asymptote/GUI/icon-list.txt b/graphics/asymptote/GUI/icon-list.txt new file mode 100644 index 0000000000..29e301cfd6 --- /dev/null +++ b/graphics/asymptote/GUI/icon-list.txt @@ -0,0 +1 @@ +https://superdevresources.com/free-svg-icons/
\ No newline at end of file diff --git a/graphics/asymptote/GUI/icons_rc.py b/graphics/asymptote/GUI/icons_rc.py new file mode 100644 index 0000000000..d1b18d19f4 --- /dev/null +++ b/graphics/asymptote/GUI/icons_rc.py @@ -0,0 +1,2680 @@ +# -*- coding: utf-8 -*- + +# Resource object code +# +# Created by: The Resource Compiler for PyQt5 (Qt v5.11.3) +# +# WARNING! All changes made in this file will be lost! + +from PyQt5 import QtCore + +qt_resource_data = b"\ +\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\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\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\x02\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\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\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\ +\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\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\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\x31\ +\x35\x70\x78\x22\x20\x68\x65\x69\x67\x68\x74\x3d\x22\x31\x35\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\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\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\x04\x22\ +\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\ +\x34\x20\x2d\x2d\x3e\x0a\x3c\x73\x76\x67\x20\x68\x65\x69\x67\x68\ +\x74\x3d\x27\x32\x34\x70\x74\x27\x20\x76\x65\x72\x73\x69\x6f\x6e\ +\x3d\x27\x31\x2e\x31\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\ +\x32\x34\x20\x32\x34\x27\x20\x77\x69\x64\x74\x68\x3d\x27\x32\x34\ +\x70\x74\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\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\x36\x38\x2e\ +\x37\x36\x35\x35\x20\x36\x38\x2e\x38\x35\x38\x33\x29\x27\x3e\x0a\ +\x3c\x70\x61\x74\x68\x20\x64\x3d\x27\x4d\x20\x2d\x39\x2e\x33\x39\ +\x31\x31\x38\x20\x2d\x30\x4c\x20\x2d\x36\x2e\x36\x34\x30\x35\x37\ +\x20\x2d\x31\x32\x2e\x30\x34\x35\x4c\x20\x38\x2e\x36\x37\x36\x33\ +\x32\x20\x2d\x36\x2e\x35\x31\x38\x37\x31\x4c\x20\x33\x2e\x33\x32\ +\x30\x32\x38\x20\x36\x2e\x30\x32\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\x31\x2e\x37\x35\x36\x35\x36\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\x36\x38\x2e\ +\x37\x36\x35\x35\x20\x36\x38\x2e\x38\x35\x38\x33\x29\x27\x3e\x0a\ +\x3c\x63\x69\x72\x63\x6c\x65\x20\x63\x78\x3d\x27\x2d\x39\x2e\x33\ +\x39\x31\x31\x38\x27\x20\x63\x79\x3d\x27\x2d\x30\x27\x20\x72\x3d\ +\x27\x33\x2e\x30\x31\x31\x32\x35\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\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\x36\x38\x2e\x37\x36\ +\x35\x35\x20\x36\x38\x2e\x38\x35\x38\x33\x29\x27\x3e\x0a\x3c\x63\ +\x69\x72\x63\x6c\x65\x20\x63\x78\x3d\x27\x2d\x36\x2e\x36\x34\x30\ +\x35\x37\x27\x20\x63\x79\x3d\x27\x2d\x31\x32\x2e\x30\x34\x35\x27\ +\x20\x72\x3d\x27\x33\x2e\x30\x31\x31\x32\x35\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\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\x36\x38\ +\x2e\x37\x36\x35\x35\x20\x36\x38\x2e\x38\x35\x38\x33\x29\x27\x3e\ +\x0a\x3c\x63\x69\x72\x63\x6c\x65\x20\x63\x78\x3d\x27\x38\x2e\x36\ +\x37\x36\x33\x32\x27\x20\x63\x79\x3d\x27\x2d\x36\x2e\x35\x31\x38\ +\x37\x31\x27\x20\x72\x3d\x27\x33\x2e\x30\x31\x31\x32\x35\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\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\x36\x38\x2e\x37\x36\x35\x35\x20\x36\x38\x2e\x38\x35\x38\x33\ +\x29\x27\x3e\x0a\x3c\x63\x69\x72\x63\x6c\x65\x20\x63\x78\x3d\x27\ +\x33\x2e\x33\x32\x30\x32\x38\x27\x20\x63\x79\x3d\x27\x36\x2e\x30\ +\x32\x32\x35\x27\x20\x72\x3d\x27\x33\x2e\x30\x31\x31\x32\x35\x27\ +\x20\x66\x69\x6c\x6c\x3d\x27\x23\x30\x30\x30\x30\x30\x30\x27\x2f\ +\x3e\x0a\x3c\x2f\x67\x3e\x3c\x2f\x67\x3e\x0a\x3c\x2f\x73\x76\x67\ +\x3e\ +\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\xbd\ +\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\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\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\x73\x76\x67\x3e\x0d\x0a\ +\x00\x00\x05\xb7\ +\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\ +\x34\x20\x2d\x2d\x3e\x0a\x3c\x73\x76\x67\x20\x68\x65\x69\x67\x68\ +\x74\x3d\x27\x32\x34\x70\x74\x27\x20\x76\x65\x72\x73\x69\x6f\x6e\ +\x3d\x27\x31\x2e\x31\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\ +\x31\x38\x2e\x34\x33\x37\x35\x20\x32\x34\x27\x20\x77\x69\x64\x74\ +\x68\x3d\x27\x31\x38\x2e\x34\x33\x37\x35\x70\x74\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\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\x36\x35\x2e\x36\x32\x38\x32\x20\x37\ +\x34\x2e\x32\x30\x32\x29\x27\x3e\x0a\x3c\x70\x61\x74\x68\x20\x64\ +\x3d\x27\x4d\x20\x38\x2e\x33\x37\x35\x30\x34\x20\x2d\x31\x31\x2e\ +\x31\x36\x36\x37\x43\x20\x38\x2e\x33\x37\x35\x30\x34\x20\x2d\x31\ +\x32\x2e\x37\x30\x38\x35\x20\x34\x2e\x36\x32\x35\x34\x31\x20\x2d\ +\x31\x33\x2e\x39\x35\x38\x34\x20\x30\x20\x2d\x31\x33\x2e\x39\x35\ +\x38\x34\x43\x20\x2d\x34\x2e\x36\x32\x35\x34\x31\x20\x2d\x31\x33\ +\x2e\x39\x35\x38\x34\x20\x2d\x38\x2e\x33\x37\x35\x30\x34\x20\x2d\ +\x31\x32\x2e\x37\x30\x38\x35\x20\x2d\x38\x2e\x33\x37\x35\x30\x34\ +\x20\x2d\x31\x31\x2e\x31\x36\x36\x37\x43\x20\x2d\x38\x2e\x33\x37\ +\x35\x30\x34\x20\x2d\x39\x2e\x36\x32\x34\x39\x32\x20\x2d\x34\x2e\ +\x36\x32\x35\x34\x31\x20\x2d\x38\x2e\x33\x37\x35\x30\x34\x20\x30\ +\x20\x2d\x38\x2e\x33\x37\x35\x30\x34\x43\x20\x34\x2e\x36\x32\x35\ +\x34\x31\x20\x2d\x38\x2e\x33\x37\x35\x30\x34\x20\x38\x2e\x33\x37\ +\x35\x30\x34\x20\x2d\x39\x2e\x36\x32\x34\x39\x32\x20\x38\x2e\x33\ +\x37\x35\x30\x34\x20\x2d\x31\x31\x2e\x31\x36\x36\x37\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\x31\x2e\x37\x35\x36\x35\x36\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\x36\x35\x2e\x36\x32\x38\x32\x20\x37\x34\x2e\x32\x30\x32\x29\ +\x27\x3e\x0a\x3c\x70\x61\x74\x68\x20\x64\x3d\x27\x4d\x20\x2d\x38\ +\x2e\x33\x37\x35\x30\x34\x20\x2d\x31\x31\x2e\x31\x36\x36\x37\x4c\ +\x20\x2d\x38\x2e\x33\x37\x35\x30\x34\x20\x2d\x30\x4c\x20\x2d\x38\ +\x2e\x33\x37\x35\x30\x34\x20\x2d\x31\x2e\x38\x35\x39\x36\x33\x65\ +\x2d\x31\x35\x43\x20\x2d\x38\x2e\x33\x37\x35\x30\x34\x20\x2d\x31\ +\x2e\x32\x33\x39\x37\x35\x65\x2d\x31\x35\x20\x2d\x38\x2e\x33\x37\ +\x35\x30\x34\x20\x2d\x36\x2e\x31\x39\x38\x37\x37\x65\x2d\x31\x36\ +\x20\x2d\x38\x2e\x33\x37\x35\x30\x34\x20\x2d\x30\x43\x20\x2d\x38\ +\x2e\x33\x37\x35\x30\x34\x20\x31\x2e\x35\x34\x31\x38\x20\x2d\x34\ +\x2e\x36\x32\x35\x34\x31\x20\x32\x2e\x37\x39\x31\x36\x38\x20\x30\ +\x20\x32\x2e\x37\x39\x31\x36\x38\x43\x20\x34\x2e\x36\x32\x35\x34\ +\x31\x20\x32\x2e\x37\x39\x31\x36\x38\x20\x38\x2e\x33\x37\x35\x30\ +\x34\x20\x31\x2e\x35\x34\x31\x38\x20\x38\x2e\x33\x37\x35\x30\x34\ +\x20\x30\x4c\x20\x38\x2e\x33\x37\x35\x30\x34\x20\x30\x4c\x20\x38\ +\x2e\x33\x37\x35\x30\x34\x20\x2d\x31\x31\x2e\x31\x36\x36\x37\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\x31\x2e\x37\x35\x36\x35\x36\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\x36\x35\x2e\x36\x32\x38\x32\x20\x37\x34\x2e\x32\x30\x32\ +\x29\x27\x3e\x0a\x3c\x70\x61\x74\x68\x20\x64\x3d\x27\x4d\x20\x38\ +\x2e\x33\x37\x35\x30\x34\x20\x2d\x31\x31\x2e\x31\x36\x36\x37\x43\ +\x20\x38\x2e\x33\x37\x35\x30\x34\x20\x2d\x31\x35\x2e\x37\x39\x32\ +\x31\x20\x34\x2e\x36\x32\x35\x34\x31\x20\x2d\x31\x39\x2e\x35\x34\ +\x31\x38\x20\x30\x20\x2d\x31\x39\x2e\x35\x34\x31\x38\x43\x20\x2d\ +\x34\x2e\x36\x32\x35\x34\x31\x20\x2d\x31\x39\x2e\x35\x34\x31\x38\ +\x20\x2d\x38\x2e\x33\x37\x35\x30\x34\x20\x2d\x31\x35\x2e\x37\x39\ +\x32\x31\x20\x2d\x38\x2e\x33\x37\x35\x30\x34\x20\x2d\x31\x31\x2e\ +\x31\x36\x36\x37\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\x31\x2e\x37\x35\ +\x36\x35\x36\x27\x2f\x3e\x0a\x3c\x2f\x67\x3e\x3c\x2f\x67\x3e\x0a\ +\x3c\x2f\x73\x76\x67\x3e\ +\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\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\x01\x20\ +\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\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\x73\x76\x67\x3e\ +\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\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\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\x93\ +\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\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\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\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\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\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\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\x8d\ +\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\ +\x34\x20\x2d\x2d\x3e\x0a\x3c\x73\x76\x67\x20\x68\x65\x69\x67\x68\ +\x74\x3d\x27\x32\x34\x70\x74\x27\x20\x76\x65\x72\x73\x69\x6f\x6e\ +\x3d\x27\x31\x2e\x31\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\ +\x32\x34\x20\x32\x34\x27\x20\x77\x69\x64\x74\x68\x3d\x27\x32\x34\ +\x70\x74\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\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\x36\x38\x2e\ +\x37\x36\x35\x35\x20\x36\x39\x2e\x38\x31\x32\x33\x29\x27\x3e\x0a\ +\x3c\x70\x61\x74\x68\x20\x64\x3d\x27\x4d\x20\x2d\x39\x2e\x33\x39\ +\x31\x31\x38\x20\x2d\x30\x43\x20\x2d\x39\x2e\x33\x32\x32\x35\x37\ +\x20\x2d\x33\x2e\x37\x37\x37\x38\x33\x20\x2d\x38\x2e\x33\x34\x33\ +\x32\x34\x20\x2d\x37\x2e\x33\x38\x34\x34\x34\x20\x2d\x36\x2e\x36\ +\x34\x30\x35\x37\x20\x2d\x31\x30\x2e\x31\x32\x39\x38\x43\x20\x2d\ +\x31\x2e\x32\x36\x32\x31\x39\x20\x2d\x31\x38\x2e\x38\x30\x31\x37\ +\x20\x37\x2e\x36\x38\x39\x37\x31\x20\x2d\x31\x35\x2e\x35\x33\x35\ +\x31\x20\x38\x2e\x36\x37\x36\x33\x32\x20\x2d\x35\x2e\x34\x38\x32\ +\x32\x43\x20\x39\x2e\x31\x38\x36\x37\x39\x20\x2d\x30\x2e\x32\x38\ +\x30\x38\x37\x37\x20\x36\x2e\x37\x34\x39\x33\x37\x20\x34\x2e\x35\ +\x31\x38\x38\x37\x20\x33\x2e\x33\x32\x30\x32\x38\x20\x35\x2e\x30\ +\x36\x34\x38\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\x31\x2e\x37\x35\ +\x36\x35\x36\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\x36\x38\x2e\x37\x36\x35\x35\x20\x36\ +\x39\x2e\x38\x31\x32\x33\x29\x27\x3e\x0a\x3c\x63\x69\x72\x63\x6c\ +\x65\x20\x63\x78\x3d\x27\x2d\x39\x2e\x33\x39\x31\x31\x38\x27\x20\ +\x63\x79\x3d\x27\x2d\x30\x27\x20\x72\x3d\x27\x33\x2e\x30\x31\x31\ +\x32\x35\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\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\x36\x38\x2e\x37\x36\x35\x35\x20\x36\x39\x2e\ +\x38\x31\x32\x33\x29\x27\x3e\x0a\x3c\x63\x69\x72\x63\x6c\x65\x20\ +\x63\x78\x3d\x27\x2d\x36\x2e\x36\x34\x30\x35\x37\x27\x20\x63\x79\ +\x3d\x27\x2d\x31\x30\x2e\x31\x32\x39\x38\x27\x20\x72\x3d\x27\x33\ +\x2e\x30\x31\x31\x32\x35\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\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\x36\x38\x2e\x37\x36\x35\x35\ +\x20\x36\x39\x2e\x38\x31\x32\x33\x29\x27\x3e\x0a\x3c\x63\x69\x72\ +\x63\x6c\x65\x20\x63\x78\x3d\x27\x38\x2e\x36\x37\x36\x33\x32\x27\ +\x20\x63\x79\x3d\x27\x2d\x35\x2e\x34\x38\x32\x32\x27\x20\x72\x3d\ +\x27\x33\x2e\x30\x31\x31\x32\x35\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\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\x36\x38\x2e\x37\x36\ +\x35\x35\x20\x36\x39\x2e\x38\x31\x32\x33\x29\x27\x3e\x0a\x3c\x63\ +\x69\x72\x63\x6c\x65\x20\x63\x78\x3d\x27\x33\x2e\x33\x32\x30\x32\ +\x38\x27\x20\x63\x79\x3d\x27\x35\x2e\x30\x36\x34\x38\x39\x27\x20\ +\x72\x3d\x27\x33\x2e\x30\x31\x31\x32\x35\x27\x20\x66\x69\x6c\x6c\ +\x3d\x27\x23\x30\x30\x30\x30\x30\x30\x27\x2f\x3e\x0a\x3c\x2f\x67\ +\x3e\x3c\x2f\x67\x3e\x0a\x3c\x2f\x73\x76\x67\x3e\ +\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\x04\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\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\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\ +\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\x73\x76\x67\x3e\x0d\x0a\ +\x00\x00\x04\x30\ +\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\ +\x34\x20\x2d\x2d\x3e\x0a\x3c\x73\x76\x67\x20\x68\x65\x69\x67\x68\ +\x74\x3d\x27\x32\x34\x70\x74\x27\x20\x76\x65\x72\x73\x69\x6f\x6e\ +\x3d\x27\x31\x2e\x31\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\ +\x32\x34\x20\x32\x34\x27\x20\x77\x69\x64\x74\x68\x3d\x27\x32\x34\ +\x70\x74\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\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\x36\x38\x2e\ +\x37\x36\x35\x35\x20\x36\x38\x2e\x38\x35\x38\x33\x29\x27\x3e\x0a\ +\x3c\x70\x61\x74\x68\x20\x64\x3d\x27\x4d\x20\x2d\x39\x2e\x33\x39\ +\x31\x31\x38\x20\x2d\x30\x4c\x20\x2d\x36\x2e\x36\x34\x30\x35\x37\ +\x20\x2d\x31\x32\x2e\x30\x34\x35\x4c\x20\x38\x2e\x36\x37\x36\x33\ +\x32\x20\x2d\x36\x2e\x35\x31\x38\x37\x31\x4c\x20\x33\x2e\x33\x32\ +\x30\x32\x38\x20\x36\x2e\x30\x32\x32\x35\x4c\x20\x2d\x39\x2e\x33\ +\x39\x31\x31\x38\x20\x2d\x30\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\ +\x31\x2e\x37\x35\x36\x35\x36\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\x36\x38\x2e\x37\x36\ +\x35\x35\x20\x36\x38\x2e\x38\x35\x38\x33\x29\x27\x3e\x0a\x3c\x63\ +\x69\x72\x63\x6c\x65\x20\x63\x78\x3d\x27\x2d\x39\x2e\x33\x39\x31\ +\x31\x38\x27\x20\x63\x79\x3d\x27\x2d\x30\x27\x20\x72\x3d\x27\x33\ +\x2e\x30\x31\x31\x32\x35\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\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\x36\x38\x2e\x37\x36\x35\x35\ +\x20\x36\x38\x2e\x38\x35\x38\x33\x29\x27\x3e\x0a\x3c\x63\x69\x72\ +\x63\x6c\x65\x20\x63\x78\x3d\x27\x2d\x36\x2e\x36\x34\x30\x35\x37\ +\x27\x20\x63\x79\x3d\x27\x2d\x31\x32\x2e\x30\x34\x35\x27\x20\x72\ +\x3d\x27\x33\x2e\x30\x31\x31\x32\x35\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\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\x36\x38\x2e\x37\ +\x36\x35\x35\x20\x36\x38\x2e\x38\x35\x38\x33\x29\x27\x3e\x0a\x3c\ +\x63\x69\x72\x63\x6c\x65\x20\x63\x78\x3d\x27\x38\x2e\x36\x37\x36\ +\x33\x32\x27\x20\x63\x79\x3d\x27\x2d\x36\x2e\x35\x31\x38\x37\x31\ +\x27\x20\x72\x3d\x27\x33\x2e\x30\x31\x31\x32\x35\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\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\x36\ +\x38\x2e\x37\x36\x35\x35\x20\x36\x38\x2e\x38\x35\x38\x33\x29\x27\ +\x3e\x0a\x3c\x63\x69\x72\x63\x6c\x65\x20\x63\x78\x3d\x27\x33\x2e\ +\x33\x32\x30\x32\x38\x27\x20\x63\x79\x3d\x27\x36\x2e\x30\x32\x32\ +\x35\x27\x20\x72\x3d\x27\x33\x2e\x30\x31\x31\x32\x35\x27\x20\x66\ +\x69\x6c\x6c\x3d\x27\x23\x30\x30\x30\x30\x30\x30\x27\x2f\x3e\x0a\ +\x3c\x2f\x67\x3e\x3c\x2f\x67\x3e\x0a\x3c\x2f\x73\x76\x67\x3e\ +\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\x04\xbd\ +\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\ +\x34\x20\x2d\x2d\x3e\x0a\x3c\x73\x76\x67\x20\x68\x65\x69\x67\x68\ +\x74\x3d\x27\x32\x34\x70\x74\x27\x20\x76\x65\x72\x73\x69\x6f\x6e\ +\x3d\x27\x31\x2e\x31\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\ +\x32\x34\x20\x32\x34\x27\x20\x77\x69\x64\x74\x68\x3d\x27\x32\x34\ +\x70\x74\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\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\x36\x38\x2e\ +\x37\x36\x35\x35\x20\x36\x39\x2e\x37\x36\x38\x38\x29\x27\x3e\x0a\ +\x3c\x70\x61\x74\x68\x20\x64\x3d\x27\x4d\x20\x2d\x39\x2e\x33\x39\ +\x31\x31\x38\x20\x2d\x30\x43\x20\x2d\x39\x2e\x39\x36\x38\x36\x31\ +\x20\x2d\x33\x2e\x38\x33\x30\x30\x34\x20\x2d\x38\x2e\x35\x35\x37\ +\x30\x36\x20\x2d\x37\x2e\x35\x31\x39\x34\x34\x20\x2d\x36\x2e\x36\ +\x34\x30\x35\x37\x20\x2d\x31\x30\x2e\x32\x31\x37\x31\x43\x20\x2d\ +\x30\x2e\x34\x39\x31\x30\x38\x39\x20\x2d\x31\x38\x2e\x38\x37\x33\ +\x33\x20\x38\x2e\x33\x35\x36\x37\x36\x20\x2d\x31\x35\x2e\x31\x39\ +\x30\x36\x20\x38\x2e\x36\x37\x36\x33\x32\x20\x2d\x35\x2e\x35\x32\ +\x39\x34\x38\x43\x20\x38\x2e\x38\x33\x36\x20\x2d\x30\x2e\x37\x30\ +\x32\x30\x30\x38\x20\x36\x2e\x32\x33\x39\x36\x38\x20\x32\x2e\x39\ +\x34\x32\x30\x37\x20\x33\x2e\x33\x32\x30\x32\x38\x20\x35\x2e\x31\ +\x30\x38\x35\x37\x43\x20\x2d\x31\x2e\x39\x36\x38\x39\x31\x20\x39\ +\x2e\x30\x33\x33\x37\x31\x20\x2d\x38\x2e\x32\x36\x38\x39\x35\x20\ +\x37\x2e\x34\x34\x33\x37\x20\x2d\x39\x2e\x33\x39\x31\x31\x38\x20\ +\x2d\x30\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\x31\x2e\x37\x35\x36\ +\x35\x36\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\x36\x38\x2e\x37\x36\x35\x35\x20\x36\x39\ +\x2e\x37\x36\x38\x38\x29\x27\x3e\x0a\x3c\x63\x69\x72\x63\x6c\x65\ +\x20\x63\x78\x3d\x27\x2d\x39\x2e\x33\x39\x31\x31\x38\x27\x20\x63\ +\x79\x3d\x27\x2d\x30\x27\x20\x72\x3d\x27\x33\x2e\x30\x31\x31\x32\ +\x35\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\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\x36\x38\x2e\x37\x36\x35\x35\x20\x36\x39\x2e\x37\ +\x36\x38\x38\x29\x27\x3e\x0a\x3c\x63\x69\x72\x63\x6c\x65\x20\x63\ +\x78\x3d\x27\x2d\x36\x2e\x36\x34\x30\x35\x37\x27\x20\x63\x79\x3d\ +\x27\x2d\x31\x30\x2e\x32\x31\x37\x31\x27\x20\x72\x3d\x27\x33\x2e\ +\x30\x31\x31\x32\x35\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\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\x36\x38\x2e\x37\x36\x35\x35\x20\ +\x36\x39\x2e\x37\x36\x38\x38\x29\x27\x3e\x0a\x3c\x63\x69\x72\x63\ +\x6c\x65\x20\x63\x78\x3d\x27\x38\x2e\x36\x37\x36\x33\x32\x27\x20\ +\x63\x79\x3d\x27\x2d\x35\x2e\x35\x32\x39\x34\x38\x27\x20\x72\x3d\ +\x27\x33\x2e\x30\x31\x31\x32\x35\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\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\x36\x38\x2e\x37\x36\ +\x35\x35\x20\x36\x39\x2e\x37\x36\x38\x38\x29\x27\x3e\x0a\x3c\x63\ +\x69\x72\x63\x6c\x65\x20\x63\x78\x3d\x27\x33\x2e\x33\x32\x30\x32\ +\x38\x27\x20\x63\x79\x3d\x27\x35\x2e\x31\x30\x38\x35\x37\x27\x20\ +\x72\x3d\x27\x33\x2e\x30\x31\x31\x32\x35\x27\x20\x66\x69\x6c\x6c\ +\x3d\x27\x23\x30\x30\x30\x30\x30\x30\x27\x2f\x3e\x0a\x3c\x2f\x67\ +\x3e\x3c\x2f\x67\x3e\x0a\x3c\x2f\x73\x76\x67\x3e\ +\x00\x00\x02\x20\ +\x00\ +\x00\x07\x7f\x78\x9c\xdd\x55\x3b\x6f\xdb\x30\x10\xde\xfb\x2b\xae\ +\xe8\xc0\x76\x20\x45\x52\x24\x45\x06\x51\x02\xd4\x40\xa7\x74\x4b\ +\x96\x6e\x6a\xcc\x48\x6c\x6c\xc9\x90\x54\xcb\xfd\xf7\x3d\xc5\xd6\ +\xc3\x56\xd0\x29\x43\x11\x69\xd0\x3d\x78\x77\xdf\x7d\xc7\x83\xae\ +\x6f\x0f\xdb\x0d\xec\x7d\xdd\x84\xaa\x4c\x89\x60\x9c\x80\x2f\x1f\ +\xab\x75\x28\xf3\x94\x3c\xdc\x7f\xa3\x96\xdc\xde\x7c\xb8\xfe\x48\ +\x29\xdc\x17\xa1\x81\xa7\xb0\xf1\xd0\x65\x0d\xe4\xbe\xf4\x75\xd6\ +\xfa\x35\xfc\xfc\x03\xeb\x7d\x68\xf6\xf9\x16\x24\x53\x40\x29\x9e\ +\x47\x0d\x0a\x1f\xf2\xa2\x4d\x89\x54\xbb\x96\xcc\x6b\x08\xd4\x82\ +\xef\xbe\x56\x87\x94\x68\xc3\x14\x77\x0a\x74\xcc\xac\xb6\x31\x08\ +\xcb\x54\x9c\x68\x90\x8a\x40\x17\xd6\x6d\x81\x01\x47\x53\x9f\x04\ +\xc1\x96\x4d\x4a\x8a\xb6\xdd\x5d\x45\x51\xd7\x75\xac\x8b\x59\x55\ +\xe7\x91\xe4\x9c\x47\x58\xf4\x74\xe4\xea\xb0\x09\xe5\xf3\x6b\x07\ +\x85\x73\x2e\x7a\xf1\x12\x84\x99\x43\x58\xa7\x64\x97\xe5\x5e\x1c\ +\xd5\xb6\xce\xca\xe6\xa9\xaa\xb7\x29\xd9\x66\x6d\x1d\x0e\x9f\x39\ +\x73\xce\x48\xa3\x80\xf7\xef\xa0\x18\xcd\x8c\xb4\x12\x12\xc5\x24\ +\x97\x5f\xfa\xe0\x5d\xd6\x16\x80\xd9\xbe\x03\xb5\x0c\xf1\x72\xa4\ +\x42\x33\x2e\x35\x97\x77\x33\x13\x9f\x2b\x02\x9b\x76\x26\xf6\x54\ +\xe8\xd5\x99\x59\xc6\x2e\xd1\xbd\x79\x66\x35\x4c\x38\x9b\x24\x68\ +\x35\xf3\x7c\xb3\x40\xc1\xb4\x12\x16\xa8\x42\x70\x28\xe1\x38\x12\ +\x27\x8c\x45\xe0\x27\x69\x05\x97\xae\x8b\xd0\x41\x45\x94\xaf\x88\ +\x53\x3f\x13\x54\xce\x38\x62\x9f\x74\x4c\xe4\x30\xd1\x50\x87\x0a\ +\xc9\xac\x12\x09\x62\x18\xc4\xd5\x04\x70\xf4\xd2\x45\x02\x7a\x5e\ +\xe2\x6e\xc9\xea\x0f\xd2\xdf\xc6\x4d\x4a\x3e\x59\xde\xbf\x24\xc2\ +\x29\x44\xf9\xdb\xcd\x71\x8e\x49\x18\x93\xcc\xdb\x44\xfe\xb8\xd5\ +\xb3\x36\x63\xe6\xb4\x55\x2f\x6d\x1e\xc5\xb3\x36\x4f\x5e\xba\x48\ +\x40\x97\x45\x26\x93\xc3\x78\xe5\xe4\x2c\xd1\x38\x94\x51\x9c\x46\ +\x3a\x3a\x17\xf1\x97\x35\x46\xe6\xca\xaa\xf4\x04\x9a\xb6\xae\x9e\ +\x3d\xf2\xc8\x5f\x9e\xc1\x40\x71\x4b\xfc\x63\xb6\x4b\x49\x5d\xfd\ +\x2e\xd7\x67\xe6\x5f\x55\x28\x2f\xed\xdb\xd0\xfa\x7a\x13\xf0\x83\ +\x3b\x8b\x33\xc3\x9a\xa3\x6f\x58\x65\x96\x68\xa3\xcd\x9b\x4f\x6a\ +\xc1\xe2\xbb\xd9\xb8\x53\x3f\xef\x6d\x60\xff\x5a\x2d\x8d\x44\x49\ +\x31\x5b\x2d\x77\x64\x8a\x8f\xe2\xd9\x6a\x9d\xbc\x74\x91\x60\x71\ +\x29\xfe\x13\x12\x8f\x44\xf6\x7f\xab\x9b\xbf\x3f\x45\xd8\x3d\ +\x00\x00\x03\x65\ +\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\ +\x34\x20\x2d\x2d\x3e\x0a\x3c\x73\x76\x67\x20\x68\x65\x69\x67\x68\ +\x74\x3d\x27\x31\x38\x2e\x37\x35\x70\x74\x27\x20\x76\x65\x72\x73\ +\x69\x6f\x6e\x3d\x27\x31\x2e\x31\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\x31\x38\x2e\x37\x35\x20\x31\x38\x2e\x37\x35\x27\x20\ +\x77\x69\x64\x74\x68\x3d\x27\x31\x38\x2e\x37\x35\x70\x74\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\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\x36\x35\x2e\x37\x38\x34\x34\ +\x20\x36\x33\x2e\x32\x33\x33\x33\x29\x27\x3e\x0a\x3c\x70\x61\x74\ +\x68\x20\x64\x3d\x27\x4d\x20\x2d\x38\x2e\x36\x35\x37\x33\x34\x20\ +\x38\x2e\x36\x35\x37\x33\x34\x4c\x20\x38\x2e\x36\x35\x37\x33\x34\ +\x20\x38\x2e\x36\x35\x37\x33\x34\x4c\x20\x38\x2e\x36\x35\x37\x33\ +\x34\x20\x2d\x38\x2e\x36\x35\x37\x33\x34\x4c\x20\x2d\x38\x2e\x36\ +\x35\x37\x33\x34\x20\x2d\x38\x2e\x36\x35\x37\x33\x34\x4c\x20\x2d\ +\x38\x2e\x36\x35\x37\x33\x34\x20\x38\x2e\x36\x35\x37\x33\x34\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\x31\x2e\x35\x30\x35\x36\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\x36\x35\x2e\x37\x38\x34\x34\x20\x36\x33\x2e\x32\x33\ +\x33\x33\x29\x27\x3e\x0a\x3c\x70\x61\x74\x68\x20\x64\x3d\x27\x4d\ +\x20\x34\x2e\x33\x32\x38\x36\x37\x20\x30\x43\x20\x34\x2e\x33\x32\ +\x38\x36\x37\x20\x2d\x32\x2e\x33\x39\x30\x36\x36\x20\x32\x2e\x33\ +\x39\x30\x36\x36\x20\x2d\x34\x2e\x33\x32\x38\x36\x37\x20\x30\x20\ +\x2d\x34\x2e\x33\x32\x38\x36\x37\x43\x20\x2d\x32\x2e\x33\x39\x30\ +\x36\x36\x20\x2d\x34\x2e\x33\x32\x38\x36\x37\x20\x2d\x34\x2e\x33\ +\x32\x38\x36\x37\x20\x2d\x32\x2e\x33\x39\x30\x36\x36\x20\x2d\x34\ +\x2e\x33\x32\x38\x36\x37\x20\x2d\x30\x43\x20\x2d\x34\x2e\x33\x32\ +\x38\x36\x37\x20\x32\x2e\x33\x39\x30\x36\x36\x20\x2d\x32\x2e\x33\ +\x39\x30\x36\x36\x20\x34\x2e\x33\x32\x38\x36\x37\x20\x30\x20\x34\ +\x2e\x33\x32\x38\x36\x37\x43\x20\x32\x2e\x33\x39\x30\x36\x36\x20\ +\x34\x2e\x33\x32\x38\x36\x37\x20\x34\x2e\x33\x32\x38\x36\x37\x20\ +\x32\x2e\x33\x39\x30\x36\x36\x20\x34\x2e\x33\x32\x38\x36\x37\x20\ +\x30\x5a\x27\x20\x66\x69\x6c\x6c\x3d\x27\x23\x30\x30\x30\x30\x30\ +\x30\x27\x2f\x3e\x0a\x3c\x2f\x67\x3e\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\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\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\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\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\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\ +\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\x73\x76\x67\ +\x3e\x0d\x0a\ +\x00\x00\x00\xdd\ +\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\x38\x22\ +\x20\x68\x65\x69\x67\x68\x74\x3d\x22\x38\x22\x20\x76\x69\x65\x77\ +\x42\x6f\x78\x3d\x22\x30\x20\x30\x20\x38\x20\x38\x22\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\x73\x76\x67\x3e\ +\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\ +\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\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\x04\x10\ +\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\ +\x34\x20\x2d\x2d\x3e\x0a\x3c\x73\x76\x67\x20\x68\x65\x69\x67\x68\ +\x74\x3d\x27\x31\x38\x2e\x37\x35\x70\x74\x27\x20\x76\x65\x72\x73\ +\x69\x6f\x6e\x3d\x27\x31\x2e\x31\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\x31\x38\x2e\x37\x35\x20\x31\x38\x2e\x37\x35\x27\x20\ +\x77\x69\x64\x74\x68\x3d\x27\x31\x38\x2e\x37\x35\x70\x74\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\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\x36\x35\x2e\x37\x38\x34\x34\ +\x20\x36\x33\x2e\x32\x33\x33\x33\x29\x27\x3e\x0a\x3c\x70\x61\x74\ +\x68\x20\x64\x3d\x27\x4d\x20\x2d\x38\x2e\x36\x35\x37\x33\x34\x20\ +\x38\x2e\x36\x35\x37\x33\x34\x4c\x20\x38\x2e\x36\x35\x37\x33\x34\ +\x20\x38\x2e\x36\x35\x37\x33\x34\x4c\x20\x38\x2e\x36\x35\x37\x33\ +\x34\x20\x2d\x38\x2e\x36\x35\x37\x33\x34\x4c\x20\x2d\x38\x2e\x36\ +\x35\x37\x33\x34\x20\x2d\x38\x2e\x36\x35\x37\x33\x34\x4c\x20\x2d\ +\x38\x2e\x36\x35\x37\x33\x34\x20\x38\x2e\x36\x35\x37\x33\x34\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\x31\x2e\x35\x30\x35\x36\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\x36\x35\x2e\x37\x38\x34\x34\x20\x36\x33\x2e\x32\x33\ +\x33\x33\x29\x27\x3e\x0a\x3c\x70\x61\x74\x68\x20\x64\x3d\x27\x4d\ +\x20\x2d\x38\x2e\x36\x35\x37\x33\x34\x20\x2d\x30\x4c\x20\x38\x2e\ +\x36\x35\x37\x33\x34\x20\x30\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\x31\ +\x2e\x35\x30\x35\x36\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\x36\x35\x2e\x37\x38\x34\ +\x34\x20\x36\x33\x2e\x32\x33\x33\x33\x29\x27\x3e\x0a\x3c\x70\x61\ +\x74\x68\x20\x64\x3d\x27\x4d\x20\x30\x20\x38\x2e\x36\x35\x37\x33\ +\x34\x4c\x20\x30\x20\x2d\x38\x2e\x36\x35\x37\x33\x34\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\x31\x2e\x35\x30\x35\x36\x32\x27\x2f\x3e\x0a\ +\x3c\x2f\x67\x3e\x3c\x2f\x67\x3e\x0a\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\xb5\ +\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\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\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\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\x09\ +\x0b\x9e\x89\x07\ +\x00\x63\ +\x00\x68\x00\x65\x00\x63\x00\x6b\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\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\x08\ +\x08\xc8\x55\xe7\ +\x00\x73\ +\x00\x61\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\ +\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\ +\x0b\x07\x57\xa7\ +\x00\x65\ +\x00\x64\x00\x69\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\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\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\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\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\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\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\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\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\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\ +\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\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\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\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\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\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\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\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\x08\ +\x05\xa8\x57\x87\ +\x00\x63\ +\x00\x6f\x00\x64\x00\x65\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\x08\ +\x08\xf7\x57\x07\ +\x00\x67\ +\x00\x72\x00\x69\x00\x64\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\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\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\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\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\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\x08\ +\x0c\xf7\x55\x87\ +\x00\x74\ +\x00\x65\x00\x78\x00\x74\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\ +\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\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\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\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\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\ +" + +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\x02\x48\x00\x00\x00\x00\x00\x01\x00\x00\x32\x5f\ +\x00\x00\x01\xae\x00\x00\x00\x00\x00\x01\x00\x00\x25\xc5\ +\x00\x00\x02\x70\x00\x00\x00\x00\x00\x01\x00\x00\x39\xe3\ +\x00\x00\x00\x58\x00\x00\x00\x00\x00\x01\x00\x00\x03\x80\ +\x00\x00\x05\x08\x00\x00\x00\x00\x00\x01\x00\x00\x73\xe0\ +\x00\x00\x04\x5c\x00\x01\x00\x00\x00\x01\x00\x00\x68\x7c\ +\x00\x00\x03\x76\x00\x00\x00\x00\x00\x01\x00\x00\x4e\x14\ +\x00\x00\x04\x38\x00\x00\x00\x00\x00\x01\x00\x00\x63\xbb\ +\x00\x00\x03\xa0\x00\x00\x00\x00\x00\x01\x00\x00\x51\x4e\ +\x00\x00\x03\xe4\x00\x00\x00\x00\x00\x01\x00\x00\x59\x29\ +\x00\x00\x03\x54\x00\x00\x00\x00\x00\x01\x00\x00\x4b\x47\ +\x00\x00\x00\xc0\x00\x00\x00\x00\x00\x01\x00\x00\x0e\xe8\ +\x00\x00\x00\x9a\x00\x00\x00\x00\x00\x01\x00\x00\x09\x1a\ +\x00\x00\x06\x0c\x00\x00\x00\x00\x00\x01\x00\x00\x88\x32\ +\x00\x00\x01\x34\x00\x00\x00\x00\x00\x01\x00\x00\x1b\x8e\ +\x00\x00\x04\xd4\x00\x00\x00\x00\x00\x01\x00\x00\x70\x8a\ +\x00\x00\x05\x70\x00\x00\x00\x00\x00\x01\x00\x00\x7c\x78\ +\x00\x00\x02\xf2\x00\x00\x00\x00\x00\x01\x00\x00\x42\xf6\ +\x00\x00\x05\xc0\x00\x00\x00\x00\x00\x01\x00\x00\x81\xa1\ +\x00\x00\x01\xf0\x00\x00\x00\x00\x00\x01\x00\x00\x2e\x3b\ +\x00\x00\x00\x84\x00\x00\x00\x00\x00\x01\x00\x00\x06\xaa\ +\x00\x00\x05\xe6\x00\x00\x00\x00\x00\x01\x00\x00\x85\xb5\ +\x00\x00\x04\x22\x00\x01\x00\x00\x00\x01\x00\x00\x61\xda\ +\x00\x00\x03\xc0\x00\x00\x00\x00\x00\x01\x00\x00\x55\xdf\ +\x00\x00\x01\x94\x00\x00\x00\x00\x00\x01\x00\x00\x23\x04\ +\x00\x00\x04\x9c\x00\x00\x00\x00\x00\x01\x00\x00\x6e\x09\ +\x00\x00\x04\x82\x00\x00\x00\x00\x00\x01\x00\x00\x6a\xa0\ +\x00\x00\x00\xf4\x00\x00\x00\x00\x00\x01\x00\x00\x13\xb6\ +\x00\x00\x00\x10\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\ +\x00\x00\x05\x9a\x00\x00\x00\x00\x00\x01\x00\x00\x7f\x1e\ +\x00\x00\x01\x0a\x00\x00\x00\x00\x00\x01\x00\x00\x17\x26\ +\x00\x00\x03\xfa\x00\x00\x00\x00\x00\x01\x00\x00\x5d\xa6\ +\x00\x00\x01\xc8\x00\x00\x00\x00\x00\x01\x00\x00\x2b\x80\ +\x00\x00\x05\x46\x00\x00\x00\x00\x00\x01\x00\x00\x77\xa8\ +\x00\x00\x05\x5c\x00\x00\x00\x00\x00\x01\x00\x00\x78\x89\ +\x00\x00\x01\x58\x00\x00\x00\x00\x00\x01\x00\x00\x1f\xb4\ +\x00\x00\x02\x2e\x00\x00\x00\x00\x00\x01\x00\x00\x31\x3b\ +\x00\x00\x02\xc4\x00\x00\x00\x00\x00\x01\x00\x00\x3f\x5f\ +\x00\x00\x00\x28\x00\x00\x00\x00\x00\x01\x00\x00\x03\x10\ +\x00\x00\x02\xa2\x00\x00\x00\x00\x00\x01\x00\x00\x3c\x64\ +\x00\x00\x03\x1c\x00\x00\x00\x00\x00\x01\x00\x00\x46\x1c\ +" + +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\x02\x48\x00\x00\x00\x00\x00\x01\x00\x00\x32\x5f\ +\x00\x00\x01\x6c\xb2\x83\xbd\xf6\ +\x00\x00\x01\xae\x00\x00\x00\x00\x00\x01\x00\x00\x25\xc5\ +\x00\x00\x01\x6c\xb2\x83\xbd\xf4\ +\x00\x00\x02\x70\x00\x00\x00\x00\x00\x01\x00\x00\x39\xe3\ +\x00\x00\x01\x6c\xb2\x83\xbd\xf3\ +\x00\x00\x00\x58\x00\x00\x00\x00\x00\x01\x00\x00\x03\x80\ +\x00\x00\x01\x6c\xb2\x83\xbd\xf4\ +\x00\x00\x05\x08\x00\x00\x00\x00\x00\x01\x00\x00\x73\xe0\ +\x00\x00\x01\x6c\xb2\x83\xbd\xf5\ +\x00\x00\x04\x5c\x00\x01\x00\x00\x00\x01\x00\x00\x68\x7c\ +\x00\x00\x01\x6c\xb2\x83\xbd\xf6\ +\x00\x00\x03\x76\x00\x00\x00\x00\x00\x01\x00\x00\x4e\x14\ +\x00\x00\x01\x6c\xb2\x83\xbd\xf3\ +\x00\x00\x04\x38\x00\x00\x00\x00\x00\x01\x00\x00\x63\xbb\ +\x00\x00\x01\x6c\xb2\x83\xbd\xf5\ +\x00\x00\x03\xa0\x00\x00\x00\x00\x00\x01\x00\x00\x51\x4e\ +\x00\x00\x01\x6c\xb2\x83\xbd\xf6\ +\x00\x00\x03\xe4\x00\x00\x00\x00\x00\x01\x00\x00\x59\x29\ +\x00\x00\x01\x6c\xb2\x83\xbd\xf5\ +\x00\x00\x03\x54\x00\x00\x00\x00\x00\x01\x00\x00\x4b\x47\ +\x00\x00\x01\x6c\xb2\x83\xbd\xf4\ +\x00\x00\x00\xc0\x00\x00\x00\x00\x00\x01\x00\x00\x0e\xe8\ +\x00\x00\x01\x6c\xb2\x83\xbd\xf7\ +\x00\x00\x00\x9a\x00\x00\x00\x00\x00\x01\x00\x00\x09\x1a\ +\x00\x00\x01\x6c\xb2\x83\xbd\xf4\ +\x00\x00\x06\x0c\x00\x00\x00\x00\x00\x01\x00\x00\x88\x32\ +\x00\x00\x01\x6c\xb2\x83\xbd\xf5\ +\x00\x00\x01\x34\x00\x00\x00\x00\x00\x01\x00\x00\x1b\x8e\ +\x00\x00\x01\x6c\xb2\x83\xbd\xf6\ +\x00\x00\x04\xd4\x00\x00\x00\x00\x00\x01\x00\x00\x70\x8a\ +\x00\x00\x01\x6c\xb2\x83\xbd\xf4\ +\x00\x00\x05\x70\x00\x00\x00\x00\x00\x01\x00\x00\x7c\x78\ +\x00\x00\x01\x6c\xb2\x83\xbd\xf3\ +\x00\x00\x02\xf2\x00\x00\x00\x00\x00\x01\x00\x00\x42\xf6\ +\x00\x00\x01\x6c\xb2\x83\xbd\xf3\ +\x00\x00\x05\xc0\x00\x00\x00\x00\x00\x01\x00\x00\x81\xa1\ +\x00\x00\x01\x6c\xb2\x83\xbd\xf5\ +\x00\x00\x01\xf0\x00\x00\x00\x00\x00\x01\x00\x00\x2e\x3b\ +\x00\x00\x01\x6c\xb2\x83\xbd\xf4\ +\x00\x00\x00\x84\x00\x00\x00\x00\x00\x01\x00\x00\x06\xaa\ +\x00\x00\x01\x6c\xb2\x83\xbd\xf6\ +\x00\x00\x05\xe6\x00\x00\x00\x00\x00\x01\x00\x00\x85\xb5\ +\x00\x00\x01\x6c\xb2\x83\xbd\xf3\ +\x00\x00\x04\x22\x00\x01\x00\x00\x00\x01\x00\x00\x61\xda\ +\x00\x00\x01\x6c\xb2\x83\xbd\xf6\ +\x00\x00\x03\xc0\x00\x00\x00\x00\x00\x01\x00\x00\x55\xdf\ +\x00\x00\x01\x6c\xb2\x83\xbd\xf5\ +\x00\x00\x01\x94\x00\x00\x00\x00\x00\x01\x00\x00\x23\x04\ +\x00\x00\x01\x6c\xb2\x83\xbd\xf5\ +\x00\x00\x04\x9c\x00\x00\x00\x00\x00\x01\x00\x00\x6e\x09\ +\x00\x00\x01\x6c\xb2\x83\xbd\xf3\ +\x00\x00\x04\x82\x00\x00\x00\x00\x00\x01\x00\x00\x6a\xa0\ +\x00\x00\x01\x6c\xb2\x83\xbd\xf4\ +\x00\x00\x00\xf4\x00\x00\x00\x00\x00\x01\x00\x00\x13\xb6\ +\x00\x00\x01\x6c\xb2\x83\xbd\xf5\ +\x00\x00\x00\x10\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\ +\x00\x00\x01\x6c\xb2\x83\xbd\xf5\ +\x00\x00\x05\x9a\x00\x00\x00\x00\x00\x01\x00\x00\x7f\x1e\ +\x00\x00\x01\x6c\xb2\x83\xbd\xf4\ +\x00\x00\x01\x0a\x00\x00\x00\x00\x00\x01\x00\x00\x17\x26\ +\x00\x00\x01\x6c\xb2\x83\xbd\xf4\ +\x00\x00\x03\xfa\x00\x00\x00\x00\x00\x01\x00\x00\x5d\xa6\ +\x00\x00\x01\x6c\xb2\x83\xbd\xf5\ +\x00\x00\x01\xc8\x00\x00\x00\x00\x00\x01\x00\x00\x2b\x80\ +\x00\x00\x01\x6c\xb2\x83\xbd\xf3\ +\x00\x00\x05\x46\x00\x00\x00\x00\x00\x01\x00\x00\x77\xa8\ +\x00\x00\x01\x6c\xb2\x83\xbd\xf6\ +\x00\x00\x05\x5c\x00\x00\x00\x00\x00\x01\x00\x00\x78\x89\ +\x00\x00\x01\x6c\xb2\x83\xbd\xf6\ +\x00\x00\x01\x58\x00\x00\x00\x00\x00\x01\x00\x00\x1f\xb4\ +\x00\x00\x01\x6c\xb2\x83\xbd\xf4\ +\x00\x00\x02\x2e\x00\x00\x00\x00\x00\x01\x00\x00\x31\x3b\ +\x00\x00\x01\x6c\xb2\x83\xbd\xf3\ +\x00\x00\x02\xc4\x00\x00\x00\x00\x00\x01\x00\x00\x3f\x5f\ +\x00\x00\x01\x6c\xb2\x83\xbd\xf6\ +\x00\x00\x00\x28\x00\x00\x00\x00\x00\x01\x00\x00\x03\x10\ +\x00\x00\x01\x6c\xb2\x83\xbd\xf6\ +\x00\x00\x02\xa2\x00\x00\x00\x00\x00\x01\x00\x00\x3c\x64\ +\x00\x00\x01\x6c\xb2\x83\xbd\xf6\ +\x00\x00\x03\x1c\x00\x00\x00\x00\x00\x01\x00\x00\x46\x1c\ +\x00\x00\x01\x6c\xb2\x83\xbd\xf3\ +" + +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() diff --git a/graphics/asymptote/GUI/labelEditor.py b/graphics/asymptote/GUI/labelEditor.py new file mode 100644 index 0000000000..76bc8d7d0a --- /dev/null +++ b/graphics/asymptote/GUI/labelEditor.py @@ -0,0 +1,154 @@ +#!/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 subprocess +import xasyOptions as xo +import xasyUtils as xu +import tempfile +import uuid +import os +import io + + +class labelEditor(Qw.QDialog): + def __init__(self, text=''): + super().__init__() + self.ui = Ui_Dialog() + self.ui.setupUi(self) + + self.ui.btnAccept.clicked.connect(self.accept) + self.ui.btnCancel.clicked.connect(self.reject) + self.ui.chkMathMode.stateChanged.connect(self.chkMathModeChecked) + self.ui.btnPreview.clicked.connect(self.btnPreviewOnClick) + self.ui.btnGetText.clicked.connect(self.btnGetTextOnClick) + + self.svgPreview = None + self.initializeText(text) + + def initializeText(self, text: str): + if text[0] == '$' and text[-1] == '$': + self.ui.chkMathMode.setChecked(True) + text = text.strip('$') + + if text.startswith('\\displaystyle{'): + self.ui.cmbMathStyle.setCurrentText('Display Style') + text = text.rstrip('}') + text = text.replace('\\displaystyle{', '', 1) + elif text.startswith('\\scriptstyle{'): + self.ui.cmbMathStyle.setCurrentText('Script Style') + text = text.rstrip('}') + text = text.replace('\\scriptstyle{', '', 1) + + self.ui.txtLabelEdit.setPlainText(text) + + def chkMathModeChecked(self, checked): + self.ui.cmbMathStyle.setEnabled(checked) + + def getText(self): + rawText = self.ui.txtLabelEdit.toPlainText() + rawText.replace('\n', ' ') + if self.ui.chkMathMode.isChecked(): + prefix = '' + suffix = '' + if self.ui.cmbMathStyle.currentText() == 'Display Style': + prefix = '\\displaystyle{' + suffix = '}' + elif self.ui.cmbMathStyle.currentText() == 'Script Style': + prefix = '\\scriptstyle{' + suffix = '}' + return '${0}{1}{2}$'.format(prefix, rawText, suffix) + else: + return rawText + + def btnPreviewOnClick(self): + path = xa.getArgs().asypath + if path is None: + opt = xo.xasyOptions().load() + path = opt['asyPath'] + + asyInput = """ + frame f; + label(f, "{0}"); + write(min(f), newl); + write(max(f), newl); + shipout(f); + """ + + self.svgPreview = Qs.QSvgRenderer() + with tempfile.TemporaryDirectory(prefix='xasylbl_') as tmpdir: + id = str(uuid.uuid4()) + tmpFile = os.path.join(tmpdir, 'lbl-{0}.svg'.format(id)) + + with subprocess.Popen(args=[path, '-fsvg', '-o', tmpFile, '-'], encoding='utf-8', stdin=subprocess.PIPE, + stdout=subprocess.PIPE) as asy: + asy.stdin.write(asyInput.format(self.getText())) + asy.stdin.close() + out = asy.stdout.read() + + raw_array = out.splitlines() + + 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)) + + new_rect = self.processBounds(min_bounds, max_bounds) + self.svgPreview.load(tmpFile) + + + + self.drawPreview(new_rect) + + def drawPreview(self, naturalBounds): + img = Qg.QPixmap(self.ui.lblLabelPreview.size()) + img.fill(Qg.QColor.fromRgbF(1, 1, 1, 1)) + if self.svgPreview is None: + pass + else: + with Qg.QPainter(img) as pnt: + scale_ratio = self.getIdealScaleRatio(naturalBounds, self.ui.lblLabelPreview.rect()) + + pnt.translate(self.ui.lblLabelPreview.rect().center()) + pnt.scale(scale_ratio, scale_ratio) + self.svgPreview.render(pnt, naturalBounds) + self.ui.lblLabelPreview.setPixmap(img) + + + def getIdealScaleRatio(self, rect, boundsRect): + assert isinstance(rect, (Qc.QRect, Qc.QRectF)) + assert isinstance(rect, (Qc.QRect, Qc.QRectF)) + + magic_ratio = 0.50 + idealRatioHeight = (magic_ratio * boundsRect.height()) / rect.height() + magicRatioWidth = 0.50 + + if idealRatioHeight * rect.width() > magicRatioWidth * boundsRect.width(): + idealRatioWidth = (magicRatioWidth * boundsRect.width()) / rect.width() + idealRatio = min(idealRatioHeight, idealRatioWidth) + else: + idealRatio = idealRatioHeight + return idealRatio + + def processBounds(self, minPt, maxPt): + p1x, p1y = minPt + p2x, p2y = maxPt + + minPt = Qc.QPointF(p1x, p1y) + maxPt = Qc.QPointF(p2x, p2y) + + newRect = Qc.QRectF(minPt, maxPt) + return newRect + + + def btnGetTextOnClick(self): + msgbox = Qw.QMessageBox() + msgbox.setText('Text Preview:\n' + self.getText()) + msgbox.setWindowTitle('Text preview') + msgbox.show() + return msgbox.exec_() diff --git a/graphics/asymptote/GUI/locale/th/LC_MESSAGES/base.po b/graphics/asymptote/GUI/locale/th/LC_MESSAGES/base.po new file mode 100644 index 0000000000..507fd33561 --- /dev/null +++ b/graphics/asymptote/GUI/locale/th/LC_MESSAGES/base.po @@ -0,0 +1,24 @@ +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# +# Supakorn Rassameemasmuang, 2018. +msgid "" +msgstr "" +"Project-Id-Version: \n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2018-05-16 17:07-0600\n" +"PO-Revision-Date: 2018-05-16 17:20-0700\n" +"Last-Translator: Supakorn Rassameemasmuang <rassamee@ualberta.ca>\n" +"Language-Team: English <kde-i18n-doc@kde.org>\n" +"Language: th\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" +"X-Generator: Lokalize 2.0\n" + +#: xasyStrings.py:10 +msgid "Rotate" +msgstr "หมุน" + + diff --git a/graphics/asymptote/GUI/pyUIClass/custMatTransform.py b/graphics/asymptote/GUI/pyUIClass/custMatTransform.py new file mode 100644 index 0000000000..7f35f8d0e7 --- /dev/null +++ b/graphics/asymptote/GUI/pyUIClass/custMatTransform.py @@ -0,0 +1,173 @@ +# -*- coding: utf-8 -*- + +# Form implementation generated from reading ui file 'GUI/windows/custMatTransform.ui' +# +# Created by: PyQt5 UI code generator 5.11.3 +# +# WARNING! All changes made in this file will be lost! + +from PyQt5 import QtCore, QtGui, QtWidgets + +class Ui_Dialog(object): + def setupUi(self, Dialog): + Dialog.setObjectName("Dialog") + Dialog.resize(500, 320) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(Dialog.sizePolicy().hasHeightForWidth()) + Dialog.setSizePolicy(sizePolicy) + Dialog.setMinimumSize(QtCore.QSize(500, 320)) + Dialog.setMaximumSize(QtCore.QSize(500, 320)) + Dialog.setMouseTracking(False) + icon = QtGui.QIcon() + icon.addPixmap(QtGui.QPixmap(":/icons/android-expand.svg"), QtGui.QIcon.Normal, QtGui.QIcon.Off) + Dialog.setWindowIcon(icon) + Dialog.setSizeGripEnabled(True) + Dialog.setModal(False) + self.centralFrame = QtWidgets.QFrame(Dialog) + self.centralFrame.setGeometry(QtCore.QRect(20, 20, 461, 271)) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Expanding) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.centralFrame.sizePolicy().hasHeightForWidth()) + self.centralFrame.setSizePolicy(sizePolicy) + self.centralFrame.setBaseSize(QtCore.QSize(0, 0)) + self.centralFrame.setObjectName("centralFrame") + self.verticalLayout_3 = QtWidgets.QVBoxLayout(self.centralFrame) + self.verticalLayout_3.setSpacing(4) + self.verticalLayout_3.setObjectName("verticalLayout_3") + self.horizontalLayout = QtWidgets.QHBoxLayout() + self.horizontalLayout.setObjectName("horizontalLayout") + self.horizontalLayout_3 = QtWidgets.QHBoxLayout() + self.horizontalLayout_3.setObjectName("horizontalLayout_3") + self.verticalLayout = QtWidgets.QVBoxLayout() + self.verticalLayout.setObjectName("verticalLayout") + self.label = QtWidgets.QLabel(self.centralFrame) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.label.sizePolicy().hasHeightForWidth()) + self.label.setSizePolicy(sizePolicy) + self.label.setObjectName("label") + self.verticalLayout.addWidget(self.label) + self.gridFrame = QtWidgets.QFrame(self.centralFrame) + self.gridFrame.setFrameShape(QtWidgets.QFrame.Box) + self.gridFrame.setObjectName("gridFrame") + self.gridLayout = QtWidgets.QGridLayout(self.gridFrame) + self.gridLayout.setObjectName("gridLayout") + self.lineMat00 = QtWidgets.QLineEdit(self.gridFrame) + self.lineMat00.setMaximumSize(QtCore.QSize(70, 16777215)) + self.lineMat00.setObjectName("lineMat00") + self.gridLayout.addWidget(self.lineMat00, 1, 0, 1, 1) + self.lineMat11 = QtWidgets.QLineEdit(self.gridFrame) + self.lineMat11.setMaximumSize(QtCore.QSize(70, 16777215)) + self.lineMat11.setObjectName("lineMat11") + self.gridLayout.addWidget(self.lineMat11, 2, 1, 1, 1) + self.lineMat10 = QtWidgets.QLineEdit(self.gridFrame) + self.lineMat10.setMaximumSize(QtCore.QSize(70, 16777215)) + self.lineMat10.setObjectName("lineMat10") + self.gridLayout.addWidget(self.lineMat10, 2, 0, 1, 1) + self.lineMat01 = QtWidgets.QLineEdit(self.gridFrame) + self.lineMat01.setMaximumSize(QtCore.QSize(70, 16777215)) + self.lineMat01.setObjectName("lineMat01") + self.gridLayout.addWidget(self.lineMat01, 1, 1, 1, 1) + self.verticalLayout.addWidget(self.gridFrame) + self.horizontalLayout_3.addLayout(self.verticalLayout) + spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + self.horizontalLayout_3.addItem(spacerItem) + self.verticalLayout_4 = QtWidgets.QVBoxLayout() + self.verticalLayout_4.setObjectName("verticalLayout_4") + self.label_3 = QtWidgets.QLabel(self.centralFrame) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.label_3.sizePolicy().hasHeightForWidth()) + self.label_3.setSizePolicy(sizePolicy) + self.label_3.setObjectName("label_3") + self.verticalLayout_4.addWidget(self.label_3) + self.gridFrame_2 = QtWidgets.QFrame(self.centralFrame) + self.gridFrame_2.setFrameShape(QtWidgets.QFrame.Box) + self.gridFrame_2.setObjectName("gridFrame_2") + self.gridLayout_2 = QtWidgets.QGridLayout(self.gridFrame_2) + self.gridLayout_2.setObjectName("gridLayout_2") + self.lineMatTy = QtWidgets.QLineEdit(self.gridFrame_2) + self.lineMatTy.setMaximumSize(QtCore.QSize(70, 16777215)) + self.lineMatTy.setObjectName("lineMatTy") + self.gridLayout_2.addWidget(self.lineMatTy, 2, 1, 1, 1) + self.lineMatTx = QtWidgets.QLineEdit(self.gridFrame_2) + self.lineMatTx.setMaximumSize(QtCore.QSize(70, 16777215)) + self.lineMatTx.setObjectName("lineMatTx") + self.gridLayout_2.addWidget(self.lineMatTx, 1, 1, 1, 1) + self.verticalLayout_4.addWidget(self.gridFrame_2) + self.horizontalLayout_3.addLayout(self.verticalLayout_4) + self.horizontalLayout.addLayout(self.horizontalLayout_3) + spacerItem1 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + self.horizontalLayout.addItem(spacerItem1) + self.verticalLayout_2 = QtWidgets.QVBoxLayout() + self.verticalLayout_2.setObjectName("verticalLayout_2") + self.label_2 = QtWidgets.QLabel(self.centralFrame) + self.label_2.setObjectName("label_2") + self.verticalLayout_2.addWidget(self.label_2) + self.imgPreview = QtWidgets.QLabel(self.centralFrame) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Minimum) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.imgPreview.sizePolicy().hasHeightForWidth()) + self.imgPreview.setSizePolicy(sizePolicy) + self.imgPreview.setMinimumSize(QtCore.QSize(150, 150)) + self.imgPreview.setBaseSize(QtCore.QSize(300, 300)) + self.imgPreview.setFrameShape(QtWidgets.QFrame.Box) + self.imgPreview.setText("") + self.imgPreview.setObjectName("imgPreview") + self.verticalLayout_2.addWidget(self.imgPreview) + self.horizontalLayout.addLayout(self.verticalLayout_2) + self.verticalLayout_3.addLayout(self.horizontalLayout) + self.lblAnchor = QtWidgets.QLabel(self.centralFrame) + self.lblAnchor.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter) + self.lblAnchor.setObjectName("lblAnchor") + self.verticalLayout_3.addWidget(self.lblAnchor) + self.lblCoordsMode = QtWidgets.QLabel(self.centralFrame) + self.lblCoordsMode.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter) + self.lblCoordsMode.setObjectName("lblCoordsMode") + self.verticalLayout_3.addWidget(self.lblCoordsMode) + spacerItem2 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) + self.verticalLayout_3.addItem(spacerItem2) + self.horizontalLayout_2 = QtWidgets.QHBoxLayout() + self.horizontalLayout_2.setObjectName("horizontalLayout_2") + spacerItem3 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + self.horizontalLayout_2.addItem(spacerItem3) + self.btnReset = QtWidgets.QPushButton(self.centralFrame) + self.btnReset.setObjectName("btnReset") + self.horizontalLayout_2.addWidget(self.btnReset) + self.btnCancel = QtWidgets.QPushButton(self.centralFrame) + self.btnCancel.setObjectName("btnCancel") + self.horizontalLayout_2.addWidget(self.btnCancel) + self.btnAccept = QtWidgets.QPushButton(self.centralFrame) + self.btnAccept.setObjectName("btnAccept") + self.horizontalLayout_2.addWidget(self.btnAccept) + self.verticalLayout_3.addLayout(self.horizontalLayout_2) + + self.retranslateUi(Dialog) + QtCore.QMetaObject.connectSlotsByName(Dialog) + + def retranslateUi(self, Dialog): + _translate = QtCore.QCoreApplication.translate + Dialog.setWindowTitle(_translate("Dialog", "Set Custom Transformation")) + self.label.setText(_translate("Dialog", "Transformation Matrix")) + self.lineMat00.setText(_translate("Dialog", "1")) + self.lineMat11.setText(_translate("Dialog", "1")) + self.lineMat10.setText(_translate("Dialog", "0")) + self.lineMat01.setText(_translate("Dialog", "0")) + self.label_3.setText(_translate("Dialog", "Translation")) + self.lineMatTy.setText(_translate("Dialog", "0")) + self.lineMatTx.setText(_translate("Dialog", "0")) + self.label_2.setText(_translate("Dialog", "Preview:")) + self.imgPreview.setToolTip(_translate("Dialog", "Shows a red square if transformation determinant is negative.")) + self.lblAnchor.setText(_translate("Dialog", "Anchor: Top Left")) + self.lblCoordsMode.setText(_translate("Dialog", "Coordinates: Global")) + self.btnReset.setText(_translate("Dialog", "Reset")) + self.btnCancel.setText(_translate("Dialog", "Cancel")) + self.btnAccept.setText(_translate("Dialog", "Accept")) + +import icons_rc diff --git a/graphics/asymptote/GUI/pyUIClass/labelTextEditor.py b/graphics/asymptote/GUI/pyUIClass/labelTextEditor.py new file mode 100644 index 0000000000..142f951009 --- /dev/null +++ b/graphics/asymptote/GUI/pyUIClass/labelTextEditor.py @@ -0,0 +1,119 @@ +# -*- coding: utf-8 -*- + +# Form implementation generated from reading ui file 'GUI/windows/labelTextEditor.ui' +# +# Created by: PyQt5 UI code generator 5.11.3 +# +# WARNING! All changes made in this file will be lost! + +from PyQt5 import QtCore, QtGui, QtWidgets + +class Ui_Dialog(object): + def setupUi(self, Dialog): + Dialog.setObjectName("Dialog") + Dialog.resize(473, 424) + self.verticalLayout = QtWidgets.QVBoxLayout(Dialog) + self.verticalLayout.setObjectName("verticalLayout") + self.frame = QtWidgets.QFrame(Dialog) + self.frame.setFrameShape(QtWidgets.QFrame.StyledPanel) + self.frame.setFrameShadow(QtWidgets.QFrame.Raised) + self.frame.setObjectName("frame") + self.verticalLayout_3 = QtWidgets.QVBoxLayout(self.frame) + self.verticalLayout_3.setObjectName("verticalLayout_3") + self.gridLayout = QtWidgets.QGridLayout() + self.gridLayout.setContentsMargins(-1, 0, -1, -1) + self.gridLayout.setObjectName("gridLayout") + spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + self.gridLayout.addItem(spacerItem, 0, 2, 1, 1) + self.chkMathMode = QtWidgets.QCheckBox(self.frame) + self.chkMathMode.setObjectName("chkMathMode") + self.gridLayout.addWidget(self.chkMathMode, 0, 0, 1, 1) + self.cmbMathStyle = QtWidgets.QComboBox(self.frame) + self.cmbMathStyle.setEnabled(False) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.cmbMathStyle.sizePolicy().hasHeightForWidth()) + self.cmbMathStyle.setSizePolicy(sizePolicy) + self.cmbMathStyle.setMinimumSize(QtCore.QSize(100, 0)) + self.cmbMathStyle.setObjectName("cmbMathStyle") + self.cmbMathStyle.addItem("") + self.cmbMathStyle.addItem("") + self.cmbMathStyle.addItem("") + self.gridLayout.addWidget(self.cmbMathStyle, 0, 1, 1, 1) + self.verticalLayout_3.addLayout(self.gridLayout) + self.verticalLayout_2 = QtWidgets.QVBoxLayout() + self.verticalLayout_2.setObjectName("verticalLayout_2") + self.txtLabelEdit = QtWidgets.QPlainTextEdit(self.frame) + self.txtLabelEdit.setObjectName("txtLabelEdit") + self.verticalLayout_2.addWidget(self.txtLabelEdit) + self.verticalLayout_3.addLayout(self.verticalLayout_2) + self.verticalLayout_4 = QtWidgets.QVBoxLayout() + self.verticalLayout_4.setContentsMargins(-1, 0, -1, -1) + self.verticalLayout_4.setObjectName("verticalLayout_4") + self.label = QtWidgets.QLabel(self.frame) + self.label.setObjectName("label") + self.verticalLayout_4.addWidget(self.label) + self.lblLabelPreview = QtWidgets.QLabel(self.frame) + self.lblLabelPreview.setMinimumSize(QtCore.QSize(0, 100)) + self.lblLabelPreview.setFrameShape(QtWidgets.QFrame.Box) + self.lblLabelPreview.setText("") + self.lblLabelPreview.setObjectName("lblLabelPreview") + self.verticalLayout_4.addWidget(self.lblLabelPreview) + self.verticalLayout_3.addLayout(self.verticalLayout_4) + self.horizontalLayout = QtWidgets.QHBoxLayout() + self.horizontalLayout.setObjectName("horizontalLayout") + spacerItem1 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + self.horizontalLayout.addItem(spacerItem1) + self.btnGetText = QtWidgets.QPushButton(self.frame) + self.btnGetText.setMaximumSize(QtCore.QSize(32, 32)) + self.btnGetText.setText("") + icon = QtGui.QIcon() + icon.addPixmap(QtGui.QPixmap(":/icons/text.svg"), QtGui.QIcon.Normal, QtGui.QIcon.Off) + self.btnGetText.setIcon(icon) + self.btnGetText.setFlat(True) + self.btnGetText.setObjectName("btnGetText") + self.horizontalLayout.addWidget(self.btnGetText) + self.btnPreview = QtWidgets.QPushButton(self.frame) + self.btnPreview.setMaximumSize(QtCore.QSize(32, 32)) + self.btnPreview.setText("") + icon1 = QtGui.QIcon() + icon1.addPixmap(QtGui.QPixmap(":/icons/eye.svg"), QtGui.QIcon.Normal, QtGui.QIcon.Off) + self.btnPreview.setIcon(icon1) + self.btnPreview.setFlat(True) + self.btnPreview.setObjectName("btnPreview") + self.horizontalLayout.addWidget(self.btnPreview) + self.btnCancel = QtWidgets.QPushButton(self.frame) + self.btnCancel.setMaximumSize(QtCore.QSize(32, 32)) + self.btnCancel.setText("") + icon2 = QtGui.QIcon() + icon2.addPixmap(QtGui.QPixmap(":/icons/android-close.svg"), QtGui.QIcon.Normal, QtGui.QIcon.Off) + self.btnCancel.setIcon(icon2) + self.btnCancel.setFlat(True) + self.btnCancel.setObjectName("btnCancel") + self.horizontalLayout.addWidget(self.btnCancel) + self.btnAccept = QtWidgets.QPushButton(self.frame) + self.btnAccept.setMaximumSize(QtCore.QSize(32, 32)) + self.btnAccept.setText("") + icon3 = QtGui.QIcon() + icon3.addPixmap(QtGui.QPixmap(":/icons/android-done.svg"), QtGui.QIcon.Normal, QtGui.QIcon.Off) + self.btnAccept.setIcon(icon3) + self.btnAccept.setFlat(True) + self.btnAccept.setObjectName("btnAccept") + self.horizontalLayout.addWidget(self.btnAccept) + self.verticalLayout_3.addLayout(self.horizontalLayout) + self.verticalLayout.addWidget(self.frame) + + self.retranslateUi(Dialog) + QtCore.QMetaObject.connectSlotsByName(Dialog) + + def retranslateUi(self, Dialog): + _translate = QtCore.QCoreApplication.translate + Dialog.setWindowTitle(_translate("Dialog", "Dialog")) + self.chkMathMode.setText(_translate("Dialog", "Math Mode")) + self.cmbMathStyle.setItemText(0, _translate("Dialog", "Inline Style")) + self.cmbMathStyle.setItemText(1, _translate("Dialog", "Display Style")) + self.cmbMathStyle.setItemText(2, _translate("Dialog", "Script Style")) + self.label.setText(_translate("Dialog", "Preview")) + +import icons_rc diff --git a/graphics/asymptote/GUI/pyUIClass/setCustomAnchor.py b/graphics/asymptote/GUI/pyUIClass/setCustomAnchor.py new file mode 100644 index 0000000000..828c27135d --- /dev/null +++ b/graphics/asymptote/GUI/pyUIClass/setCustomAnchor.py @@ -0,0 +1,55 @@ +# -*- coding: utf-8 -*- + +# Form implementation generated from reading ui file 'GUI/windows/setCustomAnchor.ui' +# +# Created by: PyQt5 UI code generator 5.11.3 +# +# WARNING! All changes made in this file will be lost! + +from PyQt5 import QtCore, QtGui, QtWidgets + +class Ui_Dialog(object): + def setupUi(self, Dialog): + Dialog.setObjectName("Dialog") + Dialog.resize(245, 161) + self.verticalLayoutWidget = QtWidgets.QWidget(Dialog) + self.verticalLayoutWidget.setGeometry(QtCore.QRect(20, 20, 201, 121)) + self.verticalLayoutWidget.setObjectName("verticalLayoutWidget") + self.verticalLayout = QtWidgets.QVBoxLayout(self.verticalLayoutWidget) + self.verticalLayout.setContentsMargins(0, 0, 0, 0) + self.verticalLayout.setObjectName("verticalLayout") + self.formLayout = QtWidgets.QFormLayout() + self.formLayout.setFieldGrowthPolicy(QtWidgets.QFormLayout.AllNonFixedFieldsGrow) + self.formLayout.setObjectName("formLayout") + self.label = QtWidgets.QLabel(self.verticalLayoutWidget) + self.label.setObjectName("label") + self.formLayout.setWidget(1, QtWidgets.QFormLayout.LabelRole, self.label) + self.lineEditX = QtWidgets.QLineEdit(self.verticalLayoutWidget) + self.lineEditX.setObjectName("lineEditX") + self.formLayout.setWidget(1, QtWidgets.QFormLayout.FieldRole, self.lineEditX) + self.label_2 = QtWidgets.QLabel(self.verticalLayoutWidget) + self.label_2.setObjectName("label_2") + self.formLayout.setWidget(2, QtWidgets.QFormLayout.LabelRole, self.label_2) + self.lineEditY = QtWidgets.QLineEdit(self.verticalLayoutWidget) + self.lineEditY.setObjectName("lineEditY") + self.formLayout.setWidget(2, QtWidgets.QFormLayout.FieldRole, self.lineEditY) + self.verticalLayout.addLayout(self.formLayout) + self.buttonBox = QtWidgets.QDialogButtonBox(self.verticalLayoutWidget) + self.buttonBox.setOrientation(QtCore.Qt.Horizontal) + self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.Cancel|QtWidgets.QDialogButtonBox.Ok|QtWidgets.QDialogButtonBox.Reset) + self.buttonBox.setObjectName("buttonBox") + self.verticalLayout.addWidget(self.buttonBox) + + self.retranslateUi(Dialog) + self.buttonBox.accepted.connect(Dialog.accept) + self.buttonBox.rejected.connect(Dialog.reject) + QtCore.QMetaObject.connectSlotsByName(Dialog) + + def retranslateUi(self, Dialog): + _translate = QtCore.QCoreApplication.translate + Dialog.setWindowTitle(_translate("Dialog", "Set Custom Anchor")) + self.label.setText(_translate("Dialog", "X:")) + self.lineEditX.setText(_translate("Dialog", "0")) + self.label_2.setText(_translate("Dialog", "Y:")) + self.lineEditY.setText(_translate("Dialog", "0")) + diff --git a/graphics/asymptote/GUI/pyUIClass/widg_addLabel.py b/graphics/asymptote/GUI/pyUIClass/widg_addLabel.py new file mode 100644 index 0000000000..fba79f6e21 --- /dev/null +++ b/graphics/asymptote/GUI/pyUIClass/widg_addLabel.py @@ -0,0 +1,140 @@ +# -*- coding: utf-8 -*- + +# Form implementation generated from reading ui file 'GUI/windows/widg_addLabel.ui' +# +# Created by: PyQt5 UI code generator 5.11.3 +# +# WARNING! All changes made in this file will be lost! + +from PyQt5 import QtCore, QtGui, QtWidgets + +class Ui_Form(object): + def setupUi(self, Form): + Form.setObjectName("Form") + Form.setWindowModality(QtCore.Qt.NonModal) + Form.resize(599, 35) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(Form.sizePolicy().hasHeightForWidth()) + Form.setSizePolicy(sizePolicy) + Form.setMinimumSize(QtCore.QSize(0, 35)) + Form.setMaximumSize(QtCore.QSize(16777215, 35)) + self.horizontalLayout_2 = QtWidgets.QHBoxLayout(Form) + self.horizontalLayout_2.setContentsMargins(0, 0, 0, 0) + self.horizontalLayout_2.setSpacing(0) + self.horizontalLayout_2.setObjectName("horizontalLayout_2") + self.horizontalLayout = QtWidgets.QHBoxLayout() + self.horizontalLayout.setObjectName("horizontalLayout") + self.txtLabelText = QtWidgets.QLineEdit(Form) + self.txtLabelText.setObjectName("txtLabelText") + self.horizontalLayout.addWidget(self.txtLabelText) + self.btnAdvancedEdit = QtWidgets.QPushButton(Form) + self.btnAdvancedEdit.setMaximumSize(QtCore.QSize(25, 25)) + self.btnAdvancedEdit.setText("") + icon = QtGui.QIcon() + icon.addPixmap(QtGui.QPixmap(":/icons/edit.svg"), QtGui.QIcon.Normal, QtGui.QIcon.Off) + self.btnAdvancedEdit.setIcon(icon) + self.btnAdvancedEdit.setFlat(True) + self.btnAdvancedEdit.setObjectName("btnAdvancedEdit") + self.horizontalLayout.addWidget(self.btnAdvancedEdit) + self.label = QtWidgets.QLabel(Form) + self.label.setObjectName("label") + self.horizontalLayout.addWidget(self.label) + self.cmbAlign = QtWidgets.QComboBox(Form) + self.cmbAlign.setObjectName("cmbAlign") + self.cmbAlign.addItem("") + self.cmbAlign.addItem("") + self.cmbAlign.addItem("") + self.cmbAlign.addItem("") + self.cmbAlign.addItem("") + self.cmbAlign.addItem("") + self.cmbAlign.addItem("") + self.cmbAlign.addItem("") + self.cmbAlign.addItem("") + self.cmbAlign.addItem("") + self.horizontalLayout.addWidget(self.cmbAlign) + self.label_3 = QtWidgets.QLabel(Form) + self.label_3.setObjectName("label_3") + self.horizontalLayout.addWidget(self.label_3) + self.cmbFontSize = QtWidgets.QComboBox(Form) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.cmbFontSize.sizePolicy().hasHeightForWidth()) + self.cmbFontSize.setSizePolicy(sizePolicy) + self.cmbFontSize.setEditable(True) + self.cmbFontSize.setObjectName("cmbFontSize") + self.cmbFontSize.addItem("") + self.cmbFontSize.addItem("") + self.cmbFontSize.addItem("") + self.cmbFontSize.addItem("") + self.cmbFontSize.addItem("") + self.cmbFontSize.addItem("") + self.cmbFontSize.addItem("") + self.cmbFontSize.addItem("") + self.cmbFontSize.addItem("") + self.cmbFontSize.addItem("") + self.cmbFontSize.addItem("") + self.horizontalLayout.addWidget(self.cmbFontSize) + self.label_2 = QtWidgets.QLabel(Form) + self.label_2.setObjectName("label_2") + self.horizontalLayout.addWidget(self.label_2) + self.txtShiftX = QtWidgets.QLineEdit(Form) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.txtShiftX.sizePolicy().hasHeightForWidth()) + self.txtShiftX.setSizePolicy(sizePolicy) + self.txtShiftX.setMaximumSize(QtCore.QSize(50, 16777215)) + self.txtShiftX.setObjectName("txtShiftX") + self.horizontalLayout.addWidget(self.txtShiftX) + self.txtShiftY = QtWidgets.QLineEdit(Form) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.txtShiftY.sizePolicy().hasHeightForWidth()) + self.txtShiftY.setSizePolicy(sizePolicy) + self.txtShiftY.setMaximumSize(QtCore.QSize(50, 16777215)) + self.txtShiftY.setObjectName("txtShiftY") + self.horizontalLayout.addWidget(self.txtShiftY) + spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + self.horizontalLayout.addItem(spacerItem) + self.horizontalLayout_2.addLayout(self.horizontalLayout) + + self.retranslateUi(Form) + QtCore.QMetaObject.connectSlotsByName(Form) + + def retranslateUi(self, Form): + _translate = QtCore.QCoreApplication.translate + Form.setWindowTitle(_translate("Form", "Form")) + self.txtLabelText.setToolTip(_translate("Form", "Number of Sides")) + self.txtLabelText.setPlaceholderText(_translate("Form", "Text")) + self.label.setText(_translate("Form", "Align")) + self.cmbAlign.setItemText(0, _translate("Form", "Center")) + self.cmbAlign.setItemText(1, _translate("Form", "N")) + self.cmbAlign.setItemText(2, _translate("Form", "E")) + self.cmbAlign.setItemText(3, _translate("Form", "W")) + self.cmbAlign.setItemText(4, _translate("Form", "S")) + self.cmbAlign.setItemText(5, _translate("Form", "NW")) + self.cmbAlign.setItemText(6, _translate("Form", "NE")) + self.cmbAlign.setItemText(7, _translate("Form", "SW")) + self.cmbAlign.setItemText(8, _translate("Form", "SE")) + self.cmbAlign.setItemText(9, _translate("Form", "Custom")) + self.label_3.setText(_translate("Form", "Font Size")) + self.cmbFontSize.setItemText(0, _translate("Form", "-")) + self.cmbFontSize.setItemText(1, _translate("Form", "8")) + self.cmbFontSize.setItemText(2, _translate("Form", "9")) + self.cmbFontSize.setItemText(3, _translate("Form", "10")) + self.cmbFontSize.setItemText(4, _translate("Form", "11")) + self.cmbFontSize.setItemText(5, _translate("Form", "12")) + self.cmbFontSize.setItemText(6, _translate("Form", "14")) + self.cmbFontSize.setItemText(7, _translate("Form", "18")) + self.cmbFontSize.setItemText(8, _translate("Form", "24")) + self.cmbFontSize.setItemText(9, _translate("Form", "48")) + self.cmbFontSize.setItemText(10, _translate("Form", "72")) + self.label_2.setText(_translate("Form", "Custom Align")) + self.txtShiftX.setPlaceholderText(_translate("Form", "Shift X")) + self.txtShiftY.setPlaceholderText(_translate("Form", "Shift Y")) + +import icons_rc diff --git a/graphics/asymptote/GUI/pyUIClass/widg_addPolyOpt.py b/graphics/asymptote/GUI/pyUIClass/widg_addPolyOpt.py new file mode 100644 index 0000000000..289f0a929b --- /dev/null +++ b/graphics/asymptote/GUI/pyUIClass/widg_addPolyOpt.py @@ -0,0 +1,48 @@ +# -*- coding: utf-8 -*- + +# Form implementation generated from reading ui file 'GUI/windows/widg_addPolyOpt.ui' +# +# Created by: PyQt5 UI code generator 5.11.3 +# +# WARNING! All changes made in this file will be lost! + +from PyQt5 import QtCore, QtGui, QtWidgets + +class Ui_Form(object): + def setupUi(self, Form): + Form.setObjectName("Form") + Form.setWindowModality(QtCore.Qt.NonModal) + Form.resize(326, 35) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(Form.sizePolicy().hasHeightForWidth()) + Form.setSizePolicy(sizePolicy) + Form.setMinimumSize(QtCore.QSize(0, 35)) + Form.setMaximumSize(QtCore.QSize(16777215, 35)) + self.horizontalLayout_2 = QtWidgets.QHBoxLayout(Form) + self.horizontalLayout_2.setContentsMargins(0, 0, 0, 0) + self.horizontalLayout_2.setSpacing(0) + self.horizontalLayout_2.setObjectName("horizontalLayout_2") + self.horizontalLayout = QtWidgets.QHBoxLayout() + self.horizontalLayout.setObjectName("horizontalLayout") + self.chkInscribed = QtWidgets.QCheckBox(Form) + self.chkInscribed.setObjectName("chkInscribed") + self.horizontalLayout.addWidget(self.chkInscribed) + 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) + self.horizontalLayout_2.addLayout(self.horizontalLayout) + + self.retranslateUi(Form) + QtCore.QMetaObject.connectSlotsByName(Form) + + def retranslateUi(self, Form): + _translate = QtCore.QCoreApplication.translate + Form.setWindowTitle(_translate("Form", "Form")) + self.chkInscribed.setText(_translate("Form", "Start at Vertex")) + self.txtSides.setToolTip(_translate("Form", "Number of Sides")) + self.txtSides.setPlaceholderText(_translate("Form", "Sides")) + diff --git a/graphics/asymptote/GUI/pyUIClass/widg_editBezier.py b/graphics/asymptote/GUI/pyUIClass/widg_editBezier.py new file mode 100644 index 0000000000..e2d95a8c98 --- /dev/null +++ b/graphics/asymptote/GUI/pyUIClass/widg_editBezier.py @@ -0,0 +1,94 @@ +# -*- coding: utf-8 -*- + +# Form implementation generated from reading ui file 'GUI/windows/widg_editBezier.ui' +# +# Created by: PyQt5 UI code generator 5.11.3 +# +# WARNING! All changes made in this file will be lost! + +from PyQt5 import QtCore, QtGui, QtWidgets + +class Ui_Form(object): + def setupUi(self, Form): + Form.setObjectName("Form") + Form.setWindowModality(QtCore.Qt.NonModal) + Form.resize(692, 35) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(Form.sizePolicy().hasHeightForWidth()) + Form.setSizePolicy(sizePolicy) + Form.setMinimumSize(QtCore.QSize(0, 35)) + Form.setMaximumSize(QtCore.QSize(16777215, 35)) + self.horizontalLayout_2 = QtWidgets.QHBoxLayout(Form) + self.horizontalLayout_2.setContentsMargins(0, 0, 0, 0) + self.horizontalLayout_2.setSpacing(0) + self.horizontalLayout_2.setObjectName("horizontalLayout_2") + self.horizontalLayout = QtWidgets.QHBoxLayout() + self.horizontalLayout.setObjectName("horizontalLayout") + self.cmbLockMode = QtWidgets.QComboBox(Form) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.cmbLockMode.sizePolicy().hasHeightForWidth()) + self.cmbLockMode.setSizePolicy(sizePolicy) + self.cmbLockMode.setObjectName("cmbLockMode") + self.cmbLockMode.addItem("") + self.cmbLockMode.addItem("") + self.cmbLockMode.addItem("") + self.horizontalLayout.addWidget(self.cmbLockMode) + spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + self.horizontalLayout.addItem(spacerItem) + self.chkRecompute = QtWidgets.QCheckBox(Form) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.chkRecompute.sizePolicy().hasHeightForWidth()) + self.chkRecompute.setSizePolicy(sizePolicy) + self.chkRecompute.setObjectName("chkRecompute") + self.horizontalLayout.addWidget(self.chkRecompute) + self.btnForceRecompute = QtWidgets.QPushButton(Form) + self.btnForceRecompute.setObjectName("btnForceRecompute") + self.horizontalLayout.addWidget(self.btnForceRecompute) + self.btnOk = QtWidgets.QPushButton(Form) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.btnOk.sizePolicy().hasHeightForWidth()) + self.btnOk.setSizePolicy(sizePolicy) + self.btnOk.setMaximumSize(QtCore.QSize(25, 25)) + icon = QtGui.QIcon() + icon.addPixmap(QtGui.QPixmap(":/icons/check.svg"), QtGui.QIcon.Normal, QtGui.QIcon.Off) + self.btnOk.setIcon(icon) + self.btnOk.setFlat(True) + self.btnOk.setObjectName("btnOk") + self.horizontalLayout.addWidget(self.btnOk) + self.btnCancel = QtWidgets.QPushButton(Form) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.btnCancel.sizePolicy().hasHeightForWidth()) + self.btnCancel.setSizePolicy(sizePolicy) + self.btnCancel.setMaximumSize(QtCore.QSize(25, 25)) + icon1 = QtGui.QIcon() + icon1.addPixmap(QtGui.QPixmap(":/icons/close-round.svg"), QtGui.QIcon.Normal, QtGui.QIcon.Off) + self.btnCancel.setIcon(icon1) + self.btnCancel.setFlat(True) + self.btnCancel.setObjectName("btnCancel") + self.horizontalLayout.addWidget(self.btnCancel) + self.horizontalLayout_2.addLayout(self.horizontalLayout) + + self.retranslateUi(Form) + self.cmbLockMode.setCurrentIndex(1) + QtCore.QMetaObject.connectSlotsByName(Form) + + def retranslateUi(self, Form): + _translate = QtCore.QCoreApplication.translate + Form.setWindowTitle(_translate("Form", "Form")) + self.cmbLockMode.setItemText(0, _translate("Form", "No Lock")) + self.cmbLockMode.setItemText(1, _translate("Form", "Lock Angle")) + self.cmbLockMode.setItemText(2, _translate("Form", "Lock Angle & Scale")) + self.chkRecompute.setText(_translate("Form", "Recompute Path")) + self.btnForceRecompute.setText(_translate("Form", "Recompute Once")) + +import icons_rc diff --git a/graphics/asymptote/GUI/pyUIClass/widgetPointEditor.py b/graphics/asymptote/GUI/pyUIClass/widgetPointEditor.py new file mode 100644 index 0000000000..c092ede85a --- /dev/null +++ b/graphics/asymptote/GUI/pyUIClass/widgetPointEditor.py @@ -0,0 +1,96 @@ +# -*- coding: utf-8 -*- + +# Form implementation generated from reading ui file 'GUI/windows/widgetPointEditor.ui' +# +# Created by: PyQt5 UI code generator 5.11.3 +# +# WARNING! All changes made in this file will be lost! + +from PyQt5 import QtCore, QtGui, QtWidgets + +class Ui_Form(object): + def setupUi(self, Form): + Form.setObjectName("Form") + Form.resize(324, 67) + self.verticalLayout = QtWidgets.QVBoxLayout(Form) + self.verticalLayout.setObjectName("verticalLayout") + self.nameLabel = QtWidgets.QLabel(Form) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.nameLabel.sizePolicy().hasHeightForWidth()) + self.nameLabel.setSizePolicy(sizePolicy) + self.nameLabel.setObjectName("nameLabel") + self.verticalLayout.addWidget(self.nameLabel) + self.horizontalLayout = QtWidgets.QHBoxLayout() + self.horizontalLayout.setObjectName("horizontalLayout") + self.lineXorA = QtWidgets.QLineEdit(Form) + self.lineXorA.setEnabled(False) + self.lineXorA.setReadOnly(False) + self.lineXorA.setObjectName("lineXorA") + self.horizontalLayout.addWidget(self.lineXorA) + self.lineYorM = QtWidgets.QLineEdit(Form) + self.lineYorM.setEnabled(False) + self.lineYorM.setAutoFillBackground(False) + self.lineYorM.setReadOnly(False) + self.lineYorM.setObjectName("lineYorM") + self.horizontalLayout.addWidget(self.lineYorM) + self.btnRelative = QtWidgets.QPushButton(Form) + self.btnRelative.setEnabled(False) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.btnRelative.sizePolicy().hasHeightForWidth()) + self.btnRelative.setSizePolicy(sizePolicy) + self.btnRelative.setText("") + icon = QtGui.QIcon() + icon.addPixmap(QtGui.QPixmap(":/icons/android-locate.svg"), QtGui.QIcon.Normal, QtGui.QIcon.Off) + self.btnRelative.setIcon(icon) + self.btnRelative.setCheckable(True) + self.btnRelative.setFlat(False) + self.btnRelative.setObjectName("btnRelative") + self.horizontalLayout.addWidget(self.btnRelative) + self.btnPolar = QtWidgets.QPushButton(Form) + self.btnPolar.setEnabled(False) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.btnPolar.sizePolicy().hasHeightForWidth()) + self.btnPolar.setSizePolicy(sizePolicy) + self.btnPolar.setText("") + icon1 = QtGui.QIcon() + icon1.addPixmap(QtGui.QPixmap(":/icons/android-radio-button-off.svg"), QtGui.QIcon.Normal, QtGui.QIcon.Off) + self.btnPolar.setIcon(icon1) + self.btnPolar.setCheckable(True) + self.btnPolar.setFlat(False) + self.btnPolar.setObjectName("btnPolar") + self.horizontalLayout.addWidget(self.btnPolar) + self.btnManualAdj = QtWidgets.QPushButton(Form) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.btnManualAdj.sizePolicy().hasHeightForWidth()) + self.btnManualAdj.setSizePolicy(sizePolicy) + self.btnManualAdj.setText("") + icon2 = QtGui.QIcon() + icon2.addPixmap(QtGui.QPixmap(":/icons/edit.svg"), QtGui.QIcon.Normal, QtGui.QIcon.Off) + self.btnManualAdj.setIcon(icon2) + self.btnManualAdj.setCheckable(True) + self.btnManualAdj.setFlat(False) + self.btnManualAdj.setObjectName("btnManualAdj") + self.horizontalLayout.addWidget(self.btnManualAdj) + self.verticalLayout.addLayout(self.horizontalLayout) + + self.retranslateUi(Form) + QtCore.QMetaObject.connectSlotsByName(Form) + + def retranslateUi(self, Form): + _translate = QtCore.QCoreApplication.translate + Form.setWindowTitle(_translate("Form", "Form")) + self.nameLabel.setText(_translate("Form", "Left Control Point")) + self.lineXorA.setToolTip(_translate("Form", "X")) + self.lineXorA.setPlaceholderText(_translate("Form", "X")) + self.lineYorM.setToolTip(_translate("Form", "X")) + self.lineYorM.setPlaceholderText(_translate("Form", "Y")) + +import icons_rc diff --git a/graphics/asymptote/GUI/pyUIClass/window1.py b/graphics/asymptote/GUI/pyUIClass/window1.py new file mode 100644 index 0000000000..f77d018fce --- /dev/null +++ b/graphics/asymptote/GUI/pyUIClass/window1.py @@ -0,0 +1,930 @@ +# -*- coding: utf-8 -*- + +# Form implementation generated from reading ui file 'GUI/windows/window1.ui' +# +# Created by: PyQt5 UI code generator 5.11.3 +# +# WARNING! All changes made in this file will be lost! + +from PyQt5 import QtCore, QtGui, QtWidgets + +class Ui_MainWindow(object): + def setupUi(self, MainWindow): + MainWindow.setObjectName("MainWindow") + MainWindow.resize(1030, 768) + self.centralwidget = QtWidgets.QWidget(MainWindow) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.centralwidget.sizePolicy().hasHeightForWidth()) + self.centralwidget.setSizePolicy(sizePolicy) + self.centralwidget.setMouseTracking(True) + self.centralwidget.setObjectName("centralwidget") + self.horizontalLayout_4 = QtWidgets.QHBoxLayout(self.centralwidget) + self.horizontalLayout_4.setContentsMargins(0, 0, 0, 0) + self.horizontalLayout_4.setSpacing(0) + self.horizontalLayout_4.setObjectName("horizontalLayout_4") + self.mainWidget = QtWidgets.QWidget(self.centralwidget) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.mainWidget.sizePolicy().hasHeightForWidth()) + self.mainWidget.setSizePolicy(sizePolicy) + self.mainWidget.setMouseTracking(True) + self.mainWidget.setObjectName("mainWidget") + self.verticalLayout = QtWidgets.QVBoxLayout(self.mainWidget) + self.verticalLayout.setContentsMargins(2, 2, 2, 2) + self.verticalLayout.setSpacing(4) + self.verticalLayout.setObjectName("verticalLayout") + self.menuFrame = QtWidgets.QFrame(self.mainWidget) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.menuFrame.sizePolicy().hasHeightForWidth()) + self.menuFrame.setSizePolicy(sizePolicy) + self.menuFrame.setFrameShape(QtWidgets.QFrame.NoFrame) + self.menuFrame.setObjectName("menuFrame") + self.horizontalLayout = QtWidgets.QHBoxLayout(self.menuFrame) + self.horizontalLayout.setSizeConstraint(QtWidgets.QLayout.SetMinimumSize) + self.horizontalLayout.setContentsMargins(0, 0, 0, 0) + self.horizontalLayout.setSpacing(4) + self.horizontalLayout.setObjectName("horizontalLayout") + self.btnUndo = QtWidgets.QPushButton(self.menuFrame) + self.btnUndo.setEnabled(False) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Minimum) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.btnUndo.sizePolicy().hasHeightForWidth()) + self.btnUndo.setSizePolicy(sizePolicy) + self.btnUndo.setMaximumSize(QtCore.QSize(25, 25)) + 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) + self.btnUndo.setIcon(icon) + self.btnUndo.setIconSize(QtCore.QSize(16, 16)) + self.btnUndo.setFlat(True) + self.btnUndo.setObjectName("btnUndo") + self.horizontalLayout.addWidget(self.btnUndo) + self.btnRedo = QtWidgets.QPushButton(self.menuFrame) + self.btnRedo.setEnabled(False) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.btnRedo.sizePolicy().hasHeightForWidth()) + self.btnRedo.setSizePolicy(sizePolicy) + self.btnRedo.setMaximumSize(QtCore.QSize(25, 25)) + 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) + self.btnRedo.setIcon(icon1) + self.btnRedo.setFlat(True) + self.btnRedo.setObjectName("btnRedo") + self.horizontalLayout.addWidget(self.btnRedo) + self.btnLoadFile = QtWidgets.QPushButton(self.menuFrame) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.btnLoadFile.sizePolicy().hasHeightForWidth()) + self.btnLoadFile.setSizePolicy(sizePolicy) + self.btnLoadFile.setMaximumSize(QtCore.QSize(25, 25)) + self.btnLoadFile.setBaseSize(QtCore.QSize(32, 32)) + self.btnLoadFile.setText("") + icon2 = QtGui.QIcon() + icon2.addPixmap(QtGui.QPixmap(":/icons/android-folder-open.svg"), QtGui.QIcon.Normal, QtGui.QIcon.Off) + self.btnLoadFile.setIcon(icon2) + self.btnLoadFile.setFlat(True) + self.btnLoadFile.setObjectName("btnLoadFile") + self.horizontalLayout.addWidget(self.btnLoadFile) + self.btnSave = QtWidgets.QPushButton(self.menuFrame) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.btnSave.sizePolicy().hasHeightForWidth()) + self.btnSave.setSizePolicy(sizePolicy) + self.btnSave.setMaximumSize(QtCore.QSize(25, 25)) + self.btnSave.setBaseSize(QtCore.QSize(32, 32)) + self.btnSave.setText("") + icon3 = QtGui.QIcon() + icon3.addPixmap(QtGui.QPixmap(":/icons/save.svg"), QtGui.QIcon.Normal, QtGui.QIcon.Off) + self.btnSave.setIcon(icon3) + self.btnSave.setFlat(True) + self.btnSave.setObjectName("btnSave") + self.horizontalLayout.addWidget(self.btnSave) + self.btnViewCode = QtWidgets.QPushButton(self.menuFrame) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Maximum) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.btnViewCode.sizePolicy().hasHeightForWidth()) + self.btnViewCode.setSizePolicy(sizePolicy) + self.btnViewCode.setMaximumSize(QtCore.QSize(25, 25)) + self.btnViewCode.setBaseSize(QtCore.QSize(32, 32)) + self.btnViewCode.setText("") + icon4 = QtGui.QIcon() + icon4.addPixmap(QtGui.QPixmap(":/icons/code.svg"), QtGui.QIcon.Normal, QtGui.QIcon.Off) + self.btnViewCode.setIcon(icon4) + self.btnViewCode.setFlat(True) + self.btnViewCode.setObjectName("btnViewCode") + self.horizontalLayout.addWidget(self.btnViewCode) + self.btnQuickScreenshot = QtWidgets.QPushButton(self.menuFrame) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.btnQuickScreenshot.sizePolicy().hasHeightForWidth()) + self.btnQuickScreenshot.setSizePolicy(sizePolicy) + self.btnQuickScreenshot.setMaximumSize(QtCore.QSize(25, 25)) + self.btnQuickScreenshot.setBaseSize(QtCore.QSize(32, 32)) + self.btnQuickScreenshot.setText("") + icon5 = QtGui.QIcon() + icon5.addPixmap(QtGui.QPixmap(":/icons/android-camera.svg"), QtGui.QIcon.Normal, QtGui.QIcon.Off) + self.btnQuickScreenshot.setIcon(icon5) + self.btnQuickScreenshot.setFlat(True) + self.btnQuickScreenshot.setObjectName("btnQuickScreenshot") + self.horizontalLayout.addWidget(self.btnQuickScreenshot) + spacerItem = QtWidgets.QSpacerItem(20, 20, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Minimum) + self.horizontalLayout.addItem(spacerItem) + self.btnDrawAxes = QtWidgets.QPushButton(self.menuFrame) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Maximum) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.btnDrawAxes.sizePolicy().hasHeightForWidth()) + self.btnDrawAxes.setSizePolicy(sizePolicy) + self.btnDrawAxes.setMaximumSize(QtCore.QSize(25, 25)) + self.btnDrawAxes.setBaseSize(QtCore.QSize(32, 32)) + font = QtGui.QFont() + font.setFamily("Roboto") + font.setBold(True) + font.setWeight(75) + self.btnDrawAxes.setFont(font) + self.btnDrawAxes.setText("") + icon6 = QtGui.QIcon() + icon6.addPixmap(QtGui.QPixmap(":/icons/plus-round.svg"), QtGui.QIcon.Normal, QtGui.QIcon.Off) + self.btnDrawAxes.setIcon(icon6) + self.btnDrawAxes.setCheckable(True) + self.btnDrawAxes.setChecked(True) + self.btnDrawAxes.setFlat(True) + self.btnDrawAxes.setObjectName("btnDrawAxes") + self.horizontalLayout.addWidget(self.btnDrawAxes) + self.btnDrawGrid = QtWidgets.QPushButton(self.menuFrame) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Maximum) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.btnDrawGrid.sizePolicy().hasHeightForWidth()) + self.btnDrawGrid.setSizePolicy(sizePolicy) + self.btnDrawGrid.setMaximumSize(QtCore.QSize(25, 25)) + self.btnDrawGrid.setBaseSize(QtCore.QSize(32, 32)) + font = QtGui.QFont() + font.setFamily("Roboto") + font.setBold(True) + font.setWeight(75) + self.btnDrawGrid.setFont(font) + self.btnDrawGrid.setText("") + icon7 = QtGui.QIcon() + icon7.addPixmap(QtGui.QPixmap(":/icons/grid.svg"), QtGui.QIcon.Normal, QtGui.QIcon.Off) + self.btnDrawGrid.setIcon(icon7) + self.btnDrawGrid.setCheckable(True) + self.btnDrawGrid.setChecked(False) + self.btnDrawGrid.setFlat(True) + self.btnDrawGrid.setObjectName("btnDrawGrid") + self.horizontalLayout.addWidget(self.btnDrawGrid) + self.btnSetZoom = QtWidgets.QPushButton(self.menuFrame) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.btnSetZoom.sizePolicy().hasHeightForWidth()) + self.btnSetZoom.setSizePolicy(sizePolicy) + self.btnSetZoom.setMaximumSize(QtCore.QSize(25, 25)) + self.btnSetZoom.setBaseSize(QtCore.QSize(32, 32)) + self.btnSetZoom.setText("") + icon8 = QtGui.QIcon() + icon8.addPixmap(QtGui.QPixmap(":/icons/magnifying-glass.svg"), QtGui.QIcon.Normal, QtGui.QIcon.Off) + self.btnSetZoom.setIcon(icon8) + self.btnSetZoom.setFlat(True) + self.btnSetZoom.setObjectName("btnSetZoom") + self.horizontalLayout.addWidget(self.btnSetZoom) + self.btnPanCenter = QtWidgets.QPushButton(self.menuFrame) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.btnPanCenter.sizePolicy().hasHeightForWidth()) + self.btnPanCenter.setSizePolicy(sizePolicy) + self.btnPanCenter.setMaximumSize(QtCore.QSize(25, 25)) + self.btnPanCenter.setBaseSize(QtCore.QSize(32, 32)) + self.btnPanCenter.setText("") + icon9 = QtGui.QIcon() + icon9.addPixmap(QtGui.QPixmap(":/icons/center.svg"), QtGui.QIcon.Normal, QtGui.QIcon.Off) + self.btnPanCenter.setIcon(icon9) + self.btnPanCenter.setFlat(True) + self.btnPanCenter.setObjectName("btnPanCenter") + self.horizontalLayout.addWidget(self.btnPanCenter) + self.btnResetPan = QtWidgets.QPushButton(self.menuFrame) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.btnResetPan.sizePolicy().hasHeightForWidth()) + self.btnResetPan.setSizePolicy(sizePolicy) + self.btnResetPan.setMaximumSize(QtCore.QSize(25, 25)) + self.btnResetPan.setBaseSize(QtCore.QSize(32, 32)) + self.btnResetPan.setText("") + icon10 = QtGui.QIcon() + icon10.addPixmap(QtGui.QPixmap(":/icons/centerorigin.svg"), QtGui.QIcon.Normal, QtGui.QIcon.Off) + self.btnResetPan.setIcon(icon10) + self.btnResetPan.setFlat(True) + self.btnResetPan.setObjectName("btnResetPan") + self.horizontalLayout.addWidget(self.btnResetPan) + self.btnAlignX = QtWidgets.QPushButton(self.menuFrame) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Maximum) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.btnAlignX.sizePolicy().hasHeightForWidth()) + self.btnAlignX.setSizePolicy(sizePolicy) + self.btnAlignX.setMaximumSize(QtCore.QSize(25, 25)) + self.btnAlignX.setBaseSize(QtCore.QSize(32, 32)) + font = QtGui.QFont() + font.setFamily("Roboto") + font.setBold(True) + font.setWeight(75) + self.btnAlignX.setFont(font) + self.btnAlignX.setCheckable(True) + self.btnAlignX.setFlat(True) + self.btnAlignX.setObjectName("btnAlignX") + self.horizontalLayout.addWidget(self.btnAlignX) + self.btnAlignY = QtWidgets.QPushButton(self.menuFrame) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Maximum) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.btnAlignY.sizePolicy().hasHeightForWidth()) + self.btnAlignY.setSizePolicy(sizePolicy) + self.btnAlignY.setMaximumSize(QtCore.QSize(25, 25)) + self.btnAlignY.setBaseSize(QtCore.QSize(32, 32)) + font = QtGui.QFont() + font.setBold(True) + font.setWeight(75) + self.btnAlignY.setFont(font) + self.btnAlignY.setCheckable(True) + self.btnAlignY.setFlat(True) + self.btnAlignY.setObjectName("btnAlignY") + self.horizontalLayout.addWidget(self.btnAlignY) + spacerItem1 = QtWidgets.QSpacerItem(20, 20, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Minimum) + self.horizontalLayout.addItem(spacerItem1) + self.btnSelectEdit = QtWidgets.QPushButton(self.menuFrame) + self.btnSelectEdit.setEnabled(True) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Maximum) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.btnSelectEdit.sizePolicy().hasHeightForWidth()) + self.btnSelectEdit.setSizePolicy(sizePolicy) + self.btnSelectEdit.setMaximumSize(QtCore.QSize(25, 25)) + self.btnSelectEdit.setText("") + icon11 = QtGui.QIcon() + icon11.addPixmap(QtGui.QPixmap(":/icons/edit.svg"), QtGui.QIcon.Normal, QtGui.QIcon.Off) + self.btnSelectEdit.setIcon(icon11) + self.btnSelectEdit.setFlat(True) + self.btnSelectEdit.setObjectName("btnSelectEdit") + self.horizontalLayout.addWidget(self.btnSelectEdit) + self.btnDeleteMode = QtWidgets.QPushButton(self.menuFrame) + self.btnDeleteMode.setEnabled(True) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Maximum) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.btnDeleteMode.sizePolicy().hasHeightForWidth()) + self.btnDeleteMode.setSizePolicy(sizePolicy) + self.btnDeleteMode.setMaximumSize(QtCore.QSize(25, 25)) + self.btnDeleteMode.setBaseSize(QtCore.QSize(32, 32)) + self.btnDeleteMode.setText("") + icon12 = QtGui.QIcon() + icon12.addPixmap(QtGui.QPixmap(":/icons/android-delete.svg"), QtGui.QIcon.Normal, QtGui.QIcon.Off) + self.btnDeleteMode.setIcon(icon12) + self.btnDeleteMode.setCheckable(False) + self.btnDeleteMode.setFlat(True) + self.btnDeleteMode.setObjectName("btnDeleteMode") + self.horizontalLayout.addWidget(self.btnDeleteMode) + spacerItem2 = QtWidgets.QSpacerItem(20, 20, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Minimum) + self.horizontalLayout.addItem(spacerItem2) + self.btnPan = QtWidgets.QPushButton(self.menuFrame) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.btnPan.sizePolicy().hasHeightForWidth()) + self.btnPan.setSizePolicy(sizePolicy) + self.btnPan.setMaximumSize(QtCore.QSize(25, 25)) + self.btnPan.setBaseSize(QtCore.QSize(32, 32)) + self.btnPan.setText("") + icon13 = QtGui.QIcon() + icon13.addPixmap(QtGui.QPixmap(":/icons/android-hand.svg"), QtGui.QIcon.Normal, QtGui.QIcon.Off) + self.btnPan.setIcon(icon13) + self.btnPan.setCheckable(True) + self.btnPan.setFlat(True) + self.btnPan.setObjectName("btnPan") + self.horizontalLayout.addWidget(self.btnPan) + self.btnTranslate = QtWidgets.QPushButton(self.menuFrame) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.btnTranslate.sizePolicy().hasHeightForWidth()) + self.btnTranslate.setSizePolicy(sizePolicy) + self.btnTranslate.setMaximumSize(QtCore.QSize(25, 25)) + self.btnTranslate.setBaseSize(QtCore.QSize(32, 32)) + self.btnTranslate.setText("") + icon14 = QtGui.QIcon() + icon14.addPixmap(QtGui.QPixmap(":/icons/arrow-move.svg"), QtGui.QIcon.Normal, QtGui.QIcon.Off) + self.btnTranslate.setIcon(icon14) + self.btnTranslate.setCheckable(True) + self.btnTranslate.setChecked(True) + self.btnTranslate.setFlat(True) + self.btnTranslate.setObjectName("btnTranslate") + self.horizontalLayout.addWidget(self.btnTranslate) + self.btnScale = QtWidgets.QPushButton(self.menuFrame) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Maximum) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.btnScale.sizePolicy().hasHeightForWidth()) + self.btnScale.setSizePolicy(sizePolicy) + self.btnScale.setMaximumSize(QtCore.QSize(25, 25)) + self.btnScale.setBaseSize(QtCore.QSize(32, 32)) + self.btnScale.setText("") + icon15 = QtGui.QIcon() + icon15.addPixmap(QtGui.QPixmap(":/icons/arrow-resize.svg"), QtGui.QIcon.Normal, QtGui.QIcon.Off) + self.btnScale.setIcon(icon15) + self.btnScale.setCheckable(True) + self.btnScale.setFlat(True) + self.btnScale.setObjectName("btnScale") + self.horizontalLayout.addWidget(self.btnScale) + self.btnRotate = QtWidgets.QPushButton(self.menuFrame) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.btnRotate.sizePolicy().hasHeightForWidth()) + self.btnRotate.setSizePolicy(sizePolicy) + self.btnRotate.setMaximumSize(QtCore.QSize(25, 25)) + self.btnRotate.setBaseSize(QtCore.QSize(32, 32)) + self.btnRotate.setText("") + icon16 = QtGui.QIcon() + icon16.addPixmap(QtGui.QPixmap(":/icons/android-refresh.svg"), QtGui.QIcon.Normal, QtGui.QIcon.Off) + self.btnRotate.setIcon(icon16) + self.btnRotate.setCheckable(True) + self.btnRotate.setFlat(True) + self.btnRotate.setObjectName("btnRotate") + self.horizontalLayout.addWidget(self.btnRotate) + spacerItem3 = QtWidgets.QSpacerItem(20, 20, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Minimum) + self.horizontalLayout.addItem(spacerItem3) + self.btnAnchor = QtWidgets.QPushButton(self.menuFrame) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Maximum) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.btnAnchor.sizePolicy().hasHeightForWidth()) + self.btnAnchor.setSizePolicy(sizePolicy) + self.btnAnchor.setMaximumSize(QtCore.QSize(25, 25)) + self.btnAnchor.setBaseSize(QtCore.QSize(32, 32)) + self.btnAnchor.setText("") + icon17 = QtGui.QIcon() + icon17.addPixmap(QtGui.QPixmap(":/icons/anchor.svg"), QtGui.QIcon.Normal, QtGui.QIcon.Off) + self.btnAnchor.setIcon(icon17) + self.btnAnchor.setCheckable(True) + self.btnAnchor.setChecked(False) + self.btnAnchor.setFlat(True) + self.btnAnchor.setObjectName("btnAnchor") + self.horizontalLayout.addWidget(self.btnAnchor) + self.comboAnchor = QtWidgets.QComboBox(self.menuFrame) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Maximum) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.comboAnchor.sizePolicy().hasHeightForWidth()) + self.comboAnchor.setSizePolicy(sizePolicy) + self.comboAnchor.setMinimumSize(QtCore.QSize(127, 0)) + self.comboAnchor.setMaximumSize(QtCore.QSize(127, 25)) + self.comboAnchor.setLayoutDirection(QtCore.Qt.LeftToRight) + self.comboAnchor.setEditable(False) + self.comboAnchor.setInsertPolicy(QtWidgets.QComboBox.InsertAtCurrent) + self.comboAnchor.setSizeAdjustPolicy(QtWidgets.QComboBox.AdjustToContentsOnFirstShow) + self.comboAnchor.setIconSize(QtCore.QSize(0, 0)) + self.comboAnchor.setDuplicatesEnabled(False) + self.comboAnchor.setFrame(False) + self.comboAnchor.setModelColumn(0) + self.comboAnchor.setObjectName("comboAnchor") + self.comboAnchor.addItem("") + self.comboAnchor.addItem("") + self.comboAnchor.addItem("") + self.comboAnchor.addItem("") + self.comboAnchor.addItem("") + self.comboAnchor.addItem("") + self.comboAnchor.addItem("") + self.horizontalLayout.addWidget(self.comboAnchor) + self.btnToggleVisible = QtWidgets.QPushButton(self.menuFrame) + self.btnToggleVisible.setEnabled(False) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Maximum) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.btnToggleVisible.sizePolicy().hasHeightForWidth()) + self.btnToggleVisible.setSizePolicy(sizePolicy) + self.btnToggleVisible.setMaximumSize(QtCore.QSize(25, 25)) + self.btnToggleVisible.setBaseSize(QtCore.QSize(32, 32)) + self.btnToggleVisible.setText("") + icon18 = QtGui.QIcon() + icon18.addPixmap(QtGui.QPixmap(":/icons/eye.svg"), QtGui.QIcon.Normal, QtGui.QIcon.Off) + self.btnToggleVisible.setIcon(icon18) + self.btnToggleVisible.setCheckable(False) + self.btnToggleVisible.setFlat(True) + self.btnToggleVisible.setObjectName("btnToggleVisible") + self.horizontalLayout.addWidget(self.btnToggleVisible) + self.btnCustTransform = QtWidgets.QPushButton(self.menuFrame) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.btnCustTransform.sizePolicy().hasHeightForWidth()) + self.btnCustTransform.setSizePolicy(sizePolicy) + self.btnCustTransform.setMaximumSize(QtCore.QSize(25, 25)) + self.btnCustTransform.setBaseSize(QtCore.QSize(32, 32)) + self.btnCustTransform.setText("") + icon19 = QtGui.QIcon() + icon19.addPixmap(QtGui.QPixmap(":/icons/android-expand.svg"), QtGui.QIcon.Normal, QtGui.QIcon.Off) + self.btnCustTransform.setIcon(icon19) + self.btnCustTransform.setFlat(True) + self.btnCustTransform.setObjectName("btnCustTransform") + self.horizontalLayout.addWidget(self.btnCustTransform) + self.btnSendBackwards = QtWidgets.QPushButton(self.menuFrame) + self.btnSendBackwards.setEnabled(False) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.btnSendBackwards.sizePolicy().hasHeightForWidth()) + self.btnSendBackwards.setSizePolicy(sizePolicy) + self.btnSendBackwards.setMaximumSize(QtCore.QSize(25, 25)) + self.btnSendBackwards.setBaseSize(QtCore.QSize(32, 32)) + self.btnSendBackwards.setText("") + icon20 = QtGui.QIcon() + icon20.addPixmap(QtGui.QPixmap(":/icons/chevron-with-circle-left.svg"), QtGui.QIcon.Normal, QtGui.QIcon.Off) + self.btnSendBackwards.setIcon(icon20) + self.btnSendBackwards.setFlat(True) + self.btnSendBackwards.setObjectName("btnSendBackwards") + self.horizontalLayout.addWidget(self.btnSendBackwards) + self.btnSendForwards = QtWidgets.QPushButton(self.menuFrame) + self.btnSendForwards.setEnabled(False) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.btnSendForwards.sizePolicy().hasHeightForWidth()) + self.btnSendForwards.setSizePolicy(sizePolicy) + self.btnSendForwards.setMaximumSize(QtCore.QSize(25, 25)) + self.btnSendForwards.setBaseSize(QtCore.QSize(32, 32)) + self.btnSendForwards.setText("") + icon21 = QtGui.QIcon() + icon21.addPixmap(QtGui.QPixmap(":/icons/chevron-with-circle-right.svg"), QtGui.QIcon.Normal, QtGui.QIcon.Off) + self.btnSendForwards.setIcon(icon21) + self.btnSendForwards.setFlat(True) + self.btnSendForwards.setObjectName("btnSendForwards") + self.horizontalLayout.addWidget(self.btnSendForwards) + spacerItem4 = QtWidgets.QSpacerItem(40, 25, QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Minimum) + self.horizontalLayout.addItem(spacerItem4) + self.btnUndo.raise_() + self.btnRedo.raise_() + self.btnLoadFile.raise_() + self.btnSave.raise_() + self.btnViewCode.raise_() + self.btnQuickScreenshot.raise_() + self.btnDrawAxes.raise_() + self.btnDrawGrid.raise_() + self.btnSetZoom.raise_() + self.btnPanCenter.raise_() + self.btnResetPan.raise_() + self.btnAlignX.raise_() + self.btnAlignY.raise_() + self.btnPan.raise_() + self.btnTranslate.raise_() + self.btnScale.raise_() + self.btnCustTransform.raise_() + self.btnSendBackwards.raise_() + self.btnSendForwards.raise_() + self.comboAnchor.raise_() + self.btnToggleVisible.raise_() + self.btnAnchor.raise_() + self.btnRotate.raise_() + self.btnSelectEdit.raise_() + self.btnDeleteMode.raise_() + self.verticalLayout.addWidget(self.menuFrame) + self.horizontalLayout_2 = QtWidgets.QHBoxLayout() + self.horizontalLayout_2.setSpacing(4) + self.horizontalLayout_2.setObjectName("horizontalLayout_2") + self.verticalLayout_2 = QtWidgets.QVBoxLayout() + self.verticalLayout_2.setSpacing(3) + self.verticalLayout_2.setObjectName("verticalLayout_2") + self.addOption = QtWidgets.QHBoxLayout() + self.addOption.setSizeConstraint(QtWidgets.QLayout.SetDefaultConstraint) + self.addOption.setContentsMargins(6, -1, -1, 0) + self.addOption.setSpacing(6) + self.addOption.setObjectName("addOption") + self.btnFill = QtWidgets.QPushButton(self.mainWidget) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.btnFill.sizePolicy().hasHeightForWidth()) + self.btnFill.setSizePolicy(sizePolicy) + self.btnFill.setMaximumSize(QtCore.QSize(32, 32)) + self.btnFill.setBaseSize(QtCore.QSize(32, 32)) + self.btnFill.setAutoFillBackground(False) + self.btnFill.setStyleSheet("") + self.btnFill.setText("") + icon22 = QtGui.QIcon() + icon22.addPixmap(QtGui.QPixmap(":/icons/bucket.svg"), QtGui.QIcon.Normal, QtGui.QIcon.Off) + icon22.addPixmap(QtGui.QPixmap(":/icons/filledbucket.svg"), QtGui.QIcon.Normal, QtGui.QIcon.On) + self.btnFill.setIcon(icon22) + self.btnFill.setCheckable(True) + self.btnFill.setDefault(False) + self.btnFill.setFlat(True) + self.btnFill.setObjectName("btnFill") + self.addOption.addWidget(self.btnFill) + self.addOptionLayout = QtWidgets.QGridLayout() + self.addOptionLayout.setSpacing(6) + self.addOptionLayout.setObjectName("addOptionLayout") + self.addOption.addLayout(self.addOptionLayout) + spacerItem5 = QtWidgets.QSpacerItem(40, 35, QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.Minimum) + self.addOption.addItem(spacerItem5) + self.label = QtWidgets.QLabel(self.mainWidget) + self.label.setObjectName("label") + self.addOption.addWidget(self.label) + self.txtLineWidth = QtWidgets.QLineEdit(self.mainWidget) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.txtLineWidth.sizePolicy().hasHeightForWidth()) + self.txtLineWidth.setSizePolicy(sizePolicy) + self.txtLineWidth.setMaximumSize(QtCore.QSize(75, 16777215)) + self.txtLineWidth.setObjectName("txtLineWidth") + self.addOption.addWidget(self.txtLineWidth) + self.frameCurrColor = QtWidgets.QFrame(self.mainWidget) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.frameCurrColor.sizePolicy().hasHeightForWidth()) + self.frameCurrColor.setSizePolicy(sizePolicy) + self.frameCurrColor.setMinimumSize(QtCore.QSize(15, 15)) + self.frameCurrColor.setAutoFillBackground(False) + self.frameCurrColor.setStyleSheet("QFrame{ \n" +"padding: 4.0;\n" +"border-radius: 3.0; \n" +"background: rgb(0, 0, 0)\n" +"}") + self.frameCurrColor.setFrameShape(QtWidgets.QFrame.StyledPanel) + self.frameCurrColor.setFrameShadow(QtWidgets.QFrame.Sunken) + self.frameCurrColor.setObjectName("frameCurrColor") + self.addOption.addWidget(self.frameCurrColor) + self.btnSelectColor = QtWidgets.QPushButton(self.mainWidget) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.btnSelectColor.sizePolicy().hasHeightForWidth()) + self.btnSelectColor.setSizePolicy(sizePolicy) + self.btnSelectColor.setMaximumSize(QtCore.QSize(25, 25)) + self.btnSelectColor.setBaseSize(QtCore.QSize(32, 32)) + self.btnSelectColor.setAutoFillBackground(False) + self.btnSelectColor.setStyleSheet("") + self.btnSelectColor.setText("") + icon23 = QtGui.QIcon() + icon23.addPixmap(QtGui.QPixmap(":/icons/android-color-palette.svg"), QtGui.QIcon.Normal, QtGui.QIcon.Off) + self.btnSelectColor.setIcon(icon23) + self.btnSelectColor.setDefault(False) + self.btnSelectColor.setFlat(True) + self.btnSelectColor.setObjectName("btnSelectColor") + self.addOption.addWidget(self.btnSelectColor) + self.verticalLayout_2.addLayout(self.addOption) + self.horizontalLayout_7 = QtWidgets.QHBoxLayout() + self.horizontalLayout_7.setContentsMargins(-1, 6, -1, -1) + self.horizontalLayout_7.setSpacing(6) + self.horizontalLayout_7.setObjectName("horizontalLayout_7") + self.formFrame = QtWidgets.QFrame(self.mainWidget) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Preferred) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.formFrame.sizePolicy().hasHeightForWidth()) + self.formFrame.setSizePolicy(sizePolicy) + self.formFrame.setFrameShape(QtWidgets.QFrame.NoFrame) + self.formFrame.setFrameShadow(QtWidgets.QFrame.Plain) + self.formFrame.setLineWidth(0) + self.formFrame.setObjectName("formFrame") + self.formLayout = QtWidgets.QFormLayout(self.formFrame) + self.formLayout.setContentsMargins(0, 0, 0, 0) + self.formLayout.setSpacing(0) + self.formLayout.setObjectName("formLayout") + self.btnOpenPoly = QtWidgets.QPushButton(self.formFrame) + self.btnOpenPoly.setEnabled(True) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Maximum) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.btnOpenPoly.sizePolicy().hasHeightForWidth()) + self.btnOpenPoly.setSizePolicy(sizePolicy) + self.btnOpenPoly.setMaximumSize(QtCore.QSize(32, 32)) + self.btnOpenPoly.setText("") + icon24 = QtGui.QIcon() + icon24.addPixmap(QtGui.QPixmap(":/icons/openpolygon.svg"), QtGui.QIcon.Normal, QtGui.QIcon.Off) + self.btnOpenPoly.setIcon(icon24) + self.btnOpenPoly.setFlat(True) + self.btnOpenPoly.setObjectName("btnOpenPoly") + self.formLayout.setWidget(4, QtWidgets.QFormLayout.LabelRole, self.btnOpenPoly) + self.btnClosedPoly = QtWidgets.QPushButton(self.formFrame) + self.btnClosedPoly.setEnabled(True) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Maximum) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.btnClosedPoly.sizePolicy().hasHeightForWidth()) + self.btnClosedPoly.setSizePolicy(sizePolicy) + self.btnClosedPoly.setMaximumSize(QtCore.QSize(32, 32)) + self.btnClosedPoly.setText("") + icon25 = QtGui.QIcon() + icon25.addPixmap(QtGui.QPixmap(":/icons/closedpolygon.svg"), QtGui.QIcon.Normal, QtGui.QIcon.Off) + self.btnClosedPoly.setIcon(icon25) + self.btnClosedPoly.setFlat(True) + self.btnClosedPoly.setObjectName("btnClosedPoly") + self.formLayout.setWidget(5, QtWidgets.QFormLayout.LabelRole, self.btnClosedPoly) + self.btnOpenCurve = QtWidgets.QPushButton(self.formFrame) + self.btnOpenCurve.setEnabled(True) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Maximum) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.btnOpenCurve.sizePolicy().hasHeightForWidth()) + self.btnOpenCurve.setSizePolicy(sizePolicy) + self.btnOpenCurve.setMaximumSize(QtCore.QSize(32, 32)) + self.btnOpenCurve.setText("") + icon26 = QtGui.QIcon() + icon26.addPixmap(QtGui.QPixmap(":/icons/opencurve.svg"), QtGui.QIcon.Normal, QtGui.QIcon.Off) + self.btnOpenCurve.setIcon(icon26) + self.btnOpenCurve.setFlat(True) + self.btnOpenCurve.setObjectName("btnOpenCurve") + self.formLayout.setWidget(6, QtWidgets.QFormLayout.LabelRole, self.btnOpenCurve) + self.btnClosedCurve = QtWidgets.QPushButton(self.formFrame) + self.btnClosedCurve.setEnabled(True) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Maximum) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.btnClosedCurve.sizePolicy().hasHeightForWidth()) + self.btnClosedCurve.setSizePolicy(sizePolicy) + self.btnClosedCurve.setMaximumSize(QtCore.QSize(32, 32)) + self.btnClosedCurve.setText("") + icon27 = QtGui.QIcon() + icon27.addPixmap(QtGui.QPixmap(":/icons/closedcurve.svg"), QtGui.QIcon.Normal, QtGui.QIcon.Off) + self.btnClosedCurve.setIcon(icon27) + self.btnClosedCurve.setFlat(True) + self.btnClosedCurve.setObjectName("btnClosedCurve") + self.formLayout.setWidget(7, QtWidgets.QFormLayout.LabelRole, self.btnClosedCurve) + self.btnAddPoly = QtWidgets.QPushButton(self.formFrame) + self.btnAddPoly.setEnabled(True) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Maximum) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.btnAddPoly.sizePolicy().hasHeightForWidth()) + self.btnAddPoly.setSizePolicy(sizePolicy) + self.btnAddPoly.setMaximumSize(QtCore.QSize(32, 32)) + self.btnAddPoly.setText("") + icon28 = QtGui.QIcon() + icon28.addPixmap(QtGui.QPixmap(":/icons/triangle-stroked-15.svg"), QtGui.QIcon.Normal, QtGui.QIcon.Off) + self.btnAddPoly.setIcon(icon28) + self.btnAddPoly.setFlat(True) + self.btnAddPoly.setObjectName("btnAddPoly") + self.formLayout.setWidget(8, QtWidgets.QFormLayout.LabelRole, self.btnAddPoly) + self.btnAddCircle = QtWidgets.QPushButton(self.formFrame) + self.btnAddCircle.setEnabled(True) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Maximum) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.btnAddCircle.sizePolicy().hasHeightForWidth()) + self.btnAddCircle.setSizePolicy(sizePolicy) + self.btnAddCircle.setMaximumSize(QtCore.QSize(32, 32)) + self.btnAddCircle.setText("") + icon29 = QtGui.QIcon() + icon29.addPixmap(QtGui.QPixmap(":/icons/circle.svg"), QtGui.QIcon.Normal, QtGui.QIcon.Off) + self.btnAddCircle.setIcon(icon29) + self.btnAddCircle.setFlat(True) + self.btnAddCircle.setObjectName("btnAddCircle") + self.formLayout.setWidget(10, QtWidgets.QFormLayout.LabelRole, self.btnAddCircle) + self.btnAddLabel = QtWidgets.QPushButton(self.formFrame) + self.btnAddLabel.setEnabled(True) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Maximum) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.btnAddLabel.sizePolicy().hasHeightForWidth()) + self.btnAddLabel.setSizePolicy(sizePolicy) + self.btnAddLabel.setMaximumSize(QtCore.QSize(32, 32)) + self.btnAddLabel.setText("") + icon30 = QtGui.QIcon() + icon30.addPixmap(QtGui.QPixmap(":/icons/text.svg"), QtGui.QIcon.Normal, QtGui.QIcon.Off) + self.btnAddLabel.setIcon(icon30) + self.btnAddLabel.setFlat(True) + self.btnAddLabel.setObjectName("btnAddLabel") + self.formLayout.setWidget(11, QtWidgets.QFormLayout.LabelRole, self.btnAddLabel) + self.horizontalLayout_7.addWidget(self.formFrame) + self.imgFrame = QtWidgets.QFrame(self.mainWidget) + self.imgFrame.setMinimumSize(QtCore.QSize(0, 6)) + self.imgFrame.setMouseTracking(True) + self.imgFrame.setFrameShape(QtWidgets.QFrame.NoFrame) + self.imgFrame.setFrameShadow(QtWidgets.QFrame.Raised) + self.imgFrame.setObjectName("imgFrame") + self.gridLayout = QtWidgets.QGridLayout(self.imgFrame) + self.gridLayout.setContentsMargins(0, 0, 0, 0) + self.gridLayout.setSpacing(0) + self.gridLayout.setObjectName("gridLayout") + self.imgLabel = QtWidgets.QLabel(self.imgFrame) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.imgLabel.sizePolicy().hasHeightForWidth()) + self.imgLabel.setSizePolicy(sizePolicy) + self.imgLabel.setMouseTracking(True) + self.imgLabel.setFrameShape(QtWidgets.QFrame.Panel) + self.imgLabel.setText("") + self.imgLabel.setAlignment(QtCore.Qt.AlignLeading|QtCore.Qt.AlignLeft|QtCore.Qt.AlignTop) + self.imgLabel.setObjectName("imgLabel") + self.gridLayout.addWidget(self.imgLabel, 0, 1, 1, 1) + self.horizontalLayout_7.addWidget(self.imgFrame) + self.verticalLayout_2.addLayout(self.horizontalLayout_7) + self.horizontalLayout_3 = QtWidgets.QHBoxLayout() + self.horizontalLayout_3.setSizeConstraint(QtWidgets.QLayout.SetDefaultConstraint) + self.horizontalLayout_3.setContentsMargins(-1, 0, -1, -1) + self.horizontalLayout_3.setSpacing(0) + self.horizontalLayout_3.setObjectName("horizontalLayout_3") + self.btnTogglePython = QtWidgets.QPushButton(self.mainWidget) + self.btnTogglePython.setEnabled(True) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Minimum) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + 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) + self.btnTogglePython.setIconSize(QtCore.QSize(16, 16)) + self.btnTogglePython.setCheckable(True) + self.btnTogglePython.setFlat(True) + self.btnTogglePython.setObjectName("btnTogglePython") + self.horizontalLayout_3.addWidget(self.btnTogglePython) + self.txtTerminalPrompt = QtWidgets.QLineEdit(self.mainWidget) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.txtTerminalPrompt.sizePolicy().hasHeightForWidth()) + self.txtTerminalPrompt.setSizePolicy(sizePolicy) + self.txtTerminalPrompt.setObjectName("txtTerminalPrompt") + self.horizontalLayout_3.addWidget(self.txtTerminalPrompt) + self.btnEnterCommand = QtWidgets.QPushButton(self.mainWidget) + self.btnEnterCommand.setEnabled(True) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Minimum) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + 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) + self.btnEnterCommand.setFlat(True) + self.btnEnterCommand.setObjectName("btnEnterCommand") + self.horizontalLayout_3.addWidget(self.btnEnterCommand) + self.verticalLayout_2.addLayout(self.horizontalLayout_3) + self.horizontalLayout_2.addLayout(self.verticalLayout_2) + self.verticalLayout.addLayout(self.horizontalLayout_2) + self.horizontalLayout_4.addWidget(self.mainWidget) + MainWindow.setCentralWidget(self.centralwidget) + self.menubar = QtWidgets.QMenuBar(MainWindow) + self.menubar.setGeometry(QtCore.QRect(0, 0, 1030, 28)) + self.menubar.setObjectName("menubar") + self.menuFIle = QtWidgets.QMenu(self.menubar) + self.menuFIle.setObjectName("menuFIle") + self.menuEdit = QtWidgets.QMenu(self.menubar) + self.menuEdit.setObjectName("menuEdit") + self.menuOptions = QtWidgets.QMenu(self.menubar) + self.menuOptions.setObjectName("menuOptions") + self.menuHelp = QtWidgets.QMenu(self.menubar) + self.menuHelp.setObjectName("menuHelp") + self.menuTools = QtWidgets.QMenu(self.menubar) + self.menuTools.setObjectName("menuTools") + MainWindow.setMenuBar(self.menubar) + self.statusbar = QtWidgets.QStatusBar(MainWindow) + self.statusbar.setSizeGripEnabled(False) + self.statusbar.setObjectName("statusbar") + MainWindow.setStatusBar(self.statusbar) + self.actionAbout = QtWidgets.QAction(MainWindow) + self.actionAbout.setObjectName("actionAbout") + self.actionManual = QtWidgets.QAction(MainWindow) + self.actionManual.setObjectName("actionManual") + self.actionSettings = QtWidgets.QAction(MainWindow) + self.actionSettings.setObjectName("actionSettings") + self.actionPause = QtWidgets.QAction(MainWindow) + self.actionPause.setObjectName("actionPause") + self.actionSaveAs = QtWidgets.QAction(MainWindow) + self.actionSaveAs.setObjectName("actionSaveAs") + self.actionEnterCommand = QtWidgets.QAction(MainWindow) + self.actionEnterCommand.setObjectName("actionEnterCommand") + self.actionQuit = QtWidgets.QAction(MainWindow) + self.actionQuit.setObjectName("actionQuit") + self.actionUndo = QtWidgets.QAction(MainWindow) + self.actionUndo.setEnabled(False) + self.actionUndo.setObjectName("actionUndo") + self.actionRedo = QtWidgets.QAction(MainWindow) + self.actionRedo.setEnabled(False) + self.actionRedo.setObjectName("actionRedo") + self.actionShow_Grid = QtWidgets.QAction(MainWindow) + self.actionShow_Grid.setObjectName("actionShow_Grid") + self.actionShow_Local_Grid = QtWidgets.QAction(MainWindow) + self.actionShow_Local_Grid.setObjectName("actionShow_Local_Grid") + self.actionTransform = QtWidgets.QAction(MainWindow) + self.actionTransform.setObjectName("actionTransform") + self.actionExportAsymptote = QtWidgets.QAction(MainWindow) + self.actionExportAsymptote.setObjectName("actionExportAsymptote") + self.actionSave = QtWidgets.QAction(MainWindow) + self.actionSave.setObjectName("actionSave") + self.actionOpen = QtWidgets.QAction(MainWindow) + self.actionOpen.setObjectName("actionOpen") + self.menuFIle.addAction(self.actionOpen) + self.menuFIle.addAction(self.actionSave) + self.menuFIle.addAction(self.actionSaveAs) + self.menuFIle.addAction(self.actionExportAsymptote) + self.menuFIle.addSeparator() + self.menuFIle.addAction(self.actionQuit) + self.menuEdit.addAction(self.actionUndo) + self.menuEdit.addAction(self.actionRedo) + self.menuEdit.addSeparator() + self.menuOptions.addAction(self.actionSettings) + self.menuHelp.addAction(self.actionManual) + self.menuHelp.addAction(self.actionAbout) + self.menuTools.addAction(self.actionEnterCommand) + self.menubar.addAction(self.menuFIle.menuAction()) + self.menubar.addAction(self.menuEdit.menuAction()) + self.menubar.addAction(self.menuOptions.menuAction()) + self.menubar.addAction(self.menuTools.menuAction()) + self.menubar.addAction(self.menuHelp.menuAction()) + + self.retranslateUi(MainWindow) + self.comboAnchor.setCurrentIndex(0) + QtCore.QMetaObject.connectSlotsByName(MainWindow) + + def retranslateUi(self, MainWindow): + _translate = QtCore.QCoreApplication.translate + MainWindow.setWindowTitle(_translate("MainWindow", "xasy")) + self.btnUndo.setToolTip(_translate("MainWindow", "Undo")) + self.btnRedo.setToolTip(_translate("MainWindow", "Redo")) + self.btnLoadFile.setToolTip(_translate("MainWindow", "<html><head/><body><p>Open file</p></body></html>")) + self.btnSave.setToolTip(_translate("MainWindow", "<html><head/><body><p>Save file</p></body></html>")) + self.btnViewCode.setToolTip(_translate("MainWindow", "<html><head/><body><p>Edit code</p></body></html>")) + self.btnQuickScreenshot.setToolTip(_translate("MainWindow", "<html><head/><body><p>Screenshot</p></body></html>")) + self.btnDrawAxes.setToolTip(_translate("MainWindow", "<html><head/><body><p>Toggle display axes</p></body></html>")) + self.btnDrawGrid.setToolTip(_translate("MainWindow", "<html><head/><body><p>Toggle grid</p></body></html>")) + self.btnSetZoom.setToolTip(_translate("MainWindow", "Synchronize with Asymptote")) + self.btnPanCenter.setToolTip(_translate("MainWindow", "<html><head/><body><p>Center</p></body></html>")) + self.btnResetPan.setToolTip(_translate("MainWindow", "<html><head/><body><p>Center about origin</p></body></html>")) + self.btnAlignX.setToolTip(_translate("MainWindow", "<html><head/><body><p>Lock transform to X axis</p></body></html>")) + self.btnAlignX.setText(_translate("MainWindow", "X")) + self.btnAlignY.setToolTip(_translate("MainWindow", "<html><head/><body><p>Lock transform to Y axis</p></body></html>")) + self.btnAlignY.setText(_translate("MainWindow", "Y")) + self.btnSelectEdit.setToolTip(_translate("MainWindow", "<html><head/><body><p>Bézier editor</p></body></html>")) + self.btnDeleteMode.setToolTip(_translate("MainWindow", "<html><head/><body><p>Delete</p></body></html>")) + self.btnPan.setToolTip(_translate("MainWindow", "Pan")) + self.btnTranslate.setToolTip(_translate("MainWindow", "Translate")) + self.btnScale.setToolTip(_translate("MainWindow", "Scale")) + self.btnRotate.setToolTip(_translate("MainWindow", "Rotate")) + self.btnAnchor.setToolTip(_translate("MainWindow", "<html><head/><body><p>Set custom anchor</p></body></html>")) + self.comboAnchor.setToolTip(_translate("MainWindow", "<html><head/><body><p>Anchor</p></body></html>")) + self.comboAnchor.setCurrentText(_translate("MainWindow", "Origin")) + self.comboAnchor.setItemText(0, _translate("MainWindow", "Origin")) + self.comboAnchor.setItemText(1, _translate("MainWindow", "Center")) + self.comboAnchor.setItemText(2, _translate("MainWindow", "Top Left")) + self.comboAnchor.setItemText(3, _translate("MainWindow", "Top Right")) + self.comboAnchor.setItemText(4, _translate("MainWindow", "Bottom Right")) + self.comboAnchor.setItemText(5, _translate("MainWindow", "Bottom Left")) + self.comboAnchor.setItemText(6, _translate("MainWindow", "Custom")) + self.btnCustTransform.setToolTip(_translate("MainWindow", "<html><head/><body><p><br/></p></body></html>")) + self.btnSendBackwards.setToolTip(_translate("MainWindow", "<html><head/><body><p><br/></p></body></html>")) + self.btnSendForwards.setToolTip(_translate("MainWindow", "Translate")) + self.btnFill.setToolTip(_translate("MainWindow", "<html><head/><body><p>Toggle fill/outline</p></body></html>")) + self.label.setText(_translate("MainWindow", "Line Width:")) + self.txtLineWidth.setToolTip(_translate("MainWindow", "<html><head/><body><p>Current pen width</p></body></html>")) + self.frameCurrColor.setToolTip(_translate("MainWindow", "<html><head/><body><p>Current pen color</p></body></html>")) + self.btnSelectColor.setToolTip(_translate("MainWindow", "<html><head/><body><p>Set color</p></body></html>")) + self.btnOpenPoly.setToolTip(_translate("MainWindow", "<html><head/><body><p>Open polygon</p></body></html>")) + self.btnClosedPoly.setToolTip(_translate("MainWindow", "<html><head/><body><p>Closed polygon</p></body></html>")) + self.btnOpenCurve.setToolTip(_translate("MainWindow", "<html><head/><body><p>Open Bézier curve</p></body></html>")) + self.btnClosedCurve.setToolTip(_translate("MainWindow", "<html><head/><body><p>Closed Bézier curve</p></body></html>")) + 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.menuFIle.setTitle(_translate("MainWindow", "&File")) + self.menuEdit.setTitle(_translate("MainWindow", "&Edit")) + self.menuOptions.setTitle(_translate("MainWindow", "Optio&ns")) + self.menuHelp.setTitle(_translate("MainWindow", "&Help")) + self.menuTools.setTitle(_translate("MainWindow", "&Tools")) + self.actionAbout.setText(_translate("MainWindow", "&About")) + 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.actionEnterCommand.setText(_translate("MainWindow", "&Enter Command")) + self.actionQuit.setText(_translate("MainWindow", "&Quit")) + self.actionUndo.setText(_translate("MainWindow", "&Undo")) + self.actionRedo.setText(_translate("MainWindow", "&Redo")) + 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.actionSave.setText(_translate("MainWindow", "Save")) + self.actionOpen.setText(_translate("MainWindow", "Open")) + +import icons_rc diff --git a/graphics/asymptote/GUI/requirements.txt b/graphics/asymptote/GUI/requirements.txt new file mode 100644 index 0000000000..47966fe275 --- /dev/null +++ b/graphics/asymptote/GUI/requirements.txt @@ -0,0 +1,4 @@ +numpy==1.11.0 +cson==0.7 +PyQt5==5.11 +rsvg-convert==2.42.3 diff --git a/graphics/asymptote/GUI/res/icons.qrc b/graphics/asymptote/GUI/res/icons.qrc new file mode 100644 index 0000000000..50928ef9b7 --- /dev/null +++ b/graphics/asymptote/GUI/res/icons.qrc @@ -0,0 +1,45 @@ +<RCC> + <qresource prefix=""> + <file>icons/android-arrow-back.svg</file> + <file>icons/android-arrow-forward.svg</file> + <file>icons/android-folder-open.svg</file> + <file>icons/save.svg</file> + <file>icons/code.svg</file> + <file>icons/android-camera.svg</file> + <file>icons/plus-round.svg</file> + <file>icons/grid.svg</file> + <file>icons/magnifying-glass.svg</file> + <file>icons/center.svg</file> + <file>icons/centerorigin.svg</file> + <file>icons/edit.svg</file> + <file>icons/android-delete.svg</file> + <file>icons/android-hand.svg</file> + <file>icons/arrow-move.svg</file> + <file>icons/arrow-resize.svg</file> + <file>icons/android-refresh.svg</file> + <file>icons/anchor.svg</file> + <file>icons/eye.svg</file> + <file>icons/android-expand.svg</file> + <file>icons/chevron-with-circle-left.svg</file> + <file>icons/chevron-with-circle-right.svg</file> + <file>icons/bucket.svg</file> + <file>icons/filledbucket.svg</file> + <file>icons/android-color-palette.svg</file> + <file>icons/openpolygon.svg</file> + <file>icons/closedpolygon.svg</file> + <file>icons/opencurve.svg</file> + <file>icons/closedcurve.svg</file> + <file>icons/triangle-stroked-15.svg</file> + <file>icons/circle.svg</file> + <file>icons/text.svg</file> + <file>icons/social-python.svg</file> + <file>icons/subdirectory-left.svg</file> + <file>icons/android-done.svg</file> + <file>icons/android-close.svg</file> + <file>icons/check.svg</file> + <file>icons/android-radio-button-on.svg</file> + <file>icons/android-radio-button-off.svg</file> + <file>icons/android-locate.svg</file> + <file>icons/close-round.svg</file> + </qresource> +</RCC> diff --git a/graphics/asymptote/GUI/res/icons/anchor.svg b/graphics/asymptote/GUI/res/icons/anchor.svg new file mode 100644 index 0000000000..886aadebf9 --- /dev/null +++ b/graphics/asymptote/GUI/res/icons/anchor.svg @@ -0,0 +1 @@ +<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"><path d="M4.34 15.66A7.97 7.97 0 0 0 9 17.94V10H5V8h4V5.83a3 3 0 1 1 2 0V8h4v2h-4v7.94a7.97 7.97 0 0 0 4.66-2.28l-1.42-1.42h5.66l-2.83 2.83a10 10 0 0 1-14.14 0L.1 14.24h5.66l-1.42 1.42zM10 4a1 1 0 1 0 0-2 1 1 0 0 0 0 2z"/></svg>
\ No newline at end of file diff --git a/graphics/asymptote/GUI/res/icons/android-arrow-back.svg b/graphics/asymptote/GUI/res/icons/android-arrow-back.svg new file mode 100644 index 0000000000..79cfe814a1 --- /dev/null +++ b/graphics/asymptote/GUI/res/icons/android-arrow-back.svg @@ -0,0 +1,11 @@ +<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 16.2.1, 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 id="Icon_8_">
+ <g>
+ <path d="M427,234.625H167.296l119.702-119.702L256,85L85,256l171,171l29.922-29.924L167.296,277.375H427V234.625z"/>
+ </g>
+</g>
+</svg>
diff --git a/graphics/asymptote/GUI/res/icons/android-arrow-forward.svg b/graphics/asymptote/GUI/res/icons/android-arrow-forward.svg new file mode 100644 index 0000000000..d63794dcc0 --- /dev/null +++ b/graphics/asymptote/GUI/res/icons/android-arrow-forward.svg @@ -0,0 +1,11 @@ +<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 16.2.1, 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 id="Icon_8_">
+ <g>
+ <path d="M85,277.375h259.704L225.002,397.077L256,427l171-171L256,85l-29.922,29.924l118.626,119.701H85V277.375z"/>
+ </g>
+</g>
+</svg>
diff --git a/graphics/asymptote/GUI/res/icons/android-camera.svg b/graphics/asymptote/GUI/res/icons/android-camera.svg new file mode 100644 index 0000000000..73aeaabe49 --- /dev/null +++ b/graphics/asymptote/GUI/res/icons/android-camera.svg @@ -0,0 +1,12 @@ +<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 16.2.1, 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>
+ <circle cx="256" cy="280" r="63"/>
+ <path d="M440,96h-88l-32-32H192l-32,32H72c-22.092,0-40,17.908-40,40v272c0,22.092,17.908,40,40,40h368c22.092,0,40-17.908,40-40
+ V136C480,113.908,462.092,96,440,96z M256,392c-61.855,0-112-50.145-112-112s50.145-112,112-112s112,50.145,112,112
+ S317.855,392,256,392z"/>
+</g>
+</svg>
diff --git a/graphics/asymptote/GUI/res/icons/android-close.svg b/graphics/asymptote/GUI/res/icons/android-close.svg new file mode 100644 index 0000000000..aee0f9f630 --- /dev/null +++ b/graphics/asymptote/GUI/res/icons/android-close.svg @@ -0,0 +1,12 @@ +<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 16.2.1, 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 id="Icon_5_">
+ <g>
+ <polygon points="405,136.798 375.202,107 256,226.202 136.798,107 107,136.798 226.202,256 107,375.202 136.798,405 256,285.798
+ 375.202,405 405,375.202 285.798,256 "/>
+ </g>
+</g>
+</svg>
diff --git a/graphics/asymptote/GUI/res/icons/android-color-palette.svg b/graphics/asymptote/GUI/res/icons/android-color-palette.svg new file mode 100644 index 0000000000..d700fe6b9d --- /dev/null +++ b/graphics/asymptote/GUI/res/icons/android-color-palette.svg @@ -0,0 +1,17 @@ +<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 16.2.1, 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 id="Icon_12_">
+ <g>
+ <path d="M256,64C150.401,64,64,150.401,64,256c0,105.604,86.401,192,192,192c18.136,0,32-13.864,32-32
+ c0-8.531-3.198-16-8.531-21.333c-5.333-5.334-8.531-12.803-8.531-21.334c0-18.135,13.864-32,32-32h38.396
+ c58.667,0,106.667-48,106.667-106.666C448,140.802,361.604,64,256,64z M138.667,256c-18.136,0-32-13.864-32-32s13.864-32,32-32
+ c18.135,0,32,13.864,32,32S156.802,256,138.667,256z M202.667,170.667c-18.136,0-32-13.865-32-32c0-18.136,13.864-32,32-32
+ c18.135,0,32,13.864,32,32C234.667,156.802,220.802,170.667,202.667,170.667z M309.333,170.667c-18.135,0-32-13.865-32-32
+ c0-18.136,13.865-32,32-32c18.136,0,32,13.864,32,32C341.333,156.802,327.469,170.667,309.333,170.667z M373.333,256
+ c-18.135,0-32-13.864-32-32s13.865-32,32-32c18.136,0,32,13.864,32,32S391.469,256,373.333,256z"/>
+ </g>
+</g>
+</svg>
diff --git a/graphics/asymptote/GUI/res/icons/android-delete.svg b/graphics/asymptote/GUI/res/icons/android-delete.svg new file mode 100644 index 0000000000..49cfa5ade4 --- /dev/null +++ b/graphics/asymptote/GUI/res/icons/android-delete.svg @@ -0,0 +1,10 @@ +<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 16.2.1, 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="M128,405.429C128,428.846,147.198,448,170.667,448h170.667C364.802,448,384,428.846,384,405.429V160H128V405.429z M416,96
+ h-80l-26.785-32H202.786L176,96H96v32h320V96z"/>
+</g>
+</svg>
diff --git a/graphics/asymptote/GUI/res/icons/android-done.svg b/graphics/asymptote/GUI/res/icons/android-done.svg new file mode 100644 index 0000000000..4bcb946f05 --- /dev/null +++ b/graphics/asymptote/GUI/res/icons/android-done.svg @@ -0,0 +1,13 @@ +<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 16.2.1, 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 id="Icon_1_">
+ <g>
+ <g>
+ <polygon points="186.301,339.893 96,249.461 64,279.968 186.301,402 448,140.506 416,110 "/>
+ </g>
+ </g>
+</g>
+</svg>
diff --git a/graphics/asymptote/GUI/res/icons/android-expand.svg b/graphics/asymptote/GUI/res/icons/android-expand.svg new file mode 100644 index 0000000000..51be003c07 --- /dev/null +++ b/graphics/asymptote/GUI/res/icons/android-expand.svg @@ -0,0 +1,12 @@ +<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 16.2.1, 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>
+ <polygon points="396.795,396.8 320,396.8 320,448 448,448 448,320 396.795,320 "/>
+ <polygon points="396.8,115.205 396.8,192 448,192 448,64 320,64 320,115.205 "/>
+ <polygon points="115.205,115.2 192,115.2 192,64 64,64 64,192 115.205,192 "/>
+ <polygon points="115.2,396.795 115.2,320 64,320 64,448 192,448 192,396.795 "/>
+</g>
+</svg>
diff --git a/graphics/asymptote/GUI/res/icons/android-folder-open.svg b/graphics/asymptote/GUI/res/icons/android-folder-open.svg new file mode 100644 index 0000000000..fa77fea215 --- /dev/null +++ b/graphics/asymptote/GUI/res/icons/android-folder-open.svg @@ -0,0 +1,10 @@ +<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 16.2.1, 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">
+<path d="M437.334,144H256.006l-42.668-48H74.666C51.197,96,32,115.198,32,138.667v234.666C32,396.802,51.197,416,74.666,416h362.668
+ C460.803,416,480,396.802,480,373.333V186.667C480,163.198,460.803,144,437.334,144z M448,373.333
+ c0,5.782-4.885,10.667-10.666,10.667H74.666C68.884,384,64,379.115,64,373.333V176h373.334c5.781,0,10.666,4.885,10.666,10.667
+ V373.333z"/>
+</svg>
diff --git a/graphics/asymptote/GUI/res/icons/android-hand.svg b/graphics/asymptote/GUI/res/icons/android-hand.svg new file mode 100644 index 0000000000..5035d875be --- /dev/null +++ b/graphics/asymptote/GUI/res/icons/android-hand.svg @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 16.2.1, 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">
+<path d="M450.679,273.5c-14.585-14.577-36.054-15.89-50.639-1.312l-41.687,41.664c-10.852,10.836-23.93,10.859-31.564,1.852
+ c-5.057-5.968-3.061-24.374-1.644-36.049l20.907-171.849c1.867-15.353-9.07-30.185-24.43-32.051
+ c-15.358-1.867-29.322,9.939-31.191,25.289L267.37,236.021c-1.205,3.358-3.79,3.938-4.081-0.582L255.44,60
+ c0-15.465-12.542-28-28.014-28c-15.473,0-28.015,12.535-28.015,28l-0.552,176.752c0.146,2.04-1.604,2.624-1.92,0.294L172.016,99.077
+ c-2.75-15.219-17.323-26.203-32.548-23.453c-15.227,2.748-25.339,18.187-22.591,33.403l22.193,161.455
+ c0.023,2.872-0.941,4.513-2.308,0.831l-33.109-88.517c-5.18-14.572-21.196-23.065-35.776-17.889
+ c-14.579,5.177-22.201,22.061-17.023,36.631l58.042,189.625c0.303,1.046,0.624,2.085,0.953,3.118l0.121,0.39
+ c0.011,0.031,0.025,0.058,0.035,0.088C126.079,444.233,172.57,480,227.427,480c35.116,0,71.591-12.378,99.357-33.672
+ c0.001,0,0.003-0.002,0.003-0.002c29.99-18.051,126.071-121.347,126.071-121.347C467.445,310.402,465.266,288.08,450.679,273.5z"/>
+</svg>
diff --git a/graphics/asymptote/GUI/res/icons/android-locate.svg b/graphics/asymptote/GUI/res/icons/android-locate.svg new file mode 100644 index 0000000000..e2dd098cbd --- /dev/null +++ b/graphics/asymptote/GUI/res/icons/android-locate.svg @@ -0,0 +1,16 @@ +<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 16.2.1, 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 id="Icon">
+ <g>
+ <path d="M256,176c-44.004,0-80.001,36-80.001,80c0,44.004,35.997,80,80.001,80c44.005,0,79.999-35.996,79.999-80
+ C335.999,212,300.005,176,256,176z M446.938,234.667c-9.605-88.531-81.074-160-169.605-169.599V32h-42.666v33.067
+ c-88.531,9.599-160,81.068-169.604,169.599H32v42.667h33.062c9.604,88.531,81.072,160,169.604,169.604V480h42.666v-33.062
+ c88.531-9.604,160-81.073,169.605-169.604H480v-42.667H446.938z M256,405.333c-82.137,0-149.334-67.198-149.334-149.333
+ c0-82.136,67.197-149.333,149.334-149.333c82.135,0,149.332,67.198,149.332,149.333C405.332,338.135,338.135,405.333,256,405.333z
+ "/>
+ </g>
+</g>
+</svg>
diff --git a/graphics/asymptote/GUI/res/icons/android-radio-button-off.svg b/graphics/asymptote/GUI/res/icons/android-radio-button-off.svg new file mode 100644 index 0000000000..d36fa657c0 --- /dev/null +++ b/graphics/asymptote/GUI/res/icons/android-radio-button-off.svg @@ -0,0 +1,12 @@ +<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 16.2.1, 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 id="Icon_20_">
+ <g>
+ <path d="M256,48C141.601,48,48,141.601,48,256s93.601,208,208,208s208-93.601,208-208S370.399,48,256,48z M256,422.399
+ c-91.518,0-166.399-74.882-166.399-166.399S164.482,89.6,256,89.6S422.4,164.482,422.4,256S347.518,422.399,256,422.399z"/>
+ </g>
+</g>
+</svg>
diff --git a/graphics/asymptote/GUI/res/icons/android-radio-button-on.svg b/graphics/asymptote/GUI/res/icons/android-radio-button-on.svg new file mode 100644 index 0000000000..1f7f54c0f2 --- /dev/null +++ b/graphics/asymptote/GUI/res/icons/android-radio-button-on.svg @@ -0,0 +1,13 @@ +<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 16.2.1, 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 id="Icon_21_">
+ <g>
+ <path d="M256,152c-57.2,0-104,46.8-104,104s46.8,104,104,104s104-46.8,104-104S313.2,152,256,152z M256,48
+ C141.601,48,48,141.601,48,256s93.601,208,208,208s208-93.601,208-208S370.399,48,256,48z M256,422.4
+ c-91.518,0-166.4-74.883-166.4-166.4S164.482,89.6,256,89.6S422.4,164.482,422.4,256S347.518,422.4,256,422.4z"/>
+ </g>
+</g>
+</svg>
diff --git a/graphics/asymptote/GUI/res/icons/android-refresh.svg b/graphics/asymptote/GUI/res/icons/android-refresh.svg new file mode 100644 index 0000000000..066f7d22c6 --- /dev/null +++ b/graphics/asymptote/GUI/res/icons/android-refresh.svg @@ -0,0 +1,11 @@ +<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 16.2.1, 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="M256,388c-72.597,0-132-59.405-132-132c0-72.601,59.403-132,132-132c36.3,0,69.299,15.4,92.406,39.601L278,234h154V80
+ l-51.698,51.702C348.406,99.798,304.406,80,256,80c-96.797,0-176,79.203-176,176s78.094,176,176,176
+ c81.045,0,148.287-54.134,169.401-128H378.85C360.105,353.561,311.712,388,256,388z"/>
+</g>
+</svg>
diff --git a/graphics/asymptote/GUI/res/icons/arrow-move.svg b/graphics/asymptote/GUI/res/icons/arrow-move.svg new file mode 100644 index 0000000000..1d4263f45a --- /dev/null +++ b/graphics/asymptote/GUI/res/icons/arrow-move.svg @@ -0,0 +1,8 @@ +<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 16.2.1, 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" style="enable-background:new 0 0 512 512;" xml:space="preserve">
+<polygon points="480,256 384,160 384,236 276,236 276,128 352,128 256,32 160,128 236,128 236,236 128,236 128,160 32,256 128,352
+ 128,276 236,276 236,384 160,384 256,480 352,384 275.8,384 275.4,275.5 384,275.8 384,352 "/>
+</svg>
diff --git a/graphics/asymptote/GUI/res/icons/arrow-resize.svg b/graphics/asymptote/GUI/res/icons/arrow-resize.svg new file mode 100644 index 0000000000..a9c3b3cc14 --- /dev/null +++ b/graphics/asymptote/GUI/res/icons/arrow-resize.svg @@ -0,0 +1,8 @@ +<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 16.2.1, 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" style="enable-background:new 0 0 512 512;" xml:space="preserve">
+<polygon points="288,96 337.9,145.9 274,209.7 274,209.7 145.9,337.9 96,288 96,416 224,416 174.1,366.1 357.4,182.9 366.1,174.1
+ 416,224 416,96 "/>
+</svg>
diff --git a/graphics/asymptote/GUI/res/icons/bucket.asy b/graphics/asymptote/GUI/res/icons/bucket.asy new file mode 100644 index 0000000000..e6468b3f06 --- /dev/null +++ b/graphics/asymptote/GUI/res/icons/bucket.asy @@ -0,0 +1,28 @@ +// Empty bucket: asy bucket -f svg +// Filled bucket: asy bucket -f svg -u fill=true -o filledbucket + +real pixel=1inch/96; +size(32*pixel); +defaultpen(1.75bp); + +real h=4; +real r=3; +path left=(-r,h)--(-r,0); +path right=(r,0)--(r,h); +path bottom=xscale(r)*arc(0,1,180,360); + +real H=0.9h; +path Left=(-r,H/2)--(-r,0); +path Right=(r,0)--(r,H/2); + +bool fill=false; // Set to true for filled bucket. +usersetting(); + +if(fill) + fill(Left--bottom--Right--shift(0,H)*xscale(r)*arc(0,1,0,180)--cycle,gray); + + +draw(shift(0,h)*xscale(r)*unitcircle); +draw(left--bottom--right); +draw(shift(0,h)*scale(r)*arc(0,1,0,180)); + diff --git a/graphics/asymptote/GUI/res/icons/bucket.svg b/graphics/asymptote/GUI/res/icons/bucket.svg new file mode 100644 index 0000000000..8898aba609 --- /dev/null +++ b/graphics/asymptote/GUI/res/icons/bucket.svg @@ -0,0 +1,14 @@ +<?xml version='1.0' encoding='UTF-8'?> +<!-- This file was generated by dvisvgm 2.4 --> +<svg height='24pt' version='1.1' viewBox='56.4094 53.8583 18.4375 24' width='18.4375pt' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink'> +<g id='page1'> +<g transform='matrix(0.996264 0 0 0.996264 65.6282 74.202)'> +<path d='M 8.37504 -11.1667C 8.37504 -12.7085 4.62541 -13.9584 0 -13.9584C -4.62541 -13.9584 -8.37504 -12.7085 -8.37504 -11.1667C -8.37504 -9.62492 -4.62541 -8.37504 0 -8.37504C 4.62541 -8.37504 8.37504 -9.62492 8.37504 -11.1667Z' fill='none' stroke='#000000' stroke-linecap='round' stroke-linejoin='round' stroke-miterlimit='10.0375' stroke-width='1.75656'/> +</g> +<g transform='matrix(0.996264 0 0 0.996264 65.6282 74.202)'> +<path d='M -8.37504 -11.1667L -8.37504 -0L -8.37504 -1.85963e-15C -8.37504 -1.23975e-15 -8.37504 -6.19877e-16 -8.37504 -0C -8.37504 1.5418 -4.62541 2.79168 0 2.79168C 4.62541 2.79168 8.37504 1.5418 8.37504 0L 8.37504 0L 8.37504 -11.1667' fill='none' stroke='#000000' stroke-linecap='round' stroke-linejoin='round' stroke-miterlimit='10.0375' stroke-width='1.75656'/> +</g> +<g transform='matrix(0.996264 0 0 0.996264 65.6282 74.202)'> +<path d='M 8.37504 -11.1667C 8.37504 -15.7921 4.62541 -19.5418 0 -19.5418C -4.62541 -19.5418 -8.37504 -15.7921 -8.37504 -11.1667' fill='none' stroke='#000000' stroke-linecap='round' stroke-linejoin='round' stroke-miterlimit='10.0375' stroke-width='1.75656'/> +</g></g> +</svg>
\ No newline at end of file diff --git a/graphics/asymptote/GUI/res/icons/center.asy b/graphics/asymptote/GUI/res/icons/center.asy new file mode 100644 index 0000000000..8db11ef08a --- /dev/null +++ b/graphics/asymptote/GUI/res/icons/center.asy @@ -0,0 +1,9 @@ +// Empty bucket: asy bucket -f svg +// Filled bucket: asy bucket -f svg -u fill=true -o filledbucket + +real pixel=1inch/96; +size(25*pixel); +defaultpen(1.5bp); + +draw(scale(2)*shift(-0.5,-0.5)*unitsquare); +fill(scale(0.5)*unitcircle); diff --git a/graphics/asymptote/GUI/res/icons/center.svg b/graphics/asymptote/GUI/res/icons/center.svg new file mode 100644 index 0000000000..15b77f5a64 --- /dev/null +++ b/graphics/asymptote/GUI/res/icons/center.svg @@ -0,0 +1,11 @@ +<?xml version='1.0' encoding='UTF-8'?> +<!-- This file was generated by dvisvgm 2.4 --> +<svg height='18.75pt' version='1.1' viewBox='56.4094 53.8583 18.75 18.75' width='18.75pt' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink'> +<g id='page1'> +<g transform='matrix(0.996264 0 0 0.996264 65.7844 63.2333)'> +<path d='M -8.65734 8.65734L 8.65734 8.65734L 8.65734 -8.65734L -8.65734 -8.65734L -8.65734 8.65734Z' fill='none' stroke='#000000' stroke-linecap='round' stroke-linejoin='round' stroke-miterlimit='10.0375' stroke-width='1.50562'/> +</g> +<g transform='matrix(0.996264 0 0 0.996264 65.7844 63.2333)'> +<path d='M 4.32867 0C 4.32867 -2.39066 2.39066 -4.32867 0 -4.32867C -2.39066 -4.32867 -4.32867 -2.39066 -4.32867 -0C -4.32867 2.39066 -2.39066 4.32867 0 4.32867C 2.39066 4.32867 4.32867 2.39066 4.32867 0Z' fill='#000000'/> +</g></g> +</svg>
\ No newline at end of file diff --git a/graphics/asymptote/GUI/res/icons/centerorigin.asy b/graphics/asymptote/GUI/res/icons/centerorigin.asy new file mode 100644 index 0000000000..b1df599d38 --- /dev/null +++ b/graphics/asymptote/GUI/res/icons/centerorigin.asy @@ -0,0 +1,7 @@ +real pixel=1inch/96; +size(25*pixel); +defaultpen(1.5bp); + +draw(scale(2)*shift(-0.5,-0.5)*unitsquare); +draw((-1,0)--(1,0)); +draw((0,-1)--(0,1)); diff --git a/graphics/asymptote/GUI/res/icons/centerorigin.svg b/graphics/asymptote/GUI/res/icons/centerorigin.svg new file mode 100644 index 0000000000..253ba7789f --- /dev/null +++ b/graphics/asymptote/GUI/res/icons/centerorigin.svg @@ -0,0 +1,14 @@ +<?xml version='1.0' encoding='UTF-8'?> +<!-- This file was generated by dvisvgm 2.4 --> +<svg height='18.75pt' version='1.1' viewBox='56.4094 53.8583 18.75 18.75' width='18.75pt' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink'> +<g id='page1'> +<g transform='matrix(0.996264 0 0 0.996264 65.7844 63.2333)'> +<path d='M -8.65734 8.65734L 8.65734 8.65734L 8.65734 -8.65734L -8.65734 -8.65734L -8.65734 8.65734Z' fill='none' stroke='#000000' stroke-linecap='round' stroke-linejoin='round' stroke-miterlimit='10.0375' stroke-width='1.50562'/> +</g> +<g transform='matrix(0.996264 0 0 0.996264 65.7844 63.2333)'> +<path d='M -8.65734 -0L 8.65734 0' fill='none' stroke='#000000' stroke-linecap='round' stroke-linejoin='round' stroke-miterlimit='10.0375' stroke-width='1.50562'/> +</g> +<g transform='matrix(0.996264 0 0 0.996264 65.7844 63.2333)'> +<path d='M 0 8.65734L 0 -8.65734' fill='none' stroke='#000000' stroke-linecap='round' stroke-linejoin='round' stroke-miterlimit='10.0375' stroke-width='1.50562'/> +</g></g> +</svg>
\ No newline at end of file diff --git a/graphics/asymptote/GUI/res/icons/check.svg b/graphics/asymptote/GUI/res/icons/check.svg new file mode 100644 index 0000000000..08ee56d87d --- /dev/null +++ b/graphics/asymptote/GUI/res/icons/check.svg @@ -0,0 +1,9 @@ +<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 18.1.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="Check" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+ viewBox="0 0 20 20" enable-background="new 0 0 20 20" xml:space="preserve">
+<path d="M8.294,16.998c-0.435,0-0.847-0.203-1.111-0.553L3.61,11.724c-0.465-0.613-0.344-1.486,0.27-1.951
+ c0.615-0.467,1.488-0.344,1.953,0.27l2.351,3.104l5.911-9.492c0.407-0.652,1.267-0.852,1.921-0.445
+ c0.653,0.406,0.854,1.266,0.446,1.92L9.478,16.34c-0.242,0.391-0.661,0.635-1.12,0.656C8.336,16.998,8.316,16.998,8.294,16.998z"/>
+</svg>
diff --git a/graphics/asymptote/GUI/res/icons/chevron-with-circle-left.svg b/graphics/asymptote/GUI/res/icons/chevron-with-circle-left.svg new file mode 100644 index 0000000000..57d5c5b257 --- /dev/null +++ b/graphics/asymptote/GUI/res/icons/chevron-with-circle-left.svg @@ -0,0 +1,11 @@ +<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 18.1.1, 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="Chevron_circled_left" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
+ x="0px" y="0px" viewBox="0 0 20 20" enable-background="new 0 0 20 20" xml:space="preserve">
+<path d="M11.302,6.776c-0.196-0.197-0.515-0.197-0.71,0L7.785,9.641c-0.196,0.199-0.196,0.52,0,0.717l2.807,2.864
+ c0.195,0.199,0.514,0.198,0.71,0c0.196-0.197,0.196-0.518,0-0.717L9,10l2.302-2.506C11.498,7.296,11.498,6.976,11.302,6.776z
+ M10,0.4c-5.302,0-9.6,4.298-9.6,9.6c0,5.303,4.298,9.6,9.6,9.6s9.6-4.297,9.6-9.6C19.6,4.698,15.302,0.4,10,0.4z M10,18.354
+ c-4.615,0-8.354-3.74-8.354-8.354c0-4.614,3.739-8.354,8.354-8.354c4.613,0,8.354,3.74,8.354,8.354
+ C18.354,14.614,14.613,18.354,10,18.354z"/>
+</svg>
diff --git a/graphics/asymptote/GUI/res/icons/chevron-with-circle-right.svg b/graphics/asymptote/GUI/res/icons/chevron-with-circle-right.svg new file mode 100644 index 0000000000..a48f0376a0 --- /dev/null +++ b/graphics/asymptote/GUI/res/icons/chevron-with-circle-right.svg @@ -0,0 +1,11 @@ +<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 18.1.1, 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="Chevron_circled_right" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
+ x="0px" y="0px" viewBox="0 0 20 20" enable-background="new 0 0 20 20" xml:space="preserve">
+<path d="M11,10L8.698,7.494c-0.196-0.198-0.196-0.519,0-0.718c0.196-0.197,0.515-0.197,0.71,0l2.807,2.864
+ c0.196,0.199,0.196,0.52,0,0.717l-2.807,2.864c-0.195,0.199-0.514,0.198-0.71,0c-0.196-0.197-0.196-0.518,0-0.717L11,10z M10,0.4
+ c5.302,0,9.6,4.298,9.6,9.6c0,5.303-4.298,9.6-9.6,9.6S0.4,15.303,0.4,10C0.4,4.698,4.698,0.4,10,0.4z M10,18.354
+ c4.613,0,8.354-3.74,8.354-8.354c0-4.614-3.741-8.354-8.354-8.354c-4.615,0-8.354,3.74-8.354,8.354
+ C1.645,14.614,5.385,18.354,10,18.354z"/>
+</svg>
diff --git a/graphics/asymptote/GUI/res/icons/circle.svg b/graphics/asymptote/GUI/res/icons/circle.svg new file mode 100644 index 0000000000..b841c238db --- /dev/null +++ b/graphics/asymptote/GUI/res/icons/circle.svg @@ -0,0 +1,9 @@ +<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 18.1.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="Circle" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+ viewBox="0 0 20 20" enable-background="new 0 0 20 20" xml:space="preserve">
+<path d="M10,0.4C4.698,0.4,0.4,4.698,0.4,10C0.4,15.302,4.698,19.6,10,19.6c5.301,0,9.6-4.298,9.6-9.601
+ C19.6,4.698,15.301,0.4,10,0.4z M10,17.599c-4.197,0-7.6-3.402-7.6-7.6S5.802,2.4,10,2.4c4.197,0,7.601,3.402,7.601,7.6
+ S14.197,17.599,10,17.599z"/>
+</svg>
diff --git a/graphics/asymptote/GUI/res/icons/close-round.svg b/graphics/asymptote/GUI/res/icons/close-round.svg new file mode 100644 index 0000000000..d8b5554c5c --- /dev/null +++ b/graphics/asymptote/GUI/res/icons/close-round.svg @@ -0,0 +1,9 @@ +<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 16.2.1, 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" style="enable-background:new 0 0 512 512;" xml:space="preserve">
+<path d="M437.5,386.6L306.9,256l130.6-130.6c14.1-14.1,14.1-36.8,0-50.9c-14.1-14.1-36.8-14.1-50.9,0L256,205.1L125.4,74.5
+ c-14.1-14.1-36.8-14.1-50.9,0c-14.1,14.1-14.1,36.8,0,50.9L205.1,256L74.5,386.6c-14.1,14.1-14.1,36.8,0,50.9
+ c14.1,14.1,36.8,14.1,50.9,0L256,306.9l130.6,130.6c14.1,14.1,36.8,14.1,50.9,0C451.5,423.4,451.5,400.6,437.5,386.6z"/>
+</svg>
diff --git a/graphics/asymptote/GUI/res/icons/closedcurve.asy b/graphics/asymptote/GUI/res/icons/closedcurve.asy new file mode 100644 index 0000000000..6406807998 --- /dev/null +++ b/graphics/asymptote/GUI/res/icons/closedcurve.asy @@ -0,0 +1,7 @@ +real pixel=1inch/96; +size(32*pixel,IgnoreAspect); +defaultpen(1.75bp); + +path p=W..NW..ENE..0.5*SE..cycle; +draw(p); +dot(p,linewidth(8pixel)); diff --git a/graphics/asymptote/GUI/res/icons/closedcurve.svg b/graphics/asymptote/GUI/res/icons/closedcurve.svg new file mode 100644 index 0000000000..946ef84df7 --- /dev/null +++ b/graphics/asymptote/GUI/res/icons/closedcurve.svg @@ -0,0 +1,20 @@ +<?xml version='1.0' encoding='UTF-8'?> +<!-- This file was generated by dvisvgm 2.4 --> +<svg height='24pt' version='1.1' viewBox='56.4094 53.8583 24 24' width='24pt' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink'> +<g id='page1'> +<g transform='matrix(0.996264 0 0 0.996264 68.7655 69.7688)'> +<path d='M -9.39118 -0C -9.96861 -3.83004 -8.55706 -7.51944 -6.64057 -10.2171C -0.491089 -18.8733 8.35676 -15.1906 8.67632 -5.52948C 8.836 -0.702008 6.23968 2.94207 3.32028 5.10857C -1.96891 9.03371 -8.26895 7.4437 -9.39118 -0Z' fill='none' stroke='#000000' stroke-linecap='round' stroke-linejoin='round' stroke-miterlimit='10.0375' stroke-width='1.75656'/> +</g> +<g transform='matrix(0.996264 0 0 0.996264 68.7655 69.7688)'> +<circle cx='-9.39118' cy='-0' r='3.01125' fill='#000000'/> +</g> +<g transform='matrix(0.996264 0 0 0.996264 68.7655 69.7688)'> +<circle cx='-6.64057' cy='-10.2171' r='3.01125' fill='#000000'/> +</g> +<g transform='matrix(0.996264 0 0 0.996264 68.7655 69.7688)'> +<circle cx='8.67632' cy='-5.52948' r='3.01125' fill='#000000'/> +</g> +<g transform='matrix(0.996264 0 0 0.996264 68.7655 69.7688)'> +<circle cx='3.32028' cy='5.10857' r='3.01125' fill='#000000'/> +</g></g> +</svg>
\ No newline at end of file diff --git a/graphics/asymptote/GUI/res/icons/closedpolygon.asy b/graphics/asymptote/GUI/res/icons/closedpolygon.asy new file mode 100644 index 0000000000..9e4719a36b --- /dev/null +++ b/graphics/asymptote/GUI/res/icons/closedpolygon.asy @@ -0,0 +1,7 @@ +real pixel=1inch/96; +size(32*pixel,IgnoreAspect); +defaultpen(1.75bp); + +path p=W--NW--ENE--0.5*SE--cycle; +draw(p); +dot(p,linewidth(8pixel)); diff --git a/graphics/asymptote/GUI/res/icons/closedpolygon.svg b/graphics/asymptote/GUI/res/icons/closedpolygon.svg new file mode 100644 index 0000000000..432195d706 --- /dev/null +++ b/graphics/asymptote/GUI/res/icons/closedpolygon.svg @@ -0,0 +1,20 @@ +<?xml version='1.0' encoding='UTF-8'?> +<!-- This file was generated by dvisvgm 2.4 --> +<svg height='24pt' version='1.1' viewBox='56.4094 53.8583 24 24' width='24pt' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink'> +<g id='page1'> +<g transform='matrix(0.996264 0 0 0.996264 68.7655 68.8583)'> +<path d='M -9.39118 -0L -6.64057 -12.045L 8.67632 -6.51871L 3.32028 6.0225L -9.39118 -0Z' fill='none' stroke='#000000' stroke-linecap='round' stroke-linejoin='round' stroke-miterlimit='10.0375' stroke-width='1.75656'/> +</g> +<g transform='matrix(0.996264 0 0 0.996264 68.7655 68.8583)'> +<circle cx='-9.39118' cy='-0' r='3.01125' fill='#000000'/> +</g> +<g transform='matrix(0.996264 0 0 0.996264 68.7655 68.8583)'> +<circle cx='-6.64057' cy='-12.045' r='3.01125' fill='#000000'/> +</g> +<g transform='matrix(0.996264 0 0 0.996264 68.7655 68.8583)'> +<circle cx='8.67632' cy='-6.51871' r='3.01125' fill='#000000'/> +</g> +<g transform='matrix(0.996264 0 0 0.996264 68.7655 68.8583)'> +<circle cx='3.32028' cy='6.0225' r='3.01125' fill='#000000'/> +</g></g> +</svg>
\ No newline at end of file diff --git a/graphics/asymptote/GUI/res/icons/code.svg b/graphics/asymptote/GUI/res/icons/code.svg new file mode 100644 index 0000000000..33a99fd5d7 --- /dev/null +++ b/graphics/asymptote/GUI/res/icons/code.svg @@ -0,0 +1,13 @@ +<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 18.1.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="Code" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+ viewBox="0 0 20 20" enable-background="new 0 0 20 20" xml:space="preserve">
+<path d="M5.719,14.75c-0.236,0-0.474-0.083-0.664-0.252L-0.005,10l5.341-4.748C5.748,4.887,6.38,4.922,6.747,5.335
+ c0.367,0.413,0.33,1.045-0.083,1.412L3.005,10l3.378,3.002c0.413,0.367,0.45,0.999,0.083,1.412
+ C6.269,14.637,5.994,14.75,5.719,14.75z M14.664,14.748L20.005,10l-5.06-4.498c-0.413-0.367-1.045-0.33-1.411,0.083
+ c-0.367,0.413-0.33,1.045,0.083,1.412L16.995,10l-3.659,3.252c-0.413,0.367-0.45,0.999-0.083,1.412C13.45,14.887,13.725,15,14,15
+ C14.236,15,14.474,14.917,14.664,14.748z M9.986,16.165l2-12c0.091-0.545-0.277-1.06-0.822-1.151
+ c-0.547-0.092-1.061,0.277-1.15,0.822l-2,12c-0.091,0.545,0.277,1.06,0.822,1.151C8.892,16.996,8.946,17,9.001,17
+ C9.481,17,9.905,16.653,9.986,16.165z"/>
+</svg>
diff --git a/graphics/asymptote/GUI/res/icons/edit.svg b/graphics/asymptote/GUI/res/icons/edit.svg new file mode 100644 index 0000000000..a0be3454e1 --- /dev/null +++ b/graphics/asymptote/GUI/res/icons/edit.svg @@ -0,0 +1,13 @@ +<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 16.2.1, 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>
+
+ <rect x="178.846" y="92.087" transform="matrix(-0.7071 -0.7071 0.7071 -0.7071 224.3476 631.1498)" width="128.085" height="354.049"/>
+ <path d="M471.723,88.393l-48.115-48.114c-11.723-11.724-31.558-10.896-44.304,1.85l-45.202,45.203l90.569,90.568l45.202-45.202
+ C482.616,119.952,483.445,100.116,471.723,88.393z"/>
+ <polygon points="64.021,363.252 32,480 148.737,447.979 "/>
+</g>
+</svg>
diff --git a/graphics/asymptote/GUI/res/icons/eye.svg b/graphics/asymptote/GUI/res/icons/eye.svg new file mode 100644 index 0000000000..6b64633fce --- /dev/null +++ b/graphics/asymptote/GUI/res/icons/eye.svg @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 16.2.1, 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" style="enable-background:new 0 0 512 512;" xml:space="preserve">
+<g>
+ <path d="M256,128c-81.9,0-145.7,48.8-224,128c67.4,67.7,124,128,224,128c99.9,0,173.4-76.4,224-126.6
+ C428.2,198.6,354.8,128,256,128z M256,347.3c-49.4,0-89.6-41-89.6-91.3c0-50.4,40.2-91.3,89.6-91.3s89.6,41,89.6,91.3
+ C345.6,306.4,305.4,347.3,256,347.3z"/>
+ <g>
+ <path d="M256,224c0-7.9,2.9-15.1,7.6-20.7c-2.5-0.4-5-0.6-7.6-0.6c-28.8,0-52.3,23.9-52.3,53.3c0,29.4,23.5,53.3,52.3,53.3
+ s52.3-23.9,52.3-53.3c0-2.3-0.2-4.6-0.4-6.9c-5.5,4.3-12.3,6.9-19.8,6.9C270.3,256,256,241.7,256,224z"/>
+ </g>
+</g>
+</svg>
diff --git a/graphics/asymptote/GUI/res/icons/filledbucket.svg b/graphics/asymptote/GUI/res/icons/filledbucket.svg new file mode 100644 index 0000000000..e768fa3d1c --- /dev/null +++ b/graphics/asymptote/GUI/res/icons/filledbucket.svg @@ -0,0 +1,17 @@ +<?xml version='1.0' encoding='UTF-8'?> +<!-- This file was generated by dvisvgm 2.4 --> +<svg height='24pt' version='1.1' viewBox='56.4094 53.8583 18.4375 24' width='18.4375pt' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink'> +<g id='page1'> +<g transform='matrix(0.996264 0 0 0.996264 65.6282 74.202)'> +<path d='M -8.37504 -5.02502L -8.37504 -0L -8.37504 -1.85963e-15C -8.37504 -1.23975e-15 -8.37504 -6.19877e-16 -8.37504 -0C -8.37504 1.5418 -4.62541 2.79168 0 2.79168C 4.62541 2.79168 8.37504 1.5418 8.37504 0L 8.37504 0L 8.37504 -5.02502L 8.37504 -10.05C 8.37504 -11.5918 4.62541 -12.8417 0 -12.8417C -4.62541 -12.8417 -8.37504 -11.5918 -8.37504 -10.05L -8.37504 -5.02502Z' fill='#808080'/> +</g> +<g transform='matrix(0.996264 0 0 0.996264 65.6282 74.202)'> +<path d='M 8.37504 -11.1667C 8.37504 -12.7085 4.62541 -13.9584 0 -13.9584C -4.62541 -13.9584 -8.37504 -12.7085 -8.37504 -11.1667C -8.37504 -9.62492 -4.62541 -8.37504 0 -8.37504C 4.62541 -8.37504 8.37504 -9.62492 8.37504 -11.1667Z' fill='none' stroke='#000000' stroke-linecap='round' stroke-linejoin='round' stroke-miterlimit='10.0375' stroke-width='1.75656'/> +</g> +<g transform='matrix(0.996264 0 0 0.996264 65.6282 74.202)'> +<path d='M -8.37504 -11.1667L -8.37504 -0L -8.37504 -1.85963e-15C -8.37504 -1.23975e-15 -8.37504 -6.19877e-16 -8.37504 -0C -8.37504 1.5418 -4.62541 2.79168 0 2.79168C 4.62541 2.79168 8.37504 1.5418 8.37504 0L 8.37504 0L 8.37504 -11.1667' fill='none' stroke='#000000' stroke-linecap='round' stroke-linejoin='round' stroke-miterlimit='10.0375' stroke-width='1.75656'/> +</g> +<g transform='matrix(0.996264 0 0 0.996264 65.6282 74.202)'> +<path d='M 8.37504 -11.1667C 8.37504 -15.7921 4.62541 -19.5418 0 -19.5418C -4.62541 -19.5418 -8.37504 -15.7921 -8.37504 -11.1667' fill='none' stroke='#000000' stroke-linecap='round' stroke-linejoin='round' stroke-miterlimit='10.0375' stroke-width='1.75656'/> +</g></g> +</svg>
\ No newline at end of file diff --git a/graphics/asymptote/GUI/res/icons/grid.svg b/graphics/asymptote/GUI/res/icons/grid.svg new file mode 100644 index 0000000000..456e501131 --- /dev/null +++ b/graphics/asymptote/GUI/res/icons/grid.svg @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 16.2.1, 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" style="enable-background:new 0 0 512 512;" xml:space="preserve">
+<g>
+ <g>
+ <path d="M160,153.3c0,3.7-3,6.7-6.7,6.7h-50.5c-3.7,0-6.7-3-6.7-6.7v-50.5c0-3.7,3-6.7,6.7-6.7h50.5c3.7,0,6.7,3,6.7,6.7V153.3z"
+ />
+ <path d="M288,153.3c0,3.7-3,6.7-6.7,6.7h-50.5c-3.7,0-6.7-3-6.7-6.7v-50.5c0-3.7,3-6.7,6.7-6.7h50.5c3.7,0,6.7,3,6.7,6.7V153.3z"
+ />
+ <path d="M416,153.3c0,3.7-3,6.7-6.7,6.7h-50.5c-3.7,0-6.7-3-6.7-6.7v-50.5c0-3.7,3-6.7,6.7-6.7h50.5c3.7,0,6.7,3,6.7,6.7V153.3z"
+ />
+ </g>
+ <g>
+ <path d="M160,281.3c0,3.7-3,6.7-6.7,6.7h-50.5c-3.7,0-6.7-3-6.7-6.7v-50.5c0-3.7,3-6.7,6.7-6.7h50.5c3.7,0,6.7,3,6.7,6.7V281.3z"
+ />
+ <path d="M288,281.3c0,3.7-3,6.7-6.7,6.7h-50.5c-3.7,0-6.7-3-6.7-6.7v-50.5c0-3.7,3-6.7,6.7-6.7h50.5c3.7,0,6.7,3,6.7,6.7V281.3z"
+ />
+ <path d="M416,281.3c0,3.7-3,6.7-6.7,6.7h-50.5c-3.7,0-6.7-3-6.7-6.7v-50.5c0-3.7,3-6.7,6.7-6.7h50.5c3.7,0,6.7,3,6.7,6.7V281.3z"
+ />
+ </g>
+ <g>
+ <path d="M160,409.3c0,3.7-3,6.7-6.7,6.7h-50.5c-3.7,0-6.7-3-6.7-6.7v-50.5c0-3.7,3-6.7,6.7-6.7h50.5c3.7,0,6.7,3,6.7,6.7V409.3z"
+ />
+ <path d="M288,409.3c0,3.7-3,6.7-6.7,6.7h-50.5c-3.7,0-6.7-3-6.7-6.7v-50.5c0-3.7,3-6.7,6.7-6.7h50.5c3.7,0,6.7,3,6.7,6.7V409.3z"
+ />
+ <path d="M416,409.3c0,3.7-3,6.7-6.7,6.7h-50.5c-3.7,0-6.7-3-6.7-6.7v-50.5c0-3.7,3-6.7,6.7-6.7h50.5c3.7,0,6.7,3,6.7,6.7V409.3z"
+ />
+ </g>
+</g>
+</svg>
diff --git a/graphics/asymptote/GUI/res/icons/magnifying-glass.svg b/graphics/asymptote/GUI/res/icons/magnifying-glass.svg new file mode 100644 index 0000000000..f82283d618 --- /dev/null +++ b/graphics/asymptote/GUI/res/icons/magnifying-glass.svg @@ -0,0 +1,11 @@ +<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 18.1.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="Magnifying_glass" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px"
+ y="0px" viewBox="0 0 20 20" enable-background="new 0 0 20 20" xml:space="preserve">
+<path d="M17.545,15.467l-3.779-3.779c0.57-0.935,0.898-2.035,0.898-3.21c0-3.417-2.961-6.377-6.378-6.377
+ C4.869,2.1,2.1,4.87,2.1,8.287c0,3.416,2.961,6.377,6.377,6.377c1.137,0,2.2-0.309,3.115-0.844l3.799,3.801
+ c0.372,0.371,0.975,0.371,1.346,0l0.943-0.943C18.051,16.307,17.916,15.838,17.545,15.467z M4.004,8.287
+ c0-2.366,1.917-4.283,4.282-4.283c2.366,0,4.474,2.107,4.474,4.474c0,2.365-1.918,4.283-4.283,4.283
+ C6.111,12.76,4.004,10.652,4.004,8.287z"/>
+</svg>
diff --git a/graphics/asymptote/GUI/res/icons/opencurve.asy b/graphics/asymptote/GUI/res/icons/opencurve.asy new file mode 100644 index 0000000000..885128358a --- /dev/null +++ b/graphics/asymptote/GUI/res/icons/opencurve.asy @@ -0,0 +1,7 @@ +real pixel=1inch/96; +size(32*pixel,IgnoreAspect); +defaultpen(1.75bp); + +path p=W..NW..ENE..0.5*SE; +draw(p); +dot(p,linewidth(8pixel)); diff --git a/graphics/asymptote/GUI/res/icons/opencurve.svg b/graphics/asymptote/GUI/res/icons/opencurve.svg new file mode 100644 index 0000000000..5086ab071b --- /dev/null +++ b/graphics/asymptote/GUI/res/icons/opencurve.svg @@ -0,0 +1,20 @@ +<?xml version='1.0' encoding='UTF-8'?> +<!-- This file was generated by dvisvgm 2.4 --> +<svg height='24pt' version='1.1' viewBox='56.4094 53.8583 24 24' width='24pt' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink'> +<g id='page1'> +<g transform='matrix(0.996264 0 0 0.996264 68.7655 69.8123)'> +<path d='M -9.39118 -0C -9.32257 -3.77783 -8.34324 -7.38444 -6.64057 -10.1298C -1.26219 -18.8017 7.68971 -15.5351 8.67632 -5.4822C 9.18679 -0.280877 6.74937 4.51887 3.32028 5.06489' fill='none' stroke='#000000' stroke-linecap='round' stroke-linejoin='round' stroke-miterlimit='10.0375' stroke-width='1.75656'/> +</g> +<g transform='matrix(0.996264 0 0 0.996264 68.7655 69.8123)'> +<circle cx='-9.39118' cy='-0' r='3.01125' fill='#000000'/> +</g> +<g transform='matrix(0.996264 0 0 0.996264 68.7655 69.8123)'> +<circle cx='-6.64057' cy='-10.1298' r='3.01125' fill='#000000'/> +</g> +<g transform='matrix(0.996264 0 0 0.996264 68.7655 69.8123)'> +<circle cx='8.67632' cy='-5.4822' r='3.01125' fill='#000000'/> +</g> +<g transform='matrix(0.996264 0 0 0.996264 68.7655 69.8123)'> +<circle cx='3.32028' cy='5.06489' r='3.01125' fill='#000000'/> +</g></g> +</svg>
\ No newline at end of file diff --git a/graphics/asymptote/GUI/res/icons/openpolygon.asy b/graphics/asymptote/GUI/res/icons/openpolygon.asy new file mode 100644 index 0000000000..19f4d5cb03 --- /dev/null +++ b/graphics/asymptote/GUI/res/icons/openpolygon.asy @@ -0,0 +1,7 @@ +real pixel=1inch/96; +size(32*pixel,IgnoreAspect); +defaultpen(1.75bp); + +path p=W--NW--ENE--0.5*SE; +draw(p); +dot(p,linewidth(8pixel)); diff --git a/graphics/asymptote/GUI/res/icons/openpolygon.svg b/graphics/asymptote/GUI/res/icons/openpolygon.svg new file mode 100644 index 0000000000..a07a63abd7 --- /dev/null +++ b/graphics/asymptote/GUI/res/icons/openpolygon.svg @@ -0,0 +1,20 @@ +<?xml version='1.0' encoding='UTF-8'?> +<!-- This file was generated by dvisvgm 2.4 --> +<svg height='24pt' version='1.1' viewBox='56.4094 53.8583 24 24' width='24pt' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink'> +<g id='page1'> +<g transform='matrix(0.996264 0 0 0.996264 68.7655 68.8583)'> +<path d='M -9.39118 -0L -6.64057 -12.045L 8.67632 -6.51871L 3.32028 6.0225' fill='none' stroke='#000000' stroke-linecap='round' stroke-linejoin='round' stroke-miterlimit='10.0375' stroke-width='1.75656'/> +</g> +<g transform='matrix(0.996264 0 0 0.996264 68.7655 68.8583)'> +<circle cx='-9.39118' cy='-0' r='3.01125' fill='#000000'/> +</g> +<g transform='matrix(0.996264 0 0 0.996264 68.7655 68.8583)'> +<circle cx='-6.64057' cy='-12.045' r='3.01125' fill='#000000'/> +</g> +<g transform='matrix(0.996264 0 0 0.996264 68.7655 68.8583)'> +<circle cx='8.67632' cy='-6.51871' r='3.01125' fill='#000000'/> +</g> +<g transform='matrix(0.996264 0 0 0.996264 68.7655 68.8583)'> +<circle cx='3.32028' cy='6.0225' r='3.01125' fill='#000000'/> +</g></g> +</svg>
\ No newline at end of file diff --git a/graphics/asymptote/GUI/res/icons/plus-round.svg b/graphics/asymptote/GUI/res/icons/plus-round.svg new file mode 100644 index 0000000000..465d937802 --- /dev/null +++ b/graphics/asymptote/GUI/res/icons/plus-round.svg @@ -0,0 +1,9 @@ +<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 16.2.1, 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" style="enable-background:new 0 0 512 512;" xml:space="preserve">
+<path d="M417.4,224H288V94.6c0-16.9-14.3-30.6-32-30.6c-17.7,0-32,13.7-32,30.6V224H94.6C77.7,224,64,238.3,64,256
+ c0,17.7,13.7,32,30.6,32H224v129.4c0,16.9,14.3,30.6,32,30.6c17.7,0,32-13.7,32-30.6V288h129.4c16.9,0,30.6-14.3,30.6-32
+ C448,238.3,434.3,224,417.4,224z"/>
+</svg>
diff --git a/graphics/asymptote/GUI/res/icons/save.svg b/graphics/asymptote/GUI/res/icons/save.svg new file mode 100644 index 0000000000..2d2823d391 --- /dev/null +++ b/graphics/asymptote/GUI/res/icons/save.svg @@ -0,0 +1,8 @@ +<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 18.1.1, 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="Save" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+ viewBox="0 0 20 20" enable-background="new 0 0 20 20" xml:space="preserve">
+<path d="M15.173,2H4C2.899,2,2,2.9,2,4v12c0,1.1,0.899,2,2,2h12c1.101,0,2-0.9,2-2V5.127L15.173,2z M14,8c0,0.549-0.45,1-1,1H7
+ C6.45,9,6,8.549,6,8V3h8V8z M13,4h-2v4h2V4z"/>
+</svg>
diff --git a/graphics/asymptote/GUI/res/icons/social-python.svg b/graphics/asymptote/GUI/res/icons/social-python.svg new file mode 100644 index 0000000000..35fcdde7c1 --- /dev/null +++ b/graphics/asymptote/GUI/res/icons/social-python.svg @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 16.2.1, 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="M193.46,249.056c3.723-0.67,7.589-1.041,11.586-1.041L201.924,248h103.823c4.503,0,8.806-0.617,12.908-1.754
+ c19.37-5.363,33.345-22.537,33.345-43.663v-30.822v-56.402c0-24.832-21.15-43.484-46.289-47.606
+ c-15.931-2.624-39.258-3.827-55.089-3.749c-15.829,0.086-30.981,1.404-44.277,3.749C167.143,74.576,160,88.928,160,115.359V144h96
+ v16H128.82c-35.628,0-64.538,42.571-64.813,95.242C64.005,255.495,64,255.747,64,256c0,9.523,0.94,18.72,2.685,27.404
+ C74.648,323.07,99.451,352,128.82,352H144v-2.662v-43.273C144,279.238,164.146,254.332,193.46,249.056z M203.656,127.002
+ c-9.592,0-17.384-7.785-17.384-17.403c0-9.664,7.774-17.52,17.384-17.52c9.574,0,17.399,7.855,17.399,17.52
+ C221.056,119.217,213.246,127.002,203.656,127.002z"/>
+ <path d="M443.951,222.543C434.78,186.021,411.033,160,383.18,160H368v2.626v38.046c0,33.915-22.286,58.474-49.489,62.681
+ c-2.737,0.424-5.483,0.646-8.301,0.646H206.351c-4.518,0-8.904,0.584-13.049,1.672C174.18,270.689,160,286.6,160,307.236v32.922
+ v54.305c0,24.832,24.977,39.426,49.481,46.551c29.327,8.531,61.267,10.068,96.366,0C329.15,434.354,352,420.893,352,394.463V368
+ h-96v-16h127.18c25.24,0,47.107-21.365,57.814-52.549C445.474,286.404,448,271.641,448,256
+ C448,244.232,446.567,232.962,443.951,222.543z M307.867,382.82c9.59,0,17.381,7.785,17.381,17.4
+ c0,9.65-7.791,17.521-17.381,17.521c-9.577,0-17.399-7.871-17.399-17.521C290.468,390.59,298.274,382.82,307.867,382.82z"/>
+</g>
+</svg>
diff --git a/graphics/asymptote/GUI/res/icons/subdirectory-left.svg b/graphics/asymptote/GUI/res/icons/subdirectory-left.svg new file mode 100644 index 0000000000..bbbf333652 --- /dev/null +++ b/graphics/asymptote/GUI/res/icons/subdirectory-left.svg @@ -0,0 +1 @@ +<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"><path d="M18 12v1H8v5l-6-6 6-6v5h8V2h2z"/></svg>
\ No newline at end of file diff --git a/graphics/asymptote/GUI/res/icons/text.svg b/graphics/asymptote/GUI/res/icons/text.svg new file mode 100644 index 0000000000..7a4ffb4c0d --- /dev/null +++ b/graphics/asymptote/GUI/res/icons/text.svg @@ -0,0 +1,3 @@ +<svg xmlns="http://www.w3.org/2000/svg" width="8" height="8" viewBox="0 0 8 8"> + <path d="M0 0v2h.5c0-.55.45-1 1-1h1.5v5.5c0 .28-.22.5-.5.5h-.5v1h4v-1h-.5c-.28 0-.5-.22-.5-.5v-5.5h1.5c.55 0 1 .45 1 1h.5v-2h-8z" /> +</svg>
\ No newline at end of file diff --git a/graphics/asymptote/GUI/res/icons/triangle-stroked-15.svg b/graphics/asymptote/GUI/res/icons/triangle-stroked-15.svg new file mode 100644 index 0000000000..c87ff1d223 --- /dev/null +++ b/graphics/asymptote/GUI/res/icons/triangle-stroked-15.svg @@ -0,0 +1,12 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Generator: Adobe Illustrator 19.2.1, 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="svg4619" inkscape:version="0.91+devel+osxmenu r12911" sodipodi:docname="triangle-stroked-15.svg" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="15px" height="15px" + viewBox="0 0 15 15" style="enable-background:new 0 0 15 15;" xml:space="preserve"> +<path id="rect3338" inkscape:connector-curvature="0" sodipodi:nodetypes="cccccccccccc" d="M7.5243,1.5004 + C7.2429,1.4913,6.9787,1.6423,6.8336,1.8952l-5.5,9.8692C1.0218,12.3078,1.395,12.9999,2,13h11 + c0.605-0.0001,0.9782-0.6922,0.6664-1.2355l-5.5-9.8692C8.0302,1.6579,7.7884,1.5092,7.5243,1.5004z M7.5,3.8993l4.1267,7.4704 + H3.3733L7.5,3.8993z"/> +</svg> diff --git a/graphics/asymptote/GUI/setup.py b/graphics/asymptote/GUI/setup.py new file mode 100644 index 0000000000..d6a4c0d6a7 --- /dev/null +++ b/graphics/asymptote/GUI/setup.py @@ -0,0 +1,13 @@ +#!/usr/bin/env python3 + +import xasyVersion +from setuptools import setup + +setup( + name="xasy", + version=xasyVersion.xasyVersion, + author="Supakorn Rassameemasmuang, Orest Shardt, and John C. Bowman", + description="User interface for Asymptote, a vector graphics language", + url="http://asymptote.sourceforge.net", + download_url="https://sourceforge.net/projects/asymptote/" +) diff --git a/graphics/asymptote/GUI/windows/custMatTransform.ui b/graphics/asymptote/GUI/windows/custMatTransform.ui new file mode 100644 index 0000000000..4612f277c9 --- /dev/null +++ b/graphics/asymptote/GUI/windows/custMatTransform.ui @@ -0,0 +1,356 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>Dialog</class> + <widget class="QDialog" name="Dialog"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>500</width> + <height>320</height> + </rect> + </property> + <property name="sizePolicy"> + <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>500</width> + <height>320</height> + </size> + </property> + <property name="maximumSize"> + <size> + <width>500</width> + <height>320</height> + </size> + </property> + <property name="mouseTracking"> + <bool>false</bool> + </property> + <property name="windowTitle"> + <string>Set Custom Transformation</string> + </property> + <property name="windowIcon"> + <iconset resource="../res/icons.qrc"> + <normaloff>:/icons/android-expand.svg</normaloff>:/icons/android-expand.svg</iconset> + </property> + <property name="sizeGripEnabled"> + <bool>true</bool> + </property> + <property name="modal"> + <bool>false</bool> + </property> + <widget class="QFrame" name="centralFrame"> + <property name="geometry"> + <rect> + <x>20</x> + <y>20</y> + <width>461</width> + <height>271</height> + </rect> + </property> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Expanding"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="baseSize"> + <size> + <width>0</width> + <height>0</height> + </size> + </property> + <layout class="QVBoxLayout" name="verticalLayout_3"> + <property name="spacing"> + <number>4</number> + </property> + <item> + <layout class="QHBoxLayout" name="horizontalLayout"> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_3"> + <item> + <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <widget class="QLabel" name="label"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>Transformation Matrix</string> + </property> + </widget> + </item> + <item> + <widget class="QFrame" name="gridFrame"> + <property name="frameShape"> + <enum>QFrame::Box</enum> + </property> + <layout class="QGridLayout" name="gridLayout"> + <item row="1" column="0"> + <widget class="QLineEdit" name="lineMat00"> + <property name="maximumSize"> + <size> + <width>70</width> + <height>16777215</height> + </size> + </property> + <property name="text"> + <string>1</string> + </property> + </widget> + </item> + <item row="2" column="1"> + <widget class="QLineEdit" name="lineMat11"> + <property name="maximumSize"> + <size> + <width>70</width> + <height>16777215</height> + </size> + </property> + <property name="text"> + <string>1</string> + </property> + </widget> + </item> + <item row="2" column="0"> + <widget class="QLineEdit" name="lineMat10"> + <property name="maximumSize"> + <size> + <width>70</width> + <height>16777215</height> + </size> + </property> + <property name="text"> + <string>0</string> + </property> + </widget> + </item> + <item row="1" column="1"> + <widget class="QLineEdit" name="lineMat01"> + <property name="maximumSize"> + <size> + <width>70</width> + <height>16777215</height> + </size> + </property> + <property name="text"> + <string>0</string> + </property> + </widget> + </item> + </layout> + </widget> + </item> + </layout> + </item> + <item> + <spacer name="horizontalSpacer_3"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item> + <layout class="QVBoxLayout" name="verticalLayout_4"> + <item> + <widget class="QLabel" name="label_3"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>Translation</string> + </property> + </widget> + </item> + <item> + <widget class="QFrame" name="gridFrame_2"> + <property name="frameShape"> + <enum>QFrame::Box</enum> + </property> + <layout class="QGridLayout" name="gridLayout_2"> + <item row="2" column="1"> + <widget class="QLineEdit" name="lineMatTy"> + <property name="maximumSize"> + <size> + <width>70</width> + <height>16777215</height> + </size> + </property> + <property name="text"> + <string>0</string> + </property> + </widget> + </item> + <item row="1" column="1"> + <widget class="QLineEdit" name="lineMatTx"> + <property name="maximumSize"> + <size> + <width>70</width> + <height>16777215</height> + </size> + </property> + <property name="text"> + <string>0</string> + </property> + </widget> + </item> + </layout> + </widget> + </item> + </layout> + </item> + </layout> + </item> + <item> + <spacer name="horizontalSpacer"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item> + <layout class="QVBoxLayout" name="verticalLayout_2"> + <item> + <widget class="QLabel" name="label_2"> + <property name="text"> + <string>Preview:</string> + </property> + </widget> + </item> + <item> + <widget class="QLabel" name="imgPreview"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Minimum" vsizetype="Minimum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>150</width> + <height>150</height> + </size> + </property> + <property name="baseSize"> + <size> + <width>300</width> + <height>300</height> + </size> + </property> + <property name="toolTip"> + <string>Shows a red square if transformation determinant is negative.</string> + </property> + <property name="frameShape"> + <enum>QFrame::Box</enum> + </property> + <property name="text"> + <string/> + </property> + </widget> + </item> + </layout> + </item> + </layout> + </item> + <item> + <widget class="QLabel" name="lblAnchor"> + <property name="text"> + <string>Anchor: Top Left</string> + </property> + <property name="alignment"> + <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> + </property> + </widget> + </item> + <item> + <widget class="QLabel" name="lblCoordsMode"> + <property name="text"> + <string>Coordinates: Global</string> + </property> + <property name="alignment"> + <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> + </property> + </widget> + </item> + <item> + <spacer name="verticalSpacer"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>20</width> + <height>40</height> + </size> + </property> + </spacer> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_2"> + <item> + <spacer name="horizontalSpacer_2"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QPushButton" name="btnReset"> + <property name="text"> + <string>Reset</string> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="btnCancel"> + <property name="text"> + <string>Cancel</string> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="btnAccept"> + <property name="text"> + <string>Accept</string> + </property> + </widget> + </item> + </layout> + </item> + </layout> + </widget> + </widget> + <resources> + <include location="../res/icons.qrc"/> + </resources> + <connections/> +</ui> diff --git a/graphics/asymptote/GUI/windows/labelTextEditor.ui b/graphics/asymptote/GUI/windows/labelTextEditor.ui new file mode 100644 index 0000000000..06cd31bd1a --- /dev/null +++ b/graphics/asymptote/GUI/windows/labelTextEditor.ui @@ -0,0 +1,230 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>Dialog</class> + <widget class="QDialog" name="Dialog"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>473</width> + <height>424</height> + </rect> + </property> + <property name="windowTitle"> + <string>Dialog</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <widget class="QFrame" name="frame"> + <property name="frameShape"> + <enum>QFrame::StyledPanel</enum> + </property> + <property name="frameShadow"> + <enum>QFrame::Raised</enum> + </property> + <layout class="QVBoxLayout" name="verticalLayout_3"> + <item> + <layout class="QGridLayout" name="gridLayout"> + <property name="topMargin"> + <number>0</number> + </property> + <item row="0" column="2"> + <spacer name="horizontalSpacer_2"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item row="0" column="0"> + <widget class="QCheckBox" name="chkMathMode"> + <property name="text"> + <string>Math Mode</string> + </property> + </widget> + </item> + <item row="0" column="1"> + <widget class="QComboBox" name="cmbMathStyle"> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="sizePolicy"> + <sizepolicy hsizetype="Maximum" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>100</width> + <height>0</height> + </size> + </property> + <item> + <property name="text"> + <string>Inline Style</string> + </property> + </item> + <item> + <property name="text"> + <string>Display Style</string> + </property> + </item> + <item> + <property name="text"> + <string>Script Style</string> + </property> + </item> + </widget> + </item> + </layout> + </item> + <item> + <layout class="QVBoxLayout" name="verticalLayout_2"> + <item> + <widget class="QPlainTextEdit" name="txtLabelEdit"/> + </item> + </layout> + </item> + <item> + <layout class="QVBoxLayout" name="verticalLayout_4"> + <property name="topMargin"> + <number>0</number> + </property> + <item> + <widget class="QLabel" name="label"> + <property name="text"> + <string>Preview</string> + </property> + </widget> + </item> + <item> + <widget class="QLabel" name="lblLabelPreview"> + <property name="minimumSize"> + <size> + <width>0</width> + <height>100</height> + </size> + </property> + <property name="frameShape"> + <enum>QFrame::Box</enum> + </property> + <property name="text"> + <string/> + </property> + </widget> + </item> + </layout> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout"> + <item> + <spacer name="horizontalSpacer"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QPushButton" name="btnGetText"> + <property name="maximumSize"> + <size> + <width>32</width> + <height>32</height> + </size> + </property> + <property name="text"> + <string/> + </property> + <property name="icon"> + <iconset resource="../res/icons.qrc"> + <normaloff>:/icons/text.svg</normaloff>:/icons/text.svg</iconset> + </property> + <property name="flat"> + <bool>true</bool> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="btnPreview"> + <property name="maximumSize"> + <size> + <width>32</width> + <height>32</height> + </size> + </property> + <property name="text"> + <string/> + </property> + <property name="icon"> + <iconset resource="../res/icons.qrc"> + <normaloff>:/icons/eye.svg</normaloff>:/icons/eye.svg</iconset> + </property> + <property name="flat"> + <bool>true</bool> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="btnCancel"> + <property name="maximumSize"> + <size> + <width>32</width> + <height>32</height> + </size> + </property> + <property name="text"> + <string/> + </property> + <property name="icon"> + <iconset resource="../res/icons.qrc"> + <normaloff>:/icons/android-close.svg</normaloff>:/icons/android-close.svg</iconset> + </property> + <property name="flat"> + <bool>true</bool> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="btnAccept"> + <property name="maximumSize"> + <size> + <width>32</width> + <height>32</height> + </size> + </property> + <property name="text"> + <string/> + </property> + <property name="icon"> + <iconset resource="../res/icons.qrc"> + <normaloff>:/icons/android-done.svg</normaloff>:/icons/android-done.svg</iconset> + </property> + <property name="flat"> + <bool>true</bool> + </property> + </widget> + </item> + </layout> + </item> + </layout> + </widget> + </item> + </layout> + </widget> + <resources> + <include location="../res/icons.qrc"/> + </resources> + <connections/> +</ui> diff --git a/graphics/asymptote/GUI/windows/setCustomAnchor.ui b/graphics/asymptote/GUI/windows/setCustomAnchor.ui new file mode 100644 index 0000000000..5a4b14676e --- /dev/null +++ b/graphics/asymptote/GUI/windows/setCustomAnchor.ui @@ -0,0 +1,109 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>Dialog</class> + <widget class="QDialog" name="Dialog"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>245</width> + <height>161</height> + </rect> + </property> + <property name="windowTitle"> + <string>Set Custom Anchor</string> + </property> + <widget class="QWidget" name="verticalLayoutWidget"> + <property name="geometry"> + <rect> + <x>20</x> + <y>20</y> + <width>201</width> + <height>121</height> + </rect> + </property> + <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <layout class="QFormLayout" name="formLayout"> + <property name="fieldGrowthPolicy"> + <enum>QFormLayout::AllNonFixedFieldsGrow</enum> + </property> + <item row="1" column="0"> + <widget class="QLabel" name="label"> + <property name="text"> + <string>X:</string> + </property> + </widget> + </item> + <item row="1" column="1"> + <widget class="QLineEdit" name="lineEditX"> + <property name="text"> + <string>0</string> + </property> + </widget> + </item> + <item row="2" column="0"> + <widget class="QLabel" name="label_2"> + <property name="text"> + <string>Y:</string> + </property> + </widget> + </item> + <item row="2" column="1"> + <widget class="QLineEdit" name="lineEditY"> + <property name="text"> + <string>0</string> + </property> + </widget> + </item> + </layout> + </item> + <item> + <widget class="QDialogButtonBox" name="buttonBox"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="standardButtons"> + <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok|QDialogButtonBox::Reset</set> + </property> + </widget> + </item> + </layout> + </widget> + </widget> + <resources/> + <connections> + <connection> + <sender>buttonBox</sender> + <signal>accepted()</signal> + <receiver>Dialog</receiver> + <slot>accept()</slot> + <hints> + <hint type="sourcelabel"> + <x>248</x> + <y>254</y> + </hint> + <hint type="destinationlabel"> + <x>157</x> + <y>274</y> + </hint> + </hints> + </connection> + <connection> + <sender>buttonBox</sender> + <signal>rejected()</signal> + <receiver>Dialog</receiver> + <slot>reject()</slot> + <hints> + <hint type="sourcelabel"> + <x>316</x> + <y>260</y> + </hint> + <hint type="destinationlabel"> + <x>286</x> + <y>274</y> + </hint> + </hints> + </connection> + </connections> +</ui> diff --git a/graphics/asymptote/GUI/windows/widg_addLabel.ui b/graphics/asymptote/GUI/windows/widg_addLabel.ui new file mode 100644 index 0000000000..40bc4ddc60 --- /dev/null +++ b/graphics/asymptote/GUI/windows/widg_addLabel.ui @@ -0,0 +1,287 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>Form</class> + <widget class="QWidget" name="Form"> + <property name="windowModality"> + <enum>Qt::NonModal</enum> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>599</width> + <height>35</height> + </rect> + </property> + <property name="sizePolicy"> + <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>0</width> + <height>35</height> + </size> + </property> + <property name="maximumSize"> + <size> + <width>16777215</width> + <height>35</height> + </size> + </property> + <property name="windowTitle"> + <string>Form</string> + </property> + <layout class="QHBoxLayout" name="horizontalLayout_2"> + <property name="spacing"> + <number>0</number> + </property> + <property name="leftMargin"> + <number>0</number> + </property> + <property name="topMargin"> + <number>0</number> + </property> + <property name="rightMargin"> + <number>0</number> + </property> + <property name="bottomMargin"> + <number>0</number> + </property> + <item> + <layout class="QHBoxLayout" name="horizontalLayout"> + <item> + <widget class="QLineEdit" name="txtLabelText"> + <property name="toolTip"> + <string>Number of Sides</string> + </property> + <property name="placeholderText"> + <string>Text</string> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="btnAdvancedEdit"> + <property name="maximumSize"> + <size> + <width>25</width> + <height>25</height> + </size> + </property> + <property name="text"> + <string/> + </property> + <property name="icon"> + <iconset> + <normaloff>:/icons/edit.svg</normaloff>:/icons/edit.svg</iconset> + </property> + <property name="flat"> + <bool>true</bool> + </property> + </widget> + </item> + <item> + <widget class="QLabel" name="label"> + <property name="text"> + <string>Align</string> + </property> + </widget> + </item> + <item> + <widget class="QComboBox" name="cmbAlign"> + <item> + <property name="text"> + <string>Center</string> + </property> + </item> + <item> + <property name="text"> + <string>N</string> + </property> + </item> + <item> + <property name="text"> + <string>E</string> + </property> + </item> + <item> + <property name="text"> + <string>W</string> + </property> + </item> + <item> + <property name="text"> + <string>S</string> + </property> + </item> + <item> + <property name="text"> + <string>NW</string> + </property> + </item> + <item> + <property name="text"> + <string>NE</string> + </property> + </item> + <item> + <property name="text"> + <string>SW</string> + </property> + </item> + <item> + <property name="text"> + <string>SE</string> + </property> + </item> + <item> + <property name="text"> + <string>Custom</string> + </property> + </item> + </widget> + </item> + <item> + <widget class="QLabel" name="label_3"> + <property name="text"> + <string>Font Size</string> + </property> + </widget> + </item> + <item> + <widget class="QComboBox" name="cmbFontSize"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Minimum" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="editable"> + <bool>true</bool> + </property> + <item> + <property name="text"> + <string>-</string> + </property> + </item> + <item> + <property name="text"> + <string>8</string> + </property> + </item> + <item> + <property name="text"> + <string>9</string> + </property> + </item> + <item> + <property name="text"> + <string>10</string> + </property> + </item> + <item> + <property name="text"> + <string>11</string> + </property> + </item> + <item> + <property name="text"> + <string>12</string> + </property> + </item> + <item> + <property name="text"> + <string>14</string> + </property> + </item> + <item> + <property name="text"> + <string>18</string> + </property> + </item> + <item> + <property name="text"> + <string>24</string> + </property> + </item> + <item> + <property name="text"> + <string>48</string> + </property> + </item> + <item> + <property name="text"> + <string>72</string> + </property> + </item> + </widget> + </item> + <item> + <widget class="QLabel" name="label_2"> + <property name="text"> + <string>Custom Align</string> + </property> + </widget> + </item> + <item> + <widget class="QLineEdit" name="txtShiftX"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Maximum" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="maximumSize"> + <size> + <width>50</width> + <height>16777215</height> + </size> + </property> + <property name="placeholderText"> + <string>Shift X</string> + </property> + </widget> + </item> + <item> + <widget class="QLineEdit" name="txtShiftY"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Maximum" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="maximumSize"> + <size> + <width>50</width> + <height>16777215</height> + </size> + </property> + <property name="placeholderText"> + <string>Shift Y</string> + </property> + </widget> + </item> + <item> + <spacer name="horizontalSpacer"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + </layout> + </item> + </layout> + </widget> + <resources> + <include location="../res/icons.qrc"/> + </resources> + <connections/> +</ui> diff --git a/graphics/asymptote/GUI/windows/widg_addPolyOpt.ui b/graphics/asymptote/GUI/windows/widg_addPolyOpt.ui new file mode 100644 index 0000000000..b8bde4236a --- /dev/null +++ b/graphics/asymptote/GUI/windows/widg_addPolyOpt.ui @@ -0,0 +1,91 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>Form</class> + <widget class="QWidget" name="Form"> + <property name="windowModality"> + <enum>Qt::NonModal</enum> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>326</width> + <height>35</height> + </rect> + </property> + <property name="sizePolicy"> + <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>0</width> + <height>35</height> + </size> + </property> + <property name="maximumSize"> + <size> + <width>16777215</width> + <height>35</height> + </size> + </property> + <property name="windowTitle"> + <string>Form</string> + </property> + <layout class="QHBoxLayout" name="horizontalLayout_2"> + <property name="spacing"> + <number>0</number> + </property> + <property name="leftMargin"> + <number>0</number> + </property> + <property name="topMargin"> + <number>0</number> + </property> + <property name="rightMargin"> + <number>0</number> + </property> + <property name="bottomMargin"> + <number>0</number> + </property> + <item> + <layout class="QHBoxLayout" name="horizontalLayout"> + <item> + <widget class="QCheckBox" name="chkInscribed"> + <property name="text"> + <string>Start at Vertex</string> + </property> + </widget> + </item> + <item> + <widget class="QLineEdit" name="txtSides"> + <property name="toolTip"> + <string>Number of Sides</string> + </property> + <property name="placeholderText"> + <string>Sides</string> + </property> + </widget> + </item> + <item> + <spacer name="horizontalSpacer"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + </layout> + </item> + </layout> + </widget> + <resources/> + <connections/> +</ui> diff --git a/graphics/asymptote/GUI/windows/widg_editBezier.ui b/graphics/asymptote/GUI/windows/widg_editBezier.ui new file mode 100644 index 0000000000..cca3aaaa2d --- /dev/null +++ b/graphics/asymptote/GUI/windows/widg_editBezier.ui @@ -0,0 +1,170 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>Form</class> + <widget class="QWidget" name="Form"> + <property name="windowModality"> + <enum>Qt::NonModal</enum> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>692</width> + <height>35</height> + </rect> + </property> + <property name="sizePolicy"> + <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>0</width> + <height>35</height> + </size> + </property> + <property name="maximumSize"> + <size> + <width>16777215</width> + <height>35</height> + </size> + </property> + <property name="windowTitle"> + <string>Form</string> + </property> + <layout class="QHBoxLayout" name="horizontalLayout_2"> + <property name="spacing"> + <number>0</number> + </property> + <property name="leftMargin"> + <number>0</number> + </property> + <property name="topMargin"> + <number>0</number> + </property> + <property name="rightMargin"> + <number>0</number> + </property> + <property name="bottomMargin"> + <number>0</number> + </property> + <item> + <layout class="QHBoxLayout" name="horizontalLayout"> + <item> + <widget class="QComboBox" name="cmbLockMode"> + <property name="sizePolicy"> + <sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="currentIndex"> + <number>1</number> + </property> + <item> + <property name="text"> + <string>No Lock</string> + </property> + </item> + <item> + <property name="text"> + <string>Lock Angle</string> + </property> + </item> + <item> + <property name="text"> + <string>Lock Angle & Scale</string> + </property> + </item> + </widget> + </item> + <item> + <spacer name="horizontalSpacer"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QCheckBox" name="chkRecompute"> + <property name="sizePolicy"> + <sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>Recompute Path</string> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="btnForceRecompute"> + <property name="text"> + <string>Recompute Once</string> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="btnOk"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="maximumSize"> + <size> + <width>25</width> + <height>25</height> + </size> + </property> + <property name="icon"> + <iconset resource="../res/icons.qrc"> + <normaloff>:/icons/check.svg</normaloff>:/icons/check.svg</iconset> + </property> + <property name="flat"> + <bool>true</bool> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="btnCancel"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="maximumSize"> + <size> + <width>25</width> + <height>25</height> + </size> + </property> + <property name="icon"> + <iconset resource="../res/icons.qrc"> + <normaloff>:/icons/close-round.svg</normaloff>:/icons/close-round.svg</iconset> + </property> + <property name="flat"> + <bool>true</bool> + </property> + </widget> + </item> + </layout> + </item> + </layout> + </widget> + <resources> + <include location="../res/icons.qrc"/> + </resources> + <connections/> +</ui> diff --git a/graphics/asymptote/GUI/windows/widgetPointEditor.ui b/graphics/asymptote/GUI/windows/widgetPointEditor.ui new file mode 100644 index 0000000000..c3e486ad5a --- /dev/null +++ b/graphics/asymptote/GUI/windows/widgetPointEditor.ui @@ -0,0 +1,150 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>Form</class> + <widget class="QWidget" name="Form"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>324</width> + <height>67</height> + </rect> + </property> + <property name="windowTitle"> + <string>Form</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <widget class="QLabel" name="nameLabel"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>Left Control Point</string> + </property> + </widget> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout"> + <item> + <widget class="QLineEdit" name="lineXorA"> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="toolTip"> + <string>X</string> + </property> + <property name="readOnly"> + <bool>false</bool> + </property> + <property name="placeholderText"> + <string>X</string> + </property> + </widget> + </item> + <item> + <widget class="QLineEdit" name="lineYorM"> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="toolTip"> + <string>X</string> + </property> + <property name="autoFillBackground"> + <bool>false</bool> + </property> + <property name="readOnly"> + <bool>false</bool> + </property> + <property name="placeholderText"> + <string>Y</string> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="btnRelative"> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="sizePolicy"> + <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string/> + </property> + <property name="icon"> + <iconset resource="../res/icons.qrc"> + <normaloff>:/icons/android-locate.svg</normaloff>:/icons/android-locate.svg</iconset> + </property> + <property name="checkable"> + <bool>true</bool> + </property> + <property name="flat"> + <bool>false</bool> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="btnPolar"> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="sizePolicy"> + <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string/> + </property> + <property name="icon"> + <iconset resource="../res/icons.qrc"> + <normaloff>:/icons/android-radio-button-off.svg</normaloff>:/icons/android-radio-button-off.svg</iconset> + </property> + <property name="checkable"> + <bool>true</bool> + </property> + <property name="flat"> + <bool>false</bool> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="btnManualAdj"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string/> + </property> + <property name="icon"> + <iconset resource="../res/icons.qrc"> + <normaloff>:/icons/edit.svg</normaloff>:/icons/edit.svg</iconset> + </property> + <property name="checkable"> + <bool>true</bool> + </property> + <property name="flat"> + <bool>false</bool> + </property> + </widget> + </item> + </layout> + </item> + </layout> + </widget> + <resources> + <include location="../res/icons.qrc"/> + </resources> + <connections/> +</ui> diff --git a/graphics/asymptote/GUI/windows/window1.ui b/graphics/asymptote/GUI/windows/window1.ui new file mode 100644 index 0000000000..bbe474bab1 --- /dev/null +++ b/graphics/asymptote/GUI/windows/window1.ui @@ -0,0 +1,2000 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>MainWindow</class> + <widget class="QMainWindow" name="MainWindow"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>1030</width> + <height>768</height> + </rect> + </property> + <property name="windowTitle"> + <string>xasy</string> + </property> + <widget class="QWidget" name="centralwidget"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Preferred"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="mouseTracking"> + <bool>true</bool> + </property> + <layout class="QHBoxLayout" name="horizontalLayout_4"> + <property name="spacing"> + <number>0</number> + </property> + <property name="leftMargin"> + <number>0</number> + </property> + <property name="topMargin"> + <number>0</number> + </property> + <property name="rightMargin"> + <number>0</number> + </property> + <property name="bottomMargin"> + <number>0</number> + </property> + <item> + <widget class="QWidget" name="mainWidget" native="true"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="mouseTracking"> + <bool>true</bool> + </property> + <layout class="QVBoxLayout" name="verticalLayout"> + <property name="spacing"> + <number>4</number> + </property> + <property name="leftMargin"> + <number>2</number> + </property> + <property name="topMargin"> + <number>2</number> + </property> + <property name="rightMargin"> + <number>2</number> + </property> + <property name="bottomMargin"> + <number>2</number> + </property> + <item> + <widget class="QFrame" name="menuFrame"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Minimum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="frameShape"> + <enum>QFrame::NoFrame</enum> + </property> + <layout class="QHBoxLayout" name="horizontalLayout"> + <property name="spacing"> + <number>4</number> + </property> + <property name="sizeConstraint"> + <enum>QLayout::SetMinimumSize</enum> + </property> + <property name="leftMargin"> + <number>0</number> + </property> + <property name="topMargin"> + <number>0</number> + </property> + <property name="rightMargin"> + <number>0</number> + </property> + <property name="bottomMargin"> + <number>0</number> + </property> + <item> + <widget class="QPushButton" name="btnUndo"> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="sizePolicy"> + <sizepolicy hsizetype="Minimum" vsizetype="Minimum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="maximumSize"> + <size> + <width>25</width> + <height>25</height> + </size> + </property> + <property name="baseSize"> + <size> + <width>32</width> + <height>32</height> + </size> + </property> + <property name="toolTip"> + <string>Undo</string> + </property> + <property name="text"> + <string/> + </property> + <property name="icon"> + <iconset> + <normaloff>:/icons/android-arrow-back.svg</normaloff>:/icons/android-arrow-back.svg</iconset> + </property> + <property name="iconSize"> + <size> + <width>16</width> + <height>16</height> + </size> + </property> + <property name="flat"> + <bool>true</bool> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="btnRedo"> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="sizePolicy"> + <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="maximumSize"> + <size> + <width>25</width> + <height>25</height> + </size> + </property> + <property name="baseSize"> + <size> + <width>32</width> + <height>32</height> + </size> + </property> + <property name="toolTip"> + <string>Redo</string> + </property> + <property name="text"> + <string/> + </property> + <property name="icon"> + <iconset> + <normaloff>:/icons/android-arrow-forward.svg</normaloff>:/icons/android-arrow-forward.svg</iconset> + </property> + <property name="flat"> + <bool>true</bool> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="btnLoadFile"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="maximumSize"> + <size> + <width>25</width> + <height>25</height> + </size> + </property> + <property name="baseSize"> + <size> + <width>32</width> + <height>32</height> + </size> + </property> + <property name="toolTip"> + <string><html><head/><body><p>Open file</p></body></html></string> + </property> + <property name="text"> + <string/> + </property> + <property name="icon"> + <iconset> + <normaloff>:/icons/android-folder-open.svg</normaloff>:/icons/android-folder-open.svg</iconset> + </property> + <property name="flat"> + <bool>true</bool> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="btnSave"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="maximumSize"> + <size> + <width>25</width> + <height>25</height> + </size> + </property> + <property name="baseSize"> + <size> + <width>32</width> + <height>32</height> + </size> + </property> + <property name="toolTip"> + <string><html><head/><body><p>Save file</p></body></html></string> + </property> + <property name="text"> + <string/> + </property> + <property name="icon"> + <iconset> + <normaloff>:/icons/save.svg</normaloff>:/icons/save.svg</iconset> + </property> + <property name="flat"> + <bool>true</bool> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="btnViewCode"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Maximum" vsizetype="Maximum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="maximumSize"> + <size> + <width>25</width> + <height>25</height> + </size> + </property> + <property name="baseSize"> + <size> + <width>32</width> + <height>32</height> + </size> + </property> + <property name="toolTip"> + <string><html><head/><body><p>Edit code</p></body></html></string> + </property> + <property name="text"> + <string/> + </property> + <property name="icon"> + <iconset> + <normaloff>:/icons/code.svg</normaloff>:/icons/code.svg</iconset> + </property> + <property name="flat"> + <bool>true</bool> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="btnQuickScreenshot"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="maximumSize"> + <size> + <width>25</width> + <height>25</height> + </size> + </property> + <property name="baseSize"> + <size> + <width>32</width> + <height>32</height> + </size> + </property> + <property name="toolTip"> + <string><html><head/><body><p>Screenshot</p></body></html></string> + </property> + <property name="text"> + <string/> + </property> + <property name="icon"> + <iconset> + <normaloff>:/icons/android-camera.svg</normaloff>:/icons/android-camera.svg</iconset> + </property> + <property name="flat"> + <bool>true</bool> + </property> + </widget> + </item> + <item> + <spacer name="horizontalSpacer_3"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeType"> + <enum>QSizePolicy::Minimum</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>20</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QPushButton" name="btnDrawAxes"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Maximum" vsizetype="Maximum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="maximumSize"> + <size> + <width>25</width> + <height>25</height> + </size> + </property> + <property name="baseSize"> + <size> + <width>32</width> + <height>32</height> + </size> + </property> + <property name="font"> + <font> + <family>Roboto</family> + <weight>75</weight> + <bold>true</bold> + </font> + </property> + <property name="toolTip"> + <string><html><head/><body><p>Toggle display axes</p></body></html></string> + </property> + <property name="text"> + <string/> + </property> + <property name="icon"> + <iconset> + <normaloff>:/icons/plus-round.svg</normaloff>:/icons/plus-round.svg</iconset> + </property> + <property name="checkable"> + <bool>true</bool> + </property> + <property name="checked"> + <bool>true</bool> + </property> + <property name="flat"> + <bool>true</bool> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="btnDrawGrid"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Maximum" vsizetype="Maximum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="maximumSize"> + <size> + <width>25</width> + <height>25</height> + </size> + </property> + <property name="baseSize"> + <size> + <width>32</width> + <height>32</height> + </size> + </property> + <property name="font"> + <font> + <family>Roboto</family> + <weight>75</weight> + <bold>true</bold> + </font> + </property> + <property name="toolTip"> + <string><html><head/><body><p>Toggle grid</p></body></html></string> + </property> + <property name="text"> + <string/> + </property> + <property name="icon"> + <iconset> + <normaloff>:/icons/grid.svg</normaloff>:/icons/grid.svg</iconset> + </property> + <property name="checkable"> + <bool>true</bool> + </property> + <property name="checked"> + <bool>false</bool> + </property> + <property name="flat"> + <bool>true</bool> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="btnSetZoom"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="maximumSize"> + <size> + <width>25</width> + <height>25</height> + </size> + </property> + <property name="baseSize"> + <size> + <width>32</width> + <height>32</height> + </size> + </property> + <property name="toolTip"> + <string>Synchronize with Asymptote</string> + </property> + <property name="text"> + <string/> + </property> + <property name="icon"> + <iconset> + <normaloff>:/icons/magnifying-glass.svg</normaloff>:/icons/magnifying-glass.svg</iconset> + </property> + <property name="flat"> + <bool>true</bool> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="btnPanCenter"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="maximumSize"> + <size> + <width>25</width> + <height>25</height> + </size> + </property> + <property name="baseSize"> + <size> + <width>32</width> + <height>32</height> + </size> + </property> + <property name="toolTip"> + <string><html><head/><body><p>Center</p></body></html></string> + </property> + <property name="text"> + <string/> + </property> + <property name="icon"> + <iconset> + <normaloff>:/icons/center.svg</normaloff>:/icons/center.svg</iconset> + </property> + <property name="flat"> + <bool>true</bool> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="btnResetPan"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="maximumSize"> + <size> + <width>25</width> + <height>25</height> + </size> + </property> + <property name="baseSize"> + <size> + <width>32</width> + <height>32</height> + </size> + </property> + <property name="toolTip"> + <string><html><head/><body><p>Center about origin</p></body></html></string> + </property> + <property name="text"> + <string/> + </property> + <property name="icon"> + <iconset> + <normaloff>:/icons/centerorigin.svg</normaloff>:/icons/centerorigin.svg</iconset> + </property> + <property name="flat"> + <bool>true</bool> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="btnAlignX"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Maximum" vsizetype="Maximum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="maximumSize"> + <size> + <width>25</width> + <height>25</height> + </size> + </property> + <property name="baseSize"> + <size> + <width>32</width> + <height>32</height> + </size> + </property> + <property name="font"> + <font> + <family>Roboto</family> + <weight>75</weight> + <bold>true</bold> + </font> + </property> + <property name="toolTip"> + <string><html><head/><body><p>Lock transform to X axis</p></body></html></string> + </property> + <property name="text"> + <string>X</string> + </property> + <property name="checkable"> + <bool>true</bool> + </property> + <property name="flat"> + <bool>true</bool> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="btnAlignY"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Maximum" vsizetype="Maximum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="maximumSize"> + <size> + <width>25</width> + <height>25</height> + </size> + </property> + <property name="baseSize"> + <size> + <width>32</width> + <height>32</height> + </size> + </property> + <property name="font"> + <font> + <weight>75</weight> + <bold>true</bold> + </font> + </property> + <property name="toolTip"> + <string><html><head/><body><p>Lock transform to Y axis</p></body></html></string> + </property> + <property name="text"> + <string>Y</string> + </property> + <property name="checkable"> + <bool>true</bool> + </property> + <property name="flat"> + <bool>true</bool> + </property> + </widget> + </item> + <item> + <spacer name="horizontalSpacer_6"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeType"> + <enum>QSizePolicy::Minimum</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>20</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QPushButton" name="btnSelectEdit"> + <property name="enabled"> + <bool>true</bool> + </property> + <property name="sizePolicy"> + <sizepolicy hsizetype="Maximum" vsizetype="Maximum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="maximumSize"> + <size> + <width>25</width> + <height>25</height> + </size> + </property> + <property name="toolTip"> + <string><html><head/><body><p>Bézier editor</p></body></html></string> + </property> + <property name="text"> + <string/> + </property> + <property name="icon"> + <iconset> + <normaloff>:/icons/edit.svg</normaloff>:/icons/edit.svg</iconset> + </property> + <property name="flat"> + <bool>true</bool> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="btnDeleteMode"> + <property name="enabled"> + <bool>true</bool> + </property> + <property name="sizePolicy"> + <sizepolicy hsizetype="Maximum" vsizetype="Maximum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="maximumSize"> + <size> + <width>25</width> + <height>25</height> + </size> + </property> + <property name="baseSize"> + <size> + <width>32</width> + <height>32</height> + </size> + </property> + <property name="toolTip"> + <string><html><head/><body><p>Delete</p></body></html></string> + </property> + <property name="text"> + <string/> + </property> + <property name="icon"> + <iconset> + <normaloff>:/icons/android-delete.svg</normaloff>:/icons/android-delete.svg</iconset> + </property> + <property name="checkable"> + <bool>false</bool> + </property> + <property name="flat"> + <bool>true</bool> + </property> + </widget> + </item> + <item> + <spacer name="horizontalSpacer_5"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeType"> + <enum>QSizePolicy::Minimum</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>20</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QPushButton" name="btnPan"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="maximumSize"> + <size> + <width>25</width> + <height>25</height> + </size> + </property> + <property name="baseSize"> + <size> + <width>32</width> + <height>32</height> + </size> + </property> + <property name="toolTip"> + <string>Pan</string> + </property> + <property name="text"> + <string/> + </property> + <property name="icon"> + <iconset> + <normaloff>:/icons/android-hand.svg</normaloff>:/icons/android-hand.svg</iconset> + </property> + <property name="checkable"> + <bool>true</bool> + </property> + <property name="flat"> + <bool>true</bool> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="btnTranslate"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="maximumSize"> + <size> + <width>25</width> + <height>25</height> + </size> + </property> + <property name="baseSize"> + <size> + <width>32</width> + <height>32</height> + </size> + </property> + <property name="toolTip"> + <string>Translate</string> + </property> + <property name="text"> + <string/> + </property> + <property name="icon"> + <iconset> + <normaloff>:/icons/arrow-move.svg</normaloff>:/icons/arrow-move.svg</iconset> + </property> + <property name="checkable"> + <bool>true</bool> + </property> + <property name="checked"> + <bool>true</bool> + </property> + <property name="flat"> + <bool>true</bool> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="btnScale"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Maximum" vsizetype="Maximum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="maximumSize"> + <size> + <width>25</width> + <height>25</height> + </size> + </property> + <property name="baseSize"> + <size> + <width>32</width> + <height>32</height> + </size> + </property> + <property name="toolTip"> + <string>Scale</string> + </property> + <property name="text"> + <string/> + </property> + <property name="icon"> + <iconset> + <normaloff>:/icons/arrow-resize.svg</normaloff>:/icons/arrow-resize.svg</iconset> + </property> + <property name="checkable"> + <bool>true</bool> + </property> + <property name="flat"> + <bool>true</bool> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="btnRotate"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="maximumSize"> + <size> + <width>25</width> + <height>25</height> + </size> + </property> + <property name="baseSize"> + <size> + <width>32</width> + <height>32</height> + </size> + </property> + <property name="toolTip"> + <string>Rotate</string> + </property> + <property name="text"> + <string/> + </property> + <property name="icon"> + <iconset> + <normaloff>:/icons/android-refresh.svg</normaloff>:/icons/android-refresh.svg</iconset> + </property> + <property name="checkable"> + <bool>true</bool> + </property> + <property name="flat"> + <bool>true</bool> + </property> + </widget> + </item> + <item> + <spacer name="horizontalSpacer_4"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeType"> + <enum>QSizePolicy::Minimum</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>20</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QPushButton" name="btnAnchor"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Maximum" vsizetype="Maximum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="maximumSize"> + <size> + <width>25</width> + <height>25</height> + </size> + </property> + <property name="baseSize"> + <size> + <width>32</width> + <height>32</height> + </size> + </property> + <property name="toolTip"> + <string><html><head/><body><p>Set custom anchor</p></body></html></string> + </property> + <property name="text"> + <string/> + </property> + <property name="icon"> + <iconset> + <normaloff>:/icons/anchor.svg</normaloff>:/icons/anchor.svg</iconset> + </property> + <property name="checkable"> + <bool>true</bool> + </property> + <property name="checked"> + <bool>false</bool> + </property> + <property name="flat"> + <bool>true</bool> + </property> + </widget> + </item> + <item> + <widget class="QComboBox" name="comboAnchor"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Maximum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>127</width> + <height>0</height> + </size> + </property> + <property name="maximumSize"> + <size> + <width>127</width> + <height>25</height> + </size> + </property> + <property name="toolTip"> + <string><html><head/><body><p>Anchor</p></body></html></string> + </property> + <property name="layoutDirection"> + <enum>Qt::LeftToRight</enum> + </property> + <property name="editable"> + <bool>false</bool> + </property> + <property name="currentText"> + <string>Origin</string> + </property> + <property name="currentIndex"> + <number>0</number> + </property> + <property name="insertPolicy"> + <enum>QComboBox::InsertAtCurrent</enum> + </property> + <property name="sizeAdjustPolicy"> + <enum>QComboBox::AdjustToContentsOnFirstShow</enum> + </property> + <property name="iconSize"> + <size> + <width>0</width> + <height>0</height> + </size> + </property> + <property name="duplicatesEnabled"> + <bool>false</bool> + </property> + <property name="frame"> + <bool>false</bool> + </property> + <property name="modelColumn"> + <number>0</number> + </property> + <item> + <property name="text"> + <string>Origin</string> + </property> + </item> + <item> + <property name="text"> + <string>Center</string> + </property> + </item> + <item> + <property name="text"> + <string>Top Left</string> + </property> + </item> + <item> + <property name="text"> + <string>Top Right</string> + </property> + </item> + <item> + <property name="text"> + <string>Bottom Right</string> + </property> + </item> + <item> + <property name="text"> + <string>Bottom Left</string> + </property> + </item> + <item> + <property name="text"> + <string>Custom</string> + </property> + </item> + </widget> + </item> + <item> + <widget class="QPushButton" name="btnToggleVisible"> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="sizePolicy"> + <sizepolicy hsizetype="Maximum" vsizetype="Maximum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="maximumSize"> + <size> + <width>25</width> + <height>25</height> + </size> + </property> + <property name="baseSize"> + <size> + <width>32</width> + <height>32</height> + </size> + </property> + <property name="text"> + <string/> + </property> + <property name="icon"> + <iconset> + <normaloff>:/icons/eye.svg</normaloff>:/icons/eye.svg</iconset> + </property> + <property name="checkable"> + <bool>false</bool> + </property> + <property name="flat"> + <bool>true</bool> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="btnCustTransform"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="maximumSize"> + <size> + <width>25</width> + <height>25</height> + </size> + </property> + <property name="baseSize"> + <size> + <width>32</width> + <height>32</height> + </size> + </property> + <property name="toolTip"> + <string><html><head/><body><p><br/></p></body></html></string> + </property> + <property name="text"> + <string/> + </property> + <property name="icon"> + <iconset> + <normaloff>:/icons/android-expand.svg</normaloff>:/icons/android-expand.svg</iconset> + </property> + <property name="flat"> + <bool>true</bool> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="btnSendBackwards"> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="maximumSize"> + <size> + <width>25</width> + <height>25</height> + </size> + </property> + <property name="baseSize"> + <size> + <width>32</width> + <height>32</height> + </size> + </property> + <property name="toolTip"> + <string><html><head/><body><p><br/></p></body></html></string> + </property> + <property name="text"> + <string/> + </property> + <property name="icon"> + <iconset> + <normaloff>:/icons/chevron-with-circle-left.svg</normaloff>:/icons/chevron-with-circle-left.svg</iconset> + </property> + <property name="flat"> + <bool>true</bool> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="btnSendForwards"> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="maximumSize"> + <size> + <width>25</width> + <height>25</height> + </size> + </property> + <property name="baseSize"> + <size> + <width>32</width> + <height>32</height> + </size> + </property> + <property name="toolTip"> + <string>Translate</string> + </property> + <property name="text"> + <string/> + </property> + <property name="icon"> + <iconset> + <normaloff>:/icons/chevron-with-circle-right.svg</normaloff>:/icons/chevron-with-circle-right.svg</iconset> + </property> + <property name="flat"> + <bool>true</bool> + </property> + </widget> + </item> + <item> + <spacer name="horizontalSpacer"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeType"> + <enum>QSizePolicy::Fixed</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>25</height> + </size> + </property> + </spacer> + </item> + </layout> + <zorder>btnUndo</zorder> + <zorder>btnRedo</zorder> + <zorder>btnLoadFile</zorder> + <zorder>btnSave</zorder> + <zorder>btnViewCode</zorder> + <zorder>btnQuickScreenshot</zorder> + <zorder>btnDrawAxes</zorder> + <zorder>btnDrawGrid</zorder> + <zorder>btnSetZoom</zorder> + <zorder>btnPanCenter</zorder> + <zorder>btnResetPan</zorder> + <zorder>btnAlignX</zorder> + <zorder>btnAlignY</zorder> + <zorder>btnPan</zorder> + <zorder>btnTranslate</zorder> + <zorder>btnScale</zorder> + <zorder>btnCustTransform</zorder> + <zorder>btnSendBackwards</zorder> + <zorder>btnSendForwards</zorder> + <zorder>comboAnchor</zorder> + <zorder>btnToggleVisible</zorder> + <zorder>btnAnchor</zorder> + <zorder>btnRotate</zorder> + <zorder>btnSelectEdit</zorder> + <zorder>btnDeleteMode</zorder> + <zorder>horizontalSpacer_4</zorder> + <zorder>horizontalSpacer_5</zorder> + <zorder>horizontalSpacer_6</zorder> + </widget> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_2"> + <property name="spacing"> + <number>4</number> + </property> + <item> + <layout class="QVBoxLayout" name="verticalLayout_2"> + <property name="spacing"> + <number>3</number> + </property> + <item> + <layout class="QHBoxLayout" name="addOption"> + <property name="spacing"> + <number>6</number> + </property> + <property name="sizeConstraint"> + <enum>QLayout::SetDefaultConstraint</enum> + </property> + <property name="leftMargin"> + <number>6</number> + </property> + <property name="bottomMargin"> + <number>0</number> + </property> + <item> + <widget class="QPushButton" name="btnFill"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="maximumSize"> + <size> + <width>32</width> + <height>32</height> + </size> + </property> + <property name="baseSize"> + <size> + <width>32</width> + <height>32</height> + </size> + </property> + <property name="toolTip"> + <string><html><head/><body><p>Toggle fill/outline</p></body></html></string> + </property> + <property name="autoFillBackground"> + <bool>false</bool> + </property> + <property name="styleSheet"> + <string notr="true"/> + </property> + <property name="text"> + <string/> + </property> + <property name="icon"> + <iconset> + <normaloff>:/icons/bucket.svg</normaloff> + <normalon>:/icons/filledbucket.svg</normalon>:/icons/bucket.svg</iconset> + </property> + <property name="checkable"> + <bool>true</bool> + </property> + <property name="default"> + <bool>false</bool> + </property> + <property name="flat"> + <bool>true</bool> + </property> + </widget> + </item> + <item> + <layout class="QGridLayout" name="addOptionLayout"/> + </item> + <item> + <spacer name="horizontalSpacer_7"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeType"> + <enum>QSizePolicy::MinimumExpanding</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>35</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QLabel" name="label"> + <property name="text"> + <string>Line Width:</string> + </property> + </widget> + </item> + <item> + <widget class="QLineEdit" name="txtLineWidth"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="maximumSize"> + <size> + <width>75</width> + <height>16777215</height> + </size> + </property> + <property name="toolTip"> + <string><html><head/><body><p>Current pen width</p></body></html></string> + </property> + </widget> + </item> + <item> + <widget class="QFrame" name="frameCurrColor"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>15</width> + <height>15</height> + </size> + </property> + <property name="toolTip"> + <string><html><head/><body><p>Current pen color</p></body></html></string> + </property> + <property name="autoFillBackground"> + <bool>false</bool> + </property> + <property name="styleSheet"> + <string notr="true">QFrame{ +padding: 4.0; +border-radius: 3.0; +background: rgb(0, 0, 0) +}</string> + </property> + <property name="frameShape"> + <enum>QFrame::StyledPanel</enum> + </property> + <property name="frameShadow"> + <enum>QFrame::Sunken</enum> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="btnSelectColor"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="maximumSize"> + <size> + <width>25</width> + <height>25</height> + </size> + </property> + <property name="baseSize"> + <size> + <width>32</width> + <height>32</height> + </size> + </property> + <property name="toolTip"> + <string><html><head/><body><p>Set color</p></body></html></string> + </property> + <property name="autoFillBackground"> + <bool>false</bool> + </property> + <property name="styleSheet"> + <string notr="true"/> + </property> + <property name="text"> + <string/> + </property> + <property name="icon"> + <iconset> + <normaloff>:/icons/android-color-palette.svg</normaloff>:/icons/android-color-palette.svg</iconset> + </property> + <property name="default"> + <bool>false</bool> + </property> + <property name="flat"> + <bool>true</bool> + </property> + </widget> + </item> + </layout> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_7"> + <property name="topMargin"> + <number>6</number> + </property> + <item> + <widget class="QFrame" name="formFrame"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Maximum" vsizetype="Preferred"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="frameShape"> + <enum>QFrame::NoFrame</enum> + </property> + <property name="frameShadow"> + <enum>QFrame::Plain</enum> + </property> + <property name="lineWidth"> + <number>0</number> + </property> + <layout class="QFormLayout" name="formLayout"> + <property name="horizontalSpacing"> + <number>0</number> + </property> + <property name="verticalSpacing"> + <number>0</number> + </property> + <property name="leftMargin"> + <number>0</number> + </property> + <property name="topMargin"> + <number>0</number> + </property> + <property name="rightMargin"> + <number>0</number> + </property> + <property name="bottomMargin"> + <number>0</number> + </property> + <item row="4" column="0"> + <widget class="QPushButton" name="btnOpenPoly"> + <property name="enabled"> + <bool>true</bool> + </property> + <property name="sizePolicy"> + <sizepolicy hsizetype="Maximum" vsizetype="Maximum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="maximumSize"> + <size> + <width>32</width> + <height>32</height> + </size> + </property> + <property name="toolTip"> + <string><html><head/><body><p>Open polygon</p></body></html></string> + </property> + <property name="text"> + <string/> + </property> + <property name="icon"> + <iconset> + <normaloff>:/icons/openpolygon.svg</normaloff>:/icons/openpolygon.svg</iconset> + </property> + <property name="flat"> + <bool>true</bool> + </property> + </widget> + </item> + <item row="5" column="0"> + <widget class="QPushButton" name="btnClosedPoly"> + <property name="enabled"> + <bool>true</bool> + </property> + <property name="sizePolicy"> + <sizepolicy hsizetype="Maximum" vsizetype="Maximum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="maximumSize"> + <size> + <width>32</width> + <height>32</height> + </size> + </property> + <property name="toolTip"> + <string><html><head/><body><p>Closed polygon</p></body></html></string> + </property> + <property name="text"> + <string/> + </property> + <property name="icon"> + <iconset> + <normaloff>:/icons/closedpolygon.svg</normaloff>:/icons/closedpolygon.svg</iconset> + </property> + <property name="flat"> + <bool>true</bool> + </property> + </widget> + </item> + <item row="6" column="0"> + <widget class="QPushButton" name="btnOpenCurve"> + <property name="enabled"> + <bool>true</bool> + </property> + <property name="sizePolicy"> + <sizepolicy hsizetype="Maximum" vsizetype="Maximum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="maximumSize"> + <size> + <width>32</width> + <height>32</height> + </size> + </property> + <property name="toolTip"> + <string><html><head/><body><p>Open Bézier curve</p></body></html></string> + </property> + <property name="text"> + <string/> + </property> + <property name="icon"> + <iconset> + <normaloff>:/icons/opencurve.svg</normaloff>:/icons/opencurve.svg</iconset> + </property> + <property name="flat"> + <bool>true</bool> + </property> + </widget> + </item> + <item row="7" column="0"> + <widget class="QPushButton" name="btnClosedCurve"> + <property name="enabled"> + <bool>true</bool> + </property> + <property name="sizePolicy"> + <sizepolicy hsizetype="Maximum" vsizetype="Maximum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="maximumSize"> + <size> + <width>32</width> + <height>32</height> + </size> + </property> + <property name="toolTip"> + <string><html><head/><body><p>Closed Bézier curve</p></body></html></string> + </property> + <property name="text"> + <string/> + </property> + <property name="icon"> + <iconset> + <normaloff>:/icons/closedcurve.svg</normaloff>:/icons/closedcurve.svg</iconset> + </property> + <property name="flat"> + <bool>true</bool> + </property> + </widget> + </item> + <item row="8" column="0"> + <widget class="QPushButton" name="btnAddPoly"> + <property name="enabled"> + <bool>true</bool> + </property> + <property name="sizePolicy"> + <sizepolicy hsizetype="Maximum" vsizetype="Maximum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="maximumSize"> + <size> + <width>32</width> + <height>32</height> + </size> + </property> + <property name="toolTip"> + <string><html><head/><body><p>Regular polygon</p></body></html></string> + </property> + <property name="text"> + <string/> + </property> + <property name="icon"> + <iconset> + <normaloff>:/icons/triangle-stroked-15.svg</normaloff>:/icons/triangle-stroked-15.svg</iconset> + </property> + <property name="flat"> + <bool>true</bool> + </property> + </widget> + </item> + <item row="10" column="0"> + <widget class="QPushButton" name="btnAddCircle"> + <property name="enabled"> + <bool>true</bool> + </property> + <property name="sizePolicy"> + <sizepolicy hsizetype="Maximum" vsizetype="Maximum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="maximumSize"> + <size> + <width>32</width> + <height>32</height> + </size> + </property> + <property name="toolTip"> + <string><html><head/><body><p>Circle</p></body></html></string> + </property> + <property name="text"> + <string/> + </property> + <property name="icon"> + <iconset> + <normaloff>:/icons/circle.svg</normaloff>:/icons/circle.svg</iconset> + </property> + <property name="flat"> + <bool>true</bool> + </property> + </widget> + </item> + <item row="11" column="0"> + <widget class="QPushButton" name="btnAddLabel"> + <property name="enabled"> + <bool>true</bool> + </property> + <property name="sizePolicy"> + <sizepolicy hsizetype="Maximum" vsizetype="Maximum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="maximumSize"> + <size> + <width>32</width> + <height>32</height> + </size> + </property> + <property name="toolTip"> + <string><html><head/><body><p>Text</p></body></html></string> + </property> + <property name="text"> + <string/> + </property> + <property name="icon"> + <iconset> + <normaloff>:/icons/text.svg</normaloff>:/icons/text.svg</iconset> + </property> + <property name="flat"> + <bool>true</bool> + </property> + </widget> + </item> + </layout> + </widget> + </item> + <item> + <widget class="QFrame" name="imgFrame"> + <property name="minimumSize"> + <size> + <width>0</width> + <height>6</height> + </size> + </property> + <property name="mouseTracking"> + <bool>true</bool> + </property> + <property name="frameShape"> + <enum>QFrame::NoFrame</enum> + </property> + <property name="frameShadow"> + <enum>QFrame::Raised</enum> + </property> + <layout class="QGridLayout" name="gridLayout"> + <property name="leftMargin"> + <number>0</number> + </property> + <property name="topMargin"> + <number>0</number> + </property> + <property name="rightMargin"> + <number>0</number> + </property> + <property name="bottomMargin"> + <number>0</number> + </property> + <property name="spacing"> + <number>0</number> + </property> + <item row="0" column="1"> + <widget class="QLabel" name="imgLabel"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="mouseTracking"> + <bool>true</bool> + </property> + <property name="frameShape"> + <enum>QFrame::Panel</enum> + </property> + <property name="text"> + <string/> + </property> + <property name="alignment"> + <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set> + </property> + </widget> + </item> + </layout> + </widget> + </item> + </layout> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_3"> + <property name="spacing"> + <number>0</number> + </property> + <property name="sizeConstraint"> + <enum>QLayout::SetDefaultConstraint</enum> + </property> + <property name="topMargin"> + <number>0</number> + </property> + <item> + <widget class="QPushButton" name="btnTogglePython"> + <property name="enabled"> + <bool>true</bool> + </property> + <property name="sizePolicy"> + <sizepolicy hsizetype="Minimum" vsizetype="Minimum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string/> + </property> + <property name="icon"> + <iconset> + <normaloff>:/icons/social-python.svg</normaloff>:/icons/social-python.svg</iconset> + </property> + <property name="iconSize"> + <size> + <width>16</width> + <height>16</height> + </size> + </property> + <property name="checkable"> + <bool>true</bool> + </property> + <property name="flat"> + <bool>true</bool> + </property> + </widget> + </item> + <item> + <widget class="QLineEdit" name="txtTerminalPrompt"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Minimum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="btnEnterCommand"> + <property name="enabled"> + <bool>true</bool> + </property> + <property name="sizePolicy"> + <sizepolicy hsizetype="Minimum" vsizetype="Minimum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string/> + </property> + <property name="icon"> + <iconset> + <normaloff>:/icons/subdirectory-left.svg</normaloff>:/icons/subdirectory-left.svg</iconset> + </property> + <property name="flat"> + <bool>true</bool> + </property> + </widget> + </item> + </layout> + </item> + </layout> + </item> + </layout> + </item> + </layout> + </widget> + </item> + </layout> + </widget> + <widget class="QMenuBar" name="menubar"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>1030</width> + <height>28</height> + </rect> + </property> + <widget class="QMenu" name="menuFIle"> + <property name="title"> + <string>&File</string> + </property> + <addaction name="actionOpen"/> + <addaction name="actionSave"/> + <addaction name="actionSaveAs"/> + <addaction name="actionExportAsymptote"/> + <addaction name="separator"/> + <addaction name="actionQuit"/> + </widget> + <widget class="QMenu" name="menuEdit"> + <property name="title"> + <string>&Edit</string> + </property> + <addaction name="actionUndo"/> + <addaction name="actionRedo"/> + <addaction name="separator"/> + </widget> + <widget class="QMenu" name="menuOptions"> + <property name="title"> + <string>Optio&ns</string> + </property> + <addaction name="actionSettings"/> + </widget> + <widget class="QMenu" name="menuHelp"> + <property name="title"> + <string>&Help</string> + </property> + <addaction name="actionManual"/> + <addaction name="actionAbout"/> + </widget> + <widget class="QMenu" name="menuTools"> + <property name="title"> + <string>&Tools</string> + </property> + <addaction name="actionEnterCommand"/> + </widget> + <addaction name="menuFIle"/> + <addaction name="menuEdit"/> + <addaction name="menuOptions"/> + <addaction name="menuTools"/> + <addaction name="menuHelp"/> + </widget> + <widget class="QStatusBar" name="statusbar"> + <property name="sizeGripEnabled"> + <bool>false</bool> + </property> + </widget> + <action name="actionAbout"> + <property name="text"> + <string>&About</string> + </property> + </action> + <action name="actionManual"> + <property name="text"> + <string>&Manual</string> + </property> + </action> + <action name="actionSettings"> + <property name="text"> + <string>&Settings</string> + </property> + </action> + <action name="actionPause"> + <property name="text"> + <string>Pause </string> + </property> + </action> + <action name="actionSaveAs"> + <property name="text"> + <string>&Save As</string> + </property> + </action> + <action name="actionEnterCommand"> + <property name="text"> + <string>&Enter Command</string> + </property> + </action> + <action name="actionQuit"> + <property name="text"> + <string>&Quit</string> + </property> + </action> + <action name="actionUndo"> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="text"> + <string>&Undo</string> + </property> + </action> + <action name="actionRedo"> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="text"> + <string>&Redo</string> + </property> + </action> + <action name="actionShow_Grid"> + <property name="text"> + <string>&Show Grid</string> + </property> + </action> + <action name="actionShow_Local_Grid"> + <property name="text"> + <string>Show &Local Grid</string> + </property> + </action> + <action name="actionTransform"> + <property name="text"> + <string>&Transform</string> + </property> + </action> + <action name="actionExportAsymptote"> + <property name="text"> + <string>Export</string> + </property> + </action> + <action name="actionSave"> + <property name="text"> + <string>Save</string> + </property> + </action> + <action name="actionOpen"> + <property name="text"> + <string>Open</string> + </property> + </action> + </widget> + <layoutdefault spacing="6" margin="9"/> + <resources> + <include location="../res/icons.qrc"/> + </resources> + <connections/> + <designerdata> + <property name="gridDeltaX"> + <number>10</number> + </property> + <property name="gridDeltaY"> + <number>10</number> + </property> + <property name="gridSnapX"> + <bool>true</bool> + </property> + <property name="gridSnapY"> + <bool>true</bool> + </property> + <property name="gridVisible"> + <bool>true</bool> + </property> + </designerdata> +</ui> diff --git a/graphics/asymptote/GUI/xasy.py b/graphics/asymptote/GUI/xasy.py new file mode 100755 index 0000000000..7e38f73a2a --- /dev/null +++ b/graphics/asymptote/GUI/xasy.py @@ -0,0 +1,16 @@ +#!/usr/bin/env python3 + +import sys +import PyQt5.QtWidgets as Qw +from Window1 import MainWindow1 + + +def main(args): + qtApp = Qw.QApplication(args) + mainWin1 = MainWindow1() + mainWin1.show() + return qtApp.exec_() + + +if __name__ == '__main__': + sys.exit(main(sys.argv) or 0) diff --git a/graphics/asymptote/GUI/xasy2asy.py b/graphics/asymptote/GUI/xasy2asy.py new file mode 100755 index 0000000000..2df6c3417a --- /dev/null +++ b/graphics/asymptote/GUI/xasy2asy.py @@ -0,0 +1,1407 @@ +#!/usr/bin/env python3 + +########################################################################### +# +# xasy2asy provides a Python interface to Asymptote +# +# +# Authors: Orest Shardt, Supakorn Rassameemasmuang, and John C. Bowman +# +########################################################################### + +import PyQt5.QtWidgets as Qw +import PyQt5.QtGui as Qg +import PyQt5.QtCore as Qc +import PyQt5.QtSvg as Qs + +import numpy as np + +import sys +import os +import signal +import threading +import string +import subprocess +import tempfile +import re +import shutil +import copy +import queue +import io +import atexit +import DebugFlags + +import xasyUtils as xu +import xasyArgs as xa +import xasyOptions as xo +import xasySvg as xs + +class AsymptoteEngine: + xasy=chr(4)+"\n" + + def __init__(self, path=None, keepFiles=DebugFlags.keepFiles, keepDefaultArgs=True): + if path is None: + path = xa.getArgs().asypath + if path is None: + opt = xo.BasicConfigs.defaultOpt + opt.load() + path = opt['asyPath'] + + if sys.platform[:3] == 'win': + rx = 0 # stdin + wa = 2 # stderr + else: + rx, wx = os.pipe() + ra, wa = os.pipe() + os.set_inheritable(rx, True) + os.set_inheritable(wx, True) + os.set_inheritable(ra, True) + 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='./')+'/' + else: + self.tmpdir = tempfile.mkdtemp(prefix='xasyData_')+os.sep + + self.args=['-xasy', '-noV', '-q', '-inpipe=' + str(rx), '-outpipe=' + str(wa), '-o', self.tmpdir] + + self.asyPath = path + self.asyProcess = None + + def start(self): + try: + if sys.platform[:3] == 'win': + self.asyProcess = subprocess.Popen([self.asyPath] + self.args, + stdin=subprocess.PIPE, stderr=subprocess.PIPE, + universal_newlines=True) + self.ostream = self.asyProcess.stdin + self.istream = self.asyProcess.stderr + else: + self.asyProcess = subprocess.Popen([self.asyPath] + self.args,close_fds=False) + finally: + atexit.register(self.cleanup) + + def wait(self): + if self.asyProcess.returncode is not None: + return + else: + return self.asyProcess.wait() + + def __enter__(self): + self.start() + return self + + def __exit__(self, exc_type, exc_val, exc_tb): + self.stop() + self.wait() + + @property + def tempDirName(self): + return self.tmpdir + + def startThenStop(self): + self.start() + self.stop() + self.wait() + + @property + def active(self): + if self.asyProcess is None: + return False + return self.asyProcess.returncode is None + + def stop(self): + if self.active: + self.asyProcess.kill() + + def cleanup(self): + self.stop() + if self.asyProcess is not None: + self.asyProcess.wait() + if not self.keepFiles: + 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""" + + def __init__(self, initTuple, delete=False): + """Initialize the transform with a 6 entry tuple""" + super().__init__() + if isinstance(initTuple, (tuple, list)) and len(initTuple) == 6: + self.t = initTuple + self.x, self.y, self.xx, self.xy, self.yx, self.yy = initTuple + self._deleted = delete + else: + raise TypeError("Illegal initializer for asyTransform") + + @property + def deleted(self): + return self._deleted + + @deleted.setter + def deleted(self, value): + self._deleted = value + + @classmethod + def zero(cls): + return asyTransform((0, 0, 0, 0, 0, 0)) + + @classmethod + def fromQTransform(cls, transform: Qg.QTransform): + tx, ty = transform.dx(), transform.dy() + xx, xy, yx, yy = transform.m11(), transform.m21(), transform.m12(), transform.m22() + + return asyTransform((tx, ty, xx, xy, yx, yy)) + + @classmethod + def fromNumpyMatrix(cls, transform: np.ndarray): + assert transform.shape == (3, 3) + + tx = transform[0, 2] + ty = transform[1, 2] + + xx, xy, yx, yy = transform[0:2, 0:2].ravel().tolist()[0] + + return asyTransform((tx, ty, xx, xy, yx, yy)) + + def getRawCode(self): + return xu.tuple2StrWOspaces(self.t) + + 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: + return 'zeroTransform' + else: + return (asy2psmap.inverted() * self * asy2psmap).getRawCode() + + def scale(self, s): + 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) + + def __str__(self): + """Equivalent functionality to getCode(). It allows the expression str(asyTransform) to be meaningful.""" + return self.getCode() + + def isIdentity(self): + return self == identity() + + def inverted(self): + return asyTransform.fromQTransform(self.toQTransform().inverted()[0]) + + def __eq__(self, other): + return list(self.t) == list(other.t) + + def __mul__(self, other): + """Define multiplication of transforms as composition.""" + if isinstance(other, tuple): + if len(other) == 6: + return self * asyTransform(other) + elif len(other) == 2: + return ((self.t[0] + self.t[2] * other[0] + self.t[3] * other[1]), + (self.t[1] + self.t[4] * other[0] + self.t[5] * other[1])) + else: + raise Exception("Illegal multiplier of {:s}".format(str(type(other)))) + elif isinstance(other, asyTransform): + result = asyTransform((0, 0, 0, 0, 0, 0)) + result.x = self.x + self.xx * other.x + self.xy * other.y + result.y = self.y + self.yx * other.x + self.yy * other.y + result.xx = self.xx * other.xx + self.xy * other.yx + result.xy = self.xx * other.xy + self.xy * other.yy + result.yx = self.yx * other.xx + self.yy * other.yx + result.yy = self.yx * other.xy + self.yy * other.yy + result.t = (result.x, result.y, result.xx, result.xy, result.yx, result.yy) + return result + elif isinstance(other, str): + if other != 'cycle': + raise TypeError + else: + return 'cycle' + else: + raise TypeError("Illegal multiplier of {:s}".format(str(type(other)))) + + +def identity(): + return asyTransform((0, 0, 1, 0, 0, 1)) + +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.""" + def __init__(self): + """Initialize the object""" + super().__init__() + self.asyCode = '' + + def updateCode(self, ps2asymap=identity()): + """Update the object's code: should be overriden.""" + raise NotImplementedError + + 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""" + @staticmethod + def getColorFromQColor(color): + return color.redF(), color.greenF(), color.blueF() + + @staticmethod + def convertToQColor(color): + r, g, b = color + return Qg.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) + + 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 + self.width = width + self._asyengine = asyengine + self._deferAsyfy = False + if pen_options: + self._deferAsyfy = True + self.updateCode() + self.setColor(color) + + @property + def asyEngine(self): + return self._asyengine + + @asyEngine.setter + def asyEngine(self, value): + self._asyengine = value + + 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)) + if len(self.options) > 0: + self.asyCode = self.asyCode + '+' + self.options + + def setWidth(self, newWidth): + """Set the pen's width""" + self.width = newWidth + self.updateCode() + + def setColor(self, color): + """Set the pen's color""" + if isinstance(color, tuple) and len(color) == 3: + self.color = color + else: + self.color = (0, 0, 0) + self.updateCode() + + def setColorFromQColor(self, color): + self.setColor(asyPen.getColorFromQColor(color)) + + def computeColor(self): + """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") + fout.write("flush(_outpipe);\n") + fout.write(self.asyEngine.xasy) + fout.flush() + + colorspace = fin.readline() + if colorspace.find("cmyk") != -1: + lines = fin.readline() + fin.readline() + fin.readline() + fin.readline() + parts = lines.split() + c, m, y, k = eval(parts[0]), eval(parts[1]), eval(parts[2]), eval(parts[3]) + k = 1 - k + r, g, b = ((1 - c) * k, (1 - m) * k, (1 - y) * k) + elif colorspace.find("rgb") != -1: + lines = fin.readline() + fin.readline() + fin.readline() + parts = lines.split() + r, g, b = eval(parts[0]), eval(parts[1]), eval(parts[2]) + elif colorspace.find("gray") != -1: + lines = fin.readline() + parts = lines.split() + r = g = b = eval(parts[0]) + else: + raise ChildProcessError('Asymptote error.') + 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.setColor(asyPen.convertToQColor(self.color)) + newPen.setWidthF(self.width) + + return newPen + + +class asyPath(asyObj): + """A python wrapper for an asymptote path""" + + 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.""" + super().__init__() + self.nodeSet = [] + self.linkSet = [] + self.forceCurve = forceCurve + self.controlSet = [] + self.computed = False + self.asyengine = asyengine + + @classmethod + def fromPath(cls, oldPath): + newObj = asyPath(None) + newObj.nodeSet = copy.copy(oldPath.nodeSet) + newObj.linkSet = copy.copy(oldPath.linkSet) + newObj.controlSet = copy.deepcopy(oldPath.controlSet) + newObj.computed = oldPath.computed + newObj.asyengine = oldPath.asyengine + + return newObj + + @classmethod + def fromBezierPoints(cls, pointList: list, engine=None): + if not pointList: + return None + assert isinstance(pointList[0], BezierCurveEditor.BezierPoint) + nodeList = [] + controlList = [] + for point in pointList: + nodeList.append(BezierCurveEditor.QPoint2Tuple(point.point)) + if point.rCtrlPoint is not None: # first + controlList.append([BezierCurveEditor.QPoint2Tuple(point.rCtrlPoint)]) + if point.lCtrlPoint is not None: # last + controlList[-1].append(BezierCurveEditor.QPoint2Tuple(point.lCtrlPoint)) + newPath = asyPath(asyengine=engine) + newPath.initFromControls(nodeList, controlList) + return newPath + + def setInfo(self, path): + self.nodeSet = copy.copy(path.nodeSet) + self.linkSet = copy.copy(path.linkSet) + self.controlSet = copy.deepcopy(path.controlSet) + self.computed = path.computed + + @property + def isEmpty(self): + return len(self.nodeSet) == 0 + + @property + def isDrawable(self): + return len(self.nodeSet) >= 2 + + def toQPainterPath(self) -> Qg.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)) + + for pointIndex in range(1, len(self.nodeSet)): + node = self.nodeSet[pointIndex] + if self.nodeSet[pointIndex] == 'cycle': + node = self.nodeSet[0] + + painterPath.lineTo(*node) + + return painterPath + + + def toQPainterPathCurve(self): + if not self.computed: + self.computeControls() + + baseX, baseY = self.nodeSet[0] + painterPath = Qg.QPainterPath(Qc.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]) + + painterPath.cubicTo(ctrlPoint1, ctrlPoint2, endPoint) + return painterPath + + def initFromNodeList(self, nodeSet, linkSet): + """Initialize the path from a set of nodes and link types, "--", "..", or "::" """ + if len(nodeSet) > 0: + self.nodeSet = nodeSet[:] + self.linkSet = linkSet[:] + self.computed = False + + def initFromControls(self, nodeSet, controlSet): + """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""" + 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... + return '({:.6g},{:.6g})'.format(node[0], node[1]) + + def updateCode(self, ps2asymap=identity()): + """Generate the code describing the path""" + # currently at postscript. Convert to asy + asy2psmap = ps2asymap.inverted() + with io.StringIO() as rawAsyCode: + count = 0 + rawAsyCode.write(self.makeNodeStr(asy2psmap * self.nodeSet[0])) + for node in self.nodeSet[1:]: + if not self.computed or count >= len(self.controlSet): + rawAsyCode.write(self.linkSet[count]) + rawAsyCode.write(self.makeNodeStr(asy2psmap * node)) + else: + rawAsyCode.write('..controls ') + rawAsyCode.write(self.makeNodeStr(asy2psmap * self.controlSet[count][0])) + rawAsyCode.write(' and ') + rawAsyCode.write(self.makeNodeStr(asy2psmap * self.controlSet[count][1])) + rawAsyCode.write(".." + self.makeNodeStr(asy2psmap * node)) + count = count + 1 + self.asyCode = rawAsyCode.getvalue() + + @property + def containsCurve(self): + return '..' in self.linkSet or self.forceCurve + + def getNode(self, index): + """Return the requested node""" + return self.nodeSet[index] + + def getLink(self, index): + """Return the requested link""" + return self.linkSet[index] + + def setNode(self, index, newNode): + """Set a node to a new position""" + self.nodeSet[index] = newNode + + def moveNode(self, index, offset): + """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""" + self.linkSet[index] = ltype + + def addNode(self, point, ltype): + """Add a node to the end of a path""" + self.nodeSet.append(point) + if len(self.nodeSet) != 1: + self.linkSet.append(ltype) + if self.computed: + self.computeControls() + + def insertNode(self, index, point, ltype=".."): + """Insert a node, and its corresponding link, at the given index""" + self.nodeSet.insert(index, point) + self.linkSet.insert(index, ltype) + if self.computed: + self.computeControls() + + def setControl(self, index, position): + """Set a control point to a new position""" + self.controlSet[index] = position + + def popNode(self): + if len(self.controlSet) == len(self.nodeSet): + self.controlSet.pop() + self.nodeSet.pop() + self.linkSet.pop() + + def moveControl(self, index, offset): + """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""" + # For now, if no asymptote process is given spawns a new one. + # Only happens if asyengine is None. + if self.asyengine is not None: + assert isinstance(self.asyengine, AsymptoteEngine) + assert self.asyengine.active + asy = self.asyengine + startUp = False + else: + startUp = True + asy = AsymptoteEngine() + asy.start() + + fout = asy.ostream + fin = asy.istream + + fout.write("path p=" + self.getCode() + ';\n') + fout.write("write(_outpipe,length(p),newl);\n") + fout.write("write(_outpipe,unstraighten(p),endl);\n") + fout.write(asy.xasy) + fout.flush() + + lengthStr = fin.readline() + pathSegments = eval(lengthStr.split()[-1]) + pathStrLines = [] + for i in range(pathSegments + 1): + line = fin.readline() + line = line.replace("\n", "") + pathStrLines.append(line) + oneLiner = "".join(pathStrLines).replace(" ", "") + splitList = oneLiner.split("..") + nodes = [a for a in splitList if a.find("controls") == -1] + self.nodeSet = [] + for a in nodes: + if a == 'cycle': + self.nodeSet.append(a) + else: + self.nodeSet.append(eval(a)) + controls = [a.replace("controls", "").split("and") for a in splitList if a.find("controls") != -1] + self.controlSet = [[eval(a[0]), eval(a[1])] for a in controls] + self.computed = True + + if startUp: + asy.stop() + +class asyLabel(asyObj): + """A python wrapper for an asy label""" + + 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 + self.pen = pen + self.fontSize = fontSize + if align is None: + self.align = 'SE' + if pen is None: + self.pen = asyPen() + self.text = text + self.location = location + + 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, + self.getFontSizeText()) + + def getFontSizeText(self): + if self.fontSize is not None: + return '+fontsize({:.6g})'.format(self.fontSize) + else: + return '' + + def setText(self, text): + """Set the label's text""" + self.text = text + self.updateCode() + + def setPen(self, pen): + """Set the label's pen""" + self.pen = pen + self.updateCode() + + def moveTo(self, newl): + """Translate the label's location""" + self.location = newl + + +class asyImage: + """A structure containing an image and its format, bbox, and IDTag""" + def __init__(self, image, format, bbox, transfKey=None, keyIndex=0): + self.image = image + self.format = format + self.bbox = bbox + self.IDTag = None + self.key = transfKey + self.keyIndex = keyIndex + +class xasyItem(Qc.QObject): + """A base class for items in the xasy GUI""" + mapString = 'xmap' + setKeyFormatStr = string.Template('$map("{:s}",{:s});').substitute(map=mapString) + setKeyAloneFormatStr = string.Template('$map("{:s}");').substitute(map=mapString) + resizeComment="// Resize to initial xasy transform" + asySize="" + def __init__(self, canvas=None, asyengine=None): + """Initialize the item to an empty item""" + super().__init__() + self.transfKeymap = {} # the new keymap. + # should be a dictionary to a list... + self.asyCode = '' + self.imageList = [] + self.IDTag = None + self.asyfied = False + self.onCanvas = canvas + self.keyBuffer = None + self._asyengine = asyengine + self.drawObjects = [] + self.drawObjectsMap = {} + 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""" + with io.StringIO() as rawCode: + transfCode = self.getTransformCode() + objCode = self.getObjectCode() + + rawCode.write(transfCode) + rawCode.write(objCode) + self.asyCode = rawCode.getvalue() + + return len(transfCode.splitlines()), len(objCode.splitlines()) + + @property + def asyengine(self): + return self._asyengine + + @asyengine.setter + def asyengine(self, value): + self._asyengine = value + + def getCode(self, ps2asymap=identity()): + """Return the code describing the item""" + self.updateCode(ps2asymap) + return self.asyCode + + def getTransformCode(self, asy2psmap=identity()): + raise NotImplementedError + + 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.""" + # image = Image.open(file).transpose(Image.FLIP_TOP_BOTTOM) + if fileformat == 'png': + image = Qg.QImage(file) + elif fileformat == 'svg': + if containsClip: + image = xs.SvgObject(file) + else: + image = Qs.QSvgRenderer(file) + assert image.isValid() + else: + raise Exception('Format not supported!') + 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] + currImage.iqt = image + currImage.originalImage = image + currImage.originalImage.theta = 0.0 + currImage.originalImage.bbox = list(bbox) + currImage.performCanvasTransform = False + + # handle this case if transform is not in the map yet. + # if deleted - set transform to 0, 0, 0, 0, 0 + transfExists = key in self.transfKeymap.keys() + if transfExists: + transfExists = localCount <= len(self.transfKeymap[key]) - 1 + if transfExists: + validKey = not self.transfKeymap[key][localCount].deleted + else: + validKey = False + + 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, + parentObj=self, keyIndex=localCount) + newDrawObj.setBoundingBoxPs(bbox) + newDrawObj.setParent(self) + + self.drawObjects.append(newDrawObj) + + if key not in self.drawObjectsMap.keys(): + self.drawObjectsMap[key] = [newDrawObj] + else: + self.drawObjectsMap[key].append(newDrawObj) + return containsClip + def asyfy(self, force=False): + if self.asyengine is None: + return 1 + if self.asyfied and not force: + return + + self.drawObjects = [] + self.drawObjectsMap.clear() + assert isinstance(self.asyengine, AsymptoteEngine) + self.imageList = [] + + self.unsetKeys.clear() + self.userKeys.clear() + + self.imageHandleQueue = queue.Queue() + worker = threading.Thread(target=self.asyfyThread, args=[]) + worker.start() + item = self.imageHandleQueue.get() + while item != (None,) and item[0] != "ERROR": + if item[0] == "OUTPUT": + print(item[1]) + else: + keepFile = self.handleImageReception(*item) + if not DebugFlags.keepFiles and not keepFile: + try: + os.remove(item[0]) + pass + except OSError: + pass + finally: + pass + item = self.imageHandleQueue.get() + # self.imageHandleQueue.task_done() + worker.join() + + def asyfyThread(self): + """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()) + + fout.write("reset\n") + fout.flush(); + for line in self.getCode().splitlines(): + if DebugFlags.printDeconstTranscript: + print('fout:', line) + fout.write(line+"\n") + fout.write(self.asySize) + fout.write("deconstruct();\n") + fout.write('write(_outpipe,yscale(-1)*currentpicture.calculateTransform(),endl);\n') + fout.write(self.asyengine.xasy) + fout.flush() + + imageInfos = [] # of (box, key) + n = 0 + + keyCounts = {} + + def render(): + for i in range(len(imageInfos)): + box, key, localCount, useClip = imageInfos[i] + l, b, r, t = [float(a) for a in box.split()] + name = "{:s}_{:d}.{:s}".format(self.asyengine.tempDirName, i, fileformat) + + self.imageHandleQueue.put((name, fileformat, (l, -t, r, -b), i, key, localCount, useClip)) + + # key first, box second. + # if key is "Done" + raw_text = fin.readline() + text = "" + if DebugFlags.printDeconstTranscript: + print(raw_text.strip()) + + # template=AsyTempDir+"%d_%d.%s" + fileformat = 'svg' + + while raw_text != "Done\n" and raw_text != "Error\n": +# print(raw_text) + text = fin.readline() # the actual bounding box. + # print('TESTING:', text) + keydata = raw_text.strip().replace('KEY=', '', 1) # key + + clipflag = keydata[-1] == '1' + userkey = keydata[-2] == '1' + keydata = keydata[:-3] + + if not userkey: + self.unsetKeys.add(keydata) # the line and column to replace. + else: + self.userKeys.add(keydata) + +# print(line, col) + + if keydata not in keyCounts.keys(): + keyCounts[keydata] = 0 + + imageInfos.append((text, keydata, keyCounts[keydata], clipflag)) # key-data pair + + # for the next item + keyCounts[keydata] += 1 + + raw_text = fin.readline() + + if DebugFlags.printDeconstTranscript: + print(text.rstrip()) + print(raw_text.rstrip()) + + n += 1 + + if text == "Error\n": + self.imageHandleQueue.put(("ERROR", fin.readline())) + else: + render() + + self.asy2psmap = asyTransform(xu.listize(fin.readline().rstrip(),float)) + 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.""" + + 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() + self.path = path + self.path.asyengine = engine + self.asyfied = True + self.pen = pen + self._asyengine = engine + self.rawIdentifier = '' + self.transfKey = key + self.transfKeymap = {self.transfKey: [transform]} + + @property + def asyengine(self): + return self._asyengine + + @asyengine.setter + def asyengine(self, value: AsymptoteEngine): + self._asyengine = value + self.path.asyengine = value + + def setKey(self, newKey=None): + transform = self.transfKeymap[self.transfKey][0] + + self.transfKey = newKey + self.transfKeymap = {self.transfKey: [transform]} + + def generateDrawObjects(self, forceUpdate=False): + 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.""" + if self.path.nodeSet[-1] == 'cycle': + self.path.nodeSet[-1] = point + self.path.nodeSet.append('cycle') + else: + self.path.nodeSet.append(point) + self.path.computed = False + self.asyfied = False + if len(self.path.nodeSet) > 1 and link is not None: + self.path.linkSet.append(link) + + def clearTransform(self): + """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.""" + if self.path.nodeSet[-1] == 'cycle': + del self.path.nodeSet[-2] + else: + del self.path.nodeSet[-1] + del self.path.linkSet[-1] + self.path.computed = False + 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.""" + if self.path.nodeSet[-1] == 'cycle': + self.path.nodeSet[-2] = point + else: + self.path.nodeSet[-1] = point + self.path.computed = False + self.asyfied = False + + +class xasyShape(xasyDrawnItem): + """An outlined shape drawn on the GUI""" + 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' + + def getTransformCode(self, asy2psmap=identity()): + transf = self.transfKeymap[self.transfKey][0] + if transf == identity(): + return '' + else: + return xasyItem.setKeyFormatStr.format(self.transfKey, transf.getCode(asy2psmap))+'\n' + + def generateDrawObjects(self, forceUpdate=False): + if self.path.containsCurve: + self.path.computeControls() + transf = self.transfKeymap[self.transfKey][0] + + newObj = DrawObject(self.path.toQPainterPath(), None, drawOrder=0, transform=transf, pen=self.pen, + key=self.transfKey) + newObj.originalObj = self + newObj.setParent(self) + return [newObj] + + def __str__(self): + """Create a string describing this shape""" + return "xasyShape code:{:s}".format("\n\t".join(self.getCode().splitlines())) + + +class xasyFilledShape(xasyShape): + """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""" + if path.nodeSet[-1] != 'cycle': + raise Exception("Filled paths must be cyclic") + super().__init__(path, asyengine, pen, transform) + + def getObjectCode(self, asy2psmap=identity()): + return 'fill(KEY="{0}",{1},{2});'.format(self.transfKey, self.path.getCode(asy2psmap), self.pen.getCode())+'\n\n' + + 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.originalObj = self + newObj.setParent(self) + return [newObj] + + def __str__(self): + """Return a string describing this shape""" + return "xasyFilledShape code:{:s}".format("\n\t".join(self.getCode().splitlines())) + + +class xasyText(xasyItem): + """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) + if pen is None: + pen = asyPen(asyengine=asyengine) + if pen.asyEngine is None: + pen.asyEngine = asyengine + 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): + transform = self.transfKeymap[self.transfKey][0] + + self.transfKey = newKey + self.transfKeymap = {self.transfKey: [transform]} + + def getTransformCode(self, asy2psmap=yflip()): + transf = self.transfKeymap[self.transfKey][0] + if transf == yflip(): + # return xasyItem.setKeyAloneFormatStr.format(self.transfKey) + return '' + else: + return xasyItem.setKeyFormatStr.format(self.transfKey, transf.getCode(asy2psmap))+"\n" + + def getObjectCode(self, asy2psmap=yflip()): + return 'label(KEY="{0}",{1});'.format(self.transfKey, self.label.getCode(asy2psmap))+'\n' + + def generateDrawObjects(self, forceUpdate=False): + self.asyfy(forceUpdate) + return self.drawObjects + + def getBoundingBox(self): + self.asyfy() + return self.imageList[0].bbox + + def __str__(self): + return "xasyText code:{:s}".format("\n\t".join(self.getCode().splitlines())) + + +class xasyScript(xasyItem): + """A set of images create from asymptote code. It is always deconstructed.""" + + def __init__(self, canvas, engine, script="", transforms=None, transfKeyMap=None): + """Initialize this script item""" + super().__init__(canvas, asyengine=engine) + if transfKeyMap is not None: + self.transfKeymap = transfKeyMap + else: + self.transfKeymap = {} + + self.script = script + self.key2imagemap = {} + self.namedUnsetKeys = {} + self.keyPrefix = '' + self.scriptAsyfied = False + self.updatedPrefix = True + + def clearTransform(self): + """Reset the transforms for each of the deconstructed images""" + # self.transform = [identity()] * len(self.imageList) + keyCount = {} + + for im in self.imageList: + if im.key not in keyCount.keys(): + keyCount[im.key] = 1 + else: + keyCount[im.key] += 1 + + 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: + for key in self.transfKeymap.keys(): + val = self.transfKeymap[key] + + 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: + 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)) + 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]) } + + def getObjectCode(self, asy2psmap=identity()): + numeric=r'([-+]?(?:(?:\d*\.\d+)|(?:\d+\.?)))' + rSize=re.compile("size\(\("+numeric+","+numeric+","+numeric+"," + +numeric+","+numeric+","+numeric+"\)\); "+ + self.resizeComment) + + newScript = self.getReplacedKeysCode(self.findNonIdKeys()) + with io.StringIO() as rawAsyCode: + for line in newScript.splitlines(): + if(rSize.match(line)): + self.asySize=line.rstrip()+'\n' + else: + raw_line = line.rstrip().replace('\t', ' ' * 4) + rawAsyCode.write(raw_line + '\n') + + self.updatedCode = rawAsyCode.getvalue() + return self.updatedCode + + def setScript(self, script): + """Sets the content of the script item.""" + self.script = script + self.updateCode() + + def setKeyPrefix(self, newPrefix=''): + self.keyPrefix = newPrefix + self.updatedPrefix = False + + def getReplacedKeysCode(self, key2replace: set=None) -> str: + keylist = {} + prefix = '' + + key2replaceSet = self.unsetKeys if key2replace is None else \ + self.unsetKeys & key2replace + + linenum2key = {} + + if not self.updatedPrefix: + prefix = self.keyPrefix + + for key in key2replaceSet: + actualkey = key + + key = key.split(':')[0] + raw_parsed = xu.tryParseKey(key) + assert raw_parsed is not None + line, col = [int(val) for val in raw_parsed.groups()] + if line not in keylist: + keylist[line] = set() + keylist[line].add(col) + linenum2key[(line, col)] = actualkey + self.unsetKeys.discard(key) + + + 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] + if i + 1 in keylist.keys(): + # this case, we have a key. + with io.StringIO() as raw_line: + for j in range(len(curr_str)): + raw_line.write(curr_str[j]) + if j + 1 in keylist[i + 1]: + # at this point, replace keys with xkey + raw_line.write('KEY="{0:s}",'.format(linenum2key[(i + 1, j + 1)])) + self.userKeys.add(linenum2key[(i + 1, j + 1)]) + curr_str = raw_line.getvalue() + # else, skip and just write the line. + raw_str.write(curr_str + '\n') + return raw_str.getvalue() + + def getUnusedKey(self, oldkey) -> str: + baseCounter = 0 + newKey = oldkey + while newKey in self.userKeys: + newKey = oldkey + ':' + str(baseCounter) + 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.""" + super().asyfy() + + # Id --> Transf --> asy-fied --> Transf + # Transf should keep the original, raw transformation + # but for all new drawn objects - assign Id as transform. + + if self.scriptAsyfied: + return + + keyCount = {} + settedKey = {} + + for im in self.imageList: + if im.key in self.unsetKeys and im.key not in settedKey.keys(): + oldkey = im.key + self.unsetKeys.remove(im.key) + im.key = self.getUnusedKey(im.key) + self.unsetKeys.add(im.key) + + for drawobj in self.drawObjectsMap[oldkey]: + drawobj.key = im.key + + self.drawObjectsMap[im.key] = self.drawObjectsMap[oldkey] + self.drawObjectsMap.pop(oldkey) + + settedKey[oldkey] = im.key + elif im.key in settedKey.keys(): + im.key = settedKey[im.key] + + if im.key not in keyCount.keys(): + keyCount[im.key] = 1 + else: + keyCount[im.key] += 1 + + if im.key not in self.key2imagemap.keys(): + self.key2imagemap[im.key] = [im] + else: + self.key2imagemap[im.key].append(im) + + + + for key in keyCount: + if key not in self.transfKeymap.keys(): + self.transfKeymap[key] = [identity()] * keyCount[key] + else: + while len(self.transfKeymap[key]) < keyCount[key]: + self.transfKeymap[key].append(identity()) + + # while len(self.transfKeymap[key]) > keyCount[key]: + # self.transfKeymap[key].pop() + + # change of basis + for keylist in self.transfKeymap.values(): + for i in range(len(keylist)): + if keylist[i] != identity(): + keylist[i] = self.asy2psmap * keylist[i] * self.asy2psmap.inverted() + + self.updateCode() + self.scriptAsyfied = True + + def generateDrawObjects(self, forceUpdate=False): + self.asyfy(forceUpdate) + return self.drawObjects + + def __str__(self): + """Return a string describing this script""" + retVal = "xasyScript\n\tTransforms:\n" + for xform in self.transform: + retVal += "\t" + str(xform) + "\n" + retVal += "\tCode Ommitted" + 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): + super().__init__() + self.drawObject = drawObject + self.mainCanvas = mainCanvas + self.pTransform = transform + self.baseTransform = transform + self.drawOrder = drawOrder + self.btmRightAnchor = btmRightanchor + self.originalObj = parentObj + self.explicitBoundingBox = None + self.useCanvasTransformation = False + self.key = key + self.cachedSvgImg = None + self.cachedDPI = None + self.maxDPI=0 + self.keyIndex = keyIndex + self.pen = pen + self.fill = fill + + def getInteriorScrTransform(self, transform): + """Generates the transform with Interior transform applied beforehand.""" + if isinstance(transform, Qg.QTransform): + transform = asyTransform.fromQTransform(transform) + return self.transform * transform * self.baseTransform.inverted() + + @property + def transform(self): + return self.pTransform + + @transform.setter + def transform(self, value): + self.pTransform = value + + 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) + + @property + def boundingBox(self): + if self.explicitBoundingBox is not None: + testBbox = self.explicitBoundingBox + 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() + + @property + def localBoundingBox(self): + testBbox = self.drawObject.rect() + testBbox.moveTo(self.btmRightAnchor.toPoint()) + return testBbox + + def getScreenTransform(self): + scrTransf = self.baseTransform.toQTransform().inverted()[0] * self.pTransform.toQTransform() + return asyTransform.fromQTransform(scrTransf) + + def draw(self, additionalTransformation=None, applyReverse=False, canvas: Qg.QPainter=None, dpi=300): + if canvas is None: + canvas = self.mainCanvas + if additionalTransformation is None: + additionalTransformation = Qg.QTransform() + + assert canvas.isActive() + + canvas.save() + if self.pen: + oldPen = Qg.QPen(canvas.pen()) + canvas.setPen(self.pen.toQPen()) + else: + oldPen = Qg.QPen() + + if not applyReverse: + canvas.setTransform(additionalTransformation, True) + canvas.setTransform(self.transform.toQTransform(), True) + else: + canvas.setTransform(self.transform.toQTransform(), True) + canvas.setTransform(additionalTransformation, True) + + 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): + threshold = 1.44 + + if self.cachedDPI is None or self.cachedSvgImg is None \ + or dpi > self.maxDPI*threshold: + self.cachedDPI = dpi + self.maxDPI=max(self.maxDPI,dpi) + self.cachedSvgImg = self.drawObject.render(dpi) + + canvas.drawImage(self.explicitBoundingBox, self.cachedSvgImg) + elif isinstance(self.drawObject, Qs.QSvgRenderer): + self.drawObject.render(canvas, self.explicitBoundingBox) + elif isinstance(self.drawObject, Qg.QPainterPath): + path = self.baseTransform.toQTransform().map(self.drawObject) + if self.fill: + if self.pen: + brush = self.pen.toQPen().brush() + else: + brush = Qg.QBrush() + canvas.fillPath(path, brush) + else: + canvas.drawPath(path) + + if self.pen: + canvas.setPen(oldPen) + canvas.restore() + + 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) + return self.boundingBox.marginsAdded(newMargin).contains(coords) + + def getID(self): + return self.originalObj diff --git a/graphics/asymptote/GUI/xasyArgs.py b/graphics/asymptote/GUI/xasyArgs.py new file mode 100644 index 0000000000..045f4bc669 --- /dev/null +++ b/graphics/asymptote/GUI/xasyArgs.py @@ -0,0 +1,23 @@ +#!/usr/bin/env python3 +import argparse +import xasyVersion +import PyQt5.QtCore as Qc +# 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', + 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( + 'filename', help='Filename to load. If empty, initializes empty xasy canvas.', nargs='?', default=None) + + return parser.parse_args() + + +def getArgs(): + return parseArgs(Qc.QCoreApplication.arguments()) diff --git a/graphics/asymptote/GUI/xasyBezierInterface.py b/graphics/asymptote/GUI/xasyBezierInterface.py new file mode 100644 index 0000000000..0a5c689bff --- /dev/null +++ b/graphics/asymptote/GUI/xasyBezierInterface.py @@ -0,0 +1,375 @@ +#!/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 Widg_editBezier as Web + +import InplaceAddObj + +import math + +class CurrentlySelctedType: + none = -1 + node = 0 + ctrlPoint = 1 + +class InteractiveBezierEditor(InplaceAddObj.InplaceObjProcess): + editAccepted = Qc.pyqtSignal() + editRejected = Qc.pyqtSignal() + + def __init__(self, parent: Qc.QObject, obj: x2a.xasyDrawnItem, info: dict={}): + super().__init__(parent) + self.info = info + self.asyPathBackup = x2a.asyPath.fromPath(obj.path) + self.asyPath = obj.path + self.curveMode = self.asyPath.containsCurve + assert isinstance(self.asyPath, x2a.asyPath) + self.transf = obj.transfKeymap[obj.transfKey][0] + self._active = True + + self.currentSelMode = None + # (Node index, Node subindex for ) + self.currentSelIndex = (None, 0) + + self.nodeSelRects = [] + self.ctrlSelRects = [] + + self.setSelectionBoundaries() + + self.lastSelPoint = None + self.preCtrlOffset = None + self.postCtrlOffset = None + self.inTransformMode = False + + self.opt = None + + self.prosectiveNodes = [] + self.prospectiveCtrlPts = [] + + def setSelectionBoundaries(self): + self.nodeSelRects = self.handleNodeSelectionBounds() + + if self.curveMode: + self.ctrlSelRects = self.handleCtrlSelectionBoundaries() + + def handleNodeSelectionBounds(self): + nodeSelectionBoundaries = [] + + for node in self.asyPath.nodeSet: + if node == 'cycle': + nodeSelectionBoundaries.append(None) + continue + + selEpsilon = 6/self.info['magnification'] + newRect = Qc.QRect(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)) + + nodeSelectionBoundaries.append(newRect) + + return nodeSelectionBoundaries + + def handleCtrlSelectionBoundaries(self): + ctrlPointSelBoundaries = [] + + for nodes in self.asyPath.controlSet: + nodea, nodeb = nodes + + selEpsilon = 6/self.info['magnification'] + + newRect = Qc.QRect(0, 0, 2 * selEpsilon, 2 * selEpsilon) + newRectb = Qc.QRect(0, 0, 2 * selEpsilon, 2 * selEpsilon) + + x, y = self.transf * nodea + x2, y2 = self.transf * nodeb + + x = int(round(x)) + y = int(round(y)) + + x2 = int(round(x2)) + y2 = int(round(y2)) + + newRect.moveCenter(Qc.QPoint(x, y)) + newRectb.moveCenter(Qc.QPoint(x2, y2)) + + ctrlPointSelBoundaries.append((newRect, newRectb)) + + return ctrlPointSelBoundaries + + def postDrawPreview(self, canvas: Qg.QPainter): + assert canvas.isActive() + + dashedPen = Qg.QPen(Qc.Qt.DashLine) + dashedPen.setWidthF(1/self.info['magnification']) + # draw the base points + canvas.save() + canvas.setWorldTransform(self.transf.toQTransform(), True) + + epsilonSize = 6/self.info['magnification'] + + if self.info['autoRecompute'] or not self.curveMode: + ctrlPtsColor = 'gray' + else: + ctrlPtsColor = 'red' + + canvas.setPen(dashedPen) + + canvas.drawPath(self.asyPath.toQPainterPath()) + + nodePen = Qg.QPen(Qg.QColor('blue')) + nodePen.setWidthF(1/self.info['magnification']) + + ctlPtsPen = Qg.QPen(Qg.QColor(ctrlPtsColor)) + ctlPtsPen.setWidthF(1/self.info['magnification']) + + for index in range(len(self.asyPath.nodeSet)): + point = self.asyPath.nodeSet[index] + + if point != 'cycle': + basePoint = Qc.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: + if index != 0: + canvas.setPen(ctlPtsPen) + postCtrolSet = self.asyPath.controlSet[index - 1][1] + postCtrlPoint = Qc.QPointF(postCtrolSet[0], postCtrolSet[1]) + canvas.drawEllipse(postCtrlPoint, epsilonSize, epsilonSize) + + canvas.setPen(dashedPen) + canvas.drawLine(basePoint, postCtrlPoint) + + if index != len(self.asyPath.nodeSet) - 1: + canvas.setPen(ctlPtsPen) + preCtrlSet = self.asyPath.controlSet[index][0] + preCtrlPoint = Qc.QPointF(preCtrlSet[0], preCtrlSet[1]) + canvas.drawEllipse(preCtrlPoint, epsilonSize, epsilonSize) + + canvas.setPen(dashedPen) + canvas.drawLine(basePoint, preCtrlPoint) + + canvas.restore() + + def getPreAndPostCtrlPts(self, index): + isCycle = self.asyPath.nodeSet[-1] == 'cycle' + + if index == 0 and not isCycle: + preCtrl = None + else: + preCtrl = self.asyPath.controlSet[index - 1][1] + + if index == len(self.asyPath.nodeSet) - 1 and not isCycle: + postCtrl = None + else: + postCtrl = self.asyPath.controlSet[index % (len(self.asyPath.nodeSet) - 1)][0] + + return preCtrl, postCtrl + + def findLinkingNode(self, index, subindex): + """index and subindex are of the control points list.""" + if subindex == 0: + return index + else: + if self.asyPath.nodeSet[index + 1] == 'cycle': + return 0 + else: + return index + 1 + + def resetObj(self): + self.asyPath.setInfo(self.asyPathBackup) + self.setSelectionBoundaries() + + def mouseDown(self, pos, info, mouseEvent: Qg.QMouseEvent=None): + self.lastSelPoint = pos + if self.inTransformMode: + return + + if self.prosectiveNodes and not self.inTransformMode: + self.currentSelMode = CurrentlySelctedType.node + self.currentSelIndex = (self.prosectiveNodes[0], 0) + self.inTransformMode = True + self.parentNodeIndex = self.currentSelIndex[0] + elif self.prospectiveCtrlPts and not self.inTransformMode: + self.currentSelMode = CurrentlySelctedType.ctrlPoint + 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 + + preCtrl, postCtrl = self.getPreAndPostCtrlPts(self.parentNodeIndex) + + if parentNode == 'cycle': + parentNode = self.asyPath.nodeSet[0] + self.parentNodeIndex = 0 + + if preCtrl is not None: + self.preCtrlOffset = xu.funcOnList( + preCtrl, parentNode, lambda a, b: a - b) + else: + self.preCtrlOffset = None + + if postCtrl is not None: + self.postCtrlOffset = xu.funcOnList( + postCtrl, parentNode, lambda a, b: a - b) + else: + self.postCtrlOffset = None + + def mouseMove(self, pos, event: Qg.QMouseEvent): + if self.currentSelMode is None and not self.inTransformMode: + # in this case, search for prosective nodes. + prospectiveNodes = [] + prospectiveCtrlpts = [] + + for i in range(len(self.nodeSelRects)): + rect = self.nodeSelRects[i] + if rect is None: + continue + if rect.contains(pos): + prospectiveNodes.append(i) + + self.prosectiveNodes = prospectiveNodes + + if not self.info['autoRecompute'] and self.curveMode: + for i in range(len(self.ctrlSelRects)): + recta, rectb = self.ctrlSelRects[i] + + if recta.contains(pos): + prospectiveCtrlpts.append((i, 0)) + + if rectb.contains(pos): + prospectiveCtrlpts.append((i, 1)) + + self.prospectiveCtrlPts = prospectiveCtrlpts + else: + self.prospectiveCtrlPts = [] + + + if self.inTransformMode: + index, subindex = self.currentSelIndex + deltaPos = pos - self.lastSelPoint + newNode = (pos.x(), pos.y()) + if self.currentSelMode == CurrentlySelctedType.node: + # static throughout the moving + if self.asyPath.nodeSet[index] == 'cycle': + return + + self.asyPath.setNode(index, newNode) + # 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 checkPre is not None: + self.asyPath.controlSet[index - 1][1] = xu.funcOnList( + newNode, self.preCtrlOffset, lambda a, b: a + b + ) + if checkPost is not None: + self.asyPath.controlSet[index][0] = xu.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] + + if parentNode == 'cycle': + parentNode = self.asyPath.nodeSet[0] + isCycle = True + else: + isCycle = False + + if self.parentNodeIndex == 0 and self.asyPath.nodeSet[-1] == 'cycle': + isCycle = True + + rawNewNode = xu.funcOnList(newNode, parentNode, lambda a, b: a - b) + rawAngle = math.atan2(rawNewNode[1], rawNewNode[0]) + newNorm = xu.twonorm(rawNewNode) + + + if self.info['editBezierlockMode'] >= Web.LockMode.angleLock: + 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( + 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) + + newPnt = (rawNorm * math.cos(rawAngle + math.pi), + rawNorm * math.sin(rawAngle + math.pi)) + + self.asyPath.controlSet[newIndex][0] = xu.funcOnList( + newPnt, parentNode, lambda a, b: a + b) + else: + if index > 0 or isCycle: + newIndex = -1 if isCycle else index - 1 + oldOtherCtrlPnt = xu.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) + + newPnt = (rawNorm * math.cos(rawAngle + math.pi), + rawNorm * math.sin(rawAngle + math.pi)) + self.asyPath.controlSet[newIndex][1] = xu.funcOnList( + newPnt, parentNode, lambda a, b: a + b) + + def recalculateCtrls(self): + self.quickRecalculateCtrls() + self.setSelectionBoundaries() + + def quickRecalculateCtrls(self): + self.asyPath.controlSet.clear() + self.asyPath.computeControls() + + def mouseRelease(self): + if self.inTransformMode: + self.inTransformMode = False + self.currentSelMode = None + + self.setSelectionBoundaries() + + def forceFinalize(self): + self.objectUpdated.emit() + + def createOptWidget(self, info): + self.opt = Web.Widg_editBezier(self.info, self.curveMode) + self.opt.ui.btnOk.clicked.connect(self.editAccepted) + self.opt.ui.btnCancel.clicked.connect(self.editRejected) + self.opt.ui.btnForceRecompute.clicked.connect(self.recalculateCtrls) + + return self.opt + + def getObject(self): + pass + + def getXasyObject(self): + pass diff --git a/graphics/asymptote/GUI/xasyFile.py b/graphics/asymptote/GUI/xasyFile.py new file mode 100755 index 0000000000..eee6d69a85 --- /dev/null +++ b/graphics/asymptote/GUI/xasyFile.py @@ -0,0 +1,83 @@ +#!/usr/bin/env python3 +########################################################################### +# +# xasyFile implements the loading, parsing, and saving of an xasy file. +# +# +# Author: Orest Shardt +# Created: June 29, 2007 +# +############################################################################ + +from string import * +import xasy2asy as x2a +import io +import re + + +class xasyParseError(Exception): + """A parsing error""" + pass + + +class xasyFileError(Exception): + """An i/o error or other error not related to parsing""" + pass + + +def extractTransform(line): + """Returns key and the new transform.""" + # see https://regex101.com/r/6DqkRJ/4 for info + mapString = x2a.xasyItem.mapString + testMatch = re.match( + r'^{0:s}\s*\(\s*\"([^\"]+)\"\s*,\s*\(([-\d, .]+)\)\s*\)'.format(mapString), line.strip()) + if testMatch is None: + mapOnlyMatch = re.match(r'^{0:s}\s*\(\s *\"([^\"]+)\"\s*\)'.format(mapString), line.strip()) + if mapOnlyMatch is None: + return None + else: + key = mapOnlyMatch.group(1) + return key, x2a.identity() + else: + key = testMatch.group(1) + rawStr = testMatch.group(2) + rawStrArray = rawStr.split(',') + + if len(rawStrArray) != 6: + return None + transf = [float(val.strip()) for val in rawStrArray] + return key, x2a.asyTransform(transf) + + +def extractTransformsFromFile(fileStr): + transfDict = {} + maxItemCount = 0 + with io.StringIO() as rawCode: + for line in fileStr.splitlines(): + test_transf = extractTransform(line.rstrip()) + if test_transf is None: + rawCode.write(line + '\n') + else: + key, transf = test_transf + if key not in transfDict.keys(): + transfDict[key] = [] + transfDict[key].append(transf) + + # see https://regex101.com/r/RgeBVc/2 for regex + + 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 + + +def saveFile(file, xasyItems, asy2psmap): + """Write a list of xasyItems to a file""" + for item in xasyItems: + file.write(item.getTransformCode(asy2psmap)) + + for item in xasyItems: + file.write(item.getObjectCode(asy2psmap)) + + file.write('size('+str(asy2psmap*x2a.yflip())+'); '+ x2a.xasyItem.resizeComment+'\n') diff --git a/graphics/asymptote/GUI/xasyOptions.py b/graphics/asymptote/GUI/xasyOptions.py new file mode 100755 index 0000000000..1923990fae --- /dev/null +++ b/graphics/asymptote/GUI/xasyOptions.py @@ -0,0 +1,159 @@ +#!/usr/bin/env python3 +########################################################################### +# +# xasyOptions provides a mechanism for storing and restoring a user's +# preferences. +# +# +# Author: Orest Shardt +# Created: June 29, 2007 +# +########################################################################### + +import json +import sys +import io +import os +import platform +import shutil + +import configs + +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: + f = io.open(self._defaultOptLocation) + try: + opt = cson.loads(f.read()) + finally: + f.close() + self._defaultOptions = opt + return self._defaultOptions + + def overrideSettings(self): + settingsName = platform.system() + + if settingsName not in self.options: + return + + 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', ''] + + searchIndex = 0 + found = False + currentFile = '' + while searchIndex < len(searchOrder) and not found: + currentFile = os.path.join(folder, self.configName + searchOrder[searchIndex]) + if os.path.isfile(currentFile): + found = True + searchIndex += 1 + + if found: + return os.path.normcase(currentFile) + else: + return os.path.normcase(os.path.join(folder, self.configName + '.cson')) + + def __init__(self, configName, defaultConfigLocation): + self.configName = configName + self.defaultConfigName = defaultConfigLocation + + self._defaultOptions = None + self._defaultOptLocation = os.path.join(defaultConfigLocation) + + self.options = self.defaultOptions() + self.load() + self.overrideSettings() + + def __getitem__(self, item): + return self.options[item] + + def __setitem__(self, key, value): + self.options[key] = value + + def load(self): + fileName = self.settingsFileLocation() + if not os.path.exists(fileName): + # make folder + thedir = os.path.dirname(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") + self.setDefaults() + 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()) + except (IOError, ModuleNotFoundError): + self.setDefaults() + else: + for key in self.options.keys(): + if key in newOptions: + assert isinstance(newOptions[key], type(self.options[key])) + else: + newOptions[key] = self.options[key] + self.options = newOptions + finally: + f.close() + + def setDefaults(self): + self.options = self.defaultOptions() + if sys.platform[:3] == 'win': # for windows, wince, win32, etc + # setAsyPathFromWindowsRegistry() + pass + 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(): + if os.name == 'nt': + import _winreg as registry + # test both registry locations + try: + key = registry.OpenKey(registry.HKEY_LOCAL_MACHINE, + "Software\\Microsoft\\Windows\\CurrentVersion\\App Paths\\Asymptote") + options['asyPath'] = registry.QueryValueEx(key, "Path")[0] + "\\asy.exe" + registry.CloseKey(key) + except: + key = registry.OpenKey(registry.HKEY_LOCAL_MACHINE, + "Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\Asymptote") + options['asyPath'] = registry.QueryValueEx(key, "InstallLocation")[0] + "\\asy.exe" + registry.CloseKey(key) +""" + + +class BasicConfigs: + _configPath = list(configs.__path__)[0] + defaultOpt = xasyOptions( + 'xasyconfig', os.path.join(_configPath, 'xasyconfig.cson')) + keymaps = xasyOptions('xasykeymap', os.path.join( + _configPath, 'xasykeymap.cson')) diff --git a/graphics/asymptote/GUI/xasyStrings.py b/graphics/asymptote/GUI/xasyStrings.py new file mode 100644 index 0000000000..53f83a64f1 --- /dev/null +++ b/graphics/asymptote/GUI/xasyStrings.py @@ -0,0 +1,23 @@ +#!/usr/bin/env python3 + +import gettext + +p = property + +class xasyString: + def __init__(self, lang=None): + s = self + if lang is None: + _ = 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') + + s.fileOpenFailed = _('File Opening Failed.') + s.fileOpenFailedText = _('File could not be opened.') + s.asyfyComplete = _('Ready.') diff --git a/graphics/asymptote/GUI/xasySvg.py b/graphics/asymptote/GUI/xasySvg.py new file mode 100644 index 0000000000..a5325f9bdd --- /dev/null +++ b/graphics/asymptote/GUI/xasySvg.py @@ -0,0 +1,22 @@ +#!/usr/bin/env python3 + +import PyQt5.QtGui as Qg +import PyQt5.QtWidgets as Qw +import io +import subprocess +import sys + +class SvgObject(): + def __init__(self, file: str): + self.file=file + + def render(self, dpi:int) -> Qg.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.') + sys.exit(-1) + + return Qg.QImage.fromData(rawDataProc.stdout.read(), 'PNG') diff --git a/graphics/asymptote/GUI/xasyTransform.py b/graphics/asymptote/GUI/xasyTransform.py new file mode 100644 index 0000000000..928e9011f0 --- /dev/null +++ b/graphics/asymptote/GUI/xasyTransform.py @@ -0,0 +1,24 @@ +#!/usr/bin/env python3 +import xasy2asy as x2a +import PyQt5.QtGui as Qg +import PyQt5.QtCore as Qc +import numpy as np +import math + + +class xasyTransform: + @classmethod + def makeRotTransform(cls, theta, origin): + if isinstance(origin, Qc.QPointF) or isinstance(origin, Qc.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])) + + @classmethod + def makeScaleTransform(cls, sx, sy, origin): + if isinstance(origin, Qc.QPointF) or isinstance(origin, Qc.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)) + diff --git a/graphics/asymptote/GUI/xasyUtils.py b/graphics/asymptote/GUI/xasyUtils.py new file mode 100644 index 0000000000..255e8b6add --- /dev/null +++ b/graphics/asymptote/GUI/xasyUtils.py @@ -0,0 +1,50 @@ +#!/usr/bin/env python3 + +import re +import typing as ty +import math +import itertools + +def tuple2StrWOspaces(val: tuple) -> str: + newStr = ','.join(['{:.6g}'.format(value) for value in val]) + return '({0})'.format(newStr) + +def tryParse(val, typ=float): + try: + return typ(val) + 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 + 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))]) + + +def listize(str, typ, delim='()') -> list: + str = str.strip(delim) + raw_elem = str.split(',') + final_list = [] + if isinstance(typ, (list, tuple)): + for i in range(len(raw_elem)): + if i < len(typ): + curr_typ = typ[i] + else: + curr_typ = typ[-1] + final_list.append(curr_typ(raw_elem[i].strip())) + else: + for elem in raw_elem: + final_list.append(typ(elem.strip())) + return final_list + +def twonorm(vec: ty.Iterable[ty.Union[float, int]]) -> float: + rawSquared = sum(map(lambda x: x*x, vec)) + return math.sqrt(rawSquared) + +def tryParseKey(raw_key): + """Returns None if raw key is not in #.# format""" + # See https://regex101.com/r/6G9MZD/1/ + # for the regex data + return re.fullmatch(r'^(\d+)\.(\d+)$', raw_key) diff --git a/graphics/asymptote/GUI/xasyValidator.py b/graphics/asymptote/GUI/xasyValidator.py new file mode 100644 index 0000000000..264e105441 --- /dev/null +++ b/graphics/asymptote/GUI/xasyValidator.py @@ -0,0 +1,13 @@ +#!/usr/bin/env python3 + +def validateFloat(text): + try: + float(text) + return True + except ValueError: + return False + + +if __name__ == '__main__': + assert validateFloat('0.5') + assert not validateFloat('.-') |