diff --git a/app.py b/app.py
index 342e8203bfb4f9bd2f8a2a189ae967d3b3730955..3a1f049c0109313ce467022701e5e0861060c5be 100644
--- a/app.py
+++ b/app.py
@@ -1,9 +1,11 @@
-from flask import Flask, request, render_template
+from flask import Flask, Response, request, render_template
 import subprocess
 import os
 import re
 import sys
+import tempfile
 import io
+from svg_to_hpgl import svgToHPGL
 
 app = Flask(__name__)
 
@@ -158,5 +160,30 @@ def catalogue():
         output = output,
         params = params)
 
+def make_svg ():
+    return ''
+
+@app.route('/hpgl/')
+def hpgl ():
+    # generate svg
+    svg = make_svg()
+    # store as a temporary file
+    (svg_file, svg_path) = tempfile.mkstemp()
+    svg_file.write(svg)
+
+    # transform to hpgl
+    hpgl = svgToHPGL(svg_path)
+
+    # remove tmp file
+    os.remove(svg_path)
+
+    r = Response(hpgl, mimetype='application/hpgl')
+
+    r.headers.extend({
+        'Content-Disposition': 'attachment; filename="cobbled-paths.hpgl"'
+    })
+
+    return r
+
 if __name__ == '__main__':
 	app.run(debug=True, host='0.0.0.0')
\ No newline at end of file
diff --git a/hpgl_multipen_encoder.py b/hpgl_multipen_encoder.py
new file mode 100644
index 0000000000000000000000000000000000000000..c6373f3b00bb903acc2d68b0b712457df05d30dd
--- /dev/null
+++ b/hpgl_multipen_encoder.py
@@ -0,0 +1,395 @@
+# coding=utf-8
+'''
+Copyright (C) 2008 Aaron Spike, aaron@ekips.org
+Copyright (C) 2013 Sebastian Wüst, sebi@timewaster.de
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+'''
+
+# standard libraries
+import math
+import re
+import sys
+sys.path.append('/usr/share/inkscape/extensions')
+# local libraries
+import bezmisc
+import cspsubdiv
+import cubicsuperpath
+import inkex
+import simplestyle
+import simpletransform
+
+
+class hpglMultipenEncoder:
+    PI = math.pi
+    TWO_PI = PI * 2
+
+    def __init__(self, effect):
+        ''' options:
+                "resolutionX":float
+                "resolutionY":float
+                "pen":int
+                "force:int
+                "speed:int
+                "orientation":string // "0", "90", "-90", "180"
+                "mirrorX":bool
+                "mirrorY":bool
+                "center":bool
+                "flat":float
+                "overcut":float
+                "toolOffset":float
+                "precut":bool
+                "autoAlign":bool
+                "debug":bool
+        '''
+        self.options = effect.options
+        self.doc = effect.document.getroot()
+        self.docWidth = effect.unittouu(self.doc.get('width'))
+        self.docHeight = effect.unittouu(self.doc.get('height'))
+        self.hpgl = ''
+        self.divergenceX = 'False'
+        self.divergenceY = 'False'
+        self.sizeX = 'False'
+        self.sizeY = 'False'
+        self.dryRun = True
+        self.lastPoint = [0, 0, 0]
+        self.lastPen = -1
+        self.offsetX = 0
+        self.offsetY = 0
+        self.penIndex = {}
+        self.penCount = self.options.penCount
+        self.scaleX = self.options.resolutionX / effect.unittouu("1.0in") # dots per inch to dots per user unit
+        self.scaleY = self.options.resolutionY / effect.unittouu("1.0in") # dots per inch to dots per user unit
+        scaleXY = (self.scaleX + self.scaleY) / 2
+        self.overcut = effect.unittouu(str(self.options.overcut) + "mm") * scaleXY # mm to dots (plotter coordinate system)
+        self.toolOffset = effect.unittouu(str(self.options.toolOffset) + "mm") * scaleXY # mm to dots
+        self.flat = self.options.flat / (1016 / ((self.options.resolutionX + self.options.resolutionY) / 2)) # scale flatness to resolution
+        if self.toolOffset > 0.0:
+            self.toolOffsetFlat = self.flat / self.toolOffset * 4.5 # scale flatness to offset
+        else:
+            self.toolOffsetFlat = 0.0
+        self.mirrorX = 1.0
+        if self.options.mirrorX:
+            self.mirrorX = -1.0
+        self.mirrorY = -1.0
+        if self.options.mirrorY:
+            self.mirrorY = 1.0
+        if self.options.debug:
+            self.debugValues = {}
+            self.debugValues['docWidth'] = self.docWidth
+            self.debugValues['docHeight'] = self.docHeight
+        # process viewBox attribute to correct page scaling
+        self.viewBoxTransformX = 1
+        self.viewBoxTransformY = 1
+        if self.options.debug:
+            self.debugValues['viewBoxWidth'] = "-"
+            self.debugValues['viewBoxHeight'] = "-"
+        viewBox = self.doc.get('viewBox')
+        if viewBox:
+            viewBox2 = viewBox.split(',')
+            if len(viewBox2) < 4:
+                viewBox2 = viewBox.split(' ')
+            if self.options.debug:
+                self.debugValues['viewBoxWidth'] = viewBox2[2]
+                self.debugValues['viewBoxHeight'] = viewBox2[3]
+            self.viewBoxTransformX = self.docWidth / effect.unittouu(effect.addDocumentUnit(viewBox2[2]))
+            self.viewBoxTransformY = self.docHeight / effect.unittouu(effect.addDocumentUnit(viewBox2[3]))
+
+    def getHpgl(self):
+        # dryRun to find edges
+        groupmat = [[self.mirrorX * self.scaleX * self.viewBoxTransformX, 0.0, 0.0], [0.0, self.mirrorY * self.scaleY * self.viewBoxTransformY, 0.0]]
+        groupmat = simpletransform.composeTransform(groupmat, simpletransform.parseTransform('rotate(' + self.options.orientation + ')'))
+        self.vData = [['', 'False', 0, 0], ['', 'False', 0, 0], ['', 'False', 0, 0], ['', 'False', 0, 0]]
+        self.processGroups(self.doc, groupmat)
+        if self.divergenceX == 'False' or self.divergenceY == 'False' or self.sizeX == 'False' or self.sizeY == 'False':
+            raise Exception('NO_PATHS')
+        # live run
+        self.dryRun = False
+        if self.options.debug:
+            self.debugValues['drawingWidth'] = self.sizeX - self.divergenceX
+            self.debugValues['drawingHeight'] = self.sizeY - self.divergenceY
+            self.debugValues['drawingWidthUU'] = self.debugValues['drawingWidth'] / self.scaleX
+            self.debugValues['drawingHeightUU'] = self.debugValues['drawingHeight'] / self.scaleY
+        # move drawing according to various modifiers
+        if self.options.autoAlign:
+            if self.options.center:
+                self.offsetX -= (self.sizeX - self.divergenceX) / 2
+                self.offsetY -= (self.sizeY - self.divergenceY) / 2
+        else:
+            self.divergenceX = 0.0
+            self.divergenceY = 0.0
+            if self.options.center:
+                if self.options.orientation == '0':
+                    self.offsetX -= (self.docWidth * self.scaleX) / 2
+                    self.offsetY += (self.docHeight * self.scaleY) / 2
+                if self.options.orientation == '90':
+                    self.offsetY += (self.docWidth * self.scaleX) / 2
+                    self.offsetX += (self.docHeight * self.scaleY) / 2
+                if self.options.orientation == '180':
+                    self.offsetX += (self.docWidth * self.scaleX) / 2
+                    self.offsetY -= (self.docHeight * self.scaleY) / 2
+                if self.options.orientation == '270':
+                    self.offsetY -= (self.docWidth * self.scaleX) / 2
+                    self.offsetX -= (self.docHeight * self.scaleY) / 2
+            else:
+                if self.options.orientation == '0':
+                    self.offsetY += self.docHeight * self.scaleY
+                if self.options.orientation == '90':
+                    self.offsetY += self.docWidth * self.scaleX
+                    self.offsetX += self.docHeight * self.scaleY
+                if self.options.orientation == '180':
+                    self.offsetX += self.docWidth * self.scaleX
+        if not self.options.center and self.toolOffset > 0.0:
+            self.offsetX += self.toolOffset
+            self.offsetY += self.toolOffset
+        # initialize transformation matrix and cache
+        groupmat = [[self.mirrorX * self.scaleX * self.viewBoxTransformX, 0.0, -self.divergenceX + self.offsetX],
+            [0.0, self.mirrorY * self.scaleY * self.viewBoxTransformY, -self.divergenceY + self.offsetY]]
+        groupmat = simpletransform.composeTransform(groupmat, simpletransform.parseTransform('rotate(' + self.options.orientation + ')'))
+        self.vData = [['', 'False', 0, 0], ['', 'False', 0, 0], ['', 'False', 0, 0], ['', 'False', 0, 0]]
+        # add move to zero point and precut
+        if self.toolOffset > 0.0 and self.options.precut:
+            if self.options.center:
+                # position precut outside of drawing plus one time the tooloffset
+                if self.offsetX >= 0.0:
+                    precutX = self.offsetX + self.toolOffset
+                else:
+                    precutX = self.offsetX - self.toolOffset
+                if self.offsetY >= 0.0:
+                    precutY = self.offsetY + self.toolOffset
+                else:
+                    precutY = self.offsetY - self.toolOffset
+                self.processOffset('PU', precutX, precutY, self.options.pen)
+                self.processOffset('PD', precutX, precutY + self.toolOffset * 8, self.options.pen)
+            else:
+                self.processOffset('PU', 0, 0, self.options.pen)
+                self.processOffset('PD', 0, self.toolOffset * 8, self.options.pen)
+        # start conversion
+        self.processGroups(self.doc, groupmat)
+        # shift an empty node in in order to process last node in cache
+        if self.toolOffset > 0.0 and not self.dryRun:
+            self.processOffset('PU', 0, 0, 0)
+        if self.options.debug:
+            return self.hpgl, self
+        else:
+            return self.hpgl, ""
+
+    def processGroups(self, doc, groupmat):
+        # flatten layers and groups to avoid recursion
+        paths = []
+        for node in doc:
+            if (node.tag == inkex.addNS('g', 'svg') and self.isGroupVisible(node)) or node.tag == inkex.addNS('path', 'svg'):
+                paths.append([node.tag, node, self.mergeTransform(node, groupmat), self.getPenNumber(node)])
+        doc = ''
+        hasGroups = True
+        while hasGroups:
+            hasGroups = False
+            for i, elm in enumerate(paths):
+                if paths[i][0] == inkex.addNS('g', 'svg') and self.isGroupVisible(paths[i][1]):
+                    hasGroups = True
+                    for path in paths[i][1]:
+                        if (path.tag == inkex.addNS('g', 'svg') and self.isGroupVisible(path)) or path.tag == inkex.addNS('path', 'svg'):
+                            paths.insert(i + 1, [path.tag, path, self.mergeTransform(path, paths[i][2]), paths[i][3]])
+                    paths[i][0] = ''
+        for node in paths:
+            if node[0] == inkex.addNS('path', 'svg'):
+                self.processPath(node[1], node[2], node[3])
+
+    def getPenNumber(self, doc):
+        penNum = str(doc.get('{' + inkex.NSS['inkscape'] + '}label')).lower().strip(' \t\n\r')
+        if re.search(r'( |\A)pen *\d+( |\Z)', penNum):
+            penNum = re.sub(r'(.* |\A)pen *(\d+)( .*|\Z)', r'\2', penNum, 1)
+            return int(penNum)
+        else:
+            style = doc.get('style')       
+            style = simplestyle.parseStyle(style)
+            if 'stroke' in style and style['stroke'] != 'none':
+                 color = style['stroke']
+            elif 'fill' in style and style['fill'] != 'none':
+                 color = style['fill']
+            else:
+                 return None
+                 
+            if not self.penIndex.has_key(color):
+                penNum = (len(self.penIndex) + 1) % self.penCount
+                self.penIndex[color] = self.penCount if penNum == 0 else penNum
+
+            return self.penIndex[color]
+            # return self.options.pen
+
+
+    def mergeTransform(self, doc, matrix):
+        # get and merge two matrixes into one
+        trans = doc.get('transform')
+        if trans:
+            return simpletransform.composeTransform(matrix, simpletransform.parseTransform(trans))
+        else:
+            return matrix
+
+    def isGroupVisible(self, group):
+        style = group.get('style')
+        if style:
+            style = simplestyle.parseStyle(style)
+            if 'display' in style and style['display'] == 'none':
+                return False
+        return True
+
+    def processPath(self, node, mat, pen):
+        # process path
+        path = node.get('d')
+        if path:
+            # parse and transform path
+            path = cubicsuperpath.parsePath(path)
+            simpletransform.applyTransformToPath(mat, path)
+            cspsubdiv.cspsubdiv(path, self.flat)
+            # path to HPGL commands
+            oldPosX = 0.0
+            oldPosY = 0.0
+            for singlePath in path:
+                cmd = 'PU'
+                for singlePathPoint in singlePath:
+                    posX, posY = singlePathPoint[1]
+                    # check if point is repeating, if so, ignore
+                    if int(round(posX)) != int(round(oldPosX)) or int(round(posY)) != int(round(oldPosY)):
+                        self.processOffset(cmd, posX, posY, pen)
+                        cmd = 'PD'
+                        oldPosX = posX
+                        oldPosY = posY
+                # perform overcut
+                if self.overcut > 0.0 and not self.dryRun:
+                    # check if last and first points are the same, otherwise the path is not closed and no overcut can be performed
+                    if int(round(oldPosX)) == int(round(singlePath[0][1][0])) and int(round(oldPosY)) == int(round(singlePath[0][1][1])):
+                        overcutLength = 0
+                        for singlePathPoint in singlePath:
+                            posX, posY = singlePathPoint[1]
+                            # check if point is repeating, if so, ignore
+                            if int(round(posX)) != int(round(oldPosX)) or int(round(posY)) != int(round(oldPosY)):
+                                overcutLength += self.getLength(oldPosX, oldPosY, posX, posY)
+                                if overcutLength >= self.overcut:
+                                    newLength = self.changeLength(oldPosX, oldPosY, posX, posY, - (overcutLength - self.overcut))
+                                    self.processOffset(cmd, newLength[0], newLength[1], pen)
+                                    break
+                                else:
+                                    self.processOffset(cmd, posX, posY, pen)
+                                oldPosX = posX
+                                oldPosY = posY
+
+    def getLength(self, x1, y1, x2, y2, absolute=True):
+        # calc absoulute or relative length between two points
+        length = math.sqrt((x2 - x1) ** 2.0 + (y2 - y1) ** 2.0)
+        if absolute:
+            length = math.fabs(length)
+        return length
+
+    def changeLength(self, x1, y1, x2, y2, offset):
+        # change length of line
+        if offset < 0:
+            offset = max( - self.getLength(x1, y1, x2, y2), offset)
+        x = x2 + (x2 - x1) / self.getLength(x1, y1, x2, y2, False) * offset
+        y = y2 + (y2 - y1) / self.getLength(x1, y1, x2, y2, False) * offset
+        return [x, y]
+
+    def processOffset(self, cmd, posX, posY, pen):
+        # calculate offset correction (or dont)
+        if self.toolOffset == 0.0 or self.dryRun:
+            self.storePoint(cmd, posX, posY, pen)
+        else:
+            # insert data into cache
+            self.vData.pop(0)
+            self.vData.insert(3, [cmd, posX, posY, pen])
+            # decide if enough data is availabe
+            if self.vData[2][1] != 'False':
+                if self.vData[1][1] == 'False':
+                    self.storePoint(self.vData[2][0], self.vData[2][1], self.vData[2][2], self.vData[2][3])
+                else:
+                    # perform tool offset correction (It's a *tad* complicated, if you want to understand it draw the data as lines on paper)
+                    if self.vData[2][0] == 'PD': # If the 3rd entry in the cache is a pen down command make the line longer by the tool offset
+                        pointThree = self.changeLength(self.vData[1][1], self.vData[1][2], self.vData[2][1], self.vData[2][2], self.toolOffset)
+                        self.storePoint('PD', pointThree[0], pointThree[1], self.vData[2][3])
+                    elif self.vData[0][1] != 'False':
+                        # Elif the 1st entry in the cache is filled with data and the 3rd entry is a pen up command shift
+                        # the 3rd entry by the current tool offset position according to the 2nd command
+                        pointThree = self.changeLength(self.vData[0][1], self.vData[0][2], self.vData[1][1], self.vData[1][2], self.toolOffset)
+                        pointThree[0] = self.vData[2][1] - (self.vData[1][1] - pointThree[0])
+                        pointThree[1] = self.vData[2][2] - (self.vData[1][2] - pointThree[1])
+                        self.storePoint('PU', pointThree[0], pointThree[1], self.vData[2][3])
+                    else:
+                        # Else just write the 3rd entry
+                        pointThree = [self.vData[2][1], self.vData[2][2]]
+                        self.storePoint('PU', pointThree[0], pointThree[1], self.vData[2][3])
+                    if self.vData[3][0] == 'PD':
+                        # If the 4th entry in the cache is a pen down command guide tool to next line with a circle between the prolonged 3rd and 4th entry
+                        if self.getLength(self.vData[2][1], self.vData[2][2], self.vData[3][1], self.vData[3][2]) >= self.toolOffset:
+                            pointFour = self.changeLength(self.vData[3][1], self.vData[3][2], self.vData[2][1], self.vData[2][2], - self.toolOffset)
+                        else:
+                            pointFour = self.changeLength(self.vData[2][1], self.vData[2][2], self.vData[3][1], self.vData[3][2],
+                                (self.toolOffset - self.getLength(self.vData[2][1], self.vData[2][2], self.vData[3][1], self.vData[3][2])))
+                        # get angle start and angle vector
+                        angleStart = math.atan2(pointThree[1] - self.vData[2][2], pointThree[0] - self.vData[2][1])
+                        angleVector = math.atan2(pointFour[1] - self.vData[2][2], pointFour[0] - self.vData[2][1]) - angleStart
+                        # switch direction when arc is bigger than 180°
+                        if angleVector > self.PI:
+                            angleVector -= self.TWO_PI
+                        elif angleVector < - self.PI:
+                            angleVector += self.TWO_PI
+                        # draw arc
+                        if angleVector >= 0:
+                            angle = angleStart + self.toolOffsetFlat
+                            while angle < angleStart + angleVector:
+                                self.storePoint('PD', self.vData[2][1] + math.cos(angle) * self.toolOffset, self.vData[2][2] + math.sin(angle) * self.toolOffset, self.vData[2][3])
+                                angle += self.toolOffsetFlat
+                        else:
+                            angle = angleStart - self.toolOffsetFlat
+                            while angle > angleStart + angleVector:
+                                self.storePoint('PD', self.vData[2][1] + math.cos(angle) * self.toolOffset, self.vData[2][2] + math.sin(angle) * self.toolOffset, self.vData[2][3])
+                                angle -= self.toolOffsetFlat
+                        self.storePoint('PD', pointFour[0], pointFour[1], self.vData[3][3])
+
+    def storePoint(self, command, x, y, pen):
+        x = int(round(x))
+        y = int(round(y))
+        # skip when no change in movement
+        if self.lastPoint[0] == command and self.lastPoint[1] == x and self.lastPoint[2] == y:
+            return
+        if self.dryRun:
+            # find edges
+            if self.divergenceX == 'False' or x < self.divergenceX:
+                self.divergenceX = x
+            if self.divergenceY == 'False' or y < self.divergenceY:
+                self.divergenceY = y
+            if self.sizeX == 'False' or x > self.sizeX:
+                self.sizeX = x
+            if self.sizeY == 'False' or y > self.sizeY:
+                self.sizeY = y
+        else:
+            # store point
+            if not self.options.center:
+                # only positive values are allowed (usually)
+                if x < 0:
+                    x = 0
+                if y < 0:
+                    y = 0
+            # select correct pen
+            if self.lastPen != pen:
+                self.hpgl += ';SP%d' % pen
+            # do not repeat command
+            if command == 'PD' and self.lastPoint[0] == 'PD' and self.lastPen == pen:
+                self.hpgl += ',%d,%d' % (x, y)
+            else:
+                self.hpgl += ';%s%d,%d' % (command, x, y)
+            self.lastPen = pen
+        self.lastPoint = [command, x, y]
+
+# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 fileencoding=utf-8 textwidth=99
diff --git a/hpgl_multipen_output.py b/hpgl_multipen_output.py
new file mode 100644
index 0000000000000000000000000000000000000000..7ad5db2c37c1779fe30a535999b8dc92cc63c8b4
--- /dev/null
+++ b/hpgl_multipen_output.py
@@ -0,0 +1,82 @@
+#! /usr/bin/python2
+# coding=utf-8
+'''
+Copyright (C) 2013 Sebastian Wüst, sebi@timewaster.de
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+'''
+
+# standard library
+import sys
+# local libraries
+import hpgl_multipen_encoder
+sys.path.append('/usr/share/inkscape/extensions')
+import inkex
+
+class HpglMultipenOutput(inkex.Effect):
+
+    def __init__(self):
+        inkex.Effect.__init__(self)
+        self.OptionParser.add_option('--tab',           action='store', type='string',  dest='tab')
+        self.OptionParser.add_option('--resolutionX',   action='store', type='float',   dest='resolutionX',   default=1016.0,  help='Resolution X (dpi)')
+        self.OptionParser.add_option('--resolutionY',   action='store', type='float',   dest='resolutionY',   default=1016.0,  help='Resolution Y (dpi)')
+        self.OptionParser.add_option('--pen',           action='store', type='int',     dest='pen',           default=1,       help='Pen number')
+        self.OptionParser.add_option('--penCount',      action='store', type='int', dest='penCount',     default=1,       help='Amount of pens to choose from')
+        self.OptionParser.add_option('--force',         action='store', type='int',     dest='force',         default=24,      help='Pen force (g)')
+        self.OptionParser.add_option('--speed',         action='store', type='int',     dest='speed',         default=20,      help='Pen speed (cm/s)')
+        self.OptionParser.add_option('--orientation',   action='store', type='string',  dest='orientation',   default='90',    help='Rotation (Clockwise)')
+        self.OptionParser.add_option('--mirrorX',       action='store', type='inkbool', dest='mirrorX',       default='FALSE', help='Mirror X axis')
+        self.OptionParser.add_option('--mirrorY',       action='store', type='inkbool', dest='mirrorY',       default='FALSE', help='Mirror Y axis')
+        self.OptionParser.add_option('--center',        action='store', type='inkbool', dest='center',        default='FALSE', help='Center zero point')
+        self.OptionParser.add_option('--overcut',       action='store', type='float',   dest='overcut',       default=1.0,     help='Overcut (mm)')
+        self.OptionParser.add_option('--toolOffset',    action='store', type='float',   dest='toolOffset',    default=0.25,    help='Tool (Knife) offset correction (mm)')
+        self.OptionParser.add_option('--precut',        action='store', type='inkbool', dest='precut',        default='TRUE',  help='Use precut')
+        self.OptionParser.add_option('--flat',          action='store', type='float',   dest='flat',          default=1.2,     help='Curve flatness')
+        self.OptionParser.add_option('--autoAlign',     action='store', type='inkbool', dest='autoAlign',     default='TRUE',  help='Auto align')
+
+    def effect(self):
+        self.options.debug = False
+        # get hpgl data
+        myHpglEncoder = hpgl_multipen_encoder.hpglMultipenEncoder(self)
+        try:
+            self.hpgl, debugObject = myHpglEncoder.getHpgl()
+        except Exception as inst:
+            if inst.args[0] == 'NO_PATHS':
+                # issue error if no paths found
+                inkex.errormsg(_("No paths where found. Please convert all objects you want to save into paths."))
+                self.hpgl = ''
+                return
+            else:
+                type, value, traceback = sys.exc_info()
+                raise ValueError("", type, value).with_traceback(traceback)
+        # convert raw HPGL to HPGL
+        hpglInit = 'IN'
+        if self.options.force > 0:
+            hpglInit += ';FS%d' % self.options.force
+        if self.options.speed > 0:
+            hpglInit += ';VS%d' % self.options.speed
+        self.hpgl = hpglInit + self.hpgl + ';SP0;PU0,0;IN; '
+
+    def output(self):
+        # print to file
+        if self.hpgl != '':
+            print(self.hpgl)
+
+if __name__ == '__main__':
+    # start extension
+    e = HpglOutput()
+    e.affect()
+
+# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 fileencoding=utf-8 textwidth=99
diff --git a/requirements.txt b/requirements.txt
new file mode 100644
index 0000000000000000000000000000000000000000..2077213c37cc027f3b2ee884c940c2f41d7adea7
--- /dev/null
+++ b/requirements.txt
@@ -0,0 +1 @@
+Flask
\ No newline at end of file
diff --git a/svg_to_hpgl.py b/svg_to_hpgl.py
new file mode 100644
index 0000000000000000000000000000000000000000..f025451bc52789f0c072ee3cb8c2d704cc6e2885
--- /dev/null
+++ b/svg_to_hpgl.py
@@ -0,0 +1,19 @@
+from hpgl_multipen_output import HpglMultipenOutput
+from sys import argv
+
+def svgToHPGL (path, speed=1, penCount=8, force=2):
+    e = HpglMultipenOutput()
+    e.affect([
+        '--orientation', '0',
+        '--force', '0',
+        '--overcut', '0',
+        '--precut', 'false',
+        '--flat', '4',
+        '--toolOffset', '0',
+        '--autoAlign', 'false',
+        '--speed', str(speed),
+        '--penCount', str(penCount),
+        '--force', str(force),
+        path], False)
+
+    return e.hpgl
\ No newline at end of file