] [-passes ] [-overlap ]\n" +
- " name: Name of the object\n"
- " dia: Tool diameter\n passes: # of tool width\n" +
- " overlap: Fraction of tool diameter to overlap passes"
+ "> isolate [-dia ] [-passes ] [-overlap ] [-combine 0|1]\n" +
+ " name: Name of the object.\n"
+ " dia: Tool diameter\n passes: # of tool width.\n" +
+ " overlap: Fraction of tool diameter to overlap passes." +
+ " combine: combine all passes into one geometry." +
+ " outname: Name of the resulting Geometry object."
},
'cutout': {
'fcn': cutout,
- 'help': "Creates cutout board.\n" +
+ 'help': "Creates board cutout.\n" +
"> cutout [-dia <3.0 (float)>] [-margin <0.0 (float)>] [-gapsize <0.5 (float)>] [-gaps ]\n" +
" name: Name of the object\n" +
- " dia: Tool diameter\n margin: # margin over bounds\n" +
- " gapsize: size of gap\n gaps: type of gaps"
+ " dia: Tool diameter\n" +
+ " margin: Margin over bounds\n" +
+ " gapsize: size of gap\n" +
+ " gaps: type of gaps"
},
'mirror': {
'fcn': mirror,
- 'help': "Mirror board.\n" +
- "> mirror -box [-axis <3.0 (X X|Y)>]\n" +
- " name: Name of the object to mirror\n" +
- " box: Name of object which act as box (cutout for example)\n" +
- " axis: axis mirror over x o y"
+ 'help': "Mirror a layer.\n" +
+ "> mirror -axis [-box | -dist ]\n" +
+ " name: Name of the object (Gerber or Excellon) to mirror.\n" +
+ " box: Name of object which act as box (cutout for example.)\n" +
+ " axis: Mirror axis parallel to the X or Y axis.\n" +
+ " dist: Distance of the mirror axis to the X or Y axis."
+ },
+ 'exteriors': {
+ 'fcn': exteriors,
+ 'help': "Get exteriors of polygons.\n" +
+ "> exteriors [-outname ]\n" +
+ " name: Name of the source Geometry object.\n" +
+ " outname: Name of the resulting Geometry object."
+ },
+ 'interiors': {
+ 'fcn': interiors,
+ 'help': "Get interiors of polygons.\n" +
+ "> interiors [-outname ]\n" +
+ " name: Name of the source Geometry object.\n" +
+ " outname: Name of the resulting Geometry object."
},
'drillcncjob': {
'fcn': drillcncjob,
'help': "Drill CNC job.\n" +
- "> drillcncjob -tools -drillz -travelz -feedrate -outname \n" +
+ "> drillcncjob -tools -drillz " +
+ "-travelz -feedrate -outname " +
+ "[-spindlespeed (int)] [-toolchange (int)] \n" +
" name: Name of the object\n" +
- " tools: coma separated indexes of tools (example: 1,3 or 2)\n" +
- " drillz: drill into material (example: -2)\n" +
- " travelz: travel above material (example: 2)\n" +
- " feedrate: drilling feed rate\n" +
- " outname: name of object to create\n"
+ " tools: Comma separated indexes of tools (example: 1,3 or 2)\n" +
+ " drillz: Drill depth into material (example: -2.0)\n" +
+ " travelz: Travel distance above material (example: 2.0)\n" +
+ " feedrate: Drilling feed rate\n" +
+ " outname: Name of object to create\n" +
+ " spindlespeed: Speed of the spindle in rpm (example: 4000)\n" +
+ " toolchange: Enable tool changes (example: 1)\n"
+ },
+ 'millholes': {
+ 'fcn': drillmillgeometry,
+ 'help': "Create Geometry Object for milling holes from Excellon.\n" +
+ "> millholes -tools -tooldia -outname \n" +
+ " name: Name of the Excellon Object\n" +
+ " tools: Comma separated indexes of tools (example: 1,3 or 2)\n" +
+ " tooldia: Diameter of the milling tool (example: 0.1)\n" +
+ " outname: Name of object to create\n"
},
'scale': {
'fcn': lambda name, factor: self.collection.get_by_name(str(name)).scale(float(factor)),
@@ -2341,12 +2789,13 @@ class App(QtCore.QObject):
'cncjob': {
'fcn': cncjob,
'help': 'Generates a CNC Job from a Geometry Object.\n' +
- '> cncjob [-z_cut ] [-z_move ] [-feedrate ] [-tooldia ] [-outname ]\n' +
+ '> cncjob [-z_cut ] [-z_move ] [-feedrate ] [-tooldia ] [-spindlespeed (int)] [-outname ]\n' +
' name: Name of the source object\n' +
' z_cut: Z-axis cutting position\n' +
' z_move: Z-axis moving position\n' +
' feedrate: Moving speed when cutting\n' +
' tooldia: Tool diameter to show on screen\n' +
+ ' spindlespeed: Speed of the spindle in rpm (example: 4000)\n' +
' outname: Name of the output object'
},
'write_gcode': {
@@ -2393,6 +2842,14 @@ class App(QtCore.QObject):
'> geo_union \n' +
' name: Name of the geometry object.'
},
+ 'join_geometries': {
+ 'fcn': join_geometries,
+ 'help': 'Runs a merge operation (join) on the geometry ' +
+ 'objects.' +
+ '> join_geometries ....\n' +
+ ' out_name: Name of the new geometry object.' +
+ ' obj_name_0... names of the objects to join'
+ },
'add_rect': {
'fcn': add_rectangle,
'help': 'Creates a rectange in the given Geometry object.\n' +
@@ -2459,14 +2916,16 @@ class App(QtCore.QObject):
"gerber": "share/flatcam_icon16.png",
"excellon": "share/drill16.png",
"cncjob": "share/cnc16.png",
- "project": "share/project16.png"
+ "project": "share/project16.png",
+ "svg": "share/geometry16.png"
}
openers = {
'gerber': lambda fname: self.worker_task.emit({'fcn': self.open_gerber, 'params': [fname]}),
'excellon': lambda fname: self.worker_task.emit({'fcn': self.open_excellon, 'params': [fname]}),
'cncjob': lambda fname: self.worker_task.emit({'fcn': self.open_gcode, 'params': [fname]}),
- 'project': self.open_project
+ 'project': self.open_project,
+ 'svg': self.import_svg
}
# Open file
@@ -2526,6 +2985,9 @@ class App(QtCore.QObject):
"""
FlatCAMObj.app = self
+ FCProcess.app = self
+ FCProcessContainer.app = self
+
def version_check(self):
"""
Checks for the latest version of the program. Alerts the
@@ -2547,7 +3009,8 @@ class App(QtCore.QObject):
try:
f = urllib.urlopen(full_url)
except:
- App.log.warning("Failed checking for latest version. Could not connect.")
+ # App.log.warning("Failed checking for latest version. Could not connect.")
+ self.log.warning("Failed checking for latest version. Could not connect.")
self.inform.emit("[warning] Failed checking for latest version. Could not connect.")
return
diff --git a/FlatCAMDraw.py b/FlatCAMDraw.py
index 9d319ef1..fbfdc059 100644
--- a/FlatCAMDraw.py
+++ b/FlatCAMDraw.py
@@ -1,6 +1,8 @@
from PyQt4 import QtGui, QtCore, Qt
import FlatCAMApp
from camlib import *
+from FlatCAMTool import FlatCAMTool
+from ObjectUI import LengthEntry
from shapely.geometry import Polygon, LineString, Point, LinearRing
from shapely.geometry import MultiPoint, MultiPolygon
@@ -14,11 +16,52 @@ from shapely.geometry.base import BaseGeometry
from numpy import arctan2, Inf, array, sqrt, pi, ceil, sin, cos, sign, dot
from numpy.linalg import solve
-from mpl_toolkits.axes_grid.anchored_artists import AnchoredDrawingArea
+#from mpl_toolkits.axes_grid.anchored_artists import AnchoredDrawingArea
from rtree import index as rtindex
+class BufferSelectionTool(FlatCAMTool):
+ """
+ Simple input for buffer distance.
+ """
+
+ toolName = "Buffer Selection"
+
+ def __init__(self, app, fcdraw):
+ FlatCAMTool.__init__(self, app)
+
+ self.fcdraw = fcdraw
+
+ ## Title
+ title_label = QtGui.QLabel("%s " % self.toolName)
+ self.layout.addWidget(title_label)
+
+ ## Form Layout
+ form_layout = QtGui.QFormLayout()
+ self.layout.addLayout(form_layout)
+
+ ## Buffer distance
+ self.buffer_distance_entry = LengthEntry()
+ form_layout.addRow("Buffer distance:", self.buffer_distance_entry)
+
+ ## Buttons
+ hlay = QtGui.QHBoxLayout()
+ self.layout.addLayout(hlay)
+ hlay.addStretch()
+ self.buffer_button = QtGui.QPushButton("Buffer")
+ hlay.addWidget(self.buffer_button)
+
+ self.layout.addStretch()
+
+ ## Signals
+ self.buffer_button.clicked.connect(self.on_buffer)
+
+ def on_buffer(self):
+ buffer_distance = self.buffer_distance_entry.get_value()
+ self.fcdraw.buffer(buffer_distance)
+
+
class DrawToolShape(object):
"""
Encapsulates "shapes" under a common class.
@@ -291,7 +334,7 @@ class FCArc(FCShapeTool):
startangle = arctan2(p1[1] - center[1], p1[0] - center[0])
stopangle = arctan2(p2[1] - center[1], p2[0] - center[0])
self.geometry = DrawToolShape(LineString(arc(center, radius, startangle, stopangle,
- self.direction, self.steps_per_circ)))
+ self.direction, self.steps_per_circ)))
elif self.mode == '132':
p1 = array(self.points[0])
@@ -305,7 +348,7 @@ class FCArc(FCShapeTool):
stopangle = arctan2(p3[1] - center[1], p3[0] - center[0])
self.geometry = DrawToolShape(LineString(arc(center, radius, startangle, stopangle,
- direction, self.steps_per_circ)))
+ direction, self.steps_per_circ)))
else: # self.mode == '12c'
p1 = array(self.points[0])
@@ -414,6 +457,11 @@ class FCPolygon(FCShapeTool):
self.geometry = DrawToolShape(Polygon(self.points))
self.complete = True
+ def on_key(self, key):
+ if key == 'backspace':
+ if len(self.points) > 0:
+ self.points = self.points[0:-1]
+
class FCPath(FCPolygon):
"""
@@ -425,13 +473,18 @@ class FCPath(FCPolygon):
self.complete = True
def utility_geometry(self, data=None):
- if len(self.points) > 1:
+ if len(self.points) > 0:
temp_points = [x for x in self.points]
temp_points.append(data)
return DrawToolUtilityShape(LineString(temp_points))
return None
+ def on_key(self, key):
+ if key == 'backspace':
+ if len(self.points) > 0:
+ self.points = self.points[0:-1]
+
class FCSelect(DrawTool):
def __init__(self, draw_app):
@@ -442,7 +495,10 @@ class FCSelect(DrawTool):
self.start_msg = "Click on geometry to select"
def click(self, point):
- _, closest_shape = self.storage.nearest(point)
+ try:
+ _, closest_shape = self.storage.nearest(point)
+ except StopIteration:
+ return ""
if self.draw_app.key != 'control':
self.draw_app.selected = []
@@ -481,7 +537,7 @@ class FCMove(FCShapeTool):
dx = self.destination[0] - self.origin[0]
dy = self.destination[1] - self.origin[1]
self.geometry = [DrawToolShape(affinity.translate(geom.geo, xoff=dx, yoff=dy))
- for geom in self.draw_app.get_selected()]
+ for geom in self.draw_app.get_selected()]
# Delete old
self.draw_app.delete_selected()
@@ -528,7 +584,9 @@ class FCCopy(FCMove):
########################
class FlatCAMDraw(QtCore.QObject):
def __init__(self, app, disabled=False):
- assert isinstance(app, FlatCAMApp.App)
+ assert isinstance(app, FlatCAMApp.App), \
+ "Expected the app to be a FlatCAMApp.App, got %s" % type(app)
+
super(FlatCAMDraw, self).__init__()
self.app = app
@@ -546,6 +604,7 @@ class FlatCAMDraw(QtCore.QObject):
self.add_polygon_btn = self.drawing_toolbar.addAction(QtGui.QIcon('share/polygon32.png'), 'Add Polygon')
self.add_path_btn = self.drawing_toolbar.addAction(QtGui.QIcon('share/path32.png'), 'Add Path')
self.union_btn = self.drawing_toolbar.addAction(QtGui.QIcon('share/union32.png'), 'Polygon Union')
+ self.intersection_btn = self.drawing_toolbar.addAction(QtGui.QIcon('share/intersection32.png'), 'Polygon Intersection')
self.subtract_btn = self.drawing_toolbar.addAction(QtGui.QIcon('share/subtract32.png'), 'Polygon Subtraction')
self.cutpath_btn = self.drawing_toolbar.addAction(QtGui.QIcon('share/cutpath32.png'), 'Cut Path')
self.move_btn = self.drawing_toolbar.addAction(QtGui.QIcon('share/move32.png'), "Move Objects 'm'")
@@ -573,14 +632,43 @@ class FlatCAMDraw(QtCore.QObject):
self.snap_toolbar.setDisabled(disabled)
self.app.ui.addToolBar(self.snap_toolbar)
+ ### Application menu ###
+ self.menu = QtGui.QMenu("Drawing")
+ self.app.ui.menu.insertMenu(self.app.ui.menutoolaction, self.menu)
+ # self.select_menuitem = self.menu.addAction(QtGui.QIcon('share/pointer16.png'), "Select 'Esc'")
+ # self.add_circle_menuitem = self.menu.addAction(QtGui.QIcon('share/circle16.png'), 'Add Circle')
+ # self.add_arc_menuitem = self.menu.addAction(QtGui.QIcon('share/arc16.png'), 'Add Arc')
+ # self.add_rectangle_menuitem = self.menu.addAction(QtGui.QIcon('share/rectangle16.png'), 'Add Rectangle')
+ # self.add_polygon_menuitem = self.menu.addAction(QtGui.QIcon('share/polygon16.png'), 'Add Polygon')
+ # self.add_path_menuitem = self.menu.addAction(QtGui.QIcon('share/path16.png'), 'Add Path')
+ self.union_menuitem = self.menu.addAction(QtGui.QIcon('share/union16.png'), 'Polygon Union')
+ self.intersection_menuitem = self.menu.addAction(QtGui.QIcon('share/intersection16.png'), 'Polygon Intersection')
+ # self.subtract_menuitem = self.menu.addAction(QtGui.QIcon('share/subtract16.png'), 'Polygon Subtraction')
+ self.cutpath_menuitem = self.menu.addAction(QtGui.QIcon('share/cutpath16.png'), 'Cut Path')
+ # self.move_menuitem = self.menu.addAction(QtGui.QIcon('share/move16.png'), "Move Objects 'm'")
+ # self.copy_menuitem = self.menu.addAction(QtGui.QIcon('share/copy16.png'), "Copy Objects 'c'")
+ self.delete_menuitem = self.menu.addAction(QtGui.QIcon('share/deleteshape16.png'), "Delete Shape '-'")
+ self.buffer_menuitem = self.menu.addAction(QtGui.QIcon('share/buffer16.png'), "Buffer selection 'b'")
+ self.menu.addSeparator()
+
+ self.buffer_menuitem.triggered.connect(self.on_buffer_tool)
+ self.delete_menuitem.triggered.connect(self.on_delete_btn)
+ self.union_menuitem.triggered.connect(self.union)
+ self.intersection_menuitem.triggered.connect(self.intersection)
+ self.cutpath_menuitem.triggered.connect(self.cutpath)
+
### Event handlers ###
- ## Canvas events
- self.canvas.mpl_connect('button_press_event', self.on_canvas_click)
- self.canvas.mpl_connect('motion_notify_event', self.on_canvas_move)
- self.canvas.mpl_connect('key_press_event', self.on_canvas_key)
- self.canvas.mpl_connect('key_release_event', self.on_canvas_key_release)
+ # Connection ids for Matplotlib
+ self.cid_canvas_click = None
+ self.cid_canvas_move = None
+ self.cid_canvas_key = None
+ self.cid_canvas_key_release = None
+
+ # Connect the canvas
+ #self.connect_canvas_event_handlers()
self.union_btn.triggered.connect(self.union)
+ self.intersection_btn.triggered.connect(self.intersection)
self.subtract_btn.triggered.connect(self.subtract)
self.cutpath_btn.triggered.connect(self.cutpath)
self.delete_btn.triggered.connect(self.on_delete_btn)
@@ -663,6 +751,19 @@ class FlatCAMDraw(QtCore.QObject):
def activate(self):
pass
+ def connect_canvas_event_handlers(self):
+ ## Canvas events
+ self.cid_canvas_click = self.canvas.mpl_connect('button_press_event', self.on_canvas_click)
+ self.cid_canvas_move = self.canvas.mpl_connect('motion_notify_event', self.on_canvas_move)
+ self.cid_canvas_key = self.canvas.mpl_connect('key_press_event', self.on_canvas_key)
+ self.cid_canvas_key_release = self.canvas.mpl_connect('key_release_event', self.on_canvas_key_release)
+
+ def disconnect_canvas_event_handlers(self):
+ self.canvas.mpl_disconnect(self.cid_canvas_click)
+ self.canvas.mpl_disconnect(self.cid_canvas_move)
+ self.canvas.mpl_disconnect(self.cid_canvas_key)
+ self.canvas.mpl_disconnect(self.cid_canvas_key_release)
+
def add_shape(self, shape):
"""
Adds a shape to the shape storage.
@@ -678,9 +779,15 @@ class FlatCAMDraw(QtCore.QObject):
self.add_shape(subshape)
return
- assert isinstance(shape, DrawToolShape)
- assert shape.geo is not None
- assert (isinstance(shape.geo, list) and len(shape.geo) > 0) or not isinstance(shape.geo, list)
+ assert isinstance(shape, DrawToolShape), \
+ "Expected a DrawToolShape, got %s" % type(shape)
+
+ assert shape.geo is not None, \
+ "Shape object has empty geometry (None)"
+
+ assert (isinstance(shape.geo, list) and len(shape.geo) > 0) or \
+ not isinstance(shape.geo, list), \
+ "Shape objects has empty geometry ([])"
if isinstance(shape, DrawToolUtilityShape):
self.utility.append(shape)
@@ -688,6 +795,7 @@ class FlatCAMDraw(QtCore.QObject):
self.storage.insert(shape)
def deactivate(self):
+ self.disconnect_canvas_event_handlers()
self.clear()
self.drawing_toolbar.setDisabled(True)
self.snap_toolbar.setDisabled(True) # TODO: Combine and move into tool
@@ -735,9 +843,13 @@ class FlatCAMDraw(QtCore.QObject):
:param fcgeometry: FlatCAMGeometry
:return: None
"""
- assert isinstance(fcgeometry, Geometry)
+ assert isinstance(fcgeometry, Geometry), \
+ "Expected a Geometry, got %s" % type(fcgeometry)
- self.clear()
+ self.deactivate()
+
+ self.connect_canvas_event_handlers()
+ self.select_tool("select")
# Link shapes into editor.
for shape in fcgeometry.flatten():
@@ -748,6 +860,10 @@ class FlatCAMDraw(QtCore.QObject):
self.drawing_toolbar.setDisabled(False)
self.snap_toolbar.setDisabled(False)
+ def on_buffer_tool(self):
+ buff_tool = BufferSelectionTool(self.app, self)
+ buff_tool.run()
+
def on_tool_select(self, tool):
"""
Behavior of the toolbar. Tool initialization.
@@ -780,7 +896,8 @@ class FlatCAMDraw(QtCore.QObject):
:param event: Event object dispatched by Matplotlib
:return: None
"""
- if self.active_tool is not None:
+ # Selection with left mouse button
+ if self.active_tool is not None and event.button is 1:
# Dispatch event to active_tool
msg = self.active_tool.click(self.snap(event.xdata, event.ydata))
self.app.info(msg)
@@ -895,19 +1012,21 @@ class FlatCAMDraw(QtCore.QObject):
self.active_tool.make()
if self.active_tool.complete:
self.on_shape_complete()
+ self.app.info("Done.")
return
### Abort the current action
if event.key == 'escape':
# TODO: ...?
- self.on_tool_select("select")
+ #self.on_tool_select("select")
self.app.info("Cancelled.")
self.delete_utility_geometry()
self.replot()
- self.select_btn.setChecked(True)
- self.on_tool_select('select')
+ # self.select_btn.setChecked(True)
+ # self.on_tool_select('select')
+ self.select_tool('select')
return
### Delete selected object
@@ -920,12 +1039,14 @@ class FlatCAMDraw(QtCore.QObject):
self.move_btn.setChecked(True)
self.on_tool_select('move')
self.active_tool.set_origin(self.snap(event.xdata, event.ydata))
+ self.app.info("Click on target point.")
### Copy
if event.key == 'c':
self.copy_btn.setChecked(True)
self.on_tool_select('copy')
self.active_tool.set_origin(self.snap(event.xdata, event.ydata))
+ self.app.info("Click on target point.")
### Snap
if event.key == 'g':
@@ -933,8 +1054,14 @@ class FlatCAMDraw(QtCore.QObject):
if event.key == 'k':
self.corner_snap_btn.trigger()
+ ### Buffer
+ if event.key == 'b':
+ self.on_buffer_tool()
+
### Propagate to tool
- response = self.active_tool.on_key(event.key)
+ response = None
+ if self.active_tool is not None:
+ response = self.active_tool.on_key(event.key)
if response is not None:
self.app.info(response)
@@ -1081,6 +1208,16 @@ class FlatCAMDraw(QtCore.QObject):
return storage
+ def select_tool(self, toolname):
+ """
+ Selects a drawing tool. Impacts the object and GUI.
+
+ :param toolname: Name of the tool.
+ :return: None
+ """
+ self.tools[toolname]["button"].setChecked(True)
+ self.on_tool_select(toolname)
+
def set_selected(self, shape):
# Remove and add to the end.
@@ -1171,6 +1308,32 @@ class FlatCAMDraw(QtCore.QObject):
self.replot()
+ def intersection(self):
+ """
+ Makes intersectino of selected polygons. Original polygons are deleted.
+
+ :return: None
+ """
+
+ shapes = self.get_selected()
+
+ results = shapes[0].geo
+
+ for shape in shapes[1:]:
+ results = results.intersection(shape.geo)
+
+ # Delete originals.
+ for_deletion = [s for s in self.get_selected()]
+ for shape in for_deletion:
+ self.delete_shape(shape)
+
+ # Selected geometry is now gone!
+ self.selected = []
+
+ self.add_shape(DrawToolShape(results))
+
+ self.replot()
+
def subtract(self):
selected = self.get_selected()
tools = selected[1:]
@@ -1182,6 +1345,23 @@ class FlatCAMDraw(QtCore.QObject):
self.replot()
+ def buffer(self, buf_distance):
+ selected = self.get_selected()
+
+ if len(selected) == 0:
+ self.app.inform.emit("[warning] Nothing selected for buffering.")
+ return
+
+ if not isinstance(buf_distance, float):
+ self.app.inform.emit("[warning] Invalid distance for buffering.")
+ return
+
+ pre_buffer = cascaded_union([t.geo for t in selected])
+ results = pre_buffer.buffer(buf_distance)
+ self.add_shape(DrawToolShape(results))
+
+ self.replot()
+
def distance(pt1, pt2):
return sqrt((pt1[0] - pt2[0]) ** 2 + (pt1[1] - pt2[1]) ** 2)
diff --git a/FlatCAMGUI.py b/FlatCAMGUI.py
index 25462f3e..8bb2445e 100644
--- a/FlatCAMGUI.py
+++ b/FlatCAMGUI.py
@@ -4,6 +4,9 @@ from GUIElements import *
class FlatCAMGUI(QtGui.QMainWindow):
+ # Emitted when persistent window geometry needs to be retained
+ geom_update = QtCore.pyqtSignal(int, int, int, int, name='geomUpdate')
+
def __init__(self, version):
super(FlatCAMGUI, self).__init__()
@@ -25,7 +28,7 @@ class FlatCAMGUI(QtGui.QMainWindow):
# Recent
self.recent = self.menufile.addMenu(QtGui.QIcon('share/folder16.png'), "Open recent ...")
- # Open gerber
+ # Open gerber ...
self.menufileopengerber = QtGui.QAction(QtGui.QIcon('share/folder16.png'), 'Open &Gerber ...', self)
self.menufile.addAction(self.menufileopengerber)
@@ -41,6 +44,10 @@ class FlatCAMGUI(QtGui.QMainWindow):
self.menufileopenproject = QtGui.QAction(QtGui.QIcon('share/folder16.png'), 'Open &Project ...', self)
self.menufile.addAction(self.menufileopenproject)
+ # Import SVG ...
+ self.menufileimportsvg = QtGui.QAction(QtGui.QIcon('share/folder16.png'), 'Import &SVG ...', self)
+ self.menufile.addAction(self.menufileimportsvg)
+
# Save Project
self.menufilesaveproject = QtGui.QAction(QtGui.QIcon('share/floppy16.png'), '&Save Project', self)
self.menufile.addAction(self.menufilesaveproject)
@@ -70,6 +77,7 @@ class FlatCAMGUI(QtGui.QMainWindow):
self.menueditnew = self.menuedit.addAction(QtGui.QIcon('share/new_geo16.png'), 'New Geometry')
self.menueditedit = self.menuedit.addAction(QtGui.QIcon('share/edit16.png'), 'Edit Geometry')
self.menueditok = self.menuedit.addAction(QtGui.QIcon('share/edit_ok16.png'), 'Update Geometry')
+ #self.menueditok.
#self.menueditcancel = self.menuedit.addAction(QtGui.QIcon('share/cancel_edit16.png'), "Cancel Edit")
self.menueditjoin = self.menuedit.addAction(QtGui.QIcon('share/join16.png'), 'Join Geometry')
self.menueditdelete = self.menuedit.addAction(QtGui.QIcon('share/trash16.png'), 'Delete')
@@ -92,7 +100,9 @@ class FlatCAMGUI(QtGui.QMainWindow):
self.menuviewenable = self.menuview.addAction(QtGui.QIcon('share/replot16.png'), 'Enable all plots')
### Tool ###
- self.menutool = self.menu.addMenu('&Tool')
+ #self.menutool = self.menu.addMenu('&Tool')
+ self.menutool = QtGui.QMenu('&Tool')
+ self.menutoolaction = self.menu.addMenu(self.menutool)
self.menutoolshell = self.menutool.addAction(QtGui.QIcon('share/shell16.png'), '&Command Line')
### Help ###
@@ -115,6 +125,7 @@ class FlatCAMGUI(QtGui.QMainWindow):
self.newgeo_btn = self.toolbar.addAction(QtGui.QIcon('share/new_geo32.png'), "New Blank Geometry")
self.editgeo_btn = self.toolbar.addAction(QtGui.QIcon('share/edit32.png'), "Edit Geometry")
self.updategeo_btn = self.toolbar.addAction(QtGui.QIcon('share/edit_ok32.png'), "Update Geometry")
+ self.updategeo_btn.setEnabled(False)
#self.canceledit_btn = self.toolbar.addAction(QtGui.QIcon('share/cancel_edit32.png'), "Cancel Edit")
self.delete_btn = self.toolbar.addAction(QtGui.QIcon('share/delete32.png'), "&Delete")
self.shell_btn = self.toolbar.addAction(QtGui.QIcon('share/shell32.png'), "&Command Line")
@@ -191,7 +202,6 @@ class FlatCAMGUI(QtGui.QMainWindow):
# self.right_layout.setContentsMargins(0, 0, 0, 0)
right_widget.setLayout(self.right_layout)
-
################
### Info bar ###
################
@@ -216,7 +226,10 @@ class FlatCAMGUI(QtGui.QMainWindow):
self.progress_bar = QtGui.QProgressBar()
self.progress_bar.setMinimum(0)
self.progress_bar.setMaximum(100)
- infobar.addWidget(self.progress_bar)
+ #infobar.addWidget(self.progress_bar)
+
+ self.activity_view = FlatCAMActivityView()
+ infobar.addWidget(self.activity_view)
#############
### Icons ###
@@ -231,13 +244,48 @@ class FlatCAMGUI(QtGui.QMainWindow):
self.setWindowIcon(self.app_icon)
self.setGeometry(100, 100, 1024, 650)
- self.setWindowTitle('FlatCAM %s' % version)
+ self.setWindowTitle('FlatCAM %s - Development Version' % version)
self.show()
def closeEvent(self, event):
+ grect = self.geometry()
+ self.geom_update.emit(grect.x(), grect.y(), grect.width(), grect.height())
QtGui.qApp.quit()
+class FlatCAMActivityView(QtGui.QWidget):
+
+ def __init__(self, parent=None):
+ super(FlatCAMActivityView, self).__init__(parent=parent)
+
+ self.setMinimumWidth(200)
+
+ self.icon = QtGui.QLabel(self)
+ self.icon.setGeometry(0, 0, 12, 12)
+ self.movie = QtGui.QMovie("share/active.gif")
+ self.icon.setMovie(self.movie)
+ #self.movie.start()
+
+ layout = QtGui.QHBoxLayout()
+ layout.setContentsMargins(5, 0, 5, 0)
+ layout.setAlignment(QtCore.Qt.AlignLeft)
+ self.setLayout(layout)
+
+ layout.addWidget(self.icon)
+ self.text = QtGui.QLabel(self)
+ self.text.setText("Idle.")
+
+ layout.addWidget(self.text)
+
+ def set_idle(self):
+ self.movie.stop()
+ self.text.setText("Idle.")
+
+ def set_busy(self, msg):
+ self.movie.start()
+ self.text.setText(msg)
+
+
class FlatCAMInfoBar(QtGui.QWidget):
def __init__(self, parent=None):
@@ -256,6 +304,7 @@ class FlatCAMInfoBar(QtGui.QWidget):
self.text = QtGui.QLabel(self)
self.text.setText("Hello!")
+ self.text.setToolTip("Hello!")
layout.addWidget(self.text)
@@ -263,6 +312,7 @@ class FlatCAMInfoBar(QtGui.QWidget):
def set_text_(self, text):
self.text.setText(text)
+ self.text.setToolTip(text)
def set_status(self, text, level="info"):
level = str(level)
@@ -361,6 +411,12 @@ class GerberOptionsGroupUI(OptionsGroupUI):
grid1.addWidget(overlabel, 2, 0)
self.iso_overlap_entry = FloatEntry()
grid1.addWidget(self.iso_overlap_entry, 2, 1)
+
+ self.combine_passes_cb = FCCheckBox(label='Combine Passes')
+ self.combine_passes_cb.setToolTip(
+ "Combine all passes into one object"
+ )
+ grid1.addWidget(self.combine_passes_cb, 3, 0)
## Board cuttout
self.board_cutout_label = QtGui.QLabel("Board cutout: ")
@@ -530,6 +586,23 @@ class ExcellonOptionsGroupUI(OptionsGroupUI):
self.feedrate_entry = LengthEntry()
grid1.addWidget(self.feedrate_entry, 2, 1)
+ toolchangezlabel = QtGui.QLabel('Toolchange Z:')
+ toolchangezlabel.setToolTip(
+ "Tool Z where user can change drill bit\n"
+ )
+ grid1.addWidget(toolchangezlabel, 3, 0)
+ self.toolchangez_entry = LengthEntry()
+ grid1.addWidget(self.toolchangez_entry, 3, 1)
+
+ spdlabel = QtGui.QLabel('Spindle speed:')
+ spdlabel.setToolTip(
+ "Speed of the spindle\n"
+ "in RPM (optional)"
+ )
+ grid1.addWidget(spdlabel, 4, 0)
+ self.spindlespeed_entry = IntEntry(allow_empty=True)
+ grid1.addWidget(self.spindlespeed_entry, 4, 1)
+
class GeometryOptionsGroupUI(OptionsGroupUI):
def __init__(self, parent=None):
@@ -597,6 +670,15 @@ class GeometryOptionsGroupUI(OptionsGroupUI):
self.cnctooldia_entry = LengthEntry()
grid1.addWidget(self.cnctooldia_entry, 3, 1)
+ spdlabel = QtGui.QLabel('Spindle speed:')
+ spdlabel.setToolTip(
+ "Speed of the spindle\n"
+ "in RPM (optional)"
+ )
+ grid1.addWidget(spdlabel, 4, 0)
+ self.cncspindlespeed_entry = IntEntry(allow_empty=True)
+ grid1.addWidget(self.cncspindlespeed_entry, 4, 1)
+
## Paint area
self.paint_label = QtGui.QLabel('Paint Area: ')
self.paint_label.setToolTip(
@@ -680,7 +762,18 @@ class CNCJobOptionsGroupUI(OptionsGroupUI):
)
self.layout.addWidget(self.export_gcode_label)
- # Append text to Gerber
+ # Prepend to G-Code
+ prependlabel = QtGui.QLabel('Prepend to G-Code:')
+ prependlabel.setToolTip(
+ "Type here any G-Code commands you would\n"
+ "like to add at the beginning of the G-Code file."
+ )
+ self.layout.addWidget(prependlabel)
+
+ self.prepend_text = FCTextArea()
+ self.layout.addWidget(self.prepend_text)
+
+ # Append text to G-Code
appendlabel = QtGui.QLabel('Append to G-Code:')
appendlabel.setToolTip(
"Type here any G-Code commands you would\n"
diff --git a/FlatCAMObj.py b/FlatCAMObj.py
index 18e31ece..8b7126a0 100644
--- a/FlatCAMObj.py
+++ b/FlatCAMObj.py
@@ -1,4 +1,5 @@
from PyQt4 import QtCore
+from copy import copy
from ObjectUI import *
import FlatCAMApp
import inspect # TODO: For debugging only.
@@ -25,8 +26,6 @@ class FlatCAMObj(QtCore.QObject):
"""
:param name: Name of the object given by the user.
- :param ui: User interface to interact with the object.
- :type ui: ObjectUI
:return: FlatCAMObj
"""
QtCore.QObject.__init__(self)
@@ -140,7 +139,8 @@ class FlatCAMObj(QtCore.QObject):
def build_ui(self):
"""
- Sets up the UI/form for this object.
+ Sets up the UI/form for this object. Show the UI
+ in the App.
:return: None
:rtype: None
@@ -219,7 +219,6 @@ class FlatCAMObj(QtCore.QObject):
# Clear axes or we will plot on top of them.
self.axes.cla() # TODO: Thread safe?
- # GLib.idle_add(self.axes.cla)
return True
def serialize(self):
@@ -265,6 +264,7 @@ class FlatCAMGerber(FlatCAMObj, Gerber):
"isotooldia": 0.016,
"isopasses": 1,
"isooverlap": 0.15,
+ "combine_passes": True,
"cutouttooldia": 0.07,
"cutoutmargin": 0.2,
"cutoutgapsize": 0.15,
@@ -290,6 +290,14 @@ class FlatCAMGerber(FlatCAMObj, Gerber):
# self.ui.generate_noncopper_button.clicked.connect(self.on_generatenoncopper_button_click)
def set_ui(self, ui):
+ """
+ Maps options with GUI inputs.
+ Connects GUI events to methods.
+
+ :param ui: GUI object.
+ :type ui: GerberObjectUI
+ :return: None
+ """
FlatCAMObj.set_ui(self, ui)
FlatCAMApp.App.log.debug("FlatCAMGerber.set_ui()")
@@ -301,6 +309,7 @@ class FlatCAMGerber(FlatCAMObj, Gerber):
"isotooldia": self.ui.iso_tool_dia_entry,
"isopasses": self.ui.iso_width_entry,
"isooverlap": self.ui.iso_overlap_entry,
+ "combine_passes":self.ui.combine_passes_cb,
"cutouttooldia": self.ui.cutout_tooldia_entry,
"cutoutmargin": self.ui.cutout_margin_entry,
"cutoutgapsize": self.ui.cutout_gap_entry,
@@ -418,7 +427,7 @@ class FlatCAMGerber(FlatCAMObj, Gerber):
# TODO: Do something if this is None. Offer changing name?
self.app.new_object("geometry", follow_name, follow_init)
- def isolate(self, dia=None, passes=None, overlap=None, outname=None):
+ def isolate(self, dia=None, passes=None, overlap=None, outname=None, combine=None):
"""
Creates an isolation routing geometry object in the project.
@@ -428,36 +437,76 @@ class FlatCAMGerber(FlatCAMObj, Gerber):
:param outname: Base name of the output object
:return: None
"""
-
if dia is None:
dia = self.options["isotooldia"]
if passes is None:
passes = int(self.options["isopasses"])
if overlap is None:
- overlap = self.options["isooverlap"] * dia
+ overlap = self.options["isooverlap"]
+ if combine is None:
+ combine = self.options["combine_passes"]
+ else:
+ combine = bool(combine)
base_name = self.options["name"] + "_iso"
base_name = outname or base_name
- for i in range(passes):
+ def generate_envelope(offset, invert):
+ # isolation_geometry produces an envelope that is going on the left of the geometry
+ # (the copper features). To leave the least amount of burrs on the features
+ # the tool needs to travel on the right side of the features (this is called conventional milling)
+ # the first pass is the one cutting all of the features, so it needs to be reversed
+ # the other passes overlap preceding ones and cut the left over copper. It is better for them
+ # to cut on the right side of the left over copper i.e on the left side of the features.
+ geom = self.isolation_geometry(offset)
+ if invert:
+ if type(geom) is MultiPolygon:
+ pl = []
+ for p in geom:
+ pl.append(Polygon(p.exterior.coords[::-1], p.interiors))
+ geom = MultiPolygon(pl)
+ elif type(geom) is Polygon:
+ geom = Polygon(geom.exterior.coords[::-1], geom.interiors)
+ else:
+ raise "Unexpected Geometry"
+ return geom
- offset = (2*i + 1)/2.0 * dia - i*overlap
- if passes > 1:
- iso_name = base_name + str(i+1)
- else:
- iso_name = base_name
+ if combine:
+ iso_name = base_name
# TODO: This is ugly. Create way to pass data into init function.
def iso_init(geo_obj, app_obj):
# Propagate options
geo_obj.options["cnctooldia"] = self.options["isotooldia"]
-
- geo_obj.solid_geometry = self.isolation_geometry(offset)
+ geo_obj.solid_geometry = []
+ for i in range(passes):
+ offset = (2 * i + 1) / 2.0 * dia - i * overlap * dia
+ geom = generate_envelope (offset, i == 0)
+ geo_obj.solid_geometry.append(geom)
app_obj.info("Isolation geometry created: %s" % geo_obj.options["name"])
# TODO: Do something if this is None. Offer changing name?
self.app.new_object("geometry", iso_name, iso_init)
+ else:
+ for i in range(passes):
+
+ offset = (2 * i + 1) / 2.0 * dia - i * overlap * dia
+ if passes > 1:
+ iso_name = base_name + str(i + 1)
+ else:
+ iso_name = base_name
+
+ # TODO: This is ugly. Create way to pass data into init function.
+ def iso_init(geo_obj, app_obj):
+ # Propagate options
+ geo_obj.options["cnctooldia"] = self.options["isotooldia"]
+ geo_obj.solid_geometry = generate_envelope (offset, i == 0)
+ app_obj.info("Isolation geometry created: %s" % geo_obj.options["name"])
+
+ # TODO: Do something if this is None. Offer changing name?
+ self.app.new_object("geometry", iso_name, iso_init)
+
def on_plot_cb_click(self, *args):
if self.muted_ui:
return
@@ -567,7 +616,10 @@ class FlatCAMExcellon(FlatCAMObj, Excellon):
"travelz": 0.1,
"feedrate": 5.0,
# "toolselection": ""
- "tooldia": 0.1
+ "tooldia": 0.1,
+ "toolchange": False,
+ "toolchangez": 1.0,
+ "spindlespeed": None
})
# TODO: Document this.
@@ -596,6 +648,12 @@ class FlatCAMExcellon(FlatCAMObj, Excellon):
dia.setFlags(QtCore.Qt.ItemIsEnabled)
self.ui.tools_table.setItem(i, 1, dia) # Diameter
i += 1
+
+ # sort the tool diameter column
+ self.ui.tools_table.sortItems(1)
+ # all the tools are selected by default
+ self.ui.tools_table.selectColumn(0)
+
self.ui.tools_table.resizeColumnsToContents()
self.ui.tools_table.resizeRowsToContents()
self.ui.tools_table.horizontalHeader().setStretchLastSection(True)
@@ -603,6 +661,14 @@ class FlatCAMExcellon(FlatCAMObj, Excellon):
self.ui.tools_table.setSortingEnabled(True)
def set_ui(self, ui):
+ """
+ Configures the user interface for this object.
+ Connects options to form fields.
+
+ :param ui: User interface object.
+ :type ui: ExcellonObjectUI
+ :return: None
+ """
FlatCAMObj.set_ui(self, ui)
FlatCAMApp.App.log.debug("FlatCAMExcellon.set_ui()")
@@ -613,14 +679,16 @@ class FlatCAMExcellon(FlatCAMObj, Excellon):
"drillz": self.ui.cutz_entry,
"travelz": self.ui.travelz_entry,
"feedrate": self.ui.feedrate_entry,
- # "toolselection": self.ui.tools_entry
- "tooldia": self.ui.tooldia_entry
+ "tooldia": self.ui.tooldia_entry,
+ "toolchange": self.ui.toolchange_cb,
+ "toolchangez": self.ui.toolchangez_entry,
+ "spindlespeed": self.ui.spindlespeed_entry
})
- assert isinstance(self.ui, ExcellonObjectUI)
+ assert isinstance(self.ui, ExcellonObjectUI), \
+ "Expected a ExcellonObjectUI, got %s" % type(self.ui)
self.ui.plot_cb.stateChanged.connect(self.on_plot_cb_click)
self.ui.solid_cb.stateChanged.connect(self.on_solid_cb_click)
- # self.ui.choose_tools_button.clicked.connect(self.show_tool_chooser)
self.ui.generate_cnc_button.clicked.connect(self.on_create_cncjob_button_click)
self.ui.generate_milling_button.clicked.connect(self.on_generate_milling_button_click)
@@ -628,30 +696,46 @@ class FlatCAMExcellon(FlatCAMObj, Excellon):
"""
Returns the keys to the self.tools dictionary corresponding
to the selections on the tool list in the GUI.
+
+ :return: List of tools.
+ :rtype: list
"""
return [str(x.text()) for x in self.ui.tools_table.selectedItems()]
- def on_generate_milling_button_click(self, *args):
- self.app.report_usage("excellon_on_create_milling_button")
- self.read_form()
+ def generate_milling(self, tools=None, outname=None, tooldia=None):
+ """
+ Note: This method is a good template for generic operations as
+ it takes it's options from parameters or otherwise from the
+ object's options and returns a success, msg tuple as feedback
+ for shell operations.
+
+ :return: Success/failure condition tuple (bool, str).
+ :rtype: tuple
+ """
# Get the tools from the list. These are keys
# to self.tools
- tools = self.get_selected_tools_list()
+ if tools is None:
+ tools = self.get_selected_tools_list()
+
+ if outname is None:
+ outname = self.options["name"] + "_mill"
+
+ if tooldia is None:
+ tooldia = self.options["tooldia"]
if len(tools) == 0:
self.app.inform.emit("Please select one or more tools from the list and try again.")
- return
+ return False, "Error: No tools."
for tool in tools:
- if self.tools[tool]["C"] < self.options["tooldia"]:
+ if self.tools[tool]["C"] < tooldia:
self.app.inform.emit("[warning] Milling tool is larger than hole size. Cancelled.")
- return
-
- geo_name = self.options["name"] + "_mill"
+ return False, "Error: Milling tool is larger than hole."
def geo_init(geo_obj, app_obj):
- assert isinstance(geo_obj, FlatCAMGeometry)
+ assert isinstance(geo_obj, FlatCAMGeometry), \
+ "Initializer expected a FlatCAMGeometry, got %s" % type(geo_obj)
app_obj.progress.emit(20)
geo_obj.solid_geometry = []
@@ -660,17 +744,27 @@ class FlatCAMExcellon(FlatCAMObj, Excellon):
if hole['tool'] in tools:
geo_obj.solid_geometry.append(
Point(hole['point']).buffer(self.tools[hole['tool']]["C"] / 2 -
- self.options["tooldia"] / 2).exterior
+ tooldia / 2).exterior
)
def geo_thread(app_obj):
- app_obj.new_object("geometry", geo_name, geo_init)
+ app_obj.new_object("geometry", outname, geo_init)
app_obj.progress.emit(100)
+ # Create a promise with the new name
+ self.app.collection.promise(outname)
+
# Send to worker
- # self.app.worker.add_task(job_thread, [self.app])
self.app.worker_task.emit({'fcn': geo_thread, 'params': [self.app]})
+ return True, ""
+
+ def on_generate_milling_button_click(self, *args):
+ self.app.report_usage("excellon_on_create_milling_button")
+ self.read_form()
+
+ self.generate_milling()
+
def on_create_cncjob_button_click(self, *args):
self.app.report_usage("excellon_on_create_cncjob_button")
self.read_form()
@@ -686,38 +780,38 @@ class FlatCAMExcellon(FlatCAMObj, Excellon):
# Object initialization function for app.new_object()
def job_init(job_obj, app_obj):
- assert isinstance(job_obj, FlatCAMCNCjob)
+ assert isinstance(job_obj, FlatCAMCNCjob), \
+ "Initializer expected a FlatCAMCNCjob, got %s" % type(job_obj)
- # GLib.idle_add(lambda: app_obj.set_progress_bar(0.2, "Creating CNC Job..."))
app_obj.progress.emit(20)
job_obj.z_cut = self.options["drillz"]
job_obj.z_move = self.options["travelz"]
job_obj.feedrate = self.options["feedrate"]
+ job_obj.spindlespeed = self.options["spindlespeed"]
# There could be more than one drill size...
# job_obj.tooldia = # TODO: duplicate variable!
# job_obj.options["tooldia"] =
tools_csv = ','.join(tools)
- # job_obj.generate_from_excellon_by_tool(self, self.options["toolselection"])
- job_obj.generate_from_excellon_by_tool(self, tools_csv)
+ job_obj.generate_from_excellon_by_tool(self, tools_csv,
+ toolchange=self.options["toolchange"],
+ toolchangez=self.options["toolchangez"])
- # GLib.idle_add(lambda: app_obj.set_progress_bar(0.5, "Parsing G-Code..."))
app_obj.progress.emit(50)
job_obj.gcode_parse()
- # GLib.idle_add(lambda: app_obj.set_progress_bar(0.6, "Creating New Geometry..."))
app_obj.progress.emit(60)
job_obj.create_geometry()
- # GLib.idle_add(lambda: app_obj.set_progress_bar(0.8, "Plotting..."))
app_obj.progress.emit(80)
# To be run in separate thread
def job_thread(app_obj):
app_obj.new_object("cncjob", job_name, job_init)
- # GLib.idle_add(lambda: app_obj.set_progress_bar(1.0, "Done!"))
app_obj.progress.emit(100)
- # GLib.timeout_add_seconds(1, lambda: app_obj.set_progress_bar(0.0, ""))
+
+ # Create promise for the new name.
+ self.app.collection.promise(job_name)
# Send to worker
# self.app.worker.add_task(job_thread, [self.app])
@@ -772,33 +866,6 @@ class FlatCAMExcellon(FlatCAMObj, Excellon):
self.axes.plot(x, y, 'g-')
self.app.plotcanvas.auto_adjust_axes()
- # GLib.idle_add(self.app.plotcanvas.auto_adjust_axes)
- # self.emit(QtCore.SIGNAL("plotChanged"), self)
-
- def show_tool_chooser(self):
- # win = Gtk.Window()
- # box = Gtk.Box(spacing=2)
- # box.set_orientation(Gtk.Orientation(1))
- # win.add(box)
- # for tool in self.tools:
- # self.tool_cbs[tool] = Gtk.CheckButton(label=tool + ": " + str(self.tools[tool]))
- # box.pack_start(self.tool_cbs[tool], False, False, 1)
- # button = Gtk.Button(label="Accept")
- # box.pack_start(button, False, False, 1)
- # win.show_all()
- #
- # def on_accept(widget):
- # win.destroy()
- # tool_list = []
- # for toolx in self.tool_cbs:
- # if self.tool_cbs[toolx].get_active():
- # tool_list.append(toolx)
- # self.options["toolselection"] = ", ".join(tool_list)
- # self.to_form()
- #
- # button.connect("activate", on_accept)
- # button.connect("clicked", on_accept)
- return
class FlatCAMCNCjob(FlatCAMObj, CNCjob):
@@ -809,10 +876,15 @@ class FlatCAMCNCjob(FlatCAMObj, CNCjob):
ui_type = CNCObjectUI
def __init__(self, name, units="in", kind="generic", z_move=0.1,
- feedrate=3.0, z_cut=-0.002, tooldia=0.0):
+ feedrate=3.0, z_cut=-0.002, tooldia=0.0,
+ spindlespeed=None):
+
FlatCAMApp.App.log.debug("Creating CNCJob object...")
+
CNCjob.__init__(self, units=units, kind=kind, z_move=z_move,
- feedrate=feedrate, z_cut=z_cut, tooldia=tooldia)
+ feedrate=feedrate, z_cut=z_cut, tooldia=tooldia,
+ spindlespeed=spindlespeed)
+
FlatCAMObj.__init__(self, name)
self.kind = "cncjob"
@@ -820,7 +892,8 @@ class FlatCAMCNCjob(FlatCAMObj, CNCjob):
self.options.update({
"plot": True,
"tooldia": 0.4 / 25.4, # 0.4mm in inches
- "append": ""
+ "append": "",
+ "prepend": ""
})
# Attributes to be included in serialization
@@ -833,12 +906,14 @@ class FlatCAMCNCjob(FlatCAMObj, CNCjob):
FlatCAMApp.App.log.debug("FlatCAMCNCJob.set_ui()")
- assert isinstance(self.ui, CNCObjectUI)
+ assert isinstance(self.ui, CNCObjectUI), \
+ "Expected a CNCObjectUI, got %s" % type(self.ui)
self.form_fields.update({
"plot": self.ui.plot_cb,
"tooldia": self.ui.tooldia_entry,
- "append": self.ui.append_text
+ "append": self.ui.append_text,
+ "prepend": self.ui.prepend_text
})
self.ui.plot_cb.stateChanged.connect(self.on_plot_cb_click)
@@ -862,16 +937,19 @@ class FlatCAMCNCjob(FlatCAMObj, CNCjob):
except TypeError:
filename = QtGui.QFileDialog.getSaveFileName(caption="Export G-Code ...")
+ preamble = str(self.ui.prepend_text.get_value())
postamble = str(self.ui.append_text.get_value())
- self.export_gcode(filename, preamble='', postamble=postamble)
+ self.export_gcode(filename, preamble=preamble, postamble=postamble)
def export_gcode(self, filename, preamble='', postamble=''):
f = open(filename, 'w')
f.write(preamble + '\n' + self.gcode + "\n" + postamble)
f.close()
+ # Just for adding it to the recent files list.
self.app.file_opened.emit("cncjob", filename)
+
self.app.inform.emit("Saved to: " + filename)
def on_plot_cb_click(self, *args):
@@ -915,14 +993,28 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
:param geo_final: Destination FlatCAMGeometry object.
:return: None
"""
- geo_final.solid_geometry = []
+
+ if geo_final.solid_geometry is None:
+ geo_final.solid_geometry = []
+ if type(geo_final.solid_geometry) is not list:
+ geo_final.solid_geometry = [geo_final.solid_geometry]
for geo in geo_list:
- try:
- for shape in geo.solid_geometry:
- geo_final.solid_geometry.append(shape)
- except:
- geo_final.solid_geometry.append(geo)
+
+ # Expand lists
+ if type(geo) is list:
+ FlatCAMGeometry.merge(geo, geo_final)
+
+ # If not list, just append
+ else:
+ geo_final.solid_geometry.append(geo.solid_geometry)
+
+ # try: # Iterable
+ # for shape in geo.solid_geometry:
+ # geo_final.solid_geometry.append(shape)
+ #
+ # except TypeError: # Non-iterable
+ # geo_final.solid_geometry.append(geo.solid_geometry)
def __init__(self, name):
FlatCAMObj.__init__(self, name)
@@ -932,16 +1024,17 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
self.options.update({
"plot": True,
- # "solid": False,
- # "multicolored": False,
"cutz": -0.002,
"travelz": 0.1,
"feedrate": 5.0,
+ "spindlespeed": None,
"cnctooldia": 0.4 / 25.4,
"painttooldia": 0.0625,
"paintoverlap": 0.15,
"paintmargin": 0.01,
- "paintmethod": "standard"
+ "paintmethod": "standard",
+ "multidepth": False,
+ "depthperpass": 0.002
})
# Attributes to be included in serialization
@@ -957,20 +1050,22 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
FlatCAMApp.App.log.debug("FlatCAMGeometry.set_ui()")
- assert isinstance(self.ui, GeometryObjectUI)
+ assert isinstance(self.ui, GeometryObjectUI), \
+ "Expected a GeometryObjectUI, got %s" % type(self.ui)
self.form_fields.update({
"plot": self.ui.plot_cb,
- # "solid": self.ui.sol,
- # "multicolored": self.ui.,
"cutz": self.ui.cutz_entry,
"travelz": self.ui.travelz_entry,
"feedrate": self.ui.cncfeedrate_entry,
+ "spindlespeed": self.ui.cncspindlespeed_entry,
"cnctooldia": self.ui.cnctooldia_entry,
"painttooldia": self.ui.painttooldia_entry,
"paintoverlap": self.ui.paintoverlap_entry,
"paintmargin": self.ui.paintmargin_entry,
- "paintmethod": self.ui.paintmethod_combo
+ "paintmethod": self.ui.paintmethod_combo,
+ "multidepth": self.ui.mpass_cb,
+ "depthperpass": self.ui.maxdepth_entry
})
self.ui.plot_cb.stateChanged.connect(self.on_plot_cb_click)
@@ -990,6 +1085,7 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
# To be called after clicking on the plot.
def doit(event):
+ self.app.info("Painting polygon...")
self.app.plotcanvas.mpl_disconnect(subscription)
point = [event.xdata, event.ydata]
self.paint_poly(point, tooldia, overlap)
@@ -999,80 +1095,136 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
def paint_poly(self, inside_pt, tooldia, overlap):
# Which polygon.
- poly = find_polygon(self.solid_geometry, inside_pt)
+ #poly = find_polygon(self.solid_geometry, inside_pt)
+ poly = self.find_polygon(inside_pt)
# No polygon?
if poly is None:
self.app.log.warning('No polygon found.')
- self.app.inform('[warning] No polygon found.')
+ self.app.inform.emit('[warning] No polygon found.')
return
+ proc = self.app.proc_container.new("Painting polygon.")
+
+ name = self.options["name"] + "_paint"
+
# Initializes the new geometry object
def gen_paintarea(geo_obj, app_obj):
- assert isinstance(geo_obj, FlatCAMGeometry)
+ assert isinstance(geo_obj, FlatCAMGeometry), \
+ "Initializer expected a FlatCAMGeometry, got %s" % type(geo_obj)
#assert isinstance(app_obj, App)
- cp = self.clear_polygon(poly.buffer(-self.options["paintmargin"]), tooldia, overlap=overlap)
if self.options["paintmethod"] == "seed":
- cp = self.clear_polygon2(poly.buffer(-self.options["paintmargin"]), tooldia, overlap=overlap)
- geo_obj.solid_geometry = cp
- geo_obj.options["cnctooldia"] = tooldia
+ cp = self.clear_polygon2(poly.buffer(-self.options["paintmargin"]),
+ tooldia, overlap=overlap)
- name = self.options["name"] + "_paint"
- self.app.new_object("geometry", name, gen_paintarea)
+ else:
+ cp = self.clear_polygon(poly.buffer(-self.options["paintmargin"]),
+ tooldia, overlap=overlap)
+
+ geo_obj.solid_geometry = list(cp.get_objects())
+ geo_obj.options["cnctooldia"] = tooldia
+ self.app.inform.emit("Done.")
+
+ def job_thread(app_obj):
+ try:
+ app_obj.new_object("geometry", name, gen_paintarea)
+ except Exception as e:
+ proc.done()
+ raise e
+ proc.done()
+
+ self.app.inform.emit("Polygon Paint started ...")
+
+ # Promise object with the new name
+ self.app.collection.promise(name)
+
+ # Background
+ self.app.worker_task.emit({'fcn': job_thread, 'params': [self.app]})
def on_generatecnc_button_click(self, *args):
self.app.report_usage("geometry_on_generatecnc_button")
self.read_form()
self.generatecncjob()
- def generatecncjob(self, z_cut=None, z_move=None,
- feedrate=None, tooldia=None, outname=None):
+ def generatecncjob(self,
+ z_cut=None,
+ z_move=None,
+ feedrate=None,
+ tooldia=None,
+ outname=None,
+ spindlespeed=None,
+ multidepth=None,
+ depthperpass=None):
+ """
+ Creates a CNCJob out of this Geometry object. The actual
+ work is done by the target FlatCAMCNCjob object's
+ `generate_from_geometry_2()` method.
+
+ :param z_cut: Cut depth (negative)
+ :param z_move: Hight of the tool when travelling (not cutting)
+ :param feedrate: Feed rate while cutting
+ :param tooldia: Tool diameter
+ :param outname: Name of the new object
+ :param spindlespeed: Spindle speed (RPM)
+ :return: None
+ """
outname = outname if outname is not None else self.options["name"] + "_cnc"
z_cut = z_cut if z_cut is not None else self.options["cutz"]
z_move = z_move if z_move is not None else self.options["travelz"]
feedrate = feedrate if feedrate is not None else self.options["feedrate"]
tooldia = tooldia if tooldia is not None else self.options["cnctooldia"]
+ multidepth = multidepth if multidepth is not None else self.options["multidepth"]
+ depthperpass = depthperpass if depthperpass is not None else self.options["depthperpass"]
+
+ # To allow default value to be "" (optional in gui) and translate to None
+ # if not isinstance(spindlespeed, int):
+ # if isinstance(self.options["spindlespeed"], int) or \
+ # isinstance(self.options["spindlespeed"], float):
+ # spindlespeed = int(self.options["spindlespeed"])
+ # else:
+ # spindlespeed = None
+
+ if spindlespeed is None:
+ # int or None.
+ spindlespeed = self.options['spindlespeed']
# Object initialization function for app.new_object()
# RUNNING ON SEPARATE THREAD!
def job_init(job_obj, app_obj):
- assert isinstance(job_obj, FlatCAMCNCjob)
+ assert isinstance(job_obj, FlatCAMCNCjob), \
+ "Initializer expected a FlatCAMCNCjob, got %s" % type(job_obj)
+
# Propagate options
job_obj.options["tooldia"] = tooldia
- # GLib.idle_add(lambda: app_obj.set_progress_bar(0.2, "Creating CNC Job..."))
app_obj.progress.emit(20)
job_obj.z_cut = z_cut
job_obj.z_move = z_move
job_obj.feedrate = feedrate
-
- # GLib.idle_add(lambda: app_obj.set_progress_bar(0.4, "Analyzing Geometry..."))
+ job_obj.spindlespeed = spindlespeed
app_obj.progress.emit(40)
# TODO: The tolerance should not be hard coded. Just for testing.
- #job_obj.generate_from_geometry(self, tolerance=0.0005)
- job_obj.generate_from_geometry_2(self, tolerance=0.0005)
+ job_obj.generate_from_geometry_2(self,
+ multidepth=multidepth,
+ depthpercut=depthperpass,
+ tolerance=0.0005)
- # GLib.idle_add(lambda: app_obj.set_progress_bar(0.5, "Parsing G-Code..."))
app_obj.progress.emit(50)
job_obj.gcode_parse()
- # TODO: job_obj.create_geometry creates stuff that is not used.
- #GLib.idle_add(lambda: app_obj.set_progress_bar(0.6, "Creating New Geometry..."))
- #job_obj.create_geometry()
-
- # GLib.idle_add(lambda: app_obj.set_progress_bar(0.8, "Plotting..."))
app_obj.progress.emit(80)
# To be run in separate thread
def job_thread(app_obj):
- app_obj.new_object("cncjob", outname, job_init)
- # GLib.idle_add(lambda: app_obj.info("CNCjob created: %s" % job_name))
- # GLib.idle_add(lambda: app_obj.set_progress_bar(1.0, "Done!"))
- # GLib.timeout_add_seconds(1, lambda: app_obj.set_progress_bar(0.0, "Idle"))
- app_obj.inform.emit("CNCjob created: %s" % outname)
- app_obj.progress.emit(100)
+ with self.app.proc_container.new("Generating CNC Job."):
+ app_obj.new_object("cncjob", outname, job_init)
+ app_obj.inform.emit("CNCjob created: %s" % outname)
+ app_obj.progress.emit(100)
+
+ # Create a promise with the name
+ self.app.collection.promise(outname)
# Send to worker
self.app.worker_task.emit({'fcn': job_thread, 'params': [self.app]})
@@ -1204,5 +1356,3 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
self.plot_element(self.solid_geometry)
self.app.plotcanvas.auto_adjust_axes()
- # GLib.idle_add(self.app.plotcanvas.auto_adjust_axes)
- # self.emit(QtCore.SIGNAL("plotChanged"), self)
\ No newline at end of file
diff --git a/FlatCAMProcess.py b/FlatCAMProcess.py
new file mode 100644
index 00000000..db65602e
--- /dev/null
+++ b/FlatCAMProcess.py
@@ -0,0 +1,148 @@
+from FlatCAMGUI import FlatCAMActivityView
+from PyQt4 import QtCore
+import weakref
+
+
+# import logging
+
+# log = logging.getLogger('base2')
+# #log.setLevel(logging.DEBUG)
+# log.setLevel(logging.WARNING)
+# #log.setLevel(logging.INFO)
+# formatter = logging.Formatter('[%(levelname)s] %(message)s')
+# handler = logging.StreamHandler()
+# handler.setFormatter(formatter)
+# log.addHandler(handler)
+
+
+class FCProcess(object):
+
+ app = None
+
+ def __init__(self, descr):
+ self.callbacks = {
+ "done": []
+ }
+ self.descr = descr
+ self.status = "Active"
+
+ def __del__(self):
+ self.done()
+
+ def __enter__(self):
+ pass
+
+ def __exit__(self, exc_type, exc_val, exc_tb):
+ if exc_type is not None:
+ self.app.log.error("Abnormal termination of process!")
+ self.app.log.error(exc_type)
+ self.app.log.error(exc_val)
+ self.app.log.error(exc_tb)
+
+ self.done()
+
+ def done(self):
+ for fcn in self.callbacks["done"]:
+ fcn(self)
+
+ def connect(self, callback, event="done"):
+ if callback not in self.callbacks[event]:
+ self.callbacks[event].append(callback)
+
+ def disconnect(self, callback, event="done"):
+ try:
+ self.callbacks[event].remove(callback)
+ except ValueError:
+ pass
+
+ def set_status(self, status_string):
+ self.status = status_string
+
+ def status_msg(self):
+ return self.descr
+
+
+class FCProcessContainer(object):
+ """
+ This is the process container, or controller (as in MVC)
+ of the Process/Activity tracking.
+
+ FCProcessContainer keeps weak references to the FCProcess'es
+ such that their __del__ method is called when the user
+ looses track of their reference.
+ """
+
+ app = None
+
+ def __init__(self):
+
+ self.procs = []
+
+ def add(self, proc):
+
+ self.procs.append(weakref.ref(proc))
+
+ def new(self, descr):
+ proc = FCProcess(descr)
+
+ proc.connect(self.on_done, event="done")
+
+ self.add(proc)
+
+ self.on_change(proc)
+
+ return proc
+
+ def on_change(self, proc):
+ pass
+
+ def on_done(self, proc):
+ self.remove(proc)
+
+ def remove(self, proc):
+
+ to_be_removed = []
+
+ for pref in self.procs:
+ if pref() == proc or pref() is None:
+ to_be_removed.append(pref)
+
+ for pref in to_be_removed:
+ self.procs.remove(pref)
+
+
+class FCVisibleProcessContainer(QtCore.QObject, FCProcessContainer):
+ something_changed = QtCore.pyqtSignal()
+
+ def __init__(self, view):
+ assert isinstance(view, FlatCAMActivityView), \
+ "Expected a FlatCAMActivityView, got %s" % type(view)
+
+ FCProcessContainer.__init__(self)
+ QtCore.QObject.__init__(self)
+
+ self.view = view
+
+ self.something_changed.connect(self.update_view)
+
+ def on_done(self, proc):
+ self.app.log.debug("FCVisibleProcessContainer.on_done()")
+ super(FCVisibleProcessContainer, self).on_done(proc)
+
+ self.something_changed.emit()
+
+ def on_change(self, proc):
+ self.app.log.debug("FCVisibleProcessContainer.on_change()")
+ super(FCVisibleProcessContainer, self).on_change(proc)
+
+ self.something_changed.emit()
+
+ def update_view(self):
+ if len(self.procs) == 0:
+ self.view.set_idle()
+
+ elif len(self.procs) == 1:
+ self.view.set_busy(self.procs[0]().status_msg())
+
+ else:
+ self.view.set_busy("%d processes running." % len(self.procs))
\ No newline at end of file
diff --git a/FlatCAMTool.py b/FlatCAMTool.py
index b880d918..0aefa646 100644
--- a/FlatCAMTool.py
+++ b/FlatCAMTool.py
@@ -1,11 +1,4 @@
-from PyQt4 import QtGui, QtCore
-from shapely.geometry import Point
-from shapely import affinity
-from math import sqrt
-
-import FlatCAMApp
-from GUIElements import *
-from FlatCAMObj import FlatCAMGerber, FlatCAMExcellon
+from PyQt4 import QtGui
class FlatCAMTool(QtGui.QWidget):
@@ -46,213 +39,3 @@ class FlatCAMTool(QtGui.QWidget):
self.app.ui.notebook.setCurrentWidget(self.app.ui.tool_tab)
self.show()
-
-
-class DblSidedTool(FlatCAMTool):
-
- toolName = "Double-Sided PCB Tool"
-
- def __init__(self, app):
- FlatCAMTool.__init__(self, app)
-
- ## Title
- title_label = QtGui.QLabel("%s " % self.toolName)
- self.layout.addWidget(title_label)
-
- ## Form Layout
- form_layout = QtGui.QFormLayout()
- self.layout.addLayout(form_layout)
-
- ## Layer to mirror
- self.object_combo = QtGui.QComboBox()
- self.object_combo.setModel(self.app.collection)
- form_layout.addRow("Bottom Layer:", self.object_combo)
-
- ## Axis
- self.mirror_axis = RadioSet([{'label': 'X', 'value': 'X'},
- {'label': 'Y', 'value': 'Y'}])
- form_layout.addRow("Mirror Axis:", self.mirror_axis)
-
- ## Axis Location
- self.axis_location = RadioSet([{'label': 'Point', 'value': 'point'},
- {'label': 'Box', 'value': 'box'}])
- form_layout.addRow("Axis Location:", self.axis_location)
-
- ## Point/Box
- self.point_box_container = QtGui.QVBoxLayout()
- form_layout.addRow("Point/Box:", self.point_box_container)
- self.point = EvalEntry()
- self.point_box_container.addWidget(self.point)
- self.box_combo = QtGui.QComboBox()
- self.box_combo.setModel(self.app.collection)
- self.point_box_container.addWidget(self.box_combo)
- self.box_combo.hide()
-
- ## Alignment holes
- self.alignment_holes = EvalEntry()
- form_layout.addRow("Alignment Holes:", self.alignment_holes)
-
- ## Drill diameter for alignment holes
- self.drill_dia = LengthEntry()
- form_layout.addRow("Drill diam.:", self.drill_dia)
-
- ## Buttons
- hlay = QtGui.QHBoxLayout()
- self.layout.addLayout(hlay)
- hlay.addStretch()
- self.create_alignment_hole_button = QtGui.QPushButton("Create Alignment Drill")
- self.mirror_object_button = QtGui.QPushButton("Mirror Object")
- hlay.addWidget(self.create_alignment_hole_button)
- hlay.addWidget(self.mirror_object_button)
-
- self.layout.addStretch()
-
- ## Signals
- self.create_alignment_hole_button.clicked.connect(self.on_create_alignment_holes)
- self.mirror_object_button.clicked.connect(self.on_mirror)
-
- self.axis_location.group_toggle_fn = self.on_toggle_pointbox
-
- ## Initialize form
- self.mirror_axis.set_value('X')
- self.axis_location.set_value('point')
-
- def on_create_alignment_holes(self):
- axis = self.mirror_axis.get_value()
- mode = self.axis_location.get_value()
-
- if mode == "point":
- px, py = self.point.get_value()
- else:
- selection_index = self.box_combo.currentIndex()
- bb_obj = self.app.collection.object_list[selection_index] # TODO: Direct access??
- xmin, ymin, xmax, ymax = bb_obj.bounds()
- px = 0.5*(xmin+xmax)
- py = 0.5*(ymin+ymax)
-
- xscale, yscale = {"X": (1.0, -1.0), "Y": (-1.0, 1.0)}[axis]
-
- dia = self.drill_dia.get_value()
- tools = {"1": {"C": dia}}
-
- holes = self.alignment_holes.get_value()
- drills = []
-
- for hole in holes:
- point = Point(hole)
- point_mirror = affinity.scale(point, xscale, yscale, origin=(px, py))
- drills.append({"point": point, "tool": "1"})
- drills.append({"point": point_mirror, "tool": "1"})
-
- def obj_init(obj_inst, app_inst):
- obj_inst.tools = tools
- obj_inst.drills = drills
- obj_inst.create_geometry()
-
- self.app.new_object("excellon", "Alignment Drills", obj_init)
-
- def on_mirror(self):
- selection_index = self.object_combo.currentIndex()
- fcobj = self.app.collection.object_list[selection_index]
-
- # For now, lets limit to Gerbers and Excellons.
- # assert isinstance(gerb, FlatCAMGerber)
- if not isinstance(fcobj, FlatCAMGerber) and not isinstance(fcobj, FlatCAMExcellon):
- self.info("ERROR: Only Gerber and Excellon objects can be mirrored.")
- return
-
- axis = self.mirror_axis.get_value()
- mode = self.axis_location.get_value()
-
- if mode == "point":
- px, py = self.point.get_value()
- else:
- selection_index = self.box_combo.currentIndex()
- bb_obj = self.app.collection.object_list[selection_index] # TODO: Direct access??
- xmin, ymin, xmax, ymax = bb_obj.bounds()
- px = 0.5*(xmin+xmax)
- py = 0.5*(ymin+ymax)
-
- fcobj.mirror(axis, [px, py])
- fcobj.plot()
-
- def on_toggle_pointbox(self):
- if self.axis_location.get_value() == "point":
- self.point.show()
- self.box_combo.hide()
- else:
- self.point.hide()
- self.box_combo.show()
-
-
-class Measurement(FlatCAMTool):
-
- toolName = "Measurement Tool"
-
- def __init__(self, app):
- FlatCAMTool.__init__(self, app)
-
- # self.setContentsMargins(0, 0, 0, 0)
- self.layout.setMargin(0)
- self.layout.setContentsMargins(0, 0, 3, 0)
-
- self.setSizePolicy(QtGui.QSizePolicy.Ignored, QtGui.QSizePolicy.Maximum)
-
- self.point1 = None
- self.point2 = None
- self.label = QtGui.QLabel("Click on a reference point ...")
- self.label.setFrameStyle(QtGui.QFrame.StyledPanel | QtGui.QFrame.Plain)
- self.label.setMargin(3)
- self.layout.addWidget(self.label)
- # self.layout.setMargin(0)
- self.setVisible(False)
-
- self.click_subscription = None
- self.move_subscription = None
-
- def install(self):
- FlatCAMTool.install(self)
- self.app.ui.right_layout.addWidget(self)
- self.app.plotcanvas.mpl_connect('key_press_event', self.on_key_press)
-
- def run(self):
- self.toggle()
-
- def on_click(self, event):
- if self.point1 is None:
- self.point1 = (event.xdata, event.ydata)
- else:
- self.point2 = copy(self.point1)
- self.point1 = (event.xdata, event.ydata)
- self.on_move(event)
-
- def on_key_press(self, event):
- if event.key == 'r':
- self.toggle()
-
- def toggle(self):
- if self.isVisible():
- self.setVisible(False)
- self.app.plotcanvas.mpl_disconnect(self.move_subscription)
- self.app.plotcanvas.mpl_disconnect(self.click_subscription)
- else:
- self.setVisible(True)
- self.move_subscription = self.app.plotcanvas.mpl_connect('motion_notify_event', self.on_move)
- self.click_subscription = self.app.plotcanvas.mpl_connect('button_press_event', self.on_click)
-
- def on_move(self, event):
- if self.point1 is None:
- self.label.setText("Click on a reference point...")
- else:
- try:
- dx = event.xdata - self.point1[0]
- dy = event.ydata - self.point1[1]
- d = sqrt(dx**2 + dy**2)
- self.label.setText("D = %.4f D(x) = %.4f D(y) = %.4f" % (d, dx, dy))
- except TypeError:
- pass
- if self.update is not None:
- self.update()
-
-
-
diff --git a/FlatCAMWorker.py b/FlatCAMWorker.py
index b0b6c720..528171b6 100644
--- a/FlatCAMWorker.py
+++ b/FlatCAMWorker.py
@@ -1,5 +1,5 @@
from PyQt4 import QtCore
-import FlatCAMApp
+#import FlatCAMApp
class Worker(QtCore.QObject):
@@ -14,13 +14,15 @@ class Worker(QtCore.QObject):
self.name = name
def run(self):
- FlatCAMApp.App.log.debug("Worker Started!")
+ # FlatCAMApp.App.log.debug("Worker Started!")
+ self.app.log.debug("Worker Started!")
# Tasks are queued in the event listener.
self.app.worker_task.connect(self.do_worker_task)
def do_worker_task(self, task):
- FlatCAMApp.App.log.debug("Running task: %s" % str(task))
+ # FlatCAMApp.App.log.debug("Running task: %s" % str(task))
+ self.app.log.debug("Running task: %s" % str(task))
# 'worker_name' property of task allows to target
# specific worker.
@@ -30,4 +32,7 @@ class Worker(QtCore.QObject):
if 'worker_name' not in task and self.name is None:
task['fcn'](*task['params'])
- return
\ No newline at end of file
+ return
+
+ # FlatCAMApp.App.log.debug("Task ignored.")
+ self.app.log.debug("Task ignored.")
\ No newline at end of file
diff --git a/GUIElements.py b/GUIElements.py
index 1555a701..ba240ad9 100644
--- a/GUIElements.py
+++ b/GUIElements.py
@@ -1,7 +1,10 @@
from PyQt4 import QtGui, QtCore
from copy import copy
-import FlatCAMApp
+#import FlatCAMApp
import re
+import logging
+
+log = logging.getLogger('base')
class RadioSet(QtGui.QWidget):
@@ -37,7 +40,7 @@ class RadioSet(QtGui.QWidget):
self.group_toggle_fn = lambda: None
def on_toggle(self):
- FlatCAMApp.App.log.debug("Radio toggled")
+ log.debug("Radio toggled")
radio = self.sender()
if radio.isChecked():
self.group_toggle_fn()
@@ -47,7 +50,7 @@ class RadioSet(QtGui.QWidget):
for choice in self.choices:
if choice['radio'].isChecked():
return choice['value']
- FlatCAMApp.App.log.error("No button was toggled in RadioSet.")
+ log.error("No button was toggled in RadioSet.")
return None
def set_value(self, val):
@@ -55,7 +58,7 @@ class RadioSet(QtGui.QWidget):
if choice['value'] == val:
choice['radio'].setChecked(True)
return
- FlatCAMApp.App.log.error("Value given is not part of this RadioSet: %s" % str(val))
+ log.error("Value given is not part of this RadioSet: %s" % str(val))
class LengthEntry(QtGui.QLineEdit):
@@ -78,21 +81,25 @@ class LengthEntry(QtGui.QLineEdit):
if val is not None:
self.set_text(QtCore.QString(str(val)))
else:
- FlatCAMApp.App.log.warning("Could not interpret entry: %s" % self.get_text())
+ log.warning("Could not interpret entry: %s" % self.get_text())
def get_value(self):
raw = str(self.text()).strip(' ')
- match = self.format_re.search(raw)
+ # match = self.format_re.search(raw)
- if not match:
- return None
try:
- if match.group(2) is not None and match.group(2).upper() in self.scales:
- return float(eval(match.group(1)))*float(self.scales[self.output_units][match.group(2).upper()])
- else:
- return float(eval(match.group(1)))
+ units = raw[-2:]
+ units = self.scales[self.output_units][units.upper()]
+ value = raw[:-2]
+ return float(eval(value))*units
+ except IndexError:
+ value = raw
+ return float(eval(value))
+ except KeyError:
+ value = raw
+ return float(eval(value))
except:
- FlatCAMApp.App.log.warning("Could not parse value in entry: %s" % str(raw))
+ log.warning("Could not parse value in entry: %s" % str(raw))
return None
def set_value(self, val):
@@ -108,30 +115,43 @@ class FloatEntry(QtGui.QLineEdit):
if val is not None:
self.set_text(QtCore.QString(str(val)))
else:
- FlatCAMApp.App.log.warning("Could not interpret entry: %s" % self.text())
+ log.warning("Could not interpret entry: %s" % self.text())
def get_value(self):
raw = str(self.text()).strip(' ')
try:
evaled = eval(raw)
except:
- FlatCAMApp.App.log.error("Could not evaluate: %s" % str(raw))
+ log.error("Could not evaluate: %s" % str(raw))
return None
return float(evaled)
def set_value(self, val):
- self.setText("%.6f"%val)
+ self.setText("%.6f" % val)
class IntEntry(QtGui.QLineEdit):
- def __init__(self, parent=None):
+
+ def __init__(self, parent=None, allow_empty=False, empty_val=None):
super(IntEntry, self).__init__(parent)
+ self.allow_empty = allow_empty
+ self.empty_val = empty_val
def get_value(self):
+
+ if self.allow_empty:
+ if str(self.text()) == "":
+ return self.empty_val
+
return int(self.text())
def set_value(self, val):
+
+ if val == self.empty_val and self.allow_empty:
+ self.setText(QtCore.QString(""))
+ return
+
self.setText(QtCore.QString(str(val)))
@@ -155,14 +175,14 @@ class EvalEntry(QtGui.QLineEdit):
if val is not None:
self.setText(QtCore.QString(str(val)))
else:
- FlatCAMApp.App.log.warning("Could not interpret entry: %s" % self.get_text())
+ log.warning("Could not interpret entry: %s" % self.get_text())
def get_value(self):
raw = str(self.text()).strip(' ')
try:
return eval(raw)
except:
- FlatCAMApp.App.log.error("Could not evaluate: %s" % str(raw))
+ log.error("Could not evaluate: %s" % str(raw))
return None
def set_value(self, val):
@@ -213,18 +233,51 @@ class VerticalScrollArea(QtGui.QScrollArea):
:return:
"""
if event.type() == QtCore.QEvent.Resize and source == self.widget():
- # FlatCAMApp.App.log.debug("VerticalScrollArea: Widget resized:")
- # FlatCAMApp.App.log.debug(" minimumSizeHint().width() = %d" % self.widget().minimumSizeHint().width())
- # FlatCAMApp.App.log.debug(" verticalScrollBar().width() = %d" % self.verticalScrollBar().width())
+ # log.debug("VerticalScrollArea: Widget resized:")
+ # log.debug(" minimumSizeHint().width() = %d" % self.widget().minimumSizeHint().width())
+ # log.debug(" verticalScrollBar().width() = %d" % self.verticalScrollBar().width())
self.setMinimumWidth(self.widget().sizeHint().width() +
self.verticalScrollBar().sizeHint().width())
# if self.verticalScrollBar().isVisible():
- # FlatCAMApp.App.log.debug(" Scroll bar visible")
+ # log.debug(" Scroll bar visible")
# self.setMinimumWidth(self.widget().minimumSizeHint().width() +
# self.verticalScrollBar().width())
# else:
- # FlatCAMApp.App.log.debug(" Scroll bar hidden")
+ # log.debug(" Scroll bar hidden")
# self.setMinimumWidth(self.widget().minimumSizeHint().width())
- return QtGui.QWidget.eventFilter(self, source, event)
\ No newline at end of file
+ return QtGui.QWidget.eventFilter(self, source, event)
+
+
+class OptionalInputSection:
+
+ def __init__(self, cb, optinputs):
+ """
+ Associates the a checkbox with a set of inputs.
+
+ :param cb: Checkbox that enables the optional inputs.
+ :param optinputs: List of widgets that are optional.
+ :return:
+ """
+ assert isinstance(cb, FCCheckBox), \
+ "Expected an FCCheckBox, got %s" % type(cb)
+
+ self.cb = cb
+ self.optinputs = optinputs
+
+ self.on_cb_change()
+ self.cb.stateChanged.connect(self.on_cb_change)
+
+ def on_cb_change(self):
+
+ if self.cb.checkState():
+
+ for widget in self.optinputs:
+ widget.setEnabled(True)
+
+ else:
+
+ for widget in self.optinputs:
+ widget.setEnabled(False)
+
diff --git a/MeasurementTool.py b/MeasurementTool.py
new file mode 100644
index 00000000..f8396d0f
--- /dev/null
+++ b/MeasurementTool.py
@@ -0,0 +1,74 @@
+from PyQt4 import QtGui
+from FlatCAMTool import FlatCAMTool
+from copy import copy
+from math import sqrt
+
+
+class Measurement(FlatCAMTool):
+
+ toolName = "Measurement Tool"
+
+ def __init__(self, app):
+ FlatCAMTool.__init__(self, app)
+
+ # self.setContentsMargins(0, 0, 0, 0)
+ self.layout.setMargin(0)
+ self.layout.setContentsMargins(0, 0, 3, 0)
+
+ self.setSizePolicy(QtGui.QSizePolicy.Ignored, QtGui.QSizePolicy.Maximum)
+
+ self.point1 = None
+ self.point2 = None
+ self.label = QtGui.QLabel("Click on a reference point ...")
+ self.label.setFrameStyle(QtGui.QFrame.StyledPanel | QtGui.QFrame.Plain)
+ self.label.setMargin(3)
+ self.layout.addWidget(self.label)
+ # self.layout.setMargin(0)
+ self.setVisible(False)
+
+ self.click_subscription = None
+ self.move_subscription = None
+
+ def install(self):
+ FlatCAMTool.install(self)
+ self.app.ui.right_layout.addWidget(self)
+ self.app.plotcanvas.mpl_connect('key_press_event', self.on_key_press)
+
+ def run(self):
+ self.toggle()
+
+ def on_click(self, event):
+ if self.point1 is None:
+ self.point1 = (event.xdata, event.ydata)
+ else:
+ self.point2 = copy(self.point1)
+ self.point1 = (event.xdata, event.ydata)
+ self.on_move(event)
+
+ def on_key_press(self, event):
+ if event.key == 'r':
+ self.toggle()
+
+ def toggle(self):
+ if self.isVisible():
+ self.setVisible(False)
+ self.app.plotcanvas.mpl_disconnect(self.move_subscription)
+ self.app.plotcanvas.mpl_disconnect(self.click_subscription)
+ else:
+ self.setVisible(True)
+ self.move_subscription = self.app.plotcanvas.mpl_connect('motion_notify_event', self.on_move)
+ self.click_subscription = self.app.plotcanvas.mpl_connect('button_press_event', self.on_click)
+
+ def on_move(self, event):
+ if self.point1 is None:
+ self.label.setText("Click on a reference point...")
+ else:
+ try:
+ dx = event.xdata - self.point1[0]
+ dy = event.ydata - self.point1[1]
+ d = sqrt(dx**2 + dy**2)
+ self.label.setText("D = %.4f D(x) = %.4f D(y) = %.4f" % (d, dx, dy))
+ except TypeError:
+ pass
+ if self.update is not None:
+ self.update()
diff --git a/ObjectCollection.py b/ObjectCollection.py
index f4f051a9..005f2bcc 100644
--- a/ObjectCollection.py
+++ b/ObjectCollection.py
@@ -1,9 +1,22 @@
-from PyQt4.QtCore import QModelIndex
+#from PyQt4.QtCore import QModelIndex
from FlatCAMObj import *
import inspect # TODO: Remove
import FlatCAMApp
from PyQt4 import Qt, QtGui, QtCore
+
+class KeySensitiveListView(QtGui.QListView):
+ """
+ QtGui.QListView extended to emit a signal on key press.
+ """
+
+ keyPressed = QtCore.pyqtSignal(int)
+
+ def keyPressEvent(self, event):
+ super(KeySensitiveListView, self).keyPressEvent(event)
+ self.keyPressed.emit(event.key())
+
+
class ObjectCollection(QtCore.QAbstractListModel):
"""
Object storage and management.
@@ -34,8 +47,16 @@ class ObjectCollection(QtCore.QAbstractListModel):
self.object_list = []
self.checked_indexes = []
+ # Names of objects that are expected to become available.
+ # For example, when the creation of a new object will run
+ # in the background and will complete some time in the
+ # future. This is a way to reserve the name and to let other
+ # tasks know that they have to wait until available.
+ self.promises = set()
+
### View
- self.view = QtGui.QListView()
+ #self.view = QtGui.QListView()
+ self.view = KeySensitiveListView()
self.view.setSelectionMode(Qt.QAbstractItemView.ExtendedSelection)
self.view.setModel(self)
@@ -44,12 +65,26 @@ class ObjectCollection(QtCore.QAbstractListModel):
## GUI Events
self.view.selectionModel().selectionChanged.connect(self.on_list_selection_change)
self.view.activated.connect(self.on_item_activated)
+ self.view.keyPressed.connect(self.on_key)
+ self.view.clicked.connect(self.on_mouse_down)
- def on_key(self, event):
- print event
+ def promise(self, obj_name):
+ FlatCAMApp.App.log.debug("Object %s has been promised." % obj_name)
+ self.promises.add(obj_name)
+
+ def has_promises(self):
+ return len(self.promises) > 0
+
+ def on_key(self, key):
+
+ # Delete
+ if key == QtCore.Qt.Key_Delete:
+ # Delete via the application to
+ # ensure cleanup of the GUI
+ self.get_active().app.on_delete()
def on_mouse_down(self, event):
- print "Mouse button pressed on list"
+ FlatCAMApp.App.log.debug("Mouse button pressed on list")
def rowCount(self, parent=QtCore.QModelIndex(), *args, **kwargs):
return len(self.object_list)
@@ -78,15 +113,37 @@ class ObjectCollection(QtCore.QAbstractListModel):
def append(self, obj, active=False):
FlatCAMApp.App.log.debug(str(inspect.stack()[1][3]) + " --> OC.append()")
+ name = obj.options["name"]
+
+ # Check promises and clear if exists
+ if name in self.promises:
+ self.promises.remove(name)
+ FlatCAMApp.App.log.debug("Promised object %s became available." % name)
+ FlatCAMApp.App.log.debug("%d promised objects remaining." % len(self.promises))
+
+ # Prevent same name
+ while name in self.get_names():
+ ## Create a new name
+ # Ends with number?
+ FlatCAMApp.App.log.debug("new_object(): Object name (%s) exists, changing." % name)
+ match = re.search(r'(.*[^\d])?(\d+)$', name)
+ if match: # Yes: Increment the number!
+ base = match.group(1) or ''
+ num = int(match.group(2))
+ name = base + str(num + 1)
+ else: # No: add a number!
+ name += "_1"
+ obj.options["name"] = name
+
obj.set_ui(obj.ui_type())
- # Required before appending
+ # Required before appending (Qt MVC)
self.beginInsertRows(QtCore.QModelIndex(), len(self.object_list), len(self.object_list))
# Simply append to the python list
self.object_list.append(obj)
- # Required after appending
+ # Required after appending (Qt MVC)
self.endInsertRows()
def get_names(self):
diff --git a/ObjectUI.py b/ObjectUI.py
index 2a5bf6e8..f54f1c3b 100644
--- a/ObjectUI.py
+++ b/ObjectUI.py
@@ -1,6 +1,8 @@
import sys
from PyQt4 import QtGui, QtCore
-from GUIElements import *
+#from GUIElements import *
+from GUIElements import FCEntry, FloatEntry, EvalEntry, FCCheckBox, \
+ LengthEntry, FCTextArea, IntEntry, RadioSet, OptionalInputSection
class ObjectUI(QtGui.QWidget):
@@ -39,19 +41,23 @@ class ObjectUI(QtGui.QWidget):
self.name_box.addWidget(self.name_entry)
## Box box for custom widgets
+ # This gets populated in offspring implementations.
self.custom_box = QtGui.QVBoxLayout()
layout.addLayout(self.custom_box)
- ## Common to all objects
- ## Scale
+ ###########################
+ ## Common to all objects ##
+ ###########################
+
+ #### Scale ####
self.scale_label = QtGui.QLabel('Scale: ')
self.scale_label.setToolTip(
"Change the size of the object."
)
layout.addWidget(self.scale_label)
- grid1 = QtGui.QGridLayout()
- layout.addLayout(grid1)
+ self.scale_grid = QtGui.QGridLayout()
+ layout.addLayout(self.scale_grid)
# Factor
faclabel = QtGui.QLabel('Factor:')
@@ -59,10 +65,10 @@ class ObjectUI(QtGui.QWidget):
"Factor by which to multiply\n"
"geometric features of this object."
)
- grid1.addWidget(faclabel, 0, 0)
+ self.scale_grid.addWidget(faclabel, 0, 0)
self.scale_entry = FloatEntry()
self.scale_entry.set_value(1.0)
- grid1.addWidget(self.scale_entry, 0, 1)
+ self.scale_grid.addWidget(self.scale_entry, 0, 1)
# GO Button
self.scale_button = QtGui.QPushButton('Scale')
@@ -71,25 +77,25 @@ class ObjectUI(QtGui.QWidget):
)
layout.addWidget(self.scale_button)
- ## Offset
+ #### Offset ####
self.offset_label = QtGui.QLabel('Offset: ')
self.offset_label.setToolTip(
"Change the position of this object."
)
layout.addWidget(self.offset_label)
- grid2 = QtGui.QGridLayout()
- layout.addLayout(grid2)
+ self.offset_grid = QtGui.QGridLayout()
+ layout.addLayout(self.offset_grid)
- self.offset_label = QtGui.QLabel('Vector:')
- self.offset_label.setToolTip(
+ self.offset_vectorlabel = QtGui.QLabel('Vector:')
+ self.offset_vectorlabel.setToolTip(
"Amount by which to move the object\n"
"in the x and y axes in (x, y) format."
)
- grid2.addWidget(self.offset_label, 0, 0)
+ self.offset_grid.addWidget(self.offset_vectorlabel, 0, 0)
self.offsetvector_entry = EvalEntry()
self.offsetvector_entry.setText("(0.0, 0.0)")
- grid2.addWidget(self.offsetvector_entry, 0, 1)
+ self.offset_grid.addWidget(self.offsetvector_entry, 0, 1)
self.offset_button = QtGui.QPushButton('Offset')
self.offset_button.setToolTip(
@@ -106,8 +112,25 @@ class CNCObjectUI(ObjectUI):
"""
def __init__(self, parent=None):
+ """
+ Creates the user interface for CNCJob objects. GUI elements should
+ be placed in ``self.custom_box`` to preserve the layout.
+ """
+
ObjectUI.__init__(self, title='CNC Job Object', icon_file='share/cnc32.png', parent=parent)
+ # Scale and offset are not available for CNCJob objects.
+ # Hiding from the GUI.
+ for i in range(0, self.scale_grid.count()):
+ self.scale_grid.itemAt(i).widget().hide()
+ self.scale_label.hide()
+ self.scale_button.hide()
+
+ for i in range(0, self.offset_grid.count()):
+ self.offset_grid.itemAt(i).widget().hide()
+ self.offset_label.hide()
+ self.offset_button.hide()
+
## Plot options
self.plot_options_label = QtGui.QLabel("Plot Options: ")
self.custom_box.addWidget(self.plot_options_label)
@@ -148,6 +171,17 @@ class CNCObjectUI(ObjectUI):
)
self.custom_box.addWidget(self.export_gcode_label)
+ # Prepend text to Gerber
+ prependlabel = QtGui.QLabel('Prepend to G-Code:')
+ prependlabel.setToolTip(
+ "Type here any G-Code commands you would\n"
+ "like to add to the beginning of the generated file."
+ )
+ self.custom_box.addWidget(prependlabel)
+
+ self.prepend_text = FCTextArea()
+ self.custom_box.addWidget(self.prepend_text)
+
# Append text to Gerber
appendlabel = QtGui.QLabel('Append to G-Code:')
appendlabel.setToolTip(
@@ -188,7 +222,9 @@ class GeometryObjectUI(ObjectUI):
)
self.custom_box.addWidget(self.plot_cb)
- ## Create CNC Job
+ #-----------------------------------
+ # Create CNC Job
+ #-----------------------------------
self.cncjob_label = QtGui.QLabel('Create CNC Job: ')
self.cncjob_label.setToolTip(
"Create a CNC Job object\n"
@@ -239,15 +275,48 @@ class GeometryObjectUI(ObjectUI):
self.cnctooldia_entry = LengthEntry()
grid1.addWidget(self.cnctooldia_entry, 3, 1)
+ # Spindlespeed
+ spdlabel = QtGui.QLabel('Spindle speed:')
+ spdlabel.setToolTip(
+ "Speed of the spindle\n"
+ "in RPM (optional)"
+ )
+ grid1.addWidget(spdlabel, 4, 0)
+ self.cncspindlespeed_entry = IntEntry(allow_empty=True)
+ grid1.addWidget(self.cncspindlespeed_entry, 4, 1)
+
+ # Multi-pass
+ mpasslabel = QtGui.QLabel('Multi-Depth:')
+ mpasslabel.setToolTip(
+ "Use multiple passes to limit\n"
+ "the cut depth in each pass. Will\n"
+ "cut multiple times until Cut Z is\n"
+ "reached."
+ )
+ grid1.addWidget(mpasslabel, 5, 0)
+ self.mpass_cb = FCCheckBox()
+ grid1.addWidget(self.mpass_cb, 5, 1)
+
+ maxdepthlabel = QtGui.QLabel('Depth/pass:')
+ maxdepthlabel.setToolTip(
+ "Depth of each pass (positive)."
+ )
+ grid1.addWidget(maxdepthlabel, 6, 0)
+ self.maxdepth_entry = LengthEntry()
+ grid1.addWidget(self.maxdepth_entry, 6, 1)
+
+ self.ois_mpass = OptionalInputSection(self.mpass_cb, [self.maxdepth_entry])
+
+ # Button
self.generate_cnc_button = QtGui.QPushButton('Generate')
self.generate_cnc_button.setToolTip(
"Generate the CNC Job object."
)
self.custom_box.addWidget(self.generate_cnc_button)
- ################
- ## Paint area ##
- ################
+ #------------------------------
+ # Paint area
+ #------------------------------
self.paint_label = QtGui.QLabel('Paint Area: ')
self.paint_label.setToolTip(
"Creates tool paths to cover the\n"
@@ -323,9 +392,12 @@ class ExcellonObjectUI(ObjectUI):
"""
def __init__(self, parent=None):
- ObjectUI.__init__(self, title='Excellon Object', icon_file='share/drill32.png', parent=parent)
+ ObjectUI.__init__(self, title='Excellon Object',
+ icon_file='share/drill32.png',
+ parent=parent)
+
+ #### Plot options ####
- ## Plot options
self.plot_options_label = QtGui.QLabel("Plot Options: ")
self.custom_box.addWidget(self.plot_options_label)
@@ -342,7 +414,8 @@ class ExcellonObjectUI(ObjectUI):
)
grid0.addWidget(self.solid_cb, 0, 1)
- ## Tools
+ #### Tools ####
+
self.tools_table_label = QtGui.QLabel('Tools ')
self.tools_table_label.setToolTip(
"Tools in this Excellon object."
@@ -352,7 +425,8 @@ class ExcellonObjectUI(ObjectUI):
self.tools_table.setFixedHeight(100)
self.custom_box.addWidget(self.tools_table)
- ## Create CNC Job
+ #### Create CNC Job ####
+
self.cncjob_label = QtGui.QLabel('Create CNC Job ')
self.cncjob_label.setToolTip(
"Create a CNC Job object\n"
@@ -390,6 +464,37 @@ class ExcellonObjectUI(ObjectUI):
self.feedrate_entry = LengthEntry()
grid1.addWidget(self.feedrate_entry, 2, 1)
+ # Tool change:
+ toolchlabel = QtGui.QLabel("Tool change:")
+ toolchlabel.setToolTip(
+ "Include tool-change sequence\n"
+ "in G-Code (Pause for tool change)."
+ )
+ self.toolchange_cb = FCCheckBox()
+ grid1.addWidget(toolchlabel, 3, 0)
+ grid1.addWidget(self.toolchange_cb, 3, 1)
+
+ # Tool change Z:
+ toolchzlabel = QtGui.QLabel("Tool change Z:")
+ toolchzlabel.setToolTip(
+ "Z-axis position (height) for\n"
+ "tool change."
+ )
+ grid1.addWidget(toolchzlabel, 4, 0)
+ self.toolchangez_entry = LengthEntry()
+ grid1.addWidget(self.toolchangez_entry, 4, 1)
+ self.ois_tcz = OptionalInputSection(self.toolchange_cb, [self.toolchangez_entry])
+
+ # Spindlespeed
+ spdlabel = QtGui.QLabel('Spindle speed:')
+ spdlabel.setToolTip(
+ "Speed of the spindle\n"
+ "in RPM (optional)"
+ )
+ grid1.addWidget(spdlabel, 5, 0)
+ self.spindlespeed_entry = IntEntry(allow_empty=True)
+ grid1.addWidget(self.spindlespeed_entry, 5, 1)
+
choose_tools_label = QtGui.QLabel(
"Select from the tools section above\n"
"the tools you want to include."
@@ -402,7 +507,7 @@ class ExcellonObjectUI(ObjectUI):
)
self.custom_box.addWidget(self.generate_cnc_button)
- ## Milling Holes
+ #### Milling Holes ####
self.mill_hole_label = QtGui.QLabel('Mill Holes ')
self.mill_hole_label.setToolTip(
"Create Geometry for milling holes."
@@ -432,6 +537,7 @@ class ExcellonObjectUI(ObjectUI):
)
self.custom_box.addWidget(self.generate_milling_button)
+
class GerberObjectUI(ObjectUI):
"""
User interface for Gerber objects.
@@ -503,6 +609,14 @@ class GerberObjectUI(ObjectUI):
self.iso_overlap_entry = FloatEntry()
grid1.addWidget(self.iso_overlap_entry, 2, 1)
+ # combine all passes CB
+ self.combine_passes_cb = FCCheckBox(label='Combine Passes')
+ self.combine_passes_cb.setToolTip(
+ "Combine all passes into one object"
+ )
+ grid1.addWidget(self.combine_passes_cb, 3, 0)
+
+
self.generate_iso_button = QtGui.QPushButton('Generate Geometry')
self.generate_iso_button.setToolTip(
"Create the Geometry Object\n"
diff --git a/PlotCanvas.py b/PlotCanvas.py
index 008b7856..94469d2b 100644
--- a/PlotCanvas.py
+++ b/PlotCanvas.py
@@ -7,17 +7,108 @@
############################################################
from PyQt4 import QtGui, QtCore
+
+# Prevent conflict with Qt5 and above.
+from matplotlib import use as mpl_use
+mpl_use("Qt4Agg")
+
from matplotlib.figure import Figure
from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvas
+from matplotlib.backends.backend_agg import FigureCanvasAgg
import FlatCAMApp
+import logging
+
+log = logging.getLogger('base')
-class PlotCanvas:
+class CanvasCache(QtCore.QObject):
+ """
+
+ Case story #1:
+
+ 1) No objects in the project.
+ 2) Object is created (new_object() emits object_created(obj)).
+ on_object_created() adds (i) object to collection and emits
+ (ii) new_object_available() then calls (iii) object.plot()
+ 3) object.plot() creates axes if necessary on
+ app.collection.figure. Then plots on it.
+ 4) Plots on a cache-size canvas (in background).
+ 5) Plot completes. Bitmap is generated.
+ 6) Visible canvas is painted.
+
+ """
+
+ # Signals:
+ # A bitmap is ready to be displayed.
+ new_screen = QtCore.pyqtSignal()
+
+ def __init__(self, plotcanvas, app, dpi=50):
+
+ super(CanvasCache, self).__init__()
+
+ self.app = app
+
+ self.plotcanvas = plotcanvas
+ self.dpi = dpi
+
+ self.figure = Figure(dpi=dpi)
+
+ self.axes = self.figure.add_axes([0.0, 0.0, 1.0, 1.0], alpha=1.0)
+ self.axes.set_frame_on(False)
+ self.axes.set_xticks([])
+ self.axes.set_yticks([])
+
+ self.canvas = FigureCanvasAgg(self.figure)
+
+ self.cache = None
+
+ def run(self):
+
+ log.debug("CanvasCache Thread Started!")
+
+ self.plotcanvas.update_screen_request.connect(self.on_update_req)
+
+ self.app.new_object_available.connect(self.on_new_object_available)
+
+ def on_update_req(self, extents):
+ """
+ Event handler for an updated display request.
+
+ :param extents: [xmin, xmax, ymin, ymax, zoom(optional)]
+ """
+
+ log.debug("Canvas update requested: %s" % str(extents))
+
+ # Note: This information below might be out of date. Establish
+ # a protocol regarding when to change the canvas in the main
+ # thread and when to check these values here in the background,
+ # or pass this data in the signal (safer).
+ log.debug("Size: %s [px]" % str(self.plotcanvas.get_axes_pixelsize()))
+ log.debug("Density: %s [units/px]" % str(self.plotcanvas.get_density()))
+
+ # Move the requested screen portion to the main thread
+ # and inform about the update:
+
+ self.new_screen.emit()
+
+ # Continue to update the cache.
+
+ def on_new_object_available(self):
+
+ log.debug("A new object is available. Should plot it!")
+
+
+class PlotCanvas(QtCore.QObject):
"""
Class handling the plotting area in the application.
"""
- def __init__(self, container):
+ # Signals:
+ # Request for new bitmap to display. The parameter
+ # is a list with [xmin, xmax, ymin, ymax, zoom(optional)]
+ update_screen_request = QtCore.pyqtSignal(list)
+
+ def __init__(self, container, app):
"""
The constructor configures the Matplotlib figure that
will contain all plots, creates the base axes and connects
@@ -26,6 +117,11 @@ class PlotCanvas:
:param container: The parent container in which to draw plots.
:rtype: PlotCanvas
"""
+
+ super(PlotCanvas, self).__init__()
+
+ self.app = app
+
# Options
self.x_margin = 15 # pixels
self.y_margin = 25 # Pixels
@@ -43,8 +139,11 @@ class PlotCanvas:
self.axes.set_aspect(1)
self.axes.grid(True)
- # The canvas is the top level container (Gtk.DrawingArea)
+ # The canvas is the top level container (FigureCanvasQTAgg)
self.canvas = FigureCanvas(self.figure)
+ # self.canvas.setFocusPolicy(QtCore.Qt.ClickFocus)
+ # self.canvas.setFocus()
+
#self.canvas.set_hexpand(1)
#self.canvas.set_vexpand(1)
#self.canvas.set_can_focus(True) # For key press
@@ -57,7 +156,18 @@ class PlotCanvas:
# Update every time the canvas is re-drawn.
self.background = self.canvas.copy_from_bbox(self.axes.bbox)
+ ### Bitmap Cache
+ self.cache = CanvasCache(self, self.app)
+ self.cache_thread = QtCore.QThread()
+ self.cache.moveToThread(self.cache_thread)
+ super(PlotCanvas, self).connect(self.cache_thread, QtCore.SIGNAL("started()"), self.cache.run)
+ # self.connect()
+ self.cache_thread.start()
+ self.cache.new_screen.connect(self.on_new_screen)
+
# Events
+ self.canvas.mpl_connect('button_press_event', self.on_mouse_press)
+ self.canvas.mpl_connect('button_release_event', self.on_mouse_release)
self.canvas.mpl_connect('motion_notify_event', self.on_mouse_move)
#self.canvas.connect('configure-event', self.auto_adjust_axes)
self.canvas.mpl_connect('resize_event', self.auto_adjust_axes)
@@ -66,10 +176,18 @@ class PlotCanvas:
self.canvas.mpl_connect('scroll_event', self.on_scroll)
self.canvas.mpl_connect('key_press_event', self.on_key_down)
self.canvas.mpl_connect('key_release_event', self.on_key_up)
+ self.canvas.mpl_connect('draw_event', self.on_draw)
self.mouse = [0, 0]
self.key = None
+ self.pan_axes = []
+ self.panning = False
+
+ def on_new_screen(self):
+
+ log.debug("Cache updated the screen!")
+
def on_key_down(self, event):
"""
@@ -110,7 +228,7 @@ class PlotCanvas:
def connect(self, event_name, callback):
"""
- Attach an event handler to the canvas through the native GTK interface.
+ Attach an event handler to the canvas through the native Qt interface.
:param event_name: Name of the event
:type event_name: str
@@ -140,7 +258,7 @@ class PlotCanvas:
self.axes.grid(True)
# Re-draw
- self.canvas.draw()
+ self.canvas.draw_idle()
def adjust_axes(self, xmin, ymin, xmax, ymax):
"""
@@ -196,9 +314,11 @@ class PlotCanvas:
ax.set_ylim((ymin, ymax))
ax.set_position([x_ratio, y_ratio, 1 - 2 * x_ratio, 1 - 2 * y_ratio])
- # Re-draw
+ # Sync re-draw to proper paint on form resize
self.canvas.draw()
- self.background = self.canvas.copy_from_bbox(self.axes.bbox)
+
+ ##### Temporary place-holder for cached update #####
+ self.update_screen_request.emit([0, 0, 0, 0, 0])
def auto_adjust_axes(self, *args):
"""
@@ -249,9 +369,11 @@ class PlotCanvas:
ax.set_xlim((xmin, xmax))
ax.set_ylim((ymin, ymax))
- # Re-draw
- self.canvas.draw()
- self.background = self.canvas.copy_from_bbox(self.axes.bbox)
+ # Async re-draw
+ self.canvas.draw_idle()
+
+ ##### Temporary place-holder for cached update #####
+ self.update_screen_request.emit([0, 0, 0, 0, 0])
def pan(self, x, y):
xmin, xmax = self.axes.get_xlim()
@@ -261,12 +383,14 @@ class PlotCanvas:
# Adjust axes
for ax in self.figure.get_axes():
- ax.set_xlim((xmin + x*width, xmax + x*width))
- ax.set_ylim((ymin + y*height, ymax + y*height))
+ ax.set_xlim((xmin + x * width, xmax + x * width))
+ ax.set_ylim((ymin + y * height, ymax + y * height))
# Re-draw
- self.canvas.draw()
- self.background = self.canvas.copy_from_bbox(self.axes.bbox)
+ self.canvas.draw_idle()
+
+ ##### Temporary place-holder for cached update #####
+ self.update_screen_request.emit([0, 0, 0, 0, 0])
def new_axes(self, name):
"""
@@ -299,7 +423,7 @@ class PlotCanvas:
if event.button == 'up':
self.zoom(1.5, self.mouse)
else:
- self.zoom(1/1.5, self.mouse)
+ self.zoom(1 / 1.5, self.mouse)
return
if self.key == 'shift':
@@ -318,12 +442,83 @@ class PlotCanvas:
self.pan(0, -0.3)
return
+ def on_mouse_press(self, event):
+
+ # Check for middle mouse button press
+ if event.button == 2:
+
+ # Prepare axes for pan (using 'matplotlib' pan function)
+ self.pan_axes = []
+ for a in self.figure.get_axes():
+ if (event.x is not None and event.y is not None and a.in_axes(event) and
+ a.get_navigate() and a.can_pan()):
+ a.start_pan(event.x, event.y, 1)
+ self.pan_axes.append(a)
+
+ # Set pan view flag
+ if len(self.pan_axes) > 0: self.panning = True;
+
+ def on_mouse_release(self, event):
+
+ # Check for middle mouse button release to complete pan procedure
+ if event.button == 2:
+ for a in self.pan_axes:
+ a.end_pan()
+
+ # Clear pan flag
+ self.panning = False
+
def on_mouse_move(self, event):
"""
- Mouse movement event hadler. Stores the coordinates.
+ Mouse movement event hadler. Stores the coordinates. Updates view on pan.
:param event: Contains information about the event.
:return: None
"""
self.mouse = [event.xdata, event.ydata]
+ # Update pan view on mouse move
+ if self.panning is True:
+ for a in self.pan_axes:
+ a.drag_pan(1, event.key, event.x, event.y)
+
+ # Async re-draw (redraws only on thread idle state, uses timer on backend)
+ self.canvas.draw_idle()
+
+ ##### Temporary place-holder for cached update #####
+ self.update_screen_request.emit([0, 0, 0, 0, 0])
+
+ def on_draw(self, renderer):
+
+ # Store background on canvas redraw
+ self.background = self.canvas.copy_from_bbox(self.axes.bbox)
+
+ def get_axes_pixelsize(self):
+ """
+ Axes size in pixels.
+
+ :return: Pixel width and height
+ :rtype: tuple
+ """
+ bbox = self.axes.get_window_extent().transformed(self.figure.dpi_scale_trans.inverted())
+ width, height = bbox.width, bbox.height
+ width *= self.figure.dpi
+ height *= self.figure.dpi
+ return width, height
+
+ def get_density(self):
+ """
+ Returns unit length per pixel on horizontal
+ and vertical axes.
+
+ :return: X and Y density
+ :rtype: tuple
+ """
+ xpx, ypx = self.get_axes_pixelsize()
+
+ xmin, xmax = self.axes.get_xlim()
+ ymin, ymax = self.axes.get_ylim()
+ width = xmax - xmin
+ height = ymax - ymin
+
+ return width / xpx, height / ypx
diff --git a/README.md b/README.md
index 352e587c..5b156d13 100644
--- a/README.md
+++ b/README.md
@@ -1,8 +1,8 @@
-FlatCAM: 2D Post-processing for Manufacturing
-=============================================
-
-(c) 2014 Juan Pablo Caram
-
-FlatCAM is a program for preparing CNC jobs for making PCBs on a CNC router.
-Among other things, it can take a Gerber file generated by your favorite PCB
-CAD program, and create G-Code for Isolation routing.
+FlatCAM: 2D Computer-Aided PCB Manufacturing
+============================================
+
+(c) 2014-2015 Juan Pablo Caram
+
+FlatCAM is a program for preparing CNC jobs for making PCBs on a CNC router.
+Among other things, it can take a Gerber file generated by your favorite PCB
+CAD program, and create G-Code for Isolation routing.
diff --git a/camlib.py b/camlib.py
index 8e5319b3..7d756a12 100644
--- a/camlib.py
+++ b/camlib.py
@@ -6,19 +6,23 @@
# MIT Licence #
############################################################
#from __future__ import division
-import traceback
+#from scipy import optimize
+#import traceback
from numpy import arctan2, Inf, array, sqrt, pi, ceil, sin, cos, dot, float32, \
transpose
from numpy.linalg import solve, norm
from matplotlib.figure import Figure
import re
+import sys
+import traceback
+from decimal import Decimal
import collections
import numpy as np
import matplotlib
-import matplotlib.pyplot as plt
-from scipy.spatial import Delaunay, KDTree
+#import matplotlib.pyplot as plt
+#from scipy.spatial import Delaunay, KDTree
from rtree import index as rtindex
@@ -37,20 +41,34 @@ from descartes.patch import PolygonPatch
import simplejson as json
# TODO: Commented for FlatCAM packaging with cx_freeze
-#from matplotlib.pyplot import plot
+#from matplotlib.pyplot import plot, subplot
+
+import xml.etree.ElementTree as ET
+from svg.path import Path, Line, Arc, CubicBezier, QuadraticBezier, parse_path
+import itertools
+
+import xml.etree.ElementTree as ET
+from svg.path import Path, Line, Arc, CubicBezier, QuadraticBezier, parse_path
+
+
+from svgparse import *
import logging
log = logging.getLogger('base2')
log.setLevel(logging.DEBUG)
-#log.setLevel(logging.WARNING)
-#log.setLevel(logging.INFO)
+# log.setLevel(logging.WARNING)
+# log.setLevel(logging.INFO)
formatter = logging.Formatter('[%(levelname)s] %(message)s')
handler = logging.StreamHandler()
handler.setFormatter(formatter)
log.addHandler(handler)
+class ParseError(Exception):
+ pass
+
+
class Geometry(object):
"""
Base geometry class.
@@ -73,9 +91,6 @@ class Geometry(object):
# Flattened geometry (list of paths only)
self.flat_geometry = []
- # Flat geometry rtree index
- self.flat_geometry_rtree = rtindex.Index()
-
def add_circle(self, origin, radius):
"""
Adds a circle to the object.
@@ -96,7 +111,8 @@ class Geometry(object):
try:
self.solid_geometry = self.solid_geometry.union(Point(origin).buffer(radius))
except:
- print "Failed to run union on polygons."
+ #print "Failed to run union on polygons."
+ log.error("Failed to run union on polygons.")
raise
def add_polygon(self, points):
@@ -116,7 +132,8 @@ class Geometry(object):
try:
self.solid_geometry = self.solid_geometry.union(Polygon(points))
except:
- print "Failed to run union on polygons."
+ #print "Failed to run union on polygons."
+ log.error("Failed to run union on polygons.")
raise
def bounds(self):
@@ -138,7 +155,94 @@ class Geometry(object):
else:
return self.solid_geometry.bounds
+ def find_polygon(self, point, geoset=None):
+ """
+ Find an object that object.contains(Point(point)) in
+ poly, which can can be iterable, contain iterable of, or
+ be itself an implementer of .contains().
+
+ :param poly: See description
+ :return: Polygon containing point or None.
+ """
+
+ if geoset is None:
+ geoset = self.solid_geometry
+
+ try: # Iterable
+ for sub_geo in geoset:
+ p = self.find_polygon(point, geoset=sub_geo)
+ if p is not None:
+ return p
+
+ except TypeError: # Non-iterable
+
+ try: # Implements .contains()
+ if geoset.contains(Point(point)):
+ return geoset
+
+ except AttributeError: # Does not implement .contains()
+ return None
+
+ return None
+
+ def get_interiors(self, geometry=None):
+
+ interiors = []
+
+ if geometry is None:
+ geometry = self.solid_geometry
+
+ ## If iterable, expand recursively.
+ try:
+ for geo in geometry:
+ interiors.extend(self.get_interiors(geometry=geo))
+
+ ## Not iterable, get the exterior if polygon.
+ except TypeError:
+ if type(geometry) == Polygon:
+ interiors.extend(geometry.interiors)
+
+ return interiors
+
+ def get_exteriors(self, geometry=None):
+ """
+ Returns all exteriors of polygons in geometry. Uses
+ ``self.solid_geometry`` if geometry is not provided.
+
+ :param geometry: Shapely type or list or list of list of such.
+ :return: List of paths constituting the exteriors
+ of polygons in geometry.
+ """
+
+ exteriors = []
+
+ if geometry is None:
+ geometry = self.solid_geometry
+
+ ## If iterable, expand recursively.
+ try:
+ for geo in geometry:
+ exteriors.extend(self.get_exteriors(geometry=geo))
+
+ ## Not iterable, get the exterior if polygon.
+ except TypeError:
+ if type(geometry) == Polygon:
+ exteriors.append(geometry.exterior)
+
+ return exteriors
+
def flatten(self, geometry=None, reset=True, pathonly=False):
+ """
+ Creates a list of non-iterable linear geometry objects.
+ Polygons are expanded into its exterior and interiors if specified.
+
+ Results are placed in self.flat_geoemtry
+
+ :param geometry: Shapely type or list or list of list of such.
+ :param reset: Clears the contents of self.flat_geometry.
+ :param pathonly: Expands polygons into linear elements.
+ """
+
if geometry is None:
geometry = self.solid_geometry
@@ -161,31 +265,29 @@ class Geometry(object):
pathonly=True)
else:
self.flat_geometry.append(geometry)
- # if type(geometry) == Polygon:
- # self.flat_geometry.append(geometry)
return self.flat_geometry
- def make2Dindex(self):
-
- self.flatten()
-
- def get_pts(o):
- pts = []
- if type(o) == Polygon:
- g = o.exterior
- pts += list(g.coords)
- for i in o.interiors:
- pts += list(i.coords)
- else:
- pts += list(o.coords)
- return pts
-
- idx = FlatCAMRTreeStorage()
- idx.get_points = get_pts
- for shape in self.flat_geometry:
- idx.insert(shape)
- return idx
+ # def make2Dstorage(self):
+ #
+ # self.flatten()
+ #
+ # def get_pts(o):
+ # pts = []
+ # if type(o) == Polygon:
+ # g = o.exterior
+ # pts += list(g.coords)
+ # for i in o.interiors:
+ # pts += list(i.coords)
+ # else:
+ # pts += list(o.coords)
+ # return pts
+ #
+ # storage = FlatCAMRTreeStorage()
+ # storage.get_points = get_pts
+ # for shape in self.flat_geometry:
+ # storage.insert(shape)
+ # return storage
# def flatten_to_paths(self, geometry=None, reset=True):
# """
@@ -252,6 +354,40 @@ class Geometry(object):
return False
+ def import_svg(self, filename, flip=True):
+ """
+ Imports shapes from an SVG file into the object's geometry.
+
+ :param filename: Path to the SVG file.
+ :type filename: str
+ :return: None
+ """
+
+ # Parse into list of shapely objects
+ svg_tree = ET.parse(filename)
+ svg_root = svg_tree.getroot()
+
+ # Change origin to bottom left
+ # h = float(svg_root.get('height'))
+ # w = float(svg_root.get('width'))
+ h = svgparselength(svg_root.get('height'))[0] # TODO: No units support yet
+ geos = getsvggeo(svg_root)
+
+ if flip:
+ geos = [translate(scale(g, 1.0, -1.0, origin=(0, 0)), yoff=h) for g in geos]
+
+ # Add to object
+ if self.solid_geometry is None:
+ self.solid_geometry = []
+
+ if type(self.solid_geometry) is list:
+ self.solid_geometry.append(cascaded_union(geos))
+ else: # It's shapely geometry
+ self.solid_geometry = cascaded_union([self.solid_geometry,
+ cascaded_union(geos)])
+
+ return
+
def size(self):
"""
Returns (width, height) of rectangular
@@ -273,7 +409,8 @@ class Geometry(object):
boundary = self.solid_geometry.envelope
return boundary.difference(self.solid_geometry)
- def clear_polygon(self, polygon, tooldia, overlap=0.15):
+ @staticmethod
+ def clear_polygon(polygon, tooldia, overlap=0.15):
"""
Creates geometry inside a polygon for a tool to cover
the whole area.
@@ -286,16 +423,63 @@ class Geometry(object):
:param overlap: Overlap of toolpasses.
:return:
"""
- poly_cuts = [polygon.buffer(-tooldia/2.0)]
+
+ log.debug("camlib.clear_polygon()")
+ assert type(polygon) == Polygon or type(polygon) == MultiPolygon, \
+ "Expected a Polygon or MultiPolygon, got %s" % type(polygon)
+
+ ## The toolpaths
+ # Index first and last points in paths
+ def get_pts(o):
+ return [o.coords[0], o.coords[-1]]
+ geoms = FlatCAMRTreeStorage()
+ geoms.get_points = get_pts
+
+ # Can only result in a Polygon or MultiPolygon
+ current = polygon.buffer(-tooldia / 2.0)
+
+ # current can be a MultiPolygon
+ try:
+ for p in current:
+ geoms.insert(p.exterior)
+ for i in p.interiors:
+ geoms.insert(i)
+
+ # Not a Multipolygon. Must be a Polygon
+ except TypeError:
+ geoms.insert(current.exterior)
+ for i in current.interiors:
+ geoms.insert(i)
+
while True:
- polygon = poly_cuts[-1].buffer(-tooldia*(1-overlap))
- if polygon.area > 0:
- poly_cuts.append(polygon)
+
+ # Can only result in a Polygon or MultiPolygon
+ current = current.buffer(-tooldia * (1 - overlap))
+ if current.area > 0:
+
+ # current can be a MultiPolygon
+ try:
+ for p in current:
+ geoms.insert(p.exterior)
+ for i in p.interiors:
+ geoms.insert(i)
+
+ # Not a Multipolygon. Must be a Polygon
+ except TypeError:
+ geoms.insert(current.exterior)
+ for i in current.interiors:
+ geoms.insert(i)
else:
break
- return poly_cuts
- def clear_polygon2(self, polygon, tooldia, seedpoint=None, overlap=0.15):
+ # Optimization: Reduce lifts
+ log.debug("Reducing tool lifts...")
+ geoms = Geometry.paint_connect(geoms, polygon, tooldia)
+
+ return geoms
+
+ @staticmethod
+ def clear_polygon2(polygon, tooldia, seedpoint=None, overlap=0.15):
"""
Creates geometry inside a polygon for a tool to cover
the whole area.
@@ -305,27 +489,34 @@ class Geometry(object):
valid cuts. Finalizes by cutting around the inside edge of
the polygon.
- :param polygon:
- :param tooldia:
- :param seedpoint:
- :param overlap:
- :return:
+ :param polygon: Shapely.geometry.Polygon
+ :param tooldia: Diameter of the tool
+ :param seedpoint: Shapely.geometry.Point or None
+ :param overlap: Tool fraction overlap bewteen passes
+ :return: List of toolpaths covering polygon.
"""
- # Estimate good seedpoint if not provided.
- if seedpoint is None:
- seedpoint = polygon.representative_point()
+ log.debug("camlib.clear_polygon2()")
# Current buffer radius
radius = tooldia / 2 * (1 - overlap)
- # The toolpaths
- geoms = []
+ ## The toolpaths
+ # Index first and last points in paths
+ def get_pts(o):
+ return [o.coords[0], o.coords[-1]]
+ geoms = FlatCAMRTreeStorage()
+ geoms.get_points = get_pts
# Path margin
path_margin = polygon.buffer(-tooldia / 2)
- # Grow from seed until outside the box.
+ # Estimate good seedpoint if not provided.
+ if seedpoint is None:
+ seedpoint = path_margin.representative_point()
+
+ # Grow from seed until outside the box. The polygons will
+ # never have an interior, so take the exterior LinearRing.
while 1:
path = Point(seedpoint).buffer(radius).exterior
path = path.intersection(path_margin)
@@ -334,17 +525,34 @@ class Geometry(object):
if path.is_empty:
break
else:
- geoms.append(path)
+ #geoms.append(path)
+ #geoms.insert(path)
+ # path can be a collection of paths.
+ try:
+ for p in path:
+ geoms.insert(p)
+ except TypeError:
+ geoms.insert(path)
radius += tooldia * (1 - overlap)
- # Clean edges
+ # Clean inside edges of the original polygon
outer_edges = [x.exterior for x in autolist(polygon.buffer(-tooldia / 2))]
inner_edges = []
for x in autolist(polygon.buffer(-tooldia / 2)): # Over resulting polygons
for y in x.interiors: # Over interiors of each polygon
inner_edges.append(y)
- geoms += outer_edges + inner_edges
+ #geoms += outer_edges + inner_edges
+ for g in outer_edges + inner_edges:
+ geoms.insert(g)
+
+ # Optimization connect touching paths
+ # log.debug("Connecting paths...")
+ # geoms = Geometry.path_connect(geoms)
+
+ # Optimization: Reduce lifts
+ log.debug("Reducing tool lifts...")
+ geoms = Geometry.paint_connect(geoms, polygon, tooldia)
return geoms
@@ -369,6 +577,209 @@ class Geometry(object):
"""
return
+ @staticmethod
+ def paint_connect(storage, boundary, tooldia, max_walk=None):
+ """
+ Connects paths that results in a connection segment that is
+ within the paint area. This avoids unnecessary tool lifting.
+
+ :param storage: Geometry to be optimized.
+ :type storage: FlatCAMRTreeStorage
+ :param boundary: Polygon defining the limits of the paintable area.
+ :type boundary: Polygon
+ :param max_walk: Maximum allowable distance without lifting tool.
+ :type max_walk: float or None
+ :return: Optimized geometry.
+ :rtype: FlatCAMRTreeStorage
+ """
+
+ # If max_walk is not specified, the maximum allowed is
+ # 10 times the tool diameter
+ max_walk = max_walk or 10 * tooldia
+
+ # Assuming geolist is a flat list of flat elements
+
+ ## Index first and last points in paths
+ def get_pts(o):
+ return [o.coords[0], o.coords[-1]]
+
+ # storage = FlatCAMRTreeStorage()
+ # storage.get_points = get_pts
+ #
+ # for shape in geolist:
+ # if shape is not None: # TODO: This shouldn't have happened.
+ # # Make LlinearRings into linestrings otherwise
+ # # When chaining the coordinates path is messed up.
+ # storage.insert(LineString(shape))
+ # #storage.insert(shape)
+
+ ## Iterate over geometry paths getting the nearest each time.
+ #optimized_paths = []
+ optimized_paths = FlatCAMRTreeStorage()
+ optimized_paths.get_points = get_pts
+ path_count = 0
+ current_pt = (0, 0)
+ pt, geo = storage.nearest(current_pt)
+ storage.remove(geo)
+ geo = LineString(geo)
+ current_pt = geo.coords[-1]
+ try:
+ while True:
+ path_count += 1
+ #log.debug("Path %d" % path_count)
+
+ pt, candidate = storage.nearest(current_pt)
+ storage.remove(candidate)
+ candidate = LineString(candidate)
+
+ # If last point in geometry is the nearest
+ # then reverse coordinates.
+ # but prefer the first one if last == first
+ if pt != candidate.coords[0] and pt == candidate.coords[-1]:
+ candidate.coords = list(candidate.coords)[::-1]
+
+ # Straight line from current_pt to pt.
+ # Is the toolpath inside the geometry?
+ walk_path = LineString([current_pt, pt])
+ walk_cut = walk_path.buffer(tooldia / 2)
+
+ if walk_cut.within(boundary) and walk_path.length < max_walk:
+ #log.debug("Walk to path #%d is inside. Joining." % path_count)
+
+ # Completely inside. Append...
+ geo.coords = list(geo.coords) + list(candidate.coords)
+ # try:
+ # last = optimized_paths[-1]
+ # last.coords = list(last.coords) + list(geo.coords)
+ # except IndexError:
+ # optimized_paths.append(geo)
+
+ else:
+
+ # Have to lift tool. End path.
+ #log.debug("Path #%d not within boundary. Next." % path_count)
+ #optimized_paths.append(geo)
+ optimized_paths.insert(geo)
+ geo = candidate
+
+ current_pt = geo.coords[-1]
+
+ # Next
+ #pt, geo = storage.nearest(current_pt)
+
+ except StopIteration: # Nothing left in storage.
+ #pass
+ optimized_paths.insert(geo)
+
+ return optimized_paths
+
+ @staticmethod
+ def path_connect(storage, origin=(0, 0)):
+ """
+
+ :return: None
+ """
+
+ log.debug("path_connect()")
+
+ ## Index first and last points in paths
+ def get_pts(o):
+ return [o.coords[0], o.coords[-1]]
+ #
+ # storage = FlatCAMRTreeStorage()
+ # storage.get_points = get_pts
+ #
+ # for shape in pathlist:
+ # if shape is not None: # TODO: This shouldn't have happened.
+ # storage.insert(shape)
+
+ path_count = 0
+ pt, geo = storage.nearest(origin)
+ storage.remove(geo)
+ #optimized_geometry = [geo]
+ optimized_geometry = FlatCAMRTreeStorage()
+ optimized_geometry.get_points = get_pts
+ #optimized_geometry.insert(geo)
+ try:
+ while True:
+ path_count += 1
+
+ #print "geo is", geo
+
+ _, left = storage.nearest(geo.coords[0])
+ #print "left is", left
+
+ # If left touches geo, remove left from original
+ # storage and append to geo.
+ if type(left) == LineString:
+ if left.coords[0] == geo.coords[0]:
+ storage.remove(left)
+ geo.coords = list(geo.coords)[::-1] + list(left.coords)
+ continue
+
+ if left.coords[-1] == geo.coords[0]:
+ storage.remove(left)
+ geo.coords = list(left.coords) + list(geo.coords)
+ continue
+
+ if left.coords[0] == geo.coords[-1]:
+ storage.remove(left)
+ geo.coords = list(geo.coords) + list(left.coords)
+ continue
+
+ if left.coords[-1] == geo.coords[-1]:
+ storage.remove(left)
+ geo.coords = list(geo.coords) + list(left.coords)[::-1]
+ continue
+
+ _, right = storage.nearest(geo.coords[-1])
+ #print "right is", right
+
+ # If right touches geo, remove left from original
+ # storage and append to geo.
+ if type(right) == LineString:
+ if right.coords[0] == geo.coords[-1]:
+ storage.remove(right)
+ geo.coords = list(geo.coords) + list(right.coords)
+ continue
+
+ if right.coords[-1] == geo.coords[-1]:
+ storage.remove(right)
+ geo.coords = list(geo.coords) + list(right.coords)[::-1]
+ continue
+
+ if right.coords[0] == geo.coords[0]:
+ storage.remove(right)
+ geo.coords = list(geo.coords)[::-1] + list(right.coords)
+ continue
+
+ if right.coords[-1] == geo.coords[0]:
+ storage.remove(right)
+ geo.coords = list(left.coords) + list(geo.coords)
+ continue
+
+ # right is either a LinearRing or it does not connect
+ # to geo (nothing left to connect to geo), so we continue
+ # with right as geo.
+ storage.remove(right)
+
+ if type(right) == LinearRing:
+ optimized_geometry.insert(right)
+ else:
+ # Cannot exteng geo any further. Put it away.
+ optimized_geometry.insert(geo)
+
+ # Continue with right.
+ geo = right
+
+ except StopIteration: # Nothing found in storage.
+ optimized_geometry.insert(geo)
+
+ #print path_count
+ log.debug("path_count = %d" % path_count)
+
+ return optimized_geometry
+
def convert_units(self, units):
"""
Converts the units of the object to ``units`` by scaling all
@@ -388,7 +799,7 @@ class Geometry(object):
if units.upper() == "MM":
factor = 25.4
elif units.upper() == "IN":
- factor = 1/25.4
+ factor = 1 / 25.4
else:
log.error("Unsupported units: %s" % str(units))
return 1.0
@@ -436,7 +847,6 @@ class Geometry(object):
self.solid_geometry = [cascaded_union(self.solid_geometry)]
-
class ApertureMacro:
"""
Syntax of aperture macros.
@@ -547,7 +957,7 @@ class ApertureMacro:
if match:
## Replace all variables
for v in self.locvars:
- part = re.sub(r'\$'+str(v)+r'(?![0-9a-zA-Z])', str(self.locvars[v]), part)
+ part = re.sub(r'\$' + str(v) + r'(?![0-9a-zA-Z])', str(self.locvars[v]), part)
# Make all others 0
part = re.sub(r'\$[0-9a-zA-Z](?![0-9a-zA-Z])', "0", part)
@@ -585,7 +995,7 @@ class ApertureMacro:
:return: Zero-padded list.
:rtype: list
"""
- x = [0.0]*n
+ x = [0.0] * n
na = len(mods)
x[0:na] = mods
return x
@@ -759,6 +1169,8 @@ class ApertureMacro:
:param modifiers: Modifiers (parameters) for this macro
:type modifiers: list
+ :return: Shapely geometry
+ :rtype: shapely.geometry.polygon
"""
## Primitive makers
@@ -779,11 +1191,11 @@ class ApertureMacro:
modifiers = [float(m) for m in modifiers]
self.locvars = {}
for i in range(0, len(modifiers)):
- self.locvars[str(i+1)] = modifiers[i]
+ self.locvars[str(i + 1)] = modifiers[i]
## Parse
self.primitives = [] # Cleanup
- self.geometry = None
+ self.geometry = Polygon()
self.parse_content()
## Make the geometry
@@ -792,9 +1204,9 @@ class ApertureMacro:
prim_geo = makers[str(int(primitive[0]))](primitive[1:])
# Add it (according to polarity)
- if self.geometry is None and prim_geo['pol'] == 1:
- self.geometry = prim_geo['geometry']
- continue
+ # if self.geometry is None and prim_geo['pol'] == 1:
+ # self.geometry = prim_geo['geometry']
+ # continue
if prim_geo['pol'] == 1:
self.geometry = self.geometry.union(prim_geo['geometry'])
continue
@@ -843,7 +1255,8 @@ class Gerber (Geometry):
"""
defaults = {
- "steps_per_circle": 40
+ "steps_per_circle": 40,
+ "use_buffer_for_union": True
}
def __init__(self, steps_per_circle=None):
@@ -896,7 +1309,9 @@ class Gerber (Geometry):
self.comm_re = re.compile(r'^G0?4(.*)$')
# AD - Aperture definition
- self.ad_re = re.compile(r'^%ADD(\d\d+)([a-zA-Z_$\.][a-zA-Z0-9_$\.]*)(?:,(.*))?\*%$')
+ # Aperture Macro names: Name = [a-zA-Z_.$]{[a-zA-Z_.0-9]+}
+ # NOTE: Adding "-" to support output from Upverter.
+ self.ad_re = re.compile(r'^%ADD(\d\d+)([a-zA-Z_$\.][a-zA-Z0-9_$\.\-]*)(?:,(.*))?\*%$')
# AM - Aperture Macro
# Beginning of macro (Ends with *%):
@@ -908,7 +1323,7 @@ class Gerber (Geometry):
# G01... - Linear interpolation plus flashes with coordinates
# Operation code (D0x) missing is deprecated... oh well I will support it.
- self.lin_re = re.compile(r'^(?:G0?(1))?(?=.*X(-?\d+))?(?=.*Y(-?\d+))?[XY][^DIJ]*(?:D0?([123]))?\*$')
+ self.lin_re = re.compile(r'^(?:G0?(1))?(?=.*X([\+-]?\d+))?(?=.*Y([\+-]?\d+))?[XY][^DIJ]*(?:D0?([123]))?\*$')
# Operation code alone, usually just D03 (Flash)
self.opcode_re = re.compile(r'^D0?([123])\*$')
@@ -918,8 +1333,8 @@ class Gerber (Geometry):
# Operation code (D0x) missing is deprecated... oh well I will support it.
# Optional start with G02 or G03, optional end with D01 or D02 with
# optional coordinates but at least one in any order.
- self.circ_re = re.compile(r'^(?:G0?([23]))?(?=.*X(-?\d+))?(?=.*Y(-?\d+))' +
- '?(?=.*I(-?\d+))?(?=.*J(-?\d+))?[XYIJ][^D]*(?:D0([12]))?\*$')
+ self.circ_re = re.compile(r'^(?:G0?([23]))?(?=.*X([\+-]?\d+))?(?=.*Y([\+-]?\d+))' +
+ '?(?=.*I([\+-]?\d+))?(?=.*J([\+-]?\d+))?[XYIJ][^D]*(?:D0([12]))?\*$')
# G01/2/3 Occurring without coordinates
self.interp_re = re.compile(r'^(?:G0?([123]))\*')
@@ -961,6 +1376,8 @@ class Gerber (Geometry):
# How to discretize a circle.
self.steps_per_circ = steps_per_circle or Gerber.defaults['steps_per_circle']
+ self.use_buffer_for_union = self.defaults["use_buffer_for_union"]
+
def scale(self, factor):
"""
Scales the objects' geometry on the XY plane by a given factor.
@@ -1113,8 +1530,15 @@ class Gerber (Geometry):
def parse_file(self, filename, follow=False):
"""
- Calls Gerber.parse_lines() with array of lines
- read from the given file.
+ Calls Gerber.parse_lines() with generator of lines
+ read from the given file. Will split the lines if multiple
+ statements are found in a single original line.
+
+ The following line is split into two::
+
+ G54D11*G36*
+
+ First is ``G54D11*`` and seconds is ``G36*``.
:param filename: Gerber file to parse.
:type filename: str
@@ -1123,11 +1547,35 @@ class Gerber (Geometry):
:type follow: bool
:return: None
"""
- gfile = open(filename, 'r')
- gstr = gfile.readlines()
- gfile.close()
- self.parse_lines(gstr, follow=follow)
+ with open(filename, 'r') as gfile:
+
+ def line_generator():
+ for line in gfile:
+ line = line.strip(' \r\n')
+ while len(line) > 0:
+
+ # If ends with '%' leave as is.
+ if line[-1] == '%':
+ yield line
+ break
+
+ # Split after '*' if any.
+ starpos = line.find('*')
+ if starpos > -1:
+ cleanline = line[:starpos + 1]
+ yield cleanline
+ line = line[starpos + 1:]
+
+ # Otherwise leave as is.
+ else:
+ # yield cleanline
+ yield line
+ break
+
+ self.parse_lines(line_generator(), follow=follow)
+
+ #@profile
def parse_lines(self, glines, follow=False):
"""
Main Gerber parser. Reads Gerber and populates ``self.paths``, ``self.apertures``,
@@ -1193,6 +1641,8 @@ class Gerber (Geometry):
### Cleanup
gline = gline.strip(' \r\n')
+ #log.debug("%3s %s" % (line_num, gline))
+
### Aperture Macros
# Having this at the beggining will slow things down
# but macros can have complicated statements than could
@@ -1201,7 +1651,7 @@ class Gerber (Geometry):
match = self.am1_re.search(gline)
# Start macro if match, else not an AM, carry on.
if match:
- log.info("Starting macro. Line %d: %s" % (line_num, gline))
+ log.debug("Starting macro. Line %d: %s" % (line_num, gline))
current_macro = match.group(1)
self.aperture_macros[current_macro] = ApertureMacro(name=current_macro)
if match.group(2): # Append
@@ -1209,13 +1659,13 @@ class Gerber (Geometry):
if match.group(3): # Finish macro
#self.aperture_macros[current_macro].parse_content()
current_macro = None
- log.info("Macro complete in 1 line.")
+ log.debug("Macro complete in 1 line.")
continue
else: # Continue macro
- log.info("Continuing macro. Line %d." % line_num)
+ log.debug("Continuing macro. Line %d." % line_num)
match = self.am2_re.search(gline)
if match: # Finish macro
- log.info("End of macro. Line %d." % line_num)
+ log.debug("End of macro. Line %d." % line_num)
self.aperture_macros[current_macro].append(match.group(1))
#self.aperture_macros[current_macro].parse_content()
current_macro = None
@@ -1267,18 +1717,30 @@ class Gerber (Geometry):
if follow:
geo = LineString(path)
else:
- geo = LineString(path).buffer(width/2)
- poly_buffer.append(geo)
+ geo = LineString(path).buffer(width / 2)
+ if not geo.is_empty: poly_buffer.append(geo)
path = [[current_x, current_y]] # Start new path
# Flash
+ # Not allowed in region mode.
elif current_operation_code == 3:
+ # Create path draw so far.
+ if len(path) > 1:
+ # --- Buffered ----
+ width = self.apertures[last_path_aperture]["size"]
+ geo = LineString(path).buffer(width / 2)
+ if not geo.is_empty: poly_buffer.append(geo)
+
+ # Reset path starting point
+ path = [[current_x, current_y]]
+
# --- BUFFERED ---
+ # Draw the flash
flash = Gerber.create_flash_geometry(Point([current_x, current_y]),
self.apertures[current_aperture])
- poly_buffer.append(flash)
+ if not flash.is_empty: poly_buffer.append(flash)
continue
@@ -1331,8 +1793,8 @@ class Gerber (Geometry):
# --- BUFFERED ---
width = self.apertures[last_path_aperture]["size"]
- buffered = LineString(path).buffer(width/2)
- poly_buffer.append(buffered)
+ buffered = LineString(path).buffer(width / 2)
+ if not buffered.is_empty: poly_buffer.append(buffered)
current_x = x
current_y = y
@@ -1360,9 +1822,15 @@ class Gerber (Geometry):
arcdir[current_interpolation_mode],
self.steps_per_circ)
+ # The last point in the computed arc can have
+ # numerical errors. The exact final point is the
+ # specified (x, y). Replace.
+ this_arc[-1] = (x, y)
+
# Last point in path is current point
- current_x = this_arc[-1][0]
- current_y = this_arc[-1][1]
+ # current_x = this_arc[-1][0]
+ # current_y = this_arc[-1][1]
+ current_x, current_y = x, y
# Append
path += this_arc
@@ -1383,11 +1851,11 @@ class Gerber (Geometry):
valid = False
log.debug("I: %f J: %f" % (i, j))
for center in center_candidates:
- radius = sqrt(i**2 + j**2)
+ radius = sqrt(i ** 2 + j ** 2)
# Make sure radius to start is the same as radius to end.
- radius2 = sqrt((center[0] - x)**2 + (center[1] - y)**2)
- if radius2 < radius*0.95 or radius2 > radius*1.05:
+ radius2 = sqrt((center[0] - x) ** 2 + (center[1] - y) ** 2)
+ if radius2 < radius * 0.95 or radius2 > radius * 1.05:
continue # Not a valid center.
# Correct i and j and continue as with multi-quadrant.
@@ -1400,16 +1868,22 @@ class Gerber (Geometry):
log.debug("ARC START: %f, %f CENTER: %f, %f STOP: %f, %f" %
(current_x, current_y, center[0], center[1], x, y))
log.debug("START Ang: %f, STOP Ang: %f, DIR: %s, ABS: %.12f <= %.12f: %s" %
- (start*180/pi, stop*180/pi, arcdir[current_interpolation_mode],
- angle*180/pi, pi/2*180/pi, angle <= (pi+1e-6)/2))
+ (start * 180 / pi, stop * 180 / pi, arcdir[current_interpolation_mode],
+ angle * 180 / pi, pi / 2 * 180 / pi, angle <= (pi + 1e-6) / 2))
- if angle <= (pi+1e-6)/2:
+ if angle <= (pi + 1e-6) / 2:
log.debug("########## ACCEPTING ARC ############")
this_arc = arc(center, radius, start, stop,
arcdir[current_interpolation_mode],
self.steps_per_circ)
- current_x = this_arc[-1][0]
- current_y = this_arc[-1][1]
+
+ # Replace with exact values
+ this_arc[-1] = (x, y)
+
+ # current_x = this_arc[-1][0]
+ # current_y = this_arc[-1][1]
+ current_x, current_y = x, y
+
path += this_arc
last_path_aperture = current_aperture
valid = True
@@ -1430,9 +1904,12 @@ class Gerber (Geometry):
## --- Buffered ---
try:
- flash = Gerber.create_flash_geometry(Point(path[-1]),
+ log.debug("Bare op-code %d." % current_operation_code)
+ # flash = Gerber.create_flash_geometry(Point(path[-1]),
+ # self.apertures[current_aperture])
+ flash = Gerber.create_flash_geometry(Point(current_x, current_y),
self.apertures[current_aperture])
- poly_buffer.append(flash)
+ if not flash.is_empty: poly_buffer.append(flash)
except IndexError:
log.warning("Line %d: %s -> Nothing there to flash!" % (line_num, gline))
@@ -1455,7 +1932,7 @@ class Gerber (Geometry):
## --- Buffered ---
width = self.apertures[last_path_aperture]["size"]
geo = LineString(path).buffer(width/2)
- poly_buffer.append(geo)
+ if not geo.is_empty: poly_buffer.append(geo)
path = [path[-1]]
@@ -1485,7 +1962,7 @@ class Gerber (Geometry):
region = Polygon(path)
if not region.is_valid:
region = region.buffer(0)
- poly_buffer.append(region)
+ if not region.is_empty: poly_buffer.append(region)
path = [[current_x, current_y]] # Start new path
continue
@@ -1510,15 +1987,16 @@ class Gerber (Geometry):
# Example: D12*
match = self.tool_re.search(gline)
if match:
- log.debug("Line %d: Aperture change to (%s)" % (line_num, match.group(1)))
current_aperture = match.group(1)
+ log.debug("Line %d: Aperture change to (%s)" % (line_num, match.group(1)))
+ log.debug(self.apertures[current_aperture])
# Take care of the current path with the previous tool
if len(path) > 1:
# --- Buffered ----
width = self.apertures[last_path_aperture]["size"]
- geo = LineString(path).buffer(width/2)
- poly_buffer.append(geo)
+ geo = LineString(path).buffer(width / 2)
+ if not geo.is_empty: poly_buffer.append(geo)
path = [path[-1]]
continue
@@ -1534,7 +2012,7 @@ class Gerber (Geometry):
# --- Buffered ----
width = self.apertures[last_path_aperture]["size"]
geo = LineString(path).buffer(width / 2)
- poly_buffer.append(geo)
+ if not geo.is_empty: poly_buffer.append(geo)
path = [path[-1]]
@@ -1565,13 +2043,19 @@ class Gerber (Geometry):
# Example: %MOIN*%
match = self.mode_re.search(gline)
if match:
- self.units = match.group(1)
+ #self.units = match.group(1)
+
+ # Changed for issue #80
+ self.convert_units(match.group(1))
continue
### Units (G70/1) OBSOLETE
match = self.units_re.search(gline)
if match:
- self.units = {'0': 'IN', '1': 'MM'}[match.group(1)]
+ #self.units = {'0': 'IN', '1': 'MM'}[match.group(1)]
+
+ # Changed for issue #80
+ self.convert_units({'0': 'IN', '1': 'MM'}[match.group(1)])
continue
### Absolute/relative coordinates G90/1 OBSOLETE
@@ -1599,28 +2083,45 @@ class Gerber (Geometry):
## --- Buffered ---
width = self.apertures[last_path_aperture]["size"]
- geo = LineString(path).buffer(width/2)
- poly_buffer.append(geo)
+ geo = LineString(path).buffer(width / 2)
+ if not geo.is_empty: poly_buffer.append(geo)
# --- Apply buffer ---
- if current_polarity == 'D':
- self.solid_geometry = self.solid_geometry.union(cascaded_union(poly_buffer))
+ log.warn("Joining %d polygons." % len(poly_buffer))
+ if self.use_buffer_for_union:
+ log.debug("Union by buffer...")
+ new_poly = MultiPolygon(poly_buffer)
+ new_poly = new_poly.buffer(0.00000001)
+ new_poly = new_poly.buffer(-0.00000001)
+ log.warn("Union(buffer) done.")
else:
- self.solid_geometry = self.solid_geometry.difference(cascaded_union(poly_buffer))
+ log.debug("Union by union()...")
+ new_poly = cascaded_union(poly_buffer)
+ new_poly = new_poly.buffer(0)
+ log.warn("Union done.")
+ if current_polarity == 'D':
+ self.solid_geometry = self.solid_geometry.union(new_poly)
+ else:
+ self.solid_geometry = self.solid_geometry.difference(new_poly)
except Exception, err:
+ ex_type, ex, tb = sys.exc_info()
+ traceback.print_tb(tb)
#print traceback.format_exc()
+
log.error("PARSING FAILED. Line %d: %s" % (line_num, gline))
- raise
+ raise ParseError("Line %d: %s" % (line_num, gline), repr(err))
@staticmethod
def create_flash_geometry(location, aperture):
+ log.debug('Flashing @%s, Aperture: %s' % (location, aperture))
+
if type(location) == list:
location = Point(location)
if aperture['type'] == 'C': # Circles
- return location.buffer(aperture['size']/2)
+ return location.buffer(aperture['size'] / 2)
if aperture['type'] == 'R': # Rectangles
loc = location.coords[0]
@@ -1654,8 +2155,8 @@ class Gerber (Geometry):
n_vertices = aperture['nVertices']
points = []
for i in range(0, n_vertices):
- x = loc[0] + diam * (cos(2 * pi * i / n_vertices))
- y = loc[1] + diam * (sin(2 * pi * i / n_vertices))
+ x = loc[0] + 0.5 * diam * (cos(2 * pi * i / n_vertices))
+ y = loc[1] + 0.5 * diam * (sin(2 * pi * i / n_vertices))
points.append((x, y))
ply = Polygon(points)
if 'rotation' in aperture:
@@ -1665,8 +2166,11 @@ class Gerber (Geometry):
if aperture['type'] == 'AM': # Aperture Macro
loc = location.coords[0]
flash_geo = aperture['macro'].make_geometry(aperture['modifiers'])
+ if flash_geo.is_empty:
+ log.warning("Empty geometry for Aperture Macro: %s" % str(aperture['macro'].name))
return affinity.translate(flash_geo, xoff=loc[0], yoff=loc[1])
+ log.warning("Unknown aperture type: %s" % aperture['type'])
return None
def create_geometry(self):
@@ -1735,7 +2239,11 @@ class Excellon(Geometry):
================ ====================================
"""
- def __init__(self, zeros="L"):
+ defaults = {
+ "zeros": "L"
+ }
+
+ def __init__(self, zeros=None):
"""
The constructor takes no parameters.
@@ -1749,9 +2257,12 @@ class Excellon(Geometry):
self.drills = []
+ ## IN|MM -> Units are inherited from Geometry
+ #self.units = units
+
# Trailing "T" or leading "L" (default)
#self.zeros = "T"
- self.zeros = zeros
+ self.zeros = zeros or self.defaults["zeros"]
# Attributes to be included in serialization
# Always append to it because it carries contents
@@ -1772,7 +2283,8 @@ class Excellon(Geometry):
self.hend_re = re.compile(r'^(?:M95|%)$')
# FMAT Excellon format
- self.fmat_re = re.compile(r'^FMAT,([12])$')
+ # Ignored in the parser
+ #self.fmat_re = re.compile(r'^FMAT,([12])$')
# Number format and units
# INCH uses 6 digits
@@ -1857,104 +2369,136 @@ class Excellon(Geometry):
#### Parsing starts here ####
line_num = 0 # Line number
- for eline in elines:
- line_num += 1
+ eline = ""
+ try:
+ for eline in elines:
+ line_num += 1
+ #log.debug("%3d %s" % (line_num, str(eline)))
- ### Cleanup lines
- eline = eline.strip(' \r\n')
+ ### Cleanup lines
+ eline = eline.strip(' \r\n')
- ## Header Begin/End ##
- if self.hbegin_re.search(eline):
- in_header = True
- continue
-
- if self.hend_re.search(eline):
- in_header = False
- continue
-
- #### Body ####
- if not in_header:
-
- ## Tool change ##
- match = self.toolsel_re.search(eline)
- if match:
- current_tool = str(int(match.group(1)))
+ ## Header Begin (M48) ##
+ if self.hbegin_re.search(eline):
+ in_header = True
continue
- ## Coordinates without period ##
- match = self.coordsnoperiod_re.search(eline)
+ ## Header End ##
+ if self.hend_re.search(eline):
+ in_header = False
+ continue
+
+ ## Alternative units format M71/M72
+ # Supposed to be just in the body (yes, the body)
+ # but some put it in the header (PADS for example).
+ # Will detect anywhere. Occurrence will change the
+ # object's units.
+ match = self.meas_re.match(eline)
if match:
- try:
- #x = float(match.group(1))/10000
- x = self.parse_number(match.group(1))
- current_x = x
- except TypeError:
- x = current_x
+ #self.units = {"1": "MM", "2": "IN"}[match.group(1)]
- try:
- #y = float(match.group(2))/10000
- y = self.parse_number(match.group(2))
- current_y = y
- except TypeError:
- y = current_y
+ # Modified for issue #80
+ self.convert_units({"1": "MM", "2": "IN"}[match.group(1)])
+ log.debug(" Units: %s" % self.units)
+ continue
- if x is None or y is None:
- log.error("Missing coordinates")
+ #### Body ####
+ if not in_header:
+
+ ## Tool change ##
+ match = self.toolsel_re.search(eline)
+ if match:
+ current_tool = str(int(match.group(1)))
+ log.debug("Tool change: %s" % current_tool)
continue
- self.drills.append({'point': Point((x, y)), 'tool': current_tool})
- continue
+ ## Coordinates without period ##
+ match = self.coordsnoperiod_re.search(eline)
+ if match:
+ try:
+ #x = float(match.group(1))/10000
+ x = self.parse_number(match.group(1))
+ current_x = x
+ except TypeError:
+ x = current_x
- ## Coordinates with period: Use literally. ##
- match = self.coordsperiod_re.search(eline)
- if match:
- try:
- x = float(match.group(1))
- current_x = x
- except TypeError:
- x = current_x
+ try:
+ #y = float(match.group(2))/10000
+ y = self.parse_number(match.group(2))
+ current_y = y
+ except TypeError:
+ y = current_y
- try:
- y = float(match.group(2))
- current_y = y
- except TypeError:
- y = current_y
+ if x is None or y is None:
+ log.error("Missing coordinates")
+ continue
- if x is None or y is None:
- log.error("Missing coordinates")
+ self.drills.append({'point': Point((x, y)), 'tool': current_tool})
+ log.debug("{:15} {:8} {:8}".format(eline, x, y))
continue
- self.drills.append({'point': Point((x, y)), 'tool': current_tool})
- continue
+ ## Coordinates with period: Use literally. ##
+ match = self.coordsperiod_re.search(eline)
+ if match:
+ try:
+ x = float(match.group(1))
+ current_x = x
+ except TypeError:
+ x = current_x
- #### Header ####
- if in_header:
+ try:
+ y = float(match.group(2))
+ current_y = y
+ except TypeError:
+ y = current_y
- ## Tool definitions ##
- match = self.toolset_re.search(eline)
- if match:
- name = str(int(match.group(1)))
- spec = {
- "C": float(match.group(2)),
- # "F": float(match.group(3)),
- # "S": float(match.group(4)),
- # "B": float(match.group(5)),
- # "H": float(match.group(6)),
- # "Z": float(match.group(7))
- }
- self.tools[name] = spec
- continue
+ if x is None or y is None:
+ log.error("Missing coordinates")
+ continue
- ## Units and number format ##
- match = self.units_re.match(eline)
- if match:
- self.zeros = match.group(2) or self.zeros # "T" or "L". Might be empty
- self.units = {"INCH": "IN", "METRIC": "MM"}[match.group(1)]
- continue
+ self.drills.append({'point': Point((x, y)), 'tool': current_tool})
+ log.debug("{:15} {:8} {:8}".format(eline, x, y))
+ continue
- log.warning("Line ignored: %s" % eline)
+ #### Header ####
+ if in_header:
- log.info("Zeros: %s, Units %s." % (self.zeros, self.units))
+ ## Tool definitions ##
+ match = self.toolset_re.search(eline)
+ if match:
+
+ name = str(int(match.group(1)))
+ spec = {
+ "C": float(match.group(2)),
+ # "F": float(match.group(3)),
+ # "S": float(match.group(4)),
+ # "B": float(match.group(5)),
+ # "H": float(match.group(6)),
+ # "Z": float(match.group(7))
+ }
+ self.tools[name] = spec
+ log.debug(" Tool definition: %s %s" % (name, spec))
+ continue
+
+ ## Units and number format ##
+ match = self.units_re.match(eline)
+ if match:
+ self.zeros = match.group(2) or self.zeros # "T" or "L". Might be empty
+
+ #self.units = {"INCH": "IN", "METRIC": "MM"}[match.group(1)]
+
+ # Modified for issue #80
+ self.convert_units({"INCH": "IN", "METRIC": "MM"}[match.group(1)])
+ log.debug(" Units/Format: %s %s" % (self.units, self.zeros))
+ continue
+
+ log.warning("Line ignored: %s" % eline)
+
+ log.info("Zeros: %s, Units %s." % (self.zeros, self.units))
+
+ except Exception as e:
+ log.error("PARSING FAILED. Line %d: %s" % (line_num, eline))
+ raise
def parse_number(self, number_str):
"""
@@ -1974,16 +2518,21 @@ class Excellon(Geometry):
# If less than size digits, they are automatically added,
# 5 digits then are divided by 10^3 and so on.
match = self.leadingzeros_re.search(number_str)
- return float(number_str)/(10**(len(match.group(1)) + len(match.group(2)) - 2))
+ if self.units.lower() == "in":
+ return float(number_str) / \
+ (10 ** (len(match.group(1)) + len(match.group(2)) - 2))
+ else:
+ return float(number_str) / \
+ (10 ** (len(match.group(1)) + len(match.group(2)) - 3))
else: # Trailing
# You must show all zeros to the right of the number and can omit
# all zeros to the left of the number. The CNC-7 will count the number
# of digits you typed and automatically fill in the missing zeros.
if self.units.lower() == "in": # Inches is 00.0000
- return float(number_str)/10000
-
- return float(number_str)/1000 # Metric is 000.000
+ return float(number_str) / 10000
+ else:
+ return float(number_str) / 1000 # Metric is 000.000
def create_geometry(self):
"""
@@ -1995,9 +2544,9 @@ class Excellon(Geometry):
self.solid_geometry = []
for drill in self.drills:
- #poly = drill['point'].buffer(self.tools[drill['tool']]["C"]/2.0)
+ # poly = drill['point'].buffer(self.tools[drill['tool']]["C"]/2.0)
tooldia = self.tools[drill['tool']]['C']
- poly = drill['point'].buffer(tooldia/2.0)
+ poly = drill['point'].buffer(tooldia / 2.0)
self.solid_geometry.append(poly)
def scale(self, factor):
@@ -2085,11 +2634,19 @@ class CNCjob(Geometry):
"""
defaults = {
- "zdownrate": None
+ "zdownrate": None,
+ "coordinate_format": "X%.4fY%.4f"
}
- def __init__(self, units="in", kind="generic", z_move=0.1,
- feedrate=3.0, z_cut=-0.002, tooldia=0.0, zdownrate=None):
+ def __init__(self,
+ units="in",
+ kind="generic",
+ z_move=0.1,
+ feedrate=3.0,
+ z_cut=-0.002,
+ tooldia=0.0,
+ zdownrate=None,
+ spindlespeed=None):
Geometry.__init__(self)
self.kind = kind
@@ -2106,6 +2663,7 @@ class CNCjob(Geometry):
self.input_geometry_bounds = None
self.gcode_parsed = None
self.steps_per_circ = 20 # Used when parsing G-code arcs
+
if zdownrate is not None:
self.zdownrate = float(zdownrate)
elif CNCjob.defaults["zdownrate"] is not None:
@@ -2113,6 +2671,7 @@ class CNCjob(Geometry):
else:
self.zdownrate = None
+ self.spindlespeed = spindlespeed
# Attributes to be included in serialization
# Always append to it because it carries contents
@@ -2121,34 +2680,6 @@ class CNCjob(Geometry):
'gcode', 'input_geometry_bounds', 'gcode_parsed',
'steps_per_circ']
- # Buffer for linear (No polygons or iterable geometry) elements
- # and their properties.
- self.flat_geometry = []
-
- # 2D index of self.flat_geometry
- self.flat_geometry_rtree = rtindex.Index()
-
- # Current insert position to flat_geometry
- self.fg_current_index = 0
-
- def flatten(self, geo):
- """
- Flattens the input geometry into an array of non-iterable geometry
- elements and indexes into rtree by their first and last coordinate
- pairs.
-
- :param geo:
- :return:
- """
- try:
- for g in geo:
- self.flatten(g)
- except TypeError: # is not iterable
- self.flat_geometry.append({"path": geo})
- self.flat_geometry_rtree.insert(self.fg_current_index, geo.coords[0])
- self.flat_geometry_rtree.insert(self.fg_current_index, geo.coords[-1])
- self.fg_current_index += 1
-
def convert_units(self, units):
factor = Geometry.convert_units(self, units)
log.debug("CNCjob.convert_units()")
@@ -2160,45 +2691,8 @@ class CNCjob(Geometry):
return factor
- def generate_from_excellon(self, exobj):
- """
- Generates G-code for drilling from Excellon object.
- self.gcode becomes a list, each element is a
- different job for each tool in the excellon code.
- """
- self.kind = "drill"
- self.gcode = []
-
- t = "G00 X%.4fY%.4f\n"
- down = "G01 Z%.4f\n" % self.z_cut
- up = "G01 Z%.4f\n" % self.z_move
-
- for tool in exobj.tools:
-
- points = []
-
- for drill in exobj.drill:
- if drill['tool'] == tool:
- points.append(drill['point'])
-
- gcode = self.unitcode[self.units.upper()] + "\n"
- gcode += self.absolutecode + "\n"
- gcode += self.feedminutecode + "\n"
- gcode += "F%.2f\n" % self.feedrate
- gcode += "G00 Z%.4f\n" % self.z_move # Move to travel height
- gcode += "M03\n" # Spindle start
- gcode += self.pausecode + "\n"
-
- for point in points:
- gcode += t % point
- gcode += down + up
-
- gcode += t % (0, 0)
- gcode += "M05\n" # Spindle stop
-
- self.gcode.append(gcode)
-
- def generate_from_excellon_by_tool(self, exobj, tools="all"):
+ def generate_from_excellon_by_tool(self, exobj, tools="all",
+ toolchange=False, toolchangez=0.1):
"""
Creates gcode for this object from an Excellon object
for the specified tools.
@@ -2210,112 +2704,87 @@ class CNCjob(Geometry):
:return: None
:rtype: None
"""
- log.debug("Creating CNC Job from Excellon...")
- if tools == "all":
- tools = [tool for tool in exobj.tools]
- else:
- tools = [x.strip() for x in tools.split(",")]
- tools = filter(lambda i: i in exobj.tools, tools)
- log.debug("Tools are: %s" % str(tools))
- points = []
+ log.debug("Creating CNC Job from Excellon...")
+
+ # Tools
+
+ # sort the tools list by the second item in tuple (here we have a dict with diameter of the tool)
+ # so we actually are sorting the tools by diameter
+ sorted_tools = sorted(exobj.tools.items(), key = lambda x: x[1])
+ if tools == "all":
+ tools = str([i[0] for i in sorted_tools]) # we get a string of ordered tools
+ log.debug("Tools 'all' and sorted are: %s" % str(tools))
+ else:
+ selected_tools = [x.strip() for x in tools.split(",")] # we strip spaces and also separate the tools by ','
+ selected_tools = filter(lambda i: i in selected_tools, selected_tools)
+ tools = [i for i,j in sorted_tools for k in selected_tools if i == k] # create a sorted list of selected tools from the sorted_tools list
+ log.debug("Tools selected and sorted are: %s" % str(tools))
+
+ # Points (Group by tool)
+ points = {}
for drill in exobj.drills:
if drill['tool'] in tools:
- points.append(drill['point'])
+ try:
+ points[drill['tool']].append(drill['point'])
+ except KeyError:
+ points[drill['tool']] = [drill['point']]
- log.debug("Found %d drills." % len(points))
- #self.kind = "drill"
+ #log.debug("Found %d drills." % len(points))
self.gcode = []
- t = "G00 X%.4fY%.4f\n"
+ # Basic G-Code macros
+ t = "G00 " + CNCjob.defaults["coordinate_format"] + "\n"
down = "G01 Z%.4f\n" % self.z_cut
up = "G01 Z%.4f\n" % self.z_move
+ # Initialization
gcode = self.unitcode[self.units.upper()] + "\n"
gcode += self.absolutecode + "\n"
gcode += self.feedminutecode + "\n"
gcode += "F%.2f\n" % self.feedrate
gcode += "G00 Z%.4f\n" % self.z_move # Move to travel height
- gcode += "M03\n" # Spindle start
+
+ if self.spindlespeed is not None:
+ gcode += "M03 S%d\n" % int(self.spindlespeed) # Spindle start with configured speed
+ else:
+ gcode += "M03\n" # Spindle start
+
gcode += self.pausecode + "\n"
- for point in points:
- x, y = point.coords.xy
- gcode += t % (x[0], y[0])
- gcode += down + up
+ for tool in tools:
+
+ # Tool change sequence (optional)
+ if toolchange:
+ gcode += "G00 Z%.4f\n" % toolchangez
+ gcode += "T%d\n" % int(tool) # Indicate tool slot (for automatic tool changer)
+ gcode += "M5\n" # Spindle Stop
+ gcode += "M6\n" # Tool change
+ gcode += "(MSG, Change to tool dia=%.4f)\n" % exobj.tools[tool]["C"]
+ gcode += "M0\n" # Temporary machine stop
+ if self.spindlespeed is not None:
+ gcode += "M03 S%d\n" % int(self.spindlespeed) # Spindle start with configured speed
+ else:
+ gcode += "M03\n" # Spindle start
+
+ # Drillling!
+ for point in points[tool]:
+ x, y = point.coords.xy
+ gcode += t % (x[0], y[0])
+ gcode += down + up
gcode += t % (0, 0)
gcode += "M05\n" # Spindle stop
self.gcode = gcode
- def generate_from_geometry(self, geometry, append=True, tooldia=None, tolerance=0):
- """
- Generates G-Code from a Geometry object. Stores in ``self.gcode``.
-
- Algorithm description:
- ----------------------
- Follow geometry paths in the order they are being read. No attempt
- to optimize.
-
- :param geometry: Geometry defining the toolpath
- :type geometry: Geometry
- :param append: Wether to append to self.gcode or re-write it.
- :type append: bool
- :param tooldia: If given, sets the tooldia property but does
- not affect the process in any other way.
- :type tooldia: bool
- :param tolerance: All points in the simplified object will be within the
- tolerance distance of the original geometry.
- :return: None
- :rtype: None
- """
- if tooldia is not None:
- self.tooldia = tooldia
-
- self.input_geometry_bounds = geometry.bounds()
-
- if not append:
- self.gcode = ""
-
- # Initial G-Code
- self.gcode = self.unitcode[self.units.upper()] + "\n"
- self.gcode += self.absolutecode + "\n"
- self.gcode += self.feedminutecode + "\n"
- self.gcode += "F%.2f\n" % self.feedrate
- self.gcode += "G00 Z%.4f\n" % self.z_move # Move (up) to travel height
- self.gcode += "M03\n" # Spindle start
- self.gcode += self.pausecode + "\n"
-
- # Iterate over geometry and run individual methods
- # depending on type
- for geo in geometry.solid_geometry:
-
- if type(geo) == Polygon:
- self.gcode += self.polygon2gcode(geo, tolerance=tolerance)
- continue
-
- if type(geo) == LineString or type(geo) == LinearRing:
- self.gcode += self.linear2gcode(geo, tolerance=tolerance)
- continue
-
- if type(geo) == Point:
- self.gcode += self.point2gcode(geo)
- continue
-
- if type(geo) == MultiPolygon:
- for poly in geo:
- self.gcode += self.polygon2gcode(poly, tolerance=tolerance)
- continue
-
- log.warning("G-code generation not implemented for %s" % (str(type(geo))))
-
- # Finish
- self.gcode += "G00 Z%.4f\n" % self.z_move # Stop cutting
- self.gcode += "G00 X0Y0\n"
- self.gcode += "M05\n" # Spindle stop
-
- def generate_from_geometry_2(self, geometry, append=True, tooldia=None, tolerance=0):
+ def generate_from_geometry_2(self,
+ geometry,
+ append=True,
+ tooldia=None,
+ tolerance=0,
+ multidepth=False,
+ depthpercut=None):
"""
Second algorithm to generate from Geometry.
@@ -2327,21 +2796,32 @@ class CNCjob(Geometry):
:param append:
:param tooldia:
:param tolerance:
+ :param multidepth: If True, use multiple passes to reach
+ the desired depth.
+ :param depthpercut: Maximum depth in each pass.
:return: None
"""
- assert isinstance(geometry, Geometry)
+ assert isinstance(geometry, Geometry), \
+ "Expected a Geometry, got %s" % type(geometry)
+
+ log.debug("generate_from_geometry_2()")
## Flatten the geometry
+ # Only linear elements (no polygons) remain.
flat_geometry = geometry.flatten(pathonly=True)
log.debug("%d paths" % len(flat_geometry))
## Index first and last points in paths
+ # What points to index.
def get_pts(o):
return [o.coords[0], o.coords[-1]]
+ # Create the indexed storage.
storage = FlatCAMRTreeStorage()
storage.get_points = get_pts
+ # Store the geometry
+ log.debug("Indexing geometry before generating G-Code...")
for shape in flat_geometry:
if shape is not None: # TODO: This shouldn't have happened.
storage.insert(shape)
@@ -2349,7 +2829,7 @@ class CNCjob(Geometry):
if tooldia is not None:
self.tooldia = tooldia
- self.input_geometry_bounds = geometry.bounds()
+ # self.input_geometry_bounds = geometry.bounds()
if not append:
self.gcode = ""
@@ -2360,10 +2840,14 @@ class CNCjob(Geometry):
self.gcode += self.feedminutecode + "\n"
self.gcode += "F%.2f\n" % self.feedrate
self.gcode += "G00 Z%.4f\n" % self.z_move # Move (up) to travel height
- self.gcode += "M03\n" # Spindle start
+ if self.spindlespeed is not None:
+ self.gcode += "M03 S%d\n" % int(self.spindlespeed) # Spindle start with configured speed
+ else:
+ self.gcode += "M03\n" # Spindle start
self.gcode += self.pausecode + "\n"
## Iterate over geometry paths getting the nearest each time.
+ log.debug("Starting G-Code...")
path_count = 0
current_pt = (0, 0)
pt, geo = storage.nearest(current_pt)
@@ -2376,18 +2860,79 @@ class CNCjob(Geometry):
# deletion will fail.
storage.remove(geo)
- if list(pt) == list(geo.coords[-1]):
- #print "Reversing"
+ # If last point in geometry is the nearest
+ # but prefer the first one if last point == first point
+ # then reverse coordinates.
+ if pt != geo.coords[0] and pt == geo.coords[-1]:
geo.coords = list(geo.coords)[::-1]
- # G-code
- if type(geo) == LineString or type(geo) == LinearRing:
- self.gcode += self.linear2gcode(geo, tolerance=tolerance)
- elif type(geo) == Point:
- self.gcode += self.point2gcode(geo)
- else:
- log.warning("G-code generation not implemented for %s" % (str(type(geo))))
+ #---------- Single depth/pass --------
+ if not multidepth:
+ # G-code
+ # Note: self.linear2gcode() and self.point2gcode() will
+ # lower and raise the tool every time.
+ if type(geo) == LineString or type(geo) == LinearRing:
+ self.gcode += self.linear2gcode(geo, tolerance=tolerance)
+ elif type(geo) == Point:
+ self.gcode += self.point2gcode(geo)
+ else:
+ log.warning("G-code generation not implemented for %s" % (str(type(geo))))
+ #--------- Multi-pass ---------
+ else:
+ if isinstance(self.z_cut, Decimal):
+ z_cut = self.z_cut
+ else:
+ z_cut = Decimal(self.z_cut).quantize(Decimal('0.000000001'))
+
+ if depthpercut is None:
+ depthpercut = z_cut
+ elif not isinstance(depthpercut, Decimal):
+ depthpercut = Decimal(depthpercut).quantize(Decimal('0.000000001'))
+
+ depth = 0
+ reverse = False
+ while depth > z_cut:
+
+ # Increase depth. Limit to z_cut.
+ depth -= depthpercut
+ if depth < z_cut:
+ depth = z_cut
+
+ # Cut at specific depth and do not lift the tool.
+ # Note: linear2gcode() will use G00 to move to the
+ # first point in the path, but it should be already
+ # at the first point if the tool is down (in the material).
+ # So, an extra G00 should show up but is inconsequential.
+ if type(geo) == LineString or type(geo) == LinearRing:
+ self.gcode += self.linear2gcode(geo, tolerance=tolerance,
+ zcut=depth,
+ up=False)
+
+ # Ignore multi-pass for points.
+ elif type(geo) == Point:
+ self.gcode += self.point2gcode(geo)
+ break # Ignoring ...
+
+ else:
+ log.warning("G-code generation not implemented for %s" % (str(type(geo))))
+
+ # Reverse coordinates if not a loop so we can continue
+ # cutting without returning to the beginhing.
+ if type(geo) == LineString:
+ geo.coords = list(geo.coords)[::-1]
+ reverse = True
+
+ # If geometry is reversed, revert.
+ if reverse:
+ if type(geo) == LineString:
+ geo.coords = list(geo.coords)[::-1]
+
+ # Lift the tool
+ self.gcode += "G00 Z%.4f\n" % self.z_move
+ # self.gcode += "( End of path. )\n"
+
+ # Did deletion at the beginning.
# Delete from index, update current location and continue.
#rti.delete(hits[0], geo.coords[0])
#rti.delete(hits[0], geo.coords[-1])
@@ -2443,7 +2988,7 @@ class CNCjob(Geometry):
# 0 4 12
# G01 X-0.007 Y-0.057
# --> codes_idx = [0, 4, 12]
- codes = "NMGXYZIJFP"
+ codes = "NMGXYZIJFPST"
codes_idx = []
i = 0
for ch in line:
@@ -2456,7 +3001,7 @@ class CNCjob(Geometry):
# Separate codes in line
parts = []
- for p in range(n_codes-1):
+ for p in range(n_codes - 1):
parts.append(line[codes_idx[p]:codes_idx[p+1]].strip())
parts.append(line[codes_idx[-1]:].strip())
@@ -2552,7 +3097,7 @@ class CNCjob(Geometry):
self.gcode_parsed = geometry
return geometry
-
+
# def plot(self, tooldia=None, dpi=75, margin=0.1,
# color={"T": ["#F0E24D", "#B5AB3A"], "C": ["#5E6CFF", "#4650BD"]},
# alpha={"T": 0.3, "C": 1.0}):
@@ -2589,8 +3134,8 @@ class CNCjob(Geometry):
# return fig
def plot2(self, axes, tooldia=None, dpi=75, margin=0.1,
- color={"T": ["#F0E24D", "#B5AB3A"], "C": ["#5E6CFF", "#4650BD"]},
- alpha={"T": 0.3, "C": 1.0}, tool_tolerance=0.0005):
+ color={"T": ["#F0E24D", "#B5AB3A"], "C": ["#5E6CFF", "#4650BD"]},
+ alpha={"T": 0.3, "C": 1.0}, tool_tolerance=0.0005):
"""
Plots the G-code job onto the given axes.
@@ -2632,57 +3177,9 @@ class CNCjob(Geometry):
# TODO: This takes forever. Too much data?
self.solid_geometry = cascaded_union([geo['geom'] for geo in self.gcode_parsed])
- def polygon2gcode(self, polygon, tolerance=0):
- """
- Creates G-Code for the exterior and all interior paths
- of a polygon.
-
- :param polygon: A Shapely.Polygon
- :type polygon: Shapely.Polygon
- :param tolerance: All points in the simplified object will be within the
- tolerance distance of the original geometry.
- :type tolerance: float
- :return: G-code to cut along polygon.
- :rtype: str
- """
-
- if tolerance > 0:
- target_polygon = polygon.simplify(tolerance)
- else:
- target_polygon = polygon
-
- gcode = ""
- t = "G0%d X%.4fY%.4f\n"
- path = list(target_polygon.exterior.coords) # Polygon exterior
- gcode += t % (0, path[0][0], path[0][1]) # Move to first point
-
- if self.zdownrate is not None:
- gcode += "F%.2f\n" % self.zdownrate
- gcode += "G01 Z%.4f\n" % self.z_cut # Start cutting
- gcode += "F%.2f\n" % self.feedrate
- else:
- gcode += "G01 Z%.4f\n" % self.z_cut # Start cutting
-
- for pt in path[1:]:
- gcode += t % (1, pt[0], pt[1]) # Linear motion to point
- gcode += "G00 Z%.4f\n" % self.z_move # Stop cutting
- for ints in target_polygon.interiors: # Polygon interiors
- path = list(ints.coords)
- gcode += t % (0, path[0][0], path[0][1]) # Move to first point
-
- if self.zdownrate is not None:
- gcode += "F%.2f\n" % self.zdownrate
- gcode += "G01 Z%.4f\n" % self.z_cut # Start cutting
- gcode += "F%.2f\n" % self.feedrate
- else:
- gcode += "G01 Z%.4f\n" % self.z_cut # Start cutting
-
- for pt in path[1:]:
- gcode += t % (1, pt[0], pt[1]) # Linear motion to point
- gcode += "G00 Z%.4f\n" % self.z_move # Stop cutting
- return gcode
-
- def linear2gcode(self, linear, tolerance=0):
+ def linear2gcode(self, linear, tolerance=0, down=True, up=True,
+ zcut=None, ztravel=None, downrate=None,
+ feedrate=None, cont=False):
"""
Generates G-code to cut along the linear feature.
@@ -2691,35 +3188,62 @@ class CNCjob(Geometry):
:param tolerance: All points in the simplified object will be within the
tolerance distance of the original geometry.
:type tolerance: float
- :return: G-code to cut alon the linear feature.
+ :return: G-code to cut along the linear feature.
:rtype: str
"""
+ if zcut is None:
+ zcut = self.z_cut
+
+ if ztravel is None:
+ ztravel = self.z_move
+
+ if downrate is None:
+ downrate = self.zdownrate
+
+ if feedrate is None:
+ feedrate = self.feedrate
+
+ t = "G0%d " + CNCjob.defaults["coordinate_format"] + "\n"
+
+ # Simplify paths?
if tolerance > 0:
target_linear = linear.simplify(tolerance)
else:
target_linear = linear
gcode = ""
- t = "G0%d X%.4fY%.4f\n"
+
path = list(target_linear.coords)
- gcode += t % (0, path[0][0], path[0][1]) # Move to first point
- if self.zdownrate is not None:
- gcode += "F%.2f\n" % self.zdownrate
- gcode += "G01 Z%.4f\n" % self.z_cut # Start cutting
- gcode += "F%.2f\n" % self.feedrate
- else:
- gcode += "G01 Z%.4f\n" % self.z_cut # Start cutting
+ # Move fast to 1st point
+ if not cont:
+ gcode += t % (0, path[0][0], path[0][1]) # Move to first point
+ # Move down to cutting depth
+ if down:
+ # Different feedrate for vertical cut?
+ if self.zdownrate is not None:
+ gcode += "F%.2f\n" % downrate
+ gcode += "G01 Z%.4f\n" % zcut # Start cutting
+ gcode += "F%.2f\n" % feedrate # Restore feedrate
+ else:
+ gcode += "G01 Z%.4f\n" % zcut # Start cutting
+
+ # Cutting...
for pt in path[1:]:
gcode += t % (1, pt[0], pt[1]) # Linear motion to point
- gcode += "G00 Z%.4f\n" % self.z_move # Stop cutting
+
+ # Up to travelling height.
+ if up:
+ gcode += "G00 Z%.4f\n" % ztravel # Stop cutting
+
return gcode
def point2gcode(self, point):
gcode = ""
- t = "G0%d X%.4fY%.4f\n"
+ #t = "G0%d X%.4fY%.4f\n"
+ t = "G0%d " + CNCjob.defaults["coordinate_format"] + "\n"
path = list(point.coords)
gcode += t % (0, path[0][0], path[0][1]) # Move to first point
@@ -2826,7 +3350,7 @@ def arc(center, radius, start, stop, direction, steps_per_circ):
:return: The desired arc, as list of tuples
:rtype: list
"""
- # TODO: Resolution should be established by fraction of total length, not angle.
+ # TODO: Resolution should be established by maximum error from the exact arc.
da_sign = {"cw": -1.0, "ccw": 1.0}
points = []
@@ -2863,42 +3387,32 @@ def arc_angle(start, stop, direction):
return angle
-# def clear_poly(poly, tooldia, overlap=0.1):
+# def find_polygon(poly, point):
# """
-# Creates a list of Shapely geometry objects covering the inside
-# of a Shapely.Polygon. Use for removing all the copper in a region
-# or bed flattening.
+# Find an object that object.contains(Point(point)) in
+# poly, which can can be iterable, contain iterable of, or
+# be itself an implementer of .contains().
#
-# :param poly: Target polygon
-# :type poly: Shapely.Polygon
-# :param tooldia: Diameter of the tool
-# :type tooldia: float
-# :param overlap: Fraction of the tool diameter to overlap
-# in each pass.
-# :type overlap: float
-# :return: list of Shapely.Polygon
-# :rtype: list
+# :param poly: See description
+# :return: Polygon containing point or None.
# """
-# poly_cuts = [poly.buffer(-tooldia/2.0)]
-# while True:
-# poly = poly_cuts[-1].buffer(-tooldia*(1-overlap))
-# if poly.area > 0:
-# poly_cuts.append(poly)
-# else:
-# break
-# return poly_cuts
-
-
-def find_polygon(poly_set, point):
- """
- Return the first polygon in the list of polygons poly_set
- that contains the given point.
- """
- p = Point(point)
- for poly in poly_set:
- if poly.contains(p):
- return poly
- return None
+#
+# if poly is None:
+# return None
+#
+# try:
+# for sub_poly in poly:
+# p = find_polygon(sub_poly, point)
+# if p is not None:
+# return p
+# except TypeError:
+# try:
+# if poly.contains(Point(point)):
+# return poly
+# except AttributeError:
+# return None
+#
+# return None
def to_dict(obj):
@@ -2946,7 +3460,7 @@ def dict2obj(d):
return d
-def plotg(geo, solid_poly=False):
+def plotg(geo, solid_poly=False, color="black"):
try:
_ = iter(geo)
except:
@@ -2964,15 +3478,15 @@ def plotg(geo, solid_poly=False):
ax.add_patch(patch)
else:
x, y = g.exterior.coords.xy
- plot(x, y)
+ plot(x, y, color=color)
for ints in g.interiors:
x, y = ints.coords.xy
- plot(x, y)
+ plot(x, y, color=color)
continue
if type(g) == LineString or type(g) == LinearRing:
x, y = g.coords.xy
- plot(x, y)
+ plot(x, y, color=color)
continue
if type(g) == Point:
@@ -2982,7 +3496,7 @@ def plotg(geo, solid_poly=False):
try:
_ = iter(g)
- plotg(g)
+ plotg(g, color=color)
except:
log.error("Cannot plot: " + str(type(g)))
continue
@@ -3001,209 +3515,209 @@ def parse_gerber_number(strnumber, frac_digits):
:return: The number in floating point.
:rtype: float
"""
- return int(strnumber)*(10**(-frac_digits))
+ return int(strnumber) * (10 ** (-frac_digits))
-def voronoi(P):
- """
- Returns a list of all edges of the voronoi diagram for the given input points.
- """
- delauny = Delaunay(P)
- triangles = delauny.points[delauny.vertices]
-
- circum_centers = np.array([triangle_csc(tri) for tri in triangles])
- long_lines_endpoints = []
-
- lineIndices = []
- for i, triangle in enumerate(triangles):
- circum_center = circum_centers[i]
- for j, neighbor in enumerate(delauny.neighbors[i]):
- if neighbor != -1:
- lineIndices.append((i, neighbor))
- else:
- ps = triangle[(j+1)%3] - triangle[(j-1)%3]
- ps = np.array((ps[1], -ps[0]))
-
- middle = (triangle[(j+1)%3] + triangle[(j-1)%3]) * 0.5
- di = middle - triangle[j]
-
- ps /= np.linalg.norm(ps)
- di /= np.linalg.norm(di)
-
- if np.dot(di, ps) < 0.0:
- ps *= -1000.0
- else:
- ps *= 1000.0
-
- long_lines_endpoints.append(circum_center + ps)
- lineIndices.append((i, len(circum_centers) + len(long_lines_endpoints)-1))
-
- vertices = np.vstack((circum_centers, long_lines_endpoints))
-
- # filter out any duplicate lines
- lineIndicesSorted = np.sort(lineIndices) # make (1,2) and (2,1) both (1,2)
- lineIndicesTupled = [tuple(row) for row in lineIndicesSorted]
- lineIndicesUnique = np.unique(lineIndicesTupled)
-
- return vertices, lineIndicesUnique
-
-
-def triangle_csc(pts):
- rows, cols = pts.shape
-
- A = np.bmat([[2 * np.dot(pts, pts.T), np.ones((rows, 1))],
- [np.ones((1, rows)), np.zeros((1, 1))]])
-
- b = np.hstack((np.sum(pts * pts, axis=1), np.ones((1))))
- x = np.linalg.solve(A,b)
- bary_coords = x[:-1]
- return np.sum(pts * np.tile(bary_coords.reshape((pts.shape[0], 1)), (1, pts.shape[1])), axis=0)
-
-
-def voronoi_cell_lines(points, vertices, lineIndices):
- """
- Returns a mapping from a voronoi cell to its edges.
-
- :param points: shape (m,2)
- :param vertices: shape (n,2)
- :param lineIndices: shape (o,2)
- :rtype: dict point index -> list of shape (n,2) with vertex indices
- """
- kd = KDTree(points)
-
- cells = collections.defaultdict(list)
- for i1, i2 in lineIndices:
- v1, v2 = vertices[i1], vertices[i2]
- mid = (v1+v2)/2
- _, (p1Idx, p2Idx) = kd.query(mid, 2)
- cells[p1Idx].append((i1, i2))
- cells[p2Idx].append((i1, i2))
-
- return cells
-
-
-def voronoi_edges2polygons(cells):
- """
- Transforms cell edges into polygons.
-
- :param cells: as returned from voronoi_cell_lines
- :rtype: dict point index -> list of vertex indices which form a polygon
- """
-
- # first, close the outer cells
- for pIdx, lineIndices_ in cells.items():
- dangling_lines = []
- for i1, i2 in lineIndices_:
- connections = filter(lambda (i1_, i2_): (i1, i2) != (i1_, i2_) and (i1 == i1_ or i1 == i2_ or i2 == i1_ or i2 == i2_), lineIndices_)
- assert 1 <= len(connections) <= 2
- if len(connections) == 1:
- dangling_lines.append((i1, i2))
- assert len(dangling_lines) in [0, 2]
- if len(dangling_lines) == 2:
- (i11, i12), (i21, i22) = dangling_lines
-
- # determine which line ends are unconnected
- connected = filter(lambda (i1,i2): (i1,i2) != (i11,i12) and (i1 == i11 or i2 == i11), lineIndices_)
- i11Unconnected = len(connected) == 0
-
- connected = filter(lambda (i1,i2): (i1,i2) != (i21,i22) and (i1 == i21 or i2 == i21), lineIndices_)
- i21Unconnected = len(connected) == 0
-
- startIdx = i11 if i11Unconnected else i12
- endIdx = i21 if i21Unconnected else i22
-
- cells[pIdx].append((startIdx, endIdx))
-
- # then, form polygons by storing vertex indices in (counter-)clockwise order
- polys = dict()
- for pIdx, lineIndices_ in cells.items():
- # get a directed graph which contains both directions and arbitrarily follow one of both
- directedGraph = lineIndices_ + [(i2, i1) for (i1, i2) in lineIndices_]
- directedGraphMap = collections.defaultdict(list)
- for (i1, i2) in directedGraph:
- directedGraphMap[i1].append(i2)
- orderedEdges = []
- currentEdge = directedGraph[0]
- while len(orderedEdges) < len(lineIndices_):
- i1 = currentEdge[1]
- i2 = directedGraphMap[i1][0] if directedGraphMap[i1][0] != currentEdge[0] else directedGraphMap[i1][1]
- nextEdge = (i1, i2)
- orderedEdges.append(nextEdge)
- currentEdge = nextEdge
-
- polys[pIdx] = [i1 for (i1, i2) in orderedEdges]
-
- return polys
-
-
-def voronoi_polygons(points):
- """
- Returns the voronoi polygon for each input point.
-
- :param points: shape (n,2)
- :rtype: list of n polygons where each polygon is an array of vertices
- """
- vertices, lineIndices = voronoi(points)
- cells = voronoi_cell_lines(points, vertices, lineIndices)
- polys = voronoi_edges2polygons(cells)
- polylist = []
- for i in xrange(len(points)):
- poly = vertices[np.asarray(polys[i])]
- polylist.append(poly)
- return polylist
-
-
-class Zprofile:
- def __init__(self):
-
- # data contains lists of [x, y, z]
- self.data = []
-
- # Computed voronoi polygons (shapely)
- self.polygons = []
- pass
-
- def plot_polygons(self):
- axes = plt.subplot(1, 1, 1)
-
- plt.axis([-0.05, 1.05, -0.05, 1.05])
-
- for poly in self.polygons:
- p = PolygonPatch(poly, facecolor=np.random.rand(3, 1), alpha=0.3)
- axes.add_patch(p)
-
- def init_from_csv(self, filename):
- pass
-
- def init_from_string(self, zpstring):
- pass
-
- def init_from_list(self, zplist):
- self.data = zplist
-
- def generate_polygons(self):
- self.polygons = [Polygon(p) for p in voronoi_polygons(array([[x[0], x[1]] for x in self.data]))]
-
- def normalize(self, origin):
- pass
-
- def paste(self, path):
- """
- Return a list of dictionaries containing the parts of the original
- path and their z-axis offset.
- """
-
- # At most one region/polygon will contain the path
- containing = [i for i in range(len(self.polygons)) if self.polygons[i].contains(path)]
-
- if len(containing) > 0:
- return [{"path": path, "z": self.data[containing[0]][2]}]
-
- # All region indexes that intersect with the path
- crossing = [i for i in range(len(self.polygons)) if self.polygons[i].intersects(path)]
-
- return [{"path": path.intersection(self.polygons[i]),
- "z": self.data[i][2]} for i in crossing]
+# def voronoi(P):
+# """
+# Returns a list of all edges of the voronoi diagram for the given input points.
+# """
+# delauny = Delaunay(P)
+# triangles = delauny.points[delauny.vertices]
+#
+# circum_centers = np.array([triangle_csc(tri) for tri in triangles])
+# long_lines_endpoints = []
+#
+# lineIndices = []
+# for i, triangle in enumerate(triangles):
+# circum_center = circum_centers[i]
+# for j, neighbor in enumerate(delauny.neighbors[i]):
+# if neighbor != -1:
+# lineIndices.append((i, neighbor))
+# else:
+# ps = triangle[(j+1)%3] - triangle[(j-1)%3]
+# ps = np.array((ps[1], -ps[0]))
+#
+# middle = (triangle[(j+1)%3] + triangle[(j-1)%3]) * 0.5
+# di = middle - triangle[j]
+#
+# ps /= np.linalg.norm(ps)
+# di /= np.linalg.norm(di)
+#
+# if np.dot(di, ps) < 0.0:
+# ps *= -1000.0
+# else:
+# ps *= 1000.0
+#
+# long_lines_endpoints.append(circum_center + ps)
+# lineIndices.append((i, len(circum_centers) + len(long_lines_endpoints)-1))
+#
+# vertices = np.vstack((circum_centers, long_lines_endpoints))
+#
+# # filter out any duplicate lines
+# lineIndicesSorted = np.sort(lineIndices) # make (1,2) and (2,1) both (1,2)
+# lineIndicesTupled = [tuple(row) for row in lineIndicesSorted]
+# lineIndicesUnique = np.unique(lineIndicesTupled)
+#
+# return vertices, lineIndicesUnique
+#
+#
+# def triangle_csc(pts):
+# rows, cols = pts.shape
+#
+# A = np.bmat([[2 * np.dot(pts, pts.T), np.ones((rows, 1))],
+# [np.ones((1, rows)), np.zeros((1, 1))]])
+#
+# b = np.hstack((np.sum(pts * pts, axis=1), np.ones((1))))
+# x = np.linalg.solve(A,b)
+# bary_coords = x[:-1]
+# return np.sum(pts * np.tile(bary_coords.reshape((pts.shape[0], 1)), (1, pts.shape[1])), axis=0)
+#
+#
+# def voronoi_cell_lines(points, vertices, lineIndices):
+# """
+# Returns a mapping from a voronoi cell to its edges.
+#
+# :param points: shape (m,2)
+# :param vertices: shape (n,2)
+# :param lineIndices: shape (o,2)
+# :rtype: dict point index -> list of shape (n,2) with vertex indices
+# """
+# kd = KDTree(points)
+#
+# cells = collections.defaultdict(list)
+# for i1, i2 in lineIndices:
+# v1, v2 = vertices[i1], vertices[i2]
+# mid = (v1+v2)/2
+# _, (p1Idx, p2Idx) = kd.query(mid, 2)
+# cells[p1Idx].append((i1, i2))
+# cells[p2Idx].append((i1, i2))
+#
+# return cells
+#
+#
+# def voronoi_edges2polygons(cells):
+# """
+# Transforms cell edges into polygons.
+#
+# :param cells: as returned from voronoi_cell_lines
+# :rtype: dict point index -> list of vertex indices which form a polygon
+# """
+#
+# # first, close the outer cells
+# for pIdx, lineIndices_ in cells.items():
+# dangling_lines = []
+# for i1, i2 in lineIndices_:
+# connections = filter(lambda (i1_, i2_): (i1, i2) != (i1_, i2_) and (i1 == i1_ or i1 == i2_ or i2 == i1_ or i2 == i2_), lineIndices_)
+# assert 1 <= len(connections) <= 2
+# if len(connections) == 1:
+# dangling_lines.append((i1, i2))
+# assert len(dangling_lines) in [0, 2]
+# if len(dangling_lines) == 2:
+# (i11, i12), (i21, i22) = dangling_lines
+#
+# # determine which line ends are unconnected
+# connected = filter(lambda (i1,i2): (i1,i2) != (i11,i12) and (i1 == i11 or i2 == i11), lineIndices_)
+# i11Unconnected = len(connected) == 0
+#
+# connected = filter(lambda (i1,i2): (i1,i2) != (i21,i22) and (i1 == i21 or i2 == i21), lineIndices_)
+# i21Unconnected = len(connected) == 0
+#
+# startIdx = i11 if i11Unconnected else i12
+# endIdx = i21 if i21Unconnected else i22
+#
+# cells[pIdx].append((startIdx, endIdx))
+#
+# # then, form polygons by storing vertex indices in (counter-)clockwise order
+# polys = dict()
+# for pIdx, lineIndices_ in cells.items():
+# # get a directed graph which contains both directions and arbitrarily follow one of both
+# directedGraph = lineIndices_ + [(i2, i1) for (i1, i2) in lineIndices_]
+# directedGraphMap = collections.defaultdict(list)
+# for (i1, i2) in directedGraph:
+# directedGraphMap[i1].append(i2)
+# orderedEdges = []
+# currentEdge = directedGraph[0]
+# while len(orderedEdges) < len(lineIndices_):
+# i1 = currentEdge[1]
+# i2 = directedGraphMap[i1][0] if directedGraphMap[i1][0] != currentEdge[0] else directedGraphMap[i1][1]
+# nextEdge = (i1, i2)
+# orderedEdges.append(nextEdge)
+# currentEdge = nextEdge
+#
+# polys[pIdx] = [i1 for (i1, i2) in orderedEdges]
+#
+# return polys
+#
+#
+# def voronoi_polygons(points):
+# """
+# Returns the voronoi polygon for each input point.
+#
+# :param points: shape (n,2)
+# :rtype: list of n polygons where each polygon is an array of vertices
+# """
+# vertices, lineIndices = voronoi(points)
+# cells = voronoi_cell_lines(points, vertices, lineIndices)
+# polys = voronoi_edges2polygons(cells)
+# polylist = []
+# for i in xrange(len(points)):
+# poly = vertices[np.asarray(polys[i])]
+# polylist.append(poly)
+# return polylist
+#
+#
+# class Zprofile:
+# def __init__(self):
+#
+# # data contains lists of [x, y, z]
+# self.data = []
+#
+# # Computed voronoi polygons (shapely)
+# self.polygons = []
+# pass
+#
+# def plot_polygons(self):
+# axes = plt.subplot(1, 1, 1)
+#
+# plt.axis([-0.05, 1.05, -0.05, 1.05])
+#
+# for poly in self.polygons:
+# p = PolygonPatch(poly, facecolor=np.random.rand(3, 1), alpha=0.3)
+# axes.add_patch(p)
+#
+# def init_from_csv(self, filename):
+# pass
+#
+# def init_from_string(self, zpstring):
+# pass
+#
+# def init_from_list(self, zplist):
+# self.data = zplist
+#
+# def generate_polygons(self):
+# self.polygons = [Polygon(p) for p in voronoi_polygons(array([[x[0], x[1]] for x in self.data]))]
+#
+# def normalize(self, origin):
+# pass
+#
+# def paste(self, path):
+# """
+# Return a list of dictionaries containing the parts of the original
+# path and their z-axis offset.
+# """
+#
+# # At most one region/polygon will contain the path
+# containing = [i for i in range(len(self.polygons)) if self.polygons[i].contains(path)]
+#
+# if len(containing) > 0:
+# return [{"path": path, "z": self.data[containing[0]][2]}]
+#
+# # All region indexes that intersect with the path
+# crossing = [i for i in range(len(self.polygons)) if self.polygons[i].intersects(path)]
+#
+# return [{"path": path.intersection(self.polygons[i]),
+# "z": self.data[i][2]} for i in crossing]
def autolist(obj):
@@ -3234,7 +3748,6 @@ def three_point_circle(p1, p2, p3):
# Params
T = solve(transpose(array([-b1, b2])), a1 - a2)
- print T
# Center
center = a1 + b1 * T[0]
@@ -3266,6 +3779,13 @@ class FlatCAMRTree(object):
self.get_points = lambda go: go.coords
def grow_obj2points(self, idx):
+ """
+ Increases the size of self.obj2points to fit
+ idx + 1 items.
+
+ :param idx: Index to fit into list.
+ :return: None
+ """
if len(self.obj2points) > idx:
# len == 2, idx == 1, ok.
return
@@ -3290,6 +3810,12 @@ class FlatCAMRTree(object):
self.rti.delete(self.obj2points[objid][i], (pt[0], pt[1], pt[0], pt[1]))
def nearest(self, pt):
+ """
+ Will raise StopIteration if no items are found.
+
+ :param pt:
+ :return:
+ """
return self.rti.nearest(pt, objects=True).next()
@@ -3299,13 +3825,29 @@ class FlatCAMRTreeStorage(FlatCAMRTree):
self.objects = []
+ # Optimization attempt!
+ self.indexes = {}
+
def insert(self, obj):
self.objects.append(obj)
- super(FlatCAMRTreeStorage, self).insert(len(self.objects) - 1, obj)
+ idx = len(self.objects) - 1
+ # Note: Shapely objects are not hashable any more, althought
+ # there seem to be plans to re-introduce the feature in
+ # version 2.0. For now, we will index using the object's id,
+ # but it's important to remember that shapely geometry is
+ # mutable, ie. it can be modified to a totally different shape
+ # and continue to have the same id.
+ # self.indexes[obj] = idx
+ self.indexes[id(obj)] = idx
+
+ super(FlatCAMRTreeStorage, self).insert(idx, obj)
+
+ #@profile
def remove(self, obj):
- # Get index in list
- objidx = self.objects.index(obj)
+ # See note about self.indexes in insert().
+ # objidx = self.indexes[obj]
+ objidx = self.indexes[id(obj)]
# Remove from list
self.objects[objidx] = None
@@ -3330,58 +3872,58 @@ class FlatCAMRTreeStorage(FlatCAMRTree):
return (tidx.bbox[0], tidx.bbox[1]), self.objects[tidx.object]
-class myO:
- def __init__(self, coords):
- self.coords = coords
-
-
-def test_rti():
-
- o1 = myO([(0, 0), (0, 1), (1, 1)])
- o2 = myO([(2, 0), (2, 1), (2, 1)])
- o3 = myO([(2, 0), (2, 1), (3, 1)])
-
- os = [o1, o2]
-
- idx = FlatCAMRTree()
-
- for o in range(len(os)):
- idx.insert(o, os[o])
-
- print [x.bbox for x in idx.rti.nearest((0, 0), num_results=20, objects=True)]
-
- idx.remove_obj(0, o1)
-
- print [x.bbox for x in idx.rti.nearest((0, 0), num_results=20, objects=True)]
-
- idx.remove_obj(1, o2)
-
- print [x.bbox for x in idx.rti.nearest((0, 0), num_results=20, objects=True)]
-
-
-def test_rtis():
-
- o1 = myO([(0, 0), (0, 1), (1, 1)])
- o2 = myO([(2, 0), (2, 1), (2, 1)])
- o3 = myO([(2, 0), (2, 1), (3, 1)])
-
- os = [o1, o2]
-
- idx = FlatCAMRTreeStorage()
-
- for o in range(len(os)):
- idx.insert(os[o])
-
- #os = None
- #o1 = None
- #o2 = None
-
- print [x.bbox for x in idx.rti.nearest((0, 0), num_results=20, objects=True)]
-
- idx.remove(idx.nearest((2,0))[1])
-
- print [x.bbox for x in idx.rti.nearest((0, 0), num_results=20, objects=True)]
-
- idx.remove(idx.nearest((0,0))[1])
-
- print [x.bbox for x in idx.rti.nearest((0, 0), num_results=20, objects=True)]
\ No newline at end of file
+# class myO:
+# def __init__(self, coords):
+# self.coords = coords
+#
+#
+# def test_rti():
+#
+# o1 = myO([(0, 0), (0, 1), (1, 1)])
+# o2 = myO([(2, 0), (2, 1), (2, 1)])
+# o3 = myO([(2, 0), (2, 1), (3, 1)])
+#
+# os = [o1, o2]
+#
+# idx = FlatCAMRTree()
+#
+# for o in range(len(os)):
+# idx.insert(o, os[o])
+#
+# print [x.bbox for x in idx.rti.nearest((0, 0), num_results=20, objects=True)]
+#
+# idx.remove_obj(0, o1)
+#
+# print [x.bbox for x in idx.rti.nearest((0, 0), num_results=20, objects=True)]
+#
+# idx.remove_obj(1, o2)
+#
+# print [x.bbox for x in idx.rti.nearest((0, 0), num_results=20, objects=True)]
+#
+#
+# def test_rtis():
+#
+# o1 = myO([(0, 0), (0, 1), (1, 1)])
+# o2 = myO([(2, 0), (2, 1), (2, 1)])
+# o3 = myO([(2, 0), (2, 1), (3, 1)])
+#
+# os = [o1, o2]
+#
+# idx = FlatCAMRTreeStorage()
+#
+# for o in range(len(os)):
+# idx.insert(os[o])
+#
+# #os = None
+# #o1 = None
+# #o2 = None
+#
+# print [x.bbox for x in idx.rti.nearest((0, 0), num_results=20, objects=True)]
+#
+# idx.remove(idx.nearest((2,0))[1])
+#
+# print [x.bbox for x in idx.rti.nearest((0, 0), num_results=20, objects=True)]
+#
+# idx.remove(idx.nearest((0,0))[1])
+#
+# print [x.bbox for x in idx.rti.nearest((0, 0), num_results=20, objects=True)]
diff --git a/make_win32.py b/make_win32.py
new file mode 100644
index 00000000..0a503eea
--- /dev/null
+++ b/make_win32.py
@@ -0,0 +1,49 @@
+# Files not needed: Qt, tk.dll, tcl.dll, tk/, tcl/, vtk/,
+# scipy.lib.lapack.flapack.pyd, scipy.lib.blas.fblas.pyd,
+# numpy.core._dotblas.pyd, scipy.sparse.sparsetools._bsr.pyd,
+# scipy.sparse.sparsetools._csr.pyd, scipy.sparse.sparsetools._csc.pyd,
+# scipy.sparse.sparsetools._coo.pyd
+
+import os, site, sys
+from cx_Freeze import setup, Executable
+
+## Get the site-package folder, not everybody will install
+## Python into C:\PythonXX
+site_dir = site.getsitepackages()[1]
+
+include_files = []
+include_files.append((os.path.join(site_dir, "shapely"), "shapely"))
+include_files.append((os.path.join(site_dir, "matplotlib"), "matplotlib"))
+include_files.append(("share", "share"))
+include_files.append((os.path.join(site_dir, "rtree"), "rtree"))
+include_files.append(("README.md", "README.md"))
+include_files.append(("LICENSE", "LICENSE"))
+
+base = None
+
+## Lets not open the console while running the app
+if sys.platform == "win32":
+ base = "Win32GUI"
+
+buildOptions = dict(
+ compressed=False,
+ include_files=include_files,
+ icon='share/flatcam_icon48.ico',
+ # excludes=['PyQt4', 'tk', 'tcl']
+ excludes=['scipy.lib.lapack.flapack.pyd',
+ 'scipy.lib.blas.fblas.pyd',
+ 'QtOpenGL4.dll']
+)
+
+print "INCLUDE_FILES", include_files
+
+execfile('clean.py')
+
+setup(
+ name="FlatCAM",
+ author="Juan Pablo Caram",
+ version="8.4",
+ description="FlatCAM: 2D Computer Aided PCB Manufacturing",
+ options=dict(build_exe=buildOptions),
+ executables=[Executable("FlatCAM.py", base=base)]
+)
\ No newline at end of file
diff --git a/manual/_theme/__init__.py b/manual/_theme/__init__.py
deleted file mode 100644
index 1440863d..00000000
--- a/manual/_theme/__init__.py
+++ /dev/null
@@ -1,17 +0,0 @@
-"""Sphinx ReadTheDocs theme.
-
-From https://github.com/ryan-roemer/sphinx-bootstrap-theme.
-
-"""
-import os
-
-VERSION = (0, 1, 5)
-
-__version__ = ".".join(str(v) for v in VERSION)
-__version_full__ = __version__
-
-
-def get_html_theme_path():
- """Return list of HTML theme paths."""
- cur_dir = os.path.abspath(os.path.dirname(os.path.dirname(__file__)))
- return cur_dir
diff --git a/manual/_theme/breadcrumbs.html b/manual/_theme/breadcrumbs.html
deleted file mode 100644
index 982c856f..00000000
--- a/manual/_theme/breadcrumbs.html
+++ /dev/null
@@ -1,19 +0,0 @@
-
diff --git a/manual/_theme/footer.html b/manual/_theme/footer.html
deleted file mode 100644
index c740b24c..00000000
--- a/manual/_theme/footer.html
+++ /dev/null
@@ -1,32 +0,0 @@
-
diff --git a/manual/_theme/layout.html b/manual/_theme/layout.html
deleted file mode 100644
index d7a59e1c..00000000
--- a/manual/_theme/layout.html
+++ /dev/null
@@ -1,149 +0,0 @@
-{# TEMPLATE VAR SETTINGS #}
-{%- set url_root = pathto('', 1) %}
-{%- if url_root == '#' %}{% set url_root = '' %}{% endif %}
-{%- if not embedded and docstitle %}
- {%- set titlesuffix = " — "|safe + docstitle|e %}
-{%- else %}
- {%- set titlesuffix = "" %}
-{%- endif %}
-
-
-
-
-
-
-
- {% block htmltitle %}
- {{ title|striptags|e }}{{ titlesuffix }}
- {% endblock %}
-
- {# FAVICON #}
- {% if favicon %}
-
- {% endif %}
-
- {# CSS #}
-
-
- {# JS #}
- {% if not embedded %}
-
-
- {%- for scriptfile in script_files %}
-
- {%- endfor %}
-
- {% if use_opensearch %}
-
- {% endif %}
-
- {% endif %}
-
- {# RTD hosts these file themselves, so just load on non RTD builds #}
- {% if not READTHEDOCS %}
-
-
- {% endif %}
-
- {# STICKY NAVIGATION #}
- {% if theme_sticky_navigation %}
-
- {% endif %}
-
- {% for cssfile in css_files %}
-
- {% endfor %}
-
- {%- block linktags %}
- {%- if hasdoc('about') %}
-
- {%- endif %}
- {%- if hasdoc('genindex') %}
-
- {%- endif %}
- {%- if hasdoc('search') %}
-
- {%- endif %}
- {%- if hasdoc('copyright') %}
-
- {%- endif %}
-
- {%- if parents %}
-
- {%- endif %}
- {%- if next %}
-
- {%- endif %}
- {%- if prev %}
-
- {%- endif %}
- {%- endblock %}
- {%- block extrahead %} {% endblock %}
-
-
-
-
-
-
-
-
-
- {# SIDE NAV, TOGGLES ON MOBILE #}
-
-
-
-
-
-
-
-
-
- {# MOBILE NAV, TRIGGLES SIDE NAV ON TOGGLE #}
-
-
- {{ project }}
-
-
-
- {# PAGE CONTENT #}
-
-
- {% include "breadcrumbs.html" %}
-
- {% block body %}{% endblock %}
-
- {% include "footer.html" %}
-
-
-
-
-
-
- {% include "versions.html" %}
-
-
diff --git a/manual/_theme/layout_old.html b/manual/_theme/layout_old.html
deleted file mode 100644
index deb8df2a..00000000
--- a/manual/_theme/layout_old.html
+++ /dev/null
@@ -1,205 +0,0 @@
-{#
- basic/layout.html
- ~~~~~~~~~~~~~~~~~
-
- Master layout template for Sphinx themes.
-
- :copyright: Copyright 2007-2013 by the Sphinx team, see AUTHORS.
- :license: BSD, see LICENSE for details.
-#}
-{%- block doctype -%}
-
-{%- endblock %}
-{%- set reldelim1 = reldelim1 is not defined and ' »' or reldelim1 %}
-{%- set reldelim2 = reldelim2 is not defined and ' |' or reldelim2 %}
-{%- set render_sidebar = (not embedded) and (not theme_nosidebar|tobool) and
- (sidebars != []) %}
-{%- set url_root = pathto('', 1) %}
-{# XXX necessary? #}
-{%- if url_root == '#' %}{% set url_root = '' %}{% endif %}
-{%- if not embedded and docstitle %}
- {%- set titlesuffix = " — "|safe + docstitle|e %}
-{%- else %}
- {%- set titlesuffix = "" %}
-{%- endif %}
-
-{%- macro relbar() %}
-
-{%- endmacro %}
-
-{%- macro sidebar() %}
- {%- if render_sidebar %}
-
- {%- endif %}
-{%- endmacro %}
-
-{%- macro script() %}
-
- {%- for scriptfile in script_files %}
-
- {%- endfor %}
-{%- endmacro %}
-
-{%- macro css() %}
-
-
- {%- for cssfile in css_files %}
-
- {%- endfor %}
-{%- endmacro %}
-
-
-
-
- {{ metatags }}
- {%- block htmltitle %}
- {{ title|striptags|e }}{{ titlesuffix }}
- {%- endblock %}
- {{ css() }}
- {%- if not embedded %}
- {{ script() }}
- {%- if use_opensearch %}
-
- {%- endif %}
- {%- if favicon %}
-
- {%- endif %}
- {%- endif %}
-{%- block linktags %}
- {%- if hasdoc('about') %}
-
- {%- endif %}
- {%- if hasdoc('genindex') %}
-
- {%- endif %}
- {%- if hasdoc('search') %}
-
- {%- endif %}
- {%- if hasdoc('copyright') %}
-
- {%- endif %}
-
- {%- if parents %}
-
- {%- endif %}
- {%- if next %}
-
- {%- endif %}
- {%- if prev %}
-
- {%- endif %}
-{%- endblock %}
-{%- block extrahead %} {% endblock %}
-
-
-{%- block header %}{% endblock %}
-
-{%- block relbar1 %}{{ relbar() }}{% endblock %}
-
-{%- block content %}
- {%- block sidebar1 %} {# possible location for sidebar #} {% endblock %}
-
-
- {%- block document %}
-
- {%- if render_sidebar %}
-
- {%- endif %}
-
- {% block body %} {% endblock %}
-
- {%- if render_sidebar %}
-
- {%- endif %}
-
- {%- endblock %}
-
- {%- block sidebar2 %}{{ sidebar() }}{% endblock %}
-
-
-{%- endblock %}
-
-{%- block relbar2 %}{{ relbar() }}{% endblock %}
-
-{%- block footer %}
-
- asdf asdf asdf asdf 22
-{%- endblock %}
-
-
-
diff --git a/manual/_theme/search.html b/manual/_theme/search.html
deleted file mode 100644
index d8bbe690..00000000
--- a/manual/_theme/search.html
+++ /dev/null
@@ -1,50 +0,0 @@
-{#
- basic/search.html
- ~~~~~~~~~~~~~~~~~
-
- Template for the search page.
-
- :copyright: Copyright 2007-2013 by the Sphinx team, see AUTHORS.
- :license: BSD, see LICENSE for details.
-#}
-{%- extends "layout.html" %}
-{% set title = _('Search') %}
-{% set script_files = script_files + ['_static/searchtools.js'] %}
-{% block extrahead %}
-
- {# this is used when loading the search index using $.ajax fails,
- such as on Chrome for documents on localhost #}
-
- {{ super() }}
-{% endblock %}
-{% block body %}
-
-
-
- {% trans %}Please activate JavaScript to enable the search
- functionality.{% endtrans %}
-
-
-
-
- {% if search_performed %}
- {{ _('Search Results') }}
- {% if not search_results %}
- {{ _('Your search did not match any documents. Please make sure that all words are spelled correctly and that you\'ve selected enough categories.') }}
- {% endif %}
- {% endif %}
-
- {% if search_results %}
-
- {% for href, caption, context in search_results %}
-
- {{ caption }}
- {{ context|e }}
-
- {% endfor %}
-
- {% endif %}
-
-{% endblock %}
diff --git a/manual/_theme/searchbox.html b/manual/_theme/searchbox.html
deleted file mode 100644
index 24418d32..00000000
--- a/manual/_theme/searchbox.html
+++ /dev/null
@@ -1,7 +0,0 @@
-
-
-
diff --git a/manual/_theme/sphinx_rtd_theme/__init__.py b/manual/_theme/sphinx_rtd_theme/__init__.py
deleted file mode 100644
index 1440863d..00000000
--- a/manual/_theme/sphinx_rtd_theme/__init__.py
+++ /dev/null
@@ -1,17 +0,0 @@
-"""Sphinx ReadTheDocs theme.
-
-From https://github.com/ryan-roemer/sphinx-bootstrap-theme.
-
-"""
-import os
-
-VERSION = (0, 1, 5)
-
-__version__ = ".".join(str(v) for v in VERSION)
-__version_full__ = __version__
-
-
-def get_html_theme_path():
- """Return list of HTML theme paths."""
- cur_dir = os.path.abspath(os.path.dirname(os.path.dirname(__file__)))
- return cur_dir
diff --git a/manual/_theme/sphinx_rtd_theme/breadcrumbs.html b/manual/_theme/sphinx_rtd_theme/breadcrumbs.html
deleted file mode 100644
index 982c856f..00000000
--- a/manual/_theme/sphinx_rtd_theme/breadcrumbs.html
+++ /dev/null
@@ -1,19 +0,0 @@
-
diff --git a/manual/_theme/sphinx_rtd_theme/footer.html b/manual/_theme/sphinx_rtd_theme/footer.html
deleted file mode 100644
index c740b24c..00000000
--- a/manual/_theme/sphinx_rtd_theme/footer.html
+++ /dev/null
@@ -1,32 +0,0 @@
-
diff --git a/manual/_theme/sphinx_rtd_theme/layout.html b/manual/_theme/sphinx_rtd_theme/layout.html
deleted file mode 100644
index c0e8dbe7..00000000
--- a/manual/_theme/sphinx_rtd_theme/layout.html
+++ /dev/null
@@ -1,170 +0,0 @@
-{# TEMPLATE VAR SETTINGS #}
-{%- set url_root = pathto('', 1) %}
-{%- if url_root == '#' %}{% set url_root = '' %}{% endif %}
-{%- if not embedded and docstitle %}
- {%- set titlesuffix = " — "|safe + docstitle|e %}
-{%- else %}
- {%- set titlesuffix = "" %}
-{%- endif %}
-
-
-
-
-
-
-
- {% block htmltitle %}
- {{ title|striptags|e }}{{ titlesuffix }}
- {% endblock %}
-
- {# FAVICON #}
- {% if favicon %}
-
- {% endif %}
-
- {# CSS #}
-
-
- {# JS #}
- {% if not embedded %}
-
-
- {%- for scriptfile in script_files %}
-
- {%- endfor %}
-
- {% if use_opensearch %}
-
- {% endif %}
-
- {% endif %}
-
- {# RTD hosts these file themselves, so just load on non RTD builds #}
- {% if not READTHEDOCS %}
-
-
- {% endif %}
-
- {# STICKY NAVIGATION #}
- {% if theme_sticky_navigation %}
-
- {% endif %}
-
- {% for cssfile in css_files %}
-
- {% endfor %}
-
- {%- block linktags %}
- {%- if hasdoc('about') %}
-
- {%- endif %}
- {%- if hasdoc('genindex') %}
-
- {%- endif %}
- {%- if hasdoc('search') %}
-
- {%- endif %}
- {%- if hasdoc('copyright') %}
-
- {%- endif %}
-
- {%- if parents %}
-
- {%- endif %}
- {%- if next %}
-
- {%- endif %}
- {%- if prev %}
-
- {%- endif %}
- {%- endblock %}
- {%- block extrahead %} {% endblock %}
-
-
-
-
-
-
-
-
-
-
-
-
- {# SIDE NAV, TOGGLES ON MOBILE #}
-
-
-
-
-
-
-
- {% include "searchbox.html" %}
-
-
-
-
-
-
-
-
- {# MOBILE NAV, TRIGGLES SIDE NAV ON TOGGLE #}
-
-
- {{ project }}
-
-
-
- {# PAGE CONTENT #}
-
-
- {% include "breadcrumbs.html" %}
-
- {% block body %}{% endblock %}
-
- {% include "footer.html" %}
-
-
-
-
-
-
- {% include "versions.html" %}
-
-
diff --git a/manual/_theme/sphinx_rtd_theme/layout_old.html b/manual/_theme/sphinx_rtd_theme/layout_old.html
deleted file mode 100644
index deb8df2a..00000000
--- a/manual/_theme/sphinx_rtd_theme/layout_old.html
+++ /dev/null
@@ -1,205 +0,0 @@
-{#
- basic/layout.html
- ~~~~~~~~~~~~~~~~~
-
- Master layout template for Sphinx themes.
-
- :copyright: Copyright 2007-2013 by the Sphinx team, see AUTHORS.
- :license: BSD, see LICENSE for details.
-#}
-{%- block doctype -%}
-
-{%- endblock %}
-{%- set reldelim1 = reldelim1 is not defined and ' »' or reldelim1 %}
-{%- set reldelim2 = reldelim2 is not defined and ' |' or reldelim2 %}
-{%- set render_sidebar = (not embedded) and (not theme_nosidebar|tobool) and
- (sidebars != []) %}
-{%- set url_root = pathto('', 1) %}
-{# XXX necessary? #}
-{%- if url_root == '#' %}{% set url_root = '' %}{% endif %}
-{%- if not embedded and docstitle %}
- {%- set titlesuffix = " — "|safe + docstitle|e %}
-{%- else %}
- {%- set titlesuffix = "" %}
-{%- endif %}
-
-{%- macro relbar() %}
-
-{%- endmacro %}
-
-{%- macro sidebar() %}
- {%- if render_sidebar %}
-
- {%- endif %}
-{%- endmacro %}
-
-{%- macro script() %}
-
- {%- for scriptfile in script_files %}
-
- {%- endfor %}
-{%- endmacro %}
-
-{%- macro css() %}
-
-
- {%- for cssfile in css_files %}
-
- {%- endfor %}
-{%- endmacro %}
-
-
-
-
- {{ metatags }}
- {%- block htmltitle %}
- {{ title|striptags|e }}{{ titlesuffix }}
- {%- endblock %}
- {{ css() }}
- {%- if not embedded %}
- {{ script() }}
- {%- if use_opensearch %}
-
- {%- endif %}
- {%- if favicon %}
-
- {%- endif %}
- {%- endif %}
-{%- block linktags %}
- {%- if hasdoc('about') %}
-
- {%- endif %}
- {%- if hasdoc('genindex') %}
-
- {%- endif %}
- {%- if hasdoc('search') %}
-
- {%- endif %}
- {%- if hasdoc('copyright') %}
-
- {%- endif %}
-
- {%- if parents %}
-
- {%- endif %}
- {%- if next %}
-
- {%- endif %}
- {%- if prev %}
-
- {%- endif %}
-{%- endblock %}
-{%- block extrahead %} {% endblock %}
-
-
-{%- block header %}{% endblock %}
-
-{%- block relbar1 %}{{ relbar() }}{% endblock %}
-
-{%- block content %}
- {%- block sidebar1 %} {# possible location for sidebar #} {% endblock %}
-
-
- {%- block document %}
-
- {%- if render_sidebar %}
-
- {%- endif %}
-
- {% block body %} {% endblock %}
-
- {%- if render_sidebar %}
-
- {%- endif %}
-
- {%- endblock %}
-
- {%- block sidebar2 %}{{ sidebar() }}{% endblock %}
-
-
-{%- endblock %}
-
-{%- block relbar2 %}{{ relbar() }}{% endblock %}
-
-{%- block footer %}
-
- asdf asdf asdf asdf 22
-{%- endblock %}
-
-
-
diff --git a/manual/_theme/sphinx_rtd_theme/search.html b/manual/_theme/sphinx_rtd_theme/search.html
deleted file mode 100644
index d8bbe690..00000000
--- a/manual/_theme/sphinx_rtd_theme/search.html
+++ /dev/null
@@ -1,50 +0,0 @@
-{#
- basic/search.html
- ~~~~~~~~~~~~~~~~~
-
- Template for the search page.
-
- :copyright: Copyright 2007-2013 by the Sphinx team, see AUTHORS.
- :license: BSD, see LICENSE for details.
-#}
-{%- extends "layout.html" %}
-{% set title = _('Search') %}
-{% set script_files = script_files + ['_static/searchtools.js'] %}
-{% block extrahead %}
-
- {# this is used when loading the search index using $.ajax fails,
- such as on Chrome for documents on localhost #}
-
- {{ super() }}
-{% endblock %}
-{% block body %}
-
-
-
- {% trans %}Please activate JavaScript to enable the search
- functionality.{% endtrans %}
-
-
-
-
- {% if search_performed %}
- {{ _('Search Results') }}
- {% if not search_results %}
- {{ _('Your search did not match any documents. Please make sure that all words are spelled correctly and that you\'ve selected enough categories.') }}
- {% endif %}
- {% endif %}
-
- {% if search_results %}
-
- {% for href, caption, context in search_results %}
-
- {{ caption }}
- {{ context|e }}
-
- {% endfor %}
-
- {% endif %}
-
-{% endblock %}
diff --git a/manual/_theme/sphinx_rtd_theme/searchbox.html b/manual/_theme/sphinx_rtd_theme/searchbox.html
deleted file mode 100644
index 24418d32..00000000
--- a/manual/_theme/sphinx_rtd_theme/searchbox.html
+++ /dev/null
@@ -1,7 +0,0 @@
-
-
-
diff --git a/manual/_theme/sphinx_rtd_theme/static/css/badge_only.css b/manual/_theme/sphinx_rtd_theme/static/css/badge_only.css
deleted file mode 100644
index e67013ae..00000000
--- a/manual/_theme/sphinx_rtd_theme/static/css/badge_only.css
+++ /dev/null
@@ -1 +0,0 @@
-.font-smooth,.icon:before{-webkit-font-smoothing:antialiased}.clearfix{*zoom:1}.clearfix:before,.clearfix:after{display:table;content:""}.clearfix:after{clear:both}@font-face{font-family:fontawesome-webfont;font-weight:normal;font-style:normal;src:url("../font/fontawesome_webfont.eot");src:url("../font/fontawesome_webfont.eot?#iefix") format("embedded-opentype"),url("../font/fontawesome_webfont.woff") format("woff"),url("../font/fontawesome_webfont.ttf") format("truetype"),url("../font/fontawesome_webfont.svg#fontawesome-webfont") format("svg")}.icon:before{display:inline-block;font-family:fontawesome-webfont;font-style:normal;font-weight:normal;line-height:1;text-decoration:inherit}a .icon{display:inline-block;text-decoration:inherit}li .icon{display:inline-block}li .icon-large:before,li .icon-large:before{width:1.875em}ul.icons{list-style-type:none;margin-left:2em;text-indent:-0.8em}ul.icons li .icon{width:0.8em}ul.icons li .icon-large:before,ul.icons li .icon-large:before{vertical-align:baseline}.icon-book:before{content:"\f02d"}.icon-caret-down:before{content:"\f0d7"}.icon-caret-up:before{content:"\f0d8"}.icon-caret-left:before{content:"\f0d9"}.icon-caret-right:before{content:"\f0da"}.rst-versions{position:fixed;bottom:0;left:0;width:300px;color:#fcfcfc;background:#1f1d1d;border-top:solid 10px #343131;font-family:"Lato","proxima-nova","Helvetica Neue",Arial,sans-serif;z-index:400}.rst-versions a{color:#2980b9;text-decoration:none}.rst-versions .rst-badge-small{display:none}.rst-versions .rst-current-version{padding:12px;background-color:#272525;display:block;text-align:right;font-size:90%;cursor:pointer;color:#27ae60;*zoom:1}.rst-versions .rst-current-version:before,.rst-versions .rst-current-version:after{display:table;content:""}.rst-versions .rst-current-version:after{clear:both}.rst-versions .rst-current-version .icon{color:#fcfcfc}.rst-versions .rst-current-version .icon-book{float:left}.rst-versions .rst-current-version.rst-out-of-date{background-color:#e74c3c;color:#fff}.rst-versions .rst-current-version.rst-active-old-version{background-color:#f1c40f;color:#000}.rst-versions.shift-up .rst-other-versions{display:block}.rst-versions .rst-other-versions{font-size:90%;padding:12px;color:gray;display:none}.rst-versions .rst-other-versions hr{display:block;height:1px;border:0;margin:20px 0;padding:0;border-top:solid 1px #413d3d}.rst-versions .rst-other-versions dd{display:inline-block;margin:0}.rst-versions .rst-other-versions dd a{display:inline-block;padding:6px;color:#fcfcfc}.rst-versions.rst-badge{width:auto;bottom:20px;right:20px;left:auto;border:none;max-width:300px}.rst-versions.rst-badge .icon-book{float:none}.rst-versions.rst-badge.shift-up .rst-current-version{text-align:right}.rst-versions.rst-badge.shift-up .rst-current-version .icon-book{float:left}.rst-versions.rst-badge .rst-current-version{width:auto;height:30px;line-height:30px;padding:0 6px;display:block;text-align:center}@media screen and (max-width: 768px){.rst-versions{width:85%;display:none}.rst-versions.shift{display:block}img{width:100%;height:auto}}
diff --git a/manual/_theme/sphinx_rtd_theme/static/css/theme.css b/manual/_theme/sphinx_rtd_theme/static/css/theme.css
deleted file mode 100644
index 481346bf..00000000
--- a/manual/_theme/sphinx_rtd_theme/static/css/theme.css
+++ /dev/null
@@ -1 +0,0 @@
-*{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}article,aside,details,figcaption,figure,footer,header,hgroup,nav,section{display:block}audio,canvas,video{display:inline-block;*display:inline;*zoom:1}audio:not([controls]){display:none}[hidden]{display:none}*{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}html{font-size:100%;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%}body{margin:0}a:hover,a:active{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:bold}blockquote{margin:0}dfn{font-style:italic}hr{display:block;height:1px;border:0;border-top:1px solid #ccc;margin:20px 0;padding:0}ins{background:#ff9;color:#000;text-decoration:none}mark{background:#ff0;color:#000;font-style:italic;font-weight:bold}pre,code,.rst-content tt,kbd,samp{font-family:monospace,serif;_font-family:"courier new",monospace;font-size:1em}pre{white-space:pre}q{quotes:none}q:before,q:after{content:"";content:none}small{font-size:85%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-0.5em}sub{bottom:-0.25em}ul,ol,dl{margin:0;padding:0;list-style:none;list-style-image:none}li{list-style:none}dd{margin:0}img{border:0;-ms-interpolation-mode:bicubic;vertical-align:middle;max-width:100%}svg:not(:root){overflow:hidden}figure{margin:0}form{margin:0}fieldset{border:0;margin:0;padding:0}label{cursor:pointer}legend{border:0;*margin-left:-7px;padding:0;white-space:normal}button,input,select,textarea{font-size:100%;margin:0;vertical-align:baseline;*vertical-align:middle}button,input{line-height:normal}button,input[type="button"],input[type="reset"],input[type="submit"]{cursor:pointer;-webkit-appearance:button;*overflow:visible}button[disabled],input[disabled]{cursor:default}input[type="checkbox"],input[type="radio"]{box-sizing:border-box;padding:0;*width:13px;*height:13px}input[type="search"]{-webkit-appearance:textfield;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;box-sizing:content-box}input[type="search"]::-webkit-search-decoration,input[type="search"]::-webkit-search-cancel-button{-webkit-appearance:none}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}textarea{overflow:auto;vertical-align:top;resize:vertical}table{border-collapse:collapse;border-spacing:0}td{vertical-align:top}.chromeframe{margin:0.2em 0;background:#ccc;color:#000;padding:0.2em 0}.ir{display:block;border:0;text-indent:-999em;overflow:hidden;background-color:transparent;background-repeat:no-repeat;text-align:left;direction:ltr;*line-height:0}.ir br{display:none}.hidden{display:none !important;visibility:hidden}.visuallyhidden{border:0;clip:rect(0 0 0 0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.visuallyhidden.focusable:active,.visuallyhidden.focusable:focus{clip:auto;height:auto;margin:0;overflow:visible;position:static;width:auto}.invisible{visibility:hidden}.relative{position:relative}big,small{font-size:100%}@media print{html,body,section{background:none !important}*{box-shadow:none !important;text-shadow:none !important;filter:none !important;-ms-filter:none !important}a,a:visited{text-decoration:underline}.ir a:after,a[href^="javascript:"]:after,a[href^="#"]:after{content:""}pre,blockquote{page-break-inside:avoid}thead{display:table-header-group}tr,img{page-break-inside:avoid}img{max-width:100% !important}@page{margin:0.5cm}p,h2,h3{orphans:3;widows:3}h2,h3{page-break-after:avoid}}.font-smooth,.icon:before,.wy-inline-validate.wy-inline-validate-success .wy-input-context:before,.wy-inline-validate.wy-inline-validate-danger .wy-input-context:before,.wy-inline-validate.wy-inline-validate-warning .wy-input-context:before,.wy-inline-validate.wy-inline-validate-info .wy-input-context:before,.wy-tag-input-group .wy-tag .wy-tag-remove:before,.rst-content .admonition-title:before,.rst-content h1 .headerlink:before,.rst-content h2 .headerlink:before,.rst-content h3 .headerlink:before,.rst-content h4 .headerlink:before,.rst-content h5 .headerlink:before,.rst-content h6 .headerlink:before,.rst-content dl dt .headerlink:before,.wy-alert,.rst-content .note,.rst-content .attention,.rst-content .caution,.rst-content .danger,.rst-content .error,.rst-content .hint,.rst-content .important,.rst-content .tip,.rst-content .warning,.rst-content .seealso,.btn,input[type="text"],input[type="password"],input[type="email"],input[type="url"],input[type="date"],input[type="month"],input[type="time"],input[type="datetime"],input[type="datetime-local"],input[type="week"],input[type="number"],input[type="search"],input[type="tel"],input[type="color"],select,textarea,.wy-tag-input-group,.wy-menu-vertical li.on a,.wy-menu-vertical li.current>a,.wy-side-nav-search>a,.wy-side-nav-search .wy-dropdown>a,.wy-nav-top a{-webkit-font-smoothing:antialiased}.clearfix{*zoom:1}.clearfix:before,.clearfix:after{display:table;content:""}.clearfix:after{clear:both}@font-face{font-family:fontawesome-webfont;font-weight:normal;font-style:normal;src:url("../font/fontawesome_webfont.eot");src:url("../font/fontawesome_webfont.eot?#iefix") format("embedded-opentype"),url("../font/fontawesome_webfont.woff") format("woff"),url("../font/fontawesome_webfont.ttf") format("truetype"),url("../font/fontawesome_webfont.svg#fontawesome-webfont") format("svg")}.icon:before,.wy-inline-validate.wy-inline-validate-success .wy-input-context:before,.wy-inline-validate.wy-inline-validate-danger .wy-input-context:before,.wy-inline-validate.wy-inline-validate-warning .wy-input-context:before,.wy-inline-validate.wy-inline-validate-info .wy-input-context:before,.wy-tag-input-group .wy-tag .wy-tag-remove:before,.rst-content .admonition-title:before,.rst-content h1 .headerlink:before,.rst-content h2 .headerlink:before,.rst-content h3 .headerlink:before,.rst-content h4 .headerlink:before,.rst-content h5 .headerlink:before,.rst-content h6 .headerlink:before,.rst-content dl dt .headerlink:before{display:inline-block;font-family:fontawesome-webfont;font-style:normal;font-weight:normal;line-height:1;text-decoration:inherit}a .icon,a .wy-inline-validate.wy-inline-validate-success .wy-input-context,.wy-inline-validate.wy-inline-validate-success a .wy-input-context,a .wy-inline-validate.wy-inline-validate-danger .wy-input-context,.wy-inline-validate.wy-inline-validate-danger a .wy-input-context,a .wy-inline-validate.wy-inline-validate-warning .wy-input-context,.wy-inline-validate.wy-inline-validate-warning a .wy-input-context,a .wy-inline-validate.wy-inline-validate-info .wy-input-context,.wy-inline-validate.wy-inline-validate-info a .wy-input-context,a .wy-tag-input-group .wy-tag .wy-tag-remove,.wy-tag-input-group .wy-tag a .wy-tag-remove,a .rst-content .admonition-title,.rst-content a .admonition-title,a .rst-content h1 .headerlink,.rst-content h1 a .headerlink,a .rst-content h2 .headerlink,.rst-content h2 a .headerlink,a .rst-content h3 .headerlink,.rst-content h3 a .headerlink,a .rst-content h4 .headerlink,.rst-content h4 a .headerlink,a .rst-content h5 .headerlink,.rst-content h5 a .headerlink,a .rst-content h6 .headerlink,.rst-content h6 a .headerlink,a .rst-content dl dt .headerlink,.rst-content dl dt a .headerlink{display:inline-block;text-decoration:inherit}.icon-large:before{vertical-align:-10%;font-size:1.33333em}.btn .icon,.btn .wy-inline-validate.wy-inline-validate-success .wy-input-context,.wy-inline-validate.wy-inline-validate-success .btn .wy-input-context,.btn .wy-inline-validate.wy-inline-validate-danger .wy-input-context,.wy-inline-validate.wy-inline-validate-danger .btn .wy-input-context,.btn .wy-inline-validate.wy-inline-validate-warning .wy-input-context,.wy-inline-validate.wy-inline-validate-warning .btn .wy-input-context,.btn .wy-inline-validate.wy-inline-validate-info .wy-input-context,.wy-inline-validate.wy-inline-validate-info .btn .wy-input-context,.btn .wy-tag-input-group .wy-tag .wy-tag-remove,.wy-tag-input-group .wy-tag .btn .wy-tag-remove,.btn .rst-content .admonition-title,.rst-content .btn .admonition-title,.btn .rst-content h1 .headerlink,.rst-content h1 .btn .headerlink,.btn .rst-content h2 .headerlink,.rst-content h2 .btn .headerlink,.btn .rst-content h3 .headerlink,.rst-content h3 .btn .headerlink,.btn .rst-content h4 .headerlink,.rst-content h4 .btn .headerlink,.btn .rst-content h5 .headerlink,.rst-content h5 .btn .headerlink,.btn .rst-content h6 .headerlink,.rst-content h6 .btn .headerlink,.btn .rst-content dl dt .headerlink,.rst-content dl dt .btn .headerlink,.nav .icon,.nav .wy-inline-validate.wy-inline-validate-success .wy-input-context,.wy-inline-validate.wy-inline-validate-success .nav .wy-input-context,.nav .wy-inline-validate.wy-inline-validate-danger .wy-input-context,.wy-inline-validate.wy-inline-validate-danger .nav .wy-input-context,.nav .wy-inline-validate.wy-inline-validate-warning .wy-input-context,.wy-inline-validate.wy-inline-validate-warning .nav .wy-input-context,.nav .wy-inline-validate.wy-inline-validate-info .wy-input-context,.wy-inline-validate.wy-inline-validate-info .nav .wy-input-context,.nav .wy-tag-input-group .wy-tag .wy-tag-remove,.wy-tag-input-group .wy-tag .nav .wy-tag-remove,.nav .rst-content .admonition-title,.rst-content .nav .admonition-title,.nav .rst-content h1 .headerlink,.rst-content h1 .nav .headerlink,.nav .rst-content h2 .headerlink,.rst-content h2 .nav .headerlink,.nav .rst-content h3 .headerlink,.rst-content h3 .nav .headerlink,.nav .rst-content h4 .headerlink,.rst-content h4 .nav .headerlink,.nav .rst-content h5 .headerlink,.rst-content h5 .nav .headerlink,.nav .rst-content h6 .headerlink,.rst-content h6 .nav .headerlink,.nav .rst-content dl dt .headerlink,.rst-content dl dt .nav .headerlink{display:inline}.btn .icon.icon-large,.btn .wy-inline-validate.wy-inline-validate-success .icon-large.wy-input-context,.wy-inline-validate.wy-inline-validate-success .btn .icon-large.wy-input-context,.btn .wy-inline-validate.wy-inline-validate-danger .icon-large.wy-input-context,.wy-inline-validate.wy-inline-validate-danger .btn .icon-large.wy-input-context,.btn .wy-inline-validate.wy-inline-validate-warning .icon-large.wy-input-context,.wy-inline-validate.wy-inline-validate-warning .btn .icon-large.wy-input-context,.btn .wy-inline-validate.wy-inline-validate-info .icon-large.wy-input-context,.wy-inline-validate.wy-inline-validate-info .btn .icon-large.wy-input-context,.btn .wy-tag-input-group .wy-tag .icon-large.wy-tag-remove,.wy-tag-input-group .wy-tag .btn .icon-large.wy-tag-remove,.btn .rst-content .icon-large.admonition-title,.rst-content .btn .icon-large.admonition-title,.btn .rst-content h1 .icon-large.headerlink,.rst-content h1 .btn .icon-large.headerlink,.btn .rst-content h2 .icon-large.headerlink,.rst-content h2 .btn .icon-large.headerlink,.btn .rst-content h3 .icon-large.headerlink,.rst-content h3 .btn .icon-large.headerlink,.btn .rst-content h4 .icon-large.headerlink,.rst-content h4 .btn .icon-large.headerlink,.btn .rst-content h5 .icon-large.headerlink,.rst-content h5 .btn .icon-large.headerlink,.btn .rst-content h6 .icon-large.headerlink,.rst-content h6 .btn .icon-large.headerlink,.btn .rst-content dl dt .icon-large.headerlink,.rst-content dl dt .btn .icon-large.headerlink,.nav .icon.icon-large,.nav .wy-inline-validate.wy-inline-validate-success .icon-large.wy-input-context,.wy-inline-validate.wy-inline-validate-success .nav .icon-large.wy-input-context,.nav .wy-inline-validate.wy-inline-validate-danger .icon-large.wy-input-context,.wy-inline-validate.wy-inline-validate-danger .nav .icon-large.wy-input-context,.nav .wy-inline-validate.wy-inline-validate-warning .icon-large.wy-input-context,.wy-inline-validate.wy-inline-validate-warning .nav .icon-large.wy-input-context,.nav .wy-inline-validate.wy-inline-validate-info .icon-large.wy-input-context,.wy-inline-validate.wy-inline-validate-info .nav .icon-large.wy-input-context,.nav .wy-tag-input-group .wy-tag .icon-large.wy-tag-remove,.wy-tag-input-group .wy-tag .nav .icon-large.wy-tag-remove,.nav .rst-content .icon-large.admonition-title,.rst-content .nav .icon-large.admonition-title,.nav .rst-content h1 .icon-large.headerlink,.rst-content h1 .nav .icon-large.headerlink,.nav .rst-content h2 .icon-large.headerlink,.rst-content h2 .nav .icon-large.headerlink,.nav .rst-content h3 .icon-large.headerlink,.rst-content h3 .nav .icon-large.headerlink,.nav .rst-content h4 .icon-large.headerlink,.rst-content h4 .nav .icon-large.headerlink,.nav .rst-content h5 .icon-large.headerlink,.rst-content h5 .nav .icon-large.headerlink,.nav .rst-content h6 .icon-large.headerlink,.rst-content h6 .nav .icon-large.headerlink,.nav .rst-content dl dt .icon-large.headerlink,.rst-content dl dt .nav .icon-large.headerlink{line-height:0.9em}.btn .icon.icon-spin,.btn .wy-inline-validate.wy-inline-validate-success .icon-spin.wy-input-context,.wy-inline-validate.wy-inline-validate-success .btn .icon-spin.wy-input-context,.btn .wy-inline-validate.wy-inline-validate-danger .icon-spin.wy-input-context,.wy-inline-validate.wy-inline-validate-danger .btn .icon-spin.wy-input-context,.btn .wy-inline-validate.wy-inline-validate-warning .icon-spin.wy-input-context,.wy-inline-validate.wy-inline-validate-warning .btn .icon-spin.wy-input-context,.btn .wy-inline-validate.wy-inline-validate-info .icon-spin.wy-input-context,.wy-inline-validate.wy-inline-validate-info .btn .icon-spin.wy-input-context,.btn .wy-tag-input-group .wy-tag .icon-spin.wy-tag-remove,.wy-tag-input-group .wy-tag .btn .icon-spin.wy-tag-remove,.btn .rst-content .icon-spin.admonition-title,.rst-content .btn .icon-spin.admonition-title,.btn .rst-content h1 .icon-spin.headerlink,.rst-content h1 .btn .icon-spin.headerlink,.btn .rst-content h2 .icon-spin.headerlink,.rst-content h2 .btn .icon-spin.headerlink,.btn .rst-content h3 .icon-spin.headerlink,.rst-content h3 .btn .icon-spin.headerlink,.btn .rst-content h4 .icon-spin.headerlink,.rst-content h4 .btn .icon-spin.headerlink,.btn .rst-content h5 .icon-spin.headerlink,.rst-content h5 .btn .icon-spin.headerlink,.btn .rst-content h6 .icon-spin.headerlink,.rst-content h6 .btn .icon-spin.headerlink,.btn .rst-content dl dt .icon-spin.headerlink,.rst-content dl dt .btn .icon-spin.headerlink,.nav .icon.icon-spin,.nav .wy-inline-validate.wy-inline-validate-success .icon-spin.wy-input-context,.wy-inline-validate.wy-inline-validate-success .nav .icon-spin.wy-input-context,.nav .wy-inline-validate.wy-inline-validate-danger .icon-spin.wy-input-context,.wy-inline-validate.wy-inline-validate-danger .nav .icon-spin.wy-input-context,.nav .wy-inline-validate.wy-inline-validate-warning .icon-spin.wy-input-context,.wy-inline-validate.wy-inline-validate-warning .nav .icon-spin.wy-input-context,.nav .wy-inline-validate.wy-inline-validate-info .icon-spin.wy-input-context,.wy-inline-validate.wy-inline-validate-info .nav .icon-spin.wy-input-context,.nav .wy-tag-input-group .wy-tag .icon-spin.wy-tag-remove,.wy-tag-input-group .wy-tag .nav .icon-spin.wy-tag-remove,.nav .rst-content .icon-spin.admonition-title,.rst-content .nav .icon-spin.admonition-title,.nav .rst-content h1 .icon-spin.headerlink,.rst-content h1 .nav .icon-spin.headerlink,.nav .rst-content h2 .icon-spin.headerlink,.rst-content h2 .nav .icon-spin.headerlink,.nav .rst-content h3 .icon-spin.headerlink,.rst-content h3 .nav .icon-spin.headerlink,.nav .rst-content h4 .icon-spin.headerlink,.rst-content h4 .nav .icon-spin.headerlink,.nav .rst-content h5 .icon-spin.headerlink,.rst-content h5 .nav .icon-spin.headerlink,.nav .rst-content h6 .icon-spin.headerlink,.rst-content h6 .nav .icon-spin.headerlink,.nav .rst-content dl dt .icon-spin.headerlink,.rst-content dl dt .nav .icon-spin.headerlink{display:inline-block}.btn.icon:before,.wy-inline-validate.wy-inline-validate-success .btn.wy-input-context:before,.wy-inline-validate.wy-inline-validate-danger .btn.wy-input-context:before,.wy-inline-validate.wy-inline-validate-warning .btn.wy-input-context:before,.wy-inline-validate.wy-inline-validate-info .btn.wy-input-context:before,.wy-tag-input-group .wy-tag .btn.wy-tag-remove:before,.rst-content .btn.admonition-title:before,.rst-content h1 .btn.headerlink:before,.rst-content h2 .btn.headerlink:before,.rst-content h3 .btn.headerlink:before,.rst-content h4 .btn.headerlink:before,.rst-content h5 .btn.headerlink:before,.rst-content h6 .btn.headerlink:before,.rst-content dl dt .btn.headerlink:before{opacity:0.5;-webkit-transition:opacity 0.05s ease-in;-moz-transition:opacity 0.05s ease-in;transition:opacity 0.05s ease-in}.btn.icon:hover:before,.wy-inline-validate.wy-inline-validate-success .btn.wy-input-context:hover:before,.wy-inline-validate.wy-inline-validate-danger .btn.wy-input-context:hover:before,.wy-inline-validate.wy-inline-validate-warning .btn.wy-input-context:hover:before,.wy-inline-validate.wy-inline-validate-info .btn.wy-input-context:hover:before,.wy-tag-input-group .wy-tag .btn.wy-tag-remove:hover:before,.rst-content .btn.admonition-title:hover:before,.rst-content h1 .btn.headerlink:hover:before,.rst-content h2 .btn.headerlink:hover:before,.rst-content h3 .btn.headerlink:hover:before,.rst-content h4 .btn.headerlink:hover:before,.rst-content h5 .btn.headerlink:hover:before,.rst-content h6 .btn.headerlink:hover:before,.rst-content dl dt .btn.headerlink:hover:before{opacity:1}.btn-mini .icon:before,.btn-mini .wy-inline-validate.wy-inline-validate-success .wy-input-context:before,.wy-inline-validate.wy-inline-validate-success .btn-mini .wy-input-context:before,.btn-mini .wy-inline-validate.wy-inline-validate-danger .wy-input-context:before,.wy-inline-validate.wy-inline-validate-danger .btn-mini .wy-input-context:before,.btn-mini .wy-inline-validate.wy-inline-validate-warning .wy-input-context:before,.wy-inline-validate.wy-inline-validate-warning .btn-mini .wy-input-context:before,.btn-mini .wy-inline-validate.wy-inline-validate-info .wy-input-context:before,.wy-inline-validate.wy-inline-validate-info .btn-mini .wy-input-context:before,.btn-mini .wy-tag-input-group .wy-tag .wy-tag-remove:before,.wy-tag-input-group .wy-tag .btn-mini .wy-tag-remove:before,.btn-mini .rst-content .admonition-title:before,.rst-content .btn-mini .admonition-title:before,.btn-mini .rst-content h1 .headerlink:before,.rst-content h1 .btn-mini .headerlink:before,.btn-mini .rst-content h2 .headerlink:before,.rst-content h2 .btn-mini .headerlink:before,.btn-mini .rst-content h3 .headerlink:before,.rst-content h3 .btn-mini .headerlink:before,.btn-mini .rst-content h4 .headerlink:before,.rst-content h4 .btn-mini .headerlink:before,.btn-mini .rst-content h5 .headerlink:before,.rst-content h5 .btn-mini .headerlink:before,.btn-mini .rst-content h6 .headerlink:before,.rst-content h6 .btn-mini .headerlink:before,.btn-mini .rst-content dl dt .headerlink:before,.rst-content dl dt .btn-mini .headerlink:before{font-size:14px;vertical-align:-15%}li .icon,li .wy-inline-validate.wy-inline-validate-success .wy-input-context,.wy-inline-validate.wy-inline-validate-success li .wy-input-context,li .wy-inline-validate.wy-inline-validate-danger .wy-input-context,.wy-inline-validate.wy-inline-validate-danger li .wy-input-context,li .wy-inline-validate.wy-inline-validate-warning .wy-input-context,.wy-inline-validate.wy-inline-validate-warning li .wy-input-context,li .wy-inline-validate.wy-inline-validate-info .wy-input-context,.wy-inline-validate.wy-inline-validate-info li .wy-input-context,li .wy-tag-input-group .wy-tag .wy-tag-remove,.wy-tag-input-group .wy-tag li .wy-tag-remove,li .rst-content .admonition-title,.rst-content li .admonition-title,li .rst-content h1 .headerlink,.rst-content h1 li .headerlink,li .rst-content h2 .headerlink,.rst-content h2 li .headerlink,li .rst-content h3 .headerlink,.rst-content h3 li .headerlink,li .rst-content h4 .headerlink,.rst-content h4 li .headerlink,li .rst-content h5 .headerlink,.rst-content h5 li .headerlink,li .rst-content h6 .headerlink,.rst-content h6 li .headerlink,li .rst-content dl dt .headerlink,.rst-content dl dt li .headerlink{display:inline-block}li .icon-large:before,li .icon-large:before{width:1.875em}ul.icons{list-style-type:none;margin-left:2em;text-indent:-0.8em}ul.icons li .icon,ul.icons li .wy-inline-validate.wy-inline-validate-success .wy-input-context,.wy-inline-validate.wy-inline-validate-success ul.icons li .wy-input-context,ul.icons li .wy-inline-validate.wy-inline-validate-danger .wy-input-context,.wy-inline-validate.wy-inline-validate-danger ul.icons li .wy-input-context,ul.icons li .wy-inline-validate.wy-inline-validate-warning .wy-input-context,.wy-inline-validate.wy-inline-validate-warning ul.icons li .wy-input-context,ul.icons li .wy-inline-validate.wy-inline-validate-info .wy-input-context,.wy-inline-validate.wy-inline-validate-info ul.icons li .wy-input-context,ul.icons li .wy-tag-input-group .wy-tag .wy-tag-remove,.wy-tag-input-group .wy-tag ul.icons li .wy-tag-remove,ul.icons li .rst-content .admonition-title,.rst-content ul.icons li .admonition-title,ul.icons li .rst-content h1 .headerlink,.rst-content h1 ul.icons li .headerlink,ul.icons li .rst-content h2 .headerlink,.rst-content h2 ul.icons li .headerlink,ul.icons li .rst-content h3 .headerlink,.rst-content h3 ul.icons li .headerlink,ul.icons li .rst-content h4 .headerlink,.rst-content h4 ul.icons li .headerlink,ul.icons li .rst-content h5 .headerlink,.rst-content h5 ul.icons li .headerlink,ul.icons li .rst-content h6 .headerlink,.rst-content h6 ul.icons li .headerlink,ul.icons li .rst-content dl dt .headerlink,.rst-content dl dt ul.icons li .headerlink{width:0.8em}ul.icons li .icon-large:before,ul.icons li .icon-large:before{vertical-align:baseline}.icon-glass:before{content:"\f000"}.icon-music:before{content:"\f001"}.icon-search:before{content:"\f002"}.icon-envelope-alt:before{content:"\f003"}.icon-heart:before{content:"\f004"}.icon-star:before{content:"\f005"}.icon-star-empty:before{content:"\f006"}.icon-user:before{content:"\f007"}.icon-film:before{content:"\f008"}.icon-th-large:before{content:"\f009"}.icon-th:before{content:"\f00a"}.icon-th-list:before{content:"\f00b"}.icon-ok:before{content:"\f00c"}.icon-remove:before,.wy-tag-input-group .wy-tag .wy-tag-remove:before{content:"\f00d"}.icon-zoom-in:before{content:"\f00e"}.icon-zoom-out:before{content:"\f010"}.icon-power-off:before,.icon-off:before{content:"\f011"}.icon-signal:before{content:"\f012"}.icon-gear:before,.icon-cog:before{content:"\f013"}.icon-trash:before{content:"\f014"}.icon-home:before{content:"\f015"}.icon-file-alt:before{content:"\f016"}.icon-time:before{content:"\f017"}.icon-road:before{content:"\f018"}.icon-download-alt:before{content:"\f019"}.icon-download:before{content:"\f01a"}.icon-upload:before{content:"\f01b"}.icon-inbox:before{content:"\f01c"}.icon-play-circle:before{content:"\f01d"}.icon-rotate-right:before,.icon-repeat:before{content:"\f01e"}.icon-refresh:before{content:"\f021"}.icon-list-alt:before{content:"\f022"}.icon-lock:before{content:"\f023"}.icon-flag:before{content:"\f024"}.icon-headphones:before{content:"\f025"}.icon-volume-off:before{content:"\f026"}.icon-volume-down:before{content:"\f027"}.icon-volume-up:before{content:"\f028"}.icon-qrcode:before{content:"\f029"}.icon-barcode:before{content:"\f02a"}.icon-tag:before{content:"\f02b"}.icon-tags:before{content:"\f02c"}.icon-book:before{content:"\f02d"}.icon-bookmark:before{content:"\f02e"}.icon-print:before{content:"\f02f"}.icon-camera:before{content:"\f030"}.icon-font:before{content:"\f031"}.icon-bold:before{content:"\f032"}.icon-italic:before{content:"\f033"}.icon-text-height:before{content:"\f034"}.icon-text-width:before{content:"\f035"}.icon-align-left:before{content:"\f036"}.icon-align-center:before{content:"\f037"}.icon-align-right:before{content:"\f038"}.icon-align-justify:before{content:"\f039"}.icon-list:before{content:"\f03a"}.icon-indent-left:before{content:"\f03b"}.icon-indent-right:before{content:"\f03c"}.icon-facetime-video:before{content:"\f03d"}.icon-picture:before{content:"\f03e"}.icon-pencil:before{content:"\f040"}.icon-map-marker:before{content:"\f041"}.icon-adjust:before{content:"\f042"}.icon-tint:before{content:"\f043"}.icon-edit:before{content:"\f044"}.icon-share:before{content:"\f045"}.icon-check:before{content:"\f046"}.icon-move:before{content:"\f047"}.icon-step-backward:before{content:"\f048"}.icon-fast-backward:before{content:"\f049"}.icon-backward:before{content:"\f04a"}.icon-play:before{content:"\f04b"}.icon-pause:before{content:"\f04c"}.icon-stop:before{content:"\f04d"}.icon-forward:before{content:"\f04e"}.icon-fast-forward:before{content:"\f050"}.icon-step-forward:before{content:"\f051"}.icon-eject:before{content:"\f052"}.icon-chevron-left:before{content:"\f053"}.icon-chevron-right:before{content:"\f054"}.icon-plus-sign:before{content:"\f055"}.icon-minus-sign:before{content:"\f056"}.icon-remove-sign:before,.wy-inline-validate.wy-inline-validate-danger .wy-input-context:before{content:"\f057"}.icon-ok-sign:before{content:"\f058"}.icon-question-sign:before{content:"\f059"}.icon-info-sign:before{content:"\f05a"}.icon-screenshot:before{content:"\f05b"}.icon-remove-circle:before{content:"\f05c"}.icon-ok-circle:before{content:"\f05d"}.icon-ban-circle:before{content:"\f05e"}.icon-arrow-left:before{content:"\f060"}.icon-arrow-right:before{content:"\f061"}.icon-arrow-up:before{content:"\f062"}.icon-arrow-down:before{content:"\f063"}.icon-mail-forward:before,.icon-share-alt:before{content:"\f064"}.icon-resize-full:before{content:"\f065"}.icon-resize-small:before{content:"\f066"}.icon-plus:before{content:"\f067"}.icon-minus:before{content:"\f068"}.icon-asterisk:before{content:"\f069"}.icon-exclamation-sign:before,.wy-inline-validate.wy-inline-validate-warning .wy-input-context:before,.wy-inline-validate.wy-inline-validate-info .wy-input-context:before,.rst-content .admonition-title:before{content:"\f06a"}.icon-gift:before{content:"\f06b"}.icon-leaf:before{content:"\f06c"}.icon-fire:before{content:"\f06d"}.icon-eye-open:before{content:"\f06e"}.icon-eye-close:before{content:"\f070"}.icon-warning-sign:before{content:"\f071"}.icon-plane:before{content:"\f072"}.icon-calendar:before{content:"\f073"}.icon-random:before{content:"\f074"}.icon-comment:before{content:"\f075"}.icon-magnet:before{content:"\f076"}.icon-chevron-up:before{content:"\f077"}.icon-chevron-down:before{content:"\f078"}.icon-retweet:before{content:"\f079"}.icon-shopping-cart:before{content:"\f07a"}.icon-folder-close:before{content:"\f07b"}.icon-folder-open:before{content:"\f07c"}.icon-resize-vertical:before{content:"\f07d"}.icon-resize-horizontal:before{content:"\f07e"}.icon-bar-chart:before{content:"\f080"}.icon-twitter-sign:before{content:"\f081"}.icon-facebook-sign:before{content:"\f082"}.icon-camera-retro:before{content:"\f083"}.icon-key:before{content:"\f084"}.icon-gears:before,.icon-cogs:before{content:"\f085"}.icon-comments:before{content:"\f086"}.icon-thumbs-up-alt:before{content:"\f087"}.icon-thumbs-down-alt:before{content:"\f088"}.icon-star-half:before{content:"\f089"}.icon-heart-empty:before{content:"\f08a"}.icon-signout:before{content:"\f08b"}.icon-linkedin-sign:before{content:"\f08c"}.icon-pushpin:before{content:"\f08d"}.icon-external-link:before{content:"\f08e"}.icon-signin:before{content:"\f090"}.icon-trophy:before{content:"\f091"}.icon-github-sign:before{content:"\f092"}.icon-upload-alt:before{content:"\f093"}.icon-lemon:before{content:"\f094"}.icon-phone:before{content:"\f095"}.icon-unchecked:before,.icon-check-empty:before{content:"\f096"}.icon-bookmark-empty:before{content:"\f097"}.icon-phone-sign:before{content:"\f098"}.icon-twitter:before{content:"\f099"}.icon-facebook:before{content:"\f09a"}.icon-github:before{content:"\f09b"}.icon-unlock:before{content:"\f09c"}.icon-credit-card:before{content:"\f09d"}.icon-rss:before{content:"\f09e"}.icon-hdd:before{content:"\f0a0"}.icon-bullhorn:before{content:"\f0a1"}.icon-bell:before{content:"\f0a2"}.icon-certificate:before{content:"\f0a3"}.icon-hand-right:before{content:"\f0a4"}.icon-hand-left:before{content:"\f0a5"}.icon-hand-up:before{content:"\f0a6"}.icon-hand-down:before{content:"\f0a7"}.icon-circle-arrow-left:before{content:"\f0a8"}.icon-circle-arrow-right:before{content:"\f0a9"}.icon-circle-arrow-up:before{content:"\f0aa"}.icon-circle-arrow-down:before{content:"\f0ab"}.icon-globe:before{content:"\f0ac"}.icon-wrench:before{content:"\f0ad"}.icon-tasks:before{content:"\f0ae"}.icon-filter:before{content:"\f0b0"}.icon-briefcase:before{content:"\f0b1"}.icon-fullscreen:before{content:"\f0b2"}.icon-group:before{content:"\f0c0"}.icon-link:before{content:"\f0c1"}.icon-cloud:before{content:"\f0c2"}.icon-beaker:before{content:"\f0c3"}.icon-cut:before{content:"\f0c4"}.icon-copy:before{content:"\f0c5"}.icon-paperclip:before,.icon-paper-clip:before{content:"\f0c6"}.icon-save:before{content:"\f0c7"}.icon-sign-blank:before{content:"\f0c8"}.icon-reorder:before{content:"\f0c9"}.icon-list-ul:before{content:"\f0ca"}.icon-list-ol:before{content:"\f0cb"}.icon-strikethrough:before{content:"\f0cc"}.icon-underline:before{content:"\f0cd"}.icon-table:before{content:"\f0ce"}.icon-magic:before{content:"\f0d0"}.icon-truck:before{content:"\f0d1"}.icon-pinterest:before{content:"\f0d2"}.icon-pinterest-sign:before{content:"\f0d3"}.icon-google-plus-sign:before{content:"\f0d4"}.icon-google-plus:before{content:"\f0d5"}.icon-money:before{content:"\f0d6"}.icon-caret-down:before{content:"\f0d7"}.icon-caret-up:before{content:"\f0d8"}.icon-caret-left:before{content:"\f0d9"}.icon-caret-right:before{content:"\f0da"}.icon-columns:before{content:"\f0db"}.icon-sort:before{content:"\f0dc"}.icon-sort-down:before{content:"\f0dd"}.icon-sort-up:before{content:"\f0de"}.icon-envelope:before{content:"\f0e0"}.icon-linkedin:before{content:"\f0e1"}.icon-rotate-left:before,.icon-undo:before{content:"\f0e2"}.icon-legal:before{content:"\f0e3"}.icon-dashboard:before{content:"\f0e4"}.icon-comment-alt:before{content:"\f0e5"}.icon-comments-alt:before{content:"\f0e6"}.icon-bolt:before{content:"\f0e7"}.icon-sitemap:before{content:"\f0e8"}.icon-umbrella:before{content:"\f0e9"}.icon-paste:before{content:"\f0ea"}.icon-lightbulb:before{content:"\f0eb"}.icon-exchange:before{content:"\f0ec"}.icon-cloud-download:before{content:"\f0ed"}.icon-cloud-upload:before{content:"\f0ee"}.icon-user-md:before{content:"\f0f0"}.icon-stethoscope:before{content:"\f0f1"}.icon-suitcase:before{content:"\f0f2"}.icon-bell-alt:before{content:"\f0f3"}.icon-coffee:before{content:"\f0f4"}.icon-food:before{content:"\f0f5"}.icon-file-text-alt:before{content:"\f0f6"}.icon-building:before{content:"\f0f7"}.icon-hospital:before{content:"\f0f8"}.icon-ambulance:before{content:"\f0f9"}.icon-medkit:before{content:"\f0fa"}.icon-fighter-jet:before{content:"\f0fb"}.icon-beer:before{content:"\f0fc"}.icon-h-sign:before{content:"\f0fd"}.icon-plus-sign-alt:before{content:"\f0fe"}.icon-double-angle-left:before{content:"\f100"}.icon-double-angle-right:before{content:"\f101"}.icon-double-angle-up:before{content:"\f102"}.icon-double-angle-down:before{content:"\f103"}.icon-angle-left:before{content:"\f104"}.icon-angle-right:before{content:"\f105"}.icon-angle-up:before{content:"\f106"}.icon-angle-down:before{content:"\f107"}.icon-desktop:before{content:"\f108"}.icon-laptop:before{content:"\f109"}.icon-tablet:before{content:"\f10a"}.icon-mobile-phone:before{content:"\f10b"}.icon-circle-blank:before{content:"\f10c"}.icon-quote-left:before{content:"\f10d"}.icon-quote-right:before{content:"\f10e"}.icon-spinner:before{content:"\f110"}.icon-circle:before{content:"\f111"}.icon-mail-reply:before,.icon-reply:before{content:"\f112"}.icon-github-alt:before{content:"\f113"}.icon-folder-close-alt:before{content:"\f114"}.icon-folder-open-alt:before{content:"\f115"}.icon-expand-alt:before{content:"\f116"}.icon-collapse-alt:before{content:"\f117"}.icon-smile:before{content:"\f118"}.icon-frown:before{content:"\f119"}.icon-meh:before{content:"\f11a"}.icon-gamepad:before{content:"\f11b"}.icon-keyboard:before{content:"\f11c"}.icon-flag-alt:before{content:"\f11d"}.icon-flag-checkered:before{content:"\f11e"}.icon-terminal:before{content:"\f120"}.icon-code:before{content:"\f121"}.icon-reply-all:before{content:"\f122"}.icon-mail-reply-all:before{content:"\f122"}.icon-star-half-full:before,.icon-star-half-empty:before{content:"\f123"}.icon-location-arrow:before{content:"\f124"}.icon-crop:before{content:"\f125"}.icon-code-fork:before{content:"\f126"}.icon-unlink:before{content:"\f127"}.icon-question:before{content:"\f128"}.icon-info:before{content:"\f129"}.icon-exclamation:before{content:"\f12a"}.icon-superscript:before{content:"\f12b"}.icon-subscript:before{content:"\f12c"}.icon-eraser:before{content:"\f12d"}.icon-puzzle-piece:before{content:"\f12e"}.icon-microphone:before{content:"\f130"}.icon-microphone-off:before{content:"\f131"}.icon-shield:before{content:"\f132"}.icon-calendar-empty:before{content:"\f133"}.icon-fire-extinguisher:before{content:"\f134"}.icon-rocket:before{content:"\f135"}.icon-maxcdn:before{content:"\f136"}.icon-chevron-sign-left:before{content:"\f137"}.icon-chevron-sign-right:before{content:"\f138"}.icon-chevron-sign-up:before{content:"\f139"}.icon-chevron-sign-down:before{content:"\f13a"}.icon-html5:before{content:"\f13b"}.icon-css3:before{content:"\f13c"}.icon-anchor:before{content:"\f13d"}.icon-unlock-alt:before{content:"\f13e"}.icon-bullseye:before{content:"\f140"}.icon-ellipsis-horizontal:before{content:"\f141"}.icon-ellipsis-vertical:before{content:"\f142"}.icon-rss-sign:before{content:"\f143"}.icon-play-sign:before{content:"\f144"}.icon-ticket:before{content:"\f145"}.icon-minus-sign-alt:before{content:"\f146"}.icon-check-minus:before{content:"\f147"}.icon-level-up:before{content:"\f148"}.icon-level-down:before{content:"\f149"}.icon-check-sign:before,.wy-inline-validate.wy-inline-validate-success .wy-input-context:before{content:"\f14a"}.icon-edit-sign:before{content:"\f14b"}.icon-external-link-sign:before{content:"\f14c"}.icon-share-sign:before{content:"\f14d"}.icon-compass:before{content:"\f14e"}.icon-collapse:before{content:"\f150"}.icon-collapse-top:before{content:"\f151"}.icon-expand:before{content:"\f152"}.icon-euro:before,.icon-eur:before{content:"\f153"}.icon-gbp:before{content:"\f154"}.icon-dollar:before,.icon-usd:before{content:"\f155"}.icon-rupee:before,.icon-inr:before{content:"\f156"}.icon-yen:before,.icon-jpy:before{content:"\f157"}.icon-renminbi:before,.icon-cny:before{content:"\f158"}.icon-won:before,.icon-krw:before{content:"\f159"}.icon-bitcoin:before,.icon-btc:before{content:"\f15a"}.icon-file:before{content:"\f15b"}.icon-file-text:before{content:"\f15c"}.icon-sort-by-alphabet:before{content:"\f15d"}.icon-sort-by-alphabet-alt:before{content:"\f15e"}.icon-sort-by-attributes:before{content:"\f160"}.icon-sort-by-attributes-alt:before{content:"\f161"}.icon-sort-by-order:before{content:"\f162"}.icon-sort-by-order-alt:before{content:"\f163"}.icon-thumbs-up:before{content:"\f164"}.icon-thumbs-down:before{content:"\f165"}.icon-youtube-sign:before{content:"\f166"}.icon-youtube:before{content:"\f167"}.icon-xing:before{content:"\f168"}.icon-xing-sign:before{content:"\f169"}.icon-youtube-play:before{content:"\f16a"}.icon-dropbox:before{content:"\f16b"}.icon-stackexchange:before{content:"\f16c"}.icon-instagram:before{content:"\f16d"}.icon-flickr:before{content:"\f16e"}.icon-adn:before{content:"\f170"}.icon-bitbucket:before{content:"\f171"}.icon-bitbucket-sign:before{content:"\f172"}.icon-tumblr:before{content:"\f173"}.icon-tumblr-sign:before{content:"\f174"}.icon-long-arrow-down:before{content:"\f175"}.icon-long-arrow-up:before{content:"\f176"}.icon-long-arrow-left:before{content:"\f177"}.icon-long-arrow-right:before{content:"\f178"}.icon-apple:before{content:"\f179"}.icon-windows:before{content:"\f17a"}.icon-android:before{content:"\f17b"}.icon-linux:before{content:"\f17c"}.icon-dribbble:before{content:"\f17d"}.icon-skype:before{content:"\f17e"}.icon-foursquare:before{content:"\f180"}.icon-trello:before{content:"\f181"}.icon-female:before{content:"\f182"}.icon-male:before{content:"\f183"}.icon-gittip:before{content:"\f184"}.icon-sun:before{content:"\f185"}.icon-moon:before{content:"\f186"}.icon-archive:before{content:"\f187"}.icon-bug:before{content:"\f188"}.icon-vk:before{content:"\f189"}.icon-weibo:before{content:"\f18a"}.icon-renren:before{content:"\f18b"}.wy-alert,.rst-content .note,.rst-content .attention,.rst-content .caution,.rst-content .danger,.rst-content .error,.rst-content .hint,.rst-content .important,.rst-content .tip,.rst-content .warning,.rst-content .seealso{padding:12px;line-height:24px;margin-bottom:24px}.wy-alert-title,.rst-content .admonition-title{color:#fff;font-weight:bold;display:block;color:#fff;background:transparent;margin:-12px;padding:6px 12px;margin-bottom:12px}.wy-alert.wy-alert-danger,.rst-content .wy-alert-danger.note,.rst-content .wy-alert-danger.attention,.rst-content .wy-alert-danger.caution,.rst-content .danger,.rst-content .error,.rst-content .wy-alert-danger.hint,.rst-content .wy-alert-danger.important,.rst-content .wy-alert-danger.tip,.rst-content .wy-alert-danger.warning,.rst-content .wy-alert-danger.seealso{background:#fdf3f2}.wy-alert.wy-alert-danger .wy-alert-title,.rst-content .wy-alert-danger.note .wy-alert-title,.rst-content .wy-alert-danger.attention .wy-alert-title,.rst-content .wy-alert-danger.caution .wy-alert-title,.rst-content .danger .wy-alert-title,.rst-content .error .wy-alert-title,.rst-content .wy-alert-danger.hint .wy-alert-title,.rst-content .wy-alert-danger.important .wy-alert-title,.rst-content .wy-alert-danger.tip .wy-alert-title,.rst-content .wy-alert-danger.warning .wy-alert-title,.rst-content .wy-alert-danger.seealso .wy-alert-title,.wy-alert.wy-alert-danger .rst-content .admonition-title,.rst-content .wy-alert.wy-alert-danger .admonition-title,.rst-content .wy-alert-danger.note .admonition-title,.rst-content .wy-alert-danger.attention .admonition-title,.rst-content .wy-alert-danger.caution .admonition-title,.rst-content .danger .admonition-title,.rst-content .error .admonition-title,.rst-content .wy-alert-danger.hint .admonition-title,.rst-content .wy-alert-danger.important .admonition-title,.rst-content .wy-alert-danger.tip .admonition-title,.rst-content .wy-alert-danger.warning .admonition-title,.rst-content .wy-alert-danger.seealso .admonition-title{background:#f29f97}.wy-alert.wy-alert-warning,.rst-content .wy-alert-warning.note,.rst-content .attention,.rst-content .caution,.rst-content .wy-alert-warning.danger,.rst-content .wy-alert-warning.error,.rst-content .wy-alert-warning.hint,.rst-content .wy-alert-warning.important,.rst-content .wy-alert-warning.tip,.rst-content .warning,.rst-content .wy-alert-warning.seealso{background:#ffedcc}.wy-alert.wy-alert-warning .wy-alert-title,.rst-content .wy-alert-warning.note .wy-alert-title,.rst-content .attention .wy-alert-title,.rst-content .caution .wy-alert-title,.rst-content .wy-alert-warning.danger .wy-alert-title,.rst-content .wy-alert-warning.error .wy-alert-title,.rst-content .wy-alert-warning.hint .wy-alert-title,.rst-content .wy-alert-warning.important .wy-alert-title,.rst-content .wy-alert-warning.tip .wy-alert-title,.rst-content .warning .wy-alert-title,.rst-content .wy-alert-warning.seealso .wy-alert-title,.wy-alert.wy-alert-warning .rst-content .admonition-title,.rst-content .wy-alert.wy-alert-warning .admonition-title,.rst-content .wy-alert-warning.note .admonition-title,.rst-content .attention .admonition-title,.rst-content .caution .admonition-title,.rst-content .wy-alert-warning.danger .admonition-title,.rst-content .wy-alert-warning.error .admonition-title,.rst-content .wy-alert-warning.hint .admonition-title,.rst-content .wy-alert-warning.important .admonition-title,.rst-content .wy-alert-warning.tip .admonition-title,.rst-content .warning .admonition-title,.rst-content .wy-alert-warning.seealso .admonition-title{background:#f0b37e}.wy-alert.wy-alert-info,.rst-content .note,.rst-content .wy-alert-info.attention,.rst-content .wy-alert-info.caution,.rst-content .wy-alert-info.danger,.rst-content .wy-alert-info.error,.rst-content .wy-alert-info.hint,.rst-content .wy-alert-info.important,.rst-content .wy-alert-info.tip,.rst-content .wy-alert-info.warning,.rst-content .seealso{background:#e7f2fa}.wy-alert.wy-alert-info .wy-alert-title,.rst-content .note .wy-alert-title,.rst-content .wy-alert-info.attention .wy-alert-title,.rst-content .wy-alert-info.caution .wy-alert-title,.rst-content .wy-alert-info.danger .wy-alert-title,.rst-content .wy-alert-info.error .wy-alert-title,.rst-content .wy-alert-info.hint .wy-alert-title,.rst-content .wy-alert-info.important .wy-alert-title,.rst-content .wy-alert-info.tip .wy-alert-title,.rst-content .wy-alert-info.warning .wy-alert-title,.rst-content .seealso .wy-alert-title,.wy-alert.wy-alert-info .rst-content .admonition-title,.rst-content .wy-alert.wy-alert-info .admonition-title,.rst-content .note .admonition-title,.rst-content .wy-alert-info.attention .admonition-title,.rst-content .wy-alert-info.caution .admonition-title,.rst-content .wy-alert-info.danger .admonition-title,.rst-content .wy-alert-info.error .admonition-title,.rst-content .wy-alert-info.hint .admonition-title,.rst-content .wy-alert-info.important .admonition-title,.rst-content .wy-alert-info.tip .admonition-title,.rst-content .wy-alert-info.warning .admonition-title,.rst-content .seealso .admonition-title{background:#6ab0de}.wy-alert.wy-alert-success,.rst-content .wy-alert-success.note,.rst-content .wy-alert-success.attention,.rst-content .wy-alert-success.caution,.rst-content .wy-alert-success.danger,.rst-content .wy-alert-success.error,.rst-content .hint,.rst-content .important,.rst-content .tip,.rst-content .wy-alert-success.warning,.rst-content .wy-alert-success.seealso{background:#dbfaf4}.wy-alert.wy-alert-success .wy-alert-title,.rst-content .wy-alert-success.note .wy-alert-title,.rst-content .wy-alert-success.attention .wy-alert-title,.rst-content .wy-alert-success.caution .wy-alert-title,.rst-content .wy-alert-success.danger .wy-alert-title,.rst-content .wy-alert-success.error .wy-alert-title,.rst-content .hint .wy-alert-title,.rst-content .important .wy-alert-title,.rst-content .tip .wy-alert-title,.rst-content .wy-alert-success.warning .wy-alert-title,.rst-content .wy-alert-success.seealso .wy-alert-title,.wy-alert.wy-alert-success .rst-content .admonition-title,.rst-content .wy-alert.wy-alert-success .admonition-title,.rst-content .wy-alert-success.note .admonition-title,.rst-content .wy-alert-success.attention .admonition-title,.rst-content .wy-alert-success.caution .admonition-title,.rst-content .wy-alert-success.danger .admonition-title,.rst-content .wy-alert-success.error .admonition-title,.rst-content .hint .admonition-title,.rst-content .important .admonition-title,.rst-content .tip .admonition-title,.rst-content .wy-alert-success.warning .admonition-title,.rst-content .wy-alert-success.seealso .admonition-title{background:#1abc9c}.wy-alert.wy-alert-neutral,.rst-content .wy-alert-neutral.note,.rst-content .wy-alert-neutral.attention,.rst-content .wy-alert-neutral.caution,.rst-content .wy-alert-neutral.danger,.rst-content .wy-alert-neutral.error,.rst-content .wy-alert-neutral.hint,.rst-content .wy-alert-neutral.important,.rst-content .wy-alert-neutral.tip,.rst-content .wy-alert-neutral.warning,.rst-content .wy-alert-neutral.seealso{background:#f3f6f6}.wy-alert.wy-alert-neutral strong,.rst-content .wy-alert-neutral.note strong,.rst-content .wy-alert-neutral.attention strong,.rst-content .wy-alert-neutral.caution strong,.rst-content .wy-alert-neutral.danger strong,.rst-content .wy-alert-neutral.error strong,.rst-content .wy-alert-neutral.hint strong,.rst-content .wy-alert-neutral.important strong,.rst-content .wy-alert-neutral.tip strong,.rst-content .wy-alert-neutral.warning strong,.rst-content .wy-alert-neutral.seealso strong{color:#404040}.wy-alert.wy-alert-neutral a,.rst-content .wy-alert-neutral.note a,.rst-content .wy-alert-neutral.attention a,.rst-content .wy-alert-neutral.caution a,.rst-content .wy-alert-neutral.danger a,.rst-content .wy-alert-neutral.error a,.rst-content .wy-alert-neutral.hint a,.rst-content .wy-alert-neutral.important a,.rst-content .wy-alert-neutral.tip a,.rst-content .wy-alert-neutral.warning a,.rst-content .wy-alert-neutral.seealso a{color:#2980b9}.wy-tray-container{position:fixed;top:-50px;left:0;width:100%;-webkit-transition:top 0.2s ease-in;-moz-transition:top 0.2s ease-in;transition:top 0.2s ease-in}.wy-tray-container.on{top:0}.wy-tray-container li{display:none;width:100%;background:#343131;padding:12px 24px;color:#fff;margin-bottom:6px;text-align:center;box-shadow:0 5px 5px 0 rgba(0,0,0,0.1),0px -1px 2px -1px rgba(255,255,255,0.5) inset}.wy-tray-container li.wy-tray-item-success{background:#27ae60}.wy-tray-container li.wy-tray-item-info{background:#2980b9}.wy-tray-container li.wy-tray-item-warning{background:#e67e22}.wy-tray-container li.wy-tray-item-danger{background:#e74c3c}.btn{display:inline-block;*display:inline;zoom:1;line-height:normal;white-space:nowrap;vertical-align:baseline;text-align:center;cursor:pointer;-webkit-user-drag:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;font-size:100%;padding:6px 12px;color:#fff;border:1px solid rgba(0,0,0,0.1);border-bottom:solid 3px rgba(0,0,0,0.1);background-color:#27ae60;text-decoration:none;font-weight:500;box-shadow:0px 1px 2px -1px rgba(255,255,255,0.5) inset;-webkit-transition:all 0.1s linear;-moz-transition:all 0.1s linear;transition:all 0.1s linear;outline-none:false}.btn-hover{background:#2e8ece;color:#fff}.btn:hover{background:#2cc36b;color:#fff}.btn:focus{background:#2cc36b;color:#fff;outline:0}.btn:active{border-top:solid 3px rgba(0,0,0,0.1);border-bottom:solid 1px rgba(0,0,0,0.1);box-shadow:0px 1px 2px -1px rgba(0,0,0,0.5) inset}.btn[disabled]{background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);filter:alpha(opacity=40);opacity:0.4;cursor:not-allowed;box-shadow:none}.btn-disabled{background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);filter:alpha(opacity=40);opacity:0.4;cursor:not-allowed;box-shadow:none}.btn-disabled:hover,.btn-disabled:focus,.btn-disabled:active{background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);filter:alpha(opacity=40);opacity:0.4;cursor:not-allowed;box-shadow:none}.btn::-moz-focus-inner{padding:0;border:0}.btn-small{font-size:80%}.btn-info{background-color:#2980b9 !important}.btn-info:hover{background-color:#2e8ece !important}.btn-neutral{background-color:#f3f6f6 !important;color:#404040 !important}.btn-neutral:hover{background-color:#e5ebeb !important;color:#404040}.btn-danger{background-color:#e74c3c !important}.btn-danger:hover{background-color:#ea6153 !important}.btn-warning{background-color:#e67e22 !important}.btn-warning:hover{background-color:#e98b39 !important}.btn-invert{background-color:#343131}.btn-invert:hover{background-color:#413d3d !important}.btn-link{background-color:transparent !important;color:#2980b9;border-color:transparent}.btn-link:hover{background-color:transparent !important;color:#409ad5;border-color:transparent}.btn-link:active{background-color:transparent !important;border-color:transparent;border-top:solid 1px transparent;border-bottom:solid 3px transparent}.wy-btn-group .btn,.wy-control .btn{vertical-align:middle}.wy-btn-group{margin-bottom:24px;*zoom:1}.wy-btn-group:before,.wy-btn-group:after{display:table;content:""}.wy-btn-group:after{clear:both}.wy-dropdown{position:relative;display:inline-block}.wy-dropdown:hover .wy-dropdown-menu{display:block}.wy-dropdown .caret:after{font-family:fontawesome-webfont;content:"\f0d7";font-size:70%}.wy-dropdown-menu{position:absolute;top:100%;left:0;display:none;float:left;min-width:100%;background:#fcfcfc;z-index:100;border:solid 1px #cfd7dd;box-shadow:0 5px 5px 0 rgba(0,0,0,0.1);padding:12px}.wy-dropdown-menu>dd>a{display:block;clear:both;color:#404040;white-space:nowrap;font-size:90%;padding:0 12px}.wy-dropdown-menu>dd>a:hover{background:#2980b9;color:#fff}.wy-dropdown-menu>dd.divider{border-top:solid 1px #cfd7dd;margin:6px 0}.wy-dropdown-menu>dd.search{padding-bottom:12px}.wy-dropdown-menu>dd.search input[type="search"]{width:100%}.wy-dropdown-menu>dd.call-to-action{background:#e3e3e3;text-transform:uppercase;font-weight:500;font-size:80%}.wy-dropdown-menu>dd.call-to-action:hover{background:#e3e3e3}.wy-dropdown-menu>dd.call-to-action .btn{color:#fff}.wy-dropdown.wy-dropdown-bubble .wy-dropdown-menu{background:#fcfcfc;margin-top:2px}.wy-dropdown.wy-dropdown-bubble .wy-dropdown-menu a{padding:6px 12px}.wy-dropdown.wy-dropdown-bubble .wy-dropdown-menu a:hover{background:#2980b9;color:#fff}.wy-dropdown.wy-dropdown-left .wy-dropdown-menu{right:0;text-align:right}.wy-dropdown-arrow:before{content:" ";border-bottom:5px solid #f5f5f5;border-left:5px solid transparent;border-right:5px solid transparent;position:absolute;display:block;top:-4px;left:50%;margin-left:-3px}.wy-dropdown-arrow.wy-dropdown-arrow-left:before{left:11px}.wy-form-stacked select{display:block}.wy-form-aligned input,.wy-form-aligned textarea,.wy-form-aligned select,.wy-form-aligned .wy-help-inline,.wy-form-aligned label{display:inline-block;*display:inline;*zoom:1;vertical-align:middle}.wy-form-aligned .wy-control-group>label{display:inline-block;vertical-align:middle;width:10em;margin:0.5em 1em 0 0;float:left}.wy-form-aligned .wy-control{float:left}.wy-form-aligned .wy-control label{display:block}.wy-form-aligned .wy-control select{margin-top:0.5em}fieldset{border:0;margin:0;padding:0}legend{display:block;width:100%;border:0;padding:0;white-space:normal;margin-bottom:24px;font-size:150%;*margin-left:-7px}label{display:block;margin:0 0 0.3125em 0;color:#999;font-size:90%}button,input,select,textarea{font-size:100%;margin:0;vertical-align:baseline;*vertical-align:middle}button,input{line-height:normal}button{-webkit-appearance:button;cursor:pointer;*overflow:visible}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}button[disabled]{cursor:default}input[type="button"],input[type="reset"],input[type="submit"]{-webkit-appearance:button;cursor:pointer;*overflow:visible}input[type="text"],input[type="password"],input[type="email"],input[type="url"],input[type="date"],input[type="month"],input[type="time"],input[type="datetime"],input[type="datetime-local"],input[type="week"],input[type="number"],input[type="search"],input[type="tel"],input[type="color"]{-webkit-appearance:none;padding:6px;display:inline-block;border:1px solid #ccc;font-size:80%;font-family:"Lato","proxima-nova","Helvetica Neue",Arial,sans-serif;box-shadow:inset 0 1px 3px #ddd;border-radius:0;-webkit-transition:border 0.3s linear;-moz-transition:border 0.3s linear;transition:border 0.3s linear}input[type="datetime-local"]{padding:0.34375em 0.625em}input[disabled]{cursor:default}input[type="checkbox"],input[type="radio"]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;padding:0;margin-right:0.3125em;*height:13px;*width:13px}input[type="search"]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}input[type="search"]::-webkit-search-cancel-button,input[type="search"]::-webkit-search-decoration{-webkit-appearance:none}input[type="text"]:focus,input[type="password"]:focus,input[type="email"]:focus,input[type="url"]:focus,input[type="date"]:focus,input[type="month"]:focus,input[type="time"]:focus,input[type="datetime"]:focus,input[type="datetime-local"]:focus,input[type="week"]:focus,input[type="number"]:focus,input[type="search"]:focus,input[type="tel"]:focus,input[type="color"]:focus{outline:0;outline:thin dotted \9;border-color:#2980b9}input.no-focus:focus{border-color:#ccc !important}input[type="file"]:focus,input[type="radio"]:focus,input[type="checkbox"]:focus{outline:thin dotted #333;outline:1px auto #129fea}input[type="text"][disabled],input[type="password"][disabled],input[type="email"][disabled],input[type="url"][disabled],input[type="date"][disabled],input[type="month"][disabled],input[type="time"][disabled],input[type="datetime"][disabled],input[type="datetime-local"][disabled],input[type="week"][disabled],input[type="number"][disabled],input[type="search"][disabled],input[type="tel"][disabled],input[type="color"][disabled]{cursor:not-allowed;background-color:#f3f6f6;color:#cad2d3}input:focus:invalid,textarea:focus:invalid,select:focus:invalid{color:#e74c3c;border:1px solid #e74c3c}input:focus:invalid:focus,textarea:focus:invalid:focus,select:focus:invalid:focus{border-color:#e9322d}input[type="file"]:focus:invalid:focus,input[type="radio"]:focus:invalid:focus,input[type="checkbox"]:focus:invalid:focus{outline-color:#e9322d}input.wy-input-large{padding:12px;font-size:100%}textarea{overflow:auto;vertical-align:top;width:100%}select,textarea{padding:0.5em 0.625em;display:inline-block;border:1px solid #ccc;font-size:0.8em;box-shadow:inset 0 1px 3px #ddd;-webkit-transition:border 0.3s linear;-moz-transition:border 0.3s linear;transition:border 0.3s linear}select{border:1px solid #ccc;background-color:#fff}select[multiple]{height:auto}select:focus,textarea:focus{outline:0}select[disabled],textarea[disabled],input[readonly],select[readonly],textarea[readonly]{cursor:not-allowed;background-color:#fff;color:#cad2d3;border-color:transparent}.wy-checkbox,.wy-radio{margin:0.5em 0;color:#404040 !important;display:block}.wy-form-message-inline{display:inline-block;*display:inline;*zoom:1;vertical-align:middle}.wy-input-prefix,.wy-input-suffix{white-space:nowrap}.wy-input-prefix .wy-input-context,.wy-input-suffix .wy-input-context{padding:6px;display:inline-block;font-size:80%;background-color:#f3f6f6;border:solid 1px #ccc;color:#999}.wy-input-suffix .wy-input-context{border-left:0}.wy-input-prefix .wy-input-context{border-right:0}.wy-inline-validate{white-space:nowrap}.wy-inline-validate .wy-input-context{padding:0.5em 0.625em;display:inline-block;font-size:80%}.wy-inline-validate.wy-inline-validate-success .wy-input-context{color:#27ae60}.wy-inline-validate.wy-inline-validate-danger .wy-input-context{color:#e74c3c}.wy-inline-validate.wy-inline-validate-warning .wy-input-context{color:#e67e22}.wy-inline-validate.wy-inline-validate-info .wy-input-context{color:#2980b9}.wy-control-group{margin-bottom:24px;*zoom:1}.wy-control-group:before,.wy-control-group:after{display:table;content:""}.wy-control-group:after{clear:both}.wy-control-group.wy-control-group-error .wy-form-message,.wy-control-group.wy-control-group-error label{color:#e74c3c}.wy-control-group.wy-control-group-error input[type="text"],.wy-control-group.wy-control-group-error input[type="password"],.wy-control-group.wy-control-group-error input[type="email"],.wy-control-group.wy-control-group-error input[type="url"],.wy-control-group.wy-control-group-error input[type="date"],.wy-control-group.wy-control-group-error input[type="month"],.wy-control-group.wy-control-group-error input[type="time"],.wy-control-group.wy-control-group-error input[type="datetime"],.wy-control-group.wy-control-group-error input[type="datetime-local"],.wy-control-group.wy-control-group-error input[type="week"],.wy-control-group.wy-control-group-error input[type="number"],.wy-control-group.wy-control-group-error input[type="search"],.wy-control-group.wy-control-group-error input[type="tel"],.wy-control-group.wy-control-group-error input[type="color"]{border:solid 2px #e74c3c}.wy-control-group.wy-control-group-error textarea{border:solid 2px #e74c3c}.wy-control-group.fluid-input input[type="text"],.wy-control-group.fluid-input input[type="password"],.wy-control-group.fluid-input input[type="email"],.wy-control-group.fluid-input input[type="url"],.wy-control-group.fluid-input input[type="date"],.wy-control-group.fluid-input input[type="month"],.wy-control-group.fluid-input input[type="time"],.wy-control-group.fluid-input input[type="datetime"],.wy-control-group.fluid-input input[type="datetime-local"],.wy-control-group.fluid-input input[type="week"],.wy-control-group.fluid-input input[type="number"],.wy-control-group.fluid-input input[type="search"],.wy-control-group.fluid-input input[type="tel"],.wy-control-group.fluid-input input[type="color"]{width:100%}.wy-form-message-inline{display:inline-block;padding-left:0.3em;color:#666;vertical-align:middle;font-size:90%}.wy-form-message{display:block;color:#ccc;font-size:70%;margin-top:0.3125em;font-style:italic}.wy-tag-input-group{padding:4px 4px 0px 4px;display:inline-block;border:1px solid #ccc;font-size:80%;font-family:"Lato","proxima-nova","Helvetica Neue",Arial,sans-serif;box-shadow:inset 0 1px 3px #ddd;background:#fff;-webkit-transition:border 0.3s linear;-moz-transition:border 0.3s linear;transition:border 0.3s linear}.wy-tag-input-group .wy-tag{display:inline-block;background-color:rgba(0,0,0,0.1);padding:0.5em 0.625em;border-radius:2px;position:relative;margin-bottom:4px}.wy-tag-input-group .wy-tag .wy-tag-remove{color:#ccc;margin-left:5px}.wy-tag-input-group .wy-tag .wy-tag-remove:hover{color:#e74c3c}.wy-tag-input-group label{margin-left:5px;display:inline-block;margin-bottom:0}.wy-tag-input-group input{border:none;font-size:100%;margin-bottom:4px;box-shadow:none}.wy-form-upload{border:solid 1px #ccc;border-bottom:solid 3px #ccc;background-color:#fff;padding:24px;display:inline-block;text-align:center;cursor:pointer;color:#404040;-webkit-transition:border-color 0.1s ease-in;-moz-transition:border-color 0.1s ease-in;transition:border-color 0.1s ease-in;*zoom:1}.wy-form-upload:before,.wy-form-upload:after{display:table;content:""}.wy-form-upload:after{clear:both}@media screen and (max-width: 480px){.wy-form-upload{width:100%}}.wy-form-upload .image-drop{display:none}.wy-form-upload .image-desktop{display:none}.wy-form-upload .image-loading{display:none}.wy-form-upload .wy-form-upload-icon{display:block;font-size:32px;color:#b3b3b3}.wy-form-upload .image-drop .wy-form-upload-icon{color:#27ae60}.wy-form-upload p{font-size:90%}.wy-form-upload .wy-form-upload-image{float:left;margin-right:24px}@media screen and (max-width: 480px){.wy-form-upload .wy-form-upload-image{width:100%;margin-bottom:24px}}.wy-form-upload img{max-width:125px;max-height:125px;opacity:0.9;-webkit-transition:opacity 0.1s ease-in;-moz-transition:opacity 0.1s ease-in;transition:opacity 0.1s ease-in}.wy-form-upload .wy-form-upload-content{float:left}@media screen and (max-width: 480px){.wy-form-upload .wy-form-upload-content{width:100%}}.wy-form-upload:hover{border-color:#b3b3b3;color:#404040}.wy-form-upload:hover .image-desktop{display:block}.wy-form-upload:hover .image-drag{display:none}.wy-form-upload:hover img{opacity:1}.wy-form-upload:active{border-top:solid 3px #ccc;border-bottom:solid 1px #ccc}.wy-form-upload.wy-form-upload-big{width:100%;text-align:center;padding:72px}.wy-form-upload.wy-form-upload-big .wy-form-upload-content{float:none}.wy-form-upload.wy-form-upload-file p{margin-bottom:0}.wy-form-upload.wy-form-upload-file .wy-form-upload-icon{display:inline-block;font-size:inherit}.wy-form-upload.wy-form-upload-drop{background-color:#ddf7e8}.wy-form-upload.wy-form-upload-drop .image-drop{display:block}.wy-form-upload.wy-form-upload-drop .image-desktop{display:none}.wy-form-upload.wy-form-upload-drop .image-drag{display:none}.wy-form-upload.wy-form-upload-loading .image-drag{display:none}.wy-form-upload.wy-form-upload-loading .image-desktop{display:none}.wy-form-upload.wy-form-upload-loading .image-loading{display:block}.wy-form-upload.wy-form-upload-loading .wy-input-prefix{display:none}.wy-form-upload.wy-form-upload-loading p{margin-bottom:0}.rotate-90{-webkit-transform:rotate(90deg);-moz-transform:rotate(90deg);-ms-transform:rotate(90deg);-o-transform:rotate(90deg);transform:rotate(90deg)}.rotate-180{-webkit-transform:rotate(180deg);-moz-transform:rotate(180deg);-ms-transform:rotate(180deg);-o-transform:rotate(180deg);transform:rotate(180deg)}.rotate-270{-webkit-transform:rotate(270deg);-moz-transform:rotate(270deg);-ms-transform:rotate(270deg);-o-transform:rotate(270deg);transform:rotate(270deg)}.mirror{-webkit-transform:scaleX(-1);-moz-transform:scaleX(-1);-ms-transform:scaleX(-1);-o-transform:scaleX(-1);transform:scaleX(-1)}.mirror.rotate-90{-webkit-transform:scaleX(-1) rotate(90deg);-moz-transform:scaleX(-1) rotate(90deg);-ms-transform:scaleX(-1) rotate(90deg);-o-transform:scaleX(-1) rotate(90deg);transform:scaleX(-1) rotate(90deg)}.mirror.rotate-180{-webkit-transform:scaleX(-1) rotate(180deg);-moz-transform:scaleX(-1) rotate(180deg);-ms-transform:scaleX(-1) rotate(180deg);-o-transform:scaleX(-1) rotate(180deg);transform:scaleX(-1) rotate(180deg)}.mirror.rotate-270{-webkit-transform:scaleX(-1) rotate(270deg);-moz-transform:scaleX(-1) rotate(270deg);-ms-transform:scaleX(-1) rotate(270deg);-o-transform:scaleX(-1) rotate(270deg);transform:scaleX(-1) rotate(270deg)}.wy-form-gallery-manage{margin-left:-12px;margin-right:-12px}.wy-form-gallery-manage li{float:left;padding:12px;width:20%;cursor:pointer}@media screen and (max-width: 768px){.wy-form-gallery-manage li{width:25%}}@media screen and (max-width: 480px){.wy-form-gallery-manage li{width:50%}}.wy-form-gallery-manage li:active{cursor:move}.wy-form-gallery-manage li>a{padding:12px;background-color:#fff;border:solid 1px #e1e4e5;border-bottom:solid 3px #e1e4e5;display:inline-block;-webkit-transition:all 0.1s ease-in;-moz-transition:all 0.1s ease-in;transition:all 0.1s ease-in}.wy-form-gallery-manage li>a:active{border:solid 1px #ccc;border-top:solid 3px #ccc}.wy-form-gallery-manage img{width:100%;-webkit-transition:all 0.05s ease-in;-moz-transition:all 0.05s ease-in;transition:all 0.05s ease-in}li.wy-form-gallery-edit{position:relative;color:#fff;padding:24px;width:100%;display:block;background-color:#343131;border-radius:4px}li.wy-form-gallery-edit .arrow{position:absolute;display:block;top:-50px;left:50%;margin-left:-25px;z-index:500;height:0;width:0;border-color:transparent;border-style:solid;border-width:25px;border-bottom-color:#343131}@media only screen and (max-width: 480px){.wy-form button[type="submit"]{margin:0.7em 0 0}.wy-form input[type="text"],.wy-form input[type="password"],.wy-form input[type="email"],.wy-form input[type="url"],.wy-form input[type="date"],.wy-form input[type="month"],.wy-form input[type="time"],.wy-form input[type="datetime"],.wy-form input[type="datetime-local"],.wy-form input[type="week"],.wy-form input[type="number"],.wy-form input[type="search"],.wy-form input[type="tel"],.wy-form input[type="color"]{margin-bottom:0.3em;display:block}.wy-form label{margin-bottom:0.3em;display:block}.wy-form input[type="password"],.wy-form input[type="email"],.wy-form input[type="url"],.wy-form input[type="date"],.wy-form input[type="month"],.wy-form input[type="time"],.wy-form input[type="datetime"],.wy-form input[type="datetime-local"],.wy-form input[type="week"],.wy-form input[type="number"],.wy-form input[type="search"],.wy-form input[type="tel"],.wy-form input[type="color"]{margin-bottom:0}.wy-form-aligned .wy-control-group label{margin-bottom:0.3em;text-align:left;display:block;width:100%}.wy-form-aligned .wy-controls{margin:1.5em 0 0 0}.wy-form .wy-help-inline,.wy-form-message-inline,.wy-form-message{display:block;font-size:80%;padding:0.2em 0 0.8em}}@media screen and (max-width: 768px){.tablet-hide{display:none}}@media screen and (max-width: 480px){.mobile-hide{display:none}}.float-left{float:left}.float-right{float:right}.full-width{width:100%}.wy-grid-one-col{*zoom:1;max-width:68em;margin-left:auto;margin-right:auto;max-width:1066px;margin-top:1.618em}.wy-grid-one-col:before,.wy-grid-one-col:after{display:table;content:""}.wy-grid-one-col:after{clear:both}.wy-grid-one-col section{display:block;float:left;margin-right:2.35765%;width:100%;background:#fcfcfc;padding:1.618em;margin-right:0}.wy-grid-one-col section:last-child{margin-right:0}.wy-grid-index-card{*zoom:1;max-width:68em;margin-left:auto;margin-right:auto;max-width:460px;margin-top:1.618em;background:#fcfcfc;padding:1.618em}.wy-grid-index-card:before,.wy-grid-index-card:after{display:table;content:""}.wy-grid-index-card:after{clear:both}.wy-grid-index-card header,.wy-grid-index-card section,.wy-grid-index-card aside{display:block;float:left;margin-right:2.35765%;width:100%}.wy-grid-index-card header:last-child,.wy-grid-index-card section:last-child,.wy-grid-index-card aside:last-child{margin-right:0}.wy-grid-index-card.twocol{max-width:768px}.wy-grid-index-card.twocol section{display:block;float:left;margin-right:2.35765%;width:48.82117%}.wy-grid-index-card.twocol section:last-child{margin-right:0}.wy-grid-index-card.twocol aside{display:block;float:left;margin-right:2.35765%;width:48.82117%}.wy-grid-index-card.twocol aside:last-child{margin-right:0}.wy-grid-search-filter{*zoom:1;max-width:68em;margin-left:auto;margin-right:auto;margin-bottom:24px}.wy-grid-search-filter:before,.wy-grid-search-filter:after{display:table;content:""}.wy-grid-search-filter:after{clear:both}.wy-grid-search-filter .wy-grid-search-filter-input{display:block;float:left;margin-right:2.35765%;width:74.41059%}.wy-grid-search-filter .wy-grid-search-filter-input:last-child{margin-right:0}.wy-grid-search-filter .wy-grid-search-filter-btn{display:block;float:left;margin-right:2.35765%;width:23.23176%}.wy-grid-search-filter .wy-grid-search-filter-btn:last-child{margin-right:0}.wy-table,.rst-content table.docutils,.rst-content table.field-list{border-collapse:collapse;border-spacing:0;empty-cells:show;margin-bottom:24px}.wy-table caption,.rst-content table.docutils caption,.rst-content table.field-list caption{color:#000;font:italic 85%/1 arial,sans-serif;padding:1em 0;text-align:center}.wy-table td,.rst-content table.docutils td,.rst-content table.field-list td,.wy-table th,.rst-content table.docutils th,.rst-content table.field-list th{font-size:90%;margin:0;overflow:visible;padding:8px 16px}.wy-table td:first-child,.rst-content table.docutils td:first-child,.rst-content table.field-list td:first-child,.wy-table th:first-child,.rst-content table.docutils th:first-child,.rst-content table.field-list th:first-child{border-left-width:0}.wy-table thead,.rst-content table.docutils thead,.rst-content table.field-list thead{color:#000;text-align:left;vertical-align:bottom;white-space:nowrap}.wy-table thead th,.rst-content table.docutils thead th,.rst-content table.field-list thead th{font-weight:bold;border-bottom:solid 2px #e1e4e5}.wy-table td,.rst-content table.docutils td,.rst-content table.field-list td{background-color:transparent;vertical-align:middle}.wy-table td p,.rst-content table.docutils td p,.rst-content table.field-list td p{line-height:18px;margin-bottom:0}.wy-table .wy-table-cell-min,.rst-content table.docutils .wy-table-cell-min,.rst-content table.field-list .wy-table-cell-min{width:1%;padding-right:0}.wy-table .wy-table-cell-min input[type=checkbox],.rst-content table.docutils .wy-table-cell-min input[type=checkbox],.rst-content table.field-list .wy-table-cell-min input[type=checkbox],.wy-table .wy-table-cell-min input[type=checkbox],.rst-content table.docutils .wy-table-cell-min input[type=checkbox],.rst-content table.field-list .wy-table-cell-min input[type=checkbox]{margin:0}.wy-table-secondary{color:gray;font-size:90%}.wy-table-tertiary{color:gray;font-size:80%}.wy-table-odd td,.wy-table-striped tr:nth-child(2n-1) td,.rst-content table.docutils:not(.field-list) tr:nth-child(2n-1) td{background-color:#f3f6f6}.wy-table-backed{background-color:#f3f6f6}.wy-table-bordered-all,.rst-content table.docutils{border:1px solid #e1e4e5}.wy-table-bordered-all td,.rst-content table.docutils td{border-bottom:1px solid #e1e4e5;border-left:1px solid #e1e4e5}.wy-table-bordered-all tbody>tr:last-child td,.rst-content table.docutils tbody>tr:last-child td{border-bottom-width:0}.wy-table-bordered{border:1px solid #e1e4e5}.wy-table-bordered-rows td{border-bottom:1px solid #e1e4e5}.wy-table-bordered-rows tbody>tr:last-child td{border-bottom-width:0}.wy-table-horizontal tbody>tr:last-child td{border-bottom-width:0}.wy-table-horizontal td,.wy-table-horizontal th{border-width:0 0 1px 0;border-bottom:1px solid #e1e4e5}.wy-table-horizontal tbody>tr:last-child td{border-bottom-width:0}.wy-table-responsive{margin-bottom:24px;max-width:100%;overflow:auto}.wy-table-responsive table{margin-bottom:0 !important}.wy-table-responsive table td,.wy-table-responsive table th{white-space:nowrap}html{height:100%;overflow-x:hidden}body{font-family:"Lato","proxima-nova","Helvetica Neue",Arial,sans-serif;font-weight:normal;color:#404040;min-height:100%;overflow-x:hidden;background:#edf0f2}a{color:#2980b9;text-decoration:none}a:hover{color:#3091d1}.link-danger{color:#e74c3c}.link-danger:hover{color:#d62c1a}.text-left{text-align:left}.text-center{text-align:center}.text-right{text-align:right}h1,h2,h3,h4,h5,h6,legend{margin-top:0;font-weight:700;font-family:"Roboto Slab","ff-tisa-web-pro","Georgia",Arial,sans-serif}p{line-height:24px;margin:0;font-size:16px;margin-bottom:24px}h1{font-size:175%}h2{font-size:150%}h3{font-size:125%}h4{font-size:115%}h5{font-size:110%}h6{font-size:100%}small{font-size:80%}code,.rst-content tt{white-space:nowrap;max-width:100%;background:#fff;border:solid 1px #e1e4e5;font-size:75%;padding:0 5px;font-family:"Incosolata","Consolata","Monaco",monospace;color:#e74c3c;overflow-x:auto}code.code-large,.rst-content tt.code-large{font-size:90%}.full-width{width:100%}.wy-plain-list-disc,.rst-content .section ul,.rst-content .toctree-wrapper ul{list-style:disc;line-height:24px;margin-bottom:24px}.wy-plain-list-disc li,.rst-content .section ul li,.rst-content .toctree-wrapper ul li{list-style:disc;margin-left:24px}.wy-plain-list-disc li ul,.rst-content .section ul li ul,.rst-content .toctree-wrapper ul li ul{margin-bottom:0}.wy-plain-list-disc li li,.rst-content .section ul li li,.rst-content .toctree-wrapper ul li li{list-style:circle}.wy-plain-list-disc li li li,.rst-content .section ul li li li,.rst-content .toctree-wrapper ul li li li{list-style:square}.wy-plain-list-decimal,.rst-content .section ol,.rst-content ol.arabic{list-style:decimal;line-height:24px;margin-bottom:24px}.wy-plain-list-decimal li,.rst-content .section ol li,.rst-content ol.arabic li{list-style:decimal;margin-left:24px}.wy-type-large{font-size:120%}.wy-type-normal{font-size:100%}.wy-type-small{font-size:100%}.wy-type-strike{text-decoration:line-through}.wy-text-warning{color:#e67e22 !important}a.wy-text-warning:hover{color:#eb9950 !important}.wy-text-info{color:#2980b9 !important}a.wy-text-info:hover{color:#409ad5 !important}.wy-text-success{color:#27ae60 !important}a.wy-text-success:hover{color:#36d278 !important}.wy-text-danger{color:#e74c3c !important}a.wy-text-danger:hover{color:#ed7669 !important}.wy-text-neutral{color:#404040 !important}a.wy-text-neutral:hover{color:#595959 !important}.codeblock-example{border:1px solid #e1e4e5;border-bottom:none;padding:24px;padding-top:48px;font-weight:500;background:#fff;position:relative}.codeblock-example:after{content:"Example";position:absolute;top:0px;left:0px;background:#9b59b6;color:#fff;padding:6px 12px}.codeblock-example.prettyprint-example-only{border:1px solid #e1e4e5;margin-bottom:24px}.codeblock,.rst-content .literal-block,div[class^='highlight']{border:1px solid #e1e4e5;padding:0px;overflow-x:auto;background:#fff;margin:1px 0 24px 0}.codeblock div[class^='highlight'],.rst-content .literal-block div[class^='highlight'],div[class^='highlight'] div[class^='highlight']{border:none;background:none;margin:0}div[class^='highlight'] td.code{width:100%}.linenodiv pre{border-right:solid 1px #e6e9ea;margin:0;padding:12px 12px;font-family:"Incosolata","Consolata","Monaco",monospace;font-size:12px;line-height:1.5;color:#d9d9d9}div[class^='highlight'] pre{white-space:pre;margin:0;padding:12px 12px;font-family:"Incosolata","Consolata","Monaco",monospace;font-size:12px;line-height:1.5;display:block;overflow:auto;color:#404040}pre.literal-block{@extends .codeblock;}@media print{.codeblock,.rst-content .literal-block,div[class^='highlight'],div[class^='highlight'] pre{white-space:pre-wrap}}.hll{background-color:#ffc;margin:0 -12px;padding:0 12px;display:block}.c{color:#998;font-style:italic}.err{color:#a61717;background-color:#e3d2d2}.k{font-weight:bold}.o{font-weight:bold}.cm{color:#998;font-style:italic}.cp{color:#999;font-weight:bold}.c1{color:#998;font-style:italic}.cs{color:#999;font-weight:bold;font-style:italic}.gd{color:#000;background-color:#fdd}.gd .x{color:#000;background-color:#faa}.ge{font-style:italic}.gr{color:#a00}.gh{color:#999}.gi{color:#000;background-color:#dfd}.gi .x{color:#000;background-color:#afa}.go{color:#888}.gp{color:#555}.gs{font-weight:bold}.gu{color:purple;font-weight:bold}.gt{color:#a00}.kc{font-weight:bold}.kd{font-weight:bold}.kn{font-weight:bold}.kp{font-weight:bold}.kr{font-weight:bold}.kt{color:#458;font-weight:bold}.m{color:#099}.s{color:#d14}.n{color:#333}.na{color:teal}.nb{color:#0086b3}.nc{color:#458;font-weight:bold}.no{color:teal}.ni{color:purple}.ne{color:#900;font-weight:bold}.nf{color:#900;font-weight:bold}.nn{color:#555}.nt{color:navy}.nv{color:teal}.ow{font-weight:bold}.w{color:#bbb}.mf{color:#099}.mh{color:#099}.mi{color:#099}.mo{color:#099}.sb{color:#d14}.sc{color:#d14}.sd{color:#d14}.s2{color:#d14}.se{color:#d14}.sh{color:#d14}.si{color:#d14}.sx{color:#d14}.sr{color:#009926}.s1{color:#d14}.ss{color:#990073}.bp{color:#999}.vc{color:teal}.vg{color:teal}.vi{color:teal}.il{color:#099}.gc{color:#999;background-color:#eaf2f5}.wy-breadcrumbs li{display:inline-block}.wy-breadcrumbs li.wy-breadcrumbs-aside{float:right}.wy-breadcrumbs li a{display:inline-block;padding:5px}.wy-breadcrumbs li a:first-child{padding-left:0}.wy-breadcrumbs-extra{margin-bottom:0;color:#b3b3b3;font-size:80%;display:inline-block}@media screen and (max-width: 480px){.wy-breadcrumbs-extra{display:none}.wy-breadcrumbs li.wy-breadcrumbs-aside{display:none}}@media print{.wy-breadcrumbs li.wy-breadcrumbs-aside{display:none}}.wy-affix{position:fixed;top:1.618em}.wy-menu a:hover{text-decoration:none}.wy-menu-horiz{*zoom:1}.wy-menu-horiz:before,.wy-menu-horiz:after{display:table;content:""}.wy-menu-horiz:after{clear:both}.wy-menu-horiz ul,.wy-menu-horiz li{display:inline-block}.wy-menu-horiz li:hover{background:rgba(255,255,255,0.1)}.wy-menu-horiz li.divide-left{border-left:solid 1px #404040}.wy-menu-horiz li.divide-right{border-right:solid 1px #404040}.wy-menu-horiz a{height:32px;display:inline-block;line-height:32px;padding:0 16px}.wy-menu-vertical header{height:32px;display:inline-block;line-height:32px;padding:0 1.618em;display:block;font-weight:bold;text-transform:uppercase;font-size:80%;color:#2980b9;white-space:nowrap}.wy-menu-vertical ul{margin-bottom:0}.wy-menu-vertical li.divide-top{border-top:solid 1px #404040}.wy-menu-vertical li.divide-bottom{border-bottom:solid 1px #404040}.wy-menu-vertical li.current{background:#e3e3e3}.wy-menu-vertical li.current a{color:gray;border-right:solid 1px #c9c9c9;padding:0.4045em 2.427em}.wy-menu-vertical li.current a:hover{background:#d6d6d6}.wy-menu-vertical li.on a,.wy-menu-vertical li.current>a{color:#404040;padding:0.4045em 1.618em;font-weight:bold;position:relative;background:#fcfcfc;border:none;border-bottom:solid 1px #c9c9c9;border-top:solid 1px #c9c9c9;padding-left:1.618em -4px}.wy-menu-vertical li.on a:hover,.wy-menu-vertical li.current>a:hover{background:#fcfcfc}.wy-menu-vertical li.toctree-l2.current>a{background:#c9c9c9;padding:0.4045em 2.427em}.wy-menu-vertical li.current ul{display:block}.wy-menu-vertical li ul{margin-bottom:0;display:none}.wy-menu-vertical .local-toc li ul{display:block}.wy-menu-vertical li ul li a{margin-bottom:0;color:#b3b3b3;font-weight:normal}.wy-menu-vertical a{display:inline-block;line-height:18px;padding:0.4045em 1.618em;display:block;position:relative;font-size:90%;color:#b3b3b3}.wy-menu-vertical a:hover{background-color:#4e4a4a;cursor:pointer}.wy-menu-vertical a:active{background-color:#2980b9;cursor:pointer;color:#fff}.wy-side-nav-search{z-index:200;background-color:#2980b9;text-align:center;padding:0.809em;display:block;color:#fcfcfc;margin-bottom:0.809em}.wy-side-nav-search input[type=text]{width:100%;border-radius:50px;padding:6px 12px;border-color:#2472a4}.wy-side-nav-search img{display:block;margin:auto auto 0.809em auto;height:45px;width:45px;background-color:#2980b9;padding:5px;border-radius:100%}.wy-side-nav-search>a,.wy-side-nav-search .wy-dropdown>a{color:#fcfcfc;font-size:100%;font-weight:bold;display:inline-block;padding:4px 6px;margin-bottom:0.809em}.wy-side-nav-search>a:hover,.wy-side-nav-search .wy-dropdown>a:hover{background:rgba(255,255,255,0.1)}.wy-nav .wy-menu-vertical header{color:#2980b9}.wy-nav .wy-menu-vertical a{color:#b3b3b3}.wy-nav .wy-menu-vertical a:hover{background-color:#2980b9;color:#fff}[data-menu-wrap]{-webkit-transition:all 0.2s ease-in;-moz-transition:all 0.2s ease-in;transition:all 0.2s ease-in;position:absolute;opacity:1;width:100%;opacity:0}[data-menu-wrap].move-center{left:0;right:auto;opacity:1}[data-menu-wrap].move-left{right:auto;left:-100%;opacity:0}[data-menu-wrap].move-right{right:-100%;left:auto;opacity:0}.wy-body-for-nav{background:left repeat-y #fcfcfc;background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAIAAACQd1PeAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyRpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMy1jMDExIDY2LjE0NTY2MSwgMjAxMi8wMi8wNi0xNDo1NjoyNyAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNiAoTWFjaW50b3NoKSIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDoxOERBMTRGRDBFMUUxMUUzODUwMkJCOThDMEVFNURFMCIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDoxOERBMTRGRTBFMUUxMUUzODUwMkJCOThDMEVFNURFMCI+IDx4bXBNTTpEZXJpdmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSJ4bXAuaWlkOjE4REExNEZCMEUxRTExRTM4NTAyQkI5OEMwRUU1REUwIiBzdFJlZjpkb2N1bWVudElEPSJ4bXAuZGlkOjE4REExNEZDMEUxRTExRTM4NTAyQkI5OEMwRUU1REUwIi8+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+EwrlwAAAAA5JREFUeNpiMDU0BAgwAAE2AJgB9BnaAAAAAElFTkSuQmCC);background-size:300px 1px}.wy-grid-for-nav{position:absolute;width:100%;height:100%}.wy-nav-side{position:absolute;top:0;left:0;width:300px;overflow:hidden;min-height:100%;background:#343131;z-index:200}.wy-nav-top{display:none;background:#2980b9;color:#fff;padding:0.4045em 0.809em;position:relative;line-height:50px;text-align:center;font-size:100%;*zoom:1}.wy-nav-top:before,.wy-nav-top:after{display:table;content:""}.wy-nav-top:after{clear:both}.wy-nav-top a{color:#fff;font-weight:bold}.wy-nav-top img{margin-right:12px;height:45px;width:45px;background-color:#2980b9;padding:5px;border-radius:100%}.wy-nav-top i{font-size:30px;float:left;cursor:pointer}.wy-nav-content-wrap{margin-left:300px;background:#fcfcfc;min-height:100%}.wy-nav-content{padding:1.618em 3.236em;height:100%;max-width:800px;margin:auto}.wy-body-mask{position:fixed;width:100%;height:100%;background:rgba(0,0,0,0.2);display:none;z-index:499}.wy-body-mask.on{display:block}footer{color:#999}footer p{margin-bottom:12px}.rst-footer-buttons{*zoom:1}.rst-footer-buttons:before,.rst-footer-buttons:after{display:table;content:""}.rst-footer-buttons:after{clear:both}#search-results .search li{margin-bottom:24px;border-bottom:solid 1px #e1e4e5;padding-bottom:24px}#search-results .search li:first-child{border-top:solid 1px #e1e4e5;padding-top:24px}#search-results .search li a{font-size:120%;margin-bottom:12px;display:inline-block}#search-results .context{color:gray;font-size:90%}@media screen and (max-width: 768px){.wy-body-for-nav{background:#fcfcfc}.wy-nav-top{display:block}.wy-nav-side{left:-300px}.wy-nav-side.shift{width:85%;left:0}.wy-nav-content-wrap{margin-left:0}.wy-nav-content-wrap .wy-nav-content{padding:1.618em}.wy-nav-content-wrap.shift{position:fixed;min-width:100%;left:85%;top:0;height:100%;overflow:hidden}}@media screen and (min-width: 1400px){.wy-nav-content-wrap{background:rgba(0,0,0,0.05)}.wy-nav-content{margin:0;background:#fcfcfc}}@media print{.wy-nav-side{display:none}.wy-nav-content-wrap{margin-left:0}}nav.stickynav{position:fixed;top:0}.rst-versions{position:fixed;bottom:0;left:0;width:300px;color:#fcfcfc;background:#1f1d1d;border-top:solid 10px #343131;font-family:"Lato","proxima-nova","Helvetica Neue",Arial,sans-serif;z-index:400}.rst-versions a{color:#2980b9;text-decoration:none}.rst-versions .rst-badge-small{display:none}.rst-versions .rst-current-version{padding:12px;background-color:#272525;display:block;text-align:right;font-size:90%;cursor:pointer;color:#27ae60;*zoom:1}.rst-versions .rst-current-version:before,.rst-versions .rst-current-version:after{display:table;content:""}.rst-versions .rst-current-version:after{clear:both}.rst-versions .rst-current-version .icon,.rst-versions .rst-current-version .wy-inline-validate.wy-inline-validate-success .wy-input-context,.wy-inline-validate.wy-inline-validate-success .rst-versions .rst-current-version .wy-input-context,.rst-versions .rst-current-version .wy-inline-validate.wy-inline-validate-danger .wy-input-context,.wy-inline-validate.wy-inline-validate-danger .rst-versions .rst-current-version .wy-input-context,.rst-versions .rst-current-version .wy-inline-validate.wy-inline-validate-warning .wy-input-context,.wy-inline-validate.wy-inline-validate-warning .rst-versions .rst-current-version .wy-input-context,.rst-versions .rst-current-version .wy-inline-validate.wy-inline-validate-info .wy-input-context,.wy-inline-validate.wy-inline-validate-info .rst-versions .rst-current-version .wy-input-context,.rst-versions .rst-current-version .wy-tag-input-group .wy-tag .wy-tag-remove,.wy-tag-input-group .wy-tag .rst-versions .rst-current-version .wy-tag-remove,.rst-versions .rst-current-version .rst-content .admonition-title,.rst-content .rst-versions .rst-current-version .admonition-title,.rst-versions .rst-current-version .rst-content h1 .headerlink,.rst-content h1 .rst-versions .rst-current-version .headerlink,.rst-versions .rst-current-version .rst-content h2 .headerlink,.rst-content h2 .rst-versions .rst-current-version .headerlink,.rst-versions .rst-current-version .rst-content h3 .headerlink,.rst-content h3 .rst-versions .rst-current-version .headerlink,.rst-versions .rst-current-version .rst-content h4 .headerlink,.rst-content h4 .rst-versions .rst-current-version .headerlink,.rst-versions .rst-current-version .rst-content h5 .headerlink,.rst-content h5 .rst-versions .rst-current-version .headerlink,.rst-versions .rst-current-version .rst-content h6 .headerlink,.rst-content h6 .rst-versions .rst-current-version .headerlink,.rst-versions .rst-current-version .rst-content dl dt .headerlink,.rst-content dl dt .rst-versions .rst-current-version .headerlink{color:#fcfcfc}.rst-versions .rst-current-version .icon-book{float:left}.rst-versions .rst-current-version.rst-out-of-date{background-color:#e74c3c;color:#fff}.rst-versions .rst-current-version.rst-active-old-version{background-color:#f1c40f;color:#000}.rst-versions.shift-up .rst-other-versions{display:block}.rst-versions .rst-other-versions{font-size:90%;padding:12px;color:gray;display:none}.rst-versions .rst-other-versions hr{display:block;height:1px;border:0;margin:20px 0;padding:0;border-top:solid 1px #413d3d}.rst-versions .rst-other-versions dd{display:inline-block;margin:0}.rst-versions .rst-other-versions dd a{display:inline-block;padding:6px;color:#fcfcfc}.rst-versions.rst-badge{width:auto;bottom:20px;right:20px;left:auto;border:none;max-width:300px}.rst-versions.rst-badge .icon-book{float:none}.rst-versions.rst-badge.shift-up .rst-current-version{text-align:right}.rst-versions.rst-badge.shift-up .rst-current-version .icon-book{float:left}.rst-versions.rst-badge .rst-current-version{width:auto;height:30px;line-height:30px;padding:0 6px;display:block;text-align:center}@media screen and (max-width: 768px){.rst-versions{width:85%;display:none}.rst-versions.shift{display:block}img{width:100%;height:auto}}.rst-content img{max-width:100%;height:auto !important}.rst-content .section>img{margin-bottom:24px}.rst-content blockquote{margin-left:24px;line-height:24px;margin-bottom:24px}.rst-content .note .last,.rst-content .attention .last,.rst-content .caution .last,.rst-content .danger .last,.rst-content .error .last,.rst-content .hint .last,.rst-content .important .last,.rst-content .tip .last,.rst-content .warning .last,.rst-content .seealso .last{margin-bottom:0}.rst-content .admonition-title:before{margin-right:4px}.rst-content .admonition table{border-color:rgba(0,0,0,0.1)}.rst-content .admonition table td,.rst-content .admonition table th{background:transparent !important;border-color:rgba(0,0,0,0.1) !important}.rst-content .section ol.loweralpha,.rst-content .section ol.loweralpha li{list-style:lower-alpha}.rst-content .section ol.upperalpha,.rst-content .section ol.upperalpha li{list-style:upper-alpha}.rst-content .section ol p,.rst-content .section ul p{margin-bottom:12px}.rst-content .line-block{margin-left:24px}.rst-content .topic-title{font-weight:bold;margin-bottom:12px}.rst-content .toc-backref{color:#404040}.rst-content .align-right{float:right;margin:0px 0px 24px 24px}.rst-content .align-left{float:left;margin:0px 24px 24px 0px}.rst-content .align-center{margin:auto;display:block}.rst-content h1 .headerlink,.rst-content h2 .headerlink,.rst-content h3 .headerlink,.rst-content h4 .headerlink,.rst-content h5 .headerlink,.rst-content h6 .headerlink,.rst-content dl dt .headerlink{display:none;visibility:hidden;font-size:14px}.rst-content h1 .headerlink:after,.rst-content h2 .headerlink:after,.rst-content h3 .headerlink:after,.rst-content h4 .headerlink:after,.rst-content h5 .headerlink:after,.rst-content h6 .headerlink:after,.rst-content dl dt .headerlink:after{visibility:visible;content:"\f0c1";font-family:fontawesome-webfont;display:inline-block}.rst-content h1:hover .headerlink,.rst-content h2:hover .headerlink,.rst-content h3:hover .headerlink,.rst-content h4:hover .headerlink,.rst-content h5:hover .headerlink,.rst-content h6:hover .headerlink,.rst-content dl dt:hover .headerlink{display:inline-block}.rst-content .sidebar{float:right;width:40%;display:block;margin:0 0 24px 24px;padding:24px;background:#f3f6f6;border:solid 1px #e1e4e5}.rst-content .sidebar p,.rst-content .sidebar ul,.rst-content .sidebar dl{font-size:90%}.rst-content .sidebar .last{margin-bottom:0}.rst-content .sidebar .sidebar-title{display:block;font-family:"Roboto Slab","ff-tisa-web-pro","Georgia",Arial,sans-serif;font-weight:bold;background:#e1e4e5;padding:6px 12px;margin:-24px;margin-bottom:24px;font-size:100%}.rst-content .highlighted{background:#f1c40f;display:inline-block;font-weight:bold;padding:0 6px}.rst-content .footnote-reference,.rst-content .citation-reference{vertical-align:super;font-size:90%}.rst-content table.docutils.citation,.rst-content table.docutils.footnote{background:none;border:none;color:#999}.rst-content table.docutils.citation td,.rst-content table.docutils.citation tr,.rst-content table.docutils.footnote td,.rst-content table.docutils.footnote tr{border:none;background-color:transparent !important;white-space:normal}.rst-content table.docutils.citation td.label,.rst-content table.docutils.footnote td.label{padding-left:0;padding-right:0;vertical-align:top}.rst-content table.field-list{border:none}.rst-content table.field-list td{border:none;padding-top:5px}.rst-content table.field-list .field-name{padding-right:10px;text-align:left;white-space:nowrap}.rst-content table.field-list .field-body{text-align:left;padding-left:0}.rst-content tt{color:#000}.rst-content tt big,.rst-content tt em{font-size:100% !important;line-height:normal}.rst-content tt .xref,a .rst-content tt{font-weight:bold}.rst-content dl{margin-bottom:24px}.rst-content dl dt{font-weight:bold}.rst-content dl p,.rst-content dl table,.rst-content dl ul,.rst-content dl ol{margin-bottom:12px !important}.rst-content dl dd{margin:0 0 12px 24px}.rst-content dl:not(.docutils){margin-bottom:24px}.rst-content dl:not(.docutils) dt{display:inline-block;margin:6px 0;font-size:90%;line-height:normal;background:#e7f2fa;color:#2980b9;border-top:solid 3px #6ab0de;padding:6px;position:relative}.rst-content dl:not(.docutils) dt:before{color:#6ab0de}.rst-content dl:not(.docutils) dt .headerlink{color:#404040;font-size:100% !important}.rst-content dl:not(.docutils) dl dt{margin-bottom:6px;border:none;border-left:solid 3px #ccc;background:#f0f0f0;color:gray}.rst-content dl:not(.docutils) dl dt .headerlink{color:#404040;font-size:100% !important}.rst-content dl:not(.docutils) dt:first-child{margin-top:0}.rst-content dl:not(.docutils) tt{font-weight:bold}.rst-content dl:not(.docutils) tt.descname,.rst-content dl:not(.docutils) tt.descclassname{background-color:transparent;border:none;padding:0;font-size:100% !important}.rst-content dl:not(.docutils) tt.descname{font-weight:bold}.rst-content dl:not(.docutils) .optional{display:inline-block;padding:0 4px;color:#000;font-weight:bold}.rst-content dl:not(.docutils) .property{display:inline-block;padding-right:8px}.rst-content .viewcode-link,.rst-content .viewcode-back{display:inline-block;color:#27ae60;font-size:80%;padding-left:24px}.rst-content .viewcode-back{display:block;float:right}@media screen and (max-width: 480px){.rst-content .sidebar{width:100%}}span[id*='MathJax-Span']{color:#404040}
diff --git a/manual/_theme/sphinx_rtd_theme/static/font/fontawesome_webfont.eot b/manual/_theme/sphinx_rtd_theme/static/font/fontawesome_webfont.eot
deleted file mode 100644
index 0662cb96..00000000
Binary files a/manual/_theme/sphinx_rtd_theme/static/font/fontawesome_webfont.eot and /dev/null differ
diff --git a/manual/_theme/sphinx_rtd_theme/static/font/fontawesome_webfont.svg b/manual/_theme/sphinx_rtd_theme/static/font/fontawesome_webfont.svg
deleted file mode 100644
index 2edb4ec3..00000000
--- a/manual/_theme/sphinx_rtd_theme/static/font/fontawesome_webfont.svg
+++ /dev/null
@@ -1,399 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/manual/_theme/sphinx_rtd_theme/static/font/fontawesome_webfont.ttf b/manual/_theme/sphinx_rtd_theme/static/font/fontawesome_webfont.ttf
deleted file mode 100644
index d3659246..00000000
Binary files a/manual/_theme/sphinx_rtd_theme/static/font/fontawesome_webfont.ttf and /dev/null differ
diff --git a/manual/_theme/sphinx_rtd_theme/static/font/fontawesome_webfont.woff b/manual/_theme/sphinx_rtd_theme/static/font/fontawesome_webfont.woff
deleted file mode 100644
index b9bd17e1..00000000
Binary files a/manual/_theme/sphinx_rtd_theme/static/font/fontawesome_webfont.woff and /dev/null differ
diff --git a/manual/_theme/sphinx_rtd_theme/static/js/theme.js b/manual/_theme/sphinx_rtd_theme/static/js/theme.js
deleted file mode 100644
index 60520cc3..00000000
--- a/manual/_theme/sphinx_rtd_theme/static/js/theme.js
+++ /dev/null
@@ -1,47 +0,0 @@
-$( document ).ready(function() {
- // Shift nav in mobile when clicking the menu.
- $(document).on('click', "[data-toggle='wy-nav-top']", function() {
- $("[data-toggle='wy-nav-shift']").toggleClass("shift");
- $("[data-toggle='rst-versions']").toggleClass("shift");
- });
- // Close menu when you click a link.
- $(document).on('click', ".wy-menu-vertical .current ul li a", function() {
- $("[data-toggle='wy-nav-shift']").removeClass("shift");
- $("[data-toggle='rst-versions']").toggleClass("shift");
- });
- $(document).on('click', "[data-toggle='rst-current-version']", function() {
- $("[data-toggle='rst-versions']").toggleClass("shift-up");
- });
- // Make tables responsive
- $("table.docutils:not(.field-list)").wrap("
");
-});
-
-window.SphinxRtdTheme = (function (jquery) {
- var stickyNav = (function () {
- var navBar,
- win,
- stickyNavCssClass = 'stickynav',
- applyStickNav = function () {
- if (navBar.height() <= win.height()) {
- navBar.addClass(stickyNavCssClass);
- } else {
- navBar.removeClass(stickyNavCssClass);
- }
- },
- enable = function () {
- applyStickNav();
- win.on('resize', applyStickNav);
- },
- init = function () {
- navBar = jquery('nav.wy-nav-side:first');
- win = jquery(window);
- };
- jquery(init);
- return {
- enable : enable
- };
- }());
- return {
- StickyNav : stickyNav
- };
-}($));
diff --git a/manual/_theme/sphinx_rtd_theme/theme.conf b/manual/_theme/sphinx_rtd_theme/theme.conf
deleted file mode 100644
index dcfbf8c2..00000000
--- a/manual/_theme/sphinx_rtd_theme/theme.conf
+++ /dev/null
@@ -1,8 +0,0 @@
-[theme]
-inherit = basic
-stylesheet = css/theme.css
-
-[options]
-typekit_id = hiw1hhg
-analytics_id =
-sticky_navigation = False
diff --git a/manual/_theme/sphinx_rtd_theme/versions.html b/manual/_theme/sphinx_rtd_theme/versions.html
deleted file mode 100644
index c131c9fc..00000000
--- a/manual/_theme/sphinx_rtd_theme/versions.html
+++ /dev/null
@@ -1,37 +0,0 @@
-{% if READTHEDOCS %}
-{# Add rst-badge after rst-versions for small badge style. #}
-
-
- Read the Docs
- v: {{ current_version }}
-
-
-
-
- Versions
- {% for slug, url in versions %}
- {{ slug }}
- {% endfor %}
-
-
- Downloads
- {% for type, url in downloads %}
- {{ type }}
- {% endfor %}
-
-
- On Read the Docs
-
- Project Home
-
-
- Builds
-
-
-
- Free document hosting provided by
Read the Docs .
-
-
-
-{% endif %}
-
diff --git a/manual/_theme/static/css/badge_only.css b/manual/_theme/static/css/badge_only.css
deleted file mode 100644
index e67013ae..00000000
--- a/manual/_theme/static/css/badge_only.css
+++ /dev/null
@@ -1 +0,0 @@
-.font-smooth,.icon:before{-webkit-font-smoothing:antialiased}.clearfix{*zoom:1}.clearfix:before,.clearfix:after{display:table;content:""}.clearfix:after{clear:both}@font-face{font-family:fontawesome-webfont;font-weight:normal;font-style:normal;src:url("../font/fontawesome_webfont.eot");src:url("../font/fontawesome_webfont.eot?#iefix") format("embedded-opentype"),url("../font/fontawesome_webfont.woff") format("woff"),url("../font/fontawesome_webfont.ttf") format("truetype"),url("../font/fontawesome_webfont.svg#fontawesome-webfont") format("svg")}.icon:before{display:inline-block;font-family:fontawesome-webfont;font-style:normal;font-weight:normal;line-height:1;text-decoration:inherit}a .icon{display:inline-block;text-decoration:inherit}li .icon{display:inline-block}li .icon-large:before,li .icon-large:before{width:1.875em}ul.icons{list-style-type:none;margin-left:2em;text-indent:-0.8em}ul.icons li .icon{width:0.8em}ul.icons li .icon-large:before,ul.icons li .icon-large:before{vertical-align:baseline}.icon-book:before{content:"\f02d"}.icon-caret-down:before{content:"\f0d7"}.icon-caret-up:before{content:"\f0d8"}.icon-caret-left:before{content:"\f0d9"}.icon-caret-right:before{content:"\f0da"}.rst-versions{position:fixed;bottom:0;left:0;width:300px;color:#fcfcfc;background:#1f1d1d;border-top:solid 10px #343131;font-family:"Lato","proxima-nova","Helvetica Neue",Arial,sans-serif;z-index:400}.rst-versions a{color:#2980b9;text-decoration:none}.rst-versions .rst-badge-small{display:none}.rst-versions .rst-current-version{padding:12px;background-color:#272525;display:block;text-align:right;font-size:90%;cursor:pointer;color:#27ae60;*zoom:1}.rst-versions .rst-current-version:before,.rst-versions .rst-current-version:after{display:table;content:""}.rst-versions .rst-current-version:after{clear:both}.rst-versions .rst-current-version .icon{color:#fcfcfc}.rst-versions .rst-current-version .icon-book{float:left}.rst-versions .rst-current-version.rst-out-of-date{background-color:#e74c3c;color:#fff}.rst-versions .rst-current-version.rst-active-old-version{background-color:#f1c40f;color:#000}.rst-versions.shift-up .rst-other-versions{display:block}.rst-versions .rst-other-versions{font-size:90%;padding:12px;color:gray;display:none}.rst-versions .rst-other-versions hr{display:block;height:1px;border:0;margin:20px 0;padding:0;border-top:solid 1px #413d3d}.rst-versions .rst-other-versions dd{display:inline-block;margin:0}.rst-versions .rst-other-versions dd a{display:inline-block;padding:6px;color:#fcfcfc}.rst-versions.rst-badge{width:auto;bottom:20px;right:20px;left:auto;border:none;max-width:300px}.rst-versions.rst-badge .icon-book{float:none}.rst-versions.rst-badge.shift-up .rst-current-version{text-align:right}.rst-versions.rst-badge.shift-up .rst-current-version .icon-book{float:left}.rst-versions.rst-badge .rst-current-version{width:auto;height:30px;line-height:30px;padding:0 6px;display:block;text-align:center}@media screen and (max-width: 768px){.rst-versions{width:85%;display:none}.rst-versions.shift{display:block}img{width:100%;height:auto}}
diff --git a/manual/_theme/static/css/theme.css b/manual/_theme/static/css/theme.css
deleted file mode 100644
index 481346bf..00000000
--- a/manual/_theme/static/css/theme.css
+++ /dev/null
@@ -1 +0,0 @@
-*{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}article,aside,details,figcaption,figure,footer,header,hgroup,nav,section{display:block}audio,canvas,video{display:inline-block;*display:inline;*zoom:1}audio:not([controls]){display:none}[hidden]{display:none}*{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}html{font-size:100%;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%}body{margin:0}a:hover,a:active{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:bold}blockquote{margin:0}dfn{font-style:italic}hr{display:block;height:1px;border:0;border-top:1px solid #ccc;margin:20px 0;padding:0}ins{background:#ff9;color:#000;text-decoration:none}mark{background:#ff0;color:#000;font-style:italic;font-weight:bold}pre,code,.rst-content tt,kbd,samp{font-family:monospace,serif;_font-family:"courier new",monospace;font-size:1em}pre{white-space:pre}q{quotes:none}q:before,q:after{content:"";content:none}small{font-size:85%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-0.5em}sub{bottom:-0.25em}ul,ol,dl{margin:0;padding:0;list-style:none;list-style-image:none}li{list-style:none}dd{margin:0}img{border:0;-ms-interpolation-mode:bicubic;vertical-align:middle;max-width:100%}svg:not(:root){overflow:hidden}figure{margin:0}form{margin:0}fieldset{border:0;margin:0;padding:0}label{cursor:pointer}legend{border:0;*margin-left:-7px;padding:0;white-space:normal}button,input,select,textarea{font-size:100%;margin:0;vertical-align:baseline;*vertical-align:middle}button,input{line-height:normal}button,input[type="button"],input[type="reset"],input[type="submit"]{cursor:pointer;-webkit-appearance:button;*overflow:visible}button[disabled],input[disabled]{cursor:default}input[type="checkbox"],input[type="radio"]{box-sizing:border-box;padding:0;*width:13px;*height:13px}input[type="search"]{-webkit-appearance:textfield;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;box-sizing:content-box}input[type="search"]::-webkit-search-decoration,input[type="search"]::-webkit-search-cancel-button{-webkit-appearance:none}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}textarea{overflow:auto;vertical-align:top;resize:vertical}table{border-collapse:collapse;border-spacing:0}td{vertical-align:top}.chromeframe{margin:0.2em 0;background:#ccc;color:#000;padding:0.2em 0}.ir{display:block;border:0;text-indent:-999em;overflow:hidden;background-color:transparent;background-repeat:no-repeat;text-align:left;direction:ltr;*line-height:0}.ir br{display:none}.hidden{display:none !important;visibility:hidden}.visuallyhidden{border:0;clip:rect(0 0 0 0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.visuallyhidden.focusable:active,.visuallyhidden.focusable:focus{clip:auto;height:auto;margin:0;overflow:visible;position:static;width:auto}.invisible{visibility:hidden}.relative{position:relative}big,small{font-size:100%}@media print{html,body,section{background:none !important}*{box-shadow:none !important;text-shadow:none !important;filter:none !important;-ms-filter:none !important}a,a:visited{text-decoration:underline}.ir a:after,a[href^="javascript:"]:after,a[href^="#"]:after{content:""}pre,blockquote{page-break-inside:avoid}thead{display:table-header-group}tr,img{page-break-inside:avoid}img{max-width:100% !important}@page{margin:0.5cm}p,h2,h3{orphans:3;widows:3}h2,h3{page-break-after:avoid}}.font-smooth,.icon:before,.wy-inline-validate.wy-inline-validate-success .wy-input-context:before,.wy-inline-validate.wy-inline-validate-danger .wy-input-context:before,.wy-inline-validate.wy-inline-validate-warning .wy-input-context:before,.wy-inline-validate.wy-inline-validate-info .wy-input-context:before,.wy-tag-input-group .wy-tag .wy-tag-remove:before,.rst-content .admonition-title:before,.rst-content h1 .headerlink:before,.rst-content h2 .headerlink:before,.rst-content h3 .headerlink:before,.rst-content h4 .headerlink:before,.rst-content h5 .headerlink:before,.rst-content h6 .headerlink:before,.rst-content dl dt .headerlink:before,.wy-alert,.rst-content .note,.rst-content .attention,.rst-content .caution,.rst-content .danger,.rst-content .error,.rst-content .hint,.rst-content .important,.rst-content .tip,.rst-content .warning,.rst-content .seealso,.btn,input[type="text"],input[type="password"],input[type="email"],input[type="url"],input[type="date"],input[type="month"],input[type="time"],input[type="datetime"],input[type="datetime-local"],input[type="week"],input[type="number"],input[type="search"],input[type="tel"],input[type="color"],select,textarea,.wy-tag-input-group,.wy-menu-vertical li.on a,.wy-menu-vertical li.current>a,.wy-side-nav-search>a,.wy-side-nav-search .wy-dropdown>a,.wy-nav-top a{-webkit-font-smoothing:antialiased}.clearfix{*zoom:1}.clearfix:before,.clearfix:after{display:table;content:""}.clearfix:after{clear:both}@font-face{font-family:fontawesome-webfont;font-weight:normal;font-style:normal;src:url("../font/fontawesome_webfont.eot");src:url("../font/fontawesome_webfont.eot?#iefix") format("embedded-opentype"),url("../font/fontawesome_webfont.woff") format("woff"),url("../font/fontawesome_webfont.ttf") format("truetype"),url("../font/fontawesome_webfont.svg#fontawesome-webfont") format("svg")}.icon:before,.wy-inline-validate.wy-inline-validate-success .wy-input-context:before,.wy-inline-validate.wy-inline-validate-danger .wy-input-context:before,.wy-inline-validate.wy-inline-validate-warning .wy-input-context:before,.wy-inline-validate.wy-inline-validate-info .wy-input-context:before,.wy-tag-input-group .wy-tag .wy-tag-remove:before,.rst-content .admonition-title:before,.rst-content h1 .headerlink:before,.rst-content h2 .headerlink:before,.rst-content h3 .headerlink:before,.rst-content h4 .headerlink:before,.rst-content h5 .headerlink:before,.rst-content h6 .headerlink:before,.rst-content dl dt .headerlink:before{display:inline-block;font-family:fontawesome-webfont;font-style:normal;font-weight:normal;line-height:1;text-decoration:inherit}a .icon,a .wy-inline-validate.wy-inline-validate-success .wy-input-context,.wy-inline-validate.wy-inline-validate-success a .wy-input-context,a .wy-inline-validate.wy-inline-validate-danger .wy-input-context,.wy-inline-validate.wy-inline-validate-danger a .wy-input-context,a .wy-inline-validate.wy-inline-validate-warning .wy-input-context,.wy-inline-validate.wy-inline-validate-warning a .wy-input-context,a .wy-inline-validate.wy-inline-validate-info .wy-input-context,.wy-inline-validate.wy-inline-validate-info a .wy-input-context,a .wy-tag-input-group .wy-tag .wy-tag-remove,.wy-tag-input-group .wy-tag a .wy-tag-remove,a .rst-content .admonition-title,.rst-content a .admonition-title,a .rst-content h1 .headerlink,.rst-content h1 a .headerlink,a .rst-content h2 .headerlink,.rst-content h2 a .headerlink,a .rst-content h3 .headerlink,.rst-content h3 a .headerlink,a .rst-content h4 .headerlink,.rst-content h4 a .headerlink,a .rst-content h5 .headerlink,.rst-content h5 a .headerlink,a .rst-content h6 .headerlink,.rst-content h6 a .headerlink,a .rst-content dl dt .headerlink,.rst-content dl dt a .headerlink{display:inline-block;text-decoration:inherit}.icon-large:before{vertical-align:-10%;font-size:1.33333em}.btn .icon,.btn .wy-inline-validate.wy-inline-validate-success .wy-input-context,.wy-inline-validate.wy-inline-validate-success .btn .wy-input-context,.btn .wy-inline-validate.wy-inline-validate-danger .wy-input-context,.wy-inline-validate.wy-inline-validate-danger .btn .wy-input-context,.btn .wy-inline-validate.wy-inline-validate-warning .wy-input-context,.wy-inline-validate.wy-inline-validate-warning .btn .wy-input-context,.btn .wy-inline-validate.wy-inline-validate-info .wy-input-context,.wy-inline-validate.wy-inline-validate-info .btn .wy-input-context,.btn .wy-tag-input-group .wy-tag .wy-tag-remove,.wy-tag-input-group .wy-tag .btn .wy-tag-remove,.btn .rst-content .admonition-title,.rst-content .btn .admonition-title,.btn .rst-content h1 .headerlink,.rst-content h1 .btn .headerlink,.btn .rst-content h2 .headerlink,.rst-content h2 .btn .headerlink,.btn .rst-content h3 .headerlink,.rst-content h3 .btn .headerlink,.btn .rst-content h4 .headerlink,.rst-content h4 .btn .headerlink,.btn .rst-content h5 .headerlink,.rst-content h5 .btn .headerlink,.btn .rst-content h6 .headerlink,.rst-content h6 .btn .headerlink,.btn .rst-content dl dt .headerlink,.rst-content dl dt .btn .headerlink,.nav .icon,.nav .wy-inline-validate.wy-inline-validate-success .wy-input-context,.wy-inline-validate.wy-inline-validate-success .nav .wy-input-context,.nav .wy-inline-validate.wy-inline-validate-danger .wy-input-context,.wy-inline-validate.wy-inline-validate-danger .nav .wy-input-context,.nav .wy-inline-validate.wy-inline-validate-warning .wy-input-context,.wy-inline-validate.wy-inline-validate-warning .nav .wy-input-context,.nav .wy-inline-validate.wy-inline-validate-info .wy-input-context,.wy-inline-validate.wy-inline-validate-info .nav .wy-input-context,.nav .wy-tag-input-group .wy-tag .wy-tag-remove,.wy-tag-input-group .wy-tag .nav .wy-tag-remove,.nav .rst-content .admonition-title,.rst-content .nav .admonition-title,.nav .rst-content h1 .headerlink,.rst-content h1 .nav .headerlink,.nav .rst-content h2 .headerlink,.rst-content h2 .nav .headerlink,.nav .rst-content h3 .headerlink,.rst-content h3 .nav .headerlink,.nav .rst-content h4 .headerlink,.rst-content h4 .nav .headerlink,.nav .rst-content h5 .headerlink,.rst-content h5 .nav .headerlink,.nav .rst-content h6 .headerlink,.rst-content h6 .nav .headerlink,.nav .rst-content dl dt .headerlink,.rst-content dl dt .nav .headerlink{display:inline}.btn .icon.icon-large,.btn .wy-inline-validate.wy-inline-validate-success .icon-large.wy-input-context,.wy-inline-validate.wy-inline-validate-success .btn .icon-large.wy-input-context,.btn .wy-inline-validate.wy-inline-validate-danger .icon-large.wy-input-context,.wy-inline-validate.wy-inline-validate-danger .btn .icon-large.wy-input-context,.btn .wy-inline-validate.wy-inline-validate-warning .icon-large.wy-input-context,.wy-inline-validate.wy-inline-validate-warning .btn .icon-large.wy-input-context,.btn .wy-inline-validate.wy-inline-validate-info .icon-large.wy-input-context,.wy-inline-validate.wy-inline-validate-info .btn .icon-large.wy-input-context,.btn .wy-tag-input-group .wy-tag .icon-large.wy-tag-remove,.wy-tag-input-group .wy-tag .btn .icon-large.wy-tag-remove,.btn .rst-content .icon-large.admonition-title,.rst-content .btn .icon-large.admonition-title,.btn .rst-content h1 .icon-large.headerlink,.rst-content h1 .btn .icon-large.headerlink,.btn .rst-content h2 .icon-large.headerlink,.rst-content h2 .btn .icon-large.headerlink,.btn .rst-content h3 .icon-large.headerlink,.rst-content h3 .btn .icon-large.headerlink,.btn .rst-content h4 .icon-large.headerlink,.rst-content h4 .btn .icon-large.headerlink,.btn .rst-content h5 .icon-large.headerlink,.rst-content h5 .btn .icon-large.headerlink,.btn .rst-content h6 .icon-large.headerlink,.rst-content h6 .btn .icon-large.headerlink,.btn .rst-content dl dt .icon-large.headerlink,.rst-content dl dt .btn .icon-large.headerlink,.nav .icon.icon-large,.nav .wy-inline-validate.wy-inline-validate-success .icon-large.wy-input-context,.wy-inline-validate.wy-inline-validate-success .nav .icon-large.wy-input-context,.nav .wy-inline-validate.wy-inline-validate-danger .icon-large.wy-input-context,.wy-inline-validate.wy-inline-validate-danger .nav .icon-large.wy-input-context,.nav .wy-inline-validate.wy-inline-validate-warning .icon-large.wy-input-context,.wy-inline-validate.wy-inline-validate-warning .nav .icon-large.wy-input-context,.nav .wy-inline-validate.wy-inline-validate-info .icon-large.wy-input-context,.wy-inline-validate.wy-inline-validate-info .nav .icon-large.wy-input-context,.nav .wy-tag-input-group .wy-tag .icon-large.wy-tag-remove,.wy-tag-input-group .wy-tag .nav .icon-large.wy-tag-remove,.nav .rst-content .icon-large.admonition-title,.rst-content .nav .icon-large.admonition-title,.nav .rst-content h1 .icon-large.headerlink,.rst-content h1 .nav .icon-large.headerlink,.nav .rst-content h2 .icon-large.headerlink,.rst-content h2 .nav .icon-large.headerlink,.nav .rst-content h3 .icon-large.headerlink,.rst-content h3 .nav .icon-large.headerlink,.nav .rst-content h4 .icon-large.headerlink,.rst-content h4 .nav .icon-large.headerlink,.nav .rst-content h5 .icon-large.headerlink,.rst-content h5 .nav .icon-large.headerlink,.nav .rst-content h6 .icon-large.headerlink,.rst-content h6 .nav .icon-large.headerlink,.nav .rst-content dl dt .icon-large.headerlink,.rst-content dl dt .nav .icon-large.headerlink{line-height:0.9em}.btn .icon.icon-spin,.btn .wy-inline-validate.wy-inline-validate-success .icon-spin.wy-input-context,.wy-inline-validate.wy-inline-validate-success .btn .icon-spin.wy-input-context,.btn .wy-inline-validate.wy-inline-validate-danger .icon-spin.wy-input-context,.wy-inline-validate.wy-inline-validate-danger .btn .icon-spin.wy-input-context,.btn .wy-inline-validate.wy-inline-validate-warning .icon-spin.wy-input-context,.wy-inline-validate.wy-inline-validate-warning .btn .icon-spin.wy-input-context,.btn .wy-inline-validate.wy-inline-validate-info .icon-spin.wy-input-context,.wy-inline-validate.wy-inline-validate-info .btn .icon-spin.wy-input-context,.btn .wy-tag-input-group .wy-tag .icon-spin.wy-tag-remove,.wy-tag-input-group .wy-tag .btn .icon-spin.wy-tag-remove,.btn .rst-content .icon-spin.admonition-title,.rst-content .btn .icon-spin.admonition-title,.btn .rst-content h1 .icon-spin.headerlink,.rst-content h1 .btn .icon-spin.headerlink,.btn .rst-content h2 .icon-spin.headerlink,.rst-content h2 .btn .icon-spin.headerlink,.btn .rst-content h3 .icon-spin.headerlink,.rst-content h3 .btn .icon-spin.headerlink,.btn .rst-content h4 .icon-spin.headerlink,.rst-content h4 .btn .icon-spin.headerlink,.btn .rst-content h5 .icon-spin.headerlink,.rst-content h5 .btn .icon-spin.headerlink,.btn .rst-content h6 .icon-spin.headerlink,.rst-content h6 .btn .icon-spin.headerlink,.btn .rst-content dl dt .icon-spin.headerlink,.rst-content dl dt .btn .icon-spin.headerlink,.nav .icon.icon-spin,.nav .wy-inline-validate.wy-inline-validate-success .icon-spin.wy-input-context,.wy-inline-validate.wy-inline-validate-success .nav .icon-spin.wy-input-context,.nav .wy-inline-validate.wy-inline-validate-danger .icon-spin.wy-input-context,.wy-inline-validate.wy-inline-validate-danger .nav .icon-spin.wy-input-context,.nav .wy-inline-validate.wy-inline-validate-warning .icon-spin.wy-input-context,.wy-inline-validate.wy-inline-validate-warning .nav .icon-spin.wy-input-context,.nav .wy-inline-validate.wy-inline-validate-info .icon-spin.wy-input-context,.wy-inline-validate.wy-inline-validate-info .nav .icon-spin.wy-input-context,.nav .wy-tag-input-group .wy-tag .icon-spin.wy-tag-remove,.wy-tag-input-group .wy-tag .nav .icon-spin.wy-tag-remove,.nav .rst-content .icon-spin.admonition-title,.rst-content .nav .icon-spin.admonition-title,.nav .rst-content h1 .icon-spin.headerlink,.rst-content h1 .nav .icon-spin.headerlink,.nav .rst-content h2 .icon-spin.headerlink,.rst-content h2 .nav .icon-spin.headerlink,.nav .rst-content h3 .icon-spin.headerlink,.rst-content h3 .nav .icon-spin.headerlink,.nav .rst-content h4 .icon-spin.headerlink,.rst-content h4 .nav .icon-spin.headerlink,.nav .rst-content h5 .icon-spin.headerlink,.rst-content h5 .nav .icon-spin.headerlink,.nav .rst-content h6 .icon-spin.headerlink,.rst-content h6 .nav .icon-spin.headerlink,.nav .rst-content dl dt .icon-spin.headerlink,.rst-content dl dt .nav .icon-spin.headerlink{display:inline-block}.btn.icon:before,.wy-inline-validate.wy-inline-validate-success .btn.wy-input-context:before,.wy-inline-validate.wy-inline-validate-danger .btn.wy-input-context:before,.wy-inline-validate.wy-inline-validate-warning .btn.wy-input-context:before,.wy-inline-validate.wy-inline-validate-info .btn.wy-input-context:before,.wy-tag-input-group .wy-tag .btn.wy-tag-remove:before,.rst-content .btn.admonition-title:before,.rst-content h1 .btn.headerlink:before,.rst-content h2 .btn.headerlink:before,.rst-content h3 .btn.headerlink:before,.rst-content h4 .btn.headerlink:before,.rst-content h5 .btn.headerlink:before,.rst-content h6 .btn.headerlink:before,.rst-content dl dt .btn.headerlink:before{opacity:0.5;-webkit-transition:opacity 0.05s ease-in;-moz-transition:opacity 0.05s ease-in;transition:opacity 0.05s ease-in}.btn.icon:hover:before,.wy-inline-validate.wy-inline-validate-success .btn.wy-input-context:hover:before,.wy-inline-validate.wy-inline-validate-danger .btn.wy-input-context:hover:before,.wy-inline-validate.wy-inline-validate-warning .btn.wy-input-context:hover:before,.wy-inline-validate.wy-inline-validate-info .btn.wy-input-context:hover:before,.wy-tag-input-group .wy-tag .btn.wy-tag-remove:hover:before,.rst-content .btn.admonition-title:hover:before,.rst-content h1 .btn.headerlink:hover:before,.rst-content h2 .btn.headerlink:hover:before,.rst-content h3 .btn.headerlink:hover:before,.rst-content h4 .btn.headerlink:hover:before,.rst-content h5 .btn.headerlink:hover:before,.rst-content h6 .btn.headerlink:hover:before,.rst-content dl dt .btn.headerlink:hover:before{opacity:1}.btn-mini .icon:before,.btn-mini .wy-inline-validate.wy-inline-validate-success .wy-input-context:before,.wy-inline-validate.wy-inline-validate-success .btn-mini .wy-input-context:before,.btn-mini .wy-inline-validate.wy-inline-validate-danger .wy-input-context:before,.wy-inline-validate.wy-inline-validate-danger .btn-mini .wy-input-context:before,.btn-mini .wy-inline-validate.wy-inline-validate-warning .wy-input-context:before,.wy-inline-validate.wy-inline-validate-warning .btn-mini .wy-input-context:before,.btn-mini .wy-inline-validate.wy-inline-validate-info .wy-input-context:before,.wy-inline-validate.wy-inline-validate-info .btn-mini .wy-input-context:before,.btn-mini .wy-tag-input-group .wy-tag .wy-tag-remove:before,.wy-tag-input-group .wy-tag .btn-mini .wy-tag-remove:before,.btn-mini .rst-content .admonition-title:before,.rst-content .btn-mini .admonition-title:before,.btn-mini .rst-content h1 .headerlink:before,.rst-content h1 .btn-mini .headerlink:before,.btn-mini .rst-content h2 .headerlink:before,.rst-content h2 .btn-mini .headerlink:before,.btn-mini .rst-content h3 .headerlink:before,.rst-content h3 .btn-mini .headerlink:before,.btn-mini .rst-content h4 .headerlink:before,.rst-content h4 .btn-mini .headerlink:before,.btn-mini .rst-content h5 .headerlink:before,.rst-content h5 .btn-mini .headerlink:before,.btn-mini .rst-content h6 .headerlink:before,.rst-content h6 .btn-mini .headerlink:before,.btn-mini .rst-content dl dt .headerlink:before,.rst-content dl dt .btn-mini .headerlink:before{font-size:14px;vertical-align:-15%}li .icon,li .wy-inline-validate.wy-inline-validate-success .wy-input-context,.wy-inline-validate.wy-inline-validate-success li .wy-input-context,li .wy-inline-validate.wy-inline-validate-danger .wy-input-context,.wy-inline-validate.wy-inline-validate-danger li .wy-input-context,li .wy-inline-validate.wy-inline-validate-warning .wy-input-context,.wy-inline-validate.wy-inline-validate-warning li .wy-input-context,li .wy-inline-validate.wy-inline-validate-info .wy-input-context,.wy-inline-validate.wy-inline-validate-info li .wy-input-context,li .wy-tag-input-group .wy-tag .wy-tag-remove,.wy-tag-input-group .wy-tag li .wy-tag-remove,li .rst-content .admonition-title,.rst-content li .admonition-title,li .rst-content h1 .headerlink,.rst-content h1 li .headerlink,li .rst-content h2 .headerlink,.rst-content h2 li .headerlink,li .rst-content h3 .headerlink,.rst-content h3 li .headerlink,li .rst-content h4 .headerlink,.rst-content h4 li .headerlink,li .rst-content h5 .headerlink,.rst-content h5 li .headerlink,li .rst-content h6 .headerlink,.rst-content h6 li .headerlink,li .rst-content dl dt .headerlink,.rst-content dl dt li .headerlink{display:inline-block}li .icon-large:before,li .icon-large:before{width:1.875em}ul.icons{list-style-type:none;margin-left:2em;text-indent:-0.8em}ul.icons li .icon,ul.icons li .wy-inline-validate.wy-inline-validate-success .wy-input-context,.wy-inline-validate.wy-inline-validate-success ul.icons li .wy-input-context,ul.icons li .wy-inline-validate.wy-inline-validate-danger .wy-input-context,.wy-inline-validate.wy-inline-validate-danger ul.icons li .wy-input-context,ul.icons li .wy-inline-validate.wy-inline-validate-warning .wy-input-context,.wy-inline-validate.wy-inline-validate-warning ul.icons li .wy-input-context,ul.icons li .wy-inline-validate.wy-inline-validate-info .wy-input-context,.wy-inline-validate.wy-inline-validate-info ul.icons li .wy-input-context,ul.icons li .wy-tag-input-group .wy-tag .wy-tag-remove,.wy-tag-input-group .wy-tag ul.icons li .wy-tag-remove,ul.icons li .rst-content .admonition-title,.rst-content ul.icons li .admonition-title,ul.icons li .rst-content h1 .headerlink,.rst-content h1 ul.icons li .headerlink,ul.icons li .rst-content h2 .headerlink,.rst-content h2 ul.icons li .headerlink,ul.icons li .rst-content h3 .headerlink,.rst-content h3 ul.icons li .headerlink,ul.icons li .rst-content h4 .headerlink,.rst-content h4 ul.icons li .headerlink,ul.icons li .rst-content h5 .headerlink,.rst-content h5 ul.icons li .headerlink,ul.icons li .rst-content h6 .headerlink,.rst-content h6 ul.icons li .headerlink,ul.icons li .rst-content dl dt .headerlink,.rst-content dl dt ul.icons li .headerlink{width:0.8em}ul.icons li .icon-large:before,ul.icons li .icon-large:before{vertical-align:baseline}.icon-glass:before{content:"\f000"}.icon-music:before{content:"\f001"}.icon-search:before{content:"\f002"}.icon-envelope-alt:before{content:"\f003"}.icon-heart:before{content:"\f004"}.icon-star:before{content:"\f005"}.icon-star-empty:before{content:"\f006"}.icon-user:before{content:"\f007"}.icon-film:before{content:"\f008"}.icon-th-large:before{content:"\f009"}.icon-th:before{content:"\f00a"}.icon-th-list:before{content:"\f00b"}.icon-ok:before{content:"\f00c"}.icon-remove:before,.wy-tag-input-group .wy-tag .wy-tag-remove:before{content:"\f00d"}.icon-zoom-in:before{content:"\f00e"}.icon-zoom-out:before{content:"\f010"}.icon-power-off:before,.icon-off:before{content:"\f011"}.icon-signal:before{content:"\f012"}.icon-gear:before,.icon-cog:before{content:"\f013"}.icon-trash:before{content:"\f014"}.icon-home:before{content:"\f015"}.icon-file-alt:before{content:"\f016"}.icon-time:before{content:"\f017"}.icon-road:before{content:"\f018"}.icon-download-alt:before{content:"\f019"}.icon-download:before{content:"\f01a"}.icon-upload:before{content:"\f01b"}.icon-inbox:before{content:"\f01c"}.icon-play-circle:before{content:"\f01d"}.icon-rotate-right:before,.icon-repeat:before{content:"\f01e"}.icon-refresh:before{content:"\f021"}.icon-list-alt:before{content:"\f022"}.icon-lock:before{content:"\f023"}.icon-flag:before{content:"\f024"}.icon-headphones:before{content:"\f025"}.icon-volume-off:before{content:"\f026"}.icon-volume-down:before{content:"\f027"}.icon-volume-up:before{content:"\f028"}.icon-qrcode:before{content:"\f029"}.icon-barcode:before{content:"\f02a"}.icon-tag:before{content:"\f02b"}.icon-tags:before{content:"\f02c"}.icon-book:before{content:"\f02d"}.icon-bookmark:before{content:"\f02e"}.icon-print:before{content:"\f02f"}.icon-camera:before{content:"\f030"}.icon-font:before{content:"\f031"}.icon-bold:before{content:"\f032"}.icon-italic:before{content:"\f033"}.icon-text-height:before{content:"\f034"}.icon-text-width:before{content:"\f035"}.icon-align-left:before{content:"\f036"}.icon-align-center:before{content:"\f037"}.icon-align-right:before{content:"\f038"}.icon-align-justify:before{content:"\f039"}.icon-list:before{content:"\f03a"}.icon-indent-left:before{content:"\f03b"}.icon-indent-right:before{content:"\f03c"}.icon-facetime-video:before{content:"\f03d"}.icon-picture:before{content:"\f03e"}.icon-pencil:before{content:"\f040"}.icon-map-marker:before{content:"\f041"}.icon-adjust:before{content:"\f042"}.icon-tint:before{content:"\f043"}.icon-edit:before{content:"\f044"}.icon-share:before{content:"\f045"}.icon-check:before{content:"\f046"}.icon-move:before{content:"\f047"}.icon-step-backward:before{content:"\f048"}.icon-fast-backward:before{content:"\f049"}.icon-backward:before{content:"\f04a"}.icon-play:before{content:"\f04b"}.icon-pause:before{content:"\f04c"}.icon-stop:before{content:"\f04d"}.icon-forward:before{content:"\f04e"}.icon-fast-forward:before{content:"\f050"}.icon-step-forward:before{content:"\f051"}.icon-eject:before{content:"\f052"}.icon-chevron-left:before{content:"\f053"}.icon-chevron-right:before{content:"\f054"}.icon-plus-sign:before{content:"\f055"}.icon-minus-sign:before{content:"\f056"}.icon-remove-sign:before,.wy-inline-validate.wy-inline-validate-danger .wy-input-context:before{content:"\f057"}.icon-ok-sign:before{content:"\f058"}.icon-question-sign:before{content:"\f059"}.icon-info-sign:before{content:"\f05a"}.icon-screenshot:before{content:"\f05b"}.icon-remove-circle:before{content:"\f05c"}.icon-ok-circle:before{content:"\f05d"}.icon-ban-circle:before{content:"\f05e"}.icon-arrow-left:before{content:"\f060"}.icon-arrow-right:before{content:"\f061"}.icon-arrow-up:before{content:"\f062"}.icon-arrow-down:before{content:"\f063"}.icon-mail-forward:before,.icon-share-alt:before{content:"\f064"}.icon-resize-full:before{content:"\f065"}.icon-resize-small:before{content:"\f066"}.icon-plus:before{content:"\f067"}.icon-minus:before{content:"\f068"}.icon-asterisk:before{content:"\f069"}.icon-exclamation-sign:before,.wy-inline-validate.wy-inline-validate-warning .wy-input-context:before,.wy-inline-validate.wy-inline-validate-info .wy-input-context:before,.rst-content .admonition-title:before{content:"\f06a"}.icon-gift:before{content:"\f06b"}.icon-leaf:before{content:"\f06c"}.icon-fire:before{content:"\f06d"}.icon-eye-open:before{content:"\f06e"}.icon-eye-close:before{content:"\f070"}.icon-warning-sign:before{content:"\f071"}.icon-plane:before{content:"\f072"}.icon-calendar:before{content:"\f073"}.icon-random:before{content:"\f074"}.icon-comment:before{content:"\f075"}.icon-magnet:before{content:"\f076"}.icon-chevron-up:before{content:"\f077"}.icon-chevron-down:before{content:"\f078"}.icon-retweet:before{content:"\f079"}.icon-shopping-cart:before{content:"\f07a"}.icon-folder-close:before{content:"\f07b"}.icon-folder-open:before{content:"\f07c"}.icon-resize-vertical:before{content:"\f07d"}.icon-resize-horizontal:before{content:"\f07e"}.icon-bar-chart:before{content:"\f080"}.icon-twitter-sign:before{content:"\f081"}.icon-facebook-sign:before{content:"\f082"}.icon-camera-retro:before{content:"\f083"}.icon-key:before{content:"\f084"}.icon-gears:before,.icon-cogs:before{content:"\f085"}.icon-comments:before{content:"\f086"}.icon-thumbs-up-alt:before{content:"\f087"}.icon-thumbs-down-alt:before{content:"\f088"}.icon-star-half:before{content:"\f089"}.icon-heart-empty:before{content:"\f08a"}.icon-signout:before{content:"\f08b"}.icon-linkedin-sign:before{content:"\f08c"}.icon-pushpin:before{content:"\f08d"}.icon-external-link:before{content:"\f08e"}.icon-signin:before{content:"\f090"}.icon-trophy:before{content:"\f091"}.icon-github-sign:before{content:"\f092"}.icon-upload-alt:before{content:"\f093"}.icon-lemon:before{content:"\f094"}.icon-phone:before{content:"\f095"}.icon-unchecked:before,.icon-check-empty:before{content:"\f096"}.icon-bookmark-empty:before{content:"\f097"}.icon-phone-sign:before{content:"\f098"}.icon-twitter:before{content:"\f099"}.icon-facebook:before{content:"\f09a"}.icon-github:before{content:"\f09b"}.icon-unlock:before{content:"\f09c"}.icon-credit-card:before{content:"\f09d"}.icon-rss:before{content:"\f09e"}.icon-hdd:before{content:"\f0a0"}.icon-bullhorn:before{content:"\f0a1"}.icon-bell:before{content:"\f0a2"}.icon-certificate:before{content:"\f0a3"}.icon-hand-right:before{content:"\f0a4"}.icon-hand-left:before{content:"\f0a5"}.icon-hand-up:before{content:"\f0a6"}.icon-hand-down:before{content:"\f0a7"}.icon-circle-arrow-left:before{content:"\f0a8"}.icon-circle-arrow-right:before{content:"\f0a9"}.icon-circle-arrow-up:before{content:"\f0aa"}.icon-circle-arrow-down:before{content:"\f0ab"}.icon-globe:before{content:"\f0ac"}.icon-wrench:before{content:"\f0ad"}.icon-tasks:before{content:"\f0ae"}.icon-filter:before{content:"\f0b0"}.icon-briefcase:before{content:"\f0b1"}.icon-fullscreen:before{content:"\f0b2"}.icon-group:before{content:"\f0c0"}.icon-link:before{content:"\f0c1"}.icon-cloud:before{content:"\f0c2"}.icon-beaker:before{content:"\f0c3"}.icon-cut:before{content:"\f0c4"}.icon-copy:before{content:"\f0c5"}.icon-paperclip:before,.icon-paper-clip:before{content:"\f0c6"}.icon-save:before{content:"\f0c7"}.icon-sign-blank:before{content:"\f0c8"}.icon-reorder:before{content:"\f0c9"}.icon-list-ul:before{content:"\f0ca"}.icon-list-ol:before{content:"\f0cb"}.icon-strikethrough:before{content:"\f0cc"}.icon-underline:before{content:"\f0cd"}.icon-table:before{content:"\f0ce"}.icon-magic:before{content:"\f0d0"}.icon-truck:before{content:"\f0d1"}.icon-pinterest:before{content:"\f0d2"}.icon-pinterest-sign:before{content:"\f0d3"}.icon-google-plus-sign:before{content:"\f0d4"}.icon-google-plus:before{content:"\f0d5"}.icon-money:before{content:"\f0d6"}.icon-caret-down:before{content:"\f0d7"}.icon-caret-up:before{content:"\f0d8"}.icon-caret-left:before{content:"\f0d9"}.icon-caret-right:before{content:"\f0da"}.icon-columns:before{content:"\f0db"}.icon-sort:before{content:"\f0dc"}.icon-sort-down:before{content:"\f0dd"}.icon-sort-up:before{content:"\f0de"}.icon-envelope:before{content:"\f0e0"}.icon-linkedin:before{content:"\f0e1"}.icon-rotate-left:before,.icon-undo:before{content:"\f0e2"}.icon-legal:before{content:"\f0e3"}.icon-dashboard:before{content:"\f0e4"}.icon-comment-alt:before{content:"\f0e5"}.icon-comments-alt:before{content:"\f0e6"}.icon-bolt:before{content:"\f0e7"}.icon-sitemap:before{content:"\f0e8"}.icon-umbrella:before{content:"\f0e9"}.icon-paste:before{content:"\f0ea"}.icon-lightbulb:before{content:"\f0eb"}.icon-exchange:before{content:"\f0ec"}.icon-cloud-download:before{content:"\f0ed"}.icon-cloud-upload:before{content:"\f0ee"}.icon-user-md:before{content:"\f0f0"}.icon-stethoscope:before{content:"\f0f1"}.icon-suitcase:before{content:"\f0f2"}.icon-bell-alt:before{content:"\f0f3"}.icon-coffee:before{content:"\f0f4"}.icon-food:before{content:"\f0f5"}.icon-file-text-alt:before{content:"\f0f6"}.icon-building:before{content:"\f0f7"}.icon-hospital:before{content:"\f0f8"}.icon-ambulance:before{content:"\f0f9"}.icon-medkit:before{content:"\f0fa"}.icon-fighter-jet:before{content:"\f0fb"}.icon-beer:before{content:"\f0fc"}.icon-h-sign:before{content:"\f0fd"}.icon-plus-sign-alt:before{content:"\f0fe"}.icon-double-angle-left:before{content:"\f100"}.icon-double-angle-right:before{content:"\f101"}.icon-double-angle-up:before{content:"\f102"}.icon-double-angle-down:before{content:"\f103"}.icon-angle-left:before{content:"\f104"}.icon-angle-right:before{content:"\f105"}.icon-angle-up:before{content:"\f106"}.icon-angle-down:before{content:"\f107"}.icon-desktop:before{content:"\f108"}.icon-laptop:before{content:"\f109"}.icon-tablet:before{content:"\f10a"}.icon-mobile-phone:before{content:"\f10b"}.icon-circle-blank:before{content:"\f10c"}.icon-quote-left:before{content:"\f10d"}.icon-quote-right:before{content:"\f10e"}.icon-spinner:before{content:"\f110"}.icon-circle:before{content:"\f111"}.icon-mail-reply:before,.icon-reply:before{content:"\f112"}.icon-github-alt:before{content:"\f113"}.icon-folder-close-alt:before{content:"\f114"}.icon-folder-open-alt:before{content:"\f115"}.icon-expand-alt:before{content:"\f116"}.icon-collapse-alt:before{content:"\f117"}.icon-smile:before{content:"\f118"}.icon-frown:before{content:"\f119"}.icon-meh:before{content:"\f11a"}.icon-gamepad:before{content:"\f11b"}.icon-keyboard:before{content:"\f11c"}.icon-flag-alt:before{content:"\f11d"}.icon-flag-checkered:before{content:"\f11e"}.icon-terminal:before{content:"\f120"}.icon-code:before{content:"\f121"}.icon-reply-all:before{content:"\f122"}.icon-mail-reply-all:before{content:"\f122"}.icon-star-half-full:before,.icon-star-half-empty:before{content:"\f123"}.icon-location-arrow:before{content:"\f124"}.icon-crop:before{content:"\f125"}.icon-code-fork:before{content:"\f126"}.icon-unlink:before{content:"\f127"}.icon-question:before{content:"\f128"}.icon-info:before{content:"\f129"}.icon-exclamation:before{content:"\f12a"}.icon-superscript:before{content:"\f12b"}.icon-subscript:before{content:"\f12c"}.icon-eraser:before{content:"\f12d"}.icon-puzzle-piece:before{content:"\f12e"}.icon-microphone:before{content:"\f130"}.icon-microphone-off:before{content:"\f131"}.icon-shield:before{content:"\f132"}.icon-calendar-empty:before{content:"\f133"}.icon-fire-extinguisher:before{content:"\f134"}.icon-rocket:before{content:"\f135"}.icon-maxcdn:before{content:"\f136"}.icon-chevron-sign-left:before{content:"\f137"}.icon-chevron-sign-right:before{content:"\f138"}.icon-chevron-sign-up:before{content:"\f139"}.icon-chevron-sign-down:before{content:"\f13a"}.icon-html5:before{content:"\f13b"}.icon-css3:before{content:"\f13c"}.icon-anchor:before{content:"\f13d"}.icon-unlock-alt:before{content:"\f13e"}.icon-bullseye:before{content:"\f140"}.icon-ellipsis-horizontal:before{content:"\f141"}.icon-ellipsis-vertical:before{content:"\f142"}.icon-rss-sign:before{content:"\f143"}.icon-play-sign:before{content:"\f144"}.icon-ticket:before{content:"\f145"}.icon-minus-sign-alt:before{content:"\f146"}.icon-check-minus:before{content:"\f147"}.icon-level-up:before{content:"\f148"}.icon-level-down:before{content:"\f149"}.icon-check-sign:before,.wy-inline-validate.wy-inline-validate-success .wy-input-context:before{content:"\f14a"}.icon-edit-sign:before{content:"\f14b"}.icon-external-link-sign:before{content:"\f14c"}.icon-share-sign:before{content:"\f14d"}.icon-compass:before{content:"\f14e"}.icon-collapse:before{content:"\f150"}.icon-collapse-top:before{content:"\f151"}.icon-expand:before{content:"\f152"}.icon-euro:before,.icon-eur:before{content:"\f153"}.icon-gbp:before{content:"\f154"}.icon-dollar:before,.icon-usd:before{content:"\f155"}.icon-rupee:before,.icon-inr:before{content:"\f156"}.icon-yen:before,.icon-jpy:before{content:"\f157"}.icon-renminbi:before,.icon-cny:before{content:"\f158"}.icon-won:before,.icon-krw:before{content:"\f159"}.icon-bitcoin:before,.icon-btc:before{content:"\f15a"}.icon-file:before{content:"\f15b"}.icon-file-text:before{content:"\f15c"}.icon-sort-by-alphabet:before{content:"\f15d"}.icon-sort-by-alphabet-alt:before{content:"\f15e"}.icon-sort-by-attributes:before{content:"\f160"}.icon-sort-by-attributes-alt:before{content:"\f161"}.icon-sort-by-order:before{content:"\f162"}.icon-sort-by-order-alt:before{content:"\f163"}.icon-thumbs-up:before{content:"\f164"}.icon-thumbs-down:before{content:"\f165"}.icon-youtube-sign:before{content:"\f166"}.icon-youtube:before{content:"\f167"}.icon-xing:before{content:"\f168"}.icon-xing-sign:before{content:"\f169"}.icon-youtube-play:before{content:"\f16a"}.icon-dropbox:before{content:"\f16b"}.icon-stackexchange:before{content:"\f16c"}.icon-instagram:before{content:"\f16d"}.icon-flickr:before{content:"\f16e"}.icon-adn:before{content:"\f170"}.icon-bitbucket:before{content:"\f171"}.icon-bitbucket-sign:before{content:"\f172"}.icon-tumblr:before{content:"\f173"}.icon-tumblr-sign:before{content:"\f174"}.icon-long-arrow-down:before{content:"\f175"}.icon-long-arrow-up:before{content:"\f176"}.icon-long-arrow-left:before{content:"\f177"}.icon-long-arrow-right:before{content:"\f178"}.icon-apple:before{content:"\f179"}.icon-windows:before{content:"\f17a"}.icon-android:before{content:"\f17b"}.icon-linux:before{content:"\f17c"}.icon-dribbble:before{content:"\f17d"}.icon-skype:before{content:"\f17e"}.icon-foursquare:before{content:"\f180"}.icon-trello:before{content:"\f181"}.icon-female:before{content:"\f182"}.icon-male:before{content:"\f183"}.icon-gittip:before{content:"\f184"}.icon-sun:before{content:"\f185"}.icon-moon:before{content:"\f186"}.icon-archive:before{content:"\f187"}.icon-bug:before{content:"\f188"}.icon-vk:before{content:"\f189"}.icon-weibo:before{content:"\f18a"}.icon-renren:before{content:"\f18b"}.wy-alert,.rst-content .note,.rst-content .attention,.rst-content .caution,.rst-content .danger,.rst-content .error,.rst-content .hint,.rst-content .important,.rst-content .tip,.rst-content .warning,.rst-content .seealso{padding:12px;line-height:24px;margin-bottom:24px}.wy-alert-title,.rst-content .admonition-title{color:#fff;font-weight:bold;display:block;color:#fff;background:transparent;margin:-12px;padding:6px 12px;margin-bottom:12px}.wy-alert.wy-alert-danger,.rst-content .wy-alert-danger.note,.rst-content .wy-alert-danger.attention,.rst-content .wy-alert-danger.caution,.rst-content .danger,.rst-content .error,.rst-content .wy-alert-danger.hint,.rst-content .wy-alert-danger.important,.rst-content .wy-alert-danger.tip,.rst-content .wy-alert-danger.warning,.rst-content .wy-alert-danger.seealso{background:#fdf3f2}.wy-alert.wy-alert-danger .wy-alert-title,.rst-content .wy-alert-danger.note .wy-alert-title,.rst-content .wy-alert-danger.attention .wy-alert-title,.rst-content .wy-alert-danger.caution .wy-alert-title,.rst-content .danger .wy-alert-title,.rst-content .error .wy-alert-title,.rst-content .wy-alert-danger.hint .wy-alert-title,.rst-content .wy-alert-danger.important .wy-alert-title,.rst-content .wy-alert-danger.tip .wy-alert-title,.rst-content .wy-alert-danger.warning .wy-alert-title,.rst-content .wy-alert-danger.seealso .wy-alert-title,.wy-alert.wy-alert-danger .rst-content .admonition-title,.rst-content .wy-alert.wy-alert-danger .admonition-title,.rst-content .wy-alert-danger.note .admonition-title,.rst-content .wy-alert-danger.attention .admonition-title,.rst-content .wy-alert-danger.caution .admonition-title,.rst-content .danger .admonition-title,.rst-content .error .admonition-title,.rst-content .wy-alert-danger.hint .admonition-title,.rst-content .wy-alert-danger.important .admonition-title,.rst-content .wy-alert-danger.tip .admonition-title,.rst-content .wy-alert-danger.warning .admonition-title,.rst-content .wy-alert-danger.seealso .admonition-title{background:#f29f97}.wy-alert.wy-alert-warning,.rst-content .wy-alert-warning.note,.rst-content .attention,.rst-content .caution,.rst-content .wy-alert-warning.danger,.rst-content .wy-alert-warning.error,.rst-content .wy-alert-warning.hint,.rst-content .wy-alert-warning.important,.rst-content .wy-alert-warning.tip,.rst-content .warning,.rst-content .wy-alert-warning.seealso{background:#ffedcc}.wy-alert.wy-alert-warning .wy-alert-title,.rst-content .wy-alert-warning.note .wy-alert-title,.rst-content .attention .wy-alert-title,.rst-content .caution .wy-alert-title,.rst-content .wy-alert-warning.danger .wy-alert-title,.rst-content .wy-alert-warning.error .wy-alert-title,.rst-content .wy-alert-warning.hint .wy-alert-title,.rst-content .wy-alert-warning.important .wy-alert-title,.rst-content .wy-alert-warning.tip .wy-alert-title,.rst-content .warning .wy-alert-title,.rst-content .wy-alert-warning.seealso .wy-alert-title,.wy-alert.wy-alert-warning .rst-content .admonition-title,.rst-content .wy-alert.wy-alert-warning .admonition-title,.rst-content .wy-alert-warning.note .admonition-title,.rst-content .attention .admonition-title,.rst-content .caution .admonition-title,.rst-content .wy-alert-warning.danger .admonition-title,.rst-content .wy-alert-warning.error .admonition-title,.rst-content .wy-alert-warning.hint .admonition-title,.rst-content .wy-alert-warning.important .admonition-title,.rst-content .wy-alert-warning.tip .admonition-title,.rst-content .warning .admonition-title,.rst-content .wy-alert-warning.seealso .admonition-title{background:#f0b37e}.wy-alert.wy-alert-info,.rst-content .note,.rst-content .wy-alert-info.attention,.rst-content .wy-alert-info.caution,.rst-content .wy-alert-info.danger,.rst-content .wy-alert-info.error,.rst-content .wy-alert-info.hint,.rst-content .wy-alert-info.important,.rst-content .wy-alert-info.tip,.rst-content .wy-alert-info.warning,.rst-content .seealso{background:#e7f2fa}.wy-alert.wy-alert-info .wy-alert-title,.rst-content .note .wy-alert-title,.rst-content .wy-alert-info.attention .wy-alert-title,.rst-content .wy-alert-info.caution .wy-alert-title,.rst-content .wy-alert-info.danger .wy-alert-title,.rst-content .wy-alert-info.error .wy-alert-title,.rst-content .wy-alert-info.hint .wy-alert-title,.rst-content .wy-alert-info.important .wy-alert-title,.rst-content .wy-alert-info.tip .wy-alert-title,.rst-content .wy-alert-info.warning .wy-alert-title,.rst-content .seealso .wy-alert-title,.wy-alert.wy-alert-info .rst-content .admonition-title,.rst-content .wy-alert.wy-alert-info .admonition-title,.rst-content .note .admonition-title,.rst-content .wy-alert-info.attention .admonition-title,.rst-content .wy-alert-info.caution .admonition-title,.rst-content .wy-alert-info.danger .admonition-title,.rst-content .wy-alert-info.error .admonition-title,.rst-content .wy-alert-info.hint .admonition-title,.rst-content .wy-alert-info.important .admonition-title,.rst-content .wy-alert-info.tip .admonition-title,.rst-content .wy-alert-info.warning .admonition-title,.rst-content .seealso .admonition-title{background:#6ab0de}.wy-alert.wy-alert-success,.rst-content .wy-alert-success.note,.rst-content .wy-alert-success.attention,.rst-content .wy-alert-success.caution,.rst-content .wy-alert-success.danger,.rst-content .wy-alert-success.error,.rst-content .hint,.rst-content .important,.rst-content .tip,.rst-content .wy-alert-success.warning,.rst-content .wy-alert-success.seealso{background:#dbfaf4}.wy-alert.wy-alert-success .wy-alert-title,.rst-content .wy-alert-success.note .wy-alert-title,.rst-content .wy-alert-success.attention .wy-alert-title,.rst-content .wy-alert-success.caution .wy-alert-title,.rst-content .wy-alert-success.danger .wy-alert-title,.rst-content .wy-alert-success.error .wy-alert-title,.rst-content .hint .wy-alert-title,.rst-content .important .wy-alert-title,.rst-content .tip .wy-alert-title,.rst-content .wy-alert-success.warning .wy-alert-title,.rst-content .wy-alert-success.seealso .wy-alert-title,.wy-alert.wy-alert-success .rst-content .admonition-title,.rst-content .wy-alert.wy-alert-success .admonition-title,.rst-content .wy-alert-success.note .admonition-title,.rst-content .wy-alert-success.attention .admonition-title,.rst-content .wy-alert-success.caution .admonition-title,.rst-content .wy-alert-success.danger .admonition-title,.rst-content .wy-alert-success.error .admonition-title,.rst-content .hint .admonition-title,.rst-content .important .admonition-title,.rst-content .tip .admonition-title,.rst-content .wy-alert-success.warning .admonition-title,.rst-content .wy-alert-success.seealso .admonition-title{background:#1abc9c}.wy-alert.wy-alert-neutral,.rst-content .wy-alert-neutral.note,.rst-content .wy-alert-neutral.attention,.rst-content .wy-alert-neutral.caution,.rst-content .wy-alert-neutral.danger,.rst-content .wy-alert-neutral.error,.rst-content .wy-alert-neutral.hint,.rst-content .wy-alert-neutral.important,.rst-content .wy-alert-neutral.tip,.rst-content .wy-alert-neutral.warning,.rst-content .wy-alert-neutral.seealso{background:#f3f6f6}.wy-alert.wy-alert-neutral strong,.rst-content .wy-alert-neutral.note strong,.rst-content .wy-alert-neutral.attention strong,.rst-content .wy-alert-neutral.caution strong,.rst-content .wy-alert-neutral.danger strong,.rst-content .wy-alert-neutral.error strong,.rst-content .wy-alert-neutral.hint strong,.rst-content .wy-alert-neutral.important strong,.rst-content .wy-alert-neutral.tip strong,.rst-content .wy-alert-neutral.warning strong,.rst-content .wy-alert-neutral.seealso strong{color:#404040}.wy-alert.wy-alert-neutral a,.rst-content .wy-alert-neutral.note a,.rst-content .wy-alert-neutral.attention a,.rst-content .wy-alert-neutral.caution a,.rst-content .wy-alert-neutral.danger a,.rst-content .wy-alert-neutral.error a,.rst-content .wy-alert-neutral.hint a,.rst-content .wy-alert-neutral.important a,.rst-content .wy-alert-neutral.tip a,.rst-content .wy-alert-neutral.warning a,.rst-content .wy-alert-neutral.seealso a{color:#2980b9}.wy-tray-container{position:fixed;top:-50px;left:0;width:100%;-webkit-transition:top 0.2s ease-in;-moz-transition:top 0.2s ease-in;transition:top 0.2s ease-in}.wy-tray-container.on{top:0}.wy-tray-container li{display:none;width:100%;background:#343131;padding:12px 24px;color:#fff;margin-bottom:6px;text-align:center;box-shadow:0 5px 5px 0 rgba(0,0,0,0.1),0px -1px 2px -1px rgba(255,255,255,0.5) inset}.wy-tray-container li.wy-tray-item-success{background:#27ae60}.wy-tray-container li.wy-tray-item-info{background:#2980b9}.wy-tray-container li.wy-tray-item-warning{background:#e67e22}.wy-tray-container li.wy-tray-item-danger{background:#e74c3c}.btn{display:inline-block;*display:inline;zoom:1;line-height:normal;white-space:nowrap;vertical-align:baseline;text-align:center;cursor:pointer;-webkit-user-drag:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;font-size:100%;padding:6px 12px;color:#fff;border:1px solid rgba(0,0,0,0.1);border-bottom:solid 3px rgba(0,0,0,0.1);background-color:#27ae60;text-decoration:none;font-weight:500;box-shadow:0px 1px 2px -1px rgba(255,255,255,0.5) inset;-webkit-transition:all 0.1s linear;-moz-transition:all 0.1s linear;transition:all 0.1s linear;outline-none:false}.btn-hover{background:#2e8ece;color:#fff}.btn:hover{background:#2cc36b;color:#fff}.btn:focus{background:#2cc36b;color:#fff;outline:0}.btn:active{border-top:solid 3px rgba(0,0,0,0.1);border-bottom:solid 1px rgba(0,0,0,0.1);box-shadow:0px 1px 2px -1px rgba(0,0,0,0.5) inset}.btn[disabled]{background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);filter:alpha(opacity=40);opacity:0.4;cursor:not-allowed;box-shadow:none}.btn-disabled{background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);filter:alpha(opacity=40);opacity:0.4;cursor:not-allowed;box-shadow:none}.btn-disabled:hover,.btn-disabled:focus,.btn-disabled:active{background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);filter:alpha(opacity=40);opacity:0.4;cursor:not-allowed;box-shadow:none}.btn::-moz-focus-inner{padding:0;border:0}.btn-small{font-size:80%}.btn-info{background-color:#2980b9 !important}.btn-info:hover{background-color:#2e8ece !important}.btn-neutral{background-color:#f3f6f6 !important;color:#404040 !important}.btn-neutral:hover{background-color:#e5ebeb !important;color:#404040}.btn-danger{background-color:#e74c3c !important}.btn-danger:hover{background-color:#ea6153 !important}.btn-warning{background-color:#e67e22 !important}.btn-warning:hover{background-color:#e98b39 !important}.btn-invert{background-color:#343131}.btn-invert:hover{background-color:#413d3d !important}.btn-link{background-color:transparent !important;color:#2980b9;border-color:transparent}.btn-link:hover{background-color:transparent !important;color:#409ad5;border-color:transparent}.btn-link:active{background-color:transparent !important;border-color:transparent;border-top:solid 1px transparent;border-bottom:solid 3px transparent}.wy-btn-group .btn,.wy-control .btn{vertical-align:middle}.wy-btn-group{margin-bottom:24px;*zoom:1}.wy-btn-group:before,.wy-btn-group:after{display:table;content:""}.wy-btn-group:after{clear:both}.wy-dropdown{position:relative;display:inline-block}.wy-dropdown:hover .wy-dropdown-menu{display:block}.wy-dropdown .caret:after{font-family:fontawesome-webfont;content:"\f0d7";font-size:70%}.wy-dropdown-menu{position:absolute;top:100%;left:0;display:none;float:left;min-width:100%;background:#fcfcfc;z-index:100;border:solid 1px #cfd7dd;box-shadow:0 5px 5px 0 rgba(0,0,0,0.1);padding:12px}.wy-dropdown-menu>dd>a{display:block;clear:both;color:#404040;white-space:nowrap;font-size:90%;padding:0 12px}.wy-dropdown-menu>dd>a:hover{background:#2980b9;color:#fff}.wy-dropdown-menu>dd.divider{border-top:solid 1px #cfd7dd;margin:6px 0}.wy-dropdown-menu>dd.search{padding-bottom:12px}.wy-dropdown-menu>dd.search input[type="search"]{width:100%}.wy-dropdown-menu>dd.call-to-action{background:#e3e3e3;text-transform:uppercase;font-weight:500;font-size:80%}.wy-dropdown-menu>dd.call-to-action:hover{background:#e3e3e3}.wy-dropdown-menu>dd.call-to-action .btn{color:#fff}.wy-dropdown.wy-dropdown-bubble .wy-dropdown-menu{background:#fcfcfc;margin-top:2px}.wy-dropdown.wy-dropdown-bubble .wy-dropdown-menu a{padding:6px 12px}.wy-dropdown.wy-dropdown-bubble .wy-dropdown-menu a:hover{background:#2980b9;color:#fff}.wy-dropdown.wy-dropdown-left .wy-dropdown-menu{right:0;text-align:right}.wy-dropdown-arrow:before{content:" ";border-bottom:5px solid #f5f5f5;border-left:5px solid transparent;border-right:5px solid transparent;position:absolute;display:block;top:-4px;left:50%;margin-left:-3px}.wy-dropdown-arrow.wy-dropdown-arrow-left:before{left:11px}.wy-form-stacked select{display:block}.wy-form-aligned input,.wy-form-aligned textarea,.wy-form-aligned select,.wy-form-aligned .wy-help-inline,.wy-form-aligned label{display:inline-block;*display:inline;*zoom:1;vertical-align:middle}.wy-form-aligned .wy-control-group>label{display:inline-block;vertical-align:middle;width:10em;margin:0.5em 1em 0 0;float:left}.wy-form-aligned .wy-control{float:left}.wy-form-aligned .wy-control label{display:block}.wy-form-aligned .wy-control select{margin-top:0.5em}fieldset{border:0;margin:0;padding:0}legend{display:block;width:100%;border:0;padding:0;white-space:normal;margin-bottom:24px;font-size:150%;*margin-left:-7px}label{display:block;margin:0 0 0.3125em 0;color:#999;font-size:90%}button,input,select,textarea{font-size:100%;margin:0;vertical-align:baseline;*vertical-align:middle}button,input{line-height:normal}button{-webkit-appearance:button;cursor:pointer;*overflow:visible}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}button[disabled]{cursor:default}input[type="button"],input[type="reset"],input[type="submit"]{-webkit-appearance:button;cursor:pointer;*overflow:visible}input[type="text"],input[type="password"],input[type="email"],input[type="url"],input[type="date"],input[type="month"],input[type="time"],input[type="datetime"],input[type="datetime-local"],input[type="week"],input[type="number"],input[type="search"],input[type="tel"],input[type="color"]{-webkit-appearance:none;padding:6px;display:inline-block;border:1px solid #ccc;font-size:80%;font-family:"Lato","proxima-nova","Helvetica Neue",Arial,sans-serif;box-shadow:inset 0 1px 3px #ddd;border-radius:0;-webkit-transition:border 0.3s linear;-moz-transition:border 0.3s linear;transition:border 0.3s linear}input[type="datetime-local"]{padding:0.34375em 0.625em}input[disabled]{cursor:default}input[type="checkbox"],input[type="radio"]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;padding:0;margin-right:0.3125em;*height:13px;*width:13px}input[type="search"]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}input[type="search"]::-webkit-search-cancel-button,input[type="search"]::-webkit-search-decoration{-webkit-appearance:none}input[type="text"]:focus,input[type="password"]:focus,input[type="email"]:focus,input[type="url"]:focus,input[type="date"]:focus,input[type="month"]:focus,input[type="time"]:focus,input[type="datetime"]:focus,input[type="datetime-local"]:focus,input[type="week"]:focus,input[type="number"]:focus,input[type="search"]:focus,input[type="tel"]:focus,input[type="color"]:focus{outline:0;outline:thin dotted \9;border-color:#2980b9}input.no-focus:focus{border-color:#ccc !important}input[type="file"]:focus,input[type="radio"]:focus,input[type="checkbox"]:focus{outline:thin dotted #333;outline:1px auto #129fea}input[type="text"][disabled],input[type="password"][disabled],input[type="email"][disabled],input[type="url"][disabled],input[type="date"][disabled],input[type="month"][disabled],input[type="time"][disabled],input[type="datetime"][disabled],input[type="datetime-local"][disabled],input[type="week"][disabled],input[type="number"][disabled],input[type="search"][disabled],input[type="tel"][disabled],input[type="color"][disabled]{cursor:not-allowed;background-color:#f3f6f6;color:#cad2d3}input:focus:invalid,textarea:focus:invalid,select:focus:invalid{color:#e74c3c;border:1px solid #e74c3c}input:focus:invalid:focus,textarea:focus:invalid:focus,select:focus:invalid:focus{border-color:#e9322d}input[type="file"]:focus:invalid:focus,input[type="radio"]:focus:invalid:focus,input[type="checkbox"]:focus:invalid:focus{outline-color:#e9322d}input.wy-input-large{padding:12px;font-size:100%}textarea{overflow:auto;vertical-align:top;width:100%}select,textarea{padding:0.5em 0.625em;display:inline-block;border:1px solid #ccc;font-size:0.8em;box-shadow:inset 0 1px 3px #ddd;-webkit-transition:border 0.3s linear;-moz-transition:border 0.3s linear;transition:border 0.3s linear}select{border:1px solid #ccc;background-color:#fff}select[multiple]{height:auto}select:focus,textarea:focus{outline:0}select[disabled],textarea[disabled],input[readonly],select[readonly],textarea[readonly]{cursor:not-allowed;background-color:#fff;color:#cad2d3;border-color:transparent}.wy-checkbox,.wy-radio{margin:0.5em 0;color:#404040 !important;display:block}.wy-form-message-inline{display:inline-block;*display:inline;*zoom:1;vertical-align:middle}.wy-input-prefix,.wy-input-suffix{white-space:nowrap}.wy-input-prefix .wy-input-context,.wy-input-suffix .wy-input-context{padding:6px;display:inline-block;font-size:80%;background-color:#f3f6f6;border:solid 1px #ccc;color:#999}.wy-input-suffix .wy-input-context{border-left:0}.wy-input-prefix .wy-input-context{border-right:0}.wy-inline-validate{white-space:nowrap}.wy-inline-validate .wy-input-context{padding:0.5em 0.625em;display:inline-block;font-size:80%}.wy-inline-validate.wy-inline-validate-success .wy-input-context{color:#27ae60}.wy-inline-validate.wy-inline-validate-danger .wy-input-context{color:#e74c3c}.wy-inline-validate.wy-inline-validate-warning .wy-input-context{color:#e67e22}.wy-inline-validate.wy-inline-validate-info .wy-input-context{color:#2980b9}.wy-control-group{margin-bottom:24px;*zoom:1}.wy-control-group:before,.wy-control-group:after{display:table;content:""}.wy-control-group:after{clear:both}.wy-control-group.wy-control-group-error .wy-form-message,.wy-control-group.wy-control-group-error label{color:#e74c3c}.wy-control-group.wy-control-group-error input[type="text"],.wy-control-group.wy-control-group-error input[type="password"],.wy-control-group.wy-control-group-error input[type="email"],.wy-control-group.wy-control-group-error input[type="url"],.wy-control-group.wy-control-group-error input[type="date"],.wy-control-group.wy-control-group-error input[type="month"],.wy-control-group.wy-control-group-error input[type="time"],.wy-control-group.wy-control-group-error input[type="datetime"],.wy-control-group.wy-control-group-error input[type="datetime-local"],.wy-control-group.wy-control-group-error input[type="week"],.wy-control-group.wy-control-group-error input[type="number"],.wy-control-group.wy-control-group-error input[type="search"],.wy-control-group.wy-control-group-error input[type="tel"],.wy-control-group.wy-control-group-error input[type="color"]{border:solid 2px #e74c3c}.wy-control-group.wy-control-group-error textarea{border:solid 2px #e74c3c}.wy-control-group.fluid-input input[type="text"],.wy-control-group.fluid-input input[type="password"],.wy-control-group.fluid-input input[type="email"],.wy-control-group.fluid-input input[type="url"],.wy-control-group.fluid-input input[type="date"],.wy-control-group.fluid-input input[type="month"],.wy-control-group.fluid-input input[type="time"],.wy-control-group.fluid-input input[type="datetime"],.wy-control-group.fluid-input input[type="datetime-local"],.wy-control-group.fluid-input input[type="week"],.wy-control-group.fluid-input input[type="number"],.wy-control-group.fluid-input input[type="search"],.wy-control-group.fluid-input input[type="tel"],.wy-control-group.fluid-input input[type="color"]{width:100%}.wy-form-message-inline{display:inline-block;padding-left:0.3em;color:#666;vertical-align:middle;font-size:90%}.wy-form-message{display:block;color:#ccc;font-size:70%;margin-top:0.3125em;font-style:italic}.wy-tag-input-group{padding:4px 4px 0px 4px;display:inline-block;border:1px solid #ccc;font-size:80%;font-family:"Lato","proxima-nova","Helvetica Neue",Arial,sans-serif;box-shadow:inset 0 1px 3px #ddd;background:#fff;-webkit-transition:border 0.3s linear;-moz-transition:border 0.3s linear;transition:border 0.3s linear}.wy-tag-input-group .wy-tag{display:inline-block;background-color:rgba(0,0,0,0.1);padding:0.5em 0.625em;border-radius:2px;position:relative;margin-bottom:4px}.wy-tag-input-group .wy-tag .wy-tag-remove{color:#ccc;margin-left:5px}.wy-tag-input-group .wy-tag .wy-tag-remove:hover{color:#e74c3c}.wy-tag-input-group label{margin-left:5px;display:inline-block;margin-bottom:0}.wy-tag-input-group input{border:none;font-size:100%;margin-bottom:4px;box-shadow:none}.wy-form-upload{border:solid 1px #ccc;border-bottom:solid 3px #ccc;background-color:#fff;padding:24px;display:inline-block;text-align:center;cursor:pointer;color:#404040;-webkit-transition:border-color 0.1s ease-in;-moz-transition:border-color 0.1s ease-in;transition:border-color 0.1s ease-in;*zoom:1}.wy-form-upload:before,.wy-form-upload:after{display:table;content:""}.wy-form-upload:after{clear:both}@media screen and (max-width: 480px){.wy-form-upload{width:100%}}.wy-form-upload .image-drop{display:none}.wy-form-upload .image-desktop{display:none}.wy-form-upload .image-loading{display:none}.wy-form-upload .wy-form-upload-icon{display:block;font-size:32px;color:#b3b3b3}.wy-form-upload .image-drop .wy-form-upload-icon{color:#27ae60}.wy-form-upload p{font-size:90%}.wy-form-upload .wy-form-upload-image{float:left;margin-right:24px}@media screen and (max-width: 480px){.wy-form-upload .wy-form-upload-image{width:100%;margin-bottom:24px}}.wy-form-upload img{max-width:125px;max-height:125px;opacity:0.9;-webkit-transition:opacity 0.1s ease-in;-moz-transition:opacity 0.1s ease-in;transition:opacity 0.1s ease-in}.wy-form-upload .wy-form-upload-content{float:left}@media screen and (max-width: 480px){.wy-form-upload .wy-form-upload-content{width:100%}}.wy-form-upload:hover{border-color:#b3b3b3;color:#404040}.wy-form-upload:hover .image-desktop{display:block}.wy-form-upload:hover .image-drag{display:none}.wy-form-upload:hover img{opacity:1}.wy-form-upload:active{border-top:solid 3px #ccc;border-bottom:solid 1px #ccc}.wy-form-upload.wy-form-upload-big{width:100%;text-align:center;padding:72px}.wy-form-upload.wy-form-upload-big .wy-form-upload-content{float:none}.wy-form-upload.wy-form-upload-file p{margin-bottom:0}.wy-form-upload.wy-form-upload-file .wy-form-upload-icon{display:inline-block;font-size:inherit}.wy-form-upload.wy-form-upload-drop{background-color:#ddf7e8}.wy-form-upload.wy-form-upload-drop .image-drop{display:block}.wy-form-upload.wy-form-upload-drop .image-desktop{display:none}.wy-form-upload.wy-form-upload-drop .image-drag{display:none}.wy-form-upload.wy-form-upload-loading .image-drag{display:none}.wy-form-upload.wy-form-upload-loading .image-desktop{display:none}.wy-form-upload.wy-form-upload-loading .image-loading{display:block}.wy-form-upload.wy-form-upload-loading .wy-input-prefix{display:none}.wy-form-upload.wy-form-upload-loading p{margin-bottom:0}.rotate-90{-webkit-transform:rotate(90deg);-moz-transform:rotate(90deg);-ms-transform:rotate(90deg);-o-transform:rotate(90deg);transform:rotate(90deg)}.rotate-180{-webkit-transform:rotate(180deg);-moz-transform:rotate(180deg);-ms-transform:rotate(180deg);-o-transform:rotate(180deg);transform:rotate(180deg)}.rotate-270{-webkit-transform:rotate(270deg);-moz-transform:rotate(270deg);-ms-transform:rotate(270deg);-o-transform:rotate(270deg);transform:rotate(270deg)}.mirror{-webkit-transform:scaleX(-1);-moz-transform:scaleX(-1);-ms-transform:scaleX(-1);-o-transform:scaleX(-1);transform:scaleX(-1)}.mirror.rotate-90{-webkit-transform:scaleX(-1) rotate(90deg);-moz-transform:scaleX(-1) rotate(90deg);-ms-transform:scaleX(-1) rotate(90deg);-o-transform:scaleX(-1) rotate(90deg);transform:scaleX(-1) rotate(90deg)}.mirror.rotate-180{-webkit-transform:scaleX(-1) rotate(180deg);-moz-transform:scaleX(-1) rotate(180deg);-ms-transform:scaleX(-1) rotate(180deg);-o-transform:scaleX(-1) rotate(180deg);transform:scaleX(-1) rotate(180deg)}.mirror.rotate-270{-webkit-transform:scaleX(-1) rotate(270deg);-moz-transform:scaleX(-1) rotate(270deg);-ms-transform:scaleX(-1) rotate(270deg);-o-transform:scaleX(-1) rotate(270deg);transform:scaleX(-1) rotate(270deg)}.wy-form-gallery-manage{margin-left:-12px;margin-right:-12px}.wy-form-gallery-manage li{float:left;padding:12px;width:20%;cursor:pointer}@media screen and (max-width: 768px){.wy-form-gallery-manage li{width:25%}}@media screen and (max-width: 480px){.wy-form-gallery-manage li{width:50%}}.wy-form-gallery-manage li:active{cursor:move}.wy-form-gallery-manage li>a{padding:12px;background-color:#fff;border:solid 1px #e1e4e5;border-bottom:solid 3px #e1e4e5;display:inline-block;-webkit-transition:all 0.1s ease-in;-moz-transition:all 0.1s ease-in;transition:all 0.1s ease-in}.wy-form-gallery-manage li>a:active{border:solid 1px #ccc;border-top:solid 3px #ccc}.wy-form-gallery-manage img{width:100%;-webkit-transition:all 0.05s ease-in;-moz-transition:all 0.05s ease-in;transition:all 0.05s ease-in}li.wy-form-gallery-edit{position:relative;color:#fff;padding:24px;width:100%;display:block;background-color:#343131;border-radius:4px}li.wy-form-gallery-edit .arrow{position:absolute;display:block;top:-50px;left:50%;margin-left:-25px;z-index:500;height:0;width:0;border-color:transparent;border-style:solid;border-width:25px;border-bottom-color:#343131}@media only screen and (max-width: 480px){.wy-form button[type="submit"]{margin:0.7em 0 0}.wy-form input[type="text"],.wy-form input[type="password"],.wy-form input[type="email"],.wy-form input[type="url"],.wy-form input[type="date"],.wy-form input[type="month"],.wy-form input[type="time"],.wy-form input[type="datetime"],.wy-form input[type="datetime-local"],.wy-form input[type="week"],.wy-form input[type="number"],.wy-form input[type="search"],.wy-form input[type="tel"],.wy-form input[type="color"]{margin-bottom:0.3em;display:block}.wy-form label{margin-bottom:0.3em;display:block}.wy-form input[type="password"],.wy-form input[type="email"],.wy-form input[type="url"],.wy-form input[type="date"],.wy-form input[type="month"],.wy-form input[type="time"],.wy-form input[type="datetime"],.wy-form input[type="datetime-local"],.wy-form input[type="week"],.wy-form input[type="number"],.wy-form input[type="search"],.wy-form input[type="tel"],.wy-form input[type="color"]{margin-bottom:0}.wy-form-aligned .wy-control-group label{margin-bottom:0.3em;text-align:left;display:block;width:100%}.wy-form-aligned .wy-controls{margin:1.5em 0 0 0}.wy-form .wy-help-inline,.wy-form-message-inline,.wy-form-message{display:block;font-size:80%;padding:0.2em 0 0.8em}}@media screen and (max-width: 768px){.tablet-hide{display:none}}@media screen and (max-width: 480px){.mobile-hide{display:none}}.float-left{float:left}.float-right{float:right}.full-width{width:100%}.wy-grid-one-col{*zoom:1;max-width:68em;margin-left:auto;margin-right:auto;max-width:1066px;margin-top:1.618em}.wy-grid-one-col:before,.wy-grid-one-col:after{display:table;content:""}.wy-grid-one-col:after{clear:both}.wy-grid-one-col section{display:block;float:left;margin-right:2.35765%;width:100%;background:#fcfcfc;padding:1.618em;margin-right:0}.wy-grid-one-col section:last-child{margin-right:0}.wy-grid-index-card{*zoom:1;max-width:68em;margin-left:auto;margin-right:auto;max-width:460px;margin-top:1.618em;background:#fcfcfc;padding:1.618em}.wy-grid-index-card:before,.wy-grid-index-card:after{display:table;content:""}.wy-grid-index-card:after{clear:both}.wy-grid-index-card header,.wy-grid-index-card section,.wy-grid-index-card aside{display:block;float:left;margin-right:2.35765%;width:100%}.wy-grid-index-card header:last-child,.wy-grid-index-card section:last-child,.wy-grid-index-card aside:last-child{margin-right:0}.wy-grid-index-card.twocol{max-width:768px}.wy-grid-index-card.twocol section{display:block;float:left;margin-right:2.35765%;width:48.82117%}.wy-grid-index-card.twocol section:last-child{margin-right:0}.wy-grid-index-card.twocol aside{display:block;float:left;margin-right:2.35765%;width:48.82117%}.wy-grid-index-card.twocol aside:last-child{margin-right:0}.wy-grid-search-filter{*zoom:1;max-width:68em;margin-left:auto;margin-right:auto;margin-bottom:24px}.wy-grid-search-filter:before,.wy-grid-search-filter:after{display:table;content:""}.wy-grid-search-filter:after{clear:both}.wy-grid-search-filter .wy-grid-search-filter-input{display:block;float:left;margin-right:2.35765%;width:74.41059%}.wy-grid-search-filter .wy-grid-search-filter-input:last-child{margin-right:0}.wy-grid-search-filter .wy-grid-search-filter-btn{display:block;float:left;margin-right:2.35765%;width:23.23176%}.wy-grid-search-filter .wy-grid-search-filter-btn:last-child{margin-right:0}.wy-table,.rst-content table.docutils,.rst-content table.field-list{border-collapse:collapse;border-spacing:0;empty-cells:show;margin-bottom:24px}.wy-table caption,.rst-content table.docutils caption,.rst-content table.field-list caption{color:#000;font:italic 85%/1 arial,sans-serif;padding:1em 0;text-align:center}.wy-table td,.rst-content table.docutils td,.rst-content table.field-list td,.wy-table th,.rst-content table.docutils th,.rst-content table.field-list th{font-size:90%;margin:0;overflow:visible;padding:8px 16px}.wy-table td:first-child,.rst-content table.docutils td:first-child,.rst-content table.field-list td:first-child,.wy-table th:first-child,.rst-content table.docutils th:first-child,.rst-content table.field-list th:first-child{border-left-width:0}.wy-table thead,.rst-content table.docutils thead,.rst-content table.field-list thead{color:#000;text-align:left;vertical-align:bottom;white-space:nowrap}.wy-table thead th,.rst-content table.docutils thead th,.rst-content table.field-list thead th{font-weight:bold;border-bottom:solid 2px #e1e4e5}.wy-table td,.rst-content table.docutils td,.rst-content table.field-list td{background-color:transparent;vertical-align:middle}.wy-table td p,.rst-content table.docutils td p,.rst-content table.field-list td p{line-height:18px;margin-bottom:0}.wy-table .wy-table-cell-min,.rst-content table.docutils .wy-table-cell-min,.rst-content table.field-list .wy-table-cell-min{width:1%;padding-right:0}.wy-table .wy-table-cell-min input[type=checkbox],.rst-content table.docutils .wy-table-cell-min input[type=checkbox],.rst-content table.field-list .wy-table-cell-min input[type=checkbox],.wy-table .wy-table-cell-min input[type=checkbox],.rst-content table.docutils .wy-table-cell-min input[type=checkbox],.rst-content table.field-list .wy-table-cell-min input[type=checkbox]{margin:0}.wy-table-secondary{color:gray;font-size:90%}.wy-table-tertiary{color:gray;font-size:80%}.wy-table-odd td,.wy-table-striped tr:nth-child(2n-1) td,.rst-content table.docutils:not(.field-list) tr:nth-child(2n-1) td{background-color:#f3f6f6}.wy-table-backed{background-color:#f3f6f6}.wy-table-bordered-all,.rst-content table.docutils{border:1px solid #e1e4e5}.wy-table-bordered-all td,.rst-content table.docutils td{border-bottom:1px solid #e1e4e5;border-left:1px solid #e1e4e5}.wy-table-bordered-all tbody>tr:last-child td,.rst-content table.docutils tbody>tr:last-child td{border-bottom-width:0}.wy-table-bordered{border:1px solid #e1e4e5}.wy-table-bordered-rows td{border-bottom:1px solid #e1e4e5}.wy-table-bordered-rows tbody>tr:last-child td{border-bottom-width:0}.wy-table-horizontal tbody>tr:last-child td{border-bottom-width:0}.wy-table-horizontal td,.wy-table-horizontal th{border-width:0 0 1px 0;border-bottom:1px solid #e1e4e5}.wy-table-horizontal tbody>tr:last-child td{border-bottom-width:0}.wy-table-responsive{margin-bottom:24px;max-width:100%;overflow:auto}.wy-table-responsive table{margin-bottom:0 !important}.wy-table-responsive table td,.wy-table-responsive table th{white-space:nowrap}html{height:100%;overflow-x:hidden}body{font-family:"Lato","proxima-nova","Helvetica Neue",Arial,sans-serif;font-weight:normal;color:#404040;min-height:100%;overflow-x:hidden;background:#edf0f2}a{color:#2980b9;text-decoration:none}a:hover{color:#3091d1}.link-danger{color:#e74c3c}.link-danger:hover{color:#d62c1a}.text-left{text-align:left}.text-center{text-align:center}.text-right{text-align:right}h1,h2,h3,h4,h5,h6,legend{margin-top:0;font-weight:700;font-family:"Roboto Slab","ff-tisa-web-pro","Georgia",Arial,sans-serif}p{line-height:24px;margin:0;font-size:16px;margin-bottom:24px}h1{font-size:175%}h2{font-size:150%}h3{font-size:125%}h4{font-size:115%}h5{font-size:110%}h6{font-size:100%}small{font-size:80%}code,.rst-content tt{white-space:nowrap;max-width:100%;background:#fff;border:solid 1px #e1e4e5;font-size:75%;padding:0 5px;font-family:"Incosolata","Consolata","Monaco",monospace;color:#e74c3c;overflow-x:auto}code.code-large,.rst-content tt.code-large{font-size:90%}.full-width{width:100%}.wy-plain-list-disc,.rst-content .section ul,.rst-content .toctree-wrapper ul{list-style:disc;line-height:24px;margin-bottom:24px}.wy-plain-list-disc li,.rst-content .section ul li,.rst-content .toctree-wrapper ul li{list-style:disc;margin-left:24px}.wy-plain-list-disc li ul,.rst-content .section ul li ul,.rst-content .toctree-wrapper ul li ul{margin-bottom:0}.wy-plain-list-disc li li,.rst-content .section ul li li,.rst-content .toctree-wrapper ul li li{list-style:circle}.wy-plain-list-disc li li li,.rst-content .section ul li li li,.rst-content .toctree-wrapper ul li li li{list-style:square}.wy-plain-list-decimal,.rst-content .section ol,.rst-content ol.arabic{list-style:decimal;line-height:24px;margin-bottom:24px}.wy-plain-list-decimal li,.rst-content .section ol li,.rst-content ol.arabic li{list-style:decimal;margin-left:24px}.wy-type-large{font-size:120%}.wy-type-normal{font-size:100%}.wy-type-small{font-size:100%}.wy-type-strike{text-decoration:line-through}.wy-text-warning{color:#e67e22 !important}a.wy-text-warning:hover{color:#eb9950 !important}.wy-text-info{color:#2980b9 !important}a.wy-text-info:hover{color:#409ad5 !important}.wy-text-success{color:#27ae60 !important}a.wy-text-success:hover{color:#36d278 !important}.wy-text-danger{color:#e74c3c !important}a.wy-text-danger:hover{color:#ed7669 !important}.wy-text-neutral{color:#404040 !important}a.wy-text-neutral:hover{color:#595959 !important}.codeblock-example{border:1px solid #e1e4e5;border-bottom:none;padding:24px;padding-top:48px;font-weight:500;background:#fff;position:relative}.codeblock-example:after{content:"Example";position:absolute;top:0px;left:0px;background:#9b59b6;color:#fff;padding:6px 12px}.codeblock-example.prettyprint-example-only{border:1px solid #e1e4e5;margin-bottom:24px}.codeblock,.rst-content .literal-block,div[class^='highlight']{border:1px solid #e1e4e5;padding:0px;overflow-x:auto;background:#fff;margin:1px 0 24px 0}.codeblock div[class^='highlight'],.rst-content .literal-block div[class^='highlight'],div[class^='highlight'] div[class^='highlight']{border:none;background:none;margin:0}div[class^='highlight'] td.code{width:100%}.linenodiv pre{border-right:solid 1px #e6e9ea;margin:0;padding:12px 12px;font-family:"Incosolata","Consolata","Monaco",monospace;font-size:12px;line-height:1.5;color:#d9d9d9}div[class^='highlight'] pre{white-space:pre;margin:0;padding:12px 12px;font-family:"Incosolata","Consolata","Monaco",monospace;font-size:12px;line-height:1.5;display:block;overflow:auto;color:#404040}pre.literal-block{@extends .codeblock;}@media print{.codeblock,.rst-content .literal-block,div[class^='highlight'],div[class^='highlight'] pre{white-space:pre-wrap}}.hll{background-color:#ffc;margin:0 -12px;padding:0 12px;display:block}.c{color:#998;font-style:italic}.err{color:#a61717;background-color:#e3d2d2}.k{font-weight:bold}.o{font-weight:bold}.cm{color:#998;font-style:italic}.cp{color:#999;font-weight:bold}.c1{color:#998;font-style:italic}.cs{color:#999;font-weight:bold;font-style:italic}.gd{color:#000;background-color:#fdd}.gd .x{color:#000;background-color:#faa}.ge{font-style:italic}.gr{color:#a00}.gh{color:#999}.gi{color:#000;background-color:#dfd}.gi .x{color:#000;background-color:#afa}.go{color:#888}.gp{color:#555}.gs{font-weight:bold}.gu{color:purple;font-weight:bold}.gt{color:#a00}.kc{font-weight:bold}.kd{font-weight:bold}.kn{font-weight:bold}.kp{font-weight:bold}.kr{font-weight:bold}.kt{color:#458;font-weight:bold}.m{color:#099}.s{color:#d14}.n{color:#333}.na{color:teal}.nb{color:#0086b3}.nc{color:#458;font-weight:bold}.no{color:teal}.ni{color:purple}.ne{color:#900;font-weight:bold}.nf{color:#900;font-weight:bold}.nn{color:#555}.nt{color:navy}.nv{color:teal}.ow{font-weight:bold}.w{color:#bbb}.mf{color:#099}.mh{color:#099}.mi{color:#099}.mo{color:#099}.sb{color:#d14}.sc{color:#d14}.sd{color:#d14}.s2{color:#d14}.se{color:#d14}.sh{color:#d14}.si{color:#d14}.sx{color:#d14}.sr{color:#009926}.s1{color:#d14}.ss{color:#990073}.bp{color:#999}.vc{color:teal}.vg{color:teal}.vi{color:teal}.il{color:#099}.gc{color:#999;background-color:#eaf2f5}.wy-breadcrumbs li{display:inline-block}.wy-breadcrumbs li.wy-breadcrumbs-aside{float:right}.wy-breadcrumbs li a{display:inline-block;padding:5px}.wy-breadcrumbs li a:first-child{padding-left:0}.wy-breadcrumbs-extra{margin-bottom:0;color:#b3b3b3;font-size:80%;display:inline-block}@media screen and (max-width: 480px){.wy-breadcrumbs-extra{display:none}.wy-breadcrumbs li.wy-breadcrumbs-aside{display:none}}@media print{.wy-breadcrumbs li.wy-breadcrumbs-aside{display:none}}.wy-affix{position:fixed;top:1.618em}.wy-menu a:hover{text-decoration:none}.wy-menu-horiz{*zoom:1}.wy-menu-horiz:before,.wy-menu-horiz:after{display:table;content:""}.wy-menu-horiz:after{clear:both}.wy-menu-horiz ul,.wy-menu-horiz li{display:inline-block}.wy-menu-horiz li:hover{background:rgba(255,255,255,0.1)}.wy-menu-horiz li.divide-left{border-left:solid 1px #404040}.wy-menu-horiz li.divide-right{border-right:solid 1px #404040}.wy-menu-horiz a{height:32px;display:inline-block;line-height:32px;padding:0 16px}.wy-menu-vertical header{height:32px;display:inline-block;line-height:32px;padding:0 1.618em;display:block;font-weight:bold;text-transform:uppercase;font-size:80%;color:#2980b9;white-space:nowrap}.wy-menu-vertical ul{margin-bottom:0}.wy-menu-vertical li.divide-top{border-top:solid 1px #404040}.wy-menu-vertical li.divide-bottom{border-bottom:solid 1px #404040}.wy-menu-vertical li.current{background:#e3e3e3}.wy-menu-vertical li.current a{color:gray;border-right:solid 1px #c9c9c9;padding:0.4045em 2.427em}.wy-menu-vertical li.current a:hover{background:#d6d6d6}.wy-menu-vertical li.on a,.wy-menu-vertical li.current>a{color:#404040;padding:0.4045em 1.618em;font-weight:bold;position:relative;background:#fcfcfc;border:none;border-bottom:solid 1px #c9c9c9;border-top:solid 1px #c9c9c9;padding-left:1.618em -4px}.wy-menu-vertical li.on a:hover,.wy-menu-vertical li.current>a:hover{background:#fcfcfc}.wy-menu-vertical li.toctree-l2.current>a{background:#c9c9c9;padding:0.4045em 2.427em}.wy-menu-vertical li.current ul{display:block}.wy-menu-vertical li ul{margin-bottom:0;display:none}.wy-menu-vertical .local-toc li ul{display:block}.wy-menu-vertical li ul li a{margin-bottom:0;color:#b3b3b3;font-weight:normal}.wy-menu-vertical a{display:inline-block;line-height:18px;padding:0.4045em 1.618em;display:block;position:relative;font-size:90%;color:#b3b3b3}.wy-menu-vertical a:hover{background-color:#4e4a4a;cursor:pointer}.wy-menu-vertical a:active{background-color:#2980b9;cursor:pointer;color:#fff}.wy-side-nav-search{z-index:200;background-color:#2980b9;text-align:center;padding:0.809em;display:block;color:#fcfcfc;margin-bottom:0.809em}.wy-side-nav-search input[type=text]{width:100%;border-radius:50px;padding:6px 12px;border-color:#2472a4}.wy-side-nav-search img{display:block;margin:auto auto 0.809em auto;height:45px;width:45px;background-color:#2980b9;padding:5px;border-radius:100%}.wy-side-nav-search>a,.wy-side-nav-search .wy-dropdown>a{color:#fcfcfc;font-size:100%;font-weight:bold;display:inline-block;padding:4px 6px;margin-bottom:0.809em}.wy-side-nav-search>a:hover,.wy-side-nav-search .wy-dropdown>a:hover{background:rgba(255,255,255,0.1)}.wy-nav .wy-menu-vertical header{color:#2980b9}.wy-nav .wy-menu-vertical a{color:#b3b3b3}.wy-nav .wy-menu-vertical a:hover{background-color:#2980b9;color:#fff}[data-menu-wrap]{-webkit-transition:all 0.2s ease-in;-moz-transition:all 0.2s ease-in;transition:all 0.2s ease-in;position:absolute;opacity:1;width:100%;opacity:0}[data-menu-wrap].move-center{left:0;right:auto;opacity:1}[data-menu-wrap].move-left{right:auto;left:-100%;opacity:0}[data-menu-wrap].move-right{right:-100%;left:auto;opacity:0}.wy-body-for-nav{background:left repeat-y #fcfcfc;background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAIAAACQd1PeAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyRpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMy1jMDExIDY2LjE0NTY2MSwgMjAxMi8wMi8wNi0xNDo1NjoyNyAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNiAoTWFjaW50b3NoKSIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDoxOERBMTRGRDBFMUUxMUUzODUwMkJCOThDMEVFNURFMCIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDoxOERBMTRGRTBFMUUxMUUzODUwMkJCOThDMEVFNURFMCI+IDx4bXBNTTpEZXJpdmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSJ4bXAuaWlkOjE4REExNEZCMEUxRTExRTM4NTAyQkI5OEMwRUU1REUwIiBzdFJlZjpkb2N1bWVudElEPSJ4bXAuZGlkOjE4REExNEZDMEUxRTExRTM4NTAyQkI5OEMwRUU1REUwIi8+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+EwrlwAAAAA5JREFUeNpiMDU0BAgwAAE2AJgB9BnaAAAAAElFTkSuQmCC);background-size:300px 1px}.wy-grid-for-nav{position:absolute;width:100%;height:100%}.wy-nav-side{position:absolute;top:0;left:0;width:300px;overflow:hidden;min-height:100%;background:#343131;z-index:200}.wy-nav-top{display:none;background:#2980b9;color:#fff;padding:0.4045em 0.809em;position:relative;line-height:50px;text-align:center;font-size:100%;*zoom:1}.wy-nav-top:before,.wy-nav-top:after{display:table;content:""}.wy-nav-top:after{clear:both}.wy-nav-top a{color:#fff;font-weight:bold}.wy-nav-top img{margin-right:12px;height:45px;width:45px;background-color:#2980b9;padding:5px;border-radius:100%}.wy-nav-top i{font-size:30px;float:left;cursor:pointer}.wy-nav-content-wrap{margin-left:300px;background:#fcfcfc;min-height:100%}.wy-nav-content{padding:1.618em 3.236em;height:100%;max-width:800px;margin:auto}.wy-body-mask{position:fixed;width:100%;height:100%;background:rgba(0,0,0,0.2);display:none;z-index:499}.wy-body-mask.on{display:block}footer{color:#999}footer p{margin-bottom:12px}.rst-footer-buttons{*zoom:1}.rst-footer-buttons:before,.rst-footer-buttons:after{display:table;content:""}.rst-footer-buttons:after{clear:both}#search-results .search li{margin-bottom:24px;border-bottom:solid 1px #e1e4e5;padding-bottom:24px}#search-results .search li:first-child{border-top:solid 1px #e1e4e5;padding-top:24px}#search-results .search li a{font-size:120%;margin-bottom:12px;display:inline-block}#search-results .context{color:gray;font-size:90%}@media screen and (max-width: 768px){.wy-body-for-nav{background:#fcfcfc}.wy-nav-top{display:block}.wy-nav-side{left:-300px}.wy-nav-side.shift{width:85%;left:0}.wy-nav-content-wrap{margin-left:0}.wy-nav-content-wrap .wy-nav-content{padding:1.618em}.wy-nav-content-wrap.shift{position:fixed;min-width:100%;left:85%;top:0;height:100%;overflow:hidden}}@media screen and (min-width: 1400px){.wy-nav-content-wrap{background:rgba(0,0,0,0.05)}.wy-nav-content{margin:0;background:#fcfcfc}}@media print{.wy-nav-side{display:none}.wy-nav-content-wrap{margin-left:0}}nav.stickynav{position:fixed;top:0}.rst-versions{position:fixed;bottom:0;left:0;width:300px;color:#fcfcfc;background:#1f1d1d;border-top:solid 10px #343131;font-family:"Lato","proxima-nova","Helvetica Neue",Arial,sans-serif;z-index:400}.rst-versions a{color:#2980b9;text-decoration:none}.rst-versions .rst-badge-small{display:none}.rst-versions .rst-current-version{padding:12px;background-color:#272525;display:block;text-align:right;font-size:90%;cursor:pointer;color:#27ae60;*zoom:1}.rst-versions .rst-current-version:before,.rst-versions .rst-current-version:after{display:table;content:""}.rst-versions .rst-current-version:after{clear:both}.rst-versions .rst-current-version .icon,.rst-versions .rst-current-version .wy-inline-validate.wy-inline-validate-success .wy-input-context,.wy-inline-validate.wy-inline-validate-success .rst-versions .rst-current-version .wy-input-context,.rst-versions .rst-current-version .wy-inline-validate.wy-inline-validate-danger .wy-input-context,.wy-inline-validate.wy-inline-validate-danger .rst-versions .rst-current-version .wy-input-context,.rst-versions .rst-current-version .wy-inline-validate.wy-inline-validate-warning .wy-input-context,.wy-inline-validate.wy-inline-validate-warning .rst-versions .rst-current-version .wy-input-context,.rst-versions .rst-current-version .wy-inline-validate.wy-inline-validate-info .wy-input-context,.wy-inline-validate.wy-inline-validate-info .rst-versions .rst-current-version .wy-input-context,.rst-versions .rst-current-version .wy-tag-input-group .wy-tag .wy-tag-remove,.wy-tag-input-group .wy-tag .rst-versions .rst-current-version .wy-tag-remove,.rst-versions .rst-current-version .rst-content .admonition-title,.rst-content .rst-versions .rst-current-version .admonition-title,.rst-versions .rst-current-version .rst-content h1 .headerlink,.rst-content h1 .rst-versions .rst-current-version .headerlink,.rst-versions .rst-current-version .rst-content h2 .headerlink,.rst-content h2 .rst-versions .rst-current-version .headerlink,.rst-versions .rst-current-version .rst-content h3 .headerlink,.rst-content h3 .rst-versions .rst-current-version .headerlink,.rst-versions .rst-current-version .rst-content h4 .headerlink,.rst-content h4 .rst-versions .rst-current-version .headerlink,.rst-versions .rst-current-version .rst-content h5 .headerlink,.rst-content h5 .rst-versions .rst-current-version .headerlink,.rst-versions .rst-current-version .rst-content h6 .headerlink,.rst-content h6 .rst-versions .rst-current-version .headerlink,.rst-versions .rst-current-version .rst-content dl dt .headerlink,.rst-content dl dt .rst-versions .rst-current-version .headerlink{color:#fcfcfc}.rst-versions .rst-current-version .icon-book{float:left}.rst-versions .rst-current-version.rst-out-of-date{background-color:#e74c3c;color:#fff}.rst-versions .rst-current-version.rst-active-old-version{background-color:#f1c40f;color:#000}.rst-versions.shift-up .rst-other-versions{display:block}.rst-versions .rst-other-versions{font-size:90%;padding:12px;color:gray;display:none}.rst-versions .rst-other-versions hr{display:block;height:1px;border:0;margin:20px 0;padding:0;border-top:solid 1px #413d3d}.rst-versions .rst-other-versions dd{display:inline-block;margin:0}.rst-versions .rst-other-versions dd a{display:inline-block;padding:6px;color:#fcfcfc}.rst-versions.rst-badge{width:auto;bottom:20px;right:20px;left:auto;border:none;max-width:300px}.rst-versions.rst-badge .icon-book{float:none}.rst-versions.rst-badge.shift-up .rst-current-version{text-align:right}.rst-versions.rst-badge.shift-up .rst-current-version .icon-book{float:left}.rst-versions.rst-badge .rst-current-version{width:auto;height:30px;line-height:30px;padding:0 6px;display:block;text-align:center}@media screen and (max-width: 768px){.rst-versions{width:85%;display:none}.rst-versions.shift{display:block}img{width:100%;height:auto}}.rst-content img{max-width:100%;height:auto !important}.rst-content .section>img{margin-bottom:24px}.rst-content blockquote{margin-left:24px;line-height:24px;margin-bottom:24px}.rst-content .note .last,.rst-content .attention .last,.rst-content .caution .last,.rst-content .danger .last,.rst-content .error .last,.rst-content .hint .last,.rst-content .important .last,.rst-content .tip .last,.rst-content .warning .last,.rst-content .seealso .last{margin-bottom:0}.rst-content .admonition-title:before{margin-right:4px}.rst-content .admonition table{border-color:rgba(0,0,0,0.1)}.rst-content .admonition table td,.rst-content .admonition table th{background:transparent !important;border-color:rgba(0,0,0,0.1) !important}.rst-content .section ol.loweralpha,.rst-content .section ol.loweralpha li{list-style:lower-alpha}.rst-content .section ol.upperalpha,.rst-content .section ol.upperalpha li{list-style:upper-alpha}.rst-content .section ol p,.rst-content .section ul p{margin-bottom:12px}.rst-content .line-block{margin-left:24px}.rst-content .topic-title{font-weight:bold;margin-bottom:12px}.rst-content .toc-backref{color:#404040}.rst-content .align-right{float:right;margin:0px 0px 24px 24px}.rst-content .align-left{float:left;margin:0px 24px 24px 0px}.rst-content .align-center{margin:auto;display:block}.rst-content h1 .headerlink,.rst-content h2 .headerlink,.rst-content h3 .headerlink,.rst-content h4 .headerlink,.rst-content h5 .headerlink,.rst-content h6 .headerlink,.rst-content dl dt .headerlink{display:none;visibility:hidden;font-size:14px}.rst-content h1 .headerlink:after,.rst-content h2 .headerlink:after,.rst-content h3 .headerlink:after,.rst-content h4 .headerlink:after,.rst-content h5 .headerlink:after,.rst-content h6 .headerlink:after,.rst-content dl dt .headerlink:after{visibility:visible;content:"\f0c1";font-family:fontawesome-webfont;display:inline-block}.rst-content h1:hover .headerlink,.rst-content h2:hover .headerlink,.rst-content h3:hover .headerlink,.rst-content h4:hover .headerlink,.rst-content h5:hover .headerlink,.rst-content h6:hover .headerlink,.rst-content dl dt:hover .headerlink{display:inline-block}.rst-content .sidebar{float:right;width:40%;display:block;margin:0 0 24px 24px;padding:24px;background:#f3f6f6;border:solid 1px #e1e4e5}.rst-content .sidebar p,.rst-content .sidebar ul,.rst-content .sidebar dl{font-size:90%}.rst-content .sidebar .last{margin-bottom:0}.rst-content .sidebar .sidebar-title{display:block;font-family:"Roboto Slab","ff-tisa-web-pro","Georgia",Arial,sans-serif;font-weight:bold;background:#e1e4e5;padding:6px 12px;margin:-24px;margin-bottom:24px;font-size:100%}.rst-content .highlighted{background:#f1c40f;display:inline-block;font-weight:bold;padding:0 6px}.rst-content .footnote-reference,.rst-content .citation-reference{vertical-align:super;font-size:90%}.rst-content table.docutils.citation,.rst-content table.docutils.footnote{background:none;border:none;color:#999}.rst-content table.docutils.citation td,.rst-content table.docutils.citation tr,.rst-content table.docutils.footnote td,.rst-content table.docutils.footnote tr{border:none;background-color:transparent !important;white-space:normal}.rst-content table.docutils.citation td.label,.rst-content table.docutils.footnote td.label{padding-left:0;padding-right:0;vertical-align:top}.rst-content table.field-list{border:none}.rst-content table.field-list td{border:none;padding-top:5px}.rst-content table.field-list .field-name{padding-right:10px;text-align:left;white-space:nowrap}.rst-content table.field-list .field-body{text-align:left;padding-left:0}.rst-content tt{color:#000}.rst-content tt big,.rst-content tt em{font-size:100% !important;line-height:normal}.rst-content tt .xref,a .rst-content tt{font-weight:bold}.rst-content dl{margin-bottom:24px}.rst-content dl dt{font-weight:bold}.rst-content dl p,.rst-content dl table,.rst-content dl ul,.rst-content dl ol{margin-bottom:12px !important}.rst-content dl dd{margin:0 0 12px 24px}.rst-content dl:not(.docutils){margin-bottom:24px}.rst-content dl:not(.docutils) dt{display:inline-block;margin:6px 0;font-size:90%;line-height:normal;background:#e7f2fa;color:#2980b9;border-top:solid 3px #6ab0de;padding:6px;position:relative}.rst-content dl:not(.docutils) dt:before{color:#6ab0de}.rst-content dl:not(.docutils) dt .headerlink{color:#404040;font-size:100% !important}.rst-content dl:not(.docutils) dl dt{margin-bottom:6px;border:none;border-left:solid 3px #ccc;background:#f0f0f0;color:gray}.rst-content dl:not(.docutils) dl dt .headerlink{color:#404040;font-size:100% !important}.rst-content dl:not(.docutils) dt:first-child{margin-top:0}.rst-content dl:not(.docutils) tt{font-weight:bold}.rst-content dl:not(.docutils) tt.descname,.rst-content dl:not(.docutils) tt.descclassname{background-color:transparent;border:none;padding:0;font-size:100% !important}.rst-content dl:not(.docutils) tt.descname{font-weight:bold}.rst-content dl:not(.docutils) .optional{display:inline-block;padding:0 4px;color:#000;font-weight:bold}.rst-content dl:not(.docutils) .property{display:inline-block;padding-right:8px}.rst-content .viewcode-link,.rst-content .viewcode-back{display:inline-block;color:#27ae60;font-size:80%;padding-left:24px}.rst-content .viewcode-back{display:block;float:right}@media screen and (max-width: 480px){.rst-content .sidebar{width:100%}}span[id*='MathJax-Span']{color:#404040}
diff --git a/manual/_theme/static/font/fontawesome_webfont.eot b/manual/_theme/static/font/fontawesome_webfont.eot
deleted file mode 100644
index 0662cb96..00000000
Binary files a/manual/_theme/static/font/fontawesome_webfont.eot and /dev/null differ
diff --git a/manual/_theme/static/font/fontawesome_webfont.svg b/manual/_theme/static/font/fontawesome_webfont.svg
deleted file mode 100644
index 2edb4ec3..00000000
--- a/manual/_theme/static/font/fontawesome_webfont.svg
+++ /dev/null
@@ -1,399 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/manual/_theme/static/font/fontawesome_webfont.ttf b/manual/_theme/static/font/fontawesome_webfont.ttf
deleted file mode 100644
index d3659246..00000000
Binary files a/manual/_theme/static/font/fontawesome_webfont.ttf and /dev/null differ
diff --git a/manual/_theme/static/font/fontawesome_webfont.woff b/manual/_theme/static/font/fontawesome_webfont.woff
deleted file mode 100644
index b9bd17e1..00000000
Binary files a/manual/_theme/static/font/fontawesome_webfont.woff and /dev/null differ
diff --git a/manual/_theme/static/js/theme.js b/manual/_theme/static/js/theme.js
deleted file mode 100644
index 60520cc3..00000000
--- a/manual/_theme/static/js/theme.js
+++ /dev/null
@@ -1,47 +0,0 @@
-$( document ).ready(function() {
- // Shift nav in mobile when clicking the menu.
- $(document).on('click', "[data-toggle='wy-nav-top']", function() {
- $("[data-toggle='wy-nav-shift']").toggleClass("shift");
- $("[data-toggle='rst-versions']").toggleClass("shift");
- });
- // Close menu when you click a link.
- $(document).on('click', ".wy-menu-vertical .current ul li a", function() {
- $("[data-toggle='wy-nav-shift']").removeClass("shift");
- $("[data-toggle='rst-versions']").toggleClass("shift");
- });
- $(document).on('click', "[data-toggle='rst-current-version']", function() {
- $("[data-toggle='rst-versions']").toggleClass("shift-up");
- });
- // Make tables responsive
- $("table.docutils:not(.field-list)").wrap("
");
-});
-
-window.SphinxRtdTheme = (function (jquery) {
- var stickyNav = (function () {
- var navBar,
- win,
- stickyNavCssClass = 'stickynav',
- applyStickNav = function () {
- if (navBar.height() <= win.height()) {
- navBar.addClass(stickyNavCssClass);
- } else {
- navBar.removeClass(stickyNavCssClass);
- }
- },
- enable = function () {
- applyStickNav();
- win.on('resize', applyStickNav);
- },
- init = function () {
- navBar = jquery('nav.wy-nav-side:first');
- win = jquery(window);
- };
- jquery(init);
- return {
- enable : enable
- };
- }());
- return {
- StickyNav : stickyNav
- };
-}($));
diff --git a/manual/_theme/theme.conf b/manual/_theme/theme.conf
deleted file mode 100644
index dcfbf8c2..00000000
--- a/manual/_theme/theme.conf
+++ /dev/null
@@ -1,8 +0,0 @@
-[theme]
-inherit = basic
-stylesheet = css/theme.css
-
-[options]
-typekit_id = hiw1hhg
-analytics_id =
-sticky_navigation = False
diff --git a/manual/_theme/versions.html b/manual/_theme/versions.html
deleted file mode 100644
index c131c9fc..00000000
--- a/manual/_theme/versions.html
+++ /dev/null
@@ -1,37 +0,0 @@
-{% if READTHEDOCS %}
-{# Add rst-badge after rst-versions for small badge style. #}
-
-
- Read the Docs
- v: {{ current_version }}
-
-
-
-
- Versions
- {% for slug, url in versions %}
- {{ slug }}
- {% endfor %}
-
-
- Downloads
- {% for type, url in downloads %}
- {{ type }}
- {% endfor %}
-
-
- On Read the Docs
-
- Project Home
-
-
- Builds
-
-
-
- Free document hosting provided by
Read the Docs .
-
-
-
-{% endif %}
-
diff --git a/manual/basics.rst b/manual/basics.rst
deleted file mode 100644
index 7fb55bb6..00000000
--- a/manual/basics.rst
+++ /dev/null
@@ -1,46 +0,0 @@
-Basics
-======
-
-Source Files
-------------
-
-Supported source files are:
-
-* **Gerber**: Typically define copper layers in a circuit board.
-* **Excellon**: (drill file): Contain drill specifications, size and coordinates.
-* **G-Code**: CNC machine instructions for cutting and/or drilling.
-
-These source files can be loaded by selecting File→Open Gerber…, File→Open Excellon… or File→Open G-Code… respectively. The objects created from source files are automatically added to the current project when loaded.
-
-
-Objects and Tasks
------------------
-
-Data in FlatCAM is in the form of 4 different kinds of objects: Gerber, Excellon, Geometry and CNC Job. Gerber, Excellon and CNC Jos objects are directly created by reading files in Gerber, Excellon and G-Code formats. Geometry objects are an intermediate step available to manipulate data. The diagram bellow illustrates the relationship between files and objects. The arrows connecting objects represent a sub-set of the tasks that can be performed in FlatCAM.
-
-.. image:: objects_flow.png
- :align: center
-
-
-Creating, Saving and Loading Projects
--------------------------------------
-
-A project is everything that you have loaded, created and set inside the program. A new project is created every time you load the program or run File→New.
-
-By running File→Save Project, File→Save Project As… or File→Save a Project Copy… you are saving everything currently in the environment including project options. File→Open Project… lets you load a saved project.
-
-
-Navigating Plots
-----------------
-
-Plots for open objects (Gerber, drills, g-code, etc…) are automatically shown on screen. A plot for a given can be updated by clicking “Update Plot” in the “Selected” tab, in case any parameters that would have changed the plot have been modified.
-
-Zooming plots in and out is accomplished by clicking on the plot and using the mouse **scroll wheel** or hitting one of the following keys:
-
-* ``1``: Fits all graphics to the available plotting area.
-* ``2``: Zooms out
-* ``3``: Zooms in
-
-When zooming in or out, the point under the cursor stays at the same location.
-
-To scroll left-right or up-down, hold the ``shift`` or ``control`` key respectively while turning the mouse **scroll wheel**.
\ No newline at end of file
diff --git a/manual/cmdreference.rst b/manual/cmdreference.rst
deleted file mode 100644
index 1d44221e..00000000
--- a/manual/cmdreference.rst
+++ /dev/null
@@ -1,241 +0,0 @@
-.. _cmdreference:
-
-Shell Command Reference
-=======================
-
-.. warning::
- The FlatCAM Shell is under development and its behavior might change in the future. This includes available commands and their syntax.
-
-.. _add_circle:
-
-add_circle
-~~~~~~~~~~
-Creates a circle in the given Geometry object.
-
- > add_circle
- name: Name of the geometry object to which to append the circle.
-
- center_x, center_y: Coordinates of the center of the circle.
-
- radius: Radius of the circle.
-
-.. _add_poly:
-
-add_poly
-~~~~~~~~
-Creates a polygon in the given Geometry object.
-
- > create_poly [x3 y3 [...]]
- name: Name of the geometry object to which to append the polygon.
-
- xi, yi: Coordinates of points in the polygon.
-
-.. _add_rect:
-
-add_rect
-~~~~~~~~
-Creates a rectange in the given Geometry object.
-
- > add_rect
- name: Name of the geometry object to which to append the rectangle.
-
- botleft_x, botleft_y: Coordinates of the bottom left corner.
-
- topright_x, topright_y Coordinates of the top right corner.
-
-cncjob
-~~~~~~
-Generates a CNC Job from a Geometry Object.
-
- > cncjob [-z_cut ] [-z_move ] [-feedrate ] [-tooldia ] [-outname ]
- name: Name of the source object
-
- z_cut: Z-axis cutting position
-
- z_move: Z-axis moving position
-
- feedrate: Moving speed when cutting
-
- tooldia: Tool diameter to show on screen
-
- outname: Name of the output object
-
-delete
-~~~~~~
-Deletes the give object.
-
- > delete
- name: Name of the object to delete.
-
-follow
-~~~~~~
-Creates a geometry object following gerber paths.
-
- > follow [-outname ]
- name: Name of the gerber object.
-
- outname: Name of the output geometry object.
-
-.. _geo_union:
-
-geo_union
-~~~~~~~~~
-Runs a union operation (addition) on the components of the geometry object. For example, if it contains 2 intersecting polygons, this opperation adds them intoa single larger polygon.
-
- > geo_union
- name: Name of the geometry object.
-
-get_names
-~~~~~~~~~
-Lists the names of objects in the project.
-
-
- > get_names
- No parameters.
-
-help
-~~~~
-Shows list of commands.
-
-isolate
-~~~~~~~
-Creates isolation routing geometry for the given Gerber.
-
- > isolate [-dia ] [-passes ] [-overlap ]
- name: Name of the object
-
- dia: Tool diameter
-
- passes: # of tool width
-
- overlap: Fraction of tool diameter to overlap passes
-
-make_docs
-~~~~~~~~~
-Prints command rererence in reStructuredText format.
-
-new
-~~~
-Starts a new project. Clears objects from memory.
-
-
- > new
- No parameters.
-
-.. _new_geometry:
-
-new_geometry
-~~~~~~~~~~~~
-Creates a new empty geometry object.
-
- > new_geometry
- name: New object name
-
-.. _offset:
-
-offset
-~~~~~~
-Changes the position of the object.
-
- > offset
- name: Name of the object
-
- x: X-axis distance
-
- y: Y-axis distance
-
-open_excellon
-~~~~~~~~~~~~~
-Opens an Excellon file.
-
- > open_excellon [-outname ]
- filename: Path to file to open.
-
- outname: Name of the created excellon object.
-
-open_gcode
-~~~~~~~~~~
-Opens an G-Code file.
-
- > open_gcode [-outname ]
- filename: Path to file to open.
-
- outname: Name of the created CNC Job object.
-
-open_gerber
-~~~~~~~~~~~
-Opens a Gerber file.
-
- > open_gerber [-follow <0|1>] [-outname ]
- filename: Path to file to open.
-
- follow: If 1, does not create polygons, just follows the gerber path.
-
- outname: Name of the created gerber object.
-
-open_project
-~~~~~~~~~~~~
-Opens a FlatCAM project.
-
- > open_project
- filename: Path to file to open.
-
-options
-~~~~~~~
-Shows the settings for an object.
-
-
- > options
- name: Object name.
-
-paint_poly
-~~~~~~~~~~
-Creates a geometry object with toolpath to cover the inside of a polygon.
-
- > paint_poly
- name: Name of the sourge geometry object.
-
- inside_pt_x, inside_pt_y: Coordinates of a point inside the polygon.
-
- tooldia: Diameter of the tool to be used.
-
- overlap: Fraction of the tool diameter to overlap cuts.
-
-plot
-~~~~
-Updates the plot on the user interface
-
-save_project
-~~~~~~~~~~~~
-Saves the FlatCAM project to file.
-
- > save_project
- filename: Path to file to save.
-
-.. _scale:
-
-scale
-~~~~~
-Resizes the object by a factor.
-
- > scale
- name: Name of the object
-
- factor: Fraction by which to scale
-
-set_active
-~~~~~~~~~~
-Sets a FlatCAM object as active.
-
-
- > set_active
- name: Name of the object.
-
-write_gcode
-~~~~~~~~~~~
-Saves G-code of a CNC Job object to file.
-
- > write_gcode
- name: Source CNC Job object
-
- filename: Output filename
diff --git a/manual/editor.rst b/manual/editor.rst
deleted file mode 100644
index d4847667..00000000
--- a/manual/editor.rst
+++ /dev/null
@@ -1,134 +0,0 @@
-Geometry Editor
-===============
-
-Introduction
-------------
-
-The Geometry Editor is a drawing CAD that allows you to edit
-FlatCAM Geometry Objects or create new ones from scratch. This
-provides the ultimate flexibility by letting you specify precisely
-and arbitrarily what you want your CNC router to do.
-
-Creating New Geometry Objects
------------------------------
-
-To create a blank Geometry Object, simply click on the menu item
-**Edit→New Geometry Object** or click the **New Blank Geometry** button on
-the toolbar. A Geometry object with the name "New Geometry" will
-be added to your project list.
-
-.. image:: editor1.png
- :align: center
-
-.. seealso::
-
- FlatCAM Shell command :ref:`new_geometry`
-
-
-Editing Existing Geometry Objects
----------------------------------
-
-To edit a Geometry Object, select it from the project list and
-click on the menu item **Edit→Edit Geometry** or on the **Edit Geometry**
-toolbar button.
-
-This will make a copy of the selected object in the editor and
-the editor toolbar buttons will become active.
-
-Changes made to the geometry in the editor will not affect the
-Geometry Object until the **Edit->Update Geometry** button or
-**Update Geometry** toolbar button is clicked.
-This replaces the geometry in the currently selected Geometry
-Object (which can be different from which the editor copied its
-contents originally) with the geometry in the editor.
-
-Selecting Shapes
-~~~~~~~~~~~~~~~~
-
-When the **Selection Tool** is active in the toolbar (Hit ``Esc``), clicking on the
-plot will select the nearest shape. If one shape is inside the other,
-you might need to move the outer one to get to the inner one. This
-behavior might be improved in the future.
-
-Holding the ``Control`` key while clicking will add the nearest shape
-to the set of selected objects.
-
-Creating Shapes
-~~~~~~~~~~~~~~~
-
-The shape creation tools in the editor are:
-
-* Circle
-* Arc
-* Rectangle
-* Polygon
-* Path
-
-.. image:: editor2.png
- :align: center
-
-After clicking on the respective toolbar button, follow the instructions
-on the status bar.
-
-Shapes that do not require a fixed number of clicks to complete, like
-polygons and paths, are complete by hitting the ``Space`` key.
-
-Certain shape tools can have different options or modes. By hitting
-`o` and/or `p` the tool will cycle through its options and/or modes.
-
-.. seealso::
-
- The FlatCAM Shell commands :ref:`add_circle`, :ref:`add_poly` and :ref:`add_rect`,
- create shapes directly on a given Geometry Object.
-
-Union
-~~~~~
-
-Clicking on the **Union** tool after selecting two or more shapes
-will create a union. For closed shapes, their union is a polygon covering
-the area that all the selected shapes encompassed. Unions of disjoint shapes
-can still be created and is equivalent to grouping shapes.
-
-.. image:: editor_union.png
- :align: center
-
-.. seealso::
-
- The FlatCAM Shell command :ref:`geo_union` executes a union of
- all geometry in a Geometry object.
-
-Moving and Copying
-~~~~~~~~~~~~~~~~~~
-
-The **Move** and **Copy** tools work on selected objects. As soon as the tool
-is selected (On the toolbar or the ``m`` and ``c`` keys) the reference point
-is set at the mouse pointer location. Clicking on the plot sets the target
-location and finalizes the operation. An outline of the shapes is shown
-while moving the mouse.
-
-.. seealso::
-
- The FlatCAM Shell command :ref:`offset` will move (offset) all
- the geometry in a Geometry Object. This can also be done in
- the **Selected** panel for selected FlatCAM object.
-
-Cancelling an operation
-~~~~~~~~~~~~~~~~~~~~~~~
-
-Hitting the ``Esc`` key cancels whatever tool/operation is active and
-selects the **Selection Tool**.
-
-Deleting selected shapes
-~~~~~~~~~~~~~~~~~~~~~~~~
-
-Selections are deleted by hitting the ``-`` sign key.
-
-Other
-~~~~~
-
-.. seealso::
-
- The FlatCAM Shell command :ref:`scale` changes the size of the
- geometry in a Geometry Object.
-
-
diff --git a/manual/flatcamshell.rst b/manual/flatcamshell.rst
deleted file mode 100644
index 537ac599..00000000
--- a/manual/flatcamshell.rst
+++ /dev/null
@@ -1,54 +0,0 @@
-Shell Command Line Interface
-============================
-
-.. warning::
- The FlatCAM Shell is under development and its behavior might change in the future. This includes available commands and their syntax.
-
-The FlatCAM Shell provides a command line interface to FlatCAM's functionalies and to the TCL language. It serves the following purposes:
-
-* An alternative the GUI for issuing commands and visualizing data output.
-* Scripting interface for automating large sequences of commands.
-* A mechanism for the user to implement new functionality.
-* A mechanism to provide detailed information to the user.
-* Keep a record of commands and responses.
-
-The Shell Window
-----------------
-
-.. image:: shell.png
- :align: center
-
-The FlatCAM Shell window is shown at startup when FlatCAM loads. It can be closed and re-opened at any time without loss of data by clicking on the close button on the top right edge of the window and selecting **Tool→Command Line** from the main menu respectively.
-
-It is divided into 2 sections, an output section on the top and an input section on the bottom. A record of previously issued commands is shown in the output section along with their results and other information that FlatCAM might provide. Distinction between types of data in the output section is done by color coding.
-
-To issue a command, type it in the input section and hit ``Enter``. If the command consists of multiple lines, use ``Shift-Enter`` to insert a new line without issuing the command.
-
-Shell Language
---------------
-
-The Shell uses the TCL_ language. TCL provides the simples posible syntax and requires no learning at all for isuing the basic FlatCAM commands. Nonetheless, TCL is a powerfull language that enables the users to create their own complex functionality if desired.
-
-.. _TCL: https://www.tcl.tk/man/tcl8.5/tutorial/tcltutorial.html
-
-Issuing a command is as simple as typing its name and hitting the ``Enter`` key. For example::
-
- new
-
-This the same as clicking on **File→New** in the main window menu.
-
-If a command requires additional information, it is given immediately after the command name and a space. For example, to open the gerber file ``mygerber.gbr``::
-
- open_gerber mygerber.gbr
-
-Sometimes a command will have optional parameters, this is, if you provide it it will use it, otherwise it will use some default value. For example::
-
- isolate mygerber.gbr -tooldia 0.04
-
-This would create isolation routing geometry for the ``mygerber.gbr`` gerber object with a tool diameter of 0.04 inches (or mm, depending on the project settings). Otherwise, if you run::
-
- isolate mygerber.gbr
-
-The same action will be performed but the tool diameter will be taken from the default value set for that object (If it is a new object, its default values will be set from the project options.)
-
-For complete reference of FlatCAM Shell commands, see :ref:`cmdreference`.
\ No newline at end of file
diff --git a/manual/installation.rst b/manual/installation.rst
deleted file mode 100644
index 1563f214..00000000
--- a/manual/installation.rst
+++ /dev/null
@@ -1,100 +0,0 @@
-Installation
-============
-
-Windows Installer
------------------
-
-Download the installer from the repository_ and run it in your machine.
-It includes everything you need.
-
-.. _repository: https://bitbucket.org/jpcgt/flatcam/downloads
-
-Ubuntu
-------
-
-FlatCAM should work on most Linux distributions but Ubuntu has been
-chosen as the test platform.
-
-There are several dependencies required to run FlatCAM. These are
-listed in the following section. Before attempting a manual installation,
-try running the provided setup script ``setup_ubuntu.sh`` that will
-download and install required packages.
-
-OS-X
-----
-
-See manual instructions below.
-
-
-Manual Installation
--------------------
-
-Requirements
-~~~~~~~~~~~~
-
-* Python 2.7 32-bit
-* PyQt 4
-* Matplotlib 1.3.1
-* Numpy 1.8
-* `Shapely 1.3`_
- * GEOS
-* RTree
- * SpatialIndex
-
-.. _Shapely 1.3: https://pypi.python.org/pypi/Shapely
-
-These packages might have their own dependencies.
-
-Linux
-~~~~~
-
-Under Linux, most modern package installers like **yum** or **apt-get**
-will attempt to locate and install the whole tree of dependencies for a
-specified package automatically. Refer to the provided setup script
-``setup_ubuntu.sh`` for the names and installation order.
-
-Once the dependencies are installed, download the latest .zip release
-(or the latest source, although it is not garanteed to work), unpack it,
-change into the created folder and run::
-
- Python FlatCAM.py
-
-
-Windows
-~~~~~~~
-
-An easy way to get the requirements in your system is to install WinPython_.
-This is a standalone distribution of Python which includes all of FlatCAM's
-dependencies, except for Shapely and RTree. These can be found here:
-`Unofficial Windows Binaries for Python Extension Packages`_.
-
-.. _WinPython: http://winpython.sourceforge.net/
-.. _Unofficial Windows Binaries for Python Extension Packages: http://www.lfd.uci.edu/~gohlke/pythonlibs/
-
-Once the dependencies are installed, download the latest .zip
-release (or the latest source, although it is not garanteed to work),
-unpack it, change into the created folder and run::
-
- python FlatCAM.py
-
-
-OS-X
-~~~~
-
-Start by installing binary packages: pyqt, geos, spatialindex.
-One way to do this is using Homebrew_::
-
- brew install name_of_package
-
-.. _Homebrew: http://brew.sh
-
-Now you can install all Python packages (numpy, matplotlib, rtree, scipy,
-shapely, simplejson) using pip::
-
- pip install name_of_package
-
-Finally, download the latest FlatCAM .zip package or source code. Change into
-its directory and launch it by running::
-
- python FlatCAM.py
-
diff --git a/manual/introduction.rst b/manual/introduction.rst
deleted file mode 100644
index c8db29f7..00000000
--- a/manual/introduction.rst
+++ /dev/null
@@ -1,4 +0,0 @@
-Introduction
-============
-
-FlatCAM is a program for preparing CNC jobs for making PCBs on a CNC router. Among other things, it can take a Gerber file generated by your favorite PCB CAD program, and create G-Code for Isolation routing.
\ No newline at end of file
diff --git a/manual/procedures.rst b/manual/procedures.rst
deleted file mode 100644
index 16d25637..00000000
--- a/manual/procedures.rst
+++ /dev/null
@@ -1,201 +0,0 @@
-Common Procedures
-=================
-
-Isolation Routing
------------------
-
-Isolation routing is the operation of cutting copper around traces for electrical isolation.
-
-1) Open a Gerber file: File→Open Gerber…
-
-The file is automatically analyzed, processed and plotted.
-
-2) Enter the diameter of the tool you will use for isolation routing and hit “Generate Geometry”. The units are determined by the project setting and are shown on the bottom right of the screen. If you want to work using different units, go to Options, Project Options (Combo box), Units. This will change the units for the whole project.
-
-.. image:: open_gerber_ready.png
- :align: center
-
-This creates a new geometry object listed under “Project” with the same name as the Gerber object with an “_iso” postfix, and its options are shown in “Selected”. Zoom into the plot (click over the plot and use the ‘2’ and ‘3’ keys to zoom in and out) to inspect the results.
-
-.. image:: iso_routing_ready.png
- :align: center
-
-3) Create a CNC job from the new geometry by indicating the desired parameters as shown in the figure above and explained below:
-
-* **Cut Z**: The depth of the tool while cutting. -2 mils or -0.05 mm are a typical value for isolation routing.
-* **Travel Z**: The height above the board at which the cutting tool will travel when not cutting copper.
-* **Feedrate**: The speed of the cutting tool while cutting in inches/minute of mm/minute depending on the project settings.
-* **Tool diam.**: The cutting tool diameter. Use the same value as when creating the isolation routing geometry in step 2.
-
-A CNC Job object has been added to your project and its options are shown in the “Selected” tab. Tool paths are shown on the plot. Blue are copper cuts, while yellow are travelling (no cutting) motions.
-
-.. image:: iso_routing_cnc_ready.png
- :align: center
-
-Click on the “Export” button under “Export G-Code”. This will open a dialog box for you to save to a file. This is the file that you will supply to your CNC router.
-
-Wide Isolation Routing
-----------------------
-
-1) Go to the “Project” tab and double-click on the isolation geometry object that you created for the 1st pass. In the “Selected” tab, change its name and hit Enter.
-
-2) Go back to “Project” and double-click on the Gerber object. This takes you back to step 1 of tutorial 4.1. We will generate geometry for a second pass in the same way but with a larger offset. If “Tool diam” reads 0.016, enter 0.016*2.5 instead (0.016*3 would put the path 3 times as far which provides no overlap with the previous pass. By setting it to 0.016*2.5 you ensure that there is no copper left on the board and a cleaner finish). Click on “Generate Geometry” just like in tutorial 4.1 and you should get something like the figure below.
-
-.. image:: Double_iso.png
- :align: center
-
-3) Generate a CNC job like you did in part 3 of tutorial 4.1. You will end up with 2 G-Code file, one for each pass.
-
-CNC Jobs for Drill Files
-------------------------
-
-1) Open a drill (Excellon) file: File→Open Excellon. The drill file will be drawn onto the plot and its options form should show up.
-
-2) A drill file will usually contain different tools (drill diameters). You can choose to create a CNC job for each individual tool or bundle some of the tools together in the same job (in case you did not intend to use drill bits of different diameters). Click on “Choose” under “Create CNC Job” to open a selection window with the list of tools. Each has the format “id”: “diameter”, where the diameter is in the project’s units. Check the boxes by the tools you want to include in the job. The comma-separated list of tools should appear in the “Tools” entry box (Note: If you know the ids of the tools you can type the list yourself).
-
-.. image:: drill_tool_select.png
- :align: center
-
-3) Adjust “Drill Z” (Drilling depth), “Travel Z” (Height for X-Y movement) and “Feed rate” (Z-axis speed in project units per minute) to your desired values, and click on “Generate”.
-
-.. image:: drill_cnc_job.png
- :align: center
-
-A CNC job will be created and the tool-path will be shown on the screen. Click on “Export G-Code” as explained in tutorial 4.1 to save the generated CNC job to G-Code.
-
-2-side PCB
-----------
-
-The main idea behind this process is to ensure that when you turn your board around to mill the bottom side of your PCB it will be perfectly aligned with the top side.
-
-The mechanical alignment is accomplished by using alignment holes/pins. These are holes on your board and on the milling machine bed (typically a board of wood, known as “sacrificial” layer). Pins are used to align the holes on the board to the holes on the sacrificial layer. The holes are always pairs of holes that are symmetrical about a mirror axis. This ensures that when you turn your board around, the board can be aligned using the same alignment holes as before.
-
-.. image:: double1.png
- :align: center
-
-The bottom layer must be flipped (mirrored) around the same axis that was used for the alignment holes.
-
-The placement of the mirror axis can be very arbitrary. You just need to make sure that after flipping the board around, it will still fit on the milling machine bed. Same for the alignment holes. It doesn’t matter much where you put them. Perhaps if you have a large bare copper board and you plan on reusing the alignment holes for different projects that will be made out of this same bare board, you might want to define the location of the axis and holes, and record them for later use.
-
-FlatCAM takes care of the rest. To ensure the symmetry of the alignment holes, FlatCAM asks you to specify the holes on only one side of the mirror axis and it will create the mirror copies for you. It will also mirror the bottom (Gerber) layer around the same axis.
-
-.. image:: double2.png
- :align: center
-
-The process of making the double-sided board consists of creating the CNC Job objects for the top layer, the mirrored bottom layer and the alignment holes using FlatCAM. Then you can run the alignment holes job (you must drill through the board and into the sacrificial layer) and the top layer job. You must then turn the board around, align it using the alignment holes (fit some kind of pin in the holes) and run the bottom layer job.
-
-Here is how to use FlatCAM to generate the required files:
-
-1) Open the Gerber files for the top and bottom layers of your PCB.
-
-2) Start the Double-sided PCB tool by selecting Tools→Double-sided PCB tool.
-
-.. image:: dbl_sided1_arrows.png
- :align: center
-
-The tool has the following options:
-
-* **Bottom Layer**: Indicates which layer is the bottom layer, which needs to be flipped.
-
-* **Mirror axis**: Around which axis, X or Y, we want to mirror the layer.
-
-* **Axis location**: How we want to specify the location of the axis.
-
-* **Point/Box**: Specifies the location of the axis. It depends on the Axis location setting:
-
- * Point: A single point specifies where the axis is, and you input the coordinates of the point in the format (x, y). For example, if Mirror Axis is set to X and Point is set to (1.0, -1.0) the axis will be horizontal at y=-1.0 (The x coordinate is ignored).
-
- * Box: If you have already defined the boundary of your PCB you may want the axis to be exactly in the middle of that rectangle. The boundary must be some geometry object defined in the project and can be selected in the combo box appearing in the Point/Box field.
-
-* Alignment holes: These can aid in placing the board at the exact position after turning it over for the bottom side job. These holes must be symmetrical to the mirror axis. You only need to specify the location of the holes on one side of the mirror axis and the program will create the mirror copy. Input the coordinates of the holes in the following format: (x1, y1), (x2, y2), etc.
-
-* Drill diameter: The diameter of the drill for the alignment holes.
-
-.. note::
- You don’t have to manually type coordinates of points. Clicking on the plot automatically copies the coordinates to the clipboard in (x, y) format and these can be pasted into the input boxes.
-
-3) Create the mirror image of the bottom layer by clicking on “Create Mirror”. This will create a new Gerber object for the project. You can work with this object, create isolation routing and a CNC job as it has been show in the previous tutorials. You may want to hide or remove the layer for the top side to ease the visualization.
-
-4) Create the alignment hole drill object by going back to the Double-sided PCB tool and clicking “Create alignment drill”. This will create a drill job as specified and a CNC job can be created for it as has been shown for the previous examples.
-
-.. image:: bottom.png
- :align: center
-
-Copper Area Clear
------------------
-
-Removing large areas of copper is necessary when trying to avoid shorts due to dust, rust, etc, or in RF circuits, where the remaining unused copper is just unwanted parasitics. This tutorial shows how to eliminate all copper that is not specified in the Gerber source, but the user can still selectively choose what to clear.
-
-.. image:: coppercleardemo1.png
- :align: center
-
-1) Open a Gerber file as explained in previous tutorials.
-
-2) In the “Select” tab for the Gerber object, under “Non-copper regions”, provide “Boundary Margin” and click “Generate Geometry”. This creates a bounding box around the Gerber object, with the given margin. Then subtracts the Gerber object from the bounding box, resulting in a Geometry object with polygons covering the areas without copper.
-
-.. image:: coppercleardemo2.png
- :align: center
-
-3) Now we can choose which polygon we want to “paint”, this is, draw a toolpath inside it to cover all its surface. In the “Selected” tab for the newly created geometry, under “Paint Area”, provide the following:
-
-* **Tool diam.**: The diameter of the tool that will be used to cut the area.
-
-* **Overlap**: Fraction of the tool diameter by which to overlap each passing cut. The default value of 0.15 is the minimum to ensure no copper is left in 90 degree turns of the toolpath.
-
-* **Margin**: Distance for the tool to stay away from the polygon boundary. This can be used to ensure that a large tool does not touch copper edges that have or will be cut by a smaller more precise tool.
-
-4) Click on “Generate” and then click on the plot inside the polygon to be painted. This will create a new Geometry object with the desired toolpaths.
-
-.. image:: coppercleardemo3.png
- :align: center
-
-Board Cutout
-------------
-
-To cut the PCB to the desired shape and remove it from a larger blank PCB, a toolpath that traces the board edge can be created. Gaps to hold the board until the job is complete can be placed along the edge.
-
-This tutorial describes how to create rectangular cutouts with 2 or 4 gaps.
-
-1) Open a Gerber file and find the **Board Cutout** section in the **Selected tab**.
-
-.. image:: cutout.png
- :align: center
-
-2) Specify a **Margin**. This will create a rectangular cutout at the given distance from any element in the Gerber. Specify a **Gap Size**. 2 times the diameter of the tool you will use for cutting is a good size. Specify how many and where you want the **Gaps** along the edge, 2 (top and bottom), 2 (left and right) or 4, one on each side. Click on **Generate Geometry**. The figure below shows an example of the results.
-
-.. image:: cutout2.png
- :align: center
-
-3) Create a CNC job for the newly created geometry as explained in earlier tutorials.
-
-.. image:: cutout3.png
- :align: center
-
-Bed Flattening
---------------
-
-Most often a sacrificial layer (e.g. wood) is used between the machine bed and the PCB so when drilling and cutting the machine is not hit by the tool. In order to have a completely flat surface for the PCB, the sacrificial layer is flattened by the machine. This tutorial shows how to create a toolpath for this purpose.
-
-1) Open a Gerber file and locate the **Bounding Box** section in the **Selected tab**.
-
-2) Specify a **Margin** (distance of the bounding box from any element in the Gerber) and whether you want **rounded corners**. Click **Generate Bounding Box**.
-
-.. image:: bedflatten0.png
- :align: center
-
-Make sure your blank PCB will fit in the bounding box.
-
-.. image:: bedflatten.png
- :align: center
-
-3) In the **Selected** tab for the newly created geometry locate the **Paint Area** section. Specify the **diameter** of the tool you will use, how much (fraction of the tool width) each pass will **overlap** each other, and a **Margin** (although typically not needed and set to 0.0 in this case.)
-
-.. image:: bedflatten1.png
- :align: center
-
-4) Click on **Generate**, and you will be asked to **click** inside the polygon inside which to create the tool path. Click inside the boundary we just created.
-
-.. image:: bedflatten2.png
- :align: center
-
-5) Create a CNC job for the newly created geometry as explained in earlier tutorials.
\ No newline at end of file
diff --git a/requirements.txt b/requirements.txt
new file mode 100644
index 00000000..53c65152
--- /dev/null
+++ b/requirements.txt
@@ -0,0 +1,9 @@
+# This file contains python only requirements to be installed with pip
+# Python pacakges that cannot be installed with pip (e.g. PyQT4) are not included.
+# Usage: pip install -r requirements.txt
+numpy>=1.8
+matplotlib>=1.3.1
+shapely>=1.3
+simplejson
+rtree
+scipy
diff --git a/sandbox/diagnose.py b/sandbox/diagnose.py
new file mode 100644
index 00000000..89618022
--- /dev/null
+++ b/sandbox/diagnose.py
@@ -0,0 +1,34 @@
+#import sys
+import platform
+
+print "Platform", platform.system(), platform.release()
+print "Distro", platform.dist()
+print "Python", platform.python_version()
+
+
+import rtree
+
+print "rtree", rtree.__version__
+
+
+import shapely
+import shapely.geos
+
+print "shapely", shapely.__version__
+print "GEOS library", shapely.geos.geos_version
+
+
+from PyQt4 import Qt
+
+print "Qt", Qt.qVersion()
+
+
+import numpy
+
+print "Numpy", numpy.__version__
+
+
+import matplotlib
+
+print "MatPlotLib", matplotlib.__version__
+print "MPL Numpy", matplotlib.__version__numpy__
\ No newline at end of file
diff --git a/sandbox/gerber_find.py b/sandbox/gerber_find.py
new file mode 100644
index 00000000..e757c003
--- /dev/null
+++ b/sandbox/gerber_find.py
@@ -0,0 +1,30 @@
+from camlib import *
+
+
+def gerber_find(filename, coords, frac_digits=5, tol=0.1):
+ g = Gerber()
+ f = open(filename)
+ current_x = None
+ current_y = None
+ line_num = 0
+ for line in f:
+ line_num += 1
+ try:
+ match = g.lin_re.search(line)
+ if match:
+ # Parse coordinates
+ if match.group(2) is not None:
+ current_x = parse_gerber_number(match.group(2), frac_digits)
+ if match.group(3) is not None:
+ current_y = parse_gerber_number(match.group(3), frac_digits)
+
+ if distance(coords, (current_x, current_y)) <= tol:
+ print line_num, ":", line.strip('\n\r')
+ except Exception as e:
+ print str(e)
+ print line_num, ":", line.strip('\n\r')
+
+
+if __name__ == "__main__":
+ filename = "/home/jpcaram/flatcam_test_files/ExtraTrace_cleanup.gbr"
+ gerber_find(filename, (1.2, 1.1))
\ No newline at end of file
diff --git a/sandbox/process_widget.py b/sandbox/process_widget.py
new file mode 100644
index 00000000..9b4790d5
--- /dev/null
+++ b/sandbox/process_widget.py
@@ -0,0 +1,20 @@
+import sys
+from PyQt4.QtGui import *
+
+app = QApplication(sys.argv)
+
+top = QWidget()
+halign = QHBoxLayout()
+top.setLayout(halign)
+busy_anim = QMovie("../share/busy16.gif")
+busy_anim.start()
+busy_anim_label = QLabel()
+busy_anim_label.setMovie(busy_anim)
+halign.addWidget(busy_anim_label)
+
+message_label = QLabel("Processing...")
+halign.addWidget(message_label)
+
+top.show()
+
+sys.exit(app.exec_())
\ No newline at end of file
diff --git a/setup_ubuntu.sh b/setup_ubuntu.sh
index f531968e..bb1d7cce 100755
--- a/setup_ubuntu.sh
+++ b/setup_ubuntu.sh
@@ -2,8 +2,7 @@
apt-get install libpng-dev
apt-get install libfreetype6 libfreetype6-dev
apt-get install python-dev
-#apt-get install python-gi
-#apt-get install libgtk-3-devel
+apt-get install python-simplejson
apt-get install python-qt4
apt-get install python-numpy python-scipy python-matplotlib
apt-get install libgeos-dev
@@ -14,3 +13,4 @@ pip install --upgrade matplotlib
pip install --upgrade Shapely
apt-get install libspatialindex-dev
pip install rtree
+pip install svg.path
\ No newline at end of file
diff --git a/share/active.gif b/share/active.gif
new file mode 100644
index 00000000..b2cb55d7
Binary files /dev/null and b/share/active.gif differ
diff --git a/share/intersection16.png b/share/intersection16.png
new file mode 100644
index 00000000..e6298995
Binary files /dev/null and b/share/intersection16.png differ
diff --git a/share/intersection24.png b/share/intersection24.png
new file mode 100644
index 00000000..a756e97c
Binary files /dev/null and b/share/intersection24.png differ
diff --git a/share/intersection32.png b/share/intersection32.png
new file mode 100644
index 00000000..0e3077f6
Binary files /dev/null and b/share/intersection32.png differ
diff --git a/svgparse.py b/svgparse.py
new file mode 100644
index 00000000..f2ecb522
--- /dev/null
+++ b/svgparse.py
@@ -0,0 +1,506 @@
+############################################################
+# FlatCAM: 2D Post-processing for Manufacturing #
+# http://flatcam.org #
+# Author: Juan Pablo Caram (c) #
+# Date: 12/18/2015 #
+# MIT Licence #
+# #
+# SVG Features supported: #
+# * Groups #
+# * Rectangles (w/ rounded corners) #
+# * Circles #
+# * Ellipses #
+# * Polygons #
+# * Polylines #
+# * Lines #
+# * Paths #
+# * All transformations #
+# #
+# Reference: www.w3.org/TR/SVG/Overview.html #
+############################################################
+
+import xml.etree.ElementTree as ET
+import re
+import itertools
+from svg.path import Path, Line, Arc, CubicBezier, QuadraticBezier, parse_path
+from shapely.geometry import LinearRing, LineString, Point
+from shapely.affinity import translate, rotate, scale, skew, affine_transform
+import numpy as np
+import logging
+
+log = logging.getLogger('base2')
+
+
+def svgparselength(lengthstr):
+ """
+ Parse an SVG length string into a float and a units
+ string, if any.
+
+ :param lengthstr: SVG length string.
+ :return: Number and units pair.
+ :rtype: tuple(float, str|None)
+ """
+
+ integer_re_str = r'[+-]?[0-9]+'
+ number_re_str = r'(?:[+-]?[0-9]*\.[0-9]+(?:[Ee]' + integer_re_str + ')?' + r')|' + \
+ r'(?:' + integer_re_str + r'(?:[Ee]' + integer_re_str + r')?)'
+ length_re_str = r'(' + number_re_str + r')(em|ex|px|in|cm|mm|pt|pc|%)?'
+
+ match = re.search(length_re_str, lengthstr)
+ if match:
+ return float(match.group(1)), match.group(2)
+
+ raise Exception('Cannot parse SVG length: %s' % lengthstr)
+
+
+def path2shapely(path, res=1.0):
+ """
+ Converts an svg.path.Path into a Shapely
+ LinearRing or LinearString.
+
+ :rtype : LinearRing
+ :rtype : LineString
+ :param path: svg.path.Path instance
+ :param res: Resolution (minimum step along path)
+ :return: Shapely geometry object
+ """
+ points = []
+
+ for component in path:
+
+ # Line
+ if isinstance(component, Line):
+ start = component.start
+ x, y = start.real, start.imag
+ if len(points) == 0 or points[-1] != (x, y):
+ points.append((x, y))
+ end = component.end
+ points.append((end.real, end.imag))
+ continue
+
+ # Arc, CubicBezier or QuadraticBezier
+ if isinstance(component, Arc) or \
+ isinstance(component, CubicBezier) or \
+ isinstance(component, QuadraticBezier):
+
+ # How many points to use in the dicrete representation.
+ length = component.length(res / 10.0)
+ steps = int(length / res + 0.5)
+ frac = 1.0 / steps
+
+ # print length, steps, frac
+ for i in range(steps):
+ point = component.point(i * frac)
+ x, y = point.real, point.imag
+ if len(points) == 0 or points[-1] != (x, y):
+ points.append((x, y))
+ end = component.point(1.0)
+ points.append((end.real, end.imag))
+ continue
+
+ log.warning("I don't know what this is:", component)
+ continue
+
+ if path.closed:
+ return LinearRing(points)
+ else:
+ return LineString(points)
+
+
+def svgrect2shapely(rect, n_points=32):
+ """
+ Converts an SVG rect into Shapely geometry.
+
+ :param rect: Rect Element
+ :type rect: xml.etree.ElementTree.Element
+ :return: shapely.geometry.polygon.LinearRing
+ """
+ w = svgparselength(rect.get('width'))[0]
+ h = svgparselength(rect.get('height'))[0]
+ x = svgparselength(rect.get('x'))[0]
+ y = svgparselength(rect.get('y'))[0]
+
+ rxstr = rect.get('rx')
+ rystr = rect.get('ry')
+
+ if rxstr is None and rystr is None: # Sharp corners
+ pts = [
+ (x, y), (x + w, y), (x + w, y + h), (x, y + h), (x, y)
+ ]
+
+ else: # Rounded corners
+ rx = 0.0 if rxstr is None else svgparselength(rxstr)[0]
+ ry = 0.0 if rystr is None else svgparselength(rystr)[0]
+
+ n_points = int(n_points / 4 + 0.5)
+ t = np.arange(n_points, dtype=float) / n_points / 4
+
+ x_ = (x + w - rx) + rx * np.cos(2 * np.pi * (t + 0.75))
+ y_ = (y + ry) + ry * np.sin(2 * np.pi * (t + 0.75))
+
+ lower_right = [(x_[i], y_[i]) for i in range(n_points)]
+
+ x_ = (x + w - rx) + rx * np.cos(2 * np.pi * t)
+ y_ = (y + h - ry) + ry * np.sin(2 * np.pi * t)
+
+ upper_right = [(x_[i], y_[i]) for i in range(n_points)]
+
+ x_ = (x + rx) + rx * np.cos(2 * np.pi * (t + 0.25))
+ y_ = (y + h - ry) + ry * np.sin(2 * np.pi * (t + 0.25))
+
+ upper_left = [(x_[i], y_[i]) for i in range(n_points)]
+
+ x_ = (x + rx) + rx * np.cos(2 * np.pi * (t + 0.5))
+ y_ = (y + ry) + ry * np.sin(2 * np.pi * (t + 0.5))
+
+ lower_left = [(x_[i], y_[i]) for i in range(n_points)]
+
+ pts = [(x + rx, y), (x - rx + w, y)] + \
+ lower_right + \
+ [(x + w, y + ry), (x + w, y + h - ry)] + \
+ upper_right + \
+ [(x + w - rx, y + h), (x + rx, y + h)] + \
+ upper_left + \
+ [(x, y + h - ry), (x, y + ry)] + \
+ lower_left
+
+ return LinearRing(pts)
+
+
+def svgcircle2shapely(circle):
+ """
+ Converts an SVG circle into Shapely geometry.
+
+ :param circle: Circle Element
+ :type circle: xml.etree.ElementTree.Element
+ :return: Shapely representation of the circle.
+ :rtype: shapely.geometry.polygon.LinearRing
+ """
+ # cx = float(circle.get('cx'))
+ # cy = float(circle.get('cy'))
+ # r = float(circle.get('r'))
+ cx = svgparselength(circle.get('cx'))[0] # TODO: No units support yet
+ cy = svgparselength(circle.get('cy'))[0] # TODO: No units support yet
+ r = svgparselength(circle.get('r'))[0] # TODO: No units support yet
+
+ # TODO: No resolution specified.
+ return Point(cx, cy).buffer(r)
+
+
+def svgellipse2shapely(ellipse, n_points=64):
+ """
+ Converts an SVG ellipse into Shapely geometry
+
+ :param ellipse: Ellipse Element
+ :type ellipse: xml.etree.ElementTree.Element
+ :param n_points: Number of discrete points in output.
+ :return: Shapely representation of the ellipse.
+ :rtype: shapely.geometry.polygon.LinearRing
+ """
+
+ cx = svgparselength(ellipse.get('cx'))[0] # TODO: No units support yet
+ cy = svgparselength(ellipse.get('cy'))[0] # TODO: No units support yet
+
+ rx = svgparselength(ellipse.get('rx'))[0] # TODO: No units support yet
+ ry = svgparselength(ellipse.get('ry'))[0] # TODO: No units support yet
+
+ t = np.arange(n_points, dtype=float) / n_points
+ x = cx + rx * np.cos(2 * np.pi * t)
+ y = cy + ry * np.sin(2 * np.pi * t)
+ pts = [(x[i], y[i]) for i in range(n_points)]
+
+ return LinearRing(pts)
+
+
+def svgline2shapely(line):
+ """
+
+ :param line: Line element
+ :type line: xml.etree.ElementTree.Element
+ :return: Shapely representation on the line.
+ :rtype: shapely.geometry.polygon.LinearRing
+ """
+
+ x1 = svgparselength(line.get('x1'))[0]
+ y1 = svgparselength(line.get('y1'))[0]
+ x2 = svgparselength(line.get('x2'))[0]
+ y2 = svgparselength(line.get('y2'))[0]
+
+ return LineString([(x1, y1), (x2, y2)])
+
+
+def svgpolyline2shapely(polyline):
+
+ ptliststr = polyline.get('points')
+ points = parse_svg_point_list(ptliststr)
+
+ return LineString(points)
+
+
+def svgpolygon2shapely(polygon):
+
+ ptliststr = polygon.get('points')
+ points = parse_svg_point_list(ptliststr)
+
+ return LinearRing(points)
+
+
+def getsvggeo(node):
+ """
+ Extracts and flattens all geometry from an SVG node
+ into a list of Shapely geometry.
+
+ :param node: xml.etree.ElementTree.Element
+ :return: List of Shapely geometry
+ :rtype: list
+ """
+ kind = re.search('(?:\{.*\})?(.*)$', node.tag).group(1)
+ geo = []
+
+ # Recurse
+ if len(node) > 0:
+ for child in node:
+ subgeo = getsvggeo(child)
+ if subgeo is not None:
+ geo += subgeo
+
+ # Parse
+ elif kind == 'path':
+ log.debug("***PATH***")
+ P = parse_path(node.get('d'))
+ P = path2shapely(P)
+ geo = [P]
+
+ elif kind == 'rect':
+ log.debug("***RECT***")
+ R = svgrect2shapely(node)
+ geo = [R]
+
+ elif kind == 'circle':
+ log.debug("***CIRCLE***")
+ C = svgcircle2shapely(node)
+ geo = [C]
+
+ elif kind == 'ellipse':
+ log.debug("***ELLIPSE***")
+ E = svgellipse2shapely(node)
+ geo = [E]
+
+ elif kind == 'polygon':
+ log.debug("***POLYGON***")
+ poly = svgpolygon2shapely(node)
+ geo = [poly]
+
+ elif kind == 'line':
+ log.debug("***LINE***")
+ line = svgline2shapely(node)
+ geo = [line]
+
+ elif kind == 'polyline':
+ log.debug("***POLYLINE***")
+ pline = svgpolyline2shapely(node)
+ geo = [pline]
+
+ else:
+ log.warning("Unknown kind: " + kind)
+ geo = None
+
+ # Transformations
+ if 'transform' in node.attrib:
+ trstr = node.get('transform')
+ trlist = parse_svg_transform(trstr)
+ #log.debug(trlist)
+
+ # Transformations are applied in reverse order
+ for tr in trlist[::-1]:
+ if tr[0] == 'translate':
+ geo = [translate(geoi, tr[1], tr[2]) for geoi in geo]
+ elif tr[0] == 'scale':
+ geo = [scale(geoi, tr[0], tr[1], origin=(0, 0))
+ for geoi in geo]
+ elif tr[0] == 'rotate':
+ geo = [rotate(geoi, tr[1], origin=(tr[2], tr[3]))
+ for geoi in geo]
+ elif tr[0] == 'skew':
+ geo = [skew(geoi, tr[1], tr[2], origin=(0, 0))
+ for geoi in geo]
+ elif tr[0] == 'matrix':
+ geo = [affine_transform(geoi, tr[1:]) for geoi in geo]
+ else:
+ raise Exception('Unknown transformation: %s', tr)
+
+ return geo
+
+
+def parse_svg_point_list(ptliststr):
+ """
+ Returns a list of coordinate pairs extracted from the "points"
+ attribute in SVG polygons and polylines.
+
+ :param ptliststr: "points" attribute string in polygon or polyline.
+ :return: List of tuples with coordinates.
+ """
+
+ pairs = []
+ last = None
+ pos = 0
+ i = 0
+
+ for match in re.finditer(r'(\s*,\s*)|(\s+)', ptliststr):
+
+ val = float(ptliststr[pos:match.start()])
+
+ if i % 2 == 1:
+ pairs.append((last, val))
+ else:
+ last = val
+
+ pos = match.end()
+ i += 1
+
+ # Check for last element
+ val = float(ptliststr[pos:])
+ if i % 2 == 1:
+ pairs.append((last, val))
+ else:
+ log.warning("Incomplete coordinates.")
+
+ return pairs
+
+
+def parse_svg_transform(trstr):
+ """
+ Parses an SVG transform string into a list
+ of transform names and their parameters.
+
+ Possible transformations are:
+
+ * Translate: translate( []), which specifies
+ a translation by tx and ty. If is not provided,
+ it is assumed to be zero. Result is
+ ['translate', tx, ty]
+
+ * Scale: scale( []), which specifies a scale operation
+ by sx and sy. If is not provided, it is assumed to be
+ equal to . Result is: ['scale', sx, sy]
+
+ * Rotate: rotate( [ ]), which specifies
+ a rotation by degrees about a given point.
+ If optional parameters and are not supplied,
+ the rotate is about the origin of the current user coordinate
+ system. Result is: ['rotate', rotate-angle, cx, cy]
+
+ * Skew: skewX(), which specifies a skew
+ transformation along the x-axis. skewY(), which
+ specifies a skew transformation along the y-axis.
+ Result is ['skew', angle-x, angle-y]
+
+ * Matrix: matrix( ), which specifies a
+ transformation in the form of a transformation matrix of six
+ values. matrix(a,b,c,d,e,f) is equivalent to applying the
+ transformation matrix [a b c d e f]. Result is
+ ['matrix', a, b, c, d, e, f]
+
+ Note: All parameters to the transformations are "numbers",
+ i.e. no units present.
+
+ :param trstr: SVG transform string.
+ :type trstr: str
+ :return: List of transforms.
+ :rtype: list
+ """
+ trlist = []
+
+ assert isinstance(trstr, str)
+ trstr = trstr.strip(' ')
+
+ integer_re_str = r'[+-]?[0-9]+'
+ number_re_str = r'(?:[+-]?[0-9]*\.[0-9]+(?:[Ee]' + integer_re_str + ')?' + r')|' + \
+ r'(?:' + integer_re_str + r'(?:[Ee]' + integer_re_str + r')?)'
+
+ # num_re_str = r'[\+\-]?[0-9\.e]+' # TODO: Negative exponents missing
+ comma_or_space_re_str = r'(?:(?:\s+)|(?:\s*,\s*))'
+ translate_re_str = r'translate\s*\(\s*(' + \
+ number_re_str + r')(?:' + \
+ comma_or_space_re_str + \
+ r'(' + number_re_str + r'))?\s*\)'
+ scale_re_str = r'scale\s*\(\s*(' + \
+ number_re_str + r')' + \
+ r'(?:' + comma_or_space_re_str + \
+ r'(' + number_re_str + r'))?\s*\)'
+ skew_re_str = r'skew([XY])\s*\(\s*(' + \
+ number_re_str + r')\s*\)'
+ rotate_re_str = r'rotate\s*\(\s*(' + \
+ number_re_str + r')' + \
+ r'(?:' + comma_or_space_re_str + \
+ r'(' + number_re_str + r')' + \
+ comma_or_space_re_str + \
+ r'(' + number_re_str + r'))?\*\)'
+ matrix_re_str = r'matrix\s*\(\s*' + \
+ r'(' + number_re_str + r')' + comma_or_space_re_str + \
+ r'(' + number_re_str + r')' + comma_or_space_re_str + \
+ r'(' + number_re_str + r')' + comma_or_space_re_str + \
+ r'(' + number_re_str + r')' + comma_or_space_re_str + \
+ r'(' + number_re_str + r')' + comma_or_space_re_str + \
+ r'(' + number_re_str + r')\s*\)'
+
+ while len(trstr) > 0:
+ match = re.search(r'^' + translate_re_str, trstr)
+ if match:
+ trlist.append([
+ 'translate',
+ float(match.group(1)),
+ float(match.group(2)) if match.group else 0.0
+ ])
+ trstr = trstr[len(match.group(0)):].strip(' ')
+ continue
+
+ match = re.search(r'^' + scale_re_str, trstr)
+ if match:
+ trlist.append([
+ 'translate',
+ float(match.group(1)),
+ float(match.group(2)) if match.group else float(match.group(1))
+ ])
+ trstr = trstr[len(match.group(0)):].strip(' ')
+ continue
+
+ match = re.search(r'^' + skew_re_str, trstr)
+ if match:
+ trlist.append([
+ 'skew',
+ float(match.group(2)) if match.group(1) == 'X' else 0.0,
+ float(match.group(2)) if match.group(1) == 'Y' else 0.0
+ ])
+ trstr = trstr[len(match.group(0)):].strip(' ')
+ continue
+
+ match = re.search(r'^' + rotate_re_str, trstr)
+ if match:
+ trlist.append([
+ 'rotate',
+ float(match.group(1)),
+ float(match.group(2)) if match.group(2) else 0.0,
+ float(match.group(3)) if match.group(3) else 0.0
+ ])
+ trstr = trstr[len(match.group(0)):].strip(' ')
+ continue
+
+ match = re.search(r'^' + matrix_re_str, trstr)
+ if match:
+ trlist.append(['matrix'] + [float(x) for x in match.groups()])
+ trstr = trstr[len(match.group(0)):].strip(' ')
+ continue
+
+ raise Exception("Don't know how to parse: %s" % trstr)
+
+ return trlist
+
+
+if __name__ == "__main__":
+ tree = ET.parse('tests/svg/drawing.svg')
+ root = tree.getroot()
+ ns = re.search(r'\{(.*)\}', root.tag).group(1)
+ print ns
+ for geo in getsvggeo(root):
+ print geo
\ No newline at end of file
diff --git a/tests/__init__.py b/tests/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/tests/canvas/performance.py b/tests/canvas/performance.py
new file mode 100644
index 00000000..9478bcbf
--- /dev/null
+++ b/tests/canvas/performance.py
@@ -0,0 +1,95 @@
+from __future__ import division
+import matplotlib
+matplotlib.use('Agg')
+import matplotlib.pyplot as plt
+import numpy as np
+import cStringIO
+from matplotlib.backends.backend_agg import FigureCanvasAgg
+from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg
+from matplotlib.figure import Figure
+import cProfile
+import sys
+
+
+def gen_data():
+ N = 100000
+ x = np.random.rand(N) * 10
+ y = np.random.rand(N) * 10
+ colors = np.random.rand(N)
+ area = np.pi * (15 * np.random.rand(N))**2 # 0 to 15 point radiuses
+ data = x, y, area, colors
+ return data
+
+
+# @profile
+def large_plot(data):
+ x, y, area, colors = data
+
+ fig = Figure(figsize=(10, 10), dpi=80)
+ axes = fig.add_axes([0.0, 0.0, 1.0, 1.0], alpha=1.0)
+ axes.set_frame_on(False)
+ axes.set_xticks([])
+ axes.set_yticks([])
+ # axes.set_xlim(0, 10)
+ # axes.set_ylim(0, 10)
+
+ axes.scatter(x, y, s=area, c=colors, alpha=0.5)
+
+ axes.set_xlim(0, 10)
+ axes.set_ylim(0, 10)
+
+ canvas = FigureCanvasAgg(fig)
+ canvas.draw()
+ # canvas = FigureCanvasQTAgg(fig)
+ # buf = canvas.tostring_rgb()
+ buf = fig.canvas.tostring_rgb()
+
+ ncols, nrows = fig.canvas.get_width_height()
+ img = np.fromstring(buf, dtype=np.uint8).reshape(nrows, ncols, 3)
+
+ return img
+
+
+def small_plot(data):
+ x, y, area, colors = data
+
+ fig = Figure(figsize=(3, 3), dpi=80)
+ axes = fig.add_axes([0.0, 0.0, 1.0, 1.0], alpha=1.0)
+ axes.set_frame_on(False)
+ axes.set_xticks([])
+ axes.set_yticks([])
+ # axes.set_xlim(5, 6)
+ # axes.set_ylim(5, 6)
+
+ axes.scatter(x, y, s=area, c=colors, alpha=0.5)
+
+ axes.set_xlim(4, 7)
+ axes.set_ylim(4, 7)
+
+ canvas = FigureCanvasAgg(fig)
+ canvas.draw()
+ # canvas = FigureCanvasQTAgg(fig)
+ # buf = canvas.tostring_rgb()
+ buf = fig.canvas.tostring_rgb()
+
+ ncols, nrows = fig.canvas.get_width_height()
+ img = np.fromstring(buf, dtype=np.uint8).reshape(nrows, ncols, 3)
+
+ return img
+
+def doit():
+ d = gen_data()
+ img = large_plot(d)
+ return img
+
+
+if __name__ == "__main__":
+
+ d = gen_data()
+
+ if sys.argv[1] == 'large':
+ cProfile.runctx('large_plot(d)', None, locals())
+ else:
+ cProfile.runctx('small_plot(d)', None, locals())
+
+
diff --git a/tests/canvas/prof.sh b/tests/canvas/prof.sh
new file mode 100755
index 00000000..b9075848
--- /dev/null
+++ b/tests/canvas/prof.sh
@@ -0,0 +1,6 @@
+#!/bin/sh
+
+echo "*** LARGE ***"
+python performance.py large | egrep "(\(scatter\))|(\(draw\))|(tostring_rgb)|(fromstring)"
+echo "*** SMALL ***"
+python performance.py small | egrep "(\(scatter\))|(\(draw\))|(tostring_rgb)|(fromstring)"
\ No newline at end of file
diff --git a/tests/gerber_files/STM32F4-spindle.cmp b/tests/gerber_files/STM32F4-spindle.cmp
new file mode 100644
index 00000000..bca2de6e
--- /dev/null
+++ b/tests/gerber_files/STM32F4-spindle.cmp
@@ -0,0 +1,6358 @@
+G75*
+%MOIN*%
+%OFA0B0*%
+%FSLAX25Y25*%
+%IPPOS*%
+%LPD*%
+%AMOC8*
+5,1,8,0,0,1.08239X$1,22.5*
+%
+%ADD10R,0.30000X0.30000*%
+%ADD11R,0.44685X0.17500*%
+%ADD12R,0.04724X0.01181*%
+%ADD13R,0.01181X0.04724*%
+%ADD14R,0.05512X0.04724*%
+%ADD15R,0.05118X0.06299*%
+%ADD16R,0.06299X0.05118*%
+%ADD17R,0.09843X0.01969*%
+%ADD18R,0.09843X0.07874*%
+%ADD19R,0.05118X0.05906*%
+%ADD20R,0.03150X0.05512*%
+%ADD21R,0.03150X0.07480*%
+%ADD22C,0.06000*%
+%ADD23R,0.05906X0.07874*%
+%ADD24OC8,0.06400*%
+%ADD25R,0.05512X0.05512*%
+%ADD26R,0.12598X0.04331*%
+%ADD27C,0.07400*%
+%ADD28R,0.06299X0.07098*%
+%ADD29R,0.03937X0.04331*%
+%ADD30R,0.05906X0.05118*%
+%ADD31C,0.01200*%
+%ADD32C,0.02400*%
+%ADD33C,0.01600*%
+%ADD34C,0.03181*%
+%ADD35C,0.04000*%
+D10*
+X0102500Y0095000D03*
+D11*
+X0212657Y0076250D03*
+D12*
+X0124941Y0080236D03*
+X0124941Y0082205D03*
+X0124941Y0084173D03*
+X0124941Y0086142D03*
+X0124941Y0088110D03*
+X0124941Y0090079D03*
+X0124941Y0092047D03*
+X0124941Y0094016D03*
+X0124941Y0095984D03*
+X0124941Y0097953D03*
+X0124941Y0099921D03*
+X0124941Y0101890D03*
+X0124941Y0103858D03*
+X0124941Y0105827D03*
+X0124941Y0107795D03*
+X0124941Y0109764D03*
+X0080059Y0109764D03*
+X0080059Y0107795D03*
+X0080059Y0105827D03*
+X0080059Y0103858D03*
+X0080059Y0101890D03*
+X0080059Y0099921D03*
+X0080059Y0097953D03*
+X0080059Y0095984D03*
+X0080059Y0094016D03*
+X0080059Y0092047D03*
+X0080059Y0090079D03*
+X0080059Y0088110D03*
+X0080059Y0086142D03*
+X0080059Y0084173D03*
+X0080059Y0082205D03*
+X0080059Y0080236D03*
+D13*
+X0087736Y0072559D03*
+X0089705Y0072559D03*
+X0091673Y0072559D03*
+X0093642Y0072559D03*
+X0095610Y0072559D03*
+X0097579Y0072559D03*
+X0099547Y0072559D03*
+X0101516Y0072559D03*
+X0103484Y0072559D03*
+X0105453Y0072559D03*
+X0107421Y0072559D03*
+X0109390Y0072559D03*
+X0111358Y0072559D03*
+X0113327Y0072559D03*
+X0115295Y0072559D03*
+X0117264Y0072559D03*
+X0117264Y0117441D03*
+X0115295Y0117441D03*
+X0113327Y0117441D03*
+X0111358Y0117441D03*
+X0109390Y0117441D03*
+X0107421Y0117441D03*
+X0105453Y0117441D03*
+X0103484Y0117441D03*
+X0101516Y0117441D03*
+X0099547Y0117441D03*
+X0097579Y0117441D03*
+X0095610Y0117441D03*
+X0093642Y0117441D03*
+X0091673Y0117441D03*
+X0089705Y0117441D03*
+X0087736Y0117441D03*
+D14*
+X0059331Y0113346D03*
+X0059331Y0106654D03*
+X0050669Y0106654D03*
+X0050669Y0113346D03*
+D15*
+X0051063Y0125000D03*
+X0058937Y0125000D03*
+X0056063Y0072500D03*
+X0063937Y0072500D03*
+X0078563Y0060000D03*
+X0086437Y0060000D03*
+X0121063Y0060000D03*
+X0128937Y0060000D03*
+X0136063Y0067500D03*
+X0143937Y0067500D03*
+X0141437Y0115000D03*
+X0133563Y0115000D03*
+X0133563Y0130000D03*
+X0141437Y0130000D03*
+D16*
+X0082500Y0136063D03*
+X0082500Y0143937D03*
+X0072500Y0123937D03*
+X0072500Y0116063D03*
+X0040000Y0113937D03*
+X0040000Y0106063D03*
+X0027500Y0141063D03*
+X0027500Y0148937D03*
+X0275000Y0208563D03*
+X0275000Y0216437D03*
+D17*
+X0255157Y0111299D03*
+X0255157Y0108150D03*
+X0255157Y0105000D03*
+X0255157Y0101850D03*
+X0255157Y0098701D03*
+D18*
+X0255157Y0087283D03*
+X0276811Y0087283D03*
+X0276811Y0122717D03*
+X0255157Y0122717D03*
+D19*
+X0223740Y0107500D03*
+X0216260Y0107500D03*
+X0216260Y0097500D03*
+X0223740Y0097500D03*
+X0267510Y0072500D03*
+X0274990Y0072500D03*
+X0161240Y0122500D03*
+X0153760Y0122500D03*
+X0082490Y0176250D03*
+X0075010Y0176250D03*
+X0103760Y0217500D03*
+X0111240Y0217500D03*
+X0128760Y0217500D03*
+X0136240Y0217500D03*
+X0153760Y0217500D03*
+X0161240Y0217500D03*
+X0126240Y0047500D03*
+X0118760Y0047500D03*
+D20*
+X0216598Y0062201D03*
+X0228402Y0062201D03*
+D21*
+X0222500Y0063201D03*
+D22*
+X0223500Y0069516D02*
+X0221500Y0069516D01*
+X0221500Y0077886D01*
+X0223500Y0077886D01*
+X0223500Y0069516D01*
+X0223500Y0075515D02*
+X0221500Y0075515D01*
+D23*
+X0244094Y0072500D03*
+X0255906Y0072500D03*
+X0255906Y0060000D03*
+X0244094Y0060000D03*
+D24*
+X0225000Y0147500D03*
+X0215000Y0147500D03*
+X0215000Y0157500D03*
+X0225000Y0157500D03*
+X0225000Y0167500D03*
+X0215000Y0167500D03*
+X0215000Y0177500D03*
+X0225000Y0177500D03*
+X0195000Y0207500D03*
+X0185000Y0207500D03*
+X0185000Y0217500D03*
+X0195000Y0217500D03*
+X0062500Y0217500D03*
+X0052500Y0217500D03*
+X0052500Y0207500D03*
+X0062500Y0207500D03*
+X0042500Y0207500D03*
+X0032500Y0207500D03*
+X0022500Y0207500D03*
+X0022500Y0217500D03*
+X0032500Y0217500D03*
+X0042500Y0217500D03*
+X0082500Y0025000D03*
+X0092500Y0025000D03*
+X0092500Y0015000D03*
+X0082500Y0015000D03*
+X0102500Y0015000D03*
+X0112500Y0015000D03*
+X0112500Y0025000D03*
+X0102500Y0025000D03*
+X0122500Y0025000D03*
+X0122500Y0015000D03*
+D25*
+X0240000Y0081270D03*
+X0240000Y0096230D03*
+X0246250Y0140020D03*
+X0257500Y0140020D03*
+X0257500Y0154980D03*
+X0246250Y0154980D03*
+D26*
+X0234114Y0202126D03*
+X0234114Y0217874D03*
+X0260886Y0217874D03*
+X0260886Y0202126D03*
+D27*
+X0273800Y0162500D02*
+X0281200Y0162500D01*
+X0281200Y0152500D02*
+X0273800Y0152500D01*
+X0273800Y0047500D02*
+X0281200Y0047500D01*
+X0271200Y0047500D02*
+X0263800Y0047500D01*
+X0263800Y0037500D02*
+X0271200Y0037500D01*
+X0273800Y0037500D02*
+X0281200Y0037500D01*
+X0281200Y0027500D02*
+X0273800Y0027500D01*
+X0271200Y0027500D02*
+X0263800Y0027500D01*
+X0263800Y0017500D02*
+X0271200Y0017500D01*
+X0273800Y0017500D02*
+X0281200Y0017500D01*
+X0096250Y0177550D02*
+X0096250Y0184950D01*
+D28*
+X0101902Y0205000D03*
+X0113098Y0205000D03*
+X0126902Y0205000D03*
+X0138098Y0205000D03*
+X0151902Y0205000D03*
+X0163098Y0205000D03*
+X0265652Y0060000D03*
+X0276848Y0060000D03*
+D29*
+X0063750Y0058346D03*
+X0063750Y0051654D03*
+D30*
+X0027500Y0071260D03*
+X0027500Y0078740D03*
+D31*
+X0002568Y0002568D02*
+X0002568Y0227392D01*
+X0014348Y0227392D01*
+X0010705Y0223749D01*
+X0009814Y0222858D01*
+X0009331Y0221693D01*
+X0009331Y0091870D01*
+X0009814Y0090705D01*
+X0014814Y0085705D01*
+X0015705Y0084814D01*
+X0016870Y0084331D01*
+X0024331Y0084331D01*
+X0024331Y0083868D01*
+X0024036Y0083868D01*
+X0023092Y0083477D01*
+X0022370Y0082754D01*
+X0021979Y0081810D01*
+X0021979Y0075670D01*
+X0022256Y0075000D01*
+X0021979Y0074330D01*
+X0021979Y0068190D01*
+X0022370Y0067246D01*
+X0023092Y0066523D01*
+X0024036Y0066132D01*
+X0024331Y0066132D01*
+X0024331Y0061653D01*
+X0024814Y0060489D01*
+X0028751Y0056552D01*
+X0029642Y0055660D01*
+X0030807Y0055178D01*
+X0059417Y0055178D01*
+X0059491Y0055000D01*
+X0059213Y0054330D01*
+X0059213Y0048977D01*
+X0059604Y0048033D01*
+X0060327Y0047311D01*
+X0061271Y0046920D01*
+X0066229Y0046920D01*
+X0067173Y0047311D01*
+X0067896Y0048033D01*
+X0068083Y0048485D01*
+X0083130Y0048485D01*
+X0084295Y0048967D01*
+X0088232Y0052904D01*
+X0089123Y0053796D01*
+X0089324Y0054282D01*
+X0089507Y0054282D01*
+X0090451Y0054673D01*
+X0091174Y0055395D01*
+X0091565Y0056339D01*
+X0091565Y0059347D01*
+X0092442Y0060225D01*
+X0092442Y0052749D01*
+X0090045Y0050353D01*
+X0089642Y0050186D01*
+X0088751Y0049295D01*
+X0084814Y0045358D01*
+X0084331Y0044193D01*
+X0084331Y0030100D01*
+X0082900Y0030100D01*
+X0082900Y0025400D01*
+X0082100Y0025400D01*
+X0082100Y0030100D01*
+X0080388Y0030100D01*
+X0077400Y0027112D01*
+X0077400Y0025400D01*
+X0082100Y0025400D01*
+X0082100Y0024600D01*
+X0077400Y0024600D01*
+X0077400Y0022888D01*
+X0079815Y0020473D01*
+X0076731Y0017389D01*
+X0076731Y0012611D01*
+X0080111Y0009231D01*
+X0084889Y0009231D01*
+X0087500Y0011842D01*
+X0090111Y0009231D01*
+X0094889Y0009231D01*
+X0097500Y0011842D01*
+X0100111Y0009231D01*
+X0104889Y0009231D01*
+X0107500Y0011842D01*
+X0110111Y0009231D01*
+X0114889Y0009231D01*
+X0117500Y0011842D01*
+X0120111Y0009231D01*
+X0124889Y0009231D01*
+X0128268Y0012611D01*
+X0128268Y0016288D01*
+X0131795Y0019814D01*
+X0132686Y0020705D01*
+X0133168Y0021870D01*
+X0133168Y0034193D01*
+X0132686Y0035358D01*
+X0128749Y0039295D01*
+X0127858Y0040186D01*
+X0126693Y0040668D01*
+X0112671Y0040668D01*
+X0110590Y0042749D01*
+X0110590Y0045756D01*
+X0111532Y0044814D01*
+X0112697Y0044331D01*
+X0113632Y0044331D01*
+X0113632Y0044036D01*
+X0114023Y0043092D01*
+X0114746Y0042370D01*
+X0115690Y0041979D01*
+X0121830Y0041979D01*
+X0122774Y0042370D01*
+X0123132Y0042727D01*
+X0123431Y0042647D01*
+X0125640Y0042647D01*
+X0125640Y0046900D01*
+X0126840Y0046900D01*
+X0126840Y0042647D01*
+X0129049Y0042647D01*
+X0129533Y0042777D01*
+X0129966Y0043027D01*
+X0130320Y0043381D01*
+X0130570Y0043814D01*
+X0130699Y0044297D01*
+X0130699Y0046900D01*
+X0126840Y0046900D01*
+X0126840Y0048100D01*
+X0125640Y0048100D01*
+X0125640Y0052353D01*
+X0123431Y0052353D01*
+X0123132Y0052273D01*
+X0122774Y0052630D01*
+X0121830Y0053021D01*
+X0115690Y0053021D01*
+X0114746Y0052630D01*
+X0114023Y0051908D01*
+X0113841Y0051467D01*
+X0112558Y0052749D01*
+X0112558Y0058328D01*
+X0112609Y0058205D01*
+X0113500Y0057314D01*
+X0114665Y0056831D01*
+X0115935Y0056831D01*
+X0115935Y0056339D01*
+X0116326Y0055395D01*
+X0117049Y0054673D01*
+X0117993Y0054282D01*
+X0124133Y0054282D01*
+X0125077Y0054673D01*
+X0125543Y0055139D01*
+X0125645Y0055080D01*
+X0126128Y0054950D01*
+X0128337Y0054950D01*
+X0128337Y0059400D01*
+X0129537Y0059400D01*
+X0129537Y0060600D01*
+X0133396Y0060600D01*
+X0133396Y0061782D01*
+X0139133Y0061782D01*
+X0140077Y0062173D01*
+X0140543Y0062639D01*
+X0140645Y0062580D01*
+X0141128Y0062450D01*
+X0143337Y0062450D01*
+X0143337Y0066900D01*
+X0144537Y0066900D01*
+X0144537Y0068100D01*
+X0148396Y0068100D01*
+X0148396Y0070900D01*
+X0148307Y0071231D01*
+X0163731Y0071231D01*
+X0163731Y0049250D01*
+X0164305Y0047865D01*
+X0165365Y0046805D01*
+X0166750Y0046231D01*
+X0257540Y0046231D01*
+X0258486Y0043949D01*
+X0259935Y0042500D01*
+X0258486Y0041051D01*
+X0257531Y0038747D01*
+X0257531Y0036253D01*
+X0258486Y0033949D01*
+X0260249Y0032186D01*
+X0260550Y0032061D01*
+X0260152Y0031771D01*
+X0259529Y0031148D01*
+X0259010Y0030435D01*
+X0258610Y0029650D01*
+X0258338Y0028811D01*
+X0258209Y0028000D01*
+X0267000Y0028000D01*
+X0267000Y0027000D01*
+X0268000Y0027000D01*
+X0268000Y0028000D01*
+X0277000Y0028000D01*
+X0277000Y0027000D01*
+X0276791Y0027000D01*
+X0268000Y0027000D01*
+X0268000Y0021900D01*
+X0268000Y0018000D01*
+X0277000Y0018000D01*
+X0277000Y0027000D01*
+X0278000Y0027000D01*
+X0278000Y0021900D01*
+X0278000Y0018000D01*
+X0277000Y0018000D01*
+X0277000Y0017000D01*
+X0276791Y0017000D01*
+X0268000Y0017000D01*
+X0268000Y0018000D01*
+X0267000Y0018000D01*
+X0267000Y0027000D01*
+X0258209Y0027000D01*
+X0258338Y0026189D01*
+X0258610Y0025350D01*
+X0259010Y0024565D01*
+X0259529Y0023852D01*
+X0260152Y0023229D01*
+X0260865Y0022710D01*
+X0261278Y0022500D01*
+X0260865Y0022290D01*
+X0260152Y0021771D01*
+X0259529Y0021148D01*
+X0259010Y0020435D01*
+X0258610Y0019650D01*
+X0258338Y0018811D01*
+X0258209Y0018000D01*
+X0267000Y0018000D01*
+X0267000Y0017000D01*
+X0268000Y0017000D01*
+X0268000Y0011900D01*
+X0271641Y0011900D01*
+X0272500Y0012036D01*
+X0273359Y0011900D01*
+X0277000Y0011900D01*
+X0277000Y0017000D01*
+X0278000Y0017000D01*
+X0278000Y0011900D01*
+X0281641Y0011900D01*
+X0282511Y0012038D01*
+X0283350Y0012310D01*
+X0284135Y0012710D01*
+X0284848Y0013229D01*
+X0285471Y0013852D01*
+X0285990Y0014565D01*
+X0286132Y0014845D01*
+X0286132Y0002568D01*
+X0002568Y0002568D01*
+X0002568Y0003596D02*
+X0286132Y0003596D01*
+X0286132Y0004794D02*
+X0002568Y0004794D01*
+X0002568Y0005993D02*
+X0286132Y0005993D01*
+X0286132Y0007191D02*
+X0002568Y0007191D01*
+X0002568Y0008390D02*
+X0286132Y0008390D01*
+X0286132Y0009588D02*
+X0125246Y0009588D01*
+X0126444Y0010787D02*
+X0286132Y0010787D01*
+X0286132Y0011985D02*
+X0282178Y0011985D01*
+X0284786Y0013184D02*
+X0286132Y0013184D01*
+X0286132Y0014382D02*
+X0285857Y0014382D01*
+X0278000Y0014382D02*
+X0277000Y0014382D01*
+X0277000Y0013184D02*
+X0278000Y0013184D01*
+X0278000Y0011985D02*
+X0277000Y0011985D01*
+X0272822Y0011985D02*
+X0272178Y0011985D01*
+X0268000Y0011985D02*
+X0267000Y0011985D01*
+X0267000Y0011900D02*
+X0267000Y0017000D01*
+X0258209Y0017000D01*
+X0258338Y0016189D01*
+X0258610Y0015350D01*
+X0259010Y0014565D01*
+X0259529Y0013852D01*
+X0260152Y0013229D01*
+X0260865Y0012710D01*
+X0261650Y0012310D01*
+X0262489Y0012038D01*
+X0263359Y0011900D01*
+X0267000Y0011900D01*
+X0267000Y0013184D02*
+X0268000Y0013184D01*
+X0268000Y0014382D02*
+X0267000Y0014382D01*
+X0267000Y0015581D02*
+X0268000Y0015581D01*
+X0268000Y0016779D02*
+X0267000Y0016779D01*
+X0267000Y0017978D02*
+X0129959Y0017978D01*
+X0131157Y0019176D02*
+X0258456Y0019176D01*
+X0258980Y0020375D02*
+X0132356Y0020375D01*
+X0133046Y0021573D02*
+X0259954Y0021573D01*
+X0260781Y0022772D02*
+X0133168Y0022772D01*
+X0133168Y0023970D02*
+X0259443Y0023970D01*
+X0258703Y0025169D02*
+X0133168Y0025169D01*
+X0133168Y0026367D02*
+X0258310Y0026367D01*
+X0258330Y0028764D02*
+X0133168Y0028764D01*
+X0133168Y0027566D02*
+X0267000Y0027566D01*
+X0268000Y0027566D02*
+X0277000Y0027566D01*
+X0277000Y0026367D02*
+X0278000Y0026367D01*
+X0278000Y0025169D02*
+X0277000Y0025169D01*
+X0277000Y0023970D02*
+X0278000Y0023970D01*
+X0278000Y0022772D02*
+X0277000Y0022772D01*
+X0277000Y0021573D02*
+X0278000Y0021573D01*
+X0278000Y0020375D02*
+X0277000Y0020375D01*
+X0277000Y0019176D02*
+X0278000Y0019176D01*
+X0277000Y0017978D02*
+X0268000Y0017978D01*
+X0268000Y0019176D02*
+X0267000Y0019176D01*
+X0267000Y0020375D02*
+X0268000Y0020375D01*
+X0268000Y0021573D02*
+X0267000Y0021573D01*
+X0267000Y0022772D02*
+X0268000Y0022772D01*
+X0268000Y0023970D02*
+X0267000Y0023970D01*
+X0267000Y0025169D02*
+X0268000Y0025169D01*
+X0268000Y0026367D02*
+X0267000Y0026367D01*
+X0259542Y0031161D02*
+X0258224Y0031161D01*
+X0258093Y0030847D02*
+X0258356Y0031482D01*
+X0258491Y0032156D01*
+X0258491Y0032500D01*
+X0258491Y0032844D01*
+X0258356Y0033518D01*
+X0258093Y0034153D01*
+X0257711Y0034725D01*
+X0257225Y0035211D01*
+X0256653Y0035593D01*
+X0256018Y0035856D01*
+X0255344Y0035991D01*
+X0255000Y0035991D01*
+X0254656Y0035991D01*
+X0253982Y0035856D01*
+X0253347Y0035593D01*
+X0252775Y0035211D01*
+X0252289Y0034725D01*
+X0251907Y0034153D01*
+X0251644Y0033518D01*
+X0251509Y0032844D01*
+X0251509Y0032500D01*
+X0251509Y0032156D01*
+X0251644Y0031482D01*
+X0251907Y0030847D01*
+X0252289Y0030275D01*
+X0252775Y0029789D01*
+X0253347Y0029407D01*
+X0253982Y0029144D01*
+X0254656Y0029009D01*
+X0255000Y0029009D01*
+X0255344Y0029009D01*
+X0256018Y0029144D01*
+X0256653Y0029407D01*
+X0257225Y0029789D01*
+X0257711Y0030275D01*
+X0258093Y0030847D01*
+X0258770Y0029963D02*
+X0257399Y0029963D01*
+X0255000Y0029963D02*
+X0255000Y0029963D01*
+X0255000Y0029009D02*
+X0255000Y0032500D01*
+X0258491Y0032500D01*
+X0255000Y0032500D01*
+X0255000Y0032500D01*
+X0255000Y0032500D01*
+X0255000Y0035991D01*
+X0255000Y0032500D01*
+X0255000Y0032500D01*
+X0255000Y0032500D01*
+X0251509Y0032500D01*
+X0255000Y0032500D01*
+X0255000Y0029009D01*
+X0255000Y0031161D02*
+X0255000Y0031161D01*
+X0255000Y0032360D02*
+X0255000Y0032360D01*
+X0255000Y0033558D02*
+X0255000Y0033558D01*
+X0255000Y0034757D02*
+X0255000Y0034757D01*
+X0255000Y0035955D02*
+X0255000Y0035955D01*
+X0255521Y0035955D02*
+X0257655Y0035955D01*
+X0257680Y0034757D02*
+X0258151Y0034757D01*
+X0258340Y0033558D02*
+X0258877Y0033558D01*
+X0258491Y0032360D02*
+X0260075Y0032360D01*
+X0257531Y0037154D02*
+X0130890Y0037154D01*
+X0129692Y0038352D02*
+X0257531Y0038352D01*
+X0257865Y0039551D02*
+X0128493Y0039551D01*
+X0126063Y0037500D02*
+X0111358Y0037500D01*
+X0107421Y0041437D01*
+X0107421Y0072559D01*
+X0105453Y0072559D02*
+X0105453Y0038937D01*
+X0109390Y0035000D01*
+X0113563Y0035000D01*
+X0117500Y0031063D01*
+X0117500Y0020000D01*
+X0112500Y0015000D01*
+X0116444Y0010787D02*
+X0118555Y0010787D01*
+X0119754Y0009588D02*
+X0115246Y0009588D01*
+X0109754Y0009588D02*
+X0105246Y0009588D01*
+X0106444Y0010787D02*
+X0108555Y0010787D01*
+X0102500Y0015000D02*
+X0107500Y0020000D01*
+X0107500Y0028563D01*
+X0103563Y0032500D01*
+X0103484Y0032500D01*
+X0099547Y0036437D01*
+X0099547Y0072559D01*
+X0097579Y0072559D02*
+X0097579Y0020079D01*
+X0092500Y0015000D01*
+X0096444Y0010787D02*
+X0098555Y0010787D01*
+X0099754Y0009588D02*
+X0095246Y0009588D01*
+X0089754Y0009588D02*
+X0085246Y0009588D01*
+X0086444Y0010787D02*
+X0088555Y0010787D01*
+X0082500Y0015000D02*
+X0087500Y0020000D01*
+X0087500Y0043563D01*
+X0091437Y0047500D01*
+X0091673Y0047500D01*
+X0095610Y0051437D01*
+X0095610Y0072559D01*
+X0091673Y0072559D02*
+X0091673Y0086142D01*
+X0100000Y0086142D01*
+X0100000Y0109764D01*
+X0080059Y0109764D01*
+X0124941Y0109764D01*
+X0128750Y0109764D01*
+X0128750Y0122500D01*
+X0153760Y0122500D01*
+X0155000Y0122500D01*
+X0155000Y0130000D01*
+X0190000Y0130000D01*
+X0186708Y0133168D02*
+X0187412Y0133873D01*
+X0189091Y0134568D01*
+X0190909Y0134568D01*
+X0192588Y0133873D01*
+X0193873Y0132588D01*
+X0194331Y0131481D01*
+X0194331Y0144208D01*
+X0193627Y0144912D01*
+X0193168Y0146019D01*
+X0193168Y0140807D01*
+X0192686Y0139642D01*
+X0189999Y0136955D01*
+X0189999Y0136955D01*
+X0189108Y0136064D01*
+X0187943Y0135581D01*
+X0136963Y0135581D01*
+X0137577Y0135327D01*
+X0138043Y0134861D01*
+X0138145Y0134920D01*
+X0138628Y0135050D01*
+X0140837Y0135050D01*
+X0140837Y0130600D01*
+X0142037Y0130600D01*
+X0142037Y0135050D01*
+X0144246Y0135050D01*
+X0144729Y0134920D01*
+X0145163Y0134670D01*
+X0145516Y0134316D01*
+X0145767Y0133883D01*
+X0145896Y0133400D01*
+X0145896Y0130600D01*
+X0142037Y0130600D01*
+X0142037Y0129400D01*
+X0145896Y0129400D01*
+X0145896Y0126600D01*
+X0145767Y0126117D01*
+X0145516Y0125684D01*
+X0145501Y0125668D01*
+X0148632Y0125668D01*
+X0148632Y0125964D01*
+X0149023Y0126908D01*
+X0149746Y0127630D01*
+X0150058Y0127759D01*
+X0150000Y0127759D01*
+X0150000Y0131250D01*
+X0150000Y0131250D01*
+X0150000Y0134741D01*
+X0149656Y0134741D01*
+X0148982Y0134606D01*
+X0148347Y0134343D01*
+X0147775Y0133961D01*
+X0147289Y0133475D01*
+X0146907Y0132903D01*
+X0146644Y0132268D01*
+X0146509Y0131594D01*
+X0146509Y0131250D01*
+X0146509Y0130906D01*
+X0146644Y0130232D01*
+X0146907Y0129597D01*
+X0147289Y0129025D01*
+X0147775Y0128539D01*
+X0148347Y0128157D01*
+X0148982Y0127894D01*
+X0149656Y0127759D01*
+X0150000Y0127759D01*
+X0150000Y0131250D01*
+X0150000Y0131250D01*
+X0150000Y0131250D01*
+X0146509Y0131250D01*
+X0150000Y0131250D01*
+X0150000Y0134741D01*
+X0150344Y0134741D01*
+X0151018Y0134606D01*
+X0151653Y0134343D01*
+X0152225Y0133961D01*
+X0152711Y0133475D01*
+X0153093Y0132903D01*
+X0153190Y0132671D01*
+X0153205Y0132686D01*
+X0154370Y0133168D01*
+X0186708Y0133168D01*
+X0188282Y0134233D02*
+X0151818Y0134233D01*
+X0153005Y0133035D02*
+X0154047Y0133035D01*
+X0150000Y0133035D02*
+X0150000Y0133035D01*
+X0150000Y0134233D02*
+X0150000Y0134233D01*
+X0148182Y0134233D02*
+X0145564Y0134233D01*
+X0145896Y0133035D02*
+X0146995Y0133035D01*
+X0146558Y0131836D02*
+X0145896Y0131836D01*
+X0145896Y0130638D02*
+X0146563Y0130638D01*
+X0147012Y0129439D02*
+X0142037Y0129439D01*
+X0142037Y0130638D02*
+X0140837Y0130638D01*
+X0140837Y0131836D02*
+X0142037Y0131836D01*
+X0142037Y0133035D02*
+X0140837Y0133035D01*
+X0140837Y0134233D02*
+X0142037Y0134233D01*
+X0137324Y0135432D02*
+X0194331Y0135432D01*
+X0194331Y0136630D02*
+X0189674Y0136630D01*
+X0190873Y0137829D02*
+X0194331Y0137829D01*
+X0194331Y0139027D02*
+X0192071Y0139027D01*
+X0192928Y0140226D02*
+X0194331Y0140226D01*
+X0194331Y0141424D02*
+X0193168Y0141424D01*
+X0193168Y0142623D02*
+X0194331Y0142623D01*
+X0194331Y0143821D02*
+X0193168Y0143821D01*
+X0193168Y0145020D02*
+X0193582Y0145020D01*
+X0197500Y0147500D02*
+X0197500Y0123937D01*
+X0196063Y0122500D01*
+X0161240Y0122500D01*
+X0160856Y0122500D01*
+X0160856Y0109764D01*
+X0156919Y0105827D01*
+X0124941Y0105827D01*
+X0124941Y0107795D02*
+X0133563Y0107795D01*
+X0133563Y0115000D01*
+X0136731Y0109323D02*
+X0137577Y0109673D01*
+X0138043Y0110139D01*
+X0138145Y0110080D01*
+X0138628Y0109950D01*
+X0140837Y0109950D01*
+X0140837Y0114400D01*
+X0142037Y0114400D01*
+X0142037Y0115600D01*
+X0145896Y0115600D01*
+X0145896Y0118400D01*
+X0145767Y0118883D01*
+X0145516Y0119316D01*
+X0145501Y0119331D01*
+X0148632Y0119331D01*
+X0148632Y0119036D01*
+X0149023Y0118092D01*
+X0149746Y0117370D01*
+X0150690Y0116979D01*
+X0156830Y0116979D01*
+X0157500Y0117256D01*
+X0157688Y0117179D01*
+X0157688Y0111076D01*
+X0155607Y0108995D01*
+X0136731Y0108995D01*
+X0136731Y0109323D01*
+X0136731Y0109065D02*
+X0150629Y0109065D01*
+X0150906Y0109009D02*
+X0151250Y0109009D01*
+X0151594Y0109009D01*
+X0152268Y0109144D01*
+X0152903Y0109407D01*
+X0153475Y0109789D01*
+X0153961Y0110275D01*
+X0154343Y0110847D01*
+X0154606Y0111482D01*
+X0154741Y0112156D01*
+X0154741Y0112500D01*
+X0154741Y0112844D01*
+X0154606Y0113518D01*
+X0154343Y0114153D01*
+X0153961Y0114725D01*
+X0153475Y0115211D01*
+X0152903Y0115593D01*
+X0152268Y0115856D01*
+X0151594Y0115991D01*
+X0151250Y0115991D01*
+X0150906Y0115991D01*
+X0150232Y0115856D01*
+X0149597Y0115593D01*
+X0149025Y0115211D01*
+X0148539Y0114725D01*
+X0148157Y0114153D01*
+X0147894Y0113518D01*
+X0147759Y0112844D01*
+X0147759Y0112500D01*
+X0147759Y0112156D01*
+X0147894Y0111482D01*
+X0148157Y0110847D01*
+X0148539Y0110275D01*
+X0149025Y0109789D01*
+X0149597Y0109407D01*
+X0150232Y0109144D01*
+X0150906Y0109009D01*
+X0151250Y0109009D02*
+X0151250Y0112500D01*
+X0154741Y0112500D01*
+X0151250Y0112500D01*
+X0151250Y0112500D01*
+X0151250Y0112500D01*
+X0151250Y0115991D01*
+X0151250Y0112500D01*
+X0151250Y0109009D01*
+X0151250Y0109065D02*
+X0151250Y0109065D01*
+X0151871Y0109065D02*
+X0155676Y0109065D01*
+X0156875Y0110263D02*
+X0153949Y0110263D01*
+X0154598Y0111462D02*
+X0157688Y0111462D01*
+X0157688Y0112660D02*
+X0154741Y0112660D01*
+X0154465Y0113859D02*
+X0157688Y0113859D01*
+X0157688Y0115057D02*
+X0153629Y0115057D01*
+X0151250Y0115057D02*
+X0151250Y0115057D01*
+X0151250Y0113859D02*
+X0151250Y0113859D01*
+X0151250Y0112660D02*
+X0151250Y0112660D01*
+X0151250Y0112500D02*
+X0151250Y0112500D01*
+X0151250Y0112500D01*
+X0147759Y0112500D01*
+X0151250Y0112500D01*
+X0151250Y0111462D02*
+X0151250Y0111462D01*
+X0151250Y0110263D02*
+X0151250Y0110263D01*
+X0148551Y0110263D02*
+X0145047Y0110263D01*
+X0145163Y0110330D02*
+X0145516Y0110684D01*
+X0145767Y0111117D01*
+X0145896Y0111600D01*
+X0145896Y0114400D01*
+X0142037Y0114400D01*
+X0142037Y0109950D01*
+X0144246Y0109950D01*
+X0144729Y0110080D01*
+X0145163Y0110330D01*
+X0145859Y0111462D02*
+X0147902Y0111462D01*
+X0147759Y0112660D02*
+X0145896Y0112660D01*
+X0145896Y0113859D02*
+X0148035Y0113859D01*
+X0148871Y0115057D02*
+X0142037Y0115057D01*
+X0142037Y0113859D02*
+X0140837Y0113859D01*
+X0140837Y0112660D02*
+X0142037Y0112660D01*
+X0142037Y0111462D02*
+X0140837Y0111462D01*
+X0140837Y0110263D02*
+X0142037Y0110263D01*
+X0145896Y0116256D02*
+X0157688Y0116256D01*
+X0164025Y0116256D02*
+X0249618Y0116256D01*
+X0249725Y0116211D02*
+X0251181Y0116211D01*
+X0251181Y0114183D01*
+X0249986Y0114183D01*
+X0249503Y0114054D01*
+X0249070Y0113804D01*
+X0248716Y0113450D01*
+X0248466Y0113017D01*
+X0248336Y0112534D01*
+X0248336Y0111299D01*
+X0248336Y0110866D01*
+X0248059Y0110589D01*
+X0247668Y0109645D01*
+X0247668Y0108168D01*
+X0236312Y0108168D01*
+X0235186Y0109295D01*
+X0234295Y0110186D01*
+X0233130Y0110668D01*
+X0228868Y0110668D01*
+X0228868Y0110964D01*
+X0228477Y0111908D01*
+X0227754Y0112630D01*
+X0226810Y0113021D01*
+X0220670Y0113021D01*
+X0220000Y0112744D01*
+X0219330Y0113021D01*
+X0213190Y0113021D01*
+X0212246Y0112630D01*
+X0211523Y0111908D01*
+X0211132Y0110964D01*
+X0211132Y0110668D01*
+X0206870Y0110668D01*
+X0205705Y0110186D01*
+X0204814Y0109295D01*
+X0202546Y0107027D01*
+X0162600Y0107027D01*
+X0162651Y0107078D01*
+X0163542Y0107969D01*
+X0164025Y0109134D01*
+X0164025Y0116979D01*
+X0164310Y0116979D01*
+X0165254Y0117370D01*
+X0165977Y0118092D01*
+X0166368Y0119036D01*
+X0166368Y0119331D01*
+X0196693Y0119331D01*
+X0197858Y0119814D01*
+X0198749Y0120705D01*
+X0200186Y0122142D01*
+X0200668Y0123307D01*
+X0200668Y0144208D01*
+X0201373Y0144912D01*
+X0202068Y0146591D01*
+X0202068Y0148409D01*
+X0201373Y0150088D01*
+X0200088Y0151373D01*
+X0198409Y0152068D01*
+X0196591Y0152068D01*
+X0194912Y0151373D01*
+X0193627Y0150088D01*
+X0193168Y0148981D01*
+X0193168Y0152251D01*
+X0194729Y0153811D01*
+X0194912Y0153627D01*
+X0196591Y0152931D01*
+X0198409Y0152931D01*
+X0200088Y0153627D01*
+X0201373Y0154912D01*
+X0202068Y0156591D01*
+X0202068Y0158409D01*
+X0201373Y0160088D01*
+X0200088Y0161373D01*
+X0198409Y0162068D01*
+X0196591Y0162068D01*
+X0194912Y0161373D01*
+X0194208Y0160668D01*
+X0193307Y0160668D01*
+X0193168Y0160611D01*
+X0193168Y0202400D01*
+X0194600Y0202400D01*
+X0194600Y0207100D01*
+X0195400Y0207100D01*
+X0195400Y0207900D01*
+X0200100Y0207900D01*
+X0200100Y0209612D01*
+X0197685Y0212027D01*
+X0200768Y0215111D01*
+X0200768Y0219331D01*
+X0225246Y0219331D01*
+X0225246Y0215198D01*
+X0225637Y0214254D01*
+X0226360Y0213531D01*
+X0227304Y0213140D01*
+X0240924Y0213140D01*
+X0241868Y0213531D01*
+X0242591Y0214254D01*
+X0242778Y0214706D01*
+X0252222Y0214706D01*
+X0252409Y0214254D01*
+X0253132Y0213531D01*
+X0254076Y0213140D01*
+X0267696Y0213140D01*
+X0268640Y0213531D01*
+X0269282Y0214173D01*
+X0269282Y0213367D01*
+X0269673Y0212423D01*
+X0270139Y0211957D01*
+X0270080Y0211855D01*
+X0269950Y0211372D01*
+X0269950Y0209163D01*
+X0274400Y0209163D01*
+X0274400Y0207963D01*
+X0269950Y0207963D01*
+X0269950Y0205754D01*
+X0270080Y0205271D01*
+X0270330Y0204837D01*
+X0270684Y0204484D01*
+X0271117Y0204233D01*
+X0271600Y0204104D01*
+X0274400Y0204104D01*
+X0274400Y0207963D01*
+X0275600Y0207963D01*
+X0275600Y0209163D01*
+X0280050Y0209163D01*
+X0280050Y0211372D01*
+X0279920Y0211855D01*
+X0279861Y0211957D01*
+X0280327Y0212423D01*
+X0280718Y0213367D01*
+X0280718Y0219507D01*
+X0280327Y0220451D01*
+X0279605Y0221174D01*
+X0278661Y0221565D01*
+X0271339Y0221565D01*
+X0270395Y0221174D01*
+X0270264Y0221043D01*
+X0269550Y0221043D01*
+X0269363Y0221494D01*
+X0268640Y0222217D01*
+X0267696Y0222608D01*
+X0254076Y0222608D01*
+X0253132Y0222217D01*
+X0252409Y0221494D01*
+X0252222Y0221043D01*
+X0242778Y0221043D01*
+X0242591Y0221494D01*
+X0241868Y0222217D01*
+X0240924Y0222608D01*
+X0237283Y0222608D01*
+X0237283Y0223130D01*
+X0236800Y0224295D01*
+X0235909Y0225186D01*
+X0234744Y0225668D01*
+X0189370Y0225668D01*
+X0188205Y0225186D01*
+X0187314Y0224295D01*
+X0186288Y0223268D01*
+X0182611Y0223268D01*
+X0179231Y0219889D01*
+X0179231Y0216212D01*
+X0178205Y0215186D01*
+X0177314Y0214295D01*
+X0176831Y0213130D01*
+X0176831Y0193812D01*
+X0173688Y0190668D01*
+X0149551Y0190668D01*
+X0153696Y0194814D01*
+X0154588Y0195705D01*
+X0155070Y0196870D01*
+X0155070Y0198882D01*
+X0155562Y0198882D01*
+X0156506Y0199273D01*
+X0157229Y0199996D01*
+X0157500Y0200651D01*
+X0157771Y0199996D01*
+X0158494Y0199273D01*
+X0159438Y0198882D01*
+X0166759Y0198882D01*
+X0167703Y0199273D01*
+X0168425Y0199996D01*
+X0168817Y0200940D01*
+X0168817Y0209060D01*
+X0168425Y0210004D01*
+X0167703Y0210727D01*
+X0166759Y0211118D01*
+X0166267Y0211118D01*
+X0166267Y0213793D01*
+X0166368Y0214036D01*
+X0166368Y0220964D01*
+X0165977Y0221908D01*
+X0165254Y0222630D01*
+X0164310Y0223021D01*
+X0158170Y0223021D01*
+X0157226Y0222630D01*
+X0156868Y0222273D01*
+X0156569Y0222353D01*
+X0154360Y0222353D01*
+X0154360Y0218100D01*
+X0153160Y0218100D01*
+X0153160Y0222353D01*
+X0150951Y0222353D01*
+X0150467Y0222223D01*
+X0150034Y0221973D01*
+X0149680Y0221619D01*
+X0149430Y0221186D01*
+X0149301Y0220703D01*
+X0149301Y0218100D01*
+X0153160Y0218100D01*
+X0153160Y0216900D01*
+X0154360Y0216900D01*
+X0154360Y0212647D01*
+X0156569Y0212647D01*
+X0156868Y0212727D01*
+X0157226Y0212370D01*
+X0158170Y0211979D01*
+X0159930Y0211979D01*
+X0159930Y0211118D01*
+X0159438Y0211118D01*
+X0158494Y0210727D01*
+X0157771Y0210004D01*
+X0157500Y0209349D01*
+X0157229Y0210004D01*
+X0156506Y0210727D01*
+X0155562Y0211118D01*
+X0148241Y0211118D01*
+X0147297Y0210727D01*
+X0146574Y0210004D01*
+X0146183Y0209060D01*
+X0146183Y0200940D01*
+X0146574Y0199996D01*
+X0147297Y0199273D01*
+X0148241Y0198882D01*
+X0148733Y0198882D01*
+X0148733Y0198812D01*
+X0145589Y0195668D01*
+X0129551Y0195668D01*
+X0129588Y0195705D01*
+X0130070Y0196870D01*
+X0130070Y0198882D01*
+X0130562Y0198882D01*
+X0131506Y0199273D01*
+X0132229Y0199996D01*
+X0132500Y0200651D01*
+X0132771Y0199996D01*
+X0133494Y0199273D01*
+X0134438Y0198882D01*
+X0141759Y0198882D01*
+X0142703Y0199273D01*
+X0143425Y0199996D01*
+X0143817Y0200940D01*
+X0143817Y0209060D01*
+X0143425Y0210004D01*
+X0142703Y0210727D01*
+X0141759Y0211118D01*
+X0141267Y0211118D01*
+X0141267Y0213793D01*
+X0141368Y0214036D01*
+X0141368Y0220964D01*
+X0140977Y0221908D01*
+X0140254Y0222630D01*
+X0139310Y0223021D01*
+X0133170Y0223021D01*
+X0132226Y0222630D01*
+X0131868Y0222273D01*
+X0131569Y0222353D01*
+X0129360Y0222353D01*
+X0129360Y0218100D01*
+X0128160Y0218100D01*
+X0128160Y0222353D01*
+X0125951Y0222353D01*
+X0125467Y0222223D01*
+X0125034Y0221973D01*
+X0124680Y0221619D01*
+X0124430Y0221186D01*
+X0124301Y0220703D01*
+X0124301Y0218100D01*
+X0128160Y0218100D01*
+X0128160Y0216900D01*
+X0129360Y0216900D01*
+X0129360Y0212647D01*
+X0131569Y0212647D01*
+X0131868Y0212727D01*
+X0132226Y0212370D01*
+X0133170Y0211979D01*
+X0134930Y0211979D01*
+X0134930Y0211118D01*
+X0134438Y0211118D01*
+X0133494Y0210727D01*
+X0132771Y0210004D01*
+X0132500Y0209349D01*
+X0132229Y0210004D01*
+X0131506Y0210727D01*
+X0130562Y0211118D01*
+X0123241Y0211118D01*
+X0122297Y0210727D01*
+X0121574Y0210004D01*
+X0121183Y0209060D01*
+X0121183Y0200940D01*
+X0121296Y0200668D01*
+X0118771Y0200668D01*
+X0118690Y0200635D01*
+X0118817Y0200940D01*
+X0118817Y0209060D01*
+X0118425Y0210004D01*
+X0117703Y0210727D01*
+X0116759Y0211118D01*
+X0116267Y0211118D01*
+X0116267Y0213793D01*
+X0116368Y0214036D01*
+X0116368Y0220964D01*
+X0115977Y0221908D01*
+X0115254Y0222630D01*
+X0114310Y0223021D01*
+X0108170Y0223021D01*
+X0107226Y0222630D01*
+X0106868Y0222273D01*
+X0106569Y0222353D01*
+X0104360Y0222353D01*
+X0104360Y0218100D01*
+X0103160Y0218100D01*
+X0103160Y0222353D01*
+X0100951Y0222353D01*
+X0100467Y0222223D01*
+X0100034Y0221973D01*
+X0099680Y0221619D01*
+X0099430Y0221186D01*
+X0099301Y0220703D01*
+X0099301Y0218100D01*
+X0103160Y0218100D01*
+X0103160Y0216900D01*
+X0104360Y0216900D01*
+X0104360Y0212647D01*
+X0106569Y0212647D01*
+X0106868Y0212727D01*
+X0107226Y0212370D01*
+X0108170Y0211979D01*
+X0109930Y0211979D01*
+X0109930Y0211118D01*
+X0109438Y0211118D01*
+X0108494Y0210727D01*
+X0107771Y0210004D01*
+X0107500Y0209349D01*
+X0107229Y0210004D01*
+X0106506Y0210727D01*
+X0105562Y0211118D01*
+X0098241Y0211118D01*
+X0097297Y0210727D01*
+X0096574Y0210004D01*
+X0096183Y0209060D01*
+X0096183Y0208168D01*
+X0085653Y0208168D01*
+X0085186Y0209295D01*
+X0084295Y0210186D01*
+X0079295Y0215186D01*
+X0078130Y0215668D01*
+X0068268Y0215668D01*
+X0068268Y0219889D01*
+X0064889Y0223268D01*
+X0061212Y0223268D01*
+X0057686Y0226795D01*
+X0057089Y0227392D01*
+X0286132Y0227392D01*
+X0286132Y0166433D01*
+X0284751Y0167814D01*
+X0282447Y0168768D01*
+X0272553Y0168768D01*
+X0270249Y0167814D01*
+X0268704Y0166268D01*
+X0261750Y0166268D01*
+X0260365Y0165695D01*
+X0255365Y0160695D01*
+X0254975Y0160305D01*
+X0254233Y0160305D01*
+X0253289Y0159914D01*
+X0252567Y0159191D01*
+X0252176Y0158247D01*
+X0252176Y0151713D01*
+X0252567Y0150769D01*
+X0253289Y0150047D01*
+X0254233Y0149656D01*
+X0260767Y0149656D01*
+X0261711Y0150047D01*
+X0262433Y0150769D01*
+X0262824Y0151713D01*
+X0262824Y0157495D01*
+X0264061Y0158731D01*
+X0268704Y0158731D01*
+X0270249Y0157186D01*
+X0270550Y0157061D01*
+X0270152Y0156771D01*
+X0269529Y0156148D01*
+X0269010Y0155435D01*
+X0268610Y0154650D01*
+X0268338Y0153811D01*
+X0268209Y0153000D01*
+X0277000Y0153000D01*
+X0277000Y0152000D01*
+X0278000Y0152000D01*
+X0278000Y0146900D01*
+X0281641Y0146900D01*
+X0282511Y0147038D01*
+X0283350Y0147310D01*
+X0284135Y0147710D01*
+X0284848Y0148229D01*
+X0285471Y0148852D01*
+X0285990Y0149565D01*
+X0286132Y0149845D01*
+X0286132Y0051433D01*
+X0284751Y0052814D01*
+X0282447Y0053768D01*
+X0272553Y0053768D01*
+X0272500Y0053746D01*
+X0272447Y0053768D01*
+X0269418Y0053768D01*
+X0269418Y0053926D01*
+X0270256Y0054273D01*
+X0270979Y0054996D01*
+X0271250Y0055651D01*
+X0271521Y0054996D01*
+X0272244Y0054273D01*
+X0273188Y0053882D01*
+X0280509Y0053882D01*
+X0281453Y0054273D01*
+X0282175Y0054996D01*
+X0282567Y0055940D01*
+X0282567Y0064060D01*
+X0282175Y0065004D01*
+X0281453Y0065727D01*
+X0280509Y0066118D01*
+X0280017Y0066118D01*
+X0280017Y0068793D01*
+X0280118Y0069036D01*
+X0280118Y0075964D01*
+X0279727Y0076908D01*
+X0279004Y0077630D01*
+X0278060Y0078021D01*
+X0277876Y0078021D01*
+X0278093Y0078347D01*
+X0278356Y0078982D01*
+X0278491Y0079656D01*
+X0278491Y0080000D01*
+X0278491Y0080344D01*
+X0278404Y0080778D01*
+X0282243Y0080778D01*
+X0283187Y0081169D01*
+X0283910Y0081892D01*
+X0284301Y0082836D01*
+X0284301Y0091731D01*
+X0283910Y0092675D01*
+X0283187Y0093398D01*
+X0282243Y0093789D01*
+X0281318Y0093789D01*
+X0281318Y0116211D01*
+X0282243Y0116211D01*
+X0283187Y0116602D01*
+X0283910Y0117325D01*
+X0284301Y0118269D01*
+X0284301Y0127164D01*
+X0283910Y0128108D01*
+X0283187Y0128831D01*
+X0282243Y0129222D01*
+X0271379Y0129222D01*
+X0271268Y0129176D01*
+X0271268Y0135750D01*
+X0270695Y0137135D01*
+X0269635Y0138195D01*
+X0264635Y0143195D01*
+X0263250Y0143768D01*
+X0262625Y0143768D01*
+X0262433Y0144231D01*
+X0261711Y0144953D01*
+X0260767Y0145344D01*
+X0254233Y0145344D01*
+X0253289Y0144953D01*
+X0252567Y0144231D01*
+X0252375Y0143768D01*
+X0251375Y0143768D01*
+X0251183Y0144231D01*
+X0250461Y0144953D01*
+X0249517Y0145344D01*
+X0242983Y0145344D01*
+X0242039Y0144953D01*
+X0241317Y0144231D01*
+X0240926Y0143286D01*
+X0240926Y0136753D01*
+X0241317Y0135809D01*
+X0242039Y0135086D01*
+X0242983Y0134695D01*
+X0249517Y0134695D01*
+X0250461Y0135086D01*
+X0251183Y0135809D01*
+X0251358Y0136231D01*
+X0252392Y0136231D01*
+X0252567Y0135809D01*
+X0253289Y0135086D01*
+X0254233Y0134695D01*
+X0260767Y0134695D01*
+X0261711Y0135086D01*
+X0261898Y0135273D01*
+X0263731Y0133439D01*
+X0263731Y0126318D01*
+X0262647Y0126318D01*
+X0262647Y0127164D01*
+X0262256Y0128108D01*
+X0261534Y0128831D01*
+X0260590Y0129222D01*
+X0249725Y0129222D01*
+X0248781Y0128831D01*
+X0248059Y0128108D01*
+X0247668Y0127164D01*
+X0247668Y0118269D01*
+X0248059Y0117325D01*
+X0248781Y0116602D01*
+X0249725Y0116211D01*
+X0251181Y0115057D02*
+X0164025Y0115057D01*
+X0164025Y0113859D02*
+X0249164Y0113859D01*
+X0248370Y0112660D02*
+X0227682Y0112660D01*
+X0228661Y0111462D02*
+X0248336Y0111462D01*
+X0248336Y0111299D02*
+X0248769Y0111299D01*
+X0248336Y0111299D01*
+X0248769Y0111299D02*
+X0248769Y0111299D01*
+X0247924Y0110263D02*
+X0234109Y0110263D01*
+X0235416Y0109065D02*
+X0247668Y0109065D01*
+X0240000Y0111299D02*
+X0240000Y0122500D01*
+X0243491Y0122500D01*
+X0243491Y0122844D01*
+X0243356Y0123518D01*
+X0243093Y0124153D01*
+X0242711Y0124725D01*
+X0242225Y0125211D01*
+X0241653Y0125593D01*
+X0241018Y0125856D01*
+X0240344Y0125991D01*
+X0240000Y0125991D01*
+X0239656Y0125991D01*
+X0238982Y0125856D01*
+X0238347Y0125593D01*
+X0237775Y0125211D01*
+X0237289Y0124725D01*
+X0236907Y0124153D01*
+X0236644Y0123518D01*
+X0236509Y0122844D01*
+X0236509Y0122500D01*
+X0236509Y0122156D01*
+X0236644Y0121482D01*
+X0236907Y0120847D01*
+X0237289Y0120275D01*
+X0237775Y0119789D01*
+X0238347Y0119407D01*
+X0238982Y0119144D01*
+X0239656Y0119009D01*
+X0240000Y0119009D01*
+X0240344Y0119009D01*
+X0241018Y0119144D01*
+X0241653Y0119407D01*
+X0242225Y0119789D01*
+X0242711Y0120275D01*
+X0243093Y0120847D01*
+X0243356Y0121482D01*
+X0243491Y0122156D01*
+X0243491Y0122500D01*
+X0240000Y0122500D01*
+X0240000Y0122500D01*
+X0240000Y0122500D01*
+X0240000Y0125991D01*
+X0240000Y0122500D01*
+X0240000Y0119009D01*
+X0240000Y0122500D01*
+X0240000Y0122500D01*
+X0240000Y0122500D01*
+X0236509Y0122500D01*
+X0240000Y0122500D01*
+X0240000Y0122248D02*
+X0240000Y0122248D01*
+X0240000Y0121050D02*
+X0240000Y0121050D01*
+X0240000Y0119851D02*
+X0240000Y0119851D01*
+X0242288Y0119851D02*
+X0247668Y0119851D01*
+X0247668Y0118653D02*
+X0166209Y0118653D01*
+X0165338Y0117454D02*
+X0248005Y0117454D01*
+X0247668Y0121050D02*
+X0243177Y0121050D01*
+X0243491Y0122248D02*
+X0247668Y0122248D01*
+X0247668Y0123447D02*
+X0243371Y0123447D01*
+X0242765Y0124645D02*
+X0247668Y0124645D01*
+X0247668Y0125844D02*
+X0241049Y0125844D01*
+X0240000Y0125844D02*
+X0240000Y0125844D01*
+X0238951Y0125844D02*
+X0200668Y0125844D01*
+X0200668Y0127042D02*
+X0247668Y0127042D01*
+X0248191Y0128241D02*
+X0200668Y0128241D01*
+X0200668Y0129439D02*
+X0263731Y0129439D01*
+X0263731Y0128241D02*
+X0262124Y0128241D01*
+X0262647Y0127042D02*
+X0263731Y0127042D01*
+X0263731Y0130638D02*
+X0200668Y0130638D01*
+X0200668Y0131836D02*
+X0223517Y0131836D01*
+X0223347Y0131907D02*
+X0223982Y0131644D01*
+X0224656Y0131509D01*
+X0225000Y0131509D01*
+X0225344Y0131509D01*
+X0226018Y0131644D01*
+X0226653Y0131907D01*
+X0227225Y0132289D01*
+X0227711Y0132775D01*
+X0228093Y0133347D01*
+X0228356Y0133982D01*
+X0228491Y0134656D01*
+X0228491Y0135000D01*
+X0228491Y0135344D01*
+X0228356Y0136018D01*
+X0228093Y0136653D01*
+X0227711Y0137225D01*
+X0227225Y0137711D01*
+X0226653Y0138093D01*
+X0226018Y0138356D01*
+X0225344Y0138491D01*
+X0225000Y0138491D01*
+X0224656Y0138491D01*
+X0223982Y0138356D01*
+X0223347Y0138093D01*
+X0222775Y0137711D01*
+X0222289Y0137225D01*
+X0221907Y0136653D01*
+X0221644Y0136018D01*
+X0221509Y0135344D01*
+X0221509Y0135000D01*
+X0221509Y0134656D01*
+X0221644Y0133982D01*
+X0221907Y0133347D01*
+X0222289Y0132775D01*
+X0222775Y0132289D01*
+X0223347Y0131907D01*
+X0225000Y0131836D02*
+X0225000Y0131836D01*
+X0225000Y0131509D02*
+X0225000Y0135000D01*
+X0228491Y0135000D01*
+X0225000Y0135000D01*
+X0225000Y0135000D01*
+X0225000Y0135000D01*
+X0225000Y0138491D01*
+X0225000Y0135000D01*
+X0225000Y0135000D01*
+X0225000Y0135000D01*
+X0221509Y0135000D01*
+X0225000Y0135000D01*
+X0225000Y0131509D01*
+X0226483Y0131836D02*
+X0263731Y0131836D01*
+X0263731Y0133035D02*
+X0227885Y0133035D01*
+X0228406Y0134233D02*
+X0262937Y0134233D01*
+X0268802Y0139027D02*
+X0274355Y0139027D01*
+X0274407Y0139153D02*
+X0274144Y0138518D01*
+X0274009Y0137844D01*
+X0274009Y0137500D01*
+X0274009Y0137156D01*
+X0274144Y0136482D01*
+X0274407Y0135847D01*
+X0274789Y0135275D01*
+X0275275Y0134789D01*
+X0275847Y0134407D01*
+X0276482Y0134144D01*
+X0277156Y0134009D01*
+X0277500Y0134009D01*
+X0277844Y0134009D01*
+X0278518Y0134144D01*
+X0279153Y0134407D01*
+X0279725Y0134789D01*
+X0280211Y0135275D01*
+X0280593Y0135847D01*
+X0280856Y0136482D01*
+X0280991Y0137156D01*
+X0280991Y0137500D01*
+X0280991Y0137844D01*
+X0280856Y0138518D01*
+X0280593Y0139153D01*
+X0280211Y0139725D01*
+X0279725Y0140211D01*
+X0279153Y0140593D01*
+X0278518Y0140856D01*
+X0277844Y0140991D01*
+X0277500Y0140991D01*
+X0277156Y0140991D01*
+X0276482Y0140856D01*
+X0275847Y0140593D01*
+X0275275Y0140211D01*
+X0274789Y0139725D01*
+X0274407Y0139153D01*
+X0274009Y0137829D02*
+X0270001Y0137829D01*
+X0270904Y0136630D02*
+X0274114Y0136630D01*
+X0274009Y0137500D02*
+X0277500Y0137500D01*
+X0280991Y0137500D01*
+X0277500Y0137500D01*
+X0277500Y0137500D01*
+X0277500Y0137500D01*
+X0277500Y0140991D01*
+X0277500Y0137500D01*
+X0277500Y0134009D01*
+X0277500Y0137500D01*
+X0277500Y0137500D01*
+X0277500Y0137500D01*
+X0274009Y0137500D01*
+X0274684Y0135432D02*
+X0271268Y0135432D01*
+X0271268Y0134233D02*
+X0276265Y0134233D01*
+X0277500Y0134233D02*
+X0277500Y0134233D01*
+X0277500Y0135432D02*
+X0277500Y0135432D01*
+X0277500Y0136630D02*
+X0277500Y0136630D01*
+X0277500Y0137829D02*
+X0277500Y0137829D01*
+X0277500Y0139027D02*
+X0277500Y0139027D01*
+X0277500Y0140226D02*
+X0277500Y0140226D01*
+X0275297Y0140226D02*
+X0267604Y0140226D01*
+X0266405Y0141424D02*
+X0286132Y0141424D01*
+X0286132Y0140226D02*
+X0279703Y0140226D01*
+X0280645Y0139027D02*
+X0286132Y0139027D01*
+X0286132Y0137829D02*
+X0280991Y0137829D01*
+X0280886Y0136630D02*
+X0286132Y0136630D01*
+X0286132Y0135432D02*
+X0280316Y0135432D01*
+X0278735Y0134233D02*
+X0286132Y0134233D01*
+X0286132Y0133035D02*
+X0271268Y0133035D01*
+X0271268Y0131836D02*
+X0286132Y0131836D01*
+X0286132Y0130638D02*
+X0271268Y0130638D01*
+X0271268Y0129439D02*
+X0286132Y0129439D01*
+X0286132Y0128241D02*
+X0283778Y0128241D01*
+X0284301Y0127042D02*
+X0286132Y0127042D01*
+X0286132Y0125844D02*
+X0284301Y0125844D01*
+X0284301Y0124645D02*
+X0286132Y0124645D01*
+X0286132Y0123447D02*
+X0284301Y0123447D01*
+X0284301Y0122248D02*
+X0286132Y0122248D01*
+X0286132Y0121050D02*
+X0284301Y0121050D01*
+X0284301Y0119851D02*
+X0286132Y0119851D01*
+X0286132Y0118653D02*
+X0284301Y0118653D01*
+X0283963Y0117454D02*
+X0286132Y0117454D01*
+X0286132Y0116256D02*
+X0282351Y0116256D01*
+X0281318Y0115057D02*
+X0286132Y0115057D01*
+X0286132Y0113859D02*
+X0281318Y0113859D01*
+X0281318Y0112660D02*
+X0286132Y0112660D01*
+X0286132Y0111462D02*
+X0281318Y0111462D01*
+X0281318Y0110263D02*
+X0286132Y0110263D01*
+X0286132Y0109065D02*
+X0281318Y0109065D01*
+X0281318Y0107866D02*
+X0286132Y0107866D01*
+X0286132Y0106668D02*
+X0281318Y0106668D01*
+X0281318Y0105469D02*
+X0286132Y0105469D01*
+X0286132Y0104270D02*
+X0281318Y0104270D01*
+X0281318Y0103072D02*
+X0286132Y0103072D01*
+X0286132Y0101873D02*
+X0281318Y0101873D01*
+X0281318Y0100675D02*
+X0286132Y0100675D01*
+X0286132Y0099476D02*
+X0281318Y0099476D01*
+X0281318Y0098278D02*
+X0286132Y0098278D01*
+X0286132Y0097079D02*
+X0281318Y0097079D01*
+X0281318Y0095881D02*
+X0286132Y0095881D01*
+X0286132Y0094682D02*
+X0281318Y0094682D01*
+X0282980Y0093484D02*
+X0286132Y0093484D01*
+X0286132Y0092285D02*
+X0284071Y0092285D01*
+X0284301Y0091087D02*
+X0286132Y0091087D01*
+X0286132Y0089888D02*
+X0284301Y0089888D01*
+X0284301Y0088690D02*
+X0286132Y0088690D01*
+X0286132Y0087491D02*
+X0284301Y0087491D01*
+X0284301Y0086293D02*
+X0286132Y0086293D01*
+X0286132Y0085094D02*
+X0284301Y0085094D01*
+X0284301Y0083896D02*
+X0286132Y0083896D01*
+X0286132Y0082697D02*
+X0284244Y0082697D01*
+X0283517Y0081499D02*
+X0286132Y0081499D01*
+X0286132Y0080300D02*
+X0278491Y0080300D01*
+X0278491Y0080000D02*
+X0275000Y0080000D01*
+X0275000Y0080000D01*
+X0275000Y0080000D01*
+X0271509Y0080000D01*
+X0271509Y0079656D01*
+X0271644Y0078982D01*
+X0271907Y0078347D01*
+X0272124Y0078021D01*
+X0271920Y0078021D01*
+X0270976Y0077630D01*
+X0270618Y0077273D01*
+X0270319Y0077353D01*
+X0268110Y0077353D01*
+X0268110Y0073100D01*
+X0266910Y0073100D01*
+X0266910Y0077353D01*
+X0265182Y0077353D01*
+X0265695Y0077865D01*
+X0269717Y0081887D01*
+X0270435Y0081169D01*
+X0271379Y0080778D01*
+X0271596Y0080778D01*
+X0271509Y0080344D01*
+X0271509Y0080000D01*
+X0275000Y0080000D01*
+X0278491Y0080000D01*
+X0278380Y0079102D02*
+X0286132Y0079102D01*
+X0286132Y0077903D02*
+X0278345Y0077903D01*
+X0279811Y0076705D02*
+X0286132Y0076705D01*
+X0286132Y0075506D02*
+X0280118Y0075506D01*
+X0280118Y0074308D02*
+X0286132Y0074308D01*
+X0286132Y0073109D02*
+X0280118Y0073109D01*
+X0280118Y0071911D02*
+X0286132Y0071911D01*
+X0286132Y0070712D02*
+X0280118Y0070712D01*
+X0280118Y0069514D02*
+X0286132Y0069514D01*
+X0286132Y0068315D02*
+X0280017Y0068315D01*
+X0280017Y0067117D02*
+X0286132Y0067117D01*
+X0286132Y0065918D02*
+X0280991Y0065918D01*
+X0282293Y0064720D02*
+X0286132Y0064720D01*
+X0286132Y0063521D02*
+X0282567Y0063521D01*
+X0282567Y0062323D02*
+X0286132Y0062323D01*
+X0286132Y0061124D02*
+X0282567Y0061124D01*
+X0282567Y0059926D02*
+X0286132Y0059926D01*
+X0286132Y0058727D02*
+X0282567Y0058727D01*
+X0282567Y0057529D02*
+X0286132Y0057529D01*
+X0286132Y0056330D02*
+X0282567Y0056330D01*
+X0282232Y0055132D02*
+X0286132Y0055132D01*
+X0286132Y0053933D02*
+X0280631Y0053933D01*
+X0284830Y0052734D02*
+X0286132Y0052734D01*
+X0286132Y0051536D02*
+X0286029Y0051536D01*
+X0276848Y0060000D02*
+X0276848Y0072500D01*
+X0274990Y0072500D01*
+X0273680Y0066979D02*
+X0271920Y0066979D01*
+X0270976Y0067370D01*
+X0270618Y0067727D01*
+X0270319Y0067647D01*
+X0268110Y0067647D01*
+X0268110Y0071900D01*
+X0266910Y0071900D01*
+X0266910Y0067647D01*
+X0264701Y0067647D01*
+X0264217Y0067777D01*
+X0263784Y0068027D01*
+X0263430Y0068381D01*
+X0263180Y0068814D01*
+X0263051Y0069297D01*
+X0263051Y0071900D01*
+X0266910Y0071900D01*
+X0266910Y0073100D01*
+X0263051Y0073100D01*
+X0263051Y0075703D01*
+X0263180Y0076186D01*
+X0263206Y0076231D01*
+X0260758Y0076231D01*
+X0260758Y0073100D01*
+X0256506Y0073100D01*
+X0256506Y0071900D01*
+X0260758Y0071900D01*
+X0260758Y0068313D01*
+X0260629Y0067830D01*
+X0260379Y0067396D01*
+X0260025Y0067043D01*
+X0259592Y0066792D01*
+X0259108Y0066663D01*
+X0256505Y0066663D01*
+X0256505Y0071900D01*
+X0255306Y0071900D01*
+X0255306Y0066663D01*
+X0255068Y0066663D01*
+X0255068Y0065837D01*
+X0255306Y0065837D01*
+X0255306Y0060600D01*
+X0256505Y0060600D01*
+X0256505Y0065837D01*
+X0259108Y0065837D01*
+X0259592Y0065708D01*
+X0260025Y0065457D01*
+X0260379Y0065104D01*
+X0260395Y0065075D01*
+X0261047Y0065727D01*
+X0261991Y0066118D01*
+X0269312Y0066118D01*
+X0270256Y0065727D01*
+X0270979Y0065004D01*
+X0271250Y0064349D01*
+X0271521Y0065004D01*
+X0272244Y0065727D01*
+X0273188Y0066118D01*
+X0273680Y0066118D01*
+X0273680Y0066979D01*
+X0272706Y0065918D02*
+X0269794Y0065918D01*
+X0271097Y0064720D02*
+X0271403Y0064720D01*
+X0271587Y0067117D02*
+X0260099Y0067117D01*
+X0260758Y0068315D02*
+X0263496Y0068315D01*
+X0263051Y0069514D02*
+X0260758Y0069514D01*
+X0260758Y0070712D02*
+X0263051Y0070712D01*
+X0263051Y0073109D02*
+X0260758Y0073109D01*
+X0260758Y0074308D02*
+X0263051Y0074308D01*
+X0263051Y0075506D02*
+X0260758Y0075506D01*
+X0265733Y0077903D02*
+X0271635Y0077903D01*
+X0271620Y0079102D02*
+X0266931Y0079102D01*
+X0268130Y0080300D02*
+X0271509Y0080300D01*
+X0270105Y0081499D02*
+X0269328Y0081499D01*
+X0268110Y0076705D02*
+X0266910Y0076705D01*
+X0266910Y0075506D02*
+X0268110Y0075506D01*
+X0268110Y0074308D02*
+X0266910Y0074308D01*
+X0266910Y0073109D02*
+X0268110Y0073109D01*
+X0266910Y0071911D02*
+X0256506Y0071911D01*
+X0256505Y0070712D02*
+X0255306Y0070712D01*
+X0255306Y0069514D02*
+X0256505Y0069514D01*
+X0256505Y0068315D02*
+X0255306Y0068315D01*
+X0255306Y0067117D02*
+X0256505Y0067117D01*
+X0255068Y0065918D02*
+X0261509Y0065918D01*
+X0256505Y0064720D02*
+X0255306Y0064720D01*
+X0255306Y0063521D02*
+X0256505Y0063521D01*
+X0256505Y0062323D02*
+X0255306Y0062323D01*
+X0255306Y0061124D02*
+X0256505Y0061124D01*
+X0256505Y0059400D02*
+X0256505Y0054163D01*
+X0259108Y0054163D01*
+X0259592Y0054292D01*
+X0260025Y0054543D01*
+X0260379Y0054896D01*
+X0260395Y0054925D01*
+X0261047Y0054273D01*
+X0261991Y0053882D01*
+X0263081Y0053882D01*
+X0263081Y0053768D01*
+X0262553Y0053768D01*
+X0254770Y0053768D01*
+X0254933Y0054163D01*
+X0255306Y0054163D01*
+X0255306Y0059400D01*
+X0256505Y0059400D01*
+X0256505Y0058727D02*
+X0255306Y0058727D01*
+X0255306Y0057529D02*
+X0256505Y0057529D01*
+X0256505Y0056330D02*
+X0255306Y0056330D01*
+X0255306Y0055132D02*
+X0256505Y0055132D01*
+X0254838Y0053933D02*
+X0261869Y0053933D01*
+X0266250Y0050000D02*
+X0266250Y0060000D01*
+X0265652Y0060000D01*
+X0271035Y0055132D02*
+X0271465Y0055132D01*
+X0273065Y0053933D02*
+X0269435Y0053933D01*
+X0257825Y0045543D02*
+X0137891Y0045543D01*
+X0137711Y0045275D02*
+X0138093Y0045847D01*
+X0138356Y0046482D01*
+X0138491Y0047156D01*
+X0138491Y0047500D01*
+X0138491Y0047844D01*
+X0138356Y0048518D01*
+X0138093Y0049153D01*
+X0137711Y0049725D01*
+X0137225Y0050211D01*
+X0136653Y0050593D01*
+X0136018Y0050856D01*
+X0135344Y0050991D01*
+X0135000Y0050991D01*
+X0134656Y0050991D01*
+X0133982Y0050856D01*
+X0133347Y0050593D01*
+X0132775Y0050211D01*
+X0132289Y0049725D01*
+X0131907Y0049153D01*
+X0131644Y0048518D01*
+X0131509Y0047844D01*
+X0131509Y0047500D01*
+X0131509Y0047156D01*
+X0131644Y0046482D01*
+X0131907Y0045847D01*
+X0132289Y0045275D01*
+X0132775Y0044789D01*
+X0133347Y0044407D01*
+X0133982Y0044144D01*
+X0134656Y0044009D01*
+X0135000Y0044009D01*
+X0135344Y0044009D01*
+X0136018Y0044144D01*
+X0136653Y0044407D01*
+X0137225Y0044789D01*
+X0137711Y0045275D01*
+X0136504Y0044345D02*
+X0258322Y0044345D01*
+X0259289Y0043146D02*
+X0130085Y0043146D01*
+X0130699Y0044345D02*
+X0133496Y0044345D01*
+X0135000Y0044345D02*
+X0135000Y0044345D01*
+X0135000Y0044009D02*
+X0135000Y0047500D01*
+X0138491Y0047500D01*
+X0135000Y0047500D01*
+X0135000Y0047500D01*
+X0135000Y0047500D01*
+X0135000Y0050991D01*
+X0135000Y0047500D01*
+X0135000Y0047500D01*
+X0135000Y0047500D01*
+X0131509Y0047500D01*
+X0135000Y0047500D01*
+X0135000Y0044009D01*
+X0135000Y0045543D02*
+X0135000Y0045543D01*
+X0135000Y0046742D02*
+X0135000Y0046742D01*
+X0135000Y0047940D02*
+X0135000Y0047940D01*
+X0135000Y0049139D02*
+X0135000Y0049139D01*
+X0135000Y0050337D02*
+X0135000Y0050337D01*
+X0132964Y0050337D02*
+X0130699Y0050337D01*
+X0130699Y0050703D02*
+X0130570Y0051186D01*
+X0130320Y0051619D01*
+X0129966Y0051973D01*
+X0129533Y0052223D01*
+X0129049Y0052353D01*
+X0126840Y0052353D01*
+X0126840Y0048100D01*
+X0130699Y0048100D01*
+X0130699Y0050703D01*
+X0130368Y0051536D02*
+X0163731Y0051536D01*
+X0163731Y0052734D02*
+X0122522Y0052734D01*
+X0125640Y0051536D02*
+X0126840Y0051536D01*
+X0126840Y0050337D02*
+X0125640Y0050337D01*
+X0125640Y0049139D02*
+X0126840Y0049139D01*
+X0126840Y0047940D02*
+X0131529Y0047940D01*
+X0131592Y0046742D02*
+X0130699Y0046742D01*
+X0130699Y0045543D02*
+X0132109Y0045543D01*
+X0131901Y0049139D02*
+X0130699Y0049139D01*
+X0126840Y0046742D02*
+X0125640Y0046742D01*
+X0125640Y0045543D02*
+X0126840Y0045543D01*
+X0126840Y0044345D02*
+X0125640Y0044345D01*
+X0125640Y0043146D02*
+X0126840Y0043146D01*
+X0126063Y0037500D02*
+X0130000Y0033563D01*
+X0130000Y0022500D01*
+X0122500Y0015000D01*
+X0128268Y0015581D02*
+X0258535Y0015581D01*
+X0258244Y0016779D02*
+X0128760Y0016779D01*
+X0128268Y0014382D02*
+X0259143Y0014382D01*
+X0260214Y0013184D02*
+X0128268Y0013184D01*
+X0127643Y0011985D02*
+X0262822Y0011985D01*
+X0277000Y0015581D02*
+X0278000Y0015581D01*
+X0278000Y0016779D02*
+X0277000Y0016779D01*
+X0252601Y0029963D02*
+X0133168Y0029963D01*
+X0133168Y0031161D02*
+X0251776Y0031161D01*
+X0251509Y0032360D02*
+X0133168Y0032360D01*
+X0133168Y0033558D02*
+X0251660Y0033558D01*
+X0252320Y0034757D02*
+X0132935Y0034757D01*
+X0132089Y0035955D02*
+X0254479Y0035955D01*
+X0258361Y0040749D02*
+X0112590Y0040749D01*
+X0111391Y0041948D02*
+X0259383Y0041948D01*
+X0239969Y0053768D02*
+X0171268Y0053768D01*
+X0171268Y0075750D01*
+X0170695Y0077135D01*
+X0169635Y0078195D01*
+X0168250Y0078768D01*
+X0129720Y0078768D01*
+X0129872Y0079135D01*
+X0129872Y0094784D01*
+X0188688Y0094784D01*
+X0195267Y0088205D01*
+X0195903Y0087568D01*
+X0189804Y0087568D01*
+X0188860Y0087177D01*
+X0188137Y0086455D01*
+X0187746Y0085511D01*
+X0187746Y0066989D01*
+X0188137Y0066045D01*
+X0188860Y0065323D01*
+X0189804Y0064931D01*
+X0213124Y0064931D01*
+X0213124Y0062388D01*
+X0216411Y0062388D01*
+X0216411Y0062013D01*
+X0216786Y0062013D01*
+X0216786Y0057545D01*
+X0218423Y0057545D01*
+X0218907Y0057674D01*
+X0219016Y0057737D01*
+X0219470Y0057283D01*
+X0220414Y0056892D01*
+X0224586Y0056892D01*
+X0225432Y0057243D01*
+X0226111Y0056961D01*
+X0226267Y0056805D01*
+X0227652Y0056231D01*
+X0238573Y0056231D01*
+X0238573Y0055552D01*
+X0238964Y0054608D01*
+X0239687Y0053886D01*
+X0239969Y0053768D01*
+X0239639Y0053933D02*
+X0171268Y0053933D01*
+X0171268Y0055132D02*
+X0204932Y0055132D01*
+X0204789Y0055275D02*
+X0205275Y0054789D01*
+X0205847Y0054407D01*
+X0206482Y0054144D01*
+X0207156Y0054009D01*
+X0207500Y0054009D01*
+X0207844Y0054009D01*
+X0208518Y0054144D01*
+X0209153Y0054407D01*
+X0209725Y0054789D01*
+X0210211Y0055275D01*
+X0210593Y0055847D01*
+X0210856Y0056482D01*
+X0210991Y0057156D01*
+X0210991Y0057500D01*
+X0210991Y0057844D01*
+X0210856Y0058518D01*
+X0210593Y0059153D01*
+X0210211Y0059725D01*
+X0209725Y0060211D01*
+X0209153Y0060593D01*
+X0208518Y0060856D01*
+X0207844Y0060991D01*
+X0207500Y0060991D01*
+X0207156Y0060991D01*
+X0206482Y0060856D01*
+X0205847Y0060593D01*
+X0205275Y0060211D01*
+X0204789Y0059725D01*
+X0204407Y0059153D01*
+X0204144Y0058518D01*
+X0204009Y0057844D01*
+X0204009Y0057500D01*
+X0204009Y0057156D01*
+X0204144Y0056482D01*
+X0204407Y0055847D01*
+X0204789Y0055275D01*
+X0204206Y0056330D02*
+X0171268Y0056330D01*
+X0171268Y0057529D02*
+X0204009Y0057529D01*
+X0204009Y0057500D02*
+X0207500Y0057500D01*
+X0210991Y0057500D01*
+X0207500Y0057500D01*
+X0207500Y0057500D01*
+X0207500Y0057500D01*
+X0207500Y0060991D01*
+X0207500Y0057500D01*
+X0207500Y0054009D01*
+X0207500Y0057500D01*
+X0207500Y0057500D01*
+X0207500Y0057500D01*
+X0204009Y0057500D01*
+X0204230Y0058727D02*
+X0171268Y0058727D01*
+X0171268Y0059926D02*
+X0204989Y0059926D01*
+X0207500Y0059926D02*
+X0207500Y0059926D01*
+X0207500Y0058727D02*
+X0207500Y0058727D01*
+X0207500Y0057529D02*
+X0207500Y0057529D01*
+X0207500Y0056330D02*
+X0207500Y0056330D01*
+X0207500Y0055132D02*
+X0207500Y0055132D01*
+X0210068Y0055132D02*
+X0238747Y0055132D01*
+X0227414Y0056330D02*
+X0210794Y0056330D01*
+X0210991Y0057529D02*
+X0219225Y0057529D01*
+X0216786Y0058727D02*
+X0216411Y0058727D01*
+X0216411Y0057545D02*
+X0216411Y0062013D01*
+X0213124Y0062013D01*
+X0213124Y0059195D01*
+X0213253Y0058712D01*
+X0213503Y0058278D01*
+X0213857Y0057924D01*
+X0214290Y0057674D01*
+X0214773Y0057545D01*
+X0216411Y0057545D01*
+X0216411Y0059926D02*
+X0216786Y0059926D01*
+X0216786Y0061124D02*
+X0216411Y0061124D01*
+X0216411Y0062323D02*
+X0171268Y0062323D01*
+X0171268Y0063521D02*
+X0213124Y0063521D01*
+X0213124Y0064720D02*
+X0171268Y0064720D01*
+X0171268Y0065918D02*
+X0188264Y0065918D01*
+X0187746Y0067117D02*
+X0171268Y0067117D01*
+X0171268Y0068315D02*
+X0187746Y0068315D01*
+X0187746Y0069514D02*
+X0171268Y0069514D01*
+X0171268Y0070712D02*
+X0187746Y0070712D01*
+X0187746Y0071911D02*
+X0171268Y0071911D01*
+X0171268Y0073109D02*
+X0187746Y0073109D01*
+X0187746Y0074308D02*
+X0171268Y0074308D01*
+X0171268Y0075506D02*
+X0187746Y0075506D01*
+X0187746Y0076705D02*
+X0170873Y0076705D01*
+X0169926Y0077903D02*
+X0187746Y0077903D01*
+X0187746Y0079102D02*
+X0129858Y0079102D01*
+X0129872Y0080300D02*
+X0187746Y0080300D01*
+X0187746Y0081499D02*
+X0129872Y0081499D01*
+X0129872Y0082697D02*
+X0187746Y0082697D01*
+X0187746Y0083896D02*
+X0129872Y0083896D01*
+X0129872Y0085094D02*
+X0187746Y0085094D01*
+X0188070Y0086293D02*
+X0129872Y0086293D01*
+X0129872Y0087491D02*
+X0189618Y0087491D01*
+X0192385Y0091087D02*
+X0129872Y0091087D01*
+X0129872Y0092285D02*
+X0191186Y0092285D01*
+X0189988Y0093484D02*
+X0129872Y0093484D01*
+X0129872Y0094682D02*
+X0188789Y0094682D01*
+X0190000Y0097953D02*
+X0197953Y0090000D01*
+X0232500Y0090000D01*
+X0237500Y0095000D01*
+X0237500Y0098701D01*
+X0236437Y0101850D02*
+X0232500Y0097913D01*
+X0232500Y0097500D01*
+X0223740Y0097500D01*
+X0216260Y0097500D02*
+X0208937Y0097500D01*
+X0207500Y0099136D01*
+X0204746Y0101890D01*
+X0124941Y0101890D01*
+X0124941Y0103858D02*
+X0203858Y0103858D01*
+X0207500Y0107500D01*
+X0216260Y0107500D01*
+X0211339Y0111462D02*
+X0164025Y0111462D01*
+X0164025Y0112660D02*
+X0212318Y0112660D01*
+X0205891Y0110263D02*
+X0164025Y0110263D01*
+X0163996Y0109065D02*
+X0204584Y0109065D01*
+X0203385Y0107866D02*
+X0163439Y0107866D01*
+X0149662Y0117454D02*
+X0145896Y0117454D01*
+X0145828Y0118653D02*
+X0148791Y0118653D01*
+X0148632Y0125844D02*
+X0145609Y0125844D01*
+X0145896Y0127042D02*
+X0149158Y0127042D01*
+X0150000Y0128241D02*
+X0150000Y0128241D01*
+X0150000Y0129439D02*
+X0150000Y0129439D01*
+X0150000Y0130638D02*
+X0150000Y0130638D01*
+X0150000Y0131836D02*
+X0150000Y0131836D01*
+X0148221Y0128241D02*
+X0145896Y0128241D01*
+X0133563Y0130000D02*
+X0128750Y0130000D01*
+X0128750Y0122500D01*
+X0117264Y0117441D02*
+X0117264Y0133563D01*
+X0122451Y0138750D01*
+X0187313Y0138750D01*
+X0190000Y0141437D01*
+X0190000Y0153563D01*
+X0193937Y0157500D01*
+X0197500Y0157500D01*
+X0201657Y0159402D02*
+X0209231Y0159402D01*
+X0209231Y0159889D02*
+X0209231Y0155111D01*
+X0211842Y0152500D01*
+X0209231Y0149889D01*
+X0209231Y0145111D01*
+X0212611Y0141731D01*
+X0217389Y0141731D01*
+X0220000Y0144342D01*
+X0222611Y0141731D01*
+X0227389Y0141731D01*
+X0230768Y0145111D01*
+X0230768Y0149889D01*
+X0227685Y0152973D01*
+X0230100Y0155388D01*
+X0230100Y0157100D01*
+X0225400Y0157100D01*
+X0225400Y0157900D01*
+X0230100Y0157900D01*
+X0230100Y0159612D01*
+X0227212Y0162500D01*
+X0230100Y0165388D01*
+X0230100Y0167100D01*
+X0225400Y0167100D01*
+X0225400Y0167900D01*
+X0230100Y0167900D01*
+X0230100Y0169612D01*
+X0227685Y0172027D01*
+X0230768Y0175111D01*
+X0230768Y0179889D01*
+X0227389Y0183268D01*
+X0222611Y0183268D01*
+X0220000Y0180658D01*
+X0217389Y0183268D01*
+X0212611Y0183268D01*
+X0209231Y0179889D01*
+X0209231Y0175111D01*
+X0211842Y0172500D01*
+X0209231Y0169889D01*
+X0209231Y0165111D01*
+X0211842Y0162500D01*
+X0209231Y0159889D01*
+X0209943Y0160601D02*
+X0200860Y0160601D01*
+X0199059Y0161799D02*
+X0211141Y0161799D01*
+X0211345Y0162998D02*
+X0193168Y0162998D01*
+X0193168Y0164196D02*
+X0210146Y0164196D01*
+X0209231Y0165395D02*
+X0193168Y0165395D01*
+X0193168Y0166593D02*
+X0209231Y0166593D01*
+X0209231Y0167792D02*
+X0193168Y0167792D01*
+X0193168Y0168990D02*
+X0209231Y0168990D01*
+X0209531Y0170189D02*
+X0193168Y0170189D01*
+X0193168Y0171387D02*
+X0210729Y0171387D01*
+X0211756Y0172586D02*
+X0193168Y0172586D01*
+X0193168Y0173784D02*
+X0210558Y0173784D01*
+X0209359Y0174983D02*
+X0193168Y0174983D01*
+X0193168Y0176181D02*
+X0209231Y0176181D01*
+X0209231Y0177380D02*
+X0193168Y0177380D01*
+X0193168Y0178578D02*
+X0209231Y0178578D01*
+X0209231Y0179777D02*
+X0193168Y0179777D01*
+X0193168Y0180975D02*
+X0210317Y0180975D01*
+X0211516Y0182174D02*
+X0193168Y0182174D01*
+X0193168Y0183372D02*
+X0286132Y0183372D01*
+X0286132Y0182174D02*
+X0228484Y0182174D01*
+X0229683Y0180975D02*
+X0243264Y0180975D01*
+X0243662Y0181373D02*
+X0242377Y0180088D01*
+X0241681Y0178409D01*
+X0241681Y0176591D01*
+X0242377Y0174912D01*
+X0242481Y0174808D01*
+X0242481Y0160097D01*
+X0242039Y0159914D01*
+X0241317Y0159191D01*
+X0240926Y0158247D01*
+X0240926Y0151713D01*
+X0241317Y0150769D01*
+X0242039Y0150047D01*
+X0242983Y0149656D01*
+X0249517Y0149656D01*
+X0250461Y0150047D01*
+X0251183Y0150769D01*
+X0251574Y0151713D01*
+X0251574Y0158247D01*
+X0251183Y0159191D01*
+X0250461Y0159914D01*
+X0250018Y0160097D01*
+X0250018Y0174808D01*
+X0250123Y0174912D01*
+X0250818Y0176591D01*
+X0250818Y0178409D01*
+X0250123Y0180088D01*
+X0248838Y0181373D01*
+X0247159Y0182068D01*
+X0245341Y0182068D01*
+X0243662Y0181373D01*
+X0242248Y0179777D02*
+X0230768Y0179777D01*
+X0230768Y0178578D02*
+X0241752Y0178578D01*
+X0241681Y0177380D02*
+X0230768Y0177380D01*
+X0230768Y0176181D02*
+X0241851Y0176181D01*
+X0242348Y0174983D02*
+X0230641Y0174983D01*
+X0229442Y0173784D02*
+X0242481Y0173784D01*
+X0242481Y0172586D02*
+X0228244Y0172586D01*
+X0228325Y0171387D02*
+X0242481Y0171387D01*
+X0242481Y0170189D02*
+X0229524Y0170189D01*
+X0230100Y0168990D02*
+X0242481Y0168990D01*
+X0242481Y0167792D02*
+X0225400Y0167792D01*
+X0225400Y0167100D02*
+X0225400Y0162400D01*
+X0225400Y0157900D01*
+X0224600Y0157900D01*
+X0224600Y0167100D01*
+X0225400Y0167100D01*
+X0225400Y0166593D02*
+X0224600Y0166593D01*
+X0224600Y0165395D02*
+X0225400Y0165395D01*
+X0225400Y0164196D02*
+X0224600Y0164196D01*
+X0224600Y0162998D02*
+X0225400Y0162998D01*
+X0225400Y0161799D02*
+X0224600Y0161799D01*
+X0224600Y0160601D02*
+X0225400Y0160601D01*
+X0225400Y0159402D02*
+X0224600Y0159402D01*
+X0224600Y0158203D02*
+X0225400Y0158203D01*
+X0227913Y0161799D02*
+X0234080Y0161799D01*
+X0234144Y0161482D02*
+X0234407Y0160847D01*
+X0234789Y0160275D01*
+X0235275Y0159789D01*
+X0235847Y0159407D01*
+X0236482Y0159144D01*
+X0237156Y0159009D01*
+X0237500Y0159009D01*
+X0237844Y0159009D01*
+X0238518Y0159144D01*
+X0239153Y0159407D01*
+X0239725Y0159789D01*
+X0240211Y0160275D01*
+X0240593Y0160847D01*
+X0240856Y0161482D01*
+X0240991Y0162156D01*
+X0240991Y0162500D01*
+X0240991Y0162844D01*
+X0240856Y0163518D01*
+X0240593Y0164153D01*
+X0240211Y0164725D01*
+X0239725Y0165211D01*
+X0239153Y0165593D01*
+X0238518Y0165856D01*
+X0237844Y0165991D01*
+X0237500Y0165991D01*
+X0237156Y0165991D01*
+X0236482Y0165856D01*
+X0235847Y0165593D01*
+X0235275Y0165211D01*
+X0234789Y0164725D01*
+X0234407Y0164153D01*
+X0234144Y0163518D01*
+X0234009Y0162844D01*
+X0234009Y0162500D01*
+X0234009Y0162156D01*
+X0234144Y0161482D01*
+X0234571Y0160601D02*
+X0229112Y0160601D01*
+X0230100Y0159402D02*
+X0235858Y0159402D01*
+X0237500Y0159402D02*
+X0237500Y0159402D01*
+X0237500Y0159009D02*
+X0237500Y0162500D01*
+X0240991Y0162500D01*
+X0237500Y0162500D01*
+X0237500Y0162500D01*
+X0237500Y0162500D01*
+X0237500Y0165991D01*
+X0237500Y0162500D01*
+X0237500Y0162500D01*
+X0237500Y0162500D01*
+X0234009Y0162500D01*
+X0237500Y0162500D01*
+X0237500Y0159009D01*
+X0237500Y0160601D02*
+X0237500Y0160601D01*
+X0237500Y0161799D02*
+X0237500Y0161799D01*
+X0237500Y0162998D02*
+X0237500Y0162998D01*
+X0237500Y0164196D02*
+X0237500Y0164196D01*
+X0237500Y0165395D02*
+X0237500Y0165395D01*
+X0239451Y0165395D02*
+X0242481Y0165395D01*
+X0242481Y0166593D02*
+X0230100Y0166593D01*
+X0230100Y0165395D02*
+X0235549Y0165395D01*
+X0234435Y0164196D02*
+X0228909Y0164196D01*
+X0227710Y0162998D02*
+X0234040Y0162998D01*
+X0230100Y0158203D02*
+X0240926Y0158203D01*
+X0240926Y0157005D02*
+X0230100Y0157005D01*
+X0230100Y0155806D02*
+X0240926Y0155806D01*
+X0240926Y0154608D02*
+X0229320Y0154608D01*
+X0228122Y0153409D02*
+X0240926Y0153409D01*
+X0240926Y0152211D02*
+X0228447Y0152211D01*
+X0229645Y0151012D02*
+X0241216Y0151012D01*
+X0242602Y0149814D02*
+X0230768Y0149814D01*
+X0230768Y0148615D02*
+X0269765Y0148615D01*
+X0269529Y0148852D02*
+X0270152Y0148229D01*
+X0270865Y0147710D01*
+X0271650Y0147310D01*
+X0272489Y0147038D01*
+X0273359Y0146900D01*
+X0277000Y0146900D01*
+X0277000Y0152000D01*
+X0268209Y0152000D01*
+X0268338Y0151189D01*
+X0268610Y0150350D01*
+X0269010Y0149565D01*
+X0269529Y0148852D01*
+X0268884Y0149814D02*
+X0261148Y0149814D01*
+X0262534Y0151012D02*
+X0268395Y0151012D01*
+X0268274Y0153409D02*
+X0262824Y0153409D01*
+X0262824Y0152211D02*
+X0277000Y0152211D01*
+X0277000Y0151012D02*
+X0278000Y0151012D01*
+X0278000Y0149814D02*
+X0277000Y0149814D01*
+X0277000Y0148615D02*
+X0278000Y0148615D01*
+X0278000Y0147417D02*
+X0277000Y0147417D01*
+X0271441Y0147417D02*
+X0230768Y0147417D01*
+X0230768Y0146218D02*
+X0286132Y0146218D01*
+X0286132Y0145020D02*
+X0261550Y0145020D01*
+X0262603Y0143821D02*
+X0286132Y0143821D01*
+X0286132Y0142623D02*
+X0265207Y0142623D01*
+X0257500Y0140020D02*
+X0257500Y0140000D01*
+X0252397Y0143821D02*
+X0251353Y0143821D01*
+X0250300Y0145020D02*
+X0253450Y0145020D01*
+X0253852Y0149814D02*
+X0249898Y0149814D01*
+X0251284Y0151012D02*
+X0252466Y0151012D01*
+X0252176Y0152211D02*
+X0251574Y0152211D01*
+X0251574Y0153409D02*
+X0252176Y0153409D01*
+X0252176Y0154608D02*
+X0251574Y0154608D01*
+X0251574Y0155806D02*
+X0252176Y0155806D01*
+X0252176Y0157005D02*
+X0251574Y0157005D01*
+X0251574Y0158203D02*
+X0252176Y0158203D01*
+X0252777Y0159402D02*
+X0250973Y0159402D01*
+X0250018Y0160601D02*
+X0255271Y0160601D01*
+X0256470Y0161799D02*
+X0250018Y0161799D01*
+X0250018Y0162998D02*
+X0257668Y0162998D01*
+X0258867Y0164196D02*
+X0250018Y0164196D01*
+X0250018Y0165395D02*
+X0260065Y0165395D01*
+X0263533Y0158203D02*
+X0269231Y0158203D01*
+X0270473Y0157005D02*
+X0262824Y0157005D01*
+X0262824Y0155806D02*
+X0269280Y0155806D01*
+X0268597Y0154608D02*
+X0262824Y0154608D01*
+X0269028Y0166593D02*
+X0250018Y0166593D01*
+X0250018Y0167792D02*
+X0270227Y0167792D01*
+X0284773Y0167792D02*
+X0286132Y0167792D01*
+X0286132Y0168990D02*
+X0250018Y0168990D01*
+X0250018Y0170189D02*
+X0286132Y0170189D01*
+X0286132Y0171387D02*
+X0250018Y0171387D01*
+X0250018Y0172586D02*
+X0286132Y0172586D01*
+X0286132Y0173784D02*
+X0250018Y0173784D01*
+X0250152Y0174983D02*
+X0286132Y0174983D01*
+X0286132Y0176181D02*
+X0250649Y0176181D01*
+X0250818Y0177380D02*
+X0286132Y0177380D01*
+X0286132Y0178578D02*
+X0250748Y0178578D01*
+X0250252Y0179777D02*
+X0286132Y0179777D01*
+X0286132Y0180975D02*
+X0249236Y0180975D01*
+X0253853Y0198190D02*
+X0254336Y0198061D01*
+X0260403Y0198061D01*
+X0260403Y0201643D01*
+X0261369Y0201643D01*
+X0261369Y0202609D01*
+X0269085Y0202609D01*
+X0269085Y0204541D01*
+X0268956Y0205025D01*
+X0268705Y0205458D01*
+X0268352Y0205812D01*
+X0267918Y0206062D01*
+X0267435Y0206191D01*
+X0261369Y0206191D01*
+X0261369Y0202609D01*
+X0260403Y0202609D01*
+X0260403Y0206191D01*
+X0254336Y0206191D01*
+X0253853Y0206062D01*
+X0253420Y0205812D01*
+X0253066Y0205458D01*
+X0252816Y0205025D01*
+X0252687Y0204541D01*
+X0252687Y0202609D01*
+X0260403Y0202609D01*
+X0260403Y0201643D01*
+X0252687Y0201643D01*
+X0252687Y0199710D01*
+X0252816Y0199227D01*
+X0253066Y0198794D01*
+X0253420Y0198440D01*
+X0253853Y0198190D01*
+X0252974Y0198953D02*
+X0242025Y0198953D01*
+X0241934Y0198794D02*
+X0242184Y0199227D01*
+X0242313Y0199710D01*
+X0242313Y0201643D01*
+X0234597Y0201643D01*
+X0234597Y0198061D01*
+X0240664Y0198061D01*
+X0241147Y0198190D01*
+X0241580Y0198440D01*
+X0241934Y0198794D01*
+X0242313Y0200151D02*
+X0252687Y0200151D01*
+X0252687Y0201350D02*
+X0242313Y0201350D01*
+X0242313Y0202609D02*
+X0242313Y0204541D01*
+X0242184Y0205025D01*
+X0241934Y0205458D01*
+X0241580Y0205812D01*
+X0241147Y0206062D01*
+X0240664Y0206191D01*
+X0234597Y0206191D01*
+X0234597Y0202609D01*
+X0233631Y0202609D01*
+X0233631Y0201643D01*
+X0225915Y0201643D01*
+X0225915Y0199710D01*
+X0226044Y0199227D01*
+X0226295Y0198794D01*
+X0226648Y0198440D01*
+X0227082Y0198190D01*
+X0227565Y0198061D01*
+X0233631Y0198061D01*
+X0233631Y0201643D01*
+X0234597Y0201643D01*
+X0234597Y0202609D01*
+X0242313Y0202609D01*
+X0242313Y0203747D02*
+X0252687Y0203747D01*
+X0252795Y0204945D02*
+X0242205Y0204945D01*
+X0240840Y0206144D02*
+X0254160Y0206144D01*
+X0260403Y0206144D02*
+X0261369Y0206144D01*
+X0261369Y0204945D02*
+X0260403Y0204945D01*
+X0260403Y0203747D02*
+X0261369Y0203747D01*
+X0261369Y0202548D02*
+X0286132Y0202548D01*
+X0286132Y0201350D02*
+X0269085Y0201350D01*
+X0269085Y0201643D02*
+X0269085Y0199710D01*
+X0268956Y0199227D01*
+X0268705Y0198794D01*
+X0268352Y0198440D01*
+X0267918Y0198190D01*
+X0267435Y0198061D01*
+X0261369Y0198061D01*
+X0261369Y0201643D01*
+X0269085Y0201643D01*
+X0270000Y0202126D02*
+X0275000Y0207126D01*
+X0275000Y0207500D01*
+X0274400Y0207342D02*
+X0275600Y0207342D01*
+X0275600Y0207963D02*
+X0275600Y0204104D01*
+X0278400Y0204104D01*
+X0278883Y0204233D01*
+X0279316Y0204484D01*
+X0279670Y0204837D01*
+X0279920Y0205271D01*
+X0280050Y0205754D01*
+X0280050Y0207963D01*
+X0275600Y0207963D01*
+X0275600Y0208541D02*
+X0286132Y0208541D01*
+X0286132Y0209739D02*
+X0280050Y0209739D01*
+X0280050Y0210938D02*
+X0286132Y0210938D01*
+X0286132Y0212137D02*
+X0280041Y0212137D01*
+X0280705Y0213335D02*
+X0286132Y0213335D01*
+X0286132Y0214534D02*
+X0280718Y0214534D01*
+X0280718Y0215732D02*
+X0286132Y0215732D01*
+X0286132Y0216931D02*
+X0280718Y0216931D01*
+X0280718Y0218129D02*
+X0286132Y0218129D01*
+X0286132Y0219328D02*
+X0280718Y0219328D01*
+X0280252Y0220526D02*
+X0286132Y0220526D01*
+X0286132Y0221725D02*
+X0269132Y0221725D01*
+X0275000Y0217874D02*
+X0260886Y0217874D01*
+X0234114Y0217874D01*
+X0234114Y0222500D01*
+X0190000Y0222500D01*
+X0185000Y0217500D01*
+X0180000Y0212500D01*
+X0180000Y0192500D01*
+X0175000Y0187500D01*
+X0127500Y0187500D01*
+X0122500Y0182500D01*
+X0122500Y0157500D01*
+X0117500Y0152500D01*
+X0107421Y0152500D01*
+X0103484Y0148563D01*
+X0103484Y0117441D01*
+X0101516Y0117441D02*
+X0101516Y0151063D01*
+X0105453Y0155000D01*
+X0113750Y0155000D01*
+X0118750Y0160000D01*
+X0118750Y0187500D01*
+X0123750Y0192500D01*
+X0146902Y0192500D01*
+X0151902Y0197500D01*
+X0151902Y0205000D01*
+X0146183Y0204945D02*
+X0143817Y0204945D01*
+X0143817Y0203747D02*
+X0146183Y0203747D01*
+X0146183Y0202548D02*
+X0143817Y0202548D01*
+X0143817Y0201350D02*
+X0146183Y0201350D01*
+X0146510Y0200151D02*
+X0143490Y0200151D01*
+X0141929Y0198953D02*
+X0148071Y0198953D01*
+X0147675Y0197754D02*
+X0130070Y0197754D01*
+X0129940Y0196556D02*
+X0146476Y0196556D01*
+X0150644Y0191762D02*
+X0168696Y0191762D01*
+X0168982Y0191644D02*
+X0169656Y0191509D01*
+X0170000Y0191509D01*
+X0170344Y0191509D01*
+X0171018Y0191644D01*
+X0171653Y0191907D01*
+X0172225Y0192289D01*
+X0172711Y0192775D01*
+X0173093Y0193347D01*
+X0173356Y0193982D01*
+X0173491Y0194656D01*
+X0173491Y0195000D01*
+X0173491Y0195344D01*
+X0173356Y0196018D01*
+X0173093Y0196653D01*
+X0172711Y0197225D01*
+X0172225Y0197711D01*
+X0171653Y0198093D01*
+X0171018Y0198356D01*
+X0170344Y0198491D01*
+X0170000Y0198491D01*
+X0169656Y0198491D01*
+X0168982Y0198356D01*
+X0168347Y0198093D01*
+X0167775Y0197711D01*
+X0167289Y0197225D01*
+X0166907Y0196653D01*
+X0166644Y0196018D01*
+X0166509Y0195344D01*
+X0166509Y0195000D01*
+X0166509Y0194656D01*
+X0166644Y0193982D01*
+X0166907Y0193347D01*
+X0167289Y0192775D01*
+X0167775Y0192289D01*
+X0168347Y0191907D01*
+X0168982Y0191644D01*
+X0170000Y0191762D02*
+X0170000Y0191762D01*
+X0170000Y0191509D02*
+X0170000Y0195000D01*
+X0173491Y0195000D01*
+X0170000Y0195000D01*
+X0170000Y0195000D01*
+X0170000Y0195000D01*
+X0170000Y0198491D01*
+X0170000Y0195000D01*
+X0170000Y0195000D01*
+X0170000Y0195000D01*
+X0166509Y0195000D01*
+X0170000Y0195000D01*
+X0170000Y0191509D01*
+X0171304Y0191762D02*
+X0174781Y0191762D01*
+X0175979Y0192960D02*
+X0172835Y0192960D01*
+X0173392Y0194159D02*
+X0176831Y0194159D01*
+X0176831Y0195357D02*
+X0173488Y0195357D01*
+X0173134Y0196556D02*
+X0176831Y0196556D01*
+X0176831Y0197754D02*
+X0172161Y0197754D01*
+X0170000Y0197754D02*
+X0170000Y0197754D01*
+X0170000Y0196556D02*
+X0170000Y0196556D01*
+X0170000Y0195357D02*
+X0170000Y0195357D01*
+X0170000Y0194159D02*
+X0170000Y0194159D01*
+X0170000Y0192960D02*
+X0170000Y0192960D01*
+X0167165Y0192960D02*
+X0151843Y0192960D01*
+X0153041Y0194159D02*
+X0166608Y0194159D01*
+X0166512Y0195357D02*
+X0154240Y0195357D01*
+X0154940Y0196556D02*
+X0166866Y0196556D01*
+X0167839Y0197754D02*
+X0155070Y0197754D01*
+X0155733Y0198953D02*
+X0159267Y0198953D01*
+X0157707Y0200151D02*
+X0157293Y0200151D01*
+X0163098Y0205000D02*
+X0163098Y0217500D01*
+X0161240Y0217500D01*
+X0166267Y0213335D02*
+X0176916Y0213335D01*
+X0176831Y0212137D02*
+X0166267Y0212137D01*
+X0167193Y0210938D02*
+X0176831Y0210938D01*
+X0176831Y0209739D02*
+X0168535Y0209739D01*
+X0168817Y0208541D02*
+X0176831Y0208541D01*
+X0176831Y0207342D02*
+X0168817Y0207342D01*
+X0168817Y0206144D02*
+X0176831Y0206144D01*
+X0176831Y0204945D02*
+X0168817Y0204945D01*
+X0168817Y0203747D02*
+X0176831Y0203747D01*
+X0176831Y0202548D02*
+X0168817Y0202548D01*
+X0168817Y0201350D02*
+X0176831Y0201350D01*
+X0176831Y0200151D02*
+X0168490Y0200151D01*
+X0166929Y0198953D02*
+X0176831Y0198953D01*
+X0183168Y0198953D02*
+X0186831Y0198953D01*
+X0186831Y0200151D02*
+X0183168Y0200151D01*
+X0183168Y0201350D02*
+X0186831Y0201350D01*
+X0186831Y0202400D02*
+X0186831Y0161312D01*
+X0184455Y0158936D01*
+X0184455Y0158936D01*
+X0183564Y0158045D01*
+X0183081Y0156880D01*
+X0183081Y0147562D01*
+X0182039Y0146520D01*
+X0182068Y0146591D01*
+X0182068Y0148409D01*
+X0181373Y0150088D01*
+X0180088Y0151373D01*
+X0178409Y0152068D01*
+X0176591Y0152068D01*
+X0174912Y0151373D01*
+X0174208Y0150668D01*
+X0120149Y0150668D01*
+X0120186Y0150705D01*
+X0125186Y0155705D01*
+X0125668Y0156870D01*
+X0125668Y0181188D01*
+X0128812Y0184331D01*
+X0175630Y0184331D01*
+X0176795Y0184814D01*
+X0177686Y0185705D01*
+X0182686Y0190705D01*
+X0183168Y0191870D01*
+X0183168Y0202400D01*
+X0184600Y0202400D01*
+X0184600Y0207100D01*
+X0185400Y0207100D01*
+X0185400Y0202400D01*
+X0186831Y0202400D01*
+X0185400Y0202548D02*
+X0184600Y0202548D01*
+X0184600Y0203747D02*
+X0185400Y0203747D01*
+X0185400Y0204945D02*
+X0184600Y0204945D01*
+X0184600Y0206144D02*
+X0185400Y0206144D01*
+X0190000Y0212500D02*
+X0190000Y0160000D01*
+X0186250Y0156250D01*
+X0186250Y0146250D01*
+X0182500Y0142500D01*
+X0115295Y0142500D01*
+X0111358Y0138563D01*
+X0111358Y0117441D01*
+X0105453Y0117441D02*
+X0105453Y0143563D01*
+X0109390Y0147500D01*
+X0177500Y0147500D01*
+X0182068Y0147417D02*
+X0182936Y0147417D01*
+X0183081Y0148615D02*
+X0181983Y0148615D01*
+X0181486Y0149814D02*
+X0183081Y0149814D01*
+X0183081Y0151012D02*
+X0180448Y0151012D01*
+X0183081Y0152211D02*
+X0121692Y0152211D01*
+X0122890Y0153409D02*
+X0183081Y0153409D01*
+X0183081Y0154608D02*
+X0124089Y0154608D01*
+X0125228Y0155806D02*
+X0183081Y0155806D01*
+X0183133Y0157005D02*
+X0125668Y0157005D01*
+X0125668Y0158203D02*
+X0183723Y0158203D01*
+X0184921Y0159402D02*
+X0125668Y0159402D01*
+X0125668Y0160601D02*
+X0186120Y0160601D01*
+X0186831Y0161799D02*
+X0125668Y0161799D01*
+X0125668Y0162998D02*
+X0186831Y0162998D01*
+X0186831Y0164196D02*
+X0125668Y0164196D01*
+X0125668Y0165395D02*
+X0186831Y0165395D01*
+X0186831Y0166593D02*
+X0125668Y0166593D01*
+X0125668Y0167792D02*
+X0186831Y0167792D01*
+X0186831Y0168990D02*
+X0125668Y0168990D01*
+X0125668Y0170189D02*
+X0186831Y0170189D01*
+X0186831Y0171387D02*
+X0125668Y0171387D01*
+X0125668Y0172586D02*
+X0149978Y0172586D01*
+X0149789Y0172775D02*
+X0150275Y0172289D01*
+X0150847Y0171907D01*
+X0151482Y0171644D01*
+X0152156Y0171509D01*
+X0152500Y0171509D01*
+X0152844Y0171509D01*
+X0153518Y0171644D01*
+X0154153Y0171907D01*
+X0154725Y0172289D01*
+X0155211Y0172775D01*
+X0155593Y0173347D01*
+X0155856Y0173982D01*
+X0155991Y0174656D01*
+X0155991Y0175000D01*
+X0155991Y0175344D01*
+X0155856Y0176018D01*
+X0155593Y0176653D01*
+X0155211Y0177225D01*
+X0154725Y0177711D01*
+X0154153Y0178093D01*
+X0153518Y0178356D01*
+X0152844Y0178491D01*
+X0152500Y0178491D01*
+X0152156Y0178491D01*
+X0151482Y0178356D01*
+X0150847Y0178093D01*
+X0150275Y0177711D01*
+X0149789Y0177225D01*
+X0149407Y0176653D01*
+X0149144Y0176018D01*
+X0149009Y0175344D01*
+X0149009Y0175000D01*
+X0149009Y0174656D01*
+X0149144Y0173982D01*
+X0149407Y0173347D01*
+X0149789Y0172775D01*
+X0149225Y0173784D02*
+X0125668Y0173784D01*
+X0125668Y0174983D02*
+X0149009Y0174983D01*
+X0149009Y0175000D02*
+X0152500Y0175000D01*
+X0155991Y0175000D01*
+X0152500Y0175000D01*
+X0152500Y0175000D01*
+X0152500Y0175000D01*
+X0152500Y0178491D01*
+X0152500Y0175000D01*
+X0152500Y0171509D01*
+X0152500Y0175000D01*
+X0152500Y0175000D01*
+X0152500Y0175000D01*
+X0149009Y0175000D01*
+X0149211Y0176181D02*
+X0125668Y0176181D01*
+X0125668Y0177380D02*
+X0149943Y0177380D01*
+X0152500Y0177380D02*
+X0152500Y0177380D01*
+X0152500Y0176181D02*
+X0152500Y0176181D01*
+X0152500Y0174983D02*
+X0152500Y0174983D01*
+X0152500Y0173784D02*
+X0152500Y0173784D01*
+X0152500Y0172586D02*
+X0152500Y0172586D01*
+X0155022Y0172586D02*
+X0186831Y0172586D01*
+X0186831Y0173784D02*
+X0155775Y0173784D01*
+X0155991Y0174983D02*
+X0186831Y0174983D01*
+X0186831Y0176181D02*
+X0155789Y0176181D01*
+X0155057Y0177380D02*
+X0186831Y0177380D01*
+X0186831Y0178578D02*
+X0125668Y0178578D01*
+X0125668Y0179777D02*
+X0186831Y0179777D01*
+X0186831Y0180975D02*
+X0125668Y0180975D01*
+X0126655Y0182174D02*
+X0186831Y0182174D01*
+X0186831Y0183372D02*
+X0127853Y0183372D01*
+X0114402Y0192500D02*
+X0119402Y0197500D01*
+X0126902Y0197500D01*
+X0126902Y0205000D01*
+X0121183Y0204945D02*
+X0118817Y0204945D01*
+X0118817Y0203747D02*
+X0121183Y0203747D01*
+X0121183Y0202548D02*
+X0118817Y0202548D01*
+X0118817Y0201350D02*
+X0121183Y0201350D01*
+X0121183Y0206144D02*
+X0118817Y0206144D01*
+X0118817Y0207342D02*
+X0121183Y0207342D01*
+X0121183Y0208541D02*
+X0118817Y0208541D01*
+X0118535Y0209739D02*
+X0121465Y0209739D01*
+X0122807Y0210938D02*
+X0117193Y0210938D01*
+X0116267Y0212137D02*
+X0132789Y0212137D01*
+X0134004Y0210938D02*
+X0130996Y0210938D01*
+X0132338Y0209739D02*
+X0132662Y0209739D01*
+X0128160Y0212647D02*
+X0128160Y0216900D01*
+X0124301Y0216900D01*
+X0124301Y0214297D01*
+X0124430Y0213814D01*
+X0124680Y0213381D01*
+X0125034Y0213027D01*
+X0125467Y0212777D01*
+X0125951Y0212647D01*
+X0128160Y0212647D01*
+X0128160Y0213335D02*
+X0129360Y0213335D01*
+X0129360Y0214534D02*
+X0128160Y0214534D01*
+X0128160Y0215732D02*
+X0129360Y0215732D01*
+X0128160Y0216931D02*
+X0116368Y0216931D01*
+X0116368Y0218129D02*
+X0124301Y0218129D01*
+X0124301Y0219328D02*
+X0116368Y0219328D01*
+X0116368Y0220526D02*
+X0124301Y0220526D01*
+X0124786Y0221725D02*
+X0116053Y0221725D01*
+X0114547Y0222923D02*
+X0132933Y0222923D01*
+X0129360Y0221725D02*
+X0128160Y0221725D01*
+X0128160Y0220526D02*
+X0129360Y0220526D01*
+X0129360Y0219328D02*
+X0128160Y0219328D01*
+X0128160Y0218129D02*
+X0129360Y0218129D01*
+X0124301Y0215732D02*
+X0116368Y0215732D01*
+X0116368Y0214534D02*
+X0124301Y0214534D01*
+X0124726Y0213335D02*
+X0116267Y0213335D01*
+X0113098Y0217500D02*
+X0111240Y0217500D01*
+X0113098Y0217500D02*
+X0113098Y0205000D01*
+X0107662Y0209739D02*
+X0107338Y0209739D01*
+X0105996Y0210938D02*
+X0109004Y0210938D01*
+X0107789Y0212137D02*
+X0082344Y0212137D01*
+X0081146Y0213335D02*
+X0099726Y0213335D01*
+X0099680Y0213381D02*
+X0100034Y0213027D01*
+X0100467Y0212777D01*
+X0100951Y0212647D01*
+X0103160Y0212647D01*
+X0103160Y0216900D01*
+X0099301Y0216900D01*
+X0099301Y0214297D01*
+X0099430Y0213814D01*
+X0099680Y0213381D01*
+X0099301Y0214534D02*
+X0079947Y0214534D01*
+X0077500Y0212500D02*
+X0082500Y0207500D01*
+X0082500Y0205000D01*
+X0101902Y0205000D01*
+X0096183Y0201831D02*
+X0096183Y0200940D01*
+X0096296Y0200668D01*
+X0053812Y0200668D01*
+X0052081Y0202400D01*
+X0052100Y0202400D01*
+X0052100Y0207100D01*
+X0052900Y0207100D01*
+X0052900Y0207900D01*
+X0057600Y0207900D01*
+X0062100Y0207900D01*
+X0062100Y0207100D01*
+X0052900Y0207100D01*
+X0052900Y0202400D01*
+X0054612Y0202400D01*
+X0057500Y0205288D01*
+X0060388Y0202400D01*
+X0062100Y0202400D01*
+X0062100Y0207100D01*
+X0062900Y0207100D01*
+X0062900Y0207900D01*
+X0067600Y0207900D01*
+X0067600Y0209331D01*
+X0076188Y0209331D01*
+X0079331Y0206188D01*
+X0079331Y0204370D01*
+X0079814Y0203205D01*
+X0080705Y0202314D01*
+X0081870Y0201831D01*
+X0096183Y0201831D01*
+X0096183Y0201350D02*
+X0053131Y0201350D01*
+X0052900Y0202548D02*
+X0052100Y0202548D01*
+X0052100Y0203747D02*
+X0052900Y0203747D01*
+X0052900Y0204945D02*
+X0052100Y0204945D01*
+X0052100Y0206144D02*
+X0052900Y0206144D01*
+X0052900Y0207342D02*
+X0062100Y0207342D01*
+X0062900Y0207342D02*
+X0078177Y0207342D01*
+X0079331Y0206144D02*
+X0067600Y0206144D01*
+X0067600Y0205388D02*
+X0067600Y0207100D01*
+X0062900Y0207100D01*
+X0062900Y0202400D01*
+X0064612Y0202400D01*
+X0067600Y0205388D01*
+X0067158Y0204945D02*
+X0079331Y0204945D01*
+X0079589Y0203747D02*
+X0065959Y0203747D01*
+X0064761Y0202548D02*
+X0080471Y0202548D01*
+X0076978Y0208541D02*
+X0067600Y0208541D01*
+X0062900Y0206144D02*
+X0062100Y0206144D01*
+X0062100Y0204945D02*
+X0062900Y0204945D01*
+X0062900Y0203747D02*
+X0062100Y0203747D01*
+X0062100Y0202548D02*
+X0062900Y0202548D01*
+X0060239Y0202548D02*
+X0054761Y0202548D01*
+X0055959Y0203747D02*
+X0059041Y0203747D01*
+X0057842Y0204945D02*
+X0057158Y0204945D01*
+X0057500Y0212500D02*
+X0077500Y0212500D01*
+X0083543Y0210938D02*
+X0097807Y0210938D01*
+X0096465Y0209739D02*
+X0084741Y0209739D01*
+X0085498Y0208541D02*
+X0096183Y0208541D01*
+X0103160Y0213335D02*
+X0104360Y0213335D01*
+X0104360Y0214534D02*
+X0103160Y0214534D01*
+X0103160Y0215732D02*
+X0104360Y0215732D01*
+X0103160Y0216931D02*
+X0068268Y0216931D01*
+X0068268Y0218129D02*
+X0099301Y0218129D01*
+X0099301Y0219328D02*
+X0068268Y0219328D01*
+X0067632Y0220526D02*
+X0099301Y0220526D01*
+X0099786Y0221725D02*
+X0066433Y0221725D01*
+X0065235Y0222923D02*
+X0107933Y0222923D01*
+X0104360Y0221725D02*
+X0103160Y0221725D01*
+X0103160Y0220526D02*
+X0104360Y0220526D01*
+X0104360Y0219328D02*
+X0103160Y0219328D01*
+X0103160Y0218129D02*
+X0104360Y0218129D01*
+X0099301Y0215732D02*
+X0068268Y0215732D01*
+X0062500Y0217500D02*
+X0055000Y0225000D01*
+X0016437Y0225000D01*
+X0012500Y0221063D01*
+X0012500Y0092500D01*
+X0017500Y0087500D01*
+X0027500Y0087500D01*
+X0027500Y0078740D01*
+X0021979Y0079102D02*
+X0002568Y0079102D01*
+X0002568Y0080300D02*
+X0021979Y0080300D01*
+X0021979Y0081499D02*
+X0002568Y0081499D01*
+X0002568Y0082697D02*
+X0022346Y0082697D01*
+X0024331Y0083896D02*
+X0002568Y0083896D01*
+X0002568Y0085094D02*
+X0015425Y0085094D01*
+X0014226Y0086293D02*
+X0002568Y0086293D01*
+X0002568Y0087491D02*
+X0013028Y0087491D01*
+X0011829Y0088690D02*
+X0002568Y0088690D01*
+X0002568Y0089888D02*
+X0010631Y0089888D01*
+X0009656Y0091087D02*
+X0002568Y0091087D01*
+X0002568Y0092285D02*
+X0009331Y0092285D01*
+X0009331Y0093484D02*
+X0002568Y0093484D01*
+X0002568Y0094682D02*
+X0009331Y0094682D01*
+X0009331Y0095881D02*
+X0002568Y0095881D01*
+X0002568Y0097079D02*
+X0009331Y0097079D01*
+X0009331Y0098278D02*
+X0002568Y0098278D01*
+X0002568Y0099476D02*
+X0009331Y0099476D01*
+X0009331Y0100675D02*
+X0002568Y0100675D01*
+X0002568Y0101873D02*
+X0009331Y0101873D01*
+X0009331Y0103072D02*
+X0002568Y0103072D01*
+X0002568Y0104270D02*
+X0009331Y0104270D01*
+X0009331Y0105469D02*
+X0002568Y0105469D01*
+X0002568Y0106668D02*
+X0009331Y0106668D01*
+X0009331Y0107866D02*
+X0002568Y0107866D01*
+X0002568Y0109065D02*
+X0009331Y0109065D01*
+X0009331Y0110263D02*
+X0002568Y0110263D01*
+X0002568Y0111462D02*
+X0009331Y0111462D01*
+X0009331Y0112660D02*
+X0002568Y0112660D01*
+X0002568Y0113859D02*
+X0009331Y0113859D01*
+X0009331Y0115057D02*
+X0002568Y0115057D01*
+X0002568Y0116256D02*
+X0009331Y0116256D01*
+X0009331Y0117454D02*
+X0002568Y0117454D01*
+X0002568Y0118653D02*
+X0009331Y0118653D01*
+X0009331Y0119851D02*
+X0002568Y0119851D01*
+X0002568Y0121050D02*
+X0009331Y0121050D01*
+X0009331Y0122248D02*
+X0002568Y0122248D01*
+X0002568Y0123447D02*
+X0009331Y0123447D01*
+X0009331Y0124645D02*
+X0002568Y0124645D01*
+X0002568Y0125844D02*
+X0009331Y0125844D01*
+X0009331Y0127042D02*
+X0002568Y0127042D01*
+X0002568Y0128241D02*
+X0009331Y0128241D01*
+X0009331Y0129439D02*
+X0002568Y0129439D01*
+X0002568Y0130638D02*
+X0009331Y0130638D01*
+X0009331Y0131836D02*
+X0002568Y0131836D01*
+X0002568Y0133035D02*
+X0009331Y0133035D01*
+X0009331Y0134233D02*
+X0002568Y0134233D01*
+X0002568Y0135432D02*
+X0009331Y0135432D01*
+X0009331Y0136630D02*
+X0002568Y0136630D01*
+X0002568Y0137829D02*
+X0009331Y0137829D01*
+X0009331Y0139027D02*
+X0002568Y0139027D01*
+X0002568Y0140226D02*
+X0009331Y0140226D01*
+X0009331Y0141424D02*
+X0002568Y0141424D01*
+X0002568Y0142623D02*
+X0009331Y0142623D01*
+X0009331Y0143821D02*
+X0002568Y0143821D01*
+X0002568Y0145020D02*
+X0009331Y0145020D01*
+X0009331Y0146218D02*
+X0002568Y0146218D01*
+X0002568Y0147417D02*
+X0009331Y0147417D01*
+X0009331Y0148615D02*
+X0002568Y0148615D01*
+X0002568Y0149814D02*
+X0009331Y0149814D01*
+X0009331Y0151012D02*
+X0002568Y0151012D01*
+X0002568Y0152211D02*
+X0009331Y0152211D01*
+X0009331Y0153409D02*
+X0002568Y0153409D01*
+X0002568Y0154608D02*
+X0009331Y0154608D01*
+X0009331Y0155806D02*
+X0002568Y0155806D01*
+X0002568Y0157005D02*
+X0009331Y0157005D01*
+X0009331Y0158203D02*
+X0002568Y0158203D01*
+X0002568Y0159402D02*
+X0009331Y0159402D01*
+X0009331Y0160601D02*
+X0002568Y0160601D01*
+X0002568Y0161799D02*
+X0009331Y0161799D01*
+X0009331Y0162998D02*
+X0002568Y0162998D01*
+X0002568Y0164196D02*
+X0009331Y0164196D01*
+X0009331Y0165395D02*
+X0002568Y0165395D01*
+X0002568Y0166593D02*
+X0009331Y0166593D01*
+X0009331Y0167792D02*
+X0002568Y0167792D01*
+X0002568Y0168990D02*
+X0009331Y0168990D01*
+X0009331Y0170189D02*
+X0002568Y0170189D01*
+X0002568Y0171387D02*
+X0009331Y0171387D01*
+X0009331Y0172586D02*
+X0002568Y0172586D01*
+X0002568Y0173784D02*
+X0009331Y0173784D01*
+X0009331Y0174983D02*
+X0002568Y0174983D01*
+X0002568Y0176181D02*
+X0009331Y0176181D01*
+X0009331Y0177380D02*
+X0002568Y0177380D01*
+X0002568Y0178578D02*
+X0009331Y0178578D01*
+X0009331Y0179777D02*
+X0002568Y0179777D01*
+X0002568Y0180975D02*
+X0009331Y0180975D01*
+X0009331Y0182174D02*
+X0002568Y0182174D01*
+X0002568Y0183372D02*
+X0009331Y0183372D01*
+X0009331Y0184571D02*
+X0002568Y0184571D01*
+X0002568Y0185769D02*
+X0009331Y0185769D01*
+X0009331Y0186968D02*
+X0002568Y0186968D01*
+X0002568Y0188166D02*
+X0009331Y0188166D01*
+X0009331Y0189365D02*
+X0002568Y0189365D01*
+X0002568Y0190563D02*
+X0009331Y0190563D01*
+X0009331Y0191762D02*
+X0002568Y0191762D01*
+X0002568Y0192960D02*
+X0009331Y0192960D01*
+X0009331Y0194159D02*
+X0002568Y0194159D01*
+X0002568Y0195357D02*
+X0009331Y0195357D01*
+X0009331Y0196556D02*
+X0002568Y0196556D01*
+X0002568Y0197754D02*
+X0009331Y0197754D01*
+X0009331Y0198953D02*
+X0002568Y0198953D01*
+X0002568Y0200151D02*
+X0009331Y0200151D01*
+X0009331Y0201350D02*
+X0002568Y0201350D01*
+X0002568Y0202548D02*
+X0009331Y0202548D01*
+X0009331Y0203747D02*
+X0002568Y0203747D01*
+X0002568Y0204945D02*
+X0009331Y0204945D01*
+X0009331Y0206144D02*
+X0002568Y0206144D01*
+X0002568Y0207342D02*
+X0009331Y0207342D01*
+X0009331Y0208541D02*
+X0002568Y0208541D01*
+X0002568Y0209739D02*
+X0009331Y0209739D01*
+X0009331Y0210938D02*
+X0002568Y0210938D01*
+X0002568Y0212137D02*
+X0009331Y0212137D01*
+X0009331Y0213335D02*
+X0002568Y0213335D01*
+X0002568Y0214534D02*
+X0009331Y0214534D01*
+X0009331Y0215732D02*
+X0002568Y0215732D01*
+X0002568Y0216931D02*
+X0009331Y0216931D01*
+X0009331Y0218129D02*
+X0002568Y0218129D01*
+X0002568Y0219328D02*
+X0009331Y0219328D01*
+X0009331Y0220526D02*
+X0002568Y0220526D01*
+X0002568Y0221725D02*
+X0009344Y0221725D01*
+X0009879Y0222923D02*
+X0002568Y0222923D01*
+X0002568Y0224122D02*
+X0011078Y0224122D01*
+X0012276Y0225320D02*
+X0002568Y0225320D01*
+X0002568Y0226519D02*
+X0013475Y0226519D01*
+X0018937Y0222500D02*
+X0015000Y0218563D01*
+X0015000Y0095000D01*
+X0020000Y0090000D01*
+X0068563Y0090000D01*
+X0070610Y0092047D01*
+X0080059Y0092047D01*
+X0080059Y0090079D02*
+X0072579Y0090079D01*
+X0070000Y0087500D01*
+X0027500Y0087500D01*
+X0030668Y0084331D02*
+X0057079Y0084331D01*
+X0056525Y0083961D01*
+X0056039Y0083475D01*
+X0055657Y0082903D01*
+X0055394Y0082268D01*
+X0055259Y0081594D01*
+X0055259Y0081250D01*
+X0055259Y0080906D01*
+X0055394Y0080232D01*
+X0055657Y0079597D01*
+X0056039Y0079025D01*
+X0056525Y0078539D01*
+X0057097Y0078157D01*
+X0057732Y0077894D01*
+X0058406Y0077759D01*
+X0058750Y0077759D01*
+X0059094Y0077759D01*
+X0059768Y0077894D01*
+X0060403Y0078157D01*
+X0060975Y0078539D01*
+X0061461Y0079025D01*
+X0061843Y0079597D01*
+X0062106Y0080232D01*
+X0062241Y0080906D01*
+X0062241Y0081250D01*
+X0062241Y0081594D01*
+X0062106Y0082268D01*
+X0061843Y0082903D01*
+X0061461Y0083475D01*
+X0060975Y0083961D01*
+X0060421Y0084331D01*
+X0069919Y0084331D01*
+X0063747Y0078218D01*
+X0060867Y0078218D01*
+X0059923Y0077827D01*
+X0059457Y0077361D01*
+X0059355Y0077420D01*
+X0058872Y0077550D01*
+X0056663Y0077550D01*
+X0056663Y0073100D01*
+X0055463Y0073100D01*
+X0055463Y0077550D01*
+X0053254Y0077550D01*
+X0052771Y0077420D01*
+X0052337Y0077170D01*
+X0051984Y0076816D01*
+X0051733Y0076383D01*
+X0051604Y0075900D01*
+X0051604Y0073100D01*
+X0055463Y0073100D01*
+X0055463Y0071900D01*
+X0056663Y0071900D01*
+X0056663Y0067450D01*
+X0058872Y0067450D01*
+X0059355Y0067580D01*
+X0059457Y0067639D01*
+X0059923Y0067173D01*
+X0060769Y0066823D01*
+X0060769Y0062872D01*
+X0060327Y0062689D01*
+X0059604Y0061967D01*
+X0059417Y0061515D01*
+X0032749Y0061515D01*
+X0030668Y0063596D01*
+X0030668Y0066132D01*
+X0030964Y0066132D01*
+X0031908Y0066523D01*
+X0032630Y0067246D01*
+X0033021Y0068190D01*
+X0033021Y0074330D01*
+X0032744Y0075000D01*
+X0033021Y0075670D01*
+X0033021Y0081810D01*
+X0032630Y0082754D01*
+X0031908Y0083477D01*
+X0030964Y0083868D01*
+X0030668Y0083868D01*
+X0030668Y0084331D01*
+X0030668Y0083896D02*
+X0056459Y0083896D01*
+X0055571Y0082697D02*
+X0032654Y0082697D01*
+X0033021Y0081499D02*
+X0055259Y0081499D01*
+X0055259Y0081250D02*
+X0058750Y0081250D01*
+X0062241Y0081250D01*
+X0058750Y0081250D01*
+X0058750Y0081250D01*
+X0058750Y0077759D01*
+X0058750Y0081250D01*
+X0058750Y0081250D01*
+X0058750Y0081250D01*
+X0055259Y0081250D01*
+X0055380Y0080300D02*
+X0033021Y0080300D01*
+X0033021Y0079102D02*
+X0055987Y0079102D01*
+X0057709Y0077903D02*
+X0033021Y0077903D01*
+X0033021Y0076705D02*
+X0051919Y0076705D01*
+X0051604Y0075506D02*
+X0032953Y0075506D01*
+X0033021Y0074308D02*
+X0051604Y0074308D01*
+X0051604Y0073109D02*
+X0033021Y0073109D01*
+X0033021Y0071911D02*
+X0055463Y0071911D01*
+X0055463Y0071900D02*
+X0051604Y0071900D01*
+X0051604Y0069100D01*
+X0051733Y0068617D01*
+X0051984Y0068184D01*
+X0052337Y0067830D01*
+X0052771Y0067580D01*
+X0053254Y0067450D01*
+X0055463Y0067450D01*
+X0055463Y0071900D01*
+X0055463Y0070712D02*
+X0056663Y0070712D01*
+X0056663Y0069514D02*
+X0055463Y0069514D01*
+X0055463Y0068315D02*
+X0056663Y0068315D01*
+X0060059Y0067117D02*
+X0032501Y0067117D01*
+X0033021Y0068315D02*
+X0051908Y0068315D01*
+X0051604Y0069514D02*
+X0033021Y0069514D01*
+X0033021Y0070712D02*
+X0051604Y0070712D01*
+X0055463Y0073109D02*
+X0056663Y0073109D01*
+X0056663Y0074308D02*
+X0055463Y0074308D01*
+X0055463Y0075506D02*
+X0056663Y0075506D01*
+X0056663Y0076705D02*
+X0055463Y0076705D01*
+X0058750Y0077903D02*
+X0058750Y0077903D01*
+X0059791Y0077903D02*
+X0060107Y0077903D01*
+X0058750Y0079102D02*
+X0058750Y0079102D01*
+X0058750Y0080300D02*
+X0058750Y0080300D01*
+X0061513Y0079102D02*
+X0064639Y0079102D01*
+X0065849Y0080300D02*
+X0062120Y0080300D01*
+X0062241Y0081499D02*
+X0067059Y0081499D01*
+X0068269Y0082697D02*
+X0061929Y0082697D01*
+X0062500Y0083750D02*
+X0070000Y0083750D01*
+X0074360Y0088110D01*
+X0080059Y0088110D01*
+X0080059Y0086142D02*
+X0076250Y0086142D01*
+X0065000Y0075000D01*
+X0063937Y0072500D01*
+X0063937Y0060846D01*
+X0063750Y0058346D01*
+X0031437Y0058346D01*
+X0027500Y0062283D01*
+X0027500Y0071260D01*
+X0021979Y0070712D02*
+X0002568Y0070712D01*
+X0002568Y0069514D02*
+X0021979Y0069514D01*
+X0021979Y0068315D02*
+X0002568Y0068315D01*
+X0002568Y0067117D02*
+X0022499Y0067117D01*
+X0024331Y0065918D02*
+X0002568Y0065918D01*
+X0002568Y0064720D02*
+X0024331Y0064720D01*
+X0024331Y0063521D02*
+X0002568Y0063521D01*
+X0002568Y0062323D02*
+X0024331Y0062323D01*
+X0024551Y0061124D02*
+X0002568Y0061124D01*
+X0002568Y0059926D02*
+X0025377Y0059926D01*
+X0026575Y0058727D02*
+X0002568Y0058727D01*
+X0002568Y0057529D02*
+X0027774Y0057529D01*
+X0028972Y0056330D02*
+X0002568Y0056330D01*
+X0002568Y0055132D02*
+X0059436Y0055132D01*
+X0059213Y0053933D02*
+X0002568Y0053933D01*
+X0002568Y0052734D02*
+X0059213Y0052734D01*
+X0059213Y0051536D02*
+X0002568Y0051536D01*
+X0002568Y0050337D02*
+X0059213Y0050337D01*
+X0059213Y0049139D02*
+X0002568Y0049139D01*
+X0002568Y0047940D02*
+X0059697Y0047940D01*
+X0063750Y0051654D02*
+X0082500Y0051654D01*
+X0086437Y0055591D01*
+X0086437Y0060000D01*
+X0087736Y0060000D01*
+X0091673Y0063937D01*
+X0091673Y0072559D01*
+X0089705Y0072559D02*
+X0089705Y0065000D01*
+X0077500Y0065000D01*
+X0077500Y0060000D01*
+X0077963Y0059926D02*
+X0068287Y0059926D01*
+X0068287Y0061023D02*
+X0067896Y0061967D01*
+X0067173Y0062689D01*
+X0067105Y0062717D01*
+X0067105Y0066823D01*
+X0067951Y0067173D01*
+X0068674Y0067895D01*
+X0069065Y0068839D01*
+X0069065Y0074566D01*
+X0073681Y0079139D01*
+X0073681Y0076989D01*
+X0074073Y0076045D01*
+X0074795Y0075323D01*
+X0075739Y0074931D01*
+X0076181Y0074931D01*
+X0076181Y0070739D01*
+X0076573Y0069795D01*
+X0077295Y0069073D01*
+X0078239Y0068681D01*
+X0085029Y0068681D01*
+X0085691Y0068019D01*
+X0086635Y0067628D01*
+X0088505Y0067628D01*
+X0088505Y0065718D01*
+X0083367Y0065718D01*
+X0082423Y0065327D01*
+X0081957Y0064861D01*
+X0081855Y0064920D01*
+X0081372Y0065050D01*
+X0079163Y0065050D01*
+X0079163Y0060600D01*
+X0077963Y0060600D01*
+X0077963Y0065050D01*
+X0075754Y0065050D01*
+X0075271Y0064920D01*
+X0074837Y0064670D01*
+X0074484Y0064316D01*
+X0074233Y0063883D01*
+X0074104Y0063400D01*
+X0074104Y0060600D01*
+X0077963Y0060600D01*
+X0077963Y0059400D01*
+X0079163Y0059400D01*
+X0079163Y0054950D01*
+X0081316Y0054950D01*
+X0081188Y0054822D01*
+X0068083Y0054822D01*
+X0068009Y0055000D01*
+X0068287Y0055670D01*
+X0068287Y0061023D01*
+X0068245Y0061124D02*
+X0074104Y0061124D01*
+X0074104Y0062323D02*
+X0067540Y0062323D01*
+X0067105Y0063521D02*
+X0074136Y0063521D01*
+X0073518Y0064144D02*
+X0074153Y0064407D01*
+X0074725Y0064789D01*
+X0075211Y0065275D01*
+X0075593Y0065847D01*
+X0075856Y0066482D01*
+X0075991Y0067156D01*
+X0075991Y0067500D01*
+X0075991Y0067844D01*
+X0075856Y0068518D01*
+X0075593Y0069153D01*
+X0075211Y0069725D01*
+X0074725Y0070211D01*
+X0074153Y0070593D01*
+X0073518Y0070856D01*
+X0072844Y0070991D01*
+X0072500Y0070991D01*
+X0072156Y0070991D01*
+X0071482Y0070856D01*
+X0070847Y0070593D01*
+X0070275Y0070211D01*
+X0069789Y0069725D01*
+X0069407Y0069153D01*
+X0069144Y0068518D01*
+X0069009Y0067844D01*
+X0069009Y0067500D01*
+X0069009Y0067156D01*
+X0069144Y0066482D01*
+X0069407Y0065847D01*
+X0069789Y0065275D01*
+X0070275Y0064789D01*
+X0070847Y0064407D01*
+X0071482Y0064144D01*
+X0072156Y0064009D01*
+X0072500Y0064009D01*
+X0072844Y0064009D01*
+X0073518Y0064144D01*
+X0072500Y0064009D02*
+X0072500Y0067500D01*
+X0075991Y0067500D01*
+X0072500Y0067500D01*
+X0072500Y0067500D01*
+X0072500Y0067500D01*
+X0072500Y0070991D01*
+X0072500Y0067500D01*
+X0072500Y0067500D01*
+X0072500Y0067500D01*
+X0069009Y0067500D01*
+X0072500Y0067500D01*
+X0072500Y0064009D01*
+X0072500Y0064720D02*
+X0072500Y0064720D01*
+X0072500Y0065918D02*
+X0072500Y0065918D01*
+X0072500Y0067117D02*
+X0072500Y0067117D01*
+X0072500Y0068315D02*
+X0072500Y0068315D01*
+X0072500Y0069514D02*
+X0072500Y0069514D01*
+X0072500Y0070712D02*
+X0072500Y0070712D01*
+X0073866Y0070712D02*
+X0076193Y0070712D01*
+X0076181Y0071911D02*
+X0069065Y0071911D01*
+X0069065Y0073109D02*
+X0076181Y0073109D01*
+X0076181Y0074308D02*
+X0069065Y0074308D01*
+X0070014Y0075506D02*
+X0074611Y0075506D01*
+X0073799Y0076705D02*
+X0071224Y0076705D01*
+X0072434Y0077903D02*
+X0073681Y0077903D01*
+X0073644Y0079102D02*
+X0073681Y0079102D01*
+X0069479Y0083896D02*
+X0061041Y0083896D01*
+X0066063Y0092500D02*
+X0021437Y0092500D01*
+X0017500Y0096437D01*
+X0017500Y0151063D01*
+X0021437Y0155000D01*
+X0027500Y0155000D01*
+X0027500Y0148937D01*
+X0033218Y0148615D02*
+X0088505Y0148615D01*
+X0088505Y0147417D02*
+X0087312Y0147417D01*
+X0087420Y0147229D02*
+X0087170Y0147663D01*
+X0086816Y0148016D01*
+X0086383Y0148267D01*
+X0085900Y0148396D01*
+X0083100Y0148396D01*
+X0083100Y0144537D01*
+X0087550Y0144537D01*
+X0087550Y0146746D01*
+X0087420Y0147229D01*
+X0087550Y0146218D02*
+X0088505Y0146218D01*
+X0088505Y0145020D02*
+X0087550Y0145020D01*
+X0088505Y0143821D02*
+X0083100Y0143821D01*
+X0083100Y0143337D02*
+X0083100Y0144537D01*
+X0081900Y0144537D01*
+X0081900Y0143337D01*
+X0077450Y0143337D01*
+X0077450Y0141128D01*
+X0077580Y0140645D01*
+X0077639Y0140543D01*
+X0077173Y0140077D01*
+X0076782Y0139133D01*
+X0076782Y0132993D01*
+X0077173Y0132049D01*
+X0077895Y0131326D01*
+X0078839Y0130935D01*
+X0079331Y0130935D01*
+X0079331Y0126870D01*
+X0079814Y0125705D01*
+X0080705Y0124814D01*
+X0081870Y0124331D01*
+X0084568Y0124331D01*
+X0084568Y0121318D01*
+X0078239Y0121318D01*
+X0077521Y0121021D01*
+X0077550Y0121128D01*
+X0077550Y0123337D01*
+X0073100Y0123337D01*
+X0073100Y0124537D01*
+X0077550Y0124537D01*
+X0077550Y0126746D01*
+X0077420Y0127229D01*
+X0077170Y0127663D01*
+X0076816Y0128016D01*
+X0076383Y0128267D01*
+X0075900Y0128396D01*
+X0073100Y0128396D01*
+X0073100Y0124537D01*
+X0071900Y0124537D01*
+X0071900Y0123337D01*
+X0067450Y0123337D01*
+X0067450Y0121128D01*
+X0067580Y0120645D01*
+X0067639Y0120543D01*
+X0067173Y0120077D01*
+X0066782Y0119133D01*
+X0066782Y0115012D01*
+X0066249Y0115545D01*
+X0065358Y0116436D01*
+X0064401Y0116832D01*
+X0064264Y0117164D01*
+X0063542Y0117886D01*
+X0063168Y0118041D01*
+X0063168Y0119890D01*
+X0063674Y0120395D01*
+X0064065Y0121339D01*
+X0064065Y0128661D01*
+X0063674Y0129605D01*
+X0062951Y0130327D01*
+X0062007Y0130718D01*
+X0055867Y0130718D01*
+X0054923Y0130327D01*
+X0054457Y0129861D01*
+X0054355Y0129920D01*
+X0053872Y0130050D01*
+X0051663Y0130050D01*
+X0051663Y0127741D01*
+X0050630Y0128168D01*
+X0050463Y0128168D01*
+X0050463Y0130050D01*
+X0048254Y0130050D01*
+X0047771Y0129920D01*
+X0047337Y0129670D01*
+X0046984Y0129316D01*
+X0046733Y0128883D01*
+X0046604Y0128400D01*
+X0046604Y0125600D01*
+X0046831Y0125600D01*
+X0046831Y0124400D01*
+X0046604Y0124400D01*
+X0046604Y0121600D01*
+X0046733Y0121117D01*
+X0046831Y0120947D01*
+X0046831Y0117278D01*
+X0046747Y0117229D01*
+X0046393Y0116875D01*
+X0046143Y0116442D01*
+X0046013Y0115959D01*
+X0046013Y0113928D01*
+X0046831Y0113928D01*
+X0046831Y0112765D01*
+X0046013Y0112765D01*
+X0046013Y0110748D01*
+X0045736Y0110471D01*
+X0045467Y0109822D01*
+X0045433Y0109822D01*
+X0045327Y0110077D01*
+X0044861Y0110543D01*
+X0044920Y0110645D01*
+X0045050Y0111128D01*
+X0045050Y0113337D01*
+X0040600Y0113337D01*
+X0040600Y0114537D01*
+X0045050Y0114537D01*
+X0045050Y0116746D01*
+X0044920Y0117229D01*
+X0044670Y0117663D01*
+X0044316Y0118016D01*
+X0043883Y0118267D01*
+X0043400Y0118396D01*
+X0040600Y0118396D01*
+X0040600Y0114537D01*
+X0039400Y0114537D01*
+X0039400Y0113337D01*
+X0034950Y0113337D01*
+X0034950Y0111128D01*
+X0035080Y0110645D01*
+X0035139Y0110543D01*
+X0034673Y0110077D01*
+X0034282Y0109133D01*
+X0034282Y0102993D01*
+X0034673Y0102049D01*
+X0035395Y0101326D01*
+X0036339Y0100935D01*
+X0043661Y0100935D01*
+X0044605Y0101326D01*
+X0045327Y0102049D01*
+X0045695Y0102936D01*
+X0045736Y0102836D01*
+X0046458Y0102114D01*
+X0047402Y0101723D01*
+X0047501Y0101723D01*
+X0047501Y0099291D01*
+X0047983Y0098126D01*
+X0048874Y0097235D01*
+X0050039Y0096753D01*
+X0067365Y0096753D01*
+X0065286Y0095668D01*
+X0022749Y0095668D01*
+X0020668Y0097749D01*
+X0020668Y0149751D01*
+X0021782Y0150864D01*
+X0021782Y0145867D01*
+X0022173Y0144923D01*
+X0022639Y0144457D01*
+X0022580Y0144355D01*
+X0022450Y0143872D01*
+X0022450Y0141663D01*
+X0026900Y0141663D01*
+X0026900Y0140463D01*
+X0022450Y0140463D01*
+X0022450Y0138254D01*
+X0022580Y0137771D01*
+X0022830Y0137337D01*
+X0023184Y0136984D01*
+X0023617Y0136733D01*
+X0024100Y0136604D01*
+X0026900Y0136604D01*
+X0026900Y0140463D01*
+X0028100Y0140463D01*
+X0028100Y0141663D01*
+X0032550Y0141663D01*
+X0032550Y0143872D01*
+X0032420Y0144355D01*
+X0032361Y0144457D01*
+X0032827Y0144923D01*
+X0033218Y0145867D01*
+X0033218Y0151831D01*
+X0079208Y0151831D01*
+X0079912Y0151127D01*
+X0081591Y0150431D01*
+X0083409Y0150431D01*
+X0085088Y0151127D01*
+X0086373Y0152412D01*
+X0087068Y0154091D01*
+X0087068Y0155909D01*
+X0086872Y0156383D01*
+X0088505Y0154751D01*
+X0088505Y0130611D01*
+X0088366Y0130668D01*
+X0085668Y0130668D01*
+X0085668Y0130935D01*
+X0086161Y0130935D01*
+X0087105Y0131326D01*
+X0087827Y0132049D01*
+X0088218Y0132993D01*
+X0088218Y0139133D01*
+X0087827Y0140077D01*
+X0087361Y0140543D01*
+X0087420Y0140645D01*
+X0087550Y0141128D01*
+X0087550Y0143337D01*
+X0083100Y0143337D01*
+X0081900Y0143821D02*
+X0032550Y0143821D01*
+X0032550Y0142623D02*
+X0077450Y0142623D01*
+X0077450Y0141424D02*
+X0028100Y0141424D01*
+X0028100Y0140463D02*
+X0032550Y0140463D01*
+X0032550Y0138254D01*
+X0032420Y0137771D01*
+X0032170Y0137337D01*
+X0031816Y0136984D01*
+X0031383Y0136733D01*
+X0030900Y0136604D01*
+X0028100Y0136604D01*
+X0028100Y0140463D01*
+X0028100Y0140226D02*
+X0026900Y0140226D01*
+X0026900Y0141424D02*
+X0020668Y0141424D01*
+X0020668Y0140226D02*
+X0022450Y0140226D01*
+X0022450Y0139027D02*
+X0020668Y0139027D01*
+X0020668Y0137829D02*
+X0022564Y0137829D01*
+X0024002Y0136630D02*
+X0020668Y0136630D01*
+X0020668Y0135432D02*
+X0069684Y0135432D01*
+X0069789Y0135275D02*
+X0070275Y0134789D01*
+X0070847Y0134407D01*
+X0071482Y0134144D01*
+X0072156Y0134009D01*
+X0072500Y0134009D01*
+X0072844Y0134009D01*
+X0073518Y0134144D01*
+X0074153Y0134407D01*
+X0074725Y0134789D01*
+X0075211Y0135275D01*
+X0075593Y0135847D01*
+X0075856Y0136482D01*
+X0075991Y0137156D01*
+X0075991Y0137500D01*
+X0075991Y0137844D01*
+X0075856Y0138518D01*
+X0075593Y0139153D01*
+X0075211Y0139725D01*
+X0074725Y0140211D01*
+X0074153Y0140593D01*
+X0073518Y0140856D01*
+X0072844Y0140991D01*
+X0072500Y0140991D01*
+X0072156Y0140991D01*
+X0071482Y0140856D01*
+X0070847Y0140593D01*
+X0070275Y0140211D01*
+X0069789Y0139725D01*
+X0069407Y0139153D01*
+X0069144Y0138518D01*
+X0069009Y0137844D01*
+X0069009Y0137500D01*
+X0069009Y0137156D01*
+X0069144Y0136482D01*
+X0069407Y0135847D01*
+X0069789Y0135275D01*
+X0069114Y0136630D02*
+X0030998Y0136630D01*
+X0032436Y0137829D02*
+X0069009Y0137829D01*
+X0069009Y0137500D02*
+X0072500Y0137500D01*
+X0075991Y0137500D01*
+X0072500Y0137500D01*
+X0072500Y0137500D01*
+X0072500Y0137500D01*
+X0072500Y0140991D01*
+X0072500Y0137500D01*
+X0072500Y0134009D01*
+X0072500Y0137500D01*
+X0072500Y0137500D01*
+X0072500Y0137500D01*
+X0069009Y0137500D01*
+X0069355Y0139027D02*
+X0032550Y0139027D01*
+X0032550Y0140226D02*
+X0070297Y0140226D01*
+X0072500Y0140226D02*
+X0072500Y0140226D01*
+X0072500Y0139027D02*
+X0072500Y0139027D01*
+X0072500Y0137829D02*
+X0072500Y0137829D01*
+X0072500Y0136630D02*
+X0072500Y0136630D01*
+X0072500Y0135432D02*
+X0072500Y0135432D01*
+X0072500Y0134233D02*
+X0072500Y0134233D01*
+X0073735Y0134233D02*
+X0076782Y0134233D01*
+X0076782Y0133035D02*
+X0020668Y0133035D01*
+X0020668Y0134233D02*
+X0071265Y0134233D01*
+X0075316Y0135432D02*
+X0076782Y0135432D01*
+X0076782Y0136630D02*
+X0075886Y0136630D01*
+X0075991Y0137829D02*
+X0076782Y0137829D01*
+X0076782Y0139027D02*
+X0075645Y0139027D01*
+X0074703Y0140226D02*
+X0077322Y0140226D01*
+X0077450Y0144537D02*
+X0081900Y0144537D01*
+X0081900Y0148396D01*
+X0079100Y0148396D01*
+X0078617Y0148267D01*
+X0078184Y0148016D01*
+X0077830Y0147663D01*
+X0077580Y0147229D01*
+X0077450Y0146746D01*
+X0077450Y0144537D01*
+X0077450Y0145020D02*
+X0032867Y0145020D01*
+X0033218Y0146218D02*
+X0077450Y0146218D01*
+X0077688Y0147417D02*
+X0033218Y0147417D01*
+X0033218Y0149814D02*
+X0088505Y0149814D01*
+X0088505Y0151012D02*
+X0084811Y0151012D01*
+X0086172Y0152211D02*
+X0088505Y0152211D01*
+X0088505Y0153409D02*
+X0086786Y0153409D01*
+X0087068Y0154608D02*
+X0088505Y0154608D01*
+X0087449Y0155806D02*
+X0087068Y0155806D01*
+X0091673Y0156063D02*
+X0091673Y0117441D01*
+X0089705Y0117441D02*
+X0089705Y0145000D01*
+X0082500Y0145000D01*
+X0081900Y0145020D02*
+X0083100Y0145020D01*
+X0083100Y0146218D02*
+X0081900Y0146218D01*
+X0081900Y0147417D02*
+X0083100Y0147417D01*
+X0080189Y0151012D02*
+X0033218Y0151012D01*
+X0027500Y0155000D02*
+X0082500Y0155000D01*
+X0086673Y0161063D02*
+X0091673Y0156063D01*
+X0093642Y0160000D02*
+X0093642Y0117441D01*
+X0095610Y0117441D02*
+X0095610Y0180000D01*
+X0096250Y0181250D01*
+X0082500Y0181250D01*
+X0082500Y0177500D01*
+X0082490Y0176250D01*
+X0087618Y0176181D02*
+X0090032Y0176181D01*
+X0089981Y0176303D02*
+X0090936Y0173999D01*
+X0092442Y0172493D01*
+X0092442Y0165681D01*
+X0090437Y0167686D01*
+X0089272Y0168168D01*
+X0043812Y0168168D01*
+X0040668Y0171312D01*
+X0040668Y0202400D01*
+X0042100Y0202400D01*
+X0042100Y0207100D01*
+X0042900Y0207100D01*
+X0042900Y0202400D01*
+X0044331Y0202400D01*
+X0044331Y0201870D01*
+X0044814Y0200705D01*
+X0049814Y0195705D01*
+X0050705Y0194814D01*
+X0051870Y0194331D01*
+X0103688Y0194331D01*
+X0106831Y0191188D01*
+X0106831Y0166312D01*
+X0103688Y0163168D01*
+X0100885Y0163168D01*
+X0099721Y0162686D01*
+X0098830Y0161795D01*
+X0098779Y0161744D01*
+X0098779Y0171812D01*
+X0099801Y0172236D01*
+X0101564Y0173999D01*
+X0102518Y0176303D01*
+X0102518Y0186197D01*
+X0101564Y0188501D01*
+X0099801Y0190264D01*
+X0097497Y0191218D01*
+X0095003Y0191218D01*
+X0092699Y0190264D01*
+X0090936Y0188501D01*
+X0089981Y0186197D01*
+X0089981Y0184418D01*
+X0081870Y0184418D01*
+X0080705Y0183936D01*
+X0079814Y0183045D01*
+X0079331Y0181880D01*
+X0079331Y0181735D01*
+X0078476Y0181380D01*
+X0078118Y0181023D01*
+X0077819Y0181103D01*
+X0075610Y0181103D01*
+X0075610Y0176850D01*
+X0074410Y0176850D01*
+X0074410Y0181103D01*
+X0072201Y0181103D01*
+X0071717Y0180973D01*
+X0071284Y0180723D01*
+X0070930Y0180369D01*
+X0070680Y0179936D01*
+X0070551Y0179453D01*
+X0070551Y0176850D01*
+X0074410Y0176850D01*
+X0074410Y0175650D01*
+X0075610Y0175650D01*
+X0075610Y0171397D01*
+X0077819Y0171397D01*
+X0078118Y0171477D01*
+X0078476Y0171120D01*
+X0079420Y0170729D01*
+X0085560Y0170729D01*
+X0086504Y0171120D01*
+X0087227Y0171842D01*
+X0087618Y0172786D01*
+X0087618Y0178081D01*
+X0089981Y0178081D01*
+X0089981Y0176303D01*
+X0089981Y0177380D02*
+X0087618Y0177380D01*
+X0087618Y0174983D02*
+X0090528Y0174983D01*
+X0091151Y0173784D02*
+X0087618Y0173784D01*
+X0087535Y0172586D02*
+X0092349Y0172586D01*
+X0092442Y0171387D02*
+X0086771Y0171387D01*
+X0090182Y0167792D02*
+X0092442Y0167792D01*
+X0092442Y0168990D02*
+X0042991Y0168990D01*
+X0041792Y0170189D02*
+X0092442Y0170189D01*
+X0092442Y0166593D02*
+X0091530Y0166593D01*
+X0088642Y0165000D02*
+X0093642Y0160000D01*
+X0098779Y0161799D02*
+X0098834Y0161799D01*
+X0098779Y0162998D02*
+X0100473Y0162998D01*
+X0098779Y0164196D02*
+X0104715Y0164196D01*
+X0105914Y0165395D02*
+X0098779Y0165395D01*
+X0098779Y0166593D02*
+X0106831Y0166593D01*
+X0106831Y0167792D02*
+X0098779Y0167792D01*
+X0098779Y0168990D02*
+X0106831Y0168990D01*
+X0106831Y0170189D02*
+X0098779Y0170189D01*
+X0098779Y0171387D02*
+X0106831Y0171387D01*
+X0106831Y0172586D02*
+X0100151Y0172586D01*
+X0101349Y0173784D02*
+X0106831Y0173784D01*
+X0106831Y0174983D02*
+X0101972Y0174983D01*
+X0102468Y0176181D02*
+X0106831Y0176181D01*
+X0106831Y0177380D02*
+X0102518Y0177380D01*
+X0102518Y0178578D02*
+X0106831Y0178578D01*
+X0106831Y0179777D02*
+X0102518Y0179777D01*
+X0102518Y0180975D02*
+X0106831Y0180975D01*
+X0106831Y0182174D02*
+X0102518Y0182174D01*
+X0102518Y0183372D02*
+X0106831Y0183372D01*
+X0106831Y0184571D02*
+X0102518Y0184571D01*
+X0102518Y0185769D02*
+X0106831Y0185769D01*
+X0106831Y0186968D02*
+X0102199Y0186968D01*
+X0101703Y0188166D02*
+X0106831Y0188166D01*
+X0106831Y0189365D02*
+X0100700Y0189365D01*
+X0099079Y0190563D02*
+X0106831Y0190563D01*
+X0106257Y0191762D02*
+X0081775Y0191762D01*
+X0081653Y0191843D02*
+X0081018Y0192106D01*
+X0080344Y0192241D01*
+X0080000Y0192241D01*
+X0079656Y0192241D01*
+X0078982Y0192106D01*
+X0078347Y0191843D01*
+X0077775Y0191461D01*
+X0077289Y0190975D01*
+X0076907Y0190403D01*
+X0076644Y0189768D01*
+X0076509Y0189094D01*
+X0076509Y0188750D01*
+X0076509Y0188406D01*
+X0076644Y0187732D01*
+X0076907Y0187097D01*
+X0077289Y0186525D01*
+X0077775Y0186039D01*
+X0078347Y0185657D01*
+X0078982Y0185394D01*
+X0079656Y0185259D01*
+X0080000Y0185259D01*
+X0080344Y0185259D01*
+X0081018Y0185394D01*
+X0081653Y0185657D01*
+X0082225Y0186039D01*
+X0082711Y0186525D01*
+X0083093Y0187097D01*
+X0083356Y0187732D01*
+X0083491Y0188406D01*
+X0083491Y0188750D01*
+X0083491Y0189094D01*
+X0083356Y0189768D01*
+X0083093Y0190403D01*
+X0082711Y0190975D01*
+X0082225Y0191461D01*
+X0081653Y0191843D01*
+X0080000Y0191762D02*
+X0080000Y0191762D01*
+X0080000Y0192241D02*
+X0080000Y0188750D01*
+X0083491Y0188750D01*
+X0080000Y0188750D01*
+X0080000Y0188750D01*
+X0080000Y0188750D01*
+X0080000Y0192241D01*
+X0080000Y0190563D02*
+X0080000Y0190563D01*
+X0080000Y0189365D02*
+X0080000Y0189365D01*
+X0080000Y0188750D02*
+X0080000Y0188750D01*
+X0080000Y0185259D01*
+X0080000Y0188750D01*
+X0080000Y0188750D01*
+X0076509Y0188750D01*
+X0080000Y0188750D01*
+X0080000Y0188166D02*
+X0080000Y0188166D01*
+X0080000Y0186968D02*
+X0080000Y0186968D01*
+X0080000Y0185769D02*
+X0080000Y0185769D01*
+X0081822Y0185769D02*
+X0089981Y0185769D01*
+X0089981Y0184571D02*
+X0040668Y0184571D01*
+X0040668Y0185769D02*
+X0078178Y0185769D01*
+X0076993Y0186968D02*
+X0040668Y0186968D01*
+X0040668Y0188166D02*
+X0076557Y0188166D01*
+X0076563Y0189365D02*
+X0040668Y0189365D01*
+X0040668Y0190563D02*
+X0077014Y0190563D01*
+X0078225Y0191762D02*
+X0040668Y0191762D01*
+X0040668Y0192960D02*
+X0105059Y0192960D01*
+X0103860Y0194159D02*
+X0040668Y0194159D01*
+X0040668Y0195357D02*
+X0050162Y0195357D01*
+X0048963Y0196556D02*
+X0040668Y0196556D01*
+X0040668Y0197754D02*
+X0047765Y0197754D01*
+X0046566Y0198953D02*
+X0040668Y0198953D01*
+X0040668Y0200151D02*
+X0045368Y0200151D01*
+X0044547Y0201350D02*
+X0040668Y0201350D01*
+X0042100Y0202548D02*
+X0042900Y0202548D01*
+X0042900Y0203747D02*
+X0042100Y0203747D01*
+X0042100Y0204945D02*
+X0042900Y0204945D01*
+X0042900Y0206144D02*
+X0042100Y0206144D01*
+X0047500Y0202500D02*
+X0052500Y0197500D01*
+X0105000Y0197500D01*
+X0110000Y0192500D01*
+X0110000Y0165000D01*
+X0105000Y0160000D01*
+X0101516Y0160000D01*
+X0097579Y0156063D01*
+X0097579Y0117441D01*
+X0099547Y0117441D02*
+X0099547Y0153563D01*
+X0103484Y0157500D01*
+X0109402Y0157500D01*
+X0114402Y0162500D01*
+X0114402Y0192500D01*
+X0130733Y0198953D02*
+X0134267Y0198953D01*
+X0132707Y0200151D02*
+X0132293Y0200151D01*
+X0138098Y0205000D02*
+X0138098Y0217500D01*
+X0136240Y0217500D01*
+X0141368Y0216931D02*
+X0153160Y0216931D01*
+X0153160Y0216900D02*
+X0149301Y0216900D01*
+X0149301Y0214297D01*
+X0149430Y0213814D01*
+X0149680Y0213381D01*
+X0150034Y0213027D01*
+X0150467Y0212777D01*
+X0150951Y0212647D01*
+X0153160Y0212647D01*
+X0153160Y0216900D01*
+X0153160Y0215732D02*
+X0154360Y0215732D01*
+X0154360Y0214534D02*
+X0153160Y0214534D01*
+X0153160Y0213335D02*
+X0154360Y0213335D01*
+X0149726Y0213335D02*
+X0141267Y0213335D01*
+X0141267Y0212137D02*
+X0157789Y0212137D01*
+X0159004Y0210938D02*
+X0155996Y0210938D01*
+X0157338Y0209739D02*
+X0157662Y0209739D01*
+X0149301Y0214534D02*
+X0141368Y0214534D01*
+X0141368Y0215732D02*
+X0149301Y0215732D01*
+X0149301Y0218129D02*
+X0141368Y0218129D01*
+X0141368Y0219328D02*
+X0149301Y0219328D01*
+X0149301Y0220526D02*
+X0141368Y0220526D01*
+X0141053Y0221725D02*
+X0149786Y0221725D01*
+X0153160Y0221725D02*
+X0154360Y0221725D01*
+X0154360Y0220526D02*
+X0153160Y0220526D01*
+X0153160Y0219328D02*
+X0154360Y0219328D01*
+X0154360Y0218129D02*
+X0153160Y0218129D01*
+X0157933Y0222923D02*
+X0139547Y0222923D01*
+X0142193Y0210938D02*
+X0147807Y0210938D01*
+X0146465Y0209739D02*
+X0143535Y0209739D01*
+X0143817Y0208541D02*
+X0146183Y0208541D01*
+X0146183Y0207342D02*
+X0143817Y0207342D01*
+X0143817Y0206144D02*
+X0146183Y0206144D01*
+X0166368Y0214534D02*
+X0177553Y0214534D01*
+X0178751Y0215732D02*
+X0166368Y0215732D01*
+X0166368Y0216931D02*
+X0179231Y0216931D01*
+X0179231Y0218129D02*
+X0166368Y0218129D01*
+X0166368Y0219328D02*
+X0179231Y0219328D01*
+X0179868Y0220526D02*
+X0166368Y0220526D01*
+X0166053Y0221725D02*
+X0181067Y0221725D01*
+X0182265Y0222923D02*
+X0164547Y0222923D01*
+X0187141Y0224122D02*
+X0060359Y0224122D01*
+X0059161Y0225320D02*
+X0188529Y0225320D01*
+X0195000Y0217500D02*
+X0190000Y0212500D01*
+X0195400Y0207342D02*
+X0209009Y0207342D01*
+X0209009Y0207500D02*
+X0209009Y0207156D01*
+X0209144Y0206482D01*
+X0209407Y0205847D01*
+X0209789Y0205275D01*
+X0210275Y0204789D01*
+X0210847Y0204407D01*
+X0211482Y0204144D01*
+X0212156Y0204009D01*
+X0212500Y0204009D01*
+X0212844Y0204009D01*
+X0213518Y0204144D01*
+X0214153Y0204407D01*
+X0214725Y0204789D01*
+X0215211Y0205275D01*
+X0215593Y0205847D01*
+X0215856Y0206482D01*
+X0215991Y0207156D01*
+X0215991Y0207500D01*
+X0215991Y0207844D01*
+X0215856Y0208518D01*
+X0215593Y0209153D01*
+X0215211Y0209725D01*
+X0214725Y0210211D01*
+X0214153Y0210593D01*
+X0213518Y0210856D01*
+X0212844Y0210991D01*
+X0212500Y0210991D01*
+X0212156Y0210991D01*
+X0211482Y0210856D01*
+X0210847Y0210593D01*
+X0210275Y0210211D01*
+X0209789Y0209725D01*
+X0209407Y0209153D01*
+X0209144Y0208518D01*
+X0209009Y0207844D01*
+X0209009Y0207500D01*
+X0212500Y0207500D01*
+X0215991Y0207500D01*
+X0212500Y0207500D01*
+X0212500Y0207500D01*
+X0212500Y0207500D01*
+X0212500Y0210991D01*
+X0212500Y0207500D01*
+X0212500Y0204009D01*
+X0212500Y0207500D01*
+X0212500Y0207500D01*
+X0212500Y0207500D01*
+X0209009Y0207500D01*
+X0209153Y0208541D02*
+X0200100Y0208541D01*
+X0199973Y0209739D02*
+X0209803Y0209739D01*
+X0211892Y0210938D02*
+X0198774Y0210938D01*
+X0197794Y0212137D02*
+X0269959Y0212137D01*
+X0269950Y0210938D02*
+X0213108Y0210938D01*
+X0212500Y0210938D02*
+X0212500Y0210938D01*
+X0212500Y0209739D02*
+X0212500Y0209739D01*
+X0212500Y0208541D02*
+X0212500Y0208541D01*
+X0212500Y0207342D02*
+X0212500Y0207342D01*
+X0212500Y0206144D02*
+X0212500Y0206144D01*
+X0212500Y0204945D02*
+X0212500Y0204945D01*
+X0214882Y0204945D02*
+X0226023Y0204945D01*
+X0226044Y0205025D02*
+X0225915Y0204541D01*
+X0225915Y0202609D01*
+X0233631Y0202609D01*
+X0233631Y0206191D01*
+X0227565Y0206191D01*
+X0227082Y0206062D01*
+X0226648Y0205812D01*
+X0226295Y0205458D01*
+X0226044Y0205025D01*
+X0225915Y0203747D02*
+X0198459Y0203747D01*
+X0197261Y0202548D02*
+X0233631Y0202548D01*
+X0234597Y0202548D02*
+X0260403Y0202548D01*
+X0260886Y0202126D02*
+X0270000Y0202126D01*
+X0269085Y0203747D02*
+X0286132Y0203747D01*
+X0286132Y0204945D02*
+X0279732Y0204945D01*
+X0280050Y0206144D02*
+X0286132Y0206144D01*
+X0286132Y0207342D02*
+X0280050Y0207342D01*
+X0275600Y0206144D02*
+X0274400Y0206144D01*
+X0274400Y0204945D02*
+X0275600Y0204945D01*
+X0274400Y0208541D02*
+X0215847Y0208541D01*
+X0215991Y0207342D02*
+X0269950Y0207342D01*
+X0269950Y0206144D02*
+X0267612Y0206144D01*
+X0268977Y0204945D02*
+X0270268Y0204945D01*
+X0269950Y0209739D02*
+X0215197Y0209739D01*
+X0215716Y0206144D02*
+X0227388Y0206144D01*
+X0225915Y0201350D02*
+X0193168Y0201350D01*
+X0193168Y0200151D02*
+X0225915Y0200151D01*
+X0226203Y0198953D02*
+X0193168Y0198953D01*
+X0193168Y0197754D02*
+X0286132Y0197754D01*
+X0286132Y0196556D02*
+X0193168Y0196556D01*
+X0193168Y0195357D02*
+X0286132Y0195357D01*
+X0286132Y0194159D02*
+X0193168Y0194159D01*
+X0193168Y0192960D02*
+X0286132Y0192960D01*
+X0286132Y0191762D02*
+X0193168Y0191762D01*
+X0193168Y0190563D02*
+X0286132Y0190563D01*
+X0286132Y0189365D02*
+X0193168Y0189365D01*
+X0193168Y0188166D02*
+X0286132Y0188166D01*
+X0286132Y0186968D02*
+X0193168Y0186968D01*
+X0193168Y0185769D02*
+X0286132Y0185769D01*
+X0286132Y0184571D02*
+X0193168Y0184571D01*
+X0186831Y0184571D02*
+X0176208Y0184571D01*
+X0177750Y0185769D02*
+X0186831Y0185769D01*
+X0186831Y0186968D02*
+X0178949Y0186968D01*
+X0180147Y0188166D02*
+X0186831Y0188166D01*
+X0186831Y0189365D02*
+X0181346Y0189365D01*
+X0182544Y0190563D02*
+X0186831Y0190563D01*
+X0186831Y0191762D02*
+X0183124Y0191762D01*
+X0183168Y0192960D02*
+X0186831Y0192960D01*
+X0186831Y0194159D02*
+X0183168Y0194159D01*
+X0183168Y0195357D02*
+X0186831Y0195357D01*
+X0186831Y0196556D02*
+X0183168Y0196556D01*
+X0183168Y0197754D02*
+X0186831Y0197754D01*
+X0194600Y0202548D02*
+X0195400Y0202548D01*
+X0195400Y0202400D02*
+X0197112Y0202400D01*
+X0200100Y0205388D01*
+X0200100Y0207100D01*
+X0195400Y0207100D01*
+X0195400Y0202400D01*
+X0195400Y0203747D02*
+X0194600Y0203747D01*
+X0194600Y0204945D02*
+X0195400Y0204945D01*
+X0195400Y0206144D02*
+X0194600Y0206144D01*
+X0199658Y0204945D02*
+X0210118Y0204945D01*
+X0209284Y0206144D02*
+X0200100Y0206144D01*
+X0198993Y0213335D02*
+X0226834Y0213335D01*
+X0225522Y0214534D02*
+X0200191Y0214534D01*
+X0200768Y0215732D02*
+X0225246Y0215732D01*
+X0225246Y0216931D02*
+X0200768Y0216931D01*
+X0200768Y0218129D02*
+X0225246Y0218129D01*
+X0225246Y0219328D02*
+X0200768Y0219328D01*
+X0233631Y0206144D02*
+X0234597Y0206144D01*
+X0234597Y0204945D02*
+X0233631Y0204945D01*
+X0233631Y0203747D02*
+X0234597Y0203747D01*
+X0234597Y0201350D02*
+X0233631Y0201350D01*
+X0233631Y0200151D02*
+X0234597Y0200151D01*
+X0234597Y0198953D02*
+X0233631Y0198953D01*
+X0241395Y0213335D02*
+X0253605Y0213335D01*
+X0252293Y0214534D02*
+X0242707Y0214534D01*
+X0242361Y0221725D02*
+X0252639Y0221725D01*
+X0237283Y0222923D02*
+X0286132Y0222923D01*
+X0286132Y0224122D02*
+X0236872Y0224122D01*
+X0235585Y0225320D02*
+X0286132Y0225320D01*
+X0286132Y0226519D02*
+X0057962Y0226519D01*
+X0057686Y0226795D02*
+X0057686Y0226795D01*
+X0052500Y0217500D02*
+X0057500Y0212500D01*
+X0052500Y0217500D02*
+X0047500Y0222500D01*
+X0018937Y0222500D01*
+X0022500Y0217500D02*
+X0027500Y0212500D01*
+X0027500Y0166063D01*
+X0032500Y0161063D01*
+X0086673Y0161063D01*
+X0088642Y0165000D02*
+X0042500Y0165000D01*
+X0037500Y0170000D01*
+X0037500Y0212500D01*
+X0032500Y0217500D01*
+X0042500Y0217500D02*
+X0047500Y0212500D01*
+X0047500Y0202500D01*
+X0034331Y0202400D02*
+X0034331Y0169370D01*
+X0034814Y0168205D01*
+X0038788Y0164231D01*
+X0033812Y0164231D01*
+X0030668Y0167375D01*
+X0030668Y0202400D01*
+X0032100Y0202400D01*
+X0032100Y0207100D01*
+X0032900Y0207100D01*
+X0032900Y0202400D01*
+X0034331Y0202400D01*
+X0034331Y0201350D02*
+X0030668Y0201350D01*
+X0030668Y0200151D02*
+X0034331Y0200151D01*
+X0034331Y0198953D02*
+X0030668Y0198953D01*
+X0030668Y0197754D02*
+X0034331Y0197754D01*
+X0034331Y0196556D02*
+X0030668Y0196556D01*
+X0030668Y0195357D02*
+X0034331Y0195357D01*
+X0034331Y0194159D02*
+X0030668Y0194159D01*
+X0030668Y0192960D02*
+X0034331Y0192960D01*
+X0034331Y0191762D02*
+X0030668Y0191762D01*
+X0030668Y0190563D02*
+X0034331Y0190563D01*
+X0034331Y0189365D02*
+X0030668Y0189365D01*
+X0030668Y0188166D02*
+X0034331Y0188166D01*
+X0034331Y0186968D02*
+X0030668Y0186968D01*
+X0030668Y0185769D02*
+X0034331Y0185769D01*
+X0034331Y0184571D02*
+X0030668Y0184571D01*
+X0030668Y0183372D02*
+X0034331Y0183372D01*
+X0034331Y0182174D02*
+X0030668Y0182174D01*
+X0030668Y0180975D02*
+X0034331Y0180975D01*
+X0034331Y0179777D02*
+X0030668Y0179777D01*
+X0030668Y0178578D02*
+X0034331Y0178578D01*
+X0034331Y0177380D02*
+X0030668Y0177380D01*
+X0030668Y0176181D02*
+X0034331Y0176181D01*
+X0034331Y0174983D02*
+X0030668Y0174983D01*
+X0030668Y0173784D02*
+X0034331Y0173784D01*
+X0034331Y0172586D02*
+X0030668Y0172586D01*
+X0030668Y0171387D02*
+X0034331Y0171387D01*
+X0034331Y0170189D02*
+X0030668Y0170189D01*
+X0030668Y0168990D02*
+X0034489Y0168990D01*
+X0035227Y0167792D02*
+X0030668Y0167792D01*
+X0031451Y0166593D02*
+X0036426Y0166593D01*
+X0037624Y0165395D02*
+X0032649Y0165395D01*
+X0028482Y0160601D02*
+X0018168Y0160601D01*
+X0018168Y0161799D02*
+X0027283Y0161799D01*
+X0026084Y0162998D02*
+X0018168Y0162998D01*
+X0018168Y0164196D02*
+X0024886Y0164196D01*
+X0024814Y0164268D02*
+X0029814Y0159268D01*
+X0030705Y0158377D01*
+X0031208Y0158168D01*
+X0028130Y0158168D01*
+X0020807Y0158168D01*
+X0019642Y0157686D01*
+X0018751Y0156795D01*
+X0018168Y0156212D01*
+X0018168Y0204619D01*
+X0020388Y0202400D01*
+X0022100Y0202400D01*
+X0022100Y0207100D01*
+X0022900Y0207100D01*
+X0022900Y0202400D01*
+X0024331Y0202400D01*
+X0024331Y0165433D01*
+X0024814Y0164268D01*
+X0024347Y0165395D02*
+X0018168Y0165395D01*
+X0018168Y0166593D02*
+X0024331Y0166593D01*
+X0024331Y0167792D02*
+X0018168Y0167792D01*
+X0018168Y0168990D02*
+X0024331Y0168990D01*
+X0024331Y0170189D02*
+X0018168Y0170189D01*
+X0018168Y0171387D02*
+X0024331Y0171387D01*
+X0024331Y0172586D02*
+X0018168Y0172586D01*
+X0018168Y0173784D02*
+X0024331Y0173784D01*
+X0024331Y0174983D02*
+X0018168Y0174983D01*
+X0018168Y0176181D02*
+X0024331Y0176181D01*
+X0024331Y0177380D02*
+X0018168Y0177380D01*
+X0018168Y0178578D02*
+X0024331Y0178578D01*
+X0024331Y0179777D02*
+X0018168Y0179777D01*
+X0018168Y0180975D02*
+X0024331Y0180975D01*
+X0024331Y0182174D02*
+X0018168Y0182174D01*
+X0018168Y0183372D02*
+X0024331Y0183372D01*
+X0024331Y0184571D02*
+X0018168Y0184571D01*
+X0018168Y0185769D02*
+X0024331Y0185769D01*
+X0024331Y0186968D02*
+X0018168Y0186968D01*
+X0018168Y0188166D02*
+X0024331Y0188166D01*
+X0024331Y0189365D02*
+X0018168Y0189365D01*
+X0018168Y0190563D02*
+X0024331Y0190563D01*
+X0024331Y0191762D02*
+X0018168Y0191762D01*
+X0018168Y0192960D02*
+X0024331Y0192960D01*
+X0024331Y0194159D02*
+X0018168Y0194159D01*
+X0018168Y0195357D02*
+X0024331Y0195357D01*
+X0024331Y0196556D02*
+X0018168Y0196556D01*
+X0018168Y0197754D02*
+X0024331Y0197754D01*
+X0024331Y0198953D02*
+X0018168Y0198953D01*
+X0018168Y0200151D02*
+X0024331Y0200151D01*
+X0024331Y0201350D02*
+X0018168Y0201350D01*
+X0018168Y0202548D02*
+X0020239Y0202548D01*
+X0019041Y0203747D02*
+X0018168Y0203747D01*
+X0022100Y0203747D02*
+X0022900Y0203747D01*
+X0022900Y0204945D02*
+X0022100Y0204945D01*
+X0022100Y0206144D02*
+X0022900Y0206144D01*
+X0022900Y0202548D02*
+X0022100Y0202548D01*
+X0032100Y0202548D02*
+X0032900Y0202548D01*
+X0032900Y0203747D02*
+X0032100Y0203747D01*
+X0032100Y0204945D02*
+X0032900Y0204945D01*
+X0032900Y0206144D02*
+X0032100Y0206144D01*
+X0040668Y0183372D02*
+X0080141Y0183372D01*
+X0079453Y0182174D02*
+X0040668Y0182174D01*
+X0040668Y0180975D02*
+X0071725Y0180975D01*
+X0070638Y0179777D02*
+X0040668Y0179777D01*
+X0040668Y0178578D02*
+X0070551Y0178578D01*
+X0070551Y0177380D02*
+X0040668Y0177380D01*
+X0040668Y0176181D02*
+X0074410Y0176181D01*
+X0074410Y0175650D02*
+X0070551Y0175650D01*
+X0070551Y0173047D01*
+X0070680Y0172564D01*
+X0070930Y0172131D01*
+X0071284Y0171777D01*
+X0071717Y0171527D01*
+X0072201Y0171397D01*
+X0074410Y0171397D01*
+X0074410Y0175650D01*
+X0074410Y0174983D02*
+X0075610Y0174983D01*
+X0075610Y0173784D02*
+X0074410Y0173784D01*
+X0074410Y0172586D02*
+X0075610Y0172586D01*
+X0078209Y0171387D02*
+X0040668Y0171387D01*
+X0040668Y0172586D02*
+X0070674Y0172586D01*
+X0070551Y0173784D02*
+X0040668Y0173784D01*
+X0040668Y0174983D02*
+X0070551Y0174983D01*
+X0074410Y0177380D02*
+X0075610Y0177380D01*
+X0075610Y0178578D02*
+X0074410Y0178578D01*
+X0074410Y0179777D02*
+X0075610Y0179777D01*
+X0075610Y0180975D02*
+X0074410Y0180975D01*
+X0083007Y0186968D02*
+X0090301Y0186968D01*
+X0090797Y0188166D02*
+X0083443Y0188166D01*
+X0083437Y0189365D02*
+X0091800Y0189365D01*
+X0093421Y0190563D02*
+X0082986Y0190563D01*
+X0120493Y0151012D02*
+X0174552Y0151012D01*
+X0193168Y0151012D02*
+X0194552Y0151012D01*
+X0193514Y0149814D02*
+X0193168Y0149814D01*
+X0193168Y0152211D02*
+X0211553Y0152211D01*
+X0210933Y0153409D02*
+X0199563Y0153409D01*
+X0201069Y0154608D02*
+X0209734Y0154608D01*
+X0209231Y0155806D02*
+X0201743Y0155806D01*
+X0202068Y0157005D02*
+X0209231Y0157005D01*
+X0209231Y0158203D02*
+X0202068Y0158203D01*
+X0195941Y0161799D02*
+X0193168Y0161799D01*
+X0194327Y0153409D02*
+X0195437Y0153409D01*
+X0200448Y0151012D02*
+X0210355Y0151012D01*
+X0209231Y0149814D02*
+X0201486Y0149814D01*
+X0201983Y0148615D02*
+X0209231Y0148615D01*
+X0209231Y0147417D02*
+X0202068Y0147417D01*
+X0201914Y0146218D02*
+X0209231Y0146218D01*
+X0209322Y0145020D02*
+X0201418Y0145020D01*
+X0200668Y0143821D02*
+X0210521Y0143821D01*
+X0211719Y0142623D02*
+X0200668Y0142623D01*
+X0200668Y0141424D02*
+X0240926Y0141424D01*
+X0240926Y0140226D02*
+X0200668Y0140226D01*
+X0200668Y0139027D02*
+X0240926Y0139027D01*
+X0240926Y0137829D02*
+X0227049Y0137829D01*
+X0228103Y0136630D02*
+X0240976Y0136630D01*
+X0241694Y0135432D02*
+X0228473Y0135432D01*
+X0225000Y0135432D02*
+X0225000Y0135432D01*
+X0225000Y0136630D02*
+X0225000Y0136630D01*
+X0225000Y0137829D02*
+X0225000Y0137829D01*
+X0222951Y0137829D02*
+X0200668Y0137829D01*
+X0200668Y0136630D02*
+X0221897Y0136630D01*
+X0221527Y0135432D02*
+X0200668Y0135432D01*
+X0200668Y0134233D02*
+X0221594Y0134233D01*
+X0222115Y0133035D02*
+X0200668Y0133035D01*
+X0194331Y0133035D02*
+X0193426Y0133035D01*
+X0194184Y0131836D02*
+X0194331Y0131836D01*
+X0194331Y0134233D02*
+X0191718Y0134233D01*
+X0200668Y0124645D02*
+X0237235Y0124645D01*
+X0236629Y0123447D02*
+X0200668Y0123447D01*
+X0200230Y0122248D02*
+X0236509Y0122248D01*
+X0236823Y0121050D02*
+X0199094Y0121050D01*
+X0197895Y0119851D02*
+X0237712Y0119851D01*
+X0240000Y0123447D02*
+X0240000Y0123447D01*
+X0240000Y0124645D02*
+X0240000Y0124645D01*
+X0250806Y0135432D02*
+X0252944Y0135432D01*
+X0247500Y0140000D02*
+X0246250Y0140020D01*
+X0240926Y0142623D02*
+X0228281Y0142623D01*
+X0229479Y0143821D02*
+X0241147Y0143821D01*
+X0242200Y0145020D02*
+X0230678Y0145020D01*
+X0221719Y0142623D02*
+X0218281Y0142623D01*
+X0219479Y0143821D02*
+X0220521Y0143821D01*
+X0225000Y0134233D02*
+X0225000Y0134233D01*
+X0225000Y0133035D02*
+X0225000Y0133035D01*
+X0223740Y0107500D02*
+X0232500Y0107500D01*
+X0235000Y0105000D01*
+X0255157Y0105000D01*
+X0255157Y0101850D02*
+X0236437Y0101850D01*
+X0266910Y0070712D02*
+X0268110Y0070712D01*
+X0268110Y0069514D02*
+X0266910Y0069514D01*
+X0266910Y0068315D02*
+X0268110Y0068315D01*
+X0213124Y0061124D02*
+X0171268Y0061124D01*
+X0163731Y0061124D02*
+X0133396Y0061124D01*
+X0133396Y0059400D02*
+X0129537Y0059400D01*
+X0129537Y0054950D01*
+X0131746Y0054950D01*
+X0132229Y0055080D01*
+X0132663Y0055330D01*
+X0133016Y0055684D01*
+X0133267Y0056117D01*
+X0133396Y0056600D01*
+X0133396Y0059400D01*
+X0133396Y0058727D02*
+X0163731Y0058727D01*
+X0163731Y0057529D02*
+X0133396Y0057529D01*
+X0133324Y0056330D02*
+X0163731Y0056330D01*
+X0163731Y0055132D02*
+X0132319Y0055132D01*
+X0129537Y0055132D02*
+X0128337Y0055132D01*
+X0128337Y0056330D02*
+X0129537Y0056330D01*
+X0129537Y0057529D02*
+X0128337Y0057529D01*
+X0128337Y0058727D02*
+X0129537Y0058727D01*
+X0129537Y0059926D02*
+X0163731Y0059926D01*
+X0163731Y0062323D02*
+X0140227Y0062323D01*
+X0143337Y0063521D02*
+X0144537Y0063521D01*
+X0144537Y0062450D02*
+X0146746Y0062450D01*
+X0147229Y0062580D01*
+X0147663Y0062830D01*
+X0148016Y0063184D01*
+X0148267Y0063617D01*
+X0148396Y0064100D01*
+X0148396Y0066900D01*
+X0144537Y0066900D01*
+X0144537Y0062450D01*
+X0144537Y0064720D02*
+X0143337Y0064720D01*
+X0143337Y0065918D02*
+X0144537Y0065918D01*
+X0144537Y0067117D02*
+X0163731Y0067117D01*
+X0163731Y0068315D02*
+X0148396Y0068315D01*
+X0148396Y0069514D02*
+X0163731Y0069514D01*
+X0163731Y0070712D02*
+X0148396Y0070712D01*
+X0148396Y0065918D02*
+X0163731Y0065918D01*
+X0163731Y0064720D02*
+X0148396Y0064720D01*
+X0148211Y0063521D02*
+X0163731Y0063521D01*
+X0163731Y0053933D02*
+X0112558Y0053933D01*
+X0112558Y0055132D02*
+X0116590Y0055132D01*
+X0115939Y0056330D02*
+X0112558Y0056330D01*
+X0112558Y0057529D02*
+X0113286Y0057529D01*
+X0115295Y0060000D02*
+X0121063Y0060000D01*
+X0122500Y0060000D01*
+X0125536Y0055132D02*
+X0125555Y0055132D01*
+X0118760Y0047500D02*
+X0113327Y0047500D01*
+X0109390Y0051437D01*
+X0109390Y0072559D01*
+X0115295Y0072559D02*
+X0115295Y0060000D01*
+X0114998Y0052734D02*
+X0112573Y0052734D01*
+X0113772Y0051536D02*
+X0113869Y0051536D01*
+X0110802Y0045543D02*
+X0110590Y0045543D01*
+X0110590Y0044345D02*
+X0112664Y0044345D01*
+X0114001Y0043146D02*
+X0110590Y0043146D01*
+X0118712Y0034331D02*
+X0124751Y0034331D01*
+X0126831Y0032251D01*
+X0126831Y0027881D01*
+X0124612Y0030100D01*
+X0122900Y0030100D01*
+X0122900Y0025400D01*
+X0122100Y0025400D01*
+X0122100Y0030100D01*
+X0120668Y0030100D01*
+X0120668Y0031693D01*
+X0120186Y0032858D01*
+X0118712Y0034331D01*
+X0119486Y0033558D02*
+X0125524Y0033558D01*
+X0126722Y0032360D02*
+X0120392Y0032360D01*
+X0120668Y0031161D02*
+X0126831Y0031161D01*
+X0126831Y0029963D02*
+X0124750Y0029963D01*
+X0125948Y0028764D02*
+X0126831Y0028764D01*
+X0122900Y0028764D02*
+X0122100Y0028764D01*
+X0122100Y0027566D02*
+X0122900Y0027566D01*
+X0122900Y0026367D02*
+X0122100Y0026367D01*
+X0122100Y0029963D02*
+X0122900Y0029963D01*
+X0113982Y0030100D02*
+X0112251Y0031831D01*
+X0108759Y0031831D01*
+X0108679Y0031865D01*
+X0110186Y0030358D01*
+X0110321Y0030033D01*
+X0110388Y0030100D01*
+X0112100Y0030100D01*
+X0112100Y0025400D01*
+X0112900Y0025400D01*
+X0112900Y0030100D01*
+X0113982Y0030100D01*
+X0112900Y0029963D02*
+X0112100Y0029963D01*
+X0112100Y0028764D02*
+X0112900Y0028764D01*
+X0112900Y0027566D02*
+X0112100Y0027566D01*
+X0112100Y0026367D02*
+X0112900Y0026367D01*
+X0112921Y0031161D02*
+X0109383Y0031161D01*
+X0094410Y0031161D02*
+X0090668Y0031161D01*
+X0090668Y0030100D02*
+X0090668Y0042251D01*
+X0093065Y0044647D01*
+X0093468Y0044814D01*
+X0094410Y0045756D01*
+X0094410Y0030100D01*
+X0092900Y0030100D01*
+X0092900Y0025400D01*
+X0092100Y0025400D01*
+X0092100Y0030100D01*
+X0090668Y0030100D01*
+X0092100Y0029963D02*
+X0092900Y0029963D01*
+X0092900Y0028764D02*
+X0092100Y0028764D01*
+X0092100Y0027566D02*
+X0092900Y0027566D01*
+X0092900Y0026367D02*
+X0092100Y0026367D01*
+X0090668Y0032360D02*
+X0094410Y0032360D01*
+X0094410Y0033558D02*
+X0090668Y0033558D01*
+X0090668Y0034757D02*
+X0094410Y0034757D01*
+X0094410Y0035955D02*
+X0090668Y0035955D01*
+X0090668Y0037154D02*
+X0094410Y0037154D01*
+X0094410Y0038352D02*
+X0090668Y0038352D01*
+X0090668Y0039551D02*
+X0094410Y0039551D01*
+X0094410Y0040749D02*
+X0090668Y0040749D01*
+X0090668Y0041948D02*
+X0094410Y0041948D01*
+X0094410Y0043146D02*
+X0091564Y0043146D01*
+X0092763Y0044345D02*
+X0094410Y0044345D01*
+X0094410Y0045543D02*
+X0094198Y0045543D01*
+X0090008Y0050337D02*
+X0085665Y0050337D01*
+X0084466Y0049139D02*
+X0088595Y0049139D01*
+X0087397Y0047940D02*
+X0067803Y0047940D01*
+X0068064Y0055132D02*
+X0075181Y0055132D01*
+X0075271Y0055080D02*
+X0075754Y0054950D01*
+X0077963Y0054950D01*
+X0077963Y0059400D01*
+X0074104Y0059400D01*
+X0074104Y0056600D01*
+X0074233Y0056117D01*
+X0074484Y0055684D01*
+X0074837Y0055330D01*
+X0075271Y0055080D01*
+X0074176Y0056330D02*
+X0068287Y0056330D01*
+X0068287Y0057529D02*
+X0074104Y0057529D01*
+X0074104Y0058727D02*
+X0068287Y0058727D01*
+X0060769Y0063521D02*
+X0030743Y0063521D01*
+X0030668Y0064720D02*
+X0060769Y0064720D01*
+X0060769Y0065918D02*
+X0030668Y0065918D01*
+X0031942Y0062323D02*
+X0059960Y0062323D01*
+X0067105Y0064720D02*
+X0070378Y0064720D01*
+X0069377Y0065918D02*
+X0067105Y0065918D01*
+X0067815Y0067117D02*
+X0069017Y0067117D01*
+X0069103Y0068315D02*
+X0068847Y0068315D01*
+X0069065Y0069514D02*
+X0069647Y0069514D01*
+X0069065Y0070712D02*
+X0071134Y0070712D01*
+X0075353Y0069514D02*
+X0076854Y0069514D01*
+X0075897Y0068315D02*
+X0085395Y0068315D01*
+X0088505Y0067117D02*
+X0075983Y0067117D01*
+X0075623Y0065918D02*
+X0088505Y0065918D01*
+X0092143Y0059926D02*
+X0092442Y0059926D01*
+X0092442Y0058727D02*
+X0091565Y0058727D01*
+X0091565Y0057529D02*
+X0092442Y0057529D01*
+X0092442Y0056330D02*
+X0091561Y0056330D01*
+X0090910Y0055132D02*
+X0092442Y0055132D01*
+X0092442Y0053933D02*
+X0089180Y0053933D01*
+X0088062Y0052734D02*
+X0092427Y0052734D01*
+X0091228Y0051536D02*
+X0086863Y0051536D01*
+X0086198Y0046742D02*
+X0002568Y0046742D01*
+X0002568Y0045543D02*
+X0084999Y0045543D01*
+X0084394Y0044345D02*
+X0002568Y0044345D01*
+X0002568Y0043146D02*
+X0084331Y0043146D01*
+X0084331Y0041948D02*
+X0002568Y0041948D01*
+X0002568Y0040749D02*
+X0084331Y0040749D01*
+X0084331Y0039551D02*
+X0002568Y0039551D01*
+X0002568Y0038352D02*
+X0084331Y0038352D01*
+X0084331Y0037154D02*
+X0002568Y0037154D01*
+X0002568Y0035955D02*
+X0084331Y0035955D01*
+X0084331Y0034757D02*
+X0002568Y0034757D01*
+X0002568Y0033558D02*
+X0084331Y0033558D01*
+X0084331Y0032360D02*
+X0002568Y0032360D01*
+X0002568Y0031161D02*
+X0084331Y0031161D01*
+X0082900Y0029963D02*
+X0082100Y0029963D01*
+X0082100Y0028764D02*
+X0082900Y0028764D01*
+X0082900Y0027566D02*
+X0082100Y0027566D01*
+X0082100Y0026367D02*
+X0082900Y0026367D01*
+X0082100Y0025169D02*
+X0002568Y0025169D01*
+X0002568Y0026367D02*
+X0077400Y0026367D01*
+X0077853Y0027566D02*
+X0002568Y0027566D01*
+X0002568Y0028764D02*
+X0079052Y0028764D01*
+X0080250Y0029963D02*
+X0002568Y0029963D01*
+X0002568Y0023970D02*
+X0077400Y0023970D01*
+X0077516Y0022772D02*
+X0002568Y0022772D01*
+X0002568Y0021573D02*
+X0078714Y0021573D01*
+X0079717Y0020375D02*
+X0002568Y0020375D01*
+X0002568Y0019176D02*
+X0078518Y0019176D01*
+X0077320Y0017978D02*
+X0002568Y0017978D01*
+X0002568Y0016779D02*
+X0076731Y0016779D01*
+X0076731Y0015581D02*
+X0002568Y0015581D01*
+X0002568Y0014382D02*
+X0076731Y0014382D01*
+X0076731Y0013184D02*
+X0002568Y0013184D01*
+X0002568Y0011985D02*
+X0077357Y0011985D01*
+X0078555Y0010787D02*
+X0002568Y0010787D01*
+X0002568Y0009588D02*
+X0079754Y0009588D01*
+X0079163Y0055132D02*
+X0077963Y0055132D01*
+X0077963Y0056330D02*
+X0079163Y0056330D01*
+X0079163Y0057529D02*
+X0077963Y0057529D01*
+X0077963Y0058727D02*
+X0079163Y0058727D01*
+X0079163Y0061124D02*
+X0077963Y0061124D01*
+X0077963Y0062323D02*
+X0079163Y0062323D01*
+X0079163Y0063521D02*
+X0077963Y0063521D01*
+X0077963Y0064720D02*
+X0079163Y0064720D01*
+X0074923Y0064720D02*
+X0074622Y0064720D01*
+X0100000Y0086142D02*
+X0117264Y0086142D01*
+X0117264Y0072559D01*
+X0117264Y0067500D01*
+X0127500Y0067500D01*
+X0136063Y0067500D01*
+X0137036Y0050337D02*
+X0163731Y0050337D01*
+X0163778Y0049139D02*
+X0138099Y0049139D01*
+X0138471Y0047940D02*
+X0164274Y0047940D01*
+X0165518Y0046742D02*
+X0138408Y0046742D01*
+X0129872Y0088690D02*
+X0194782Y0088690D01*
+X0193583Y0089888D02*
+X0129872Y0089888D01*
+X0124941Y0097953D02*
+X0190000Y0097953D01*
+X0162500Y0122500D02*
+X0161240Y0122500D01*
+X0088505Y0130638D02*
+X0088441Y0130638D01*
+X0088505Y0131836D02*
+X0087614Y0131836D01*
+X0088218Y0133035D02*
+X0088505Y0133035D01*
+X0088505Y0134233D02*
+X0088218Y0134233D01*
+X0088218Y0135432D02*
+X0088505Y0135432D01*
+X0088505Y0136630D02*
+X0088218Y0136630D01*
+X0088218Y0137829D02*
+X0088505Y0137829D01*
+X0088505Y0139027D02*
+X0088218Y0139027D01*
+X0088505Y0140226D02*
+X0087678Y0140226D01*
+X0087550Y0141424D02*
+X0088505Y0141424D01*
+X0088505Y0142623D02*
+X0087550Y0142623D01*
+X0082500Y0136063D02*
+X0082500Y0127500D01*
+X0087736Y0127500D01*
+X0087736Y0117441D01*
+X0087500Y0117500D02*
+X0087500Y0110000D01*
+X0080059Y0109764D02*
+X0075000Y0109764D01*
+X0072500Y0112264D01*
+X0072500Y0116063D01*
+X0066782Y0116256D02*
+X0065538Y0116256D01*
+X0066737Y0115057D02*
+X0066782Y0115057D01*
+X0066782Y0117454D02*
+X0063974Y0117454D01*
+X0063168Y0118653D02*
+X0066782Y0118653D01*
+X0067079Y0119851D02*
+X0063168Y0119851D01*
+X0063944Y0121050D02*
+X0067471Y0121050D01*
+X0067450Y0122248D02*
+X0064065Y0122248D01*
+X0064065Y0123447D02*
+X0071900Y0123447D01*
+X0071900Y0124537D02*
+X0067450Y0124537D01*
+X0067450Y0126746D01*
+X0067580Y0127229D01*
+X0067830Y0127663D01*
+X0068184Y0128016D01*
+X0068617Y0128267D01*
+X0069100Y0128396D01*
+X0071900Y0128396D01*
+X0071900Y0124537D01*
+X0071900Y0124645D02*
+X0073100Y0124645D01*
+X0073100Y0123447D02*
+X0084568Y0123447D01*
+X0084568Y0122248D02*
+X0077550Y0122248D01*
+X0077529Y0121050D02*
+X0077590Y0121050D01*
+X0077550Y0124645D02*
+X0081112Y0124645D01*
+X0079756Y0125844D02*
+X0077550Y0125844D01*
+X0077470Y0127042D02*
+X0079331Y0127042D01*
+X0079331Y0128241D02*
+X0076428Y0128241D01*
+X0079331Y0129439D02*
+X0063742Y0129439D01*
+X0064065Y0128241D02*
+X0068572Y0128241D01*
+X0067530Y0127042D02*
+X0064065Y0127042D01*
+X0064065Y0125844D02*
+X0067450Y0125844D01*
+X0067450Y0124645D02*
+X0064065Y0124645D01*
+X0060000Y0125000D02*
+X0060000Y0113750D01*
+X0060000Y0112500D01*
+X0060000Y0113750D02*
+X0063563Y0113750D01*
+X0075423Y0101890D01*
+X0080059Y0101890D01*
+X0080059Y0099921D02*
+X0050669Y0099921D01*
+X0050669Y0106654D01*
+X0040000Y0106654D01*
+X0040000Y0106063D01*
+X0045141Y0110263D02*
+X0045650Y0110263D01*
+X0046013Y0111462D02*
+X0045050Y0111462D01*
+X0045050Y0112660D02*
+X0046013Y0112660D01*
+X0046831Y0113859D02*
+X0040600Y0113859D01*
+X0040000Y0113937D02*
+X0040000Y0113346D01*
+X0050669Y0113346D01*
+X0050000Y0112500D02*
+X0050000Y0125000D01*
+X0046831Y0124645D02*
+X0043488Y0124645D01*
+X0043491Y0124656D02*
+X0043491Y0125000D01*
+X0043491Y0125344D01*
+X0043356Y0126018D01*
+X0043093Y0126653D01*
+X0042711Y0127225D01*
+X0042225Y0127711D01*
+X0041653Y0128093D01*
+X0041018Y0128356D01*
+X0040344Y0128491D01*
+X0040000Y0128491D01*
+X0039656Y0128491D01*
+X0038982Y0128356D01*
+X0038347Y0128093D01*
+X0037775Y0127711D01*
+X0037289Y0127225D01*
+X0036907Y0126653D01*
+X0036644Y0126018D01*
+X0036509Y0125344D01*
+X0036509Y0125000D01*
+X0036509Y0124656D01*
+X0036644Y0123982D01*
+X0036907Y0123347D01*
+X0037289Y0122775D01*
+X0037775Y0122289D01*
+X0038347Y0121907D01*
+X0038982Y0121644D01*
+X0039656Y0121509D01*
+X0040000Y0121509D01*
+X0040344Y0121509D01*
+X0041018Y0121644D01*
+X0041653Y0121907D01*
+X0042225Y0122289D01*
+X0042711Y0122775D01*
+X0043093Y0123347D01*
+X0043356Y0123982D01*
+X0043491Y0124656D01*
+X0043491Y0125000D02*
+X0040000Y0125000D01*
+X0043491Y0125000D01*
+X0043391Y0125844D02*
+X0046604Y0125844D01*
+X0046604Y0127042D02*
+X0042833Y0127042D01*
+X0041297Y0128241D02*
+X0046604Y0128241D01*
+X0047107Y0129439D02*
+X0020668Y0129439D01*
+X0020668Y0128241D02*
+X0038703Y0128241D01*
+X0040000Y0128241D02*
+X0040000Y0128241D01*
+X0040000Y0128491D02*
+X0040000Y0125000D01*
+X0040000Y0125000D01*
+X0040000Y0125000D01*
+X0040000Y0128491D01*
+X0040000Y0127042D02*
+X0040000Y0127042D01*
+X0040000Y0125844D02*
+X0040000Y0125844D01*
+X0040000Y0125000D02*
+X0040000Y0125000D01*
+X0040000Y0121509D01*
+X0040000Y0125000D01*
+X0040000Y0125000D01*
+X0036509Y0125000D01*
+X0040000Y0125000D01*
+X0040000Y0124645D02*
+X0040000Y0124645D01*
+X0040000Y0123447D02*
+X0040000Y0123447D01*
+X0040000Y0122248D02*
+X0040000Y0122248D01*
+X0042164Y0122248D02*
+X0046604Y0122248D01*
+X0046604Y0123447D02*
+X0043135Y0123447D01*
+X0046772Y0121050D02*
+X0020668Y0121050D01*
+X0020668Y0122248D02*
+X0037836Y0122248D01*
+X0036865Y0123447D02*
+X0020668Y0123447D01*
+X0020668Y0124645D02*
+X0036512Y0124645D01*
+X0036609Y0125844D02*
+X0020668Y0125844D01*
+X0020668Y0127042D02*
+X0037167Y0127042D01*
+X0036600Y0118396D02*
+X0036117Y0118267D01*
+X0035684Y0118016D01*
+X0035330Y0117663D01*
+X0035080Y0117229D01*
+X0034950Y0116746D01*
+X0034950Y0114537D01*
+X0039400Y0114537D01*
+X0039400Y0118396D01*
+X0036600Y0118396D01*
+X0035210Y0117454D02*
+X0020668Y0117454D01*
+X0020668Y0116256D02*
+X0034950Y0116256D01*
+X0034950Y0115057D02*
+X0020668Y0115057D01*
+X0020668Y0113859D02*
+X0039400Y0113859D01*
+X0039400Y0115057D02*
+X0040600Y0115057D01*
+X0040600Y0116256D02*
+X0039400Y0116256D01*
+X0039400Y0117454D02*
+X0040600Y0117454D01*
+X0044790Y0117454D02*
+X0046831Y0117454D01*
+X0046831Y0118653D02*
+X0020668Y0118653D01*
+X0020668Y0119851D02*
+X0046831Y0119851D01*
+X0046093Y0116256D02*
+X0045050Y0116256D01*
+X0045050Y0115057D02*
+X0046013Y0115057D01*
+X0034950Y0112660D02*
+X0020668Y0112660D01*
+X0020668Y0111462D02*
+X0034950Y0111462D01*
+X0034859Y0110263D02*
+X0020668Y0110263D01*
+X0020668Y0109065D02*
+X0034282Y0109065D01*
+X0034282Y0107866D02*
+X0020668Y0107866D01*
+X0020668Y0106668D02*
+X0034282Y0106668D01*
+X0034282Y0105469D02*
+X0020668Y0105469D01*
+X0020668Y0104270D02*
+X0034282Y0104270D01*
+X0034282Y0103072D02*
+X0020668Y0103072D01*
+X0020668Y0101873D02*
+X0034848Y0101873D01*
+X0045152Y0101873D02*
+X0047039Y0101873D01*
+X0047501Y0100675D02*
+X0020668Y0100675D01*
+X0020668Y0099476D02*
+X0047501Y0099476D01*
+X0047920Y0098278D02*
+X0020668Y0098278D01*
+X0021339Y0097079D02*
+X0049250Y0097079D01*
+X0060000Y0105000D02*
+X0066250Y0105000D01*
+X0060000Y0105000D02*
+X0060000Y0107500D01*
+X0065693Y0095881D02*
+X0022537Y0095881D01*
+X0021979Y0077903D02*
+X0002568Y0077903D01*
+X0002568Y0076705D02*
+X0021979Y0076705D01*
+X0022047Y0075506D02*
+X0002568Y0075506D01*
+X0002568Y0074308D02*
+X0021979Y0074308D01*
+X0021979Y0073109D02*
+X0002568Y0073109D01*
+X0002568Y0071911D02*
+X0021979Y0071911D01*
+X0066063Y0092500D02*
+X0076516Y0097953D01*
+X0080059Y0097953D01*
+X0073100Y0125844D02*
+X0071900Y0125844D01*
+X0071900Y0127042D02*
+X0073100Y0127042D01*
+X0073100Y0128241D02*
+X0071900Y0128241D01*
+X0077386Y0131836D02*
+X0020668Y0131836D01*
+X0020668Y0130638D02*
+X0055673Y0130638D01*
+X0051663Y0129439D02*
+X0050463Y0129439D01*
+X0050463Y0128241D02*
+X0051663Y0128241D01*
+X0062201Y0130638D02*
+X0079331Y0130638D01*
+X0031124Y0158203D02*
+X0018168Y0158203D01*
+X0018168Y0157005D02*
+X0018961Y0157005D01*
+X0018168Y0159402D02*
+X0029680Y0159402D01*
+X0021782Y0149814D02*
+X0020732Y0149814D01*
+X0020668Y0148615D02*
+X0021782Y0148615D01*
+X0021782Y0147417D02*
+X0020668Y0147417D01*
+X0020668Y0146218D02*
+X0021782Y0146218D01*
+X0022133Y0145020D02*
+X0020668Y0145020D01*
+X0020668Y0143821D02*
+X0022450Y0143821D01*
+X0022450Y0142623D02*
+X0020668Y0142623D01*
+X0026900Y0139027D02*
+X0028100Y0139027D01*
+X0028100Y0137829D02*
+X0026900Y0137829D01*
+X0026900Y0136630D02*
+X0028100Y0136630D01*
+X0210011Y0059926D02*
+X0213124Y0059926D01*
+X0213249Y0058727D02*
+X0210770Y0058727D01*
+X0283559Y0147417D02*
+X0286132Y0147417D01*
+X0286132Y0148615D02*
+X0285235Y0148615D01*
+X0286116Y0149814D02*
+X0286132Y0149814D01*
+X0285972Y0166593D02*
+X0286132Y0166593D01*
+X0286132Y0198953D02*
+X0268797Y0198953D01*
+X0269085Y0200151D02*
+X0286132Y0200151D01*
+X0269295Y0213335D02*
+X0268166Y0213335D01*
+X0275000Y0216437D02*
+X0275000Y0217874D01*
+X0261369Y0201350D02*
+X0260403Y0201350D01*
+X0260403Y0200151D02*
+X0261369Y0200151D01*
+X0261369Y0198953D02*
+X0260403Y0198953D01*
+X0221516Y0182174D02*
+X0218484Y0182174D01*
+X0219683Y0180975D02*
+X0220317Y0180975D01*
+X0240565Y0164196D02*
+X0242481Y0164196D01*
+X0242481Y0162998D02*
+X0240960Y0162998D01*
+X0240919Y0161799D02*
+X0242481Y0161799D01*
+X0242481Y0160601D02*
+X0240429Y0160601D01*
+X0241527Y0159402D02*
+X0239142Y0159402D01*
+D32*
+X0246250Y0154980D02*
+X0246250Y0177500D01*
+X0262500Y0162500D02*
+X0257500Y0157500D01*
+X0257500Y0154980D01*
+X0262500Y0162500D02*
+X0277500Y0162500D01*
+X0262500Y0140000D02*
+X0257500Y0140000D01*
+X0247500Y0140000D01*
+X0262500Y0140000D02*
+X0267500Y0135000D01*
+X0267500Y0085000D01*
+X0262500Y0080000D01*
+X0240000Y0080000D01*
+X0237500Y0080000D01*
+X0237500Y0077500D01*
+X0242500Y0077500D01*
+X0242500Y0072500D01*
+X0237500Y0077500D02*
+X0222500Y0077500D01*
+X0222500Y0073701D01*
+X0228402Y0062201D02*
+X0228402Y0060000D01*
+X0244094Y0060000D01*
+X0245000Y0060000D01*
+X0245000Y0050000D01*
+X0167500Y0050000D01*
+X0167500Y0075000D01*
+X0127500Y0075000D01*
+X0245000Y0050000D02*
+X0266250Y0050000D01*
+X0267500Y0047500D01*
+X0255906Y0060000D02*
+X0255906Y0072500D01*
+X0255000Y0072500D02*
+X0267500Y0072500D01*
+D33*
+X0267500Y0075000D01*
+X0272500Y0080000D01*
+X0275000Y0080000D01*
+X0267510Y0072500D02*
+X0267500Y0072500D01*
+X0244094Y0072500D02*
+X0242500Y0072500D01*
+X0240000Y0080000D02*
+X0240000Y0081270D01*
+X0237500Y0094980D02*
+X0237500Y0095000D01*
+X0237500Y0094980D02*
+X0240000Y0096230D01*
+X0237500Y0098701D02*
+X0255157Y0098701D01*
+X0255157Y0111299D02*
+X0240000Y0111299D01*
+X0222500Y0073701D02*
+X0222500Y0063201D01*
+X0267500Y0047500D02*
+X0267500Y0037500D01*
+X0277500Y0037500D01*
+X0277500Y0027500D02*
+X0267500Y0027500D01*
+X0267500Y0017500D01*
+X0277500Y0017500D01*
+X0277500Y0047500D02*
+X0267500Y0047500D01*
+X0127500Y0067500D02*
+X0127500Y0075000D01*
+D34*
+X0135000Y0047500D03*
+X0072500Y0067500D03*
+X0058750Y0081250D03*
+X0040000Y0125000D03*
+X0072500Y0137500D03*
+X0080000Y0188750D03*
+X0152500Y0175000D03*
+X0170000Y0195000D03*
+X0212500Y0207500D03*
+X0237500Y0162500D03*
+X0225000Y0135000D03*
+X0240000Y0122500D03*
+X0277500Y0137500D03*
+X0275000Y0080000D03*
+X0255000Y0032500D03*
+X0207500Y0057500D03*
+X0151250Y0112500D03*
+X0150000Y0131250D03*
+D35*
+X0177500Y0147500D03*
+X0197500Y0147500D03*
+X0197500Y0157500D03*
+X0190000Y0130000D03*
+X0246250Y0177500D03*
+X0082500Y0155000D03*
+X0066250Y0105000D03*
+M02*
diff --git a/tests/gerber_files/simple1.gbr b/tests/gerber_files/simple1.gbr
new file mode 100644
index 00000000..2ca21d77
--- /dev/null
+++ b/tests/gerber_files/simple1.gbr
@@ -0,0 +1,54 @@
+G04 MADE WITH FRITZING*
+G04 WWW.FRITZING.ORG*
+G04 DOUBLE SIDED*
+G04 HOLES PLATED*
+G04 CONTOUR ON CENTER OF CONTOUR VECTOR*
+%ASAXBY*%
+%FSLAX23Y23*%
+%MOIN*%
+%OFA0B0*%
+%SFA1.0B1.0*%
+%ADD10R,0.047244X0.078740*%
+%ADD11C,0.024000*%
+%LNCOPPER1*%
+G90*
+G70*
+G54D10*
+X2940Y1051D03*
+X2940Y941D03*
+G54D11*
+X2438Y839D02*
+X2440Y1023D01*
+D02*
+X2940Y907D02*
+X2941Y839D01*
+D02*
+X2941Y839D02*
+X2438Y839D01*
+D02*
+X2941Y1239D02*
+X2940Y1085D01*
+D02*
+X2438Y1239D02*
+X2941Y1239D01*
+D02*
+X2440Y1126D02*
+X2438Y1239D01*
+G36*
+X2418Y1064D02*
+X2461Y1064D01*
+X2461Y1017D01*
+X2418Y1017D01*
+X2418Y1064D01*
+G37*
+D02*
+G36*
+X2418Y1131D02*
+X2461Y1131D01*
+X2461Y1084D01*
+X2418Y1084D01*
+X2418Y1131D01*
+G37*
+D02*
+G04 End of Copper1*
+M02*
\ No newline at end of file
diff --git a/tests/gerber_parsing_profiling/gerber1.gbr b/tests/gerber_parsing_profiling/gerber1.gbr
new file mode 100755
index 00000000..245ae335
--- /dev/null
+++ b/tests/gerber_parsing_profiling/gerber1.gbr
@@ -0,0 +1,3045 @@
+G04 Generated by Ultiboard 12.0 *
+%FSLAX25Y25*%
+%MOMM*%
+
+%ADD10C,0.00001*%
+%ADD11C,0.25400*%
+%ADD12C,0.50800*%
+%ADD13C,1.90500*%
+%ADD14C,0.12700*%
+%ADD15C,2.00000*%
+%ADD16R,1.80000X1.15000*%
+%ADD17C,1.60884*%
+%ADD18R,0.67742X0.67742*%
+%ADD19C,0.84658*%
+%ADD20R,0.76200X0.76200*%
+%ADD21C,0.50800*%
+%ADD22R,1.27000X1.27000*%
+%ADD23R,2.70000X1.15000*%
+%ADD24R,1.15000X1.45000*%
+%ADD25R,1.15000X2.70000*%
+%ADD26R,0.52908X0.52908*%
+%ADD27C,0.99492*%
+%ADD28C,1.80000*%
+%ADD29R,1.80000X1.80000*%
+%ADD30R,2.57000X2.80000*%
+%ADD31C,1.98984*%
+
+
+G04 ColorRGB 002000 for the following layer *
+%LNCopper Top*%
+%LPD*%
+G54D10*
+G36*
+X1590549Y63807D02*
+X1590549Y63807D01*
+X3936193Y63807D01*
+X3936193Y6436193D01*
+X63807Y6436193D01*
+X63807Y63807D01*
+X1254251Y63807D01*
+G75*
+D01*
+G02X1230093Y113800I39649J49993*
+G01*
+X1230093Y113800D01*
+X1230093Y185606D01*
+X1354206Y185606D01*
+X1354206Y63807D01*
+X1490594Y63807D01*
+X1490594Y185606D01*
+X1614707Y185606D01*
+X1614707Y113800D01*
+G75*
+D01*
+G02X1590549Y63807I-63807J0*
+G01*
+D02*
+G37*
+%LPC*%
+G36*
+X2821307Y4787900D02*
+X2821307Y4787900D01*
+X2821307Y4717860D01*
+G75*
+D01*
+G02X2855900Y4724830I34593J-82359*
+G01*
+X2855900Y4724830D01*
+X2932100Y4724830D01*
+G74*
+D01*
+G02X3021430Y4635500I0J89330*
+G01*
+X3021430Y4635500D01*
+X3021430Y4559300D01*
+G75*
+D01*
+G02X2940855Y4470400I-89330J0*
+G01*
+G74*
+D01*
+G02X3021430Y4381500I8755J88900*
+G01*
+X3021430Y4381500D01*
+X3021430Y4379662D01*
+X3024710Y4382942D01*
+X3024710Y5027758D01*
+X2858598Y5193870D01*
+X1490507Y5193870D01*
+X1490507Y5148200D01*
+G75*
+D01*
+G02X1426700Y5084393I-63807J0*
+G01*
+X1426700Y5084393D01*
+X1311700Y5084393D01*
+G75*
+D01*
+G02X1247893Y5148200I0J63807*
+G01*
+X1247893Y5148200D01*
+X1247893Y5418200D01*
+G75*
+D01*
+G02X1311700Y5482007I63807J0*
+G01*
+X1311700Y5482007D01*
+X1426700Y5482007D01*
+G74*
+D01*
+G02X1490507Y5418200I0J63807*
+G01*
+X1490507Y5418200D01*
+X1490507Y5372530D01*
+X2022842Y5372530D01*
+G75*
+D01*
+G02X2244358Y5372530I110758J120269*
+G01*
+X2244358Y5372530D01*
+X2530842Y5372530D01*
+G75*
+D01*
+G02X2752358Y5372530I110758J120269*
+G01*
+X2752358Y5372530D01*
+X2895490Y5372530D01*
+G75*
+D01*
+G02X2928856Y5366109I110J-89330*
+G01*
+G74*
+D01*
+G02X2958845Y5346286I33257J82908*
+G01*
+X2958845Y5346286D01*
+X3177126Y5128005D01*
+G74*
+D01*
+G02X3203370Y5064760I63085J63245*
+G01*
+X3203370Y5064760D01*
+X3203370Y4345940D01*
+G75*
+D01*
+G02X3177126Y4282695I-89330J1*
+G01*
+X3177126Y4282695D01*
+X3047745Y4153314D01*
+G74*
+D01*
+G02X3021121Y4134921I63246J63084*
+G01*
+G74*
+D01*
+G02X3021430Y4127500I89020J7424*
+G01*
+X3021430Y4127500D01*
+X3021430Y4051300D01*
+G75*
+D01*
+G02X2940855Y3962400I-89330J0*
+G01*
+G74*
+D01*
+G02X3021148Y3880588I8755J88900*
+G01*
+X3021148Y3880588D01*
+X2939188Y3880588D01*
+X2939188Y3962252D01*
+G74*
+D01*
+G02X2932100Y3961970I7092J89047*
+G01*
+X2932100Y3961970D01*
+X2855900Y3961970D01*
+G75*
+D01*
+G02X2848812Y3962252I4J89330*
+G01*
+X2848812Y3962252D01*
+X2848812Y3880588D01*
+X2810004Y3880588D01*
+G74*
+D01*
+G02X2740855Y3835400I77904J43711*
+G01*
+G74*
+D01*
+G02X2810004Y3790212I8756J88900*
+G01*
+X2810004Y3790212D01*
+X2848812Y3790212D01*
+X2848812Y3708548D01*
+G75*
+D01*
+G02X2855900Y3708830I7092J-89047*
+G01*
+X2855900Y3708830D01*
+X2932100Y3708830D01*
+G74*
+D01*
+G02X2939188Y3708548I4J89330*
+G01*
+X2939188Y3708548D01*
+X2939188Y3790212D01*
+X3021148Y3790212D01*
+G74*
+D01*
+G02X2940855Y3708400I89047J7087*
+G01*
+G74*
+D01*
+G02X3021430Y3619500I8755J88900*
+G01*
+X3021430Y3619500D01*
+X3021430Y3543300D01*
+G75*
+D01*
+G02X2940855Y3454400I-89330J0*
+G01*
+G74*
+D01*
+G02X3021430Y3365500I8755J88900*
+G01*
+X3021430Y3365500D01*
+X3021430Y3289300D01*
+G75*
+D01*
+G02X3001389Y3232918I-89330J0*
+G01*
+X3001389Y3232918D01*
+X3318326Y3232918D01*
+G75*
+D01*
+G02X3364423Y3252607I46097J-44117*
+G01*
+X3364423Y3252607D01*
+X3412122Y3252607D01*
+G75*
+D01*
+G02X3496724Y3252607I42301J-153806*
+G01*
+X3496724Y3252607D01*
+X3544423Y3252607D01*
+G74*
+D01*
+G02X3608231Y3188800I1J63807*
+G01*
+X3608231Y3188800D01*
+X3608231Y3141101D01*
+G75*
+D01*
+G02X3608231Y3056499I-153807J-42301*
+G01*
+X3608231Y3056499D01*
+X3608231Y3008800D01*
+G75*
+D01*
+G02X3544423Y2944993I-63808J1*
+G01*
+X3544423Y2944993D01*
+X3523668Y2944993D01*
+G74*
+D01*
+G02X3429023Y2913882I94645J128407*
+G01*
+X3429023Y2913882D01*
+X3001389Y2913882D01*
+G74*
+D01*
+G02X3021430Y2857500I69289J56382*
+G01*
+X3021430Y2857500D01*
+X3021430Y2781300D01*
+G75*
+D01*
+G02X2940855Y2692400I-89330J0*
+G01*
+G74*
+D01*
+G02X3021148Y2610588I8755J88900*
+G01*
+X3021148Y2610588D01*
+X2939188Y2610588D01*
+X2939188Y2692252D01*
+G74*
+D01*
+G02X2932100Y2691970I7092J89047*
+G01*
+X2932100Y2691970D01*
+X2855900Y2691970D01*
+G75*
+D01*
+G02X2848812Y2692252I4J89330*
+G01*
+X2848812Y2692252D01*
+X2848812Y2610588D01*
+X2810004Y2610588D01*
+G74*
+D01*
+G02X2740855Y2565400I77904J43711*
+G01*
+G74*
+D01*
+G02X2810004Y2520212I8756J88900*
+G01*
+X2810004Y2520212D01*
+X2848812Y2520212D01*
+X2848812Y2438548D01*
+G75*
+D01*
+G02X2855900Y2438830I7092J-89047*
+G01*
+X2855900Y2438830D01*
+X2932100Y2438830D01*
+G74*
+D01*
+G02X2939188Y2438548I4J89330*
+G01*
+X2939188Y2438548D01*
+X2939188Y2520212D01*
+X3021148Y2520212D01*
+G74*
+D01*
+G02X2940855Y2438400I89047J7087*
+G01*
+G74*
+D01*
+G02X3021430Y2349500I8755J88900*
+G01*
+X3021430Y2349500D01*
+X3021430Y2273300D01*
+G75*
+D01*
+G02X2940855Y2184400I-89330J0*
+G01*
+G74*
+D01*
+G02X3021430Y2095500I8755J88900*
+G01*
+X3021430Y2095500D01*
+X3021430Y2019300D01*
+G75*
+D01*
+G02X2940855Y1930400I-89330J0*
+G01*
+G74*
+D01*
+G02X3021430Y1841500I8755J88900*
+G01*
+X3021430Y1841500D01*
+X3021430Y1765300D01*
+G75*
+D01*
+G02X2932100Y1675970I-89330J0*
+G01*
+X2932100Y1675970D01*
+X2855900Y1675970D01*
+G75*
+D01*
+G02X2821430Y1682888I-1J89330*
+G01*
+X2821430Y1682888D01*
+X2821430Y1638300D01*
+G75*
+D01*
+G02X2732100Y1548970I-89330J0*
+G01*
+X2732100Y1548970D01*
+X2655900Y1548970D01*
+G75*
+D01*
+G02X2566570Y1638300I0J89330*
+G01*
+X2566570Y1638300D01*
+X2566570Y1714500D01*
+G74*
+D01*
+G02X2647145Y1803400I89330J0*
+G01*
+G75*
+D01*
+G02X2566570Y1892300I8755J88900*
+G01*
+X2566570Y1892300D01*
+X2566570Y1968500D01*
+G74*
+D01*
+G02X2647145Y2057400I89330J0*
+G01*
+G74*
+D01*
+G02X2582720Y2095070I8755J88900*
+G01*
+X2582720Y2095070D01*
+X2045877Y2095070D01*
+G75*
+D01*
+G02X1982664Y2121234I-47J89330*
+G01*
+X1982664Y2121234D01*
+X1562434Y2541464D01*
+G75*
+D01*
+G02X1536270Y2604716I63166J63166*
+G01*
+X1536270Y2604716D01*
+X1536270Y2878293D01*
+X1490600Y2878293D01*
+G75*
+D01*
+G02X1427407Y2933270I0J63807*
+G01*
+X1427407Y2933270D01*
+X725170Y2933270D01*
+G75*
+D01*
+G02X701417Y2936486I0J89330*
+G01*
+G74*
+D01*
+G02X662004Y2959434I23752J86113*
+G01*
+X662004Y2959434D01*
+X597330Y3024108D01*
+X597330Y2563005D01*
+G74*
+D01*
+G02X648212Y2472271I55458J90734*
+G01*
+X648212Y2472271D01*
+X648212Y2404529D01*
+G75*
+D01*
+G02X597330Y2313795I-106341J0*
+G01*
+X597330Y2313795D01*
+X597330Y2297269D01*
+G75*
+D01*
+G02X597330Y2071531I-89329J-112869*
+G01*
+X597330Y2071531D01*
+X597330Y2043269D01*
+G75*
+D01*
+G02X597330Y1817531I-89329J-112869*
+G01*
+X597330Y1817531D01*
+X597330Y1789269D01*
+G75*
+D01*
+G02X597330Y1563531I-89329J-112869*
+G01*
+X597330Y1563531D01*
+X597330Y1486330D01*
+X1473200Y1486330D01*
+G74*
+D01*
+G02X1536445Y1460086I1J89330*
+G01*
+X1536445Y1460086D01*
+X1815686Y1180845D01*
+G74*
+D01*
+G02X1827393Y1166446I63083J63248*
+G01*
+X1827393Y1166446D01*
+X1827393Y1172700D01*
+G75*
+D01*
+G02X1891200Y1236507I63807J0*
+G01*
+X1891200Y1236507D01*
+X1891870Y1236507D01*
+X1891870Y1239969D01*
+G75*
+D01*
+G02X1918034Y1303266I89330J131*
+G01*
+X1918034Y1303266D01*
+X2032334Y1417566D01*
+G74*
+D01*
+G02X2052310Y1432595I63165J63167*
+G01*
+G75*
+D01*
+G02X2309229Y1443730I132090J-78194*
+G01*
+X2309229Y1443730D01*
+X2362157Y1443730D01*
+G75*
+D01*
+G02X2370371Y1443356I48J-89330*
+G01*
+G74*
+D01*
+G02X2425445Y1417486I8172J88955*
+G01*
+X2425445Y1417486D01*
+X2603086Y1239845D01*
+G74*
+D01*
+G02X2629330Y1176600I63085J63245*
+G01*
+X2629330Y1176600D01*
+X2629330Y644332D01*
+G74*
+D01*
+G02X2702712Y517549I89329J136332*
+G01*
+X2702712Y517549D01*
+X2712261Y508000D01*
+X2702712Y498451D01*
+G75*
+D01*
+G02X2413000Y405837I-162711J9547*
+G01*
+G75*
+D01*
+G02X2196670Y644332I-126997J102166*
+G01*
+X2196670Y644332D01*
+X2196670Y693893D01*
+X2196000Y693893D01*
+G75*
+D01*
+G02X2140699Y725870I0J63807*
+G01*
+X2140699Y725870D01*
+X2126501Y725870D01*
+G74*
+D01*
+G02X2071200Y693893I55301J31830*
+G01*
+X2071200Y693893D01*
+X1891200Y693893D01*
+G75*
+D01*
+G02X1835899Y725870I0J63807*
+G01*
+X1835899Y725870D01*
+X1826450Y725870D01*
+G75*
+D01*
+G02X1763234Y752034I-50J89330*
+G01*
+X1763234Y752034D01*
+X1689434Y825834D01*
+G75*
+D01*
+G02X1663270Y889088I63166J63166*
+G01*
+X1663270Y889088D01*
+X1663270Y1080598D01*
+X1625968Y1117900D01*
+G74*
+D01*
+G02X1625969Y1117600I76567J405*
+G01*
+X1625969Y1117600D01*
+X1625969Y736600D01*
+G75*
+D01*
+G02X1567930Y662307I-76569J0*
+G01*
+G74*
+D01*
+G02X1550900Y659993I17028J61493*
+G01*
+X1550900Y659993D01*
+X1293900Y659993D01*
+G75*
+D01*
+G02X1276871Y662307I-1J63807*
+G01*
+G74*
+D01*
+G02X1266963Y665508I18531J74292*
+G01*
+X1266963Y665508D01*
+X758963Y868708D01*
+G75*
+D01*
+G02X710831Y939939I28436J71092*
+G01*
+X710831Y939939D01*
+X710831Y1117600D01*
+G75*
+D01*
+G02X787400Y1194169I76569J0*
+G01*
+X787400Y1194169D01*
+X1549400Y1194169D01*
+G74*
+D01*
+G02X1549700Y1194168I105J76569*
+G01*
+X1549700Y1194168D01*
+X1436198Y1307670D01*
+X508000Y1307670D01*
+G75*
+D01*
+G02X418670Y1397000I0J89330*
+G01*
+X418670Y1397000D01*
+X418670Y1563531D01*
+G75*
+D01*
+G02X418670Y1789269I89329J112869*
+G01*
+X418670Y1789269D01*
+X418670Y1817531D01*
+G75*
+D01*
+G02X418670Y2043269I89329J112869*
+G01*
+X418670Y2043269D01*
+X418670Y2071531D01*
+G75*
+D01*
+G02X418670Y2297269I89329J112869*
+G01*
+X418670Y2297269D01*
+X418670Y2313795D01*
+G75*
+D01*
+G02X367788Y2404529I55458J90734*
+G01*
+X367788Y2404529D01*
+X367788Y2472271D01*
+G74*
+D01*
+G02X418670Y2563005I106341J0*
+G01*
+X418670Y2563005D01*
+X418670Y4408331D01*
+G75*
+D01*
+G02X418670Y4634069I89329J112869*
+G01*
+X418670Y4634069D01*
+X418670Y4650595D01*
+G75*
+D01*
+G02X367788Y4741329I55458J90734*
+G01*
+X367788Y4741329D01*
+X367788Y4809071D01*
+G74*
+D01*
+G02X418670Y4899805I106341J0*
+G01*
+X418670Y4899805D01*
+X418670Y5029034D01*
+G75*
+D01*
+G02X444834Y5092366I89330J166*
+G01*
+X444834Y5092366D01*
+X698834Y5346366D01*
+G74*
+D01*
+G02X749888Y5371705I63166J63166*
+G01*
+G75*
+D01*
+G02X762000Y5372530I12112J-88504*
+G01*
+X762000Y5372530D01*
+X947893Y5372530D01*
+X947893Y5418200D01*
+G75*
+D01*
+G02X1011700Y5482007I63807J0*
+G01*
+X1011700Y5482007D01*
+X1126700Y5482007D01*
+G74*
+D01*
+G02X1190507Y5418200I0J63807*
+G01*
+X1190507Y5418200D01*
+X1190507Y5148200D01*
+G75*
+D01*
+G02X1126700Y5084393I-63807J0*
+G01*
+X1126700Y5084393D01*
+X1011700Y5084393D01*
+G75*
+D01*
+G02X947893Y5148200I0J63807*
+G01*
+X947893Y5148200D01*
+X947893Y5193870D01*
+X799002Y5193870D01*
+X597330Y4992198D01*
+X597330Y4899805D01*
+G74*
+D01*
+G02X648212Y4809071I55458J90734*
+G01*
+X648212Y4809071D01*
+X648212Y4741329D01*
+G75*
+D01*
+G02X597330Y4650595I-106341J0*
+G01*
+X597330Y4650595D01*
+X597330Y4634069D01*
+G75*
+D01*
+G02X597330Y4408331I-89329J-112869*
+G01*
+X597330Y4408331D01*
+X597330Y4379992D01*
+X646904Y4429566D01*
+G74*
+D01*
+G02X677608Y4449623I63166J63166*
+G01*
+G75*
+D01*
+G02X710070Y4455730I32462J-83223*
+G01*
+X710070Y4455730D01*
+X1141809Y4455730D01*
+G75*
+D01*
+G02X1202249Y4648200I128190J65470*
+G01*
+G75*
+D01*
+G02X1382869Y4864530I67754J126998*
+G01*
+X1382869Y4864530D01*
+X2640232Y4864530D01*
+G75*
+D01*
+G02X2669697Y4859565I98J-89330*
+G01*
+G74*
+D01*
+G02X2686444Y4851707I29368J84364*
+G01*
+X2686444Y4851707D01*
+X2757500Y4851707D01*
+G74*
+D01*
+G02X2821307Y4787900I0J63807*
+G01*
+D02*
+G37*
+G36*
+X1202249Y2311400D02*
+G75*
+D01*
+G02X1337751Y2311400I67751J126999*
+G01*
+G75*
+D01*
+G02X1337751Y2057400I-67750J-127000*
+G01*
+G75*
+D01*
+G02X1337751Y1803400I-67750J-127000*
+G01*
+G75*
+D01*
+G02X1202249Y1803400I-67751J-126999*
+G01*
+G75*
+D01*
+G02X1202249Y2057400I67750J127000*
+G01*
+G75*
+D01*
+G02X1202249Y2311400I67750J127000*
+G01*
+D02*
+G37*
+G36*
+X2986100Y5492800D02*
+G75*
+D01*
+G02X2986100Y5492800I163500J0*
+G01*
+D02*
+G37*
+G36*
+X3494100Y5492800D02*
+G75*
+D01*
+G02X3494100Y5492800I163500J0*
+G01*
+D02*
+G37*
+G36*
+X2864000Y2565400D02*
+G75*
+D01*
+G02X2864000Y2565400I30000J0*
+G01*
+D02*
+G37*
+G36*
+X2864000Y3835400D02*
+G75*
+D01*
+G02X2864000Y3835400I30000J0*
+G01*
+D02*
+G37*
+G36*
+X2860893Y359367D02*
+G75*
+D01*
+G02X2727107Y359367I-66893J148633*
+G01*
+X2727107Y359367D01*
+X2794000Y426261D01*
+X2860893Y359367D01*
+D02*
+G37*
+G36*
+X3300593Y351300D02*
+X3300593Y351300D01*
+X3300593Y365783D01*
+X3411383Y365783D01*
+X3411383Y287493D01*
+X3364400Y287493D01*
+G75*
+D01*
+G02X3300593Y351300I0J63807*
+G01*
+D02*
+G37*
+G36*
+X3608207Y351300D02*
+G75*
+D01*
+G02X3544400Y287493I-63807J0*
+G01*
+X3544400Y287493D01*
+X3497417Y287493D01*
+X3497417Y365783D01*
+X3608207Y365783D01*
+X3608207Y351300D01*
+D02*
+G37*
+G36*
+X2727107Y656633D02*
+G75*
+D01*
+G02X2860893Y656633I66893J-148633*
+G01*
+X2860893Y656633D01*
+X2794000Y589739D01*
+X2727107Y656633D01*
+D02*
+G37*
+G36*
+X2734729Y508000D02*
+G75*
+D01*
+G02X2734729Y508000I59271J0*
+G01*
+D02*
+G37*
+G36*
+X2942633Y574893D02*
+G75*
+D01*
+G02X2942633Y441107I-148633J-66893*
+G01*
+X2942633Y441107D01*
+X2875739Y508000D01*
+X2942633Y574893D01*
+D02*
+G37*
+G36*
+X3364400Y530107D02*
+X3364400Y530107D01*
+X3411383Y530107D01*
+X3411383Y451817D01*
+X3300593Y451817D01*
+X3300593Y466300D01*
+G75*
+D01*
+G02X3364400Y530107I63807J0*
+G01*
+D02*
+G37*
+G36*
+X3543730Y873971D02*
+X3543730Y873971D01*
+X3543730Y830107D01*
+X3544400Y830107D01*
+G74*
+D01*
+G02X3608207Y766300I0J63807*
+G01*
+X3608207Y766300D01*
+X3608207Y651300D01*
+G75*
+D01*
+G02X3544400Y587493I-63807J0*
+G01*
+X3544400Y587493D01*
+X3364400Y587493D01*
+G75*
+D01*
+G02X3300593Y651300I0J63807*
+G01*
+X3300593Y651300D01*
+X3300593Y766300D01*
+G75*
+D01*
+G02X3364400Y830107I63807J0*
+G01*
+X3364400Y830107D01*
+X3365070Y830107D01*
+X3365070Y873971D01*
+G75*
+D01*
+G02X3543730Y873971I89330J124828*
+G01*
+D02*
+G37*
+G36*
+X3608207Y466300D02*
+X3608207Y466300D01*
+X3608207Y451817D01*
+X3497417Y451817D01*
+X3497417Y530107D01*
+X3544400Y530107D01*
+G74*
+D01*
+G02X3608207Y466300I0J63807*
+G01*
+D02*
+G37*
+G36*
+X1230093Y393800D02*
+G75*
+D01*
+G02X1293900Y457607I63807J0*
+G01*
+X1293900Y457607D01*
+X1354206Y457607D01*
+X1354206Y321994D01*
+X1230093Y321994D01*
+X1230093Y393800D01*
+D02*
+G37*
+G36*
+X1614707Y393800D02*
+X1614707Y393800D01*
+X1614707Y321994D01*
+X1490594Y321994D01*
+X1490594Y457607D01*
+X1550900Y457607D01*
+G74*
+D01*
+G02X1614707Y393800I0J63807*
+G01*
+D02*
+G37*
+G36*
+X242900Y1009600D02*
+G75*
+D01*
+G02X242900Y1009600I163500J0*
+G01*
+D02*
+G37*
+%LPD*%
+G36*
+X1760600Y2878293D02*
+X1760600Y2878293D01*
+X1714930Y2878293D01*
+X1714930Y2641632D01*
+X2020369Y2336193D01*
+X2082832Y2273730D01*
+X2582720Y2273730D01*
+G74*
+D01*
+G02X2647145Y2311400I73180J51229*
+G01*
+G75*
+D01*
+G02X2566570Y2400300I8755J88900*
+G01*
+X2566570Y2400300D01*
+X2566570Y2476500D01*
+G74*
+D01*
+G02X2647145Y2565400I89330J0*
+G01*
+G75*
+D01*
+G02X2566570Y2654300I8755J88900*
+G01*
+X2566570Y2654300D01*
+X2566570Y2730500D01*
+G74*
+D01*
+G02X2647145Y2819400I89330J0*
+G01*
+G75*
+D01*
+G02X2566570Y2908300I8755J88900*
+G01*
+X2566570Y2908300D01*
+X2566570Y2984500D01*
+G74*
+D01*
+G02X2647145Y3073400I89330J0*
+G01*
+G75*
+D01*
+G02X2566570Y3162300I8755J88900*
+G01*
+X2566570Y3162300D01*
+X2566570Y3238500D01*
+G74*
+D01*
+G02X2586611Y3294882I89330J0*
+G01*
+X2586611Y3294882D01*
+X2184423Y3294882D01*
+G75*
+D01*
+G02X2142122Y3300593I0J159518*
+G01*
+X2142122Y3300593D01*
+X2094423Y3300593D01*
+G75*
+D01*
+G02X2030616Y3364400I0J63807*
+G01*
+X2030616Y3364400D01*
+X2030616Y3412099D01*
+G75*
+D01*
+G02X2030616Y3496701I153806J42301*
+G01*
+X2030616Y3496701D01*
+X2030616Y3544400D01*
+G75*
+D01*
+G02X2094423Y3608207I63807J0*
+G01*
+X2094423Y3608207D01*
+X2142122Y3608207D01*
+G75*
+D01*
+G02X2184423Y3613918I42301J-153806*
+G01*
+X2184423Y3613918D01*
+X2586611Y3613918D01*
+G75*
+D01*
+G02X2566570Y3670300I69289J56382*
+G01*
+X2566570Y3670300D01*
+X2566570Y3746500D01*
+G74*
+D01*
+G02X2647145Y3835400I89330J0*
+G01*
+G74*
+D01*
+G02X2582720Y3873070I8755J88900*
+G01*
+X2582720Y3873070D01*
+X2495048Y3873070D01*
+G74*
+D01*
+G02X2433500Y3826093I61547J16830*
+G01*
+X2433500Y3826093D01*
+X2318500Y3826093D01*
+G75*
+D01*
+G02X2286000Y3834990I0J63807*
+G01*
+G74*
+D01*
+G02X2253500Y3826093I32500J54910*
+G01*
+X2253500Y3826093D01*
+X2138500Y3826093D01*
+G75*
+D01*
+G02X2093648Y3844516I-1J63807*
+G01*
+X2093648Y3844516D01*
+X1714930Y3465798D01*
+X1714930Y3420907D01*
+X1760600Y3420907D01*
+G74*
+D01*
+G02X1824407Y3357100I0J63807*
+G01*
+X1824407Y3357100D01*
+X1824407Y3242100D01*
+G75*
+D01*
+G02X1760600Y3178293I-63807J0*
+G01*
+X1760600Y3178293D01*
+X1490600Y3178293D01*
+G75*
+D01*
+G02X1433985Y3212670I0J63807*
+G01*
+X1433985Y3212670D01*
+X1252630Y3212670D01*
+G75*
+D01*
+G02X1201009Y3212670I-25810J85519*
+G01*
+X1201009Y3212670D01*
+X925669Y3212670D01*
+G75*
+D01*
+G02X702740Y3209231I-112869J89329*
+G01*
+X702740Y3209231D01*
+X702740Y3171362D01*
+X762172Y3111930D01*
+X1457965Y3111930D01*
+G75*
+D01*
+G02X1490600Y3120907I32634J-54830*
+G01*
+X1490600Y3120907D01*
+X1760600Y3120907D01*
+G74*
+D01*
+G02X1824407Y3057100I0J63807*
+G01*
+X1824407Y3057100D01*
+X1824407Y2942100D01*
+G75*
+D01*
+G02X1760600Y2878293I-63807J0*
+G01*
+D02*
+G37*
+G36*
+X699445Y3644713D02*
+G74*
+D01*
+G03X646764Y3619166I10485J88713*
+G01*
+X646764Y3619166D01*
+X597330Y3569732D01*
+X597330Y4127328D01*
+X747072Y4277070D01*
+X1435299Y4277070D01*
+G75*
+D01*
+G03X1490600Y4245093I55301J31830*
+G01*
+X1490600Y4245093D01*
+X1760600Y4245093D01*
+G75*
+D01*
+G03X1824407Y4308900I0J63807*
+G01*
+X1824407Y4308900D01*
+X1824407Y4423900D01*
+G74*
+D01*
+G03X1760600Y4487707I63807J0*
+G01*
+X1760600Y4487707D01*
+X1490600Y4487707D01*
+G75*
+D01*
+G03X1435299Y4455730I0J-63807*
+G01*
+X1435299Y4455730D01*
+X1398191Y4455730D01*
+G74*
+D01*
+G03X1413342Y4508070I128190J65470*
+G01*
+X1413342Y4508070D01*
+X2056368Y4508070D01*
+X1736005Y4187707D01*
+X1490600Y4187707D01*
+G75*
+D01*
+G03X1433985Y4153330I0J-63807*
+G01*
+X1433985Y4153330D01*
+X934099Y4153330D01*
+G74*
+D01*
+G03X839254Y4204248I94845J62875*
+G01*
+X839254Y4204248D01*
+X786346Y4204248D01*
+G75*
+D01*
+G03X672552Y4090454I0J-113794*
+G01*
+X672552Y4090454D01*
+X672552Y4037546D01*
+G75*
+D01*
+G03X739463Y3933859I113794J0*
+G01*
+G75*
+D01*
+G03X745049Y3683000I73337J-123859*
+G01*
+G74*
+D01*
+G03X699445Y3644713I67749J127000*
+G01*
+D02*
+G37*
+G36*
+X2376000Y993893D02*
+X2376000Y993893D01*
+X2196000Y993893D01*
+G75*
+D01*
+G02X2140699Y1025870I0J63807*
+G01*
+X2140699Y1025870D01*
+X2126501Y1025870D01*
+G74*
+D01*
+G02X2071200Y993893I55301J31830*
+G01*
+X2071200Y993893D01*
+X1891200Y993893D01*
+G75*
+D01*
+G02X1841930Y1017156I0J63807*
+G01*
+X1841930Y1017156D01*
+X1841930Y926002D01*
+X1848142Y919789D01*
+G75*
+D01*
+G02X1891200Y936507I43058J-47089*
+G01*
+X1891200Y936507D01*
+X2071200Y936507D01*
+G74*
+D01*
+G02X2126501Y904530I0J63807*
+G01*
+X2126501Y904530D01*
+X2140699Y904530D01*
+G75*
+D01*
+G02X2196000Y936507I55301J-31830*
+G01*
+X2196000Y936507D01*
+X2376000Y936507D01*
+G74*
+D01*
+G02X2439807Y872700I0J63807*
+G01*
+X2439807Y872700D01*
+X2439807Y757700D01*
+G75*
+D01*
+G02X2376000Y693893I-63807J0*
+G01*
+X2376000Y693893D01*
+X2375330Y693893D01*
+X2375330Y644332D01*
+G74*
+D01*
+G02X2413000Y610163I89329J136332*
+G01*
+G74*
+D01*
+G02X2450670Y644332I126999J102163*
+G01*
+X2450670Y644332D01*
+X2450670Y1139598D01*
+X2439807Y1150461D01*
+X2439807Y1057700D01*
+G75*
+D01*
+G02X2376000Y993893I-63807J0*
+G01*
+D02*
+G37*
+G36*
+X787400Y1117600D02*
+X787400Y1117600D01*
+X1549400Y1117600D01*
+X1549400Y736600D01*
+X1295400Y736600D01*
+X787400Y939800D01*
+X787400Y1117600D01*
+D02*
+G37*
+G36*
+X925669Y3391330D02*
+G74*
+D01*
+G03X880551Y3429000I112868J89330*
+G01*
+G75*
+D01*
+G03X880551Y3683000I-67750J127000*
+G01*
+G74*
+D01*
+G03X925669Y3720670I67750J127000*
+G01*
+X925669Y3720670D01*
+X1129185Y3720670D01*
+G75*
+D01*
+G03X1185800Y3686293I56615J29430*
+G01*
+X1185800Y3686293D01*
+X1455800Y3686293D01*
+G74*
+D01*
+G03X1512415Y3720670I0J63807*
+G01*
+X1512415Y3720670D01*
+X1715696Y3720670D01*
+G75*
+D01*
+G03X1717149Y3720681I50J89330*
+G01*
+X1717149Y3720681D01*
+X1562434Y3565966D01*
+G75*
+D01*
+G03X1536270Y3502656I63166J-63166*
+G01*
+X1536270Y3502656D01*
+X1536270Y3420907D01*
+X1512537Y3420907D01*
+G75*
+D01*
+G03X1519607Y3450100I-56736J29193*
+G01*
+X1519607Y3450100D01*
+X1519607Y3565100D01*
+G74*
+D01*
+G03X1455800Y3628907I63807J0*
+G01*
+X1455800Y3628907D01*
+X1185800Y3628907D01*
+G75*
+D01*
+G03X1121993Y3565100I0J-63807*
+G01*
+X1121993Y3565100D01*
+X1121993Y3450100D01*
+G75*
+D01*
+G03X1160951Y3391330I63807J0*
+G01*
+X1160951Y3391330D01*
+X925669Y3391330D01*
+D02*
+G37*
+G36*
+X2566570Y4178300D02*
+X2566570Y4178300D01*
+X2566570Y4254070D01*
+X2286172Y4254070D01*
+X2130277Y4098175D01*
+G75*
+D01*
+G02X2138500Y4098707I8222J-63275*
+G01*
+X2138500Y4098707D01*
+X2253500Y4098707D01*
+G74*
+D01*
+G02X2286000Y4089810I0J63807*
+G01*
+G75*
+D01*
+G02X2318500Y4098707I32500J-54910*
+G01*
+X2318500Y4098707D01*
+X2433500Y4098707D01*
+G74*
+D01*
+G02X2495048Y4051730I1J63807*
+G01*
+X2495048Y4051730D01*
+X2582720Y4051730D01*
+G74*
+D01*
+G02X2647145Y4089400I73180J51229*
+G01*
+G75*
+D01*
+G02X2566570Y4178300I8755J88900*
+G01*
+D02*
+G37*
+G36*
+X925669Y3899330D02*
+G74*
+D01*
+G03X886137Y3933859I112869J89329*
+G01*
+G74*
+D01*
+G03X934099Y3974670I46883J103686*
+G01*
+X934099Y3974670D01*
+X1436752Y3974670D01*
+G75*
+D01*
+G03X1490600Y3945093I53848J34229*
+G01*
+X1490600Y3945093D01*
+X1724531Y3945093D01*
+X1678768Y3899330D01*
+X1509648Y3899330D01*
+G74*
+D01*
+G03X1455800Y3928907I53848J34229*
+G01*
+X1455800Y3928907D01*
+X1185800Y3928907D01*
+G75*
+D01*
+G03X1131952Y3899330I0J-63807*
+G01*
+X1131952Y3899330D01*
+X925669Y3899330D01*
+D02*
+G37*
+G36*
+X2309229Y1265070D02*
+X2309229Y1265070D01*
+X2325198Y1265070D01*
+X2353761Y1236507D01*
+X2282703Y1236507D01*
+G74*
+D01*
+G03X2309229Y1265070I98303J117891*
+G01*
+D02*
+G37*
+G54D11*
+X787400Y1117600D02*
+X1549400Y1117600D01*
+X1549400Y736600D01*
+X1295400Y736600D01*
+X787400Y939800D01*
+X787400Y1117600D01*
+X2821307Y4787900D02*
+X2821307Y4717860D01*
+G75*
+D01*
+G02X2855900Y4724830I34593J-82359*
+G01*
+X2932100Y4724830D01*
+G74*
+D01*
+G02X3021430Y4635500I0J89330*
+G01*
+X3021430Y4559300D01*
+G75*
+D01*
+G02X2940855Y4470400I-89330J0*
+G01*
+G74*
+D01*
+G02X3021430Y4381500I8755J88900*
+G01*
+X3021430Y4379662D01*
+X3024710Y4382942D01*
+X3024710Y5027758D01*
+X2858598Y5193870D01*
+X1490507Y5193870D01*
+X1490507Y5148200D01*
+G75*
+D01*
+G02X1426700Y5084393I-63807J0*
+G01*
+X1311700Y5084393D01*
+G75*
+D01*
+G02X1247893Y5148200I0J63807*
+G01*
+X1247893Y5418200D01*
+G75*
+D01*
+G02X1311700Y5482007I63807J0*
+G01*
+X1426700Y5482007D01*
+G74*
+D01*
+G02X1490507Y5418200I0J63807*
+G01*
+X1490507Y5372530D01*
+X2022842Y5372530D01*
+G75*
+D01*
+G02X2244358Y5372530I110758J120269*
+G01*
+X2530842Y5372530D01*
+G75*
+D01*
+G02X2752358Y5372530I110758J120269*
+G01*
+X2895490Y5372530D01*
+G75*
+D01*
+G02X2928856Y5366109I110J-89330*
+G01*
+G74*
+D01*
+G02X2958845Y5346286I33257J82908*
+G01*
+X3177126Y5128005D01*
+G74*
+D01*
+G02X3203370Y5064760I63085J63245*
+G01*
+X3203370Y4345940D01*
+G75*
+D01*
+G02X3177126Y4282695I-89330J1*
+G01*
+X3047745Y4153314D01*
+G74*
+D01*
+G02X3021121Y4134921I63246J63084*
+G01*
+G74*
+D01*
+G02X3021430Y4127500I89020J7424*
+G01*
+X3021430Y4051300D01*
+G75*
+D01*
+G02X2940855Y3962400I-89330J0*
+G01*
+G74*
+D01*
+G02X3021148Y3880588I8755J88900*
+G01*
+X2939188Y3880588D01*
+X2939188Y3962252D01*
+G74*
+D01*
+G02X2932100Y3961970I7092J89047*
+G01*
+X2855900Y3961970D01*
+G75*
+D01*
+G02X2848812Y3962252I4J89330*
+G01*
+X2848812Y3880588D01*
+X2810004Y3880588D01*
+G74*
+D01*
+G02X2740855Y3835400I77904J43711*
+G01*
+G74*
+D01*
+G02X2810004Y3790212I8756J88900*
+G01*
+X2848812Y3790212D01*
+X2848812Y3708548D01*
+G75*
+D01*
+G02X2855900Y3708830I7092J-89047*
+G01*
+X2932100Y3708830D01*
+G74*
+D01*
+G02X2939188Y3708548I4J89330*
+G01*
+X2939188Y3790212D01*
+X3021148Y3790212D01*
+G74*
+D01*
+G02X2940855Y3708400I89047J7087*
+G01*
+G74*
+D01*
+G02X3021430Y3619500I8755J88900*
+G01*
+X3021430Y3543300D01*
+G75*
+D01*
+G02X2940855Y3454400I-89330J0*
+G01*
+G74*
+D01*
+G02X3021430Y3365500I8755J88900*
+G01*
+X3021430Y3289300D01*
+G75*
+D01*
+G02X3001389Y3232918I-89330J0*
+G01*
+X3318326Y3232918D01*
+G75*
+D01*
+G02X3364423Y3252607I46097J-44117*
+G01*
+X3412122Y3252607D01*
+G75*
+D01*
+G02X3496724Y3252607I42301J-153806*
+G01*
+X3544423Y3252607D01*
+G74*
+D01*
+G02X3608231Y3188800I1J63807*
+G01*
+X3608231Y3141101D01*
+G75*
+D01*
+G02X3608231Y3056499I-153807J-42301*
+G01*
+X3608231Y3008800D01*
+G75*
+D01*
+G02X3544423Y2944993I-63808J1*
+G01*
+X3523668Y2944993D01*
+G74*
+D01*
+G02X3429023Y2913882I94645J128407*
+G01*
+X3001389Y2913882D01*
+G74*
+D01*
+G02X3021430Y2857500I69289J56382*
+G01*
+X3021430Y2781300D01*
+G75*
+D01*
+G02X2940855Y2692400I-89330J0*
+G01*
+G74*
+D01*
+G02X3021148Y2610588I8755J88900*
+G01*
+X2939188Y2610588D01*
+X2939188Y2692252D01*
+G74*
+D01*
+G02X2932100Y2691970I7092J89047*
+G01*
+X2855900Y2691970D01*
+G75*
+D01*
+G02X2848812Y2692252I4J89330*
+G01*
+X2848812Y2610588D01*
+X2810004Y2610588D01*
+G74*
+D01*
+G02X2740855Y2565400I77904J43711*
+G01*
+G74*
+D01*
+G02X2810004Y2520212I8756J88900*
+G01*
+X2848812Y2520212D01*
+X2848812Y2438548D01*
+G75*
+D01*
+G02X2855900Y2438830I7092J-89047*
+G01*
+X2932100Y2438830D01*
+G74*
+D01*
+G02X2939188Y2438548I4J89330*
+G01*
+X2939188Y2520212D01*
+X3021148Y2520212D01*
+G74*
+D01*
+G02X2940855Y2438400I89047J7087*
+G01*
+G74*
+D01*
+G02X3021430Y2349500I8755J88900*
+G01*
+X3021430Y2273300D01*
+G75*
+D01*
+G02X2940855Y2184400I-89330J0*
+G01*
+G74*
+D01*
+G02X3021430Y2095500I8755J88900*
+G01*
+X3021430Y2019300D01*
+G75*
+D01*
+G02X2940855Y1930400I-89330J0*
+G01*
+G74*
+D01*
+G02X3021430Y1841500I8755J88900*
+G01*
+X3021430Y1765300D01*
+G75*
+D01*
+G02X2932100Y1675970I-89330J0*
+G01*
+X2855900Y1675970D01*
+G75*
+D01*
+G02X2821430Y1682888I-1J89330*
+G01*
+X2821430Y1638300D01*
+G75*
+D01*
+G02X2732100Y1548970I-89330J0*
+G01*
+X2655900Y1548970D01*
+G75*
+D01*
+G02X2566570Y1638300I0J89330*
+G01*
+X2566570Y1714500D01*
+G74*
+D01*
+G02X2647145Y1803400I89330J0*
+G01*
+G75*
+D01*
+G02X2566570Y1892300I8755J88900*
+G01*
+X2566570Y1968500D01*
+G74*
+D01*
+G02X2647145Y2057400I89330J0*
+G01*
+G74*
+D01*
+G02X2582720Y2095070I8755J88900*
+G01*
+X2045877Y2095070D01*
+G75*
+D01*
+G02X1982664Y2121234I-47J89330*
+G01*
+X1562434Y2541464D01*
+G75*
+D01*
+G02X1536270Y2604716I63166J63166*
+G01*
+X1536270Y2878293D01*
+X1490600Y2878293D01*
+G75*
+D01*
+G02X1427407Y2933270I0J63807*
+G01*
+X725170Y2933270D01*
+G75*
+D01*
+G02X701417Y2936486I0J89330*
+G01*
+G74*
+D01*
+G02X662004Y2959434I23752J86113*
+G01*
+X597330Y3024108D01*
+X597330Y2563005D01*
+G74*
+D01*
+G02X648212Y2472271I55458J90734*
+G01*
+X648212Y2404529D01*
+G75*
+D01*
+G02X597330Y2313795I-106341J0*
+G01*
+X597330Y2297269D01*
+G75*
+D01*
+G02X597330Y2071531I-89329J-112869*
+G01*
+X597330Y2043269D01*
+G75*
+D01*
+G02X597330Y1817531I-89329J-112869*
+G01*
+X597330Y1789269D01*
+G75*
+D01*
+G02X597330Y1563531I-89329J-112869*
+G01*
+X597330Y1486330D01*
+X1473200Y1486330D01*
+G74*
+D01*
+G02X1536445Y1460086I1J89330*
+G01*
+X1815686Y1180845D01*
+G74*
+D01*
+G02X1827393Y1166446I63083J63248*
+G01*
+X1827393Y1172700D01*
+G75*
+D01*
+G02X1891200Y1236507I63807J0*
+G01*
+X1891870Y1236507D01*
+X1891870Y1239969D01*
+G75*
+D01*
+G02X1918034Y1303266I89330J131*
+G01*
+X2032334Y1417566D01*
+G74*
+D01*
+G02X2052310Y1432595I63165J63167*
+G01*
+G75*
+D01*
+G02X2309229Y1443730I132090J-78194*
+G01*
+X2362157Y1443730D01*
+G75*
+D01*
+G02X2370371Y1443356I48J-89330*
+G01*
+G74*
+D01*
+G02X2425445Y1417486I8172J88955*
+G01*
+X2603086Y1239845D01*
+G74*
+D01*
+G02X2629330Y1176600I63085J63245*
+G01*
+X2629330Y644332D01*
+G74*
+D01*
+G02X2702712Y517549I89329J136332*
+G01*
+X2712261Y508000D01*
+X2702712Y498451D01*
+G75*
+D01*
+G02X2413000Y405837I-162711J9547*
+G01*
+G75*
+D01*
+G02X2196670Y644332I-126997J102166*
+G01*
+X2196670Y693893D01*
+X2196000Y693893D01*
+G75*
+D01*
+G02X2140699Y725870I0J63807*
+G01*
+X2126501Y725870D01*
+G74*
+D01*
+G02X2071200Y693893I55301J31830*
+G01*
+X1891200Y693893D01*
+G75*
+D01*
+G02X1835899Y725870I0J63807*
+G01*
+X1826450Y725870D01*
+G75*
+D01*
+G02X1763234Y752034I-50J89330*
+G01*
+X1689434Y825834D01*
+G75*
+D01*
+G02X1663270Y889088I63166J63166*
+G01*
+X1663270Y1080598D01*
+X1625968Y1117900D01*
+G74*
+D01*
+G02X1625969Y1117600I76567J405*
+G01*
+X1625969Y736600D01*
+G75*
+D01*
+G02X1567930Y662307I-76569J0*
+G01*
+G74*
+D01*
+G02X1550900Y659993I17028J61493*
+G01*
+X1293900Y659993D01*
+G75*
+D01*
+G02X1276871Y662307I-1J63807*
+G01*
+G74*
+D01*
+G02X1266963Y665508I18531J74292*
+G01*
+X758963Y868708D01*
+G75*
+D01*
+G02X710831Y939939I28436J71092*
+G01*
+X710831Y1117600D01*
+G75*
+D01*
+G02X787400Y1194169I76569J0*
+G01*
+X1549400Y1194169D01*
+G74*
+D01*
+G02X1549700Y1194168I105J76569*
+G01*
+X1436198Y1307670D01*
+X508000Y1307670D01*
+G75*
+D01*
+G02X418670Y1397000I0J89330*
+G01*
+X418670Y1563531D01*
+G75*
+D01*
+G02X418670Y1789269I89329J112869*
+G01*
+X418670Y1817531D01*
+G75*
+D01*
+G02X418670Y2043269I89329J112869*
+G01*
+X418670Y2071531D01*
+G75*
+D01*
+G02X418670Y2297269I89329J112869*
+G01*
+X418670Y2313795D01*
+G75*
+D01*
+G02X367788Y2404529I55458J90734*
+G01*
+X367788Y2472271D01*
+G74*
+D01*
+G02X418670Y2563005I106341J0*
+G01*
+X418670Y4408331D01*
+G75*
+D01*
+G02X418670Y4634069I89329J112869*
+G01*
+X418670Y4650595D01*
+G75*
+D01*
+G02X367788Y4741329I55458J90734*
+G01*
+X367788Y4809071D01*
+G74*
+D01*
+G02X418670Y4899805I106341J0*
+G01*
+X418670Y5029034D01*
+G75*
+D01*
+G02X444834Y5092366I89330J166*
+G01*
+X698834Y5346366D01*
+G74*
+D01*
+G02X749888Y5371705I63166J63166*
+G01*
+G75*
+D01*
+G02X762000Y5372530I12112J-88504*
+G01*
+X947893Y5372530D01*
+X947893Y5418200D01*
+G75*
+D01*
+G02X1011700Y5482007I63807J0*
+G01*
+X1126700Y5482007D01*
+G74*
+D01*
+G02X1190507Y5418200I0J63807*
+G01*
+X1190507Y5148200D01*
+G75*
+D01*
+G02X1126700Y5084393I-63807J0*
+G01*
+X1011700Y5084393D01*
+G75*
+D01*
+G02X947893Y5148200I0J63807*
+G01*
+X947893Y5193870D01*
+X799002Y5193870D01*
+X597330Y4992198D01*
+X597330Y4899805D01*
+G74*
+D01*
+G02X648212Y4809071I55458J90734*
+G01*
+X648212Y4741329D01*
+G75*
+D01*
+G02X597330Y4650595I-106341J0*
+G01*
+X597330Y4634069D01*
+G75*
+D01*
+G02X597330Y4408331I-89329J-112869*
+G01*
+X597330Y4379992D01*
+X646904Y4429566D01*
+G74*
+D01*
+G02X677608Y4449623I63166J63166*
+G01*
+G75*
+D01*
+G02X710070Y4455730I32462J-83223*
+G01*
+X1141809Y4455730D01*
+G75*
+D01*
+G02X1202249Y4648200I128190J65470*
+G01*
+G75*
+D01*
+G02X1382869Y4864530I67754J126998*
+G01*
+X2640232Y4864530D01*
+G75*
+D01*
+G02X2669697Y4859565I98J-89330*
+G01*
+G74*
+D01*
+G02X2686444Y4851707I29368J84364*
+G01*
+X2757500Y4851707D01*
+G74*
+D01*
+G02X2821307Y4787900I0J63807*
+G01*
+X1202249Y2311400D02*
+G75*
+D01*
+G02X1337751Y2311400I67751J126999*
+G01*
+G75*
+D01*
+G02X1337751Y2057400I-67750J-127000*
+G01*
+G75*
+D01*
+G02X1337751Y1803400I-67750J-127000*
+G01*
+G75*
+D01*
+G02X1202249Y1803400I-67751J-126999*
+G01*
+G75*
+D01*
+G02X1202249Y2057400I67750J127000*
+G01*
+G75*
+D01*
+G02X1202249Y2311400I67750J127000*
+G01*
+X2986100Y5492800D02*
+G75*
+D01*
+G02X2986100Y5492800I163500J0*
+G01*
+X3494100Y5492800D02*
+G75*
+D01*
+G02X3494100Y5492800I163500J0*
+G01*
+X2864000Y2565400D02*
+G75*
+D01*
+G02X2864000Y2565400I30000J0*
+G01*
+X2864000Y3835400D02*
+G75*
+D01*
+G02X2864000Y3835400I30000J0*
+G01*
+X2860893Y359367D02*
+G75*
+D01*
+G02X2727107Y359367I-66893J148633*
+G01*
+X2794000Y426261D01*
+X2860893Y359367D01*
+X3300593Y351300D02*
+X3300593Y365783D01*
+X3411383Y365783D01*
+X3411383Y287493D01*
+X3364400Y287493D01*
+G75*
+D01*
+G02X3300593Y351300I0J63807*
+G01*
+X3608207Y351300D02*
+G75*
+D01*
+G02X3544400Y287493I-63807J0*
+G01*
+X3497417Y287493D01*
+X3497417Y365783D01*
+X3608207Y365783D01*
+X3608207Y351300D01*
+X2727107Y656633D02*
+G75*
+D01*
+G02X2860893Y656633I66893J-148633*
+G01*
+X2794000Y589739D01*
+X2727107Y656633D01*
+X2734729Y508000D02*
+G75*
+D01*
+G02X2734729Y508000I59271J0*
+G01*
+X2942633Y574893D02*
+G75*
+D01*
+G02X2942633Y441107I-148633J-66893*
+G01*
+X2875739Y508000D01*
+X2942633Y574893D01*
+X3364400Y530107D02*
+X3411383Y530107D01*
+X3411383Y451817D01*
+X3300593Y451817D01*
+X3300593Y466300D01*
+G75*
+D01*
+G02X3364400Y530107I63807J0*
+G01*
+X3543730Y873971D02*
+X3543730Y830107D01*
+X3544400Y830107D01*
+G74*
+D01*
+G02X3608207Y766300I0J63807*
+G01*
+X3608207Y651300D01*
+G75*
+D01*
+G02X3544400Y587493I-63807J0*
+G01*
+X3364400Y587493D01*
+G75*
+D01*
+G02X3300593Y651300I0J63807*
+G01*
+X3300593Y766300D01*
+G75*
+D01*
+G02X3364400Y830107I63807J0*
+G01*
+X3365070Y830107D01*
+X3365070Y873971D01*
+G75*
+D01*
+G02X3543730Y873971I89330J124828*
+G01*
+X3608207Y466300D02*
+X3608207Y451817D01*
+X3497417Y451817D01*
+X3497417Y530107D01*
+X3544400Y530107D01*
+G74*
+D01*
+G02X3608207Y466300I0J63807*
+G01*
+X1230093Y393800D02*
+G75*
+D01*
+G02X1293900Y457607I63807J0*
+G01*
+X1354206Y457607D01*
+X1354206Y321994D01*
+X1230093Y321994D01*
+X1230093Y393800D01*
+X1614707Y393800D02*
+X1614707Y321994D01*
+X1490594Y321994D01*
+X1490594Y457607D01*
+X1550900Y457607D01*
+G74*
+D01*
+G02X1614707Y393800I0J63807*
+G01*
+X242900Y1009600D02*
+G75*
+D01*
+G02X242900Y1009600I163500J0*
+G01*
+X1590549Y63807D02*
+X3936193Y63807D01*
+X3936193Y6436193D01*
+X63807Y6436193D01*
+X63807Y63807D01*
+X1254251Y63807D01*
+G75*
+D01*
+G02X1230093Y113800I39649J49993*
+G01*
+X1230093Y185606D01*
+X1354206Y185606D01*
+X1354206Y63807D01*
+X1490594Y63807D01*
+X1490594Y185606D01*
+X1614707Y185606D01*
+X1614707Y113800D01*
+G75*
+D01*
+G02X1590549Y63807I-63807J0*
+G01*
+X2376000Y993893D02*
+X2196000Y993893D01*
+G75*
+D01*
+G02X2140699Y1025870I0J63807*
+G01*
+X2126501Y1025870D01*
+G74*
+D01*
+G02X2071200Y993893I55301J31830*
+G01*
+X1891200Y993893D01*
+G75*
+D01*
+G02X1841930Y1017156I0J63807*
+G01*
+X1841930Y926002D01*
+X1848142Y919789D01*
+G75*
+D01*
+G02X1891200Y936507I43058J-47089*
+G01*
+X2071200Y936507D01*
+G74*
+D01*
+G02X2126501Y904530I0J63807*
+G01*
+X2140699Y904530D01*
+G75*
+D01*
+G02X2196000Y936507I55301J-31830*
+G01*
+X2376000Y936507D01*
+G74*
+D01*
+G02X2439807Y872700I0J63807*
+G01*
+X2439807Y757700D01*
+G75*
+D01*
+G02X2376000Y693893I-63807J0*
+G01*
+X2375330Y693893D01*
+X2375330Y644332D01*
+G74*
+D01*
+G02X2413000Y610163I89329J136332*
+G01*
+G74*
+D01*
+G02X2450670Y644332I126999J102163*
+G01*
+X2450670Y1139598D01*
+X2439807Y1150461D01*
+X2439807Y1057700D01*
+G75*
+D01*
+G02X2376000Y993893I-63807J0*
+G01*
+X2309229Y1265070D02*
+X2325198Y1265070D01*
+X2353761Y1236507D01*
+X2282703Y1236507D01*
+G74*
+D01*
+G03X2309229Y1265070I98303J117891*
+G01*
+X1760600Y2878293D02*
+X1714930Y2878293D01*
+X1714930Y2641632D01*
+X2020369Y2336193D01*
+X2082832Y2273730D01*
+X2582720Y2273730D01*
+G74*
+D01*
+G02X2647145Y2311400I73180J51229*
+G01*
+G75*
+D01*
+G02X2566570Y2400300I8755J88900*
+G01*
+X2566570Y2476500D01*
+G74*
+D01*
+G02X2647145Y2565400I89330J0*
+G01*
+G75*
+D01*
+G02X2566570Y2654300I8755J88900*
+G01*
+X2566570Y2730500D01*
+G74*
+D01*
+G02X2647145Y2819400I89330J0*
+G01*
+G75*
+D01*
+G02X2566570Y2908300I8755J88900*
+G01*
+X2566570Y2984500D01*
+G74*
+D01*
+G02X2647145Y3073400I89330J0*
+G01*
+G75*
+D01*
+G02X2566570Y3162300I8755J88900*
+G01*
+X2566570Y3238500D01*
+G74*
+D01*
+G02X2586611Y3294882I89330J0*
+G01*
+X2184423Y3294882D01*
+G75*
+D01*
+G02X2142122Y3300593I0J159518*
+G01*
+X2094423Y3300593D01*
+G75*
+D01*
+G02X2030616Y3364400I0J63807*
+G01*
+X2030616Y3412099D01*
+G75*
+D01*
+G02X2030616Y3496701I153806J42301*
+G01*
+X2030616Y3544400D01*
+G75*
+D01*
+G02X2094423Y3608207I63807J0*
+G01*
+X2142122Y3608207D01*
+G75*
+D01*
+G02X2184423Y3613918I42301J-153806*
+G01*
+X2586611Y3613918D01*
+G75*
+D01*
+G02X2566570Y3670300I69289J56382*
+G01*
+X2566570Y3746500D01*
+G74*
+D01*
+G02X2647145Y3835400I89330J0*
+G01*
+G74*
+D01*
+G02X2582720Y3873070I8755J88900*
+G01*
+X2495048Y3873070D01*
+G74*
+D01*
+G02X2433500Y3826093I61547J16830*
+G01*
+X2318500Y3826093D01*
+G75*
+D01*
+G02X2286000Y3834990I0J63807*
+G01*
+G74*
+D01*
+G02X2253500Y3826093I32500J54910*
+G01*
+X2138500Y3826093D01*
+G75*
+D01*
+G02X2093648Y3844516I-1J63807*
+G01*
+X1714930Y3465798D01*
+X1714930Y3420907D01*
+X1760600Y3420907D01*
+G74*
+D01*
+G02X1824407Y3357100I0J63807*
+G01*
+X1824407Y3242100D01*
+G75*
+D01*
+G02X1760600Y3178293I-63807J0*
+G01*
+X1490600Y3178293D01*
+G75*
+D01*
+G02X1433985Y3212670I0J63807*
+G01*
+X1252630Y3212670D01*
+G75*
+D01*
+G02X1201009Y3212670I-25810J85519*
+G01*
+X925669Y3212670D01*
+G75*
+D01*
+G02X702740Y3209231I-112869J89329*
+G01*
+X702740Y3171362D01*
+X762172Y3111930D01*
+X1457965Y3111930D01*
+G75*
+D01*
+G02X1490600Y3120907I32634J-54830*
+G01*
+X1760600Y3120907D01*
+G74*
+D01*
+G02X1824407Y3057100I0J63807*
+G01*
+X1824407Y2942100D01*
+G75*
+D01*
+G02X1760600Y2878293I-63807J0*
+G01*
+X925669Y3391330D02*
+G74*
+D01*
+G03X880551Y3429000I112868J89330*
+G01*
+G75*
+D01*
+G03X880551Y3683000I-67750J127000*
+G01*
+G74*
+D01*
+G03X925669Y3720670I67750J127000*
+G01*
+X1129185Y3720670D01*
+G75*
+D01*
+G03X1185800Y3686293I56615J29430*
+G01*
+X1455800Y3686293D01*
+G74*
+D01*
+G03X1512415Y3720670I0J63807*
+G01*
+X1715696Y3720670D01*
+G75*
+D01*
+G03X1717149Y3720681I50J89330*
+G01*
+X1562434Y3565966D01*
+G75*
+D01*
+G03X1536270Y3502656I63166J-63166*
+G01*
+X1536270Y3420907D01*
+X1512537Y3420907D01*
+G75*
+D01*
+G03X1519607Y3450100I-56736J29193*
+G01*
+X1519607Y3565100D01*
+G74*
+D01*
+G03X1455800Y3628907I63807J0*
+G01*
+X1185800Y3628907D01*
+G75*
+D01*
+G03X1121993Y3565100I0J-63807*
+G01*
+X1121993Y3450100D01*
+G75*
+D01*
+G03X1160951Y3391330I63807J0*
+G01*
+X925669Y3391330D01*
+X699445Y3644713D02*
+G74*
+D01*
+G03X646764Y3619166I10485J88713*
+G01*
+X597330Y3569732D01*
+X597330Y4127328D01*
+X747072Y4277070D01*
+X1435299Y4277070D01*
+G75*
+D01*
+G03X1490600Y4245093I55301J31830*
+G01*
+X1760600Y4245093D01*
+G75*
+D01*
+G03X1824407Y4308900I0J63807*
+G01*
+X1824407Y4423900D01*
+G74*
+D01*
+G03X1760600Y4487707I63807J0*
+G01*
+X1490600Y4487707D01*
+G75*
+D01*
+G03X1435299Y4455730I0J-63807*
+G01*
+X1398191Y4455730D01*
+G74*
+D01*
+G03X1413342Y4508070I128190J65470*
+G01*
+X2056368Y4508070D01*
+X1736005Y4187707D01*
+X1490600Y4187707D01*
+G75*
+D01*
+G03X1433985Y4153330I0J-63807*
+G01*
+X934099Y4153330D01*
+G74*
+D01*
+G03X839254Y4204248I94845J62875*
+G01*
+X786346Y4204248D01*
+G75*
+D01*
+G03X672552Y4090454I0J-113794*
+G01*
+X672552Y4037546D01*
+G75*
+D01*
+G03X739463Y3933859I113794J0*
+G01*
+G75*
+D01*
+G03X745049Y3683000I73337J-123859*
+G01*
+G74*
+D01*
+G03X699445Y3644713I67749J127000*
+G01*
+X925669Y3899330D02*
+G74*
+D01*
+G03X886137Y3933859I112869J89329*
+G01*
+G74*
+D01*
+G03X934099Y3974670I46883J103686*
+G01*
+X1436752Y3974670D01*
+G75*
+D01*
+G03X1490600Y3945093I53848J34229*
+G01*
+X1724531Y3945093D01*
+X1678768Y3899330D01*
+X1509648Y3899330D01*
+G74*
+D01*
+G03X1455800Y3928907I53848J34229*
+G01*
+X1185800Y3928907D01*
+G75*
+D01*
+G03X1131952Y3899330I0J-63807*
+G01*
+X925669Y3899330D01*
+X2566570Y4178300D02*
+X2566570Y4254070D01*
+X2286172Y4254070D01*
+X2130277Y4098175D01*
+G75*
+D01*
+G02X2138500Y4098707I8222J-63275*
+G01*
+X2253500Y4098707D01*
+G74*
+D01*
+G02X2286000Y4089810I0J63807*
+G01*
+G75*
+D01*
+G02X2318500Y4098707I32500J-54910*
+G01*
+X2433500Y4098707D01*
+G74*
+D01*
+G02X2495048Y4051730I1J63807*
+G01*
+X2582720Y4051730D01*
+G74*
+D01*
+G02X2647145Y4089400I73180J51229*
+G01*
+G75*
+D01*
+G02X2566570Y4178300I8755J88900*
+G01*
+G54D12*
+X3454400Y304600D02*
+X3302000Y152200D01*
+X3454400Y408800D02*
+X3454400Y304600D01*
+X2286000Y815200D02*
+X2286000Y508000D01*
+X3454400Y408800D02*
+X2893200Y408800D01*
+X2794000Y508000D01*
+X3454400Y708800D02*
+X3454400Y998800D01*
+X1752600Y1117600D02*
+X1752600Y889000D01*
+X1826400Y815200D01*
+X2286000Y815200D01*
+X1473200Y1397000D02*
+X1752600Y1117600D01*
+X508000Y5029200D02*
+X508000Y1397000D01*
+X1473200Y1397000D01*
+X1459230Y3302000D02*
+X812800Y3302000D01*
+X1625600Y3299600D02*
+X1461630Y3299600D01*
+X1715770Y3810000D02*
+X812800Y3810000D01*
+X2249170Y4343400D02*
+X1715770Y3810000D01*
+X2694000Y3962400D02*
+X2376000Y3962400D01*
+X2894000Y4343400D02*
+X2249170Y4343400D01*
+X2694000Y4216400D02*
+X2984500Y4216400D01*
+X3114040Y4345940D01*
+X3114040Y5064760D01*
+X1346200Y4597400D02*
+X1270000Y4521200D01*
+X2894000Y4597400D02*
+X1346200Y4597400D01*
+X762000Y5283200D02*
+X508000Y5029200D01*
+X3114040Y5064760D02*
+X2895600Y5283200D01*
+X1069200Y5283200D02*
+X762000Y5283200D01*
+X2895600Y5283200D02*
+X1369200Y5283200D01*
+X1981200Y1240100D02*
+X2095500Y1354400D01*
+X1981200Y1115200D02*
+X1981200Y1240100D01*
+X710070Y4366400D02*
+X511810Y4168140D01*
+X1625600Y4366400D02*
+X710070Y4366400D01*
+X613410Y3459480D02*
+X709930Y3556000D01*
+X812800Y3556000D01*
+X725170Y3022600D02*
+X613410Y3134360D01*
+X725170Y3022600D02*
+X1602600Y3022600D01*
+X613410Y3134360D02*
+X613410Y3459480D01*
+X1602600Y3022600D02*
+X1625600Y2999600D01*
+X1625600Y2604630D02*
+X2045830Y2184400D01*
+X1625600Y2604630D02*
+X1625600Y2999600D01*
+X2045830Y2184400D02*
+X2694000Y2184400D01*
+X2085200Y3962400D02*
+X1625600Y3502800D01*
+X2085200Y3962400D02*
+X2196000Y3962400D01*
+X1625600Y3502800D02*
+X1625600Y3299600D01*
+X1320800Y3392170D02*
+X1226820Y3298190D01*
+X1320800Y3507600D02*
+X1320800Y3392170D01*
+X2691130Y4724400D02*
+X2640330Y4775200D01*
+X2694000Y4724400D02*
+X2691130Y4724400D01*
+X2640330Y4775200D02*
+X1270000Y4775200D01*
+X1738630Y4064000D02*
+X2145030Y4470400D01*
+X2694000Y4470400D01*
+X812800Y4064000D02*
+X1738630Y4064000D01*
+X1981200Y1115200D02*
+X2286000Y1115200D01*
+X2540000Y508000D02*
+X2540000Y1176600D01*
+X2362200Y1354400D01*
+X2095500Y1354400D02*
+X2362200Y1354400D01*
+G54D13*
+X3694230Y152200D02*
+X3840480Y298450D01*
+X3840480Y298450D02*
+X3840480Y3542030D01*
+X3562350Y2565400D02*
+X3835400Y2292350D01*
+X2894000Y2565400D02*
+X3562350Y2565400D01*
+X2894000Y3073400D02*
+X3429023Y3073400D01*
+X3454423Y3098800D01*
+X2694000Y3454400D02*
+X2184423Y3454400D01*
+X3840480Y3542030D02*
+X3547110Y3835400D01*
+X2894000Y3835400D01*
+X3694230Y152200D02*
+X1524000Y152200D01*
+X1422400Y253800D01*
+G54D14*
+X-63500Y-63500D02*
+X-63500Y599200D01*
+X-63500Y-63500D02*
+X349200Y-63500D01*
+X4063500Y-63500D02*
+X3650800Y-63500D01*
+X4063500Y-63500D02*
+X4063500Y599200D01*
+X4063500Y6563500D02*
+X4063500Y5900800D01*
+X4063500Y6563500D02*
+X3650800Y6563500D01*
+X-63500Y6563500D02*
+X349200Y6563500D01*
+X-63500Y6563500D02*
+X-63500Y5900800D01*
+X-563500Y-63500D02*
+X-1563500Y-63500D01*
+X-1063500Y-563500D02*
+X-1063500Y436500D01*
+X-1438500Y-63500D02*
+G75*
+D01*
+G02X-1438500Y-63500I375000J0*
+G01*
+X4563500Y-63500D02*
+X5563500Y-63500D01*
+X5063500Y-563500D02*
+X5063500Y436500D01*
+X4688500Y-63500D02*
+G75*
+D01*
+G02X4688500Y-63500I375000J0*
+G01*
+X4938500Y-63500D02*
+G75*
+D01*
+G02X4938500Y-63500I125000J0*
+G01*
+X-563500Y6563500D02*
+X-1563500Y6563500D01*
+X-1063500Y6063500D02*
+X-1063500Y7063500D01*
+X-1438500Y6563500D02*
+G75*
+D01*
+G02X-1438500Y6563500I375000J0*
+G01*
+X-1313500Y6563500D02*
+G75*
+D01*
+G02X-1313500Y6563500I250000J0*
+G01*
+X-1188500Y6563500D02*
+G75*
+D01*
+G02X-1188500Y6563500I125000J0*
+G01*
+G54D15*
+X406400Y1009600D03*
+X914400Y1009600D03*
+X3657600Y5492800D03*
+X3149600Y5492800D03*
+X2641600Y5492800D03*
+X2133600Y5492800D03*
+G54D16*
+X3454400Y408800D03*
+X3454400Y708800D03*
+X1981200Y815200D03*
+X1981200Y1115200D03*
+X2286000Y815200D03*
+X2286000Y1115200D03*
+G54D17*
+X1270000Y2438400D03*
+X508000Y1676400D03*
+X1270000Y1676400D03*
+X508000Y1930400D03*
+X508000Y2184400D03*
+X1270000Y1930400D03*
+X1270000Y2184400D03*
+X508000Y4521200D03*
+X1270000Y4521200D03*
+X1270000Y4775200D03*
+X812800Y3556000D03*
+X812800Y3810000D03*
+X812800Y3302000D03*
+G54D18*
+X508000Y2438400D03*
+X508000Y4775200D03*
+G54D19*
+X474129Y2404529D02*
+X541871Y2404529D01*
+X541871Y2472271D01*
+X474129Y2472271D01*
+X474129Y2404529D01*D02*
+X474129Y4741329D02*
+X541871Y4741329D01*
+X541871Y4809071D01*
+X474129Y4809071D01*
+X474129Y4741329D01*D02*
+G54D20*
+X2694000Y4470400D03*
+X2694000Y4216400D03*
+X2694000Y3962400D03*
+X2694000Y3708400D03*
+X2694000Y3454400D03*
+X2694000Y3200400D03*
+X2694000Y2946400D03*
+X2694000Y2692400D03*
+X2694000Y2438400D03*
+X2694000Y2184400D03*
+X2694000Y1930400D03*
+X2694000Y1676400D03*
+X2894000Y4597400D03*
+X2894000Y4343400D03*
+X2894000Y4089400D03*
+X2894000Y3835400D03*
+X2894000Y3581400D03*
+X2894000Y3327400D03*
+X2894000Y3073400D03*
+X2894000Y2819400D03*
+X2894000Y2565400D03*
+X2894000Y2311400D03*
+X2894000Y2057400D03*
+X2894000Y1803400D03*
+G54D21*
+X2655900Y4432300D02*
+X2732100Y4432300D01*
+X2732100Y4508500D01*
+X2655900Y4508500D01*
+X2655900Y4432300D01*D02*
+X2655900Y4178300D02*
+X2732100Y4178300D01*
+X2732100Y4254500D01*
+X2655900Y4254500D01*
+X2655900Y4178300D01*D02*
+X2655900Y3924300D02*
+X2732100Y3924300D01*
+X2732100Y4000500D01*
+X2655900Y4000500D01*
+X2655900Y3924300D01*D02*
+X2655900Y3670300D02*
+X2732100Y3670300D01*
+X2732100Y3746500D01*
+X2655900Y3746500D01*
+X2655900Y3670300D01*D02*
+X2655900Y3416300D02*
+X2732100Y3416300D01*
+X2732100Y3492500D01*
+X2655900Y3492500D01*
+X2655900Y3416300D01*D02*
+X2655900Y3162300D02*
+X2732100Y3162300D01*
+X2732100Y3238500D01*
+X2655900Y3238500D01*
+X2655900Y3162300D01*D02*
+X2655900Y2908300D02*
+X2732100Y2908300D01*
+X2732100Y2984500D01*
+X2655900Y2984500D01*
+X2655900Y2908300D01*D02*
+X2655900Y2654300D02*
+X2732100Y2654300D01*
+X2732100Y2730500D01*
+X2655900Y2730500D01*
+X2655900Y2654300D01*D02*
+X2655900Y2400300D02*
+X2732100Y2400300D01*
+X2732100Y2476500D01*
+X2655900Y2476500D01*
+X2655900Y2400300D01*D02*
+X2655900Y2146300D02*
+X2732100Y2146300D01*
+X2732100Y2222500D01*
+X2655900Y2222500D01*
+X2655900Y2146300D01*D02*
+X2655900Y1892300D02*
+X2732100Y1892300D01*
+X2732100Y1968500D01*
+X2655900Y1968500D01*
+X2655900Y1892300D01*D02*
+X2655900Y1638300D02*
+X2732100Y1638300D01*
+X2732100Y1714500D01*
+X2655900Y1714500D01*
+X2655900Y1638300D01*D02*
+X2855900Y4559300D02*
+X2932100Y4559300D01*
+X2932100Y4635500D01*
+X2855900Y4635500D01*
+X2855900Y4559300D01*D02*
+X2855900Y4305300D02*
+X2932100Y4305300D01*
+X2932100Y4381500D01*
+X2855900Y4381500D01*
+X2855900Y4305300D01*D02*
+X2855900Y4051300D02*
+X2932100Y4051300D01*
+X2932100Y4127500D01*
+X2855900Y4127500D01*
+X2855900Y4051300D01*D02*
+X2855900Y3797300D02*
+X2932100Y3797300D01*
+X2932100Y3873500D01*
+X2855900Y3873500D01*
+X2855900Y3797300D01*D02*
+X2855900Y3543300D02*
+X2932100Y3543300D01*
+X2932100Y3619500D01*
+X2855900Y3619500D01*
+X2855900Y3543300D01*D02*
+X2855900Y3289300D02*
+X2932100Y3289300D01*
+X2932100Y3365500D01*
+X2855900Y3365500D01*
+X2855900Y3289300D01*D02*
+X2855900Y3035300D02*
+X2932100Y3035300D01*
+X2932100Y3111500D01*
+X2855900Y3111500D01*
+X2855900Y3035300D01*D02*
+X2855900Y2781300D02*
+X2932100Y2781300D01*
+X2932100Y2857500D01*
+X2855900Y2857500D01*
+X2855900Y2781300D01*D02*
+X2855900Y2527300D02*
+X2932100Y2527300D01*
+X2932100Y2603500D01*
+X2855900Y2603500D01*
+X2855900Y2527300D01*D02*
+X2855900Y2273300D02*
+X2932100Y2273300D01*
+X2932100Y2349500D01*
+X2855900Y2349500D01*
+X2855900Y2273300D01*D02*
+X2855900Y2019300D02*
+X2932100Y2019300D01*
+X2932100Y2095500D01*
+X2855900Y2095500D01*
+X2855900Y2019300D01*D02*
+X2855900Y1765300D02*
+X2932100Y1765300D01*
+X2932100Y1841500D01*
+X2855900Y1841500D01*
+X2855900Y1765300D01*D02*
+G54D22*
+X2694000Y4724400D03*
+G54D23*
+X1625600Y3299600D03*
+X1625600Y2999600D03*
+X1625600Y4366400D03*
+X1625600Y4066400D03*
+X1320800Y3507600D03*
+X1320800Y3807600D03*
+G54D24*
+X2196000Y3962400D03*
+X2376000Y3962400D03*
+G54D25*
+X1069200Y5283200D03*
+X1369200Y5283200D03*
+G54D26*
+X812800Y4064000D03*
+G54D27*
+X786346Y4037546D02*
+X839254Y4037546D01*
+X839254Y4090454D01*
+X786346Y4090454D01*
+X786346Y4037546D01*D02*
+G54D28*
+X3454400Y998800D03*
+X2184400Y1354400D03*
+G54D29*
+X3454423Y3098800D03*
+X2184423Y3454400D03*
+G54D30*
+X1422400Y863800D03*
+X1422400Y253800D03*
+G54D31*
+X2286000Y508000D03*
+X2540000Y508000D03*
+X2794000Y508000D03*
+
+M00*
diff --git a/tests/gerber_parsing_profiling/gerber_parsing_line_profile_1.py b/tests/gerber_parsing_profiling/gerber_parsing_line_profile_1.py
new file mode 100644
index 00000000..421714eb
--- /dev/null
+++ b/tests/gerber_parsing_profiling/gerber_parsing_line_profile_1.py
@@ -0,0 +1,13 @@
+# This script is for profiling Gerber.parse_lines() line by line.
+# Run kernprof -l -v gerber_parsing_line_profile_1.py
+
+import sys
+sys.path.append('../../')
+
+from camlib import *
+
+log = logging.getLogger('base2')
+log.setLevel(logging.WARNING)
+
+g = Gerber()
+g.parse_file("gerber1.gbr")
\ No newline at end of file
diff --git a/tests/gerber_parsing_profiling/gerber_parsing_profile_1.py b/tests/gerber_parsing_profiling/gerber_parsing_profile_1.py
new file mode 100644
index 00000000..0c3ff2d0
--- /dev/null
+++ b/tests/gerber_parsing_profiling/gerber_parsing_profile_1.py
@@ -0,0 +1,17 @@
+import cProfile
+import pstats
+import sys
+sys.path.append('../../')
+
+from camlib import *
+
+log = logging.getLogger('base2')
+log.setLevel(logging.WARNING)
+
+g = Gerber()
+
+#cProfile.run('g.parse_file("gerber1.gbr")', 'gerber1_profile', sort='cumtime')
+cProfile.run('g.parse_file("/home/jpcaram/flatcam_test_files/Gerbers/AVR_Transistor_Tester_silkscreen_top.GTO")',
+ 'gerber1_profile', sort='cumtime')
+p = pstats.Stats('gerber1_profile')
+p.strip_dirs().sort_stats('cumulative').print_stats(.1)
\ No newline at end of file
diff --git a/tests/other/destructor_test.py b/tests/other/destructor_test.py
new file mode 100644
index 00000000..c42d8d17
--- /dev/null
+++ b/tests/other/destructor_test.py
@@ -0,0 +1,34 @@
+import sys
+from PyQt4 import QtCore, QtGui
+
+
+class MyObj():
+
+ def __init__(self):
+ pass
+
+ def __del__(self):
+ print "##### Destroyed ######"
+
+
+def parse():
+ o = MyObj()
+ raise Exception("Intentional Exception")
+
+
+class Example(QtGui.QWidget):
+
+ def __init__(self):
+ super(Example, self).__init__()
+
+ qbtn = QtGui.QPushButton('Raise', self)
+ qbtn.clicked.connect(parse)
+
+ self.setWindowTitle('Quit button')
+ self.show()
+
+
+if __name__ == '__main__':
+ app = QtGui.QApplication(sys.argv)
+ ex = Example()
+ sys.exit(app.exec_())
\ No newline at end of file
diff --git a/tests/profile_gerber_parser.py b/tests/other/profile_gerber_parser.py
similarity index 100%
rename from tests/profile_gerber_parser.py
rename to tests/other/profile_gerber_parser.py
diff --git a/tests/test_excellon_1.py b/tests/other/test_excellon_1.py
similarity index 100%
rename from tests/test_excellon_1.py
rename to tests/other/test_excellon_1.py
diff --git a/tests/test_fcrts.py b/tests/other/test_fcrts.py
similarity index 100%
rename from tests/test_fcrts.py
rename to tests/other/test_fcrts.py
diff --git a/tests/other/test_plotg.py b/tests/other/test_plotg.py
new file mode 100644
index 00000000..518517d1
--- /dev/null
+++ b/tests/other/test_plotg.py
@@ -0,0 +1,47 @@
+from shapely.geometry import LineString, Polygon
+from shapely.ops import cascaded_union, unary_union
+from matplotlib.pyplot import plot, subplot, show
+from camlib import *
+
+
+def plotg2(geo, solid_poly=False, color="black", linestyle='solid'):
+
+ try:
+ for sub_geo in geo:
+ plotg2(sub_geo, solid_poly=solid_poly, color=color, linestyle=linestyle)
+ except TypeError:
+ if type(geo) == Polygon:
+ if solid_poly:
+ patch = PolygonPatch(geo,
+ #facecolor="#BBF268",
+ facecolor=color,
+ edgecolor="#006E20",
+ alpha=0.5,
+ zorder=2)
+ ax = subplot(111)
+ ax.add_patch(patch)
+ else:
+ x, y = geo.exterior.coords.xy
+ plot(x, y, color=color, linestyle=linestyle)
+ for ints in geo.interiors:
+ x, y = ints.coords.xy
+ plot(x, y, color=color, linestyle=linestyle)
+
+ if type(geo) == LineString or type(geo) == LinearRing:
+ x, y = geo.coords.xy
+ plot(x, y, color=color, linestyle=linestyle)
+
+ if type(geo) == Point:
+ x, y = geo.coords.xy
+ plot(x, y, 'o')
+
+
+if __name__ == "__main__":
+ p = Polygon([[0, 0], [0, 5], [5, 5], [5, 0]])
+ paths = [
+ LineString([[0.5, 2], [2, 4.5]]),
+ LineString([[2, 0.5], [4.5, 2]])
+ ]
+ plotg2(p, solid_poly=True)
+ plotg2(paths, linestyle="dashed")
+ show()
\ No newline at end of file
diff --git a/tests/test_rt.py b/tests/other/test_rt.py
similarity index 99%
rename from tests/test_rt.py
rename to tests/other/test_rt.py
index cb80b3f3..609e5fb4 100644
--- a/tests/test_rt.py
+++ b/tests/other/test_rt.py
@@ -1,6 +1,5 @@
from rtree import index as rtindex
-
def pt2rect(pt):
return pt[0], pt[1], pt[0], pt[1]
diff --git a/tests/svg/drawing.svg b/tests/svg/drawing.svg
new file mode 100644
index 00000000..7feb03a4
--- /dev/null
+++ b/tests/svg/drawing.svg
@@ -0,0 +1,126 @@
+
+
+
+
+
+
+
+
+
+ image/svg+xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/test_excellon.py b/tests/test_excellon.py
new file mode 100644
index 00000000..1a422994
--- /dev/null
+++ b/tests/test_excellon.py
@@ -0,0 +1,330 @@
+import unittest
+import camlib
+
+
+class ExcellonNumberParseTestInch(unittest.TestCase):
+ # Inch base format: 00.0000
+
+ # LEADING ZEROS
+ # With leading zeros, when you type in a coordinate,
+ # the leading zeros must always be included. Trailing zeros
+ # are unneeded and may be left off. The CNC-7 will automatically add them.
+
+ # TRAILING ZEROS
+ # You must show all zeros to the right of the number and can omit
+ # all zeros to the left of the number. The CNC-7 will count the number
+ # of digits you typed and automatically fill in the missing zeros.
+
+ def test_inch_leading_6digit(self):
+ excellon = camlib.Excellon()
+ self.assertEqual(excellon.zeros, "L")
+ self.assertEqual(excellon.parse_number("123456"), 12.3456)
+
+ def test_inch_leading_5digit(self):
+ excellon = camlib.Excellon()
+ self.assertEqual(excellon.parse_number("12345"), 12.345)
+
+ def test_inch_leading_15digit(self):
+ excellon = camlib.Excellon()
+ self.assertEqual(excellon.parse_number("012345"), 1.2345)
+
+ def test_inch_leading_51digit(self):
+ excellon = camlib.Excellon()
+ self.assertEqual(excellon.parse_number("123450"), 12.345)
+
+ def test_inch_trailing_6digit(self):
+ excellon = camlib.Excellon()
+ excellon.zeros = "T"
+ self.assertEqual(excellon.parse_number("123456"), 12.3456)
+
+ def test_inch_trailing_5digit(self):
+ excellon = camlib.Excellon()
+ excellon.zeros = "T"
+ self.assertEqual(excellon.parse_number("12345"), 1.2345)
+
+ def test_inch_trailing_15digit(self):
+ excellon = camlib.Excellon()
+ excellon.zeros = "T"
+ self.assertEqual(excellon.parse_number("012345"), 1.2345)
+
+ def test_inch_trailing_51digit(self):
+ excellon = camlib.Excellon()
+ excellon.zeros = "T"
+ self.assertEqual(excellon.parse_number("123450"), 12.345)
+
+
+class ExcellonNumberParseTestMetric(unittest.TestCase):
+ # Metric base format: 000.000
+
+ # LEADING ZEROS
+ # With leading zeros, when you type in a coordinate,
+ # the leading zeros must always be included. Trailing zeros
+ # are unneeded and may be left off. The CNC-7 will automatically add them.
+
+ # TRAILING ZEROS
+ # You must show all zeros to the right of the number and can omit
+ # all zeros to the left of the number. The CNC-7 will count the number
+ # of digits you typed and automatically fill in the missing zeros.
+
+ def test_inch_leading_6digit(self):
+ excellon = camlib.Excellon()
+ excellon.units = "mm"
+ self.assertEqual(excellon.parse_number("123456"), 123.456)
+
+ def test_inch_leading_5digit(self):
+ excellon = camlib.Excellon()
+ excellon.units = "mm"
+ self.assertEqual(excellon.parse_number("12345"), 123.45)
+
+ def test_inch_leading_15digit(self):
+ excellon = camlib.Excellon()
+ excellon.units = "mm"
+ self.assertEqual(excellon.parse_number("012345"), 12.345)
+
+ def test_inch_leading_51digit(self):
+ excellon = camlib.Excellon()
+ excellon.units = "mm"
+ self.assertEqual(excellon.parse_number("123450"), 123.45)
+
+ def test_inch_trailing_6digit(self):
+ excellon = camlib.Excellon()
+ excellon.units = "mm"
+ excellon.zeros = "T"
+ self.assertEqual(excellon.parse_number("123456"), 123.456)
+
+ def test_inch_trailing_5digit(self):
+ excellon = camlib.Excellon()
+ excellon.units = "mm"
+ excellon.zeros = "T"
+ self.assertEqual(excellon.parse_number("12345"), 12.345)
+
+ def test_inch_trailing_15digit(self):
+ excellon = camlib.Excellon()
+ excellon.units = "mm"
+ excellon.zeros = "T"
+ self.assertEqual(excellon.parse_number("012345"), 12.345)
+
+ def test_inch_trailing_51digit(self):
+ excellon = camlib.Excellon()
+ excellon.units = "mm"
+ excellon.zeros = "T"
+ self.assertEqual(excellon.parse_number("123450"), 123.45)
+
+
+class ExcellonFormatM72Test(unittest.TestCase):
+
+ def setUp(self):
+ self.excellon = camlib.Excellon()
+ code = """
+ M48
+ M72
+ T1C.02362F197S550
+ T2C.03543F197S550
+ M95
+ T1
+ X9000Y11750
+ X30250Y10500
+ """
+ code = code.split('\n')
+ self.excellon.parse_lines(code)
+
+ def test_format(self):
+ self.assertEqual(self.excellon.units.lower(), "in")
+ self.assertEqual(self.excellon.zeros, "L")
+
+ def test_coords(self):
+ # For X9000 add the missing 00 on the right. Then divide by 10000.
+ self.assertEqual(self.excellon.drills[0]["point"].coords[0], (90.0, 11.75))
+ self.assertEqual(self.excellon.drills[1]["point"].coords[0], (30.25, 10.5))
+
+
+class ExcellonFormatM71Test(unittest.TestCase):
+
+ def setUp(self):
+ self.excellon = camlib.Excellon()
+ code = """
+ M48
+ M71
+ T1C.02362F197S550
+ T2C.03543F197S550
+ M95
+ T1
+ X9000Y11750
+ X30250Y10500
+ """
+ code = code.split('\n')
+ self.excellon.parse_lines(code)
+
+ def test_format(self):
+ self.assertEqual(self.excellon.units.lower(), "mm")
+ self.assertEqual(self.excellon.zeros, "L")
+
+ def test_coords(self):
+ # For X9000 add the missing 00 on the right. Then divide by 10000.
+ self.assertEqual(self.excellon.drills[0]["point"].coords[0], (900.0, 117.5))
+ self.assertEqual(self.excellon.drills[1]["point"].coords[0], (302.5, 105.0))
+
+
+class ExcellonFormatINCHLZTest(unittest.TestCase):
+
+ def setUp(self):
+ self.excellon = camlib.Excellon()
+ code = """
+ M48
+ INCH,LZ
+ T1C.02362F197S550
+ T2C.03543F197S550
+ M95
+ T1
+ X9000Y11750
+ X30250Y10500
+ """
+ code = code.split('\n')
+ self.excellon.parse_lines(code)
+
+ def test_format(self):
+ self.assertEqual(self.excellon.units.lower(), "in")
+ self.assertEqual(self.excellon.zeros, "L")
+
+ def test_coords(self):
+ # For X9000 add the missing 00 on the right. Then divide by 10000.
+ self.assertEqual(self.excellon.drills[0]["point"].coords[0], (90.0, 11.75))
+ self.assertEqual(self.excellon.drills[1]["point"].coords[0], (30.25, 10.5))
+
+
+class ExcellonFormatINCHTest(unittest.TestCase):
+
+ def setUp(self):
+ self.excellon = camlib.Excellon()
+ code = """
+ M48
+ INCH,LZ
+ T1C.02362F197S550
+ T2C.03543F197S550
+ M95
+ T1
+ X9000Y11750
+ X30250Y10500
+ """
+ code = code.split('\n')
+ self.excellon.parse_lines(code)
+
+ def test_format(self):
+ self.assertEqual(self.excellon.units.lower(), "in")
+ self.assertEqual(self.excellon.zeros, "L")
+
+ def test_coords(self):
+ # For X9000 add the missing 00 on the right. Then divide by 10000.
+ self.assertEqual(self.excellon.drills[0]["point"].coords[0], (90.0, 11.75))
+ self.assertEqual(self.excellon.drills[1]["point"].coords[0], (30.25, 10.5))
+
+
+class ExcellonFormatINCHTZTest(unittest.TestCase):
+
+ def setUp(self):
+ self.excellon = camlib.Excellon()
+ code = """
+ M48
+ INCH,TZ
+ T1C.02362F197S550
+ T2C.03543F197S550
+ M95
+ T1
+ X9000Y11750
+ X30250Y10500
+ """
+ code = code.split('\n')
+ self.excellon.parse_lines(code)
+
+ def test_format(self):
+ self.assertEqual(self.excellon.units.lower(), "in")
+ self.assertEqual(self.excellon.zeros, "T")
+
+ def test_coords(self):
+ # For X9000 add the missing 00 on the right. Then divide by 10000.
+ self.assertEqual(self.excellon.drills[0]["point"].coords[0], (0.9, 1.175))
+ self.assertEqual(self.excellon.drills[1]["point"].coords[0], (3.025, 1.05))
+
+
+class ExcellonFormatMETRICLZTest(unittest.TestCase):
+
+ def setUp(self):
+ self.excellon = camlib.Excellon()
+ code = """
+ M48
+ METRIC,LZ
+ T1C.02362F197S550
+ T2C.03543F197S550
+ M95
+ T1
+ X9000Y11750
+ X30250Y10500
+ """
+ code = code.split('\n')
+ self.excellon.parse_lines(code)
+
+ def test_format(self):
+ self.assertEqual(self.excellon.units.lower(), "mm")
+ self.assertEqual(self.excellon.zeros, "L")
+
+ def test_coords(self):
+ # For X9000 add the missing 00 on the right. Then divide by 10000.
+ self.assertEqual(self.excellon.drills[0]["point"].coords[0], (900.0, 117.5))
+ self.assertEqual(self.excellon.drills[1]["point"].coords[0], (302.5, 105.0))
+
+
+class ExcellonFormatMETRICTest(unittest.TestCase):
+
+ def setUp(self):
+ self.excellon = camlib.Excellon()
+ code = """
+ M48
+ METRIC,LZ
+ T1C.02362F197S550
+ T2C.03543F197S550
+ M95
+ T1
+ X9000Y11750
+ X30250Y10500
+ """
+ code = code.split('\n')
+ self.excellon.parse_lines(code)
+
+ def test_format(self):
+ self.assertEqual(self.excellon.units.lower(), "mm")
+ self.assertEqual(self.excellon.zeros, "L")
+
+ def test_coords(self):
+ # For X9000 add the missing 00 on the right. Then divide by 10000.
+ self.assertEqual(self.excellon.drills[0]["point"].coords[0], (900.0, 117.5))
+ self.assertEqual(self.excellon.drills[1]["point"].coords[0], (302.5, 105.0))
+
+
+class ExcellonFormatMETRICTZTest(unittest.TestCase):
+
+ def setUp(self):
+ self.excellon = camlib.Excellon()
+ code = """
+ M48
+ METRIC,TZ
+ T1C.02362F197S550
+ T2C.03543F197S550
+ M95
+ T1
+ X9000Y11750
+ X30250Y10500
+ """
+ code = code.split('\n')
+ self.excellon.parse_lines(code)
+
+ def test_format(self):
+ self.assertEqual(self.excellon.units.lower(), "mm")
+ self.assertEqual(self.excellon.zeros, "T")
+
+ def test_coords(self):
+ # For X9000 add the missing 00 on the right. Then divide by 10000.
+ self.assertEqual(self.excellon.drills[0]["point"].coords[0], (9.0, 11.75))
+ self.assertEqual(self.excellon.drills[1]["point"].coords[0], (30.25, 10.5))
+
+if __name__ == '__main__':
+ unittest.main()
\ No newline at end of file
diff --git a/tests/test_gerber_buffer.py b/tests/test_gerber_buffer.py
new file mode 100644
index 00000000..7696b5b0
--- /dev/null
+++ b/tests/test_gerber_buffer.py
@@ -0,0 +1,34 @@
+import unittest
+import camlib
+
+
+class GerberBuffer(unittest.TestCase):
+ def setUp(self):
+ self.gerber1 = camlib.Gerber()
+ self.gerber1.use_buffer_for_union = True
+ self.gerber1.parse_file("tests/gerber_files/STM32F4-spindle.cmp")
+ geometry1 = self.gerber1.solid_geometry
+ self.geometry1_area = self.compute_area(geometry1)
+ self.gerber2 = camlib.Gerber()
+ self.gerber2.use_buffer_for_union = False
+ self.gerber2.parse_file("tests/gerber_files/STM32F4-spindle.cmp")
+ geometry2 = self.gerber2.solid_geometry
+ self.geometry2_area = self.compute_area (geometry2)
+
+ def compute_area(self, geometry):
+ area = 0
+ try:
+ for geo in geometry:
+ area += geo.area
+
+ ## Not iterable, do the actual indexing and add.
+ except TypeError:
+ area = geometry.area
+ return area
+
+ def test_buffer(self):
+ self.assertLessEqual(abs(self.geometry2_area - self.geometry1_area), 0.000001)
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/tests/test_gerber_flow.py b/tests/test_gerber_flow.py
new file mode 100644
index 00000000..ac51b1c0
--- /dev/null
+++ b/tests/test_gerber_flow.py
@@ -0,0 +1,136 @@
+import sys
+import unittest
+from PyQt4 import QtGui
+from FlatCAMApp import App
+from FlatCAMObj import FlatCAMGerber, FlatCAMGeometry, FlatCAMCNCjob
+from ObjectUI import GerberObjectUI, GeometryObjectUI
+from time import sleep
+import os
+
+
+class GerberFlowTestCase(unittest.TestCase):
+
+ filename = 'simple1.gbr'
+
+ def setUp(self):
+ self.app = QtGui.QApplication(sys.argv)
+
+ # Create App, keep app defaults (do not load
+ # user-defined defaults).
+ self.fc = App(user_defaults=False)
+
+ self.fc.open_gerber('tests/gerber_files/' + self.filename)
+
+ def tearDown(self):
+ del self.fc
+ del self.app
+
+ def test_flow(self):
+ # Names of available objects.
+ names = self.fc.collection.get_names()
+ print names
+
+ #--------------------------------------
+ # Total of 1 objects.
+ #--------------------------------------
+ self.assertEquals(len(names), 1,
+ "Expected 1 object, found %d" % len(names))
+
+ #--------------------------------------
+ # Object's name matches the file name.
+ #--------------------------------------
+ self.assertEquals(names[0], self.filename,
+ "Expected name == %s, got %s" % (self.filename, names[0]))
+
+ #---------------------------------------
+ # Get object by that name, make sure it's a FlatCAMGerber.
+ #---------------------------------------
+ gerber_name = names[0]
+ gerber_obj = self.fc.collection.get_by_name(gerber_name)
+ self.assertTrue(isinstance(gerber_obj, FlatCAMGerber),
+ "Expected FlatCAMGerber, instead, %s is %s" %
+ (gerber_name, type(gerber_obj)))
+
+ #--------------------------------------------------
+ # Create isolation routing using default values
+ # and by clicking on the button.
+ #--------------------------------------------------
+ # Get the object's GUI and click on "Generate Geometry" under
+ # "Isolation Routing"
+ assert isinstance(gerber_obj, FlatCAMGerber) # Just for the IDE
+ gerber_obj.build_ui() # Open the object's UI.
+ ui = gerber_obj.ui
+ assert isinstance(ui, GerberObjectUI)
+ ui.generate_iso_button.click() # Click
+
+ #---------------------------------------------
+ # Check that only 1 object has been created.
+ #---------------------------------------------
+ names = self.fc.collection.get_names()
+ self.assertEqual(len(names), 2,
+ "Expected 2 objects, found %d" % len(names))
+
+ #-------------------------------------------------------
+ # Make sure the Geometry Object has the correct name
+ #-------------------------------------------------------
+ geo_name = gerber_name + "_iso"
+ self.assertTrue(geo_name in names,
+ "Object named %s not found." % geo_name)
+
+ #-------------------------------------------------------
+ # Get the object make sure it's a geometry object
+ #-------------------------------------------------------
+ geo_obj = self.fc.collection.get_by_name(geo_name)
+ self.assertTrue(isinstance(geo_obj, FlatCAMGeometry),
+ "Expected a FlatCAMGeometry, got %s" % type(geo_obj))
+
+ #------------------------------------
+ # Open the UI, make CNCObject
+ #------------------------------------
+ geo_obj.build_ui()
+ ui = geo_obj.ui
+ assert isinstance(ui, GeometryObjectUI) # Just for the IDE
+ ui.generate_cnc_button.click() # Click
+
+ # Work is done in a separate thread and results are
+ # passed via events to the main event loop which is
+ # not running. Run only for pending events.
+ #
+ # I'm not sure why, but running it only once does
+ # not catch the new object. Might be a timing issue.
+ # http://pyqt.sourceforge.net/Docs/PyQt4/qeventloop.html#details
+ for _ in range(2):
+ sleep(0.1)
+ self.app.processEvents()
+
+ #---------------------------------------------
+ # Check that only 1 object has been created.
+ #---------------------------------------------
+ names = self.fc.collection.get_names()
+ self.assertEqual(len(names), 3,
+ "Expected 3 objects, found %d" % len(names))
+
+ #-------------------------------------------------------
+ # Make sure the CNC Job Object has the correct name
+ #-------------------------------------------------------
+ cnc_name = geo_name + "_cnc"
+ self.assertTrue(cnc_name in names,
+ "Object named %s not found." % geo_name)
+
+ #-------------------------------------------------------
+ # Get the object make sure it's a CNC Job object
+ #-------------------------------------------------------
+ cnc_obj = self.fc.collection.get_by_name(cnc_name)
+ self.assertTrue(isinstance(cnc_obj, FlatCAMCNCjob),
+ "Expected a FlatCAMCNCJob, got %s" % type(geo_obj))
+
+ #-----------------------------------------
+ # Export G-Code, check output
+ #-----------------------------------------
+ assert isinstance(cnc_obj, FlatCAMCNCjob)
+ output_filename = "tests/tmp/" + cnc_name + ".gcode"
+ cnc_obj.export_gcode(output_filename)
+ self.assertTrue(os.path.isfile(output_filename))
+ os.remove(output_filename)
+
+ print names
\ No newline at end of file
diff --git a/tests/test_paint.py b/tests/test_paint.py
new file mode 100644
index 00000000..4bba42db
--- /dev/null
+++ b/tests/test_paint.py
@@ -0,0 +1,212 @@
+import unittest
+
+from shapely.geometry import LineString, Polygon
+from shapely.ops import cascaded_union, unary_union
+from matplotlib.pyplot import plot, subplot, show, cla, clf, xlim, ylim, title
+from camlib import *
+from copy import deepcopy
+
+
+def mkstorage(paths):
+ def get_pts(o):
+ return [o.coords[0], o.coords[-1]]
+ storage = FlatCAMRTreeStorage()
+ storage.get_points = get_pts
+ for p in paths:
+ storage.insert(p)
+ return storage
+
+
+def plotg2(geo, solid_poly=False, color="black", linestyle='solid'):
+
+ try:
+ for sub_geo in geo:
+ plotg2(sub_geo, solid_poly=solid_poly, color=color, linestyle=linestyle)
+ except TypeError:
+ if type(geo) == Polygon:
+ if solid_poly:
+ patch = PolygonPatch(geo,
+ #facecolor="#BBF268",
+ facecolor=color,
+ edgecolor="#006E20",
+ alpha=0.5,
+ zorder=2)
+ ax = subplot(111)
+ ax.add_patch(patch)
+ else:
+ x, y = geo.exterior.coords.xy
+ plot(x, y, color=color, linestyle=linestyle)
+ for ints in geo.interiors:
+ x, y = ints.coords.xy
+ plot(x, y, color=color, linestyle=linestyle)
+
+ if type(geo) == LineString or type(geo) == LinearRing:
+ x, y = geo.coords.xy
+ plot(x, y, color=color, linestyle=linestyle)
+
+ if type(geo) == Point:
+ x, y = geo.coords.xy
+ plot(x, y, 'o')
+
+
+class PaintTestCase(unittest.TestCase):
+ # def __init__(self):
+ # super(PaintTestCase, self).__init__()
+ # self.boundary = None
+ # self.descr = None
+
+ def plot_summary_A(self, paths, tooldia, result, msg):
+ plotg2(self.boundary, solid_poly=True, color="green")
+ plotg2(paths, color="red")
+ plotg2([r.buffer(tooldia / 2) for r in result], solid_poly=True, color="blue")
+ plotg2(result, color="black", linestyle='dashed')
+ title(msg)
+ xlim(0, 5)
+ ylim(0, 5)
+ show()
+
+
+class PaintConnectTest(PaintTestCase):
+ """
+ Simple rectangular boundary and paths inside.
+ """
+
+ def setUp(self):
+ self.boundary = Polygon([[0, 0], [0, 5], [5, 5], [5, 0]])
+
+ def test_jump(self):
+ print "Test: WALK Expected"
+ paths = [
+ LineString([[0.5, 2], [2, 4.5]]),
+ LineString([[2, 0.5], [4.5, 2]])
+ ]
+ for p in paths:
+ print p
+
+ tooldia = 1.0
+
+ print "--"
+ result = Geometry.paint_connect(mkstorage(deepcopy(paths)), self.boundary, tooldia)
+
+ result = list(result.get_objects())
+ for r in result:
+ print r
+
+ self.assertEqual(len(result), 1)
+
+ # self.plot_summary_A(paths, tooldia, result, "WALK expected.")
+
+ def test_no_jump1(self):
+ print "Test: FLY Expected"
+ paths = [
+ LineString([[0, 2], [2, 5]]),
+ LineString([[2, 0], [5, 2]])
+ ]
+ for p in paths:
+ print p
+
+ tooldia = 1.0
+
+ print "--"
+ result = Geometry.paint_connect(mkstorage(deepcopy(paths)), self.boundary, tooldia)
+
+ result = list(result.get_objects())
+ for r in result:
+ print r
+
+ self.assertEqual(len(result), len(paths))
+
+ # self.plot_summary_A(paths, tooldia, result, "FLY Expected")
+
+ def test_no_jump2(self):
+ print "Test: FLY Expected"
+ paths = [
+ LineString([[0.5, 2], [2, 4.5]]),
+ LineString([[2, 0.5], [4.5, 2]])
+ ]
+ for p in paths:
+ print p
+
+ tooldia = 1.1
+
+ print "--"
+ result = Geometry.paint_connect(mkstorage(deepcopy(paths)), self.boundary, tooldia)
+
+ result = list(result.get_objects())
+ for r in result:
+ print r
+
+ self.assertEqual(len(result), len(paths))
+
+ # self.plot_summary_A(paths, tooldia, result, "FLY Expected")
+
+
+class PaintConnectTest2(PaintTestCase):
+ """
+ Boundary with an internal cutout.
+ """
+
+ def setUp(self):
+ self.boundary = Polygon([[0, 0], [0, 5], [5, 5], [5, 0]])
+ self.boundary = self.boundary.difference(
+ Polygon([[2, 1], [3, 1], [3, 4], [2, 4]])
+ )
+
+ def test_no_jump3(self):
+ print "TEST: No jump expected"
+ paths = [
+ LineString([[0.5, 1], [1.5, 3]]),
+ LineString([[4, 1], [4, 4]])
+ ]
+ for p in paths:
+ print p
+
+ tooldia = 1.0
+
+ print "--"
+ result = Geometry.paint_connect(mkstorage(deepcopy(paths)), self.boundary, tooldia)
+
+ result = list(result.get_objects())
+ for r in result:
+ print r
+
+ self.assertEqual(len(result), len(paths))
+
+ # self.plot_summary_A(paths, tooldia, result, "FLY Expected")
+
+
+class PaintConnectTest3(PaintTestCase):
+ """
+ Tests with linerings among elements.
+ """
+
+ def setUp(self):
+ self.boundary = Polygon([[0, 0], [0, 5], [5, 5], [5, 0]])
+ print "TEST w/ LinearRings"
+
+ def test_jump2(self):
+ print "Test: WALK Expected"
+ paths = [
+ LineString([[0.5, 2], [2, 4.5]]),
+ LineString([[2, 0.5], [4.5, 2]]),
+ self.boundary.buffer(-0.5).exterior
+ ]
+ for p in paths:
+ print p
+
+ tooldia = 1.0
+
+ print "--"
+ result = Geometry.paint_connect(mkstorage(deepcopy(paths)), self.boundary, tooldia)
+
+ result = list(result.get_objects())
+ for r in result:
+ print r
+
+ self.assertEqual(len(result), 1)
+
+ # self.plot_summary_A(paths, tooldia, result, "WALK Expected")
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/tests/test_pathconnect.py b/tests/test_pathconnect.py
new file mode 100644
index 00000000..ec422c1e
--- /dev/null
+++ b/tests/test_pathconnect.py
@@ -0,0 +1,88 @@
+import unittest
+
+from shapely.geometry import LineString, Polygon
+from shapely.ops import cascaded_union, unary_union
+from matplotlib.pyplot import plot, subplot, show, cla, clf, xlim, ylim, title
+from camlib import *
+from random import random
+
+
+def mkstorage(paths):
+ def get_pts(o):
+ return [o.coords[0], o.coords[-1]]
+ storage = FlatCAMRTreeStorage()
+ storage.get_points = get_pts
+ for p in paths:
+ storage.insert(p)
+ return storage
+
+
+class PathConnectTest1(unittest.TestCase):
+
+ def setUp(self):
+ print "PathConnectTest1.setUp()"
+ pass
+
+ def test_simple_connect(self):
+ paths = [
+ LineString([[0, 0], [1, 1]]),
+ LineString([[1, 1], [2, 1]])
+ ]
+
+ result = Geometry.path_connect(mkstorage(paths))
+
+ result = list(result.get_objects())
+ self.assertEqual(len(result), 1)
+ self.assertTrue(result[0].equals(LineString([[0, 0], [1, 1], [2, 1]])))
+
+ def test_interfere_connect(self):
+ paths = [
+ LineString([[0, 0], [1, 1]]),
+ LineString([[1, 1], [2, 1]]),
+ LineString([[-0.5, 0.5], [0.5, 0]])
+ ]
+
+ result = Geometry.path_connect(mkstorage(paths))
+
+ result = list(result.get_objects())
+ self.assertEqual(len(result), 2)
+ matches = [p for p in result if p.equals(LineString([[0, 0], [1, 1], [2, 1]]))]
+ self.assertEqual(len(matches), 1)
+
+ def test_simple_connect_offset1(self):
+ for i in range(20):
+ offset_x = random()
+ offset_y = random()
+
+ paths = [
+ LineString([[0 + offset_x, 0 + offset_y], [1 + offset_x, 1 + offset_y]]),
+ LineString([[1 + offset_x, 1 + offset_y], [2 + offset_x, 1 + offset_y]])
+ ]
+
+ result = Geometry.path_connect(mkstorage(paths))
+
+ result = list(result.get_objects())
+ self.assertEqual(len(result), 1)
+ self.assertTrue(result[0].equals(LineString([[0 + offset_x, 0 + offset_y],
+ [1 + offset_x, 1 + offset_y],
+ [2 + offset_x, 1 + offset_y]])))
+
+ def test_ring_interfere_connect(self):
+ print
+ print "TEST STARTING ..."
+
+ paths = [
+ LineString([[0, 0], [1, 1]]),
+ LineString([[1, 1], [2, 1]]),
+ LinearRing([[1, 1], [2, 2], [1, 3], [0, 2]])
+ ]
+
+ result = Geometry.path_connect(mkstorage(paths))
+
+ result = list(result.get_objects())
+ self.assertEqual(len(result), 2)
+ matches = [p for p in result if p.equals(LineString([[0, 0], [1, 1], [2, 1]]))]
+ self.assertEqual(len(matches), 1)
+
+if __name__ == "__main__":
+ unittest.main()
\ No newline at end of file
diff --git a/tests/toolpath_optimization_profiling/toollift_minimization_line_profile1.py b/tests/toolpath_optimization_profiling/toollift_minimization_line_profile1.py
new file mode 100644
index 00000000..c66245bc
--- /dev/null
+++ b/tests/toolpath_optimization_profiling/toollift_minimization_line_profile1.py
@@ -0,0 +1,8 @@
+# Run kernprof -l -v gerber_parsing_line_profile_1.py
+import sys
+sys.path.append('../../')
+from camlib import *
+from shapely.geometry import Polygon
+
+poly = Polygon([(0.0, 0.0), (1.0, 0.0), (1.0, 0.5), (0.0, 0.5)])
+result = Geometry.clear_polygon2(poly, 0.01)
diff --git a/tests/toolpath_optimization_profiling/toollift_minimization_profile1.py b/tests/toolpath_optimization_profiling/toollift_minimization_profile1.py
new file mode 100644
index 00000000..038e09b3
--- /dev/null
+++ b/tests/toolpath_optimization_profiling/toollift_minimization_profile1.py
@@ -0,0 +1,11 @@
+import cProfile
+import pstats
+from camlib import *
+from shapely.geometry import Polygon
+
+poly = Polygon([(0.0, 0.0), (1.0, 0.0), (1.0, 0.5), (0.0, 0.5)])
+
+cProfile.run('result = Geometry.clear_polygon2(poly, 0.01)',
+ 'toollist_minimization_profile', sort='cumtime')
+p = pstats.Stats('toollist_minimization_profile')
+p.sort_stats('cumulative').print_stats(.1)
\ No newline at end of file